diff --git a/src/lib.rs b/src/lib.rs index 6b5845d..7a276d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,6 @@ use core::{ fmt::{self, Debug}, hash::{Hash, Hasher}, ops::{Deref, DerefMut}, - ptr, }; use heapless::Vec; @@ -20,7 +19,7 @@ use serde::{ ser::{Serialize, Serializer}, }; -#[derive(Clone, Default, Eq)] +#[derive(Clone, Default, Eq, Ord)] pub struct Bytes { bytes: Vec, } @@ -36,84 +35,150 @@ impl From> for Bytes { } } +impl From> for Vec { + fn from(value: Bytes) -> Self { + value.bytes + } +} + +impl TryFrom<&[u8]> for Bytes { + type Error = (); + fn try_from(value: &[u8]) -> Result { + Ok(Self { + bytes: Vec::from_slice(value)?, + }) + } +} + impl Bytes { /// Construct a new, empty `Bytes`. pub fn new() -> Self { Bytes::from(Vec::new()) } - /// Unwraps the Vec, same as `into_vec`. - pub fn into_inner(self) -> Vec { - self.bytes + pub fn as_ptr(&self) -> *const u8 { + self.bytes.as_ptr() } - /// Unwraps the Vec, same as `into_inner`. - pub fn into_vec(self) -> Vec { - self.bytes + pub fn as_mut_ptr(&mut self) -> *mut u8 { + self.bytes.as_mut_ptr() } - /// Returns an immutable slice view. - // Add as inherent method as it's annoying to import AsSlice. pub fn as_slice(&self) -> &[u8] { - self.bytes.as_ref() + self.bytes.as_slice() } - - /// Returns a mutable slice view. - // Add as inherent method as it's annoying to import AsSlice. pub fn as_mut_slice(&mut self) -> &mut [u8] { - self.bytes.as_mut() + self.bytes.as_mut_slice() } - /// Low-noise conversion between lengths. - /// - /// We can't implement TryInto since it would clash with blanket implementations. - pub fn try_convert_into(&self) -> Result, ()> { - Bytes::::from_slice(self) + pub const fn capacity(&self) -> usize { + self.bytes.capacity() } - // pub fn try_from_slice(slice: &[u8]) -> core::result::Result { - // let mut bytes = Vec::::new(); - // bytes.extend_from_slice(slice)?; - // Ok(Self::from(bytes)) - // } - - pub fn from_slice(slice: &[u8]) -> core::result::Result { - let mut bytes = Vec::::new(); - bytes.extend_from_slice(slice)?; - Ok(Self::from(bytes)) + pub fn clear(&mut self) { + self.bytes.clear() } - /// Some APIs offer an interface of the form `f(&mut [u8]) -> Result`, - /// with the contract that the Ok-value signals how many bytes were written. - /// - /// This constructor allows wrapping such interfaces in a more ergonomic way, - /// returning a Bytes willed using `f`. - /// - /// It seems it's not possible to do this as an actual `TryFrom` implementation. - pub fn try_from( - f: impl FnOnce(&mut [u8]) -> core::result::Result, - ) -> core::result::Result { - let mut data = Self::new(); - data.resize_to_capacity(); - let result = f(&mut data); - - result.map(|count| { - data.resize_default(count).unwrap(); - data - }) + #[deprecated(note = "Panics when out of capacity")] + pub fn extend>(&mut self, iter: I) { + self.bytes.extend(iter) } - // pub fn try_from<'a, E>( - // f: impl FnOnce(&'a mut [u8]) -> core::result::Result<&'a mut [u8], E> - // ) - // -> core::result::Result - // { + pub fn extend_from_slice(&mut self, other: &[u8]) -> Result<(), ()> { + self.bytes.extend_from_slice(other) + } + + pub fn pop(&mut self) -> Option { + self.bytes.pop() + } + + pub fn push(&mut self, byte: u8) -> Result<(), ()> { + self.bytes.push(byte).map_err(drop) + } + + pub unsafe fn pop_unchecked(&mut self) -> u8 { + unsafe { self.bytes.pop_unchecked() } + } + + pub unsafe fn push_unchecked(&mut self, byte: u8) { + unsafe { + self.bytes.push_unchecked(byte); + } + } + + pub fn truncate(&mut self, len: usize) { + self.bytes.truncate(len) + } + + pub fn resize(&mut self, new_len: usize, value: u8) -> Result<(), ()> { + self.bytes.resize(new_len, value) + } + + pub fn resize_zero(&mut self, new_len: usize) -> Result<(), ()> { + self.bytes.resize_default(new_len) + } + + pub unsafe fn set_len(&mut self, new_len: usize) { + self.bytes.set_len(new_len) + } + + pub fn swap_remove(&mut self, index: usize) -> u8 { + self.bytes.swap_remove(index) + } + + pub unsafe fn swap_remove_unchecked(&mut self, index: usize) -> u8 { + unsafe { self.bytes.swap_remove_unchecked(index) } + } + + pub fn is_full(&self) -> bool { + self.bytes.is_full() + } + + pub fn is_empty(&self) -> bool { + self.bytes.is_empty() + } + + pub fn starts_with(&self, needle: &[u8]) -> bool { + self.bytes.starts_with(needle) + } + pub fn ends_with(&self, needle: &[u8]) -> bool { + self.bytes.ends_with(needle) + } + + pub fn insert(&mut self, index: usize, value: u8) -> Result<(), ()> { + self.bytes.insert(index, value).map_err(drop) + } + + pub fn remove(&mut self, index: usize) -> u8 { + self.bytes.remove(index) + } + + pub fn retain(&mut self, f: impl FnMut(&u8) -> bool) { + self.bytes.retain(f) + } + pub fn retain_mut(&mut self, f: impl FnMut(&mut u8) -> bool) { + self.bytes.retain_mut(f) + } +} + +impl Bytes { + // /// Some APIs offer an interface of the form `f(&mut [u8]) -> Result`, + // /// with the contract that the Ok-value signals how many bytes were written. + // /// + // /// This constructor allows wrapping such interfaces in a more ergonomic way, + // /// returning a Bytes willed using `f`. + // /// + // /// It seems it's not possible to do this as an actual `TryFrom` implementation. + // pub fn from_constructor( + // f: impl FnOnce(&mut [u8]) -> core::result::Result, + // ) -> core::result::Result { // let mut data = Self::new(); // data.resize_to_capacity(); // let result = f(&mut data); // result.map(|count| { - // data.resize_default(count).unwrap(); + // data.resize_default(count) + // .expect("Contructor returned size larger than capacity"); // data // }) // } @@ -136,32 +201,32 @@ impl Bytes { Ok(()) } - pub fn insert(&mut self, index: usize, item: u8) -> Result<(), u8> { - self.insert_slice_at(&[item], index).map_err(|_| item) - } + // pub fn insert(&mut self, index: usize, item: u8) -> Result<(), u8> { + // self.insert_slice_at(&[item], index).map_err(|_| item) + // } - pub fn remove(&mut self, index: usize) -> Result { - if index < self.len() { - unsafe { Ok(self.remove_unchecked(index)) } - } else { - Err(()) - } - } + // pub fn remove(&mut self, index: usize) -> Result { + // if index < self.len() { + // unsafe { Ok(self.remove_unchecked(index)) } + // } else { + // Err(()) + // } + // } - pub(crate) unsafe fn remove_unchecked(&mut self, index: usize) -> u8 { - // the place we are taking from. - let p = self.bytes.as_mut_ptr().add(index); + // pub(crate) unsafe fn remove_unchecked(&mut self, index: usize) -> u8 { + // // the place we are taking from. + // let p = self.bytes.as_mut_ptr().add(index); - // copy it out, unsafely having a copy of the value on - // the stack and in the vector at the same time. - let ret = ptr::read(p); + // // copy it out, unsafely having a copy of the value on + // // the stack and in the vector at the same time. + // let ret = ptr::read(p); - // shift everything down to fill in that spot. - ptr::copy(p.offset(1), p, self.len() - index - 1); + // // shift everything down to fill in that spot. + // ptr::copy(p.offset(1), p, self.len() - index - 1); - self.resize_default(self.len() - 1).unwrap(); - ret - } + // self.resize_default(self.len() - 1).unwrap(); + // ret + // } pub fn resize_default(&mut self, new_len: usize) -> core::result::Result<(), ()> { self.bytes.resize_default(new_len) @@ -171,6 +236,13 @@ impl Bytes { self.bytes.resize_default(self.bytes.capacity()).ok(); } + /// Low-noise conversion between lengths. + /// + /// For an infaillible version when `M` is known to be larger than `N`, see [`increase_capacity`](Self::increase_capacity) + pub fn resize_capacity(&self) -> Result, ()> { + Bytes::try_from(&**self) + } + /// Copy the contents of this `Bytes` instance into a new instance with a higher capacity. /// /// ``` @@ -194,33 +266,6 @@ impl Bytes { bytes.extend_from_slice(self.as_slice()).unwrap(); bytes.into() } - - /// Fallible conversion into differently sized byte buffer. - pub fn to_bytes(&self) -> Result, ()> { - Bytes::::from_slice(self) - } - - #[cfg(feature = "cbor")] - pub fn from_serialized(t: &T) -> Self - where - T: Serialize, - { - let mut vec = Vec::::new(); - vec.resize_default(N).unwrap(); - let buffer = vec.deref_mut(); - - let writer = serde_cbor::ser::SliceWrite::new(buffer); - let mut ser = serde_cbor::Serializer::new(writer) - .packed_format() - // .pack_starting_with(1) - // .pack_to_depth(1) - ; - t.serialize(&mut ser).unwrap(); - let writer = ser.into_inner(); - let size = writer.bytes_written(); - vec.resize_default(size).unwrap(); - Self::from(vec) - } } /// Construct a `Bytes` instance from an array with `N` elements. @@ -324,7 +369,7 @@ impl AsMut<[u8]> for Bytes { } impl Deref for Bytes { - type Target = Vec; + type Target = [u8]; fn deref(&self) -> &Self::Target { &self.bytes @@ -337,18 +382,6 @@ impl DerefMut for Bytes { } } -// impl Borrow for Bytes { -// fn borrow(&self) -> &Bytes { -// Bytes::new(&self.bytes) -// } -// } - -// impl BorrowMut for Bytes { -// fn borrow_mut(&mut self) -> &mut Bytes { -// unsafe { &mut *(&mut self.bytes as &mut [u8] as *mut [u8] as *mut Bytes) } -// } -// } - impl PartialEq for Bytes where Rhs: ?Sized + AsRef<[u8]>, @@ -409,7 +442,18 @@ impl Serialize for Bytes { } } -// TODO: can we delegate to Vec deserialization instead of reimplementing? +impl core::fmt::Write for Bytes { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.bytes.write_str(s) + } + fn write_char(&mut self, s: char) -> fmt::Result { + self.bytes.write_char(s) + } + fn write_fmt(&mut self, s: core::fmt::Arguments<'_>) -> fmt::Result { + self.bytes.write_fmt(s) + } +} + impl<'de, const N: usize> Deserialize<'de> for Bytes { fn deserialize(deserializer: D) -> Result where @@ -445,6 +489,20 @@ impl<'de, const N: usize> Deserialize<'de> for Bytes { } Ok(Bytes::::from(buf)) } + + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + use serde::de::Error; + + let mut this = Bytes::new(); + while let Some(byte) = seq.next_element()? { + this.push(byte) + .map_err(|()| A::Error::invalid_length(this.len(), &self))?; + } + Ok(this) + } } deserializer.deserialize_bytes(ValueVisitor) @@ -466,9 +524,9 @@ mod tests_serde { bytes.push(1).unwrap(); assert_tokens(&bytes, &[Token::Bytes(&[1])]); assert!(bytes.extend_from_slice(&[2; 16]).is_err()); - assert_eq!(&**bytes, &[1]); + assert_eq!(&*bytes, &[1]); assert!(bytes.extend_from_slice(&[2; 15]).is_ok()); - assert_eq!(&**bytes, &[1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]); + assert_eq!(&*bytes, &[1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]); assert_tokens( &bytes, &[Token::Bytes(&[ @@ -481,7 +539,10 @@ mod tests_serde { fn display() { assert_eq!( r"b'\x00abcde\n'", - format!("{:?}", Bytes::<10>::from_slice(b"\0abcde\n").unwrap()) + format!( + "{:?}", + Bytes::<10>::try_from(b"\0abcde\n".as_slice()).unwrap() + ) ); } }