diff --git a/src/attr.rs b/src/attr.rs index 4ab3cb3..42a7cde 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -15,6 +15,8 @@ pub struct Params { pub into: Option, pub from: Option, pub bits: usize, + pub binread: Enable, + pub binwrite: Enable, pub new: Enable, pub clone: Enable, pub debug: Enable, @@ -41,6 +43,8 @@ impl Parse for Params { into: None, from: None, bits, + binread: Enable::No, + binwrite: Enable::No, new: Enable::Yes, clone: Enable::Yes, debug: Enable::Yes, @@ -93,6 +97,17 @@ impl Parse for Params { "conversion" => { ret.conversion = syn::LitBool::parse(input)?.value; } + "binrw" => { + let enable: Enable = input.parse()?; + ret.binread = enable.clone(); + ret.binwrite = enable; + } + "binread" => { + ret.binread = input.parse()?; + } + "binwrite" => { + ret.binwrite = input.parse()?; + } _ => return Err(s_err(ident.span(), "unknown argument")), }; } diff --git a/src/lib.rs b/src/lib.rs index cb40704..7960dfb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,9 @@ fn s_err(span: proc_macro2::Span, msg: impl fmt::Display) -> syn::Error { /// - `from` to specify a conversion function from repr to the bitfield's integer type /// - `into` to specify a conversion function from the bitfield's integer type to repr /// - `new` to disable the `new` function generation +/// - `binread` to enable the `BinRead` trait generation +/// - `binwrite` to enable the `BinWrite` trait generation +/// - `binrw` to enable both `BinRead` and `BinWrite` trait generation /// - `clone` to disable the `Clone` trait generation /// - `debug` to disable the `Debug` trait generation /// - `defmt` to enable the `defmt::Format` trait generation @@ -64,6 +67,8 @@ fn bitfield_inner(args: TokenStream, input: TokenStream) -> syn::Result syn::Result>(); diff --git a/src/traits.rs b/src/traits.rs index aa08768..34cd715 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -131,3 +131,69 @@ pub fn hash( } } } + +/// Implements the `binrw::BinWrite` trait for the given bitfield struct. +pub fn binwrite( + name: &syn::Ident, + cfg: Option, +) -> TokenStream { + let attr = cfg.map(|cfg| quote!(#[cfg(#cfg)])); + + quote! { + #attr + impl binrw::BinWrite for #name { + type Args<'a> = (); + + fn write_options( + &self, + writer: &mut W, + endian: binrw::Endian, + args: Self::Args<'_>, + ) -> binrw::BinResult<()> { + let raw = self.into_bits(); + + let bytes = match endian { + binrw::Endian::Big => raw.to_be_bytes(), + binrw::Endian::Little => raw.to_le_bytes(), + }; + + writer.write_all(&bytes)?; + + Ok(()) + } + } + } +} + +/// Implements the `binrw::BinRead` trait for the given bitfield struct. +pub fn binread( + name: &syn::Ident, + repr: &syn::Type, + cfg: Option, +) -> TokenStream { + let attr = cfg.map(|cfg| quote!(#[cfg(#cfg)])); + + quote! { + #attr + impl binrw::BinRead for #name { + type Args<'a> = (); + + fn read_options( + reader: &mut R, + endian: binrw::Endian, + args: Self::Args<'_>, + ) -> binrw::BinResult { + let mut buf = [0u8; core::mem::size_of::<#repr>()]; + + reader.read_exact(&mut buf)?; + + let raw = match endian { + binrw::Endian::Big => <#repr>::from_be_bytes(buf), + binrw::Endian::Little => <#repr>::from_le_bytes(buf), + }; + + Ok(Self::from_bits(raw)) + } + } + } +}