From ecbf7c361340daab0b15ad4143ea14732a0811d5 Mon Sep 17 00:00:00 2001 From: hecatia-elegua <108802164+hecatia-elegua@users.noreply.github.com> Date: Wed, 9 Aug 2023 10:30:22 +0200 Subject: [PATCH 1/2] Add a crude `to_ne_bytes` implementation --- bilge-impl/src/bitsize_internal.rs | 30 ++++++++++++++++++++++++++++ examples/nested_tuples_and_arrays.rs | 23 +++++++++++++++++++-- examples/readme.rs | 3 +++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/bilge-impl/src/bitsize_internal.rs b/bilge-impl/src/bitsize_internal.rs index e6061a7..e93def3 100644 --- a/bilge-impl/src/bitsize_internal.rs +++ b/bilge-impl/src/bitsize_internal.rs @@ -231,5 +231,35 @@ fn generate_common(ir: ItemIr, arb_int: &TokenStream) -> TokenStream { const BITS: usize = ::BITS; const MAX: Self::ArbitraryInt = ::MAX; } + impl #name { + pub fn to_ne_bytes(&self) -> [u8; (::BITS + 7) / 8] { + //this works on little endian, since zeroes are cut out (i.e. u40 has 3 bytes left until u64 but they are cut out) + // 0 0 0 [1 1 1 1 1] + //but not on big endian, since it still copies from the back + // 1 1 1 [1 1 0 0 0] + // unsafe { core::mem::transmute_copy::::BITS + 7) / 8]>(self) } + + //this doesn't work for non-repr enums + // let mut full = unsafe { core::mem::transmute_copy::()]>(self) }; + + //this doesn't work for non-repr enums either, since `Self > Dst` is still getting size checked in `transmute_copy` + //and `Self` is 1 byte even if bitsize(32) + // let mut full = unsafe { + // core::mem::transmute_copy::::ArbitraryInt as Number>::UnderlyingType::BITS as usize) / 8]>(self) + // }; + + //so, let's use the first one since it's readable: + // u40, as 8 bytes + let mut full = unsafe { core::mem::transmute_copy::()]>(self) }; + + // u40, as 5 bytes + #[cfg(target_endian = "big")] + { + let size_difference = core::mem::size_of::() - ((::BITS + 7) / 8); + full.rotate_left(size_difference); + } + full[0..((::BITS + 7) / 8)].try_into().unwrap() + } + } } } diff --git a/examples/nested_tuples_and_arrays.rs b/examples/nested_tuples_and_arrays.rs index 0a67229..45d08d6 100644 --- a/examples/nested_tuples_and_arrays.rs +++ b/examples/nested_tuples_and_arrays.rs @@ -3,13 +3,13 @@ // you can use the "Expand glob import" command on // use bilge::prelude::*; // but still need to add Bitsized, Number yourself -use bilge::prelude::{bitsize, u1, u18, u2, u39, Bitsized, DebugBits, DefaultBits, FromBits, Number, TryFromBits}; +use bilge::prelude::{bitsize, u1, u18, u2, u39, BinaryBits, Bitsized, DebugBits, DefaultBits, FromBits, Number, TryFromBits}; // This file basically just informs you that yes, combinations of different nestings work. // also see `tests/struct.rs` #[bitsize(39)] -#[derive(FromBits, DebugBits, PartialEq)] +#[derive(FromBits, DebugBits, PartialEq, BinaryBits)] struct Mess { field1: (u1, (u2, u8), u1), array: [[InnerTupleStruct; 2]; 2], @@ -123,4 +123,23 @@ fn main() { let default = UnfilledEnumMess::default(); println!("{default:?}"); + + println!("{:b}", mess); + println!("{:?}", mess.to_ne_bytes()); + println!( + "{:?} == {:?} == {:?}", + core::mem::size_of::(), + core::mem::size_of::<[u8; (::BITS + 7) / 8]>(), + core::mem::size_of::<[u8; (<::ArbitraryInt as Number>::UnderlyingType::BITS as usize + 7) / 8]>() + ); + // 1u8.to_ne_bytes() -> unsafe { mem::transmute(self) } + const SIZE: usize = core::mem::size_of::(); + let mut full = unsafe { core::mem::transmute_copy::(&mess) }; + println!("{:?}", full); + full.rotate_left(3); + println!("{:?}", full); + let part: [u8; (::BITS + 7) / 8] = full[0..((::BITS + 7) / 8)].try_into().unwrap(); + println!("{:?}", part); + + println!("{:?}", default.to_ne_bytes()); } diff --git a/examples/readme.rs b/examples/readme.rs index 13cb0e9..1c8df98 100644 --- a/examples/readme.rs +++ b/examples/readme.rs @@ -48,6 +48,7 @@ struct InterruptSetEnables([bool; 32]); #[bitsize(32)] #[derive(FromBits, Debug, PartialEq)] +#[repr(u32)] enum Subclass { Mouse, Keyboard, @@ -84,6 +85,8 @@ fn main() { assert_eq!(3, num); assert_ne!(42, num); + println!("{:?}", Subclass::from(42).to_ne_bytes()); + assert_eq!(Subclass2::Reserved(3), Subclass2::from(3)); assert_eq!(Subclass2::Reserved(42), Subclass2::from(42)); let num = u32::from(Subclass2::from(42)); From 015adbebf87058cbb0cd934b014786c3b21f4106 Mon Sep 17 00:00:00 2001 From: hecatia-elegua <108802164+hecatia-elegua@users.noreply.github.com> Date: Fri, 11 Aug 2023 18:49:03 +0200 Subject: [PATCH 2/2] Adjust and document `to_ne_bytes` --- bilge-impl/src/bitsize_internal.rs | 36 +++++++++++++----------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/bilge-impl/src/bitsize_internal.rs b/bilge-impl/src/bitsize_internal.rs index e93def3..050dd97 100644 --- a/bilge-impl/src/bitsize_internal.rs +++ b/bilge-impl/src/bitsize_internal.rs @@ -233,32 +233,26 @@ fn generate_common(ir: ItemIr, arb_int: &TokenStream) -> TokenStream { } impl #name { pub fn to_ne_bytes(&self) -> [u8; (::BITS + 7) / 8] { - //this works on little endian, since zeroes are cut out (i.e. u40 has 3 bytes left until u64 but they are cut out) - // 0 0 0 [1 1 1 1 1] - //but not on big endian, since it still copies from the back - // 1 1 1 [1 1 0 0 0] - // unsafe { core::mem::transmute_copy::::BITS + 7) / 8]>(self) } - - //this doesn't work for non-repr enums - // let mut full = unsafe { core::mem::transmute_copy::()]>(self) }; - - //this doesn't work for non-repr enums either, since `Self > Dst` is still getting size checked in `transmute_copy` - //and `Self` is 1 byte even if bitsize(32) - // let mut full = unsafe { - // core::mem::transmute_copy::::ArbitraryInt as Number>::UnderlyingType::BITS as usize) / 8]>(self) - // }; - - //so, let's use the first one since it's readable: - // u40, as 8 bytes - let mut full = unsafe { core::mem::transmute_copy::()]>(self) }; + // u40 = u64 = 8 bytes + const ARB_INT_BYTES: usize = core::mem::size_of::<#name>(); + // u40 = (40 + 7) / 8 = 5 bytes + const MIN_BYTES: usize = (<#name as Bitsized>::BITS + 7) / 8; + // u40, as 8 bytes + let mut full = unsafe { core::mem::transmute_copy::(self) }; // u40, as 5 bytes #[cfg(target_endian = "big")] { - let size_difference = core::mem::size_of::() - ((::BITS + 7) / 8); - full.rotate_left(size_difference); + // = 3 + let size_difference = ARB_INT_BYTES - MIN_BYTES; + // 0 0 0 [1 1 1 1 1] + return full[size_difference..].try_into().unwrap() + } + #[cfg(target_endian = "little")] + { + // [1 1 1 1 1] 0 0 0 + return full[..MIN_BYTES].try_into().unwrap(); } - full[0..((::BITS + 7) / 8)].try_into().unwrap() } } }