commonlibsse_ng_proc_macro_common\to_bitflags/
mod.rs1use core::str::FromStr as _;
3
4use proc_macro2::TokenStream;
5use quote::quote;
6use syn::ItemEnum;
7
8use crate::{
9 enum_parser::{
10 filter_default_attr, filter_repr_default_attr, parse_discriminant, select_bitflags_type,
11 },
12 ffi_enum::attr_args,
13};
14
15pub fn to_bitflags(
16 attrs: TokenStream,
17 item_enum: ItemEnum,
18 crate_root_name: TokenStream,
19) -> TokenStream {
20 let args = {
21 let attr_args = match darling::ast::NestedMeta::parse_meta_list(attrs) {
22 Ok(v) => v,
23 Err(e) => {
24 return darling::Error::from(e).write_errors();
25 }
26 };
27
28 match <attr_args::MacroArgs as darling::FromMeta>::from_list(&attr_args) {
29 Ok(v) => v,
30 Err(e) => {
31 return e.write_errors();
32 }
33 }
34 };
35 to_bitflags_inner(args, item_enum, crate_root_name)
36 .unwrap_or_else(syn::Error::into_compile_error)
37}
38
39fn to_bitflags_inner(
40 _args: attr_args::MacroArgs,
41 item_enum: ItemEnum,
42 crate_root_name: TokenStream,
43) -> syn::Result<TokenStream> {
44 let enum_ident = &item_enum.ident;
45 let vis = &item_enum.vis;
46
47 let (others_attr, repr_attr) = filter_repr_default_attr(&item_enum.attrs);
48 let bitflags_type = match repr_attr {
49 Some(repr_attr) => select_bitflags_type(repr_attr)?,
50 None => quote! { usize },
51 };
52
53 let DiscriminantData { bitflags, default_value, .. } =
55 DiscriminantData::from_item_enum(&item_enum)?;
56 let docs = format!("- size type: [`{bitflags_type}`]");
57
58 let expanded = quote! {
59 #crate_root_name::__private::bitflags::bitflags! {
60 #(#others_attr)*
61 #[doc = #docs]
63 #[repr(transparent)]
64 #vis struct #enum_ident: #bitflags_type {
65 #(#bitflags;)*
66 }
67 }
68
69 impl Default for #enum_ident {
70 #[inline]
71 fn default() -> Self {
72 Self::from_bits_retain(#default_value)
73 }
74 }
75 };
76
77 Ok(expanded)
78}
79
80pub(crate) struct DiscriminantData {
82 pub(crate) bitflags: Vec<TokenStream>,
84 #[allow(unused)]
85 pub(crate) default_value: TokenStream,
86}
87
88macro_rules! to_non_suffix_num_token {
89 ($value:expr) => {
90 TokenStream::from_str(&format!("{}", $value)).unwrap()
91 };
92}
93
94impl DiscriminantData {
96 pub(crate) fn from_item_enum(item_enum: &ItemEnum) -> syn::Result<Self> {
97 let mut current_value = 0;
98 let mut bitflags = Vec::new();
99 let mut default_value = quote! { 0 };
100
101 for variant in &item_enum.variants {
102 let var_name = &variant.ident;
103 let (variant_attrs, found_default) = filter_default_attr(&variant.attrs);
104
105 let value = if let Some((_, expr)) = &variant.discriminant {
107 let parsed = parse_discriminant(expr)?;
108 current_value = parsed; if found_default {
110 default_value = quote! { #expr };
111 };
112
113 quote! { #expr }
114 } else {
115 to_non_suffix_num_token!(current_value)
116 };
117
118 bitflags.push(quote! {
120 #(#variant_attrs)*
121
122 #[allow(non_upper_case_globals)]
123 const #var_name = #value
124 });
125
126 current_value += 1;
127 }
128
129 Ok(Self { bitflags, default_value })
130 }
131}