Clean-up postprocessing to use less macro magic. · rust-lang/rust-bindgen@0798bda (original) (raw)

`@@ -4,145 +4,126 @@ use syn::Item;

`

4

4

``

5

5

`use crate::BindgenOptions;

`

6

6

``

7

``

`-

macro_rules! decl_postprocessing {

`

8

``

`-

($($ty:ty),*) => {

`

9

``

`-

pub(crate) fn postprocessing(

`

10

``

`-

items: Vec,

`

11

``

`-

options: &BindgenOptions,

`

12

``

`-

) -> TokenStream {

`

13

``

`` -

// Whether any of the enabled options requires syn.

``

14

``

`-

let require_syn = (<(<(<ty as PostProcessing>::should_run(options))||*;

`

15

``

-

16

``

`-

if !require_syn {

`

17

``

`-

return items.into_iter().collect();

`

18

``

`-

}

`

19

``

-

20

``

`-

let module_wrapped_tokens =

`

21

``

`-

quote!(mod wrapper_for_sorting_hack { #( #items )* });

`

22

``

-

23

``

`-

// This syn business is a hack, for now. This means that we are re-parsing already

`

24

``

`` -

// generated code using syn (as opposed to quote) because syn provides us more

``

25

``

`-

// control over the elements.

`

26

``

`` -

// One caveat is that some of the items coming from quoted output might have

``

27

``

`` -

// multiple items within them. Hence, we have to wrap the incoming in a mod.

``

28

``

`` -

// The two unwraps here are deliberate because

``

29

``

`` -

// The first one won't panic because we build the mod and know it is there

``

30

``

`-

// The second one won't panic because we know original output has something in

`

31

``

`-

// it already.

`

32

``

`-

let mut items =

`

33

``

`-

syn::parse2::syn::ItemMod(module_wrapped_tokens)

`

34

``

`-

.unwrap()

`

35

``

`-

.content

`

36

``

`-

.unwrap()

`

37

``

`-

.1;

`

38

``

-

39

``

`-

(if<(if <(if<ty as PostProcessing>::should_run(options) {

`

40

``

`-

<$ty as PostProcessing>::run(&mut items);

`

41

``

`-

})*

`

42

``

-

43

``

`-

let synful_items = items

`

44

``

`-

.into_iter()

`

45

``

`-

.map(|item| item.into_token_stream());

`

``

7

`+

struct PostProcessingPass {

`

``

8

`+

should_run: fn(&BindgenOptions) -> bool,

`

``

9

`+

run: fn(&mut Vec),

`

``

10

`+

}

`

46

11

``

47

``

`-

quote! { #( #synful_items )* }

`

``

12

`+

// TODO: This can be a const fn when mutable references are allowed in const

`

``

13

`+

// context.

`

``

14

`+

macro_rules! pass {

`

``

15

`+

($pass:ident) => {

`

``

16

`+

PostProcessingPass {

`

``

17

`+

should_run: |options| options.$pass,

`

``

18

`+

run: $pass,

`

48

19

`}

`

49

20

`};

`

50

21

`}

`

51

22

``

52

``

`-

decl_postprocessing! {

`

53

``

`-

MergeExternBlocks,

`

54

``

`-

SortSemantically

`

55

``

`-

}

`

56

``

-

57

``

`-

trait PostProcessing {

`

58

``

`-

fn should_run(options: &BindgenOptions) -> bool;

`

59

``

-

60

``

`-

fn run(items: &mut Vec);

`

61

``

`-

}

`

62

``

-

63

``

`-

struct SortSemantically;

`

``

23

`+

static PASSES: [PostProcessingPass; 2] =

`

``

24

`+

[pass!(merge_extern_blocks), pass!(sort_semantically)];

`

64

25

``

65

``

`-

impl PostProcessing for SortSemantically {

`

66

``

`-

#[inline]

`

67

``

`-

fn should_run(options: &BindgenOptions) -> bool {

`

68

``

`-

options.sort_semantically

`

``

26

`+

pub(crate) fn postprocessing(

`

``

27

`+

items: Vec,

`

``

28

`+

options: &BindgenOptions,

`

``

29

`+

) -> TokenStream {

`

``

30

`+

let require_syn = PASSES.iter().any(|pass| (pass.should_run)(options));

`

