1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use proc_macro2::TokenStream;
6 use syn;
7 use syn::parse::{Parse, ParseStream, Parser, Result as ParseResult};
8 
9 // $(#[$outer:meta])*
10 // ($($vis:tt)*) $BitFlags:ident: $T:ty {
11 //     $(
12 //         $(#[$inner:ident $($args:tt)*])*
13 //         const $Flag:ident = $value:expr;
14 //     )+
15 // }
16 #[derive(Debug)]
17 pub struct Bitflags {
18     attrs: Vec<syn::Attribute>,
19     vis: syn::Visibility,
20     struct_token: Token![struct],
21     name: syn::Ident,
22     colon_token: Token![:],
23     repr: syn::Type,
24     flags: Flags,
25 }
26 
27 impl Bitflags {
expand(&self) -> (syn::ItemStruct, syn::ItemImpl)28     pub fn expand(&self) -> (syn::ItemStruct, syn::ItemImpl) {
29         let Bitflags {
30             ref attrs,
31             ref vis,
32             ref name,
33             ref repr,
34             ref flags,
35             ..
36         } = *self;
37 
38         let struct_ = parse_quote! {
39             /// cbindgen:internal-derive-bitflags=true
40             #(#attrs)*
41             #vis struct #name {
42                 bits: #repr,
43             }
44         };
45 
46         let consts = flags.expand(name);
47         let impl_ = parse_quote! {
48             impl #name {
49                 #consts
50             }
51         };
52 
53         (struct_, impl_)
54     }
55 }
56 
57 impl Parse for Bitflags {
parse(input: ParseStream) -> ParseResult<Self>58     fn parse(input: ParseStream) -> ParseResult<Self> {
59         Ok(Self {
60             attrs: input.call(syn::Attribute::parse_outer)?,
61             vis: input.parse()?,
62             struct_token: input.parse()?,
63             name: input.parse()?,
64             colon_token: input.parse()?,
65             repr: input.parse()?,
66             flags: input.parse()?,
67         })
68     }
69 }
70 
71 // $(#[$inner:ident $($args:tt)*])*
72 // const $Flag:ident = $value:expr;
73 #[derive(Debug)]
74 struct Flag {
75     attrs: Vec<syn::Attribute>,
76     const_token: Token![const],
77     name: syn::Ident,
78     equals_token: Token![=],
79     value: syn::Expr,
80     semicolon_token: Token![;],
81 }
82 
83 impl Flag {
expand(&self, struct_name: &syn::Ident) -> TokenStream84     fn expand(&self, struct_name: &syn::Ident) -> TokenStream {
85         let Flag {
86             ref attrs,
87             ref name,
88             ref value,
89             ..
90         } = *self;
91         quote! {
92             #(#attrs)*
93             pub const #name : #struct_name = #struct_name { bits: #value };
94         }
95     }
96 }
97 
98 impl Parse for Flag {
parse(input: ParseStream) -> ParseResult<Self>99     fn parse(input: ParseStream) -> ParseResult<Self> {
100         Ok(Self {
101             attrs: input.call(syn::Attribute::parse_outer)?,
102             const_token: input.parse()?,
103             name: input.parse()?,
104             equals_token: input.parse()?,
105             value: input.parse()?,
106             semicolon_token: input.parse()?,
107         })
108     }
109 }
110 
111 #[derive(Debug)]
112 struct Flags(Vec<Flag>);
113 
114 impl Parse for Flags {
parse(input: ParseStream) -> ParseResult<Self>115     fn parse(input: ParseStream) -> ParseResult<Self> {
116         let content;
117         let _ = braced!(content in input);
118         let mut flags = vec![];
119         while !content.is_empty() {
120             flags.push(content.parse()?);
121         }
122         Ok(Flags(flags))
123     }
124 }
125 
126 impl Flags {
expand(&self, struct_name: &syn::Ident) -> TokenStream127     fn expand(&self, struct_name: &syn::Ident) -> TokenStream {
128         let mut ts = quote! {};
129         for flag in &self.0 {
130             ts.extend(flag.expand(struct_name));
131         }
132         ts
133     }
134 }
135 
parse(tokens: TokenStream) -> ParseResult<Bitflags>136 pub fn parse(tokens: TokenStream) -> ParseResult<Bitflags> {
137     let parser = Bitflags::parse;
138     parser.parse2(tokens)
139 }
140