diff --git a/rmp/Cargo.toml b/rmp/Cargo.toml index 07bad9ae..f0de45bc 100644 --- a/rmp/Cargo.toml +++ b/rmp/Cargo.toml @@ -13,6 +13,7 @@ edition = "2021" [dependencies] byteorder = { version = "1.4.2", default-features = false } +heapless = { version = "0.7.16", optional = true } num-traits = { version = "0.2.14", default-features = false } # This is macro_only ;) paste = "1.0" @@ -20,7 +21,9 @@ paste = "1.0" [features] default = ["std"] -std = ["byteorder/std", "num-traits/std"] +alloc = [] +heapless = ["dep:heapless"] +std = ["alloc", "byteorder/std", "num-traits/std"] [dev-dependencies] quickcheck = "1.0.2" diff --git a/rmp/src/encode/buffer.rs b/rmp/src/encode/buffer.rs index 8461897d..7213c4c2 100644 --- a/rmp/src/encode/buffer.rs +++ b/rmp/src/encode/buffer.rs @@ -3,7 +3,10 @@ use super::RmpWrite; #[cfg(not(feature = "std"))] use core::fmt::{self, Display, Formatter}; +#[cfg(feature="alloc")] use alloc::vec::Vec; +#[cfg(feature="heapless")] +use heapless::Vec; /// An error returned from writing to `&mut [u8]` (a byte buffer of fixed capacity) on no_std /// @@ -68,6 +71,8 @@ impl<'a> RmpWrite for &'a mut [u8] { } } +#[cfg(feature="heapless")] + /// A wrapper around `Vec` to serialize more efficiently. /// /// This has a specialized implementation of `RmpWrite` @@ -77,10 +82,12 @@ impl<'a> RmpWrite for &'a mut [u8] { /// This has the additional benefit of working on `#[no_std]` /// /// See also [serde_bytes::ByteBuf](https://docs.rs/serde_bytes/0.11/serde_bytes/struct.ByteBuf.html) +#[cfg(feature="alloc")] #[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct ByteBuf { bytes: Vec, } +#[cfg(feature="alloc")] impl ByteBuf { /// Construct a new empty buffer #[inline] @@ -120,29 +127,34 @@ impl ByteBuf { &self.bytes } } +#[cfg(feature="alloc")] impl AsRef<[u8]> for ByteBuf { fn as_ref(&self) -> &[u8] { &self.bytes } } +#[cfg(feature="alloc")] impl AsRef> for ByteBuf { #[inline] fn as_ref(&self) -> &Vec { &self.bytes } } +#[cfg(feature="alloc")] impl AsMut> for ByteBuf { #[inline] fn as_mut(&mut self) -> &mut Vec { &mut self.bytes } } +#[cfg(feature="alloc")] impl From for Vec { #[inline] fn from(buf: ByteBuf) -> Self { buf.bytes } } +#[cfg(feature="alloc")] impl From> for ByteBuf { #[inline] fn from(bytes: Vec) -> Self { @@ -150,6 +162,7 @@ impl From> for ByteBuf { } } +#[cfg(feature="alloc")] impl RmpWrite for ByteBuf { type Error = core::convert::Infallible; @@ -165,7 +178,7 @@ impl RmpWrite for ByteBuf { Ok(()) } } -#[cfg(not(feature = "std"))] +#[cfg(all(feature = "alloc", not(feature = "std")))] impl<'a> RmpWrite for Vec { type Error = core::convert::Infallible; @@ -181,4 +194,123 @@ impl<'a> RmpWrite for Vec { self.extend_from_slice(buf); Ok(()) } -} \ No newline at end of file +} + +#[cfg(feature="heapless")] +#[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct ByteBuf { + bytes: Vec, +} + +#[cfg(feature="heapless")] +impl ByteBuf { + /// Construct a new empty buffer + #[inline] + pub fn new() -> Self { + ByteBuf { bytes: Vec::new() } + } + /// Construct a new buffer with the specified capacity + /// + /// See [Vec::with_capacity] for details + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + assert!(capacity <= N); + ByteBuf { bytes: Vec::new() } + } + /// Unwrap the underlying buffer of this vector + #[inline] + pub fn into_vec(self) -> Vec { + self.bytes + } + /// Wrap the specified vector as a [ByteBuf] + #[inline] + pub fn from_vec(bytes: Vec) -> Self { + ByteBuf { bytes } + } + /// Get a reference to this type as a [Vec] + #[inline] + pub fn as_vec(&self) -> &Vec { + &self.bytes + } + /// Get a mutable reference to this type as a [Vec] + #[inline] + pub fn as_mut_vec(&mut self) -> &mut Vec { + &mut self.bytes + } + /// Get a reference to this type as a slice of bytes (`&[u8]`) + #[inline] + pub fn as_slice(&self) -> &[u8] { + &self.bytes + } +} +#[cfg(feature="heapless")] +impl AsRef<[u8]> for ByteBuf { + fn as_ref(&self) -> &[u8] { + &self.bytes + } +} +#[cfg(feature="heapless")] +impl AsRef> for ByteBuf { + #[inline] + fn as_ref(&self) -> &Vec { + &self.bytes + } +} +#[cfg(feature="heapless")] +impl AsMut> for ByteBuf { + #[inline] + fn as_mut(&mut self) -> &mut Vec { + &mut self.bytes + } +} +#[cfg(feature="heapless")] +impl From> for Vec { + #[inline] + fn from(buf: ByteBuf) -> Self { + buf.bytes + } +} +#[cfg(feature="heapless")] +impl From> for ByteBuf { + #[inline] + fn from(bytes: Vec) -> Self { + ByteBuf { bytes } + } +} + +#[cfg(feature="heapless")] +impl RmpWrite for ByteBuf { + type Error = core::convert::Infallible; + + #[inline] + fn write_u8(&mut self, val: u8) -> Result<(), Self::Error> { + // TODO: Error handling + self.bytes.push(val).unwrap(); + Ok(()) + } + + #[inline] + fn write_bytes(&mut self, buf: &[u8]) -> Result<(), Self::Error> { + // TODO: Error handling + self.bytes.extend_from_slice(buf).unwrap(); + Ok(()) + } +} +#[cfg(all(feature = "heapless", not(feature = "std")))] +impl<'a, const N: usize> RmpWrite for Vec { + type Error = core::convert::Infallible; + + #[inline] + fn write_u8(&mut self, val: u8) -> Result<(), Self::Error> { + // TODO: Error handling + self.push(val).unwrap(); + Ok(()) + } + + #[inline] + fn write_bytes(&mut self, buf: &[u8]) -> Result<(), Self::Error> { + // TODO: Error handling + self.extend_from_slice(buf).unwrap(); + Ok(()) + } +} diff --git a/rmp/src/encode/mod.rs b/rmp/src/encode/mod.rs index a35b86db..fb4d6f74 100644 --- a/rmp/src/encode/mod.rs +++ b/rmp/src/encode/mod.rs @@ -110,9 +110,14 @@ mod sealed{ impl Sealed for T {} #[cfg(not(feature = "std"))] impl Sealed for &mut [u8] {} - #[cfg(not(feature = "std"))] + #[cfg(all(feature = "alloc", not(feature = "std")))] impl Sealed for alloc::vec::Vec {} + #[cfg(all(feature = "alloc", not(feature = "std")))] impl Sealed for super::ByteBuf {} + #[cfg(all(feature = "heapless", not(feature = "std")))] + impl Sealed for heapless::Vec {} + #[cfg(all(feature = "heapless", not(feature = "std")))] + impl Sealed for super::ByteBuf {} } diff --git a/rmp/src/lib.rs b/rmp/src/lib.rs index ddee6cef..52b308b4 100644 --- a/rmp/src/lib.rs +++ b/rmp/src/lib.rs @@ -149,6 +149,7 @@ //! [read_int]: decode/fn.read_int.html #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature="alloc")] extern crate alloc; pub mod decode;