use proc_macro::TokenStream;
mod codegen;
mod tokens;
#[proc_macro]
pub fn bitstruct_owned(input: TokenStream) -> TokenStream {
let bitstruct = syn::parse_macro_input!(input as tokens::Bitstruct);
let code = codegen::gen_code_with_owned(bitstruct);
match code {
Ok(code) => code.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn bitstruct_cow(input: TokenStream) -> TokenStream {
let bitstruct = syn::parse_macro_input!(input as tokens::Bitstruct);
let code = codegen::gen_code_with_cow(bitstruct);
match code {
Ok(code) => code.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn bitstruct_small(input: TokenStream) -> TokenStream {
let bitstruct = syn::parse_macro_input!(input as tokens::Bitstruct);
let code = codegen::gen_code_for_small(bitstruct);
match code {
Ok(code) => code.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro_attribute]
pub fn bitstruct_field_enum(attr: TokenStream, input: TokenStream) -> TokenStream {
let field_bit_width = syn::parse::<syn::LitInt>(attr).map_err(|_| {
syn::Error::new(
proc_macro2::Span::call_site(),
"bitstruct_field_enum attribute should be used like this: #[bitstruct_field_enum(2)], \
2 is a literal, meaning for the bit width of the field.",
)
});
let field_bit_width = match field_bit_width {
Ok(field_bit_width) => field_bit_width,
Err(e) => return e.to_compile_error().into(),
};
let field_bit_width = field_bit_width.base10_parse::<u32>().unwrap();
let field_enum = syn::parse_macro_input!(input as tokens::BitstructFieldEnumType);
let code = codegen::gen_code_of_enum_type(&field_enum, field_bit_width, true);
match code {
Ok(code) => code.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro_attribute]
pub fn bitstruct_repr(_: TokenStream, _: TokenStream) -> TokenStream {
syn::Error::new(
proc_macro2::Span::call_site(),
"bitstruct_repr is used by other macros, do not use it directly.",
)
.to_compile_error()
.into()
}
const BITSTRUCT_REPR: &str = "bitstruct_repr";
#[cfg(test)]
mod test {
use quote::quote;
use crate::codegen;
use crate::tokens;
#[test]
fn test_inline_enum_auto_completion() {
let incomplete = quote::quote! {
pub struct Test1 {
a: 4,
b: 2 =>
enum B {
Foo = 2,
Bar = 3
},
}
};
let complete = quote::quote! {
pub struct Test1 {
a: 4,
b: 2 =>
enum B {
Foo = 2,
Bar = 3,
__Reserved0 = 0,
__Reserved1 = 1,
},
}
};
let incomplete_bitstruct = syn::parse2::<tokens::Bitstruct>(incomplete.into()).unwrap();
let complete_bitstruct = syn::parse2::<tokens::Bitstruct>(complete.into()).unwrap();
assert_eq!(
codegen::gen_code_with_owned(incomplete_bitstruct.clone())
.unwrap()
.to_string(),
codegen::gen_code_with_owned(complete_bitstruct.clone())
.unwrap()
.to_string()
);
assert_eq!(
codegen::gen_code_with_cow(incomplete_bitstruct.clone())
.unwrap()
.to_string(),
codegen::gen_code_with_cow(complete_bitstruct.clone())
.unwrap()
.to_string()
);
assert_eq!(
codegen::gen_code_for_small(incomplete_bitstruct)
.unwrap()
.to_string(),
codegen::gen_code_for_small(complete_bitstruct)
.unwrap()
.to_string()
);
}
#[test]
fn test_noninline_enum_auto_completion() {
let incomplete = quote! {
pub enum TwoBitEnum {
Zero = 0,
Two = 2,
}
};
let complete = quote! {
pub enum TwoBitEnum {
Zero = 0,
Two = 2,
__Reserved1 = 1,
__Reserved3 = 3,
}
};
let incomplete_bitstruct_enum =
syn::parse2::<tokens::BitstructFieldEnumType>(incomplete.into()).unwrap();
let complete_bitstruct_enum =
syn::parse2::<tokens::BitstructFieldEnumType>(complete.into()).unwrap();
assert_eq!(
codegen::gen_code_of_enum_type(&incomplete_bitstruct_enum, 2, true)
.unwrap()
.to_string(),
codegen::gen_code_of_enum_type(&complete_bitstruct_enum, 2, true)
.unwrap()
.to_string()
)
}
}