diff --git a/hdl/src/wires/conversions.rs b/hdl/src/wires/conversions.rs index 80d84cb..fe8e059 100644 --- a/hdl/src/wires/conversions.rs +++ b/hdl/src/wires/conversions.rs @@ -150,6 +150,30 @@ repeat_with_n!(8, N, single_impl! {N, FitsInU8}); // } // } +macro_rules! into_bits_impl { + ($type:ty) => { + impl IntoBits for $type { + const BYTES: usize = core::mem::size_of::(); + // type ByteArr = [u8; core::mem::size_of::()]; + + // fn to_le_bytes(&self) -> [u8; Self::BYTES as usize] { + // fn to_le_bytes(&self) -> Self::ByteArr { + // self.to_le_bytes() + // } + + #[inline] + fn le_bytes(&self) -> Box<[u8]> { + Box::new(self.to_le_bytes()) + } + + #[inline] + fn num_leading_zeros(&self) -> u32 { + self.leading_zeros() + } + } + }; +} + macro_rules! impl_for_size { ($type:ty, $marker_trait:path, $nom:expr) => { #[doc = "Wires with 0 to 8 bits (0 to 1 bytes) can be represented by a `"] @@ -182,25 +206,7 @@ macro_rules! impl_for_size { } } - impl IntoBits for $type { - const BYTES: usize = core::mem::size_of::(); - // type ByteArr = [u8; core::mem::size_of::()]; - - // fn to_le_bytes(&self) -> [u8; Self::BYTES as usize] { - // fn to_le_bytes(&self) -> Self::ByteArr { - // self.to_le_bytes() - // } - - #[inline] - fn le_bytes(&self) -> Box<[u8]> { - Box::new(self.to_le_bytes()) - } - - #[inline] - fn num_leading_zeros(&self) -> u32 { - self.leading_zeros() - } - } + into_bits_impl!($type); }; ($type:ty, $marker_trait:path) => { @@ -274,6 +280,8 @@ impl_for_size!(u32, FitsInU32); impl_for_size!(u64, FitsInU64); impl_for_size!(u128, FitsInU128); +into_bits_impl!(usize); + // /// Wires with 0 to 8 bits (0 to 1 bytes) can be represented by a u8. // impl From> for u8 // where diff --git a/hdl/src/wires/mod.rs b/hdl/src/wires/mod.rs index 7158365..6732ac3 100644 --- a/hdl/src/wires/mod.rs +++ b/hdl/src/wires/mod.rs @@ -134,7 +134,7 @@ pub struct Wire { } // Doesn't work: -type WireAlias = Wire<{B}, {num_bytes(B)}>; +// type WireAlias = Wire<{B}, {num_bytes(B)}>; // Also doesn't work: // pub fn new() -> Wire<{B}, {_}> { @@ -156,8 +156,13 @@ impl Wire<{B}, {S}> { } } + // Unfortunately this function doesn't appear to work (ICEs whenever it's actually + // invoked like `Wire::get_bytes(&self)`). There's a workaround (calling new and + // then set at the call site) but we'll still leave this function in in-case this + // works once const generics become more stable. #[inline] - pub fn new_with_val(val: C) -> Self { + #[allow(unused)] + fn new_with_val(val: C) -> Self { let mut wire = Self::new(); wire.set(val); @@ -166,8 +171,8 @@ impl Wire<{B}, {S}> { #[inline] pub fn set(&mut self, val: C) -> &Self { - // Make sure we've got enough bytes to represent the value: - debug_assert!(S >= C::BYTES); + // Make sure our number of bytes matches our number of bits: + debug_assert!(S == num_bytes(B)); // Check that the value we're trying to represent fits in the number of // bits we've got: @@ -201,6 +206,11 @@ impl Wire<{B}, {S}> { /// 4 | 4 | 0..4 /// 0 | 8 | 8..8 /// 8 | 8 | 0..8 + /// + // Unfortunately this function doesn't appear to work (ICEs whenever it's actually + // invoked). We found a workaround that we're using for now, but we'll still leave + // this function in in-case this works once const generics become more stable. + #[allow(unused)] fn get_bytes(&self) -> [u8; U] { // let mut bytes = [0u8; core::mem::size_of::()]; let mut bytes = ConstU8Arr::<{U}>::new(); @@ -212,16 +222,58 @@ impl Wire<{B}, {S}> { // fn new_with_inference() -> Self } -mod conversions; - #[cfg(test)] mod tests { use super::*; + macro_rules! new_wire { + ($bits:expr) => {Wire::<{ $bits }, { num_bytes($bits) }>::new()}; + } + + // For some reason this fails to compile: + // Update: it's because calls to `Wire::new_with_val` fail to compile (just like + // `Wire::get_bytes`). The below works so we'll use it. + // macro_rules! new_wire_with_val { + // ($bits:expr, $val:expr) => {Wire::<{ $bits }, { num_bytes($bits) }>::new_with_val($val)}; + // } + + macro_rules! new_wire_with_val { + ($bits:expr, $val:expr) => {new_wire!($bits).set($val)}; + } + + #[test] + fn new() { + new_wire!(0); + new_wire!(1); + } + + // #[test] + // fn new_with_val() { + // new_wire!(1).set(1usize); + // } + + #[test] + fn new_with_val() { + new_wire_with_val!(0, 0usize); + new_wire_with_val!(1, 1usize); + new_wire_with_val!(2, 2usize); + new_wire_with_val!(2, 3usize); + new_wire_with_val!(3, 4usize); + new_wire_with_val!(4, 15usize); + new_wire_with_val!(32, 4_294_967_295usize); + new_wire_with_val!(33, 4_294_967_296usize); + } + + #[test] + #[should_panic] + fn not_enough_bits_1() { + new_wire_with_val!(0, 1usize); + } + #[test] - fn new_direct() { - Wire::<{ 1 }, { 1 }>::new(); - Wire::<{ 1 }, { num_bytes(1) }>::new(); + #[should_panic] + fn not_enough_bits_2() { + new_wire_with_val!(4, 16usize); } // #[test]