Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add heapless-backed ByteBuf #340

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion rmp/Cargo.toml
Expand Up @@ -13,14 +13,17 @@ 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"


[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"
Expand Down
136 changes: 134 additions & 2 deletions rmp/src/encode/buffer.rs
Expand Up @@ -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
///
Expand Down Expand Up @@ -68,6 +71,8 @@ impl<'a> RmpWrite for &'a mut [u8] {
}
}

#[cfg(feature="heapless")]

/// A wrapper around `Vec<u8>` to serialize more efficiently.
///
/// This has a specialized implementation of `RmpWrite`
Expand All @@ -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<u8>,
}
#[cfg(feature="alloc")]
impl ByteBuf {
/// Construct a new empty buffer
#[inline]
Expand Down Expand Up @@ -120,36 +127,42 @@ impl ByteBuf {
&self.bytes
}
}
#[cfg(feature="alloc")]
impl AsRef<[u8]> for ByteBuf {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
#[cfg(feature="alloc")]
impl AsRef<Vec<u8>> for ByteBuf {
#[inline]
fn as_ref(&self) -> &Vec<u8> {
&self.bytes
}
}
#[cfg(feature="alloc")]
impl AsMut<Vec<u8>> for ByteBuf {
#[inline]
fn as_mut(&mut self) -> &mut Vec<u8> {
&mut self.bytes
}
}
#[cfg(feature="alloc")]
impl From<ByteBuf> for Vec<u8> {
#[inline]
fn from(buf: ByteBuf) -> Self {
buf.bytes
}
}
#[cfg(feature="alloc")]
impl From<Vec<u8>> for ByteBuf {
#[inline]
fn from(bytes: Vec<u8>) -> Self {
ByteBuf { bytes }
}
}

#[cfg(feature="alloc")]
impl RmpWrite for ByteBuf {
type Error = core::convert::Infallible;

Expand All @@ -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<u8> {
type Error = core::convert::Infallible;

Expand All @@ -181,4 +194,123 @@ impl<'a> RmpWrite for Vec<u8> {
self.extend_from_slice(buf);
Ok(())
}
}
}

#[cfg(feature="heapless")]
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct ByteBuf<const N: usize> {
bytes: Vec<u8, N>,
}

#[cfg(feature="heapless")]
impl<const N: usize> ByteBuf<N> {
/// 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<u8, N> {
self.bytes
}
/// Wrap the specified vector as a [ByteBuf]
#[inline]
pub fn from_vec(bytes: Vec<u8, N>) -> Self {
ByteBuf { bytes }
}
/// Get a reference to this type as a [Vec]
#[inline]
pub fn as_vec(&self) -> &Vec<u8, N> {
&self.bytes
}
/// Get a mutable reference to this type as a [Vec]
#[inline]
pub fn as_mut_vec(&mut self) -> &mut Vec<u8, N> {
&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<const N: usize> AsRef<[u8]> for ByteBuf<N> {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
#[cfg(feature="heapless")]
impl<const N: usize> AsRef<Vec<u8, N>> for ByteBuf<N> {
#[inline]
fn as_ref(&self) -> &Vec<u8, N> {
&self.bytes
}
}
#[cfg(feature="heapless")]
impl<const N: usize> AsMut<Vec<u8, N>> for ByteBuf<N> {
#[inline]
fn as_mut(&mut self) -> &mut Vec<u8, N> {
&mut self.bytes
}
}
#[cfg(feature="heapless")]
impl<const N: usize> From<ByteBuf<N>> for Vec<u8, N> {
#[inline]
fn from(buf: ByteBuf<N>) -> Self {
buf.bytes
}
}
#[cfg(feature="heapless")]
impl<const N: usize> From<Vec<u8, N>> for ByteBuf<N> {
#[inline]
fn from(bytes: Vec<u8, N>) -> Self {
ByteBuf { bytes }
}
}

#[cfg(feature="heapless")]
impl<const N: usize> RmpWrite for ByteBuf<N> {
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<u8, N> {
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(())
}
}
7 changes: 6 additions & 1 deletion rmp/src/encode/mod.rs
Expand Up @@ -110,9 +110,14 @@ mod sealed{
impl<T: ?Sized + std::io::Write> 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<u8> {}
#[cfg(all(feature = "alloc", not(feature = "std")))]
impl Sealed for super::ByteBuf {}
#[cfg(all(feature = "heapless", not(feature = "std")))]
impl<const N: usize> Sealed for heapless::Vec<u8, N> {}
#[cfg(all(feature = "heapless", not(feature = "std")))]
impl<const N: usize> Sealed for super::ByteBuf<N> {}
}


Expand Down
1 change: 1 addition & 0 deletions rmp/src/lib.rs
Expand Up @@ -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;
Expand Down