``

31

`+

if !require_syn {

`

``

32

`+

return items.into_iter().collect();

`

69

33

`}

`

70

``

-

71

``

`-

fn run(items: &mut Vec) {

`

72

``

`-

items.sort_by_key(|item| match item {

`

73

``

`-

Item::Type(_) => 0,

`

74

``

`-

Item::Struct(_) => 1,

`

75

``

`-

Item::Const(_) => 2,

`

76

``

`-

Item::Fn(_) => 3,

`

77

``

`-

Item::Enum(_) => 4,

`

78

``

`-

Item::Union(_) => 5,

`

79

``

`-

Item::Static(_) => 6,

`

80

``

`-

Item::Trait(_) => 7,

`

81

``

`-

Item::TraitAlias(_) => 8,

`

82

``

`-

Item::Impl(_) => 9,

`

83

``

`-

Item::Mod(_) => 10,

`

84

``

`-

Item::Use(_) => 11,

`

85

``

`-

Item::Verbatim(_) => 12,

`

86

``

`-

Item::ExternCrate(_) => 13,

`

87

``

`-

Item::ForeignMod(_) => 14,

`

88

``

`-

Item::Macro(_) => 15,

`

89

``

`-

Item::Macro2(_) => 16,

`

90

``

`-

_ => 18,

`

91

``

`-

});

`

``

34

`+

let module_wrapped_tokens =

`

``

35

`+

quote!(mod wrapper_for_sorting_hack { #( #items )* });

`

``

36

+

``

37

`+

// This syn business is a hack, for now. This means that we are re-parsing already

`

``

38

`` +

// generated code using syn (as opposed to quote) because syn provides us more

``

``

39

`+

// control over the elements.

`

``

40

`` +

// One caveat is that some of the items coming from quoted output might have

``

``

41

`` +

// multiple items within them. Hence, we have to wrap the incoming in a mod.

``

``

42

`` +

// The two unwraps here are deliberate because

``

``

43

`` +

// The first one won't panic because we build the mod and know it is there

``

``

44

`+

// The second one won't panic because we know original output has something in

`

``

45

`+

// it already.

`

``

46

`+

let mut items = syn::parse2::syn::ItemMod(module_wrapped_tokens)

`

``

47

`+

.unwrap()

`

``

48

`+

.content

`

``

49

`+

.unwrap()

`

``

50

`+

.1;

`

``

51

+

``

52

`+

for pass in PASSES.iter() {

`

``

53

`+

if (pass.should_run)(options) {

`

``

54

`+

(pass.run)(&mut items);

`

``

55

`+

}

`

92

56

`}

`

93

``

`-

}

`

94

57

``

95

``

`-

struct MergeExternBlocks;

`

``

58

`+

let synful_items = items.into_iter().map(|item| item.into_token_stream());

`

96

59

``

97

``

`-

impl PostProcessing for MergeExternBlocks {

`

98

``

`-

#[inline]

`

99

``

`-

fn should_run(options: &BindgenOptions) -> bool {

`

100

``

`-

options.merge_extern_blocks

`

101

``

`-

}

`

``

60

`+

quote! { #( #synful_items )* }

`

``

61

`+

}

`

102

62

``

103

``

`-

fn run(items: &mut Vec) {

`

104

``

`` -

// Keep all the extern blocks in a different Vec for faster search.

``

105

``

`-

let mut foreign_mods = Vec::syn::ItemForeignMod::new();

`

``

63

`+

fn sort_semantically(items: &mut Vec) {

`

``

64

`+

items.sort_by_key(|item| match item {

`

``

65

`+

Item::Type(_) => 0,

`

``

66

`+

Item::Struct(_) => 1,

`

``

67

`+

Item::Const(_) => 2,

`

``

68

`+

Item::Fn(_) => 3,

`

``

69

`+

Item::Enum(_) => 4,

`

``

70

`+

Item::Union(_) => 5,

`

``

71

`+

Item::Static(_) => 6,

`

``

72

`+

Item::Trait(_) => 7,

`

``

73

`+

Item::TraitAlias(_) => 8,

`

``

74

`+

Item::Impl(_) => 9,

`

``

75

`+

Item::Mod(_) => 10,

`

``

76

`+

Item::Use(_) => 11,

`

``

77

