diff --git a/Cargo.toml b/Cargo.toml index b64411f..a6f6646 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bit-struct" -version = "0.3.0" +version = "0.4.0" edition = "2021" description = "Define structs which have fields which are assigned to individual bits, not bytes" repository = "https://github.com/parallel-systems/bit-struct" diff --git a/src/lib.rs b/src/lib.rs index 7c5a4e1..2b5a9dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -146,12 +146,12 @@ pub struct GetSet<'a, P, T, const START: usize, const STOP: usize> { impl<'a, P, T, const START: usize, const STOP: usize> GetSet<'a, P, T, START, STOP> { /// The bit offset at which this `GetSet` instance starts - pub const fn start(&self) -> usize { + #[must_use] pub const fn start(&self) -> usize { START } /// The bit offset at which this `GetSet` instance ends - pub const fn stop(&self) -> usize { + #[must_use] pub const fn stop(&self) -> usize { STOP } } @@ -206,7 +206,7 @@ impl< > GetSet<'a, P, T, START, STOP> { /// Get the property this `GetSet` points at - pub fn get(&self) -> T { + #[must_use] pub fn get(&self) -> T { let section = self.get_raw(); // Safety: // This is guaranteed to be safe because the underlying storage must be bigger @@ -216,14 +216,14 @@ impl< /// Returns true if the memory this `GetSet` points at is a valid /// representation of `T` - pub fn is_valid(&self) -> bool { + #[must_use] pub fn is_valid(&self) -> bool { let section = self.get_raw(); T::is_valid(section) } /// Get the raw bits being pointed at, without type conversion nor any form /// of validation - pub fn get_raw(&self) -> P { + #[must_use] pub fn get_raw(&self) -> P { let parent = *self.parent; let mask = self.mask(); (parent >> START) & mask @@ -373,7 +373,7 @@ macro_rules! bit_struct_impl { /// A bit struct which has a zero value we can get pub trait BitStructZero: Zero { /// Get a zero value for this bit struct - fn bs_zero() -> Self { + #[must_use] fn bs_zero() -> Self { Self::zero() } } @@ -540,6 +540,8 @@ macro_rules! bit_struct { impl $crate::BitStruct<{$(<$actual as $crate::ValidCheck<$kind>>::ALWAYS_VALID &&)* true}> for $name { type Kind = $kind; + /// # Safety + /// - This is implemented automatically by the bit-struct crate. unsafe fn from_unchecked(inner: $kind) -> Self { Self(unsafe {$crate::UnsafeStorage::new_unsafe(inner)}) } @@ -548,12 +550,16 @@ macro_rules! bit_struct { #[allow(clippy::used_underscore_binding)] impl $name { + /// # Safety + /// - This is implemented automatically by the bit-struct crate. unsafe fn from_unchecked(inner: $kind) -> Self { Self(unsafe {$crate::UnsafeStorage::new_unsafe(inner)}) } #[allow(clippy::too_many_arguments)] pub fn new($($field: $actual),*) -> Self { + // SAFETY: + // - This is implemented automatically by the bit-struct crate. let mut res = unsafe { Self::from_unchecked(<$kind as $crate::BitStructZero>::bs_zero()) }; $( res.$field().set($field); @@ -607,7 +613,7 @@ macro_rules! count_idents { /// assert_eq!(bits(5), 3); /// assert_eq!(bits(32), 6); /// ``` -pub const fn bits(num: usize) -> usize { +#[must_use] pub const fn bits(num: usize) -> usize { /// Helper function for [`bits`] const fn helper(count: usize, on: usize) -> usize { // 0b11 = 3 log2_ceil(0b11) = 2 .. 2^2 @@ -637,6 +643,7 @@ macro_rules! enum_impl { }; (VALID_CORE $name: ident: [$($kind: ty),*]) => { $( + #[allow(clippy::undocumented_unsafe_blocks, clippy::use_self)] unsafe impl $crate::ValidCheck<$kind> for $name { const ALWAYS_VALID: bool = >::ALWAYS_VALID; fn is_valid(value: $kind) -> bool { @@ -653,6 +660,7 @@ macro_rules! enum_impl { }; (VALID_BIT_STRUCT $name: ident: [$($kind: ty),*]) => { $( + #[allow(clippy::undocumented_unsafe_blocks, clippy::use_self)] unsafe impl $crate::ValidCheck<$kind> for $name { const ALWAYS_VALID: bool = >::ALWAYS_VALID; fn is_valid(value: $kind) -> bool { @@ -709,14 +717,19 @@ macro_rules! enum_impl { ),* } + /// # Safety + /// - This is implemented automatically by the bit-struct crate. + #[allow(clippy::use_self)] unsafe impl $crate::BitCount for $name { const COUNT: usize = $crate::bits($crate::count_idents!(0, [$($field),*])); } + #[allow(clippy::use_self)] impl $name { const VARIANT_COUNT: usize = $crate::enum_impl!(COUNT $fst_field $(,$field)*); } + #[allow(clippy::undocumented_unsafe_blocks, clippy::use_self)] unsafe impl $crate::ValidCheck for $name { const ALWAYS_VALID: bool = Self::VARIANT_COUNT.count_ones() == 1; fn is_valid(value: u8) -> bool { @@ -730,6 +743,7 @@ macro_rules! enum_impl { $crate::enum_impl!(FROM_IMPLS $name); + #[allow(clippy::use_self)] impl Default for $name { fn default() -> Self { Self::$default @@ -762,6 +776,7 @@ macro_rules! enum_impl { ),* } + #[allow(clippy::use_self)] impl Default for $name { fn default() -> Self { Self::$fst_field @@ -772,11 +787,12 @@ macro_rules! enum_impl { const VARIANT_COUNT: usize = $crate::enum_impl!(COUNT $fst_field $(,$field)*); } + #[allow(clippy::undocumented_unsafe_blocks)] unsafe impl $crate::BitCount for $name { const COUNT: usize = $crate::bits($crate::count_idents!(0, [$($field),*])); } - + #[allow(clippy::undocumented_unsafe_blocks)] unsafe impl $crate::ValidCheck for $name { const ALWAYS_VALID: bool = Self::VARIANT_COUNT.count_ones() == 1; diff --git a/src/types.rs b/src/types.rs index 0809ef6..9f44e9c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,7 +1,12 @@ //! New integer types used in this crate, and trait implementations for those //! types -use super::*; +use super::{ + serde, Add, BitAnd, BitAndAssign, BitCount, BitOr, BitOrAssign, BitXor, BitXorAssign, + BitsFitIn, Bounded, Debug, Display, Div, FieldStorage, Mul, Num, One, Rem, Shl, ShlAssign, Shr, + ShrAssign, Sub, ValidCheck, Zero, +}; +use crate::enums; use serde::{Deserializer, Serializer}; /// Assert that the given type is valid for any representation thereof @@ -54,6 +59,7 @@ impl_field_storage!( (u64, Self), (u128, Self), ); +/// helper macro to implement signed types macro_rules! impl_signed_field_storage { ($(($type:ty, $base:ty)),+ $(,)?) => { $( @@ -156,7 +162,7 @@ macro_rules! new_signed_types { /// Create a new $name from value /// # Safety /// - value must fit within the number of bits defined in the type - pub const unsafe fn new_unchecked(value: $signed) -> Self { + #[must_use] pub const unsafe fn new_unchecked(value: $signed) -> Self { let unsigned_value = value as $inner; if value >= 0 { Self(unsigned_value) @@ -171,7 +177,7 @@ macro_rules! new_signed_types { /// Create a new $name from value /// # Safety /// - value must fit within the number of bits defined in the type - pub fn new(value: $signed) -> Option { + #[must_use] pub fn new(value: $signed) -> Option { if (Self::MIN..=Self::MAX).contains(&value) { // SAFETY: // We've just checked that this is safe to call @@ -189,7 +195,7 @@ macro_rules! new_signed_types { pub const MIN: $signed = -(Self::MAX_UNSIGNED as $signed) - 1; /// Get the value stored in here, as a signed integer - pub const fn value(self) -> $signed { + #[must_use] pub const fn value(self) -> $signed { match self.0 >> ($count - 1) { 0 => self.0 as $signed, _ => { @@ -467,14 +473,14 @@ macro_rules! new_unsigned_types { /// /// # Safety /// The value must be valid value of the given type. - pub const unsafe fn new_unchecked(value: $inner) -> Self { + #[must_use] pub const unsafe fn new_unchecked(value: $inner) -> Self { Self(value) } #[doc = concat!("Create a new ", stringify!($name), " from an inner value")] /// /// This method checks that the inner value is valid, and return `None` if it isn't. - pub fn new(value: $inner) -> Option { + #[must_use] pub fn new(value: $inner) -> Option { if (Self::MIN..=Self::MAX).contains(&value) { // SAFETY: // We've checked that this is safe to do in the above `if` @@ -485,7 +491,7 @@ macro_rules! new_unsigned_types { } /// Get the stored value - pub const fn value(self) -> $inner { + #[must_use] pub const fn value(self) -> $inner { self.0 } } @@ -646,7 +652,7 @@ macro_rules! byte_from_impls { /// The size of byte array equal to the underlying storage for this value const SUPER_BYTES: usize = ::core::mem::size_of::<$super_kind>(); /// Convert from an array of bytes, in big-endian order - pub fn from_be_bytes(bytes: [u8; Self::ARR_SIZE]) -> Self { + #[must_use] pub fn from_be_bytes(bytes: [u8; Self::ARR_SIZE]) -> Self { let mut res_bytes = [0_u8; Self::SUPER_BYTES]; for (set, &get) in res_bytes.iter_mut().rev().zip(bytes.iter().rev()) { *set = get; @@ -655,7 +661,7 @@ macro_rules! byte_from_impls { } /// Convert `self` into an array of bytes, in big-endian order - pub fn to_be_bytes(self) -> [u8; Self::ARR_SIZE] { + #[must_use] pub fn to_be_bytes(self) -> [u8; Self::ARR_SIZE] { let mut res = [0; Self::ARR_SIZE]; let inner_bytes = self.0.to_be_bytes(); for (&get, set) in inner_bytes.iter().rev().zip(res.iter_mut().rev()) { @@ -665,7 +671,7 @@ macro_rules! byte_from_impls { } /// Convert from an array of bytes, in little-endian order - pub fn from_le_bytes(bytes: [u8; Self::ARR_SIZE]) -> Self { + #[must_use] pub fn from_le_bytes(bytes: [u8; Self::ARR_SIZE]) -> Self { let mut res_bytes = [0_u8; Self::SUPER_BYTES]; for (set, &get) in res_bytes.iter_mut().zip(bytes.iter()) { *set = get; @@ -674,7 +680,7 @@ macro_rules! byte_from_impls { } /// Convert `self` into an array of bytes, in little-endian order - pub fn to_le_bytes(self) -> [u8; Self::ARR_SIZE] { + #[must_use] pub fn to_le_bytes(self) -> [u8; Self::ARR_SIZE] { let mut res = [0; Self::ARR_SIZE]; let inner_bytes = self.0.to_le_bytes(); for (&get, set) in inner_bytes.iter().zip(res.iter_mut()) { @@ -724,6 +730,7 @@ impl u1 { /// Implement `BitsFitIn` for the given pair of types, using the given method macro_rules! bits_fit_in_impl { ($basety:ty => $target:ty : from) => { + #[allow(clippy::use_self)] impl BitsFitIn<$target> for $basety { fn fit(self) -> $target { self.inner_raw().into() @@ -731,6 +738,7 @@ macro_rules! bits_fit_in_impl { } }; ($basety:ty => $target:ty : new_unchecked) => { + #[allow(clippy::use_self)] impl BitsFitIn<$target> for $basety { fn fit(self) -> $target { // Safety: