diff --git a/src/btreemap.rs b/src/btreemap.rs index b06a7f65..1e73232c 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -353,7 +353,7 @@ where /// key.to_bytes().len() <= max_size(Key) /// value.to_bytes().len() <= max_size(Value) pub fn insert(&mut self, key: K, value: V) -> Option { - let value = value.to_bytes_checked().into_owned(); + let value = value.into_bytes_checked(); let root = if self.root_addr == NULL { // No root present. Allocate one. diff --git a/src/storable.rs b/src/storable.rs index 8ae6ddec..d1acd406 100644 --- a/src/storable.rs +++ b/src/storable.rs @@ -10,7 +10,7 @@ mod tuples; mod tests; /// A trait with convenience methods for storing an element into a stable structure. -pub trait Storable { +pub trait Storable: Sized { /// Converts an element into bytes. /// /// NOTE: `Cow` is used here to avoid unnecessary cloning. @@ -22,36 +22,55 @@ pub trait Storable { /// The size bounds of the type. const BOUND: Bound; + /// Consumes self and converts it into bytes. + /// Uses `to_bytes` by default. + fn into_bytes(self) -> Vec { + self.to_bytes().into_owned() + } + /// Like `to_bytes`, but includes additional checks to ensure the element's serialized bytes /// are within the element's bounds. fn to_bytes_checked(&self) -> Cow<[u8]> { let bytes = self.to_bytes(); - if let Bound::Bounded { - max_size, - is_fixed_size, - } = Self::BOUND - { - if is_fixed_size { - assert_eq!( - bytes.len(), - max_size as usize, - "expected a fixed-size element with length {} bytes, but found {} bytes", - max_size, - bytes.len() - ); - } else { - assert!( - bytes.len() <= max_size as usize, - "expected an element with length <= {} bytes, but found {} bytes", - max_size, - bytes.len() - ); - } - } + check_bounds(&bytes, Self::BOUND); + bytes + } + + /// Like `into_bytes`, but includes additional checks to ensure the element's serialized bytes + /// are within the element's bounds. + fn into_bytes_checked(self) -> Vec { + let bytes = self.into_bytes(); + check_bounds(&bytes, Self::BOUND); bytes } } +#[inline] +fn check_bounds(bytes: &[u8], bounds: Bound) { + if let Bound::Bounded { + max_size, + is_fixed_size, + } = bounds + { + if is_fixed_size { + assert_eq!( + bytes.len(), + max_size as usize, + "expected a fixed-size element with length {} bytes, but found {} bytes", + max_size, + bytes.len() + ); + } else { + assert!( + bytes.len() <= max_size as usize, + "expected an element with length <= {} bytes, but found {} bytes", + max_size, + bytes.len() + ); + } + } +} + #[derive(Debug, PartialEq)] /// States whether the type's size is bounded or unbounded. pub enum Bound { @@ -227,6 +246,10 @@ impl Storable for Vec { bytes.to_vec() } + fn into_bytes(self) -> Vec { + self + } + const BOUND: Bound = Bound::Unbounded; }