`+

Item::Verbatim(_) => 12,

`

``

78

`+

Item::ExternCrate(_) => 13,

`

``

79

`+

Item::ForeignMod(_) => 14,

`

``

80

`+

Item::Macro(_) => 15,

`

``

81

`+

Item::Macro2(_) => 16,

`

``

82

`+

_ => 18,

`

``

83

`+

});

`

``

84

`+

}

`

106

85

``

107

``

`-

for item in std::mem::take(items) {

`

108

``

`-

match item {

`

109

``

`-

Item::ForeignMod(syn::ItemForeignMod {

`

110

``

`-

attrs,

`

111

``

`-

abi,

`

112

``

`-

brace_token,

`

113

``

`-

items: foreign_items,

`

114

``

`-

}) => {

`

115

``

`-

let mut exists = false;

`

116

``

`-

for foreign_mod in &mut foreign_mods {

`

117

``

`-

// Check if there is a extern block with the same ABI and

`

118

``

`-

// attributes.

`

119

``

`-

if foreign_mod.attrs == attrs && foreign_mod.abi == abi

`

120

``

`-

{

`

121

``

`-

// Merge the items of the two blocks.

`

122

``

`-

foreign_mod.items.extend_from_slice(&foreign_items);

`

123

``

`-

exists = true;

`

124

``

`-

break;

`

125

``

`-

}

`

126

``

`-

}

`

127

``

`-

// If no existing extern block had the same ABI and attributes, store

`

128

``

`-

// it.

`

129

``

`-

if !exists {

`

130

``

`-

foreign_mods.push(syn::ItemForeignMod {

`

131

``

`-

attrs,

`

132

``

`-

abi,

`

133

``

`-

brace_token,

`

134

``

`-

items: foreign_items,

`

135

``

`-

});

`

``

86

`+

fn merge_extern_blocks(items: &mut Vec) {

`

``

87

`` +

// Keep all the extern blocks in a different Vec for faster search.

``

``

88

`+

let mut foreign_mods = Vec::syn::ItemForeignMod::new();

`

``

89

+

``

90

`+

for item in std::mem::take(items) {

`

``

91

`+

match item {

`

``

92

`+

Item::ForeignMod(syn::ItemForeignMod {

`

``

93

`+

attrs,

`

``

94

`+

abi,

`

``

95

`+

brace_token,

`

``

96

`+

items: foreign_items,

`

``

97

`+

}) => {

`

``

98

`+

let mut exists = false;

`

``

99

`+

for foreign_mod in &mut foreign_mods {

`

``

100

`+

// Check if there is a extern block with the same ABI and

`

``

101

`+

// attributes.

`

``

102

`+

if foreign_mod.attrs == attrs && foreign_mod.abi == abi {

`

``

103

`+

// Merge the items of the two blocks.

`

``

104

`+

foreign_mod.items.extend_from_slice(&foreign_items);

`

``

105

`+

exists = true;

`

``

106

`+

break;

`

136

107

`}

`

137

108

`}

`

138

``

`-

// If the item is not an extern block, we don't have to do anything.

`

139

``

`-

_ => items.push(item),

`

``

109

`+

// If no existing extern block had the same ABI and attributes, store

`

``

110

`+

// it.

`

``

111

`+

if !exists {

`

``

112

`+

foreign_mods.push(syn::ItemForeignMod {

`

``

113

`+

attrs,

`

``

114

`+

abi,

`

``

115

`+

brace_token,

`

``

116

`+

items: foreign_items,

`

``

117

`+

});

`

``

118

`+

}

`

140

119

`}

`

``

120

`+

// If the item is not an extern block, we don't have to do anything.

`

``

121

`+

_ => items.push(item),

`

141

122

`}

`

``

123

`+

}

`

142

124

``

143

``

`-

// Move all the extern blocks alongiside the rest of the items.

`

144

``

`-

for foreign_mod in foreign_mods {

`

145

``

`-

items.push(Item::ForeignMod(foreign_mod));

`

146

``

`-

}

`

``

125

`+

// Move all the extern blocks alongside the rest of the items.

`

``

126

`+

for foreign_mod in foreign_mods {

`

``

127

`+

items.push(Item::ForeignMod(foreign_mod));

`

147

128

`}

`

148

129

`}

`