mirror of
https://github.com/trussed-dev/cbor-smol.git
synced 2026-06-20 04:17:03 -07:00
Support multiple versions of heapless and heapless bytes
This allows better backwards compatibility and serializing to heapless directly. Given https://github.com/trussed-dev/cbor-smol/issues/11 I went with a breaking change update (the `Serializer` field was public and existing implementations are put behind a breaking change)
This commit is contained in:
committed by
sosthene-nitrokey
parent
3e9e218f55
commit
40708abdc5
+11
-3
@@ -13,16 +13,24 @@ categories = ["development-tools", "embedded"]
|
||||
|
||||
[dependencies]
|
||||
delog = "0.1.0-alpha.3"
|
||||
heapless = "0.7"
|
||||
heapless-bytes = "0.3"
|
||||
heapless-bytes-v0-3 = { package = "heapless-bytes", version = "0.3", optional = true }
|
||||
heapless-bytes-v0-4 = { package = "heapless-bytes", version = "0.4", optional = true }
|
||||
heapless-v0-7 = { package = "heapless", version = "0.7", optional = true }
|
||||
heapless-v0-8 = { package = "heapless", version = "0.8", optional = true }
|
||||
serde = { version = "1", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
heapless = { version = "0.7", features = ["serde"] }
|
||||
heapless-v0-8 = { package = "heapless", version = "0.8", features = ["serde"] }
|
||||
heapless-bytes-v0-4 = { package = "heapless-bytes", version = "0.4" }
|
||||
serde = { version = "1", default-features = false, features = ["derive"] }
|
||||
serde_bytes = "0.11.12"
|
||||
|
||||
[features]
|
||||
heapless-bytes-v0-3 = ["dep:heapless-bytes-v0-3"]
|
||||
heapless-bytes-v0-4 = ["dep:heapless-bytes-v0-4"]
|
||||
heapless-v0-7 = ["dep:heapless-v0-7"]
|
||||
heapless-v0-8 = ["dep:heapless-v0-8"]
|
||||
|
||||
log-all = []
|
||||
log-none = []
|
||||
log-info = []
|
||||
|
||||
@@ -812,7 +812,8 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||
// strings to fields (and the mapping from bytes to fields can be optimized out).
|
||||
let length = self.raw_deserialize_u32(major)? as usize;
|
||||
let bytes: &'de [u8] = self.try_take_n(length)?;
|
||||
let string_slice = core::str::from_utf8(bytes).map_err(|_| Error::DeserializeBadUtf8)?;
|
||||
let string_slice =
|
||||
core::str::from_utf8(bytes).map_err(|_| Error::DeserializeBadUtf8)?;
|
||||
visitor.visit_borrowed_str(string_slice)
|
||||
}
|
||||
MAJOR_POSINT => self.deserialize_u64(visitor),
|
||||
@@ -1054,17 +1055,28 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
not(feature = "heapless-bytes-v0-4"),
|
||||
ignore = "Enable heapless-bytes-v0-4 feature"
|
||||
)]
|
||||
#[test]
|
||||
fn de_bytes() {
|
||||
let mut buf = [0u8; 64];
|
||||
#[cfg(feature = "heapless-bytes-v0-4")]
|
||||
{
|
||||
let mut buf = [0u8; 64];
|
||||
|
||||
let slice = b"thank you postcard!";
|
||||
let bytes = crate::Bytes::<64>::from_slice(slice).unwrap();
|
||||
let ser = cbor_serialize(&bytes, &mut buf).unwrap();
|
||||
println!("serialized bytes = {:?}", ser);
|
||||
let de: crate::Bytes<64> = from_bytes(&buf).unwrap();
|
||||
println!("deserialized bytes = {:?}", &de);
|
||||
assert_eq!(&de, slice);
|
||||
let slice = b"thank you postcard!";
|
||||
let bytes = heapless_bytes_v0_4::Bytes::<64>::try_from(slice).unwrap();
|
||||
let ser = cbor_serialize(&bytes, &mut buf).unwrap();
|
||||
println!("serialized bytes = {:?}", ser);
|
||||
let de: heapless_bytes_v0_4::Bytes<64> = from_bytes(&buf).unwrap();
|
||||
println!("deserialized bytes = {:?}", &de);
|
||||
assert_eq!(&de, slice);
|
||||
}
|
||||
#[cfg(not(feature = "heapless-bytes-v0-4"))]
|
||||
{
|
||||
panic!("This test must be run with the heapless-v0-4 feature")
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1072,10 +1084,10 @@ mod tests {
|
||||
let mut buf = [0u8; 64];
|
||||
|
||||
let string_slice = "thank you postcard, for blazing the path 🐝";
|
||||
let mut string = heapless::String::<64>::new();
|
||||
let mut string = heapless_v0_8::String::<64>::new();
|
||||
string.push_str(string_slice).unwrap();
|
||||
let _n = cbor_serialize(&string, &mut buf);
|
||||
let de: heapless::String<64> = from_bytes(&buf).unwrap();
|
||||
let de: heapless_v0_8::String<64> = from_bytes(&buf).unwrap();
|
||||
assert_eq!(de, string_slice);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
use core::fmt::{Display, Formatter};
|
||||
|
||||
/// This is the Result type used by cbor-smol.
|
||||
pub type Result<T> = core::result::Result<T, Error>;
|
||||
pub type Result<T, Err = Error> = core::result::Result<T, Err>;
|
||||
|
||||
/// This is the error type used by cbor-smol
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
|
||||
+20
-16
@@ -4,38 +4,41 @@
|
||||
extern crate delog;
|
||||
generate_macros!();
|
||||
|
||||
pub use heapless_bytes::Bytes;
|
||||
|
||||
pub(crate) mod consts;
|
||||
pub mod de;
|
||||
pub mod error;
|
||||
pub mod ser;
|
||||
|
||||
pub use error::{Error, Result};
|
||||
use ser::Writer;
|
||||
|
||||
// pub use de::from_bytes;
|
||||
// pub use de::take_from_bytes;
|
||||
/// Serialize an object to a `Writer`
|
||||
///
|
||||
/// Returns the amount of bytes written to the writer
|
||||
pub fn cbor_serialize_to<'a, T: ?Sized + serde::Serialize, W: Writer>(
|
||||
object: &T,
|
||||
writer: W,
|
||||
) -> Result<usize> {
|
||||
let mut serializer = ser::Serializer::new(writer);
|
||||
object.serialize(&mut serializer)?;
|
||||
Ok(serializer.written())
|
||||
}
|
||||
|
||||
// kudos to postcard, this is much nicer than returning size
|
||||
pub fn cbor_serialize<'a, T: ?Sized + serde::Serialize>(
|
||||
object: &T,
|
||||
buffer: &'a mut [u8],
|
||||
) -> Result<&'a [u8]> {
|
||||
let writer = ser::SliceWriter::new(buffer);
|
||||
let mut ser = ser::Serializer::new(writer);
|
||||
|
||||
object.serialize(&mut ser)?;
|
||||
|
||||
let writer = ser.into_inner();
|
||||
let size = writer.bytes_written();
|
||||
|
||||
Ok(&buffer[..size])
|
||||
let mut buf = &mut *buffer;
|
||||
let written = cbor_serialize_to(object, &mut buf)?;
|
||||
Ok(&buffer[..written])
|
||||
}
|
||||
|
||||
#[cfg(feature = "heapless-bytes-v0-3")]
|
||||
/// Append serialization of object to existing bytes, returning length of serialized object.
|
||||
pub fn cbor_serialize_extending_bytes<T: ?Sized + serde::Serialize, const N: usize>(
|
||||
object: &T,
|
||||
bytes: &mut Bytes<N>,
|
||||
bytes: &mut heapless_bytes_v0_3::Bytes<N>,
|
||||
) -> Result<usize> {
|
||||
let len_before = bytes.len();
|
||||
let mut ser = ser::Serializer::new(bytes);
|
||||
@@ -45,11 +48,12 @@ pub fn cbor_serialize_extending_bytes<T: ?Sized + serde::Serialize, const N: usi
|
||||
Ok(ser.into_inner().len() - len_before)
|
||||
}
|
||||
|
||||
#[cfg(feature = "heapless-bytes-v0-3")]
|
||||
/// Serialize object into newly allocated Bytes.
|
||||
pub fn cbor_serialize_bytes<T: ?Sized + serde::Serialize, const N: usize>(
|
||||
object: &T,
|
||||
) -> Result<Bytes<N>> {
|
||||
let mut data = Bytes::<N>::new();
|
||||
) -> Result<heapless_bytes_v0_3::Bytes<N>> {
|
||||
let mut data = heapless_bytes_v0_3::Bytes::<N>::new();
|
||||
cbor_serialize_extending_bytes(object, &mut data)?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
+127
-56
@@ -2,6 +2,8 @@ use super::error::{Error, Result};
|
||||
use serde::ser;
|
||||
use serde::Serialize;
|
||||
|
||||
use core::mem;
|
||||
|
||||
use crate::consts::*;
|
||||
|
||||
// pub fn to_slice<'a, 'b, T>(value: &'a T, buf: &'b mut [u8]) -> Result<&'b mut [u8]>
|
||||
@@ -16,86 +18,157 @@ pub trait Writer {
|
||||
type Error: Into<Error>;
|
||||
|
||||
/// Attempts to write an entire buffer into this write.
|
||||
fn write_all(&mut self, buf: &[u8]) -> core::result::Result<(), Self::Error>;
|
||||
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SliceWriter<'a> {
|
||||
slice: &'a mut [u8],
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a> SliceWriter<'a> {
|
||||
/// Wraps a mutable slice so it can be used as a `Writer`.
|
||||
pub fn new(slice: &'a mut [u8]) -> SliceWriter<'a> {
|
||||
SliceWriter { slice, index: 0 }
|
||||
}
|
||||
|
||||
/// Returns the number of bytes written to the underlying slice.
|
||||
pub fn bytes_written(&self) -> usize {
|
||||
self.index
|
||||
}
|
||||
|
||||
/// Returns the underlying slice.
|
||||
pub fn into_inner(self) -> &'a mut [u8] {
|
||||
self.slice
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Writer for SliceWriter<'a> {
|
||||
impl<'a> Writer for &'a mut [u8] {
|
||||
type Error = Error;
|
||||
|
||||
fn write_all(&mut self, buf: &[u8]) -> Result<()> {
|
||||
fn write_all<'b>(&'b mut self, buf: &[u8]) -> Result<()> {
|
||||
let l = buf.len();
|
||||
if self.slice.len() - self.index < l {
|
||||
if self.len() < l {
|
||||
// This buffer will not fit in our slice
|
||||
return Err(Error::SerializeBufferFull(self.index));
|
||||
return Err(Error::SerializeBufferFull(0));
|
||||
}
|
||||
self.slice[self.index..][..l].copy_from_slice(buf);
|
||||
self.index += l;
|
||||
let (current, rem) = mem::take(self).split_at_mut(l);
|
||||
current.copy_from_slice(buf);
|
||||
*self = rem;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const N: usize> Writer for &'a mut crate::Bytes<N> {
|
||||
#[cfg(feature = "heapless-bytes-v0-3")]
|
||||
impl<const N: usize> Writer for heapless_bytes_v0_3::Bytes<N> {
|
||||
type Error = Error;
|
||||
|
||||
fn write_all(&mut self, buf: &[u8]) -> Result<()> {
|
||||
self.extend_from_slice(buf)
|
||||
.map_err(|_| Error::SerializeBufferFull(buf.len()))
|
||||
.or(Err(Error::SerializeBufferFull(self.len())))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Serializer<W>
|
||||
// where
|
||||
// W: Writer,
|
||||
{
|
||||
pub writer: W,
|
||||
#[cfg(feature = "heapless-bytes-v0-4")]
|
||||
impl<const N: usize> Writer for heapless_bytes_v0_4::Bytes<N> {
|
||||
type Error = Error;
|
||||
fn write_all(&mut self, buf: &[u8]) -> Result<()> {
|
||||
self.extend_from_slice(buf)
|
||||
.or(Err(Error::SerializeBufferFull(self.len())))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "heapless-v0-7")]
|
||||
impl<const N: usize> Writer for heapless_v0_7::Vec<u8, N> {
|
||||
type Error = Error;
|
||||
fn write_all(&mut self, buf: &[u8]) -> Result<()> {
|
||||
self.extend_from_slice(buf)
|
||||
.or(Err(Error::SerializeBufferFull(self.len())))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "heapless-v0-8")]
|
||||
impl<const N: usize> Writer for heapless_v0_8::Vec<u8, N> {
|
||||
type Error = Error;
|
||||
fn write_all(&mut self, buf: &[u8]) -> Result<()> {
|
||||
self.extend_from_slice(buf)
|
||||
.or(Err(Error::SerializeBufferFull(self.len())))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Writer> Writer for &'a mut T {
|
||||
type Error = T::Error;
|
||||
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
|
||||
(**self).write_all(buf)
|
||||
}
|
||||
}
|
||||
|
||||
// #[derive(Debug)]
|
||||
// pub struct SliceWriter<'a> {
|
||||
// slice: &'a mut [u8],
|
||||
// index: usize,
|
||||
// }
|
||||
|
||||
// impl<'a> SliceWriter<'a> {
|
||||
// /// Wraps a mutable slice so it can be used as a `Writer`.
|
||||
// pub fn new(slice: &'a mut [u8]) -> SliceWriter<'a> {
|
||||
// SliceWriter { slice, index: 0 }
|
||||
// }
|
||||
|
||||
// /// Returns the number of bytes written to the underlying slice.
|
||||
// pub fn bytes_written(&self) -> usize {
|
||||
// self.index
|
||||
// }
|
||||
|
||||
// /// Returns the underlying slice.
|
||||
// pub fn into_inner(self) -> &'a mut [u8] {
|
||||
// self.slice
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl<'a> Writer for SliceWriter<'a> {
|
||||
// type Error = Error;
|
||||
|
||||
// fn write_all(&mut self, buf: &[u8]) -> Result<()> {
|
||||
// let l = buf.len();
|
||||
// if self.slice.len() - self.index < l {
|
||||
// // This buffer will not fit in our slice
|
||||
// return Err(Error::SerializeBufferFull(self.index));
|
||||
// }
|
||||
// self.slice[self.index..][..l].copy_from_slice(buf);
|
||||
// self.index += l;
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl<'a, const N: usize> Writer for &'a mut crate::Bytes<N> {
|
||||
// type Error = Error;
|
||||
|
||||
// fn write_all(&mut self, buf: &[u8]) -> Result<()> {
|
||||
// self.extend_from_slice(buf)
|
||||
// .map_err(|_| Error::SerializeBufferFull(buf.len()))
|
||||
// }
|
||||
// }
|
||||
|
||||
struct WrittenWriter<W> {
|
||||
writer: W,
|
||||
written: usize,
|
||||
}
|
||||
|
||||
impl<W: Writer> Writer for WrittenWriter<W> {
|
||||
type Error = W::Error;
|
||||
|
||||
fn write_all(&mut self, buf: &[u8]) -> core::result::Result<(), Self::Error> {
|
||||
self.written += buf.len();
|
||||
self.writer.write_all(buf)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Serializer<W> {
|
||||
inner: WrittenWriter<W>,
|
||||
}
|
||||
|
||||
impl<W: Writer> Serializer<W> {
|
||||
#[inline]
|
||||
pub fn new(writer: W) -> Self {
|
||||
Serializer {
|
||||
writer,
|
||||
// packed: false,
|
||||
// enum_as_map: true,
|
||||
inner: WrittenWriter { writer, written: 0 },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn written(&self) -> usize {
|
||||
self.inner.written
|
||||
}
|
||||
|
||||
/// Unwrap the `Writer` from the `Serializer`.
|
||||
#[inline]
|
||||
pub fn into_inner(self) -> W {
|
||||
self.writer
|
||||
self.inner.writer
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u8(&mut self, major: u8, value: u8) -> Result<()> {
|
||||
if value <= 0x17 {
|
||||
self.writer.write_all(&[major << MAJOR_OFFSET | value])
|
||||
self.inner.write_all(&[major << MAJOR_OFFSET | value])
|
||||
} else {
|
||||
let buf = [major << MAJOR_OFFSET | 24, value];
|
||||
self.writer.write_all(&buf)
|
||||
self.inner.write_all(&buf)
|
||||
}
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
@@ -107,7 +180,7 @@ impl<W: Writer> Serializer<W> {
|
||||
} else {
|
||||
let mut buf = [major << MAJOR_OFFSET | 25, 0, 0];
|
||||
buf[1..].copy_from_slice(&value.to_be_bytes());
|
||||
self.writer.write_all(&buf).map_err(|e| e.into())
|
||||
self.inner.write_all(&buf).map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +191,7 @@ impl<W: Writer> Serializer<W> {
|
||||
} else {
|
||||
let mut buf = [major << MAJOR_OFFSET | 26, 0, 0, 0, 0];
|
||||
buf[1..].copy_from_slice(&value.to_be_bytes());
|
||||
self.writer.write_all(&buf).map_err(|e| e.into())
|
||||
self.inner.write_all(&buf).map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +202,7 @@ impl<W: Writer> Serializer<W> {
|
||||
} else {
|
||||
let mut buf = [major << MAJOR_OFFSET | 27, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
buf[1..].copy_from_slice(&value.to_be_bytes());
|
||||
self.writer.write_all(&buf).map_err(|e| e.into())
|
||||
self.inner.write_all(&buf).map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +218,7 @@ impl<W: Writer> Serializer<W> {
|
||||
false
|
||||
}
|
||||
None => {
|
||||
self.writer
|
||||
self.inner
|
||||
.write_all(&[major << MAJOR_OFFSET | 31])
|
||||
.map_err(|e| e.into())?;
|
||||
true
|
||||
@@ -186,7 +259,7 @@ where
|
||||
#[inline]
|
||||
fn serialize_bool(self, value: bool) -> Result<()> {
|
||||
let value = if value { VALUE_TRUE } else { VALUE_FALSE };
|
||||
self.writer.write_all(&[value]).map_err(|e| e.into())
|
||||
self.inner.write_all(&[value]).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -259,20 +332,18 @@ where
|
||||
#[inline]
|
||||
fn serialize_str(self, value: &str) -> Result<()> {
|
||||
self.write_u64(MAJOR_STR, value.len() as u64)?;
|
||||
self.writer
|
||||
.write_all(value.as_bytes())
|
||||
.map_err(|e| e.into())
|
||||
self.inner.write_all(value.as_bytes()).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_bytes(self, value: &[u8]) -> Result<()> {
|
||||
self.write_u64(MAJOR_BYTES, value.len() as u64)?;
|
||||
self.writer.write_all(value).map_err(|e| e.into())
|
||||
self.inner.write_all(value).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_none(self) -> Result<()> {
|
||||
self.writer.write_all(&[VALUE_NULL]).map_err(|e| e.into())
|
||||
self.inner.write_all(&[VALUE_NULL]).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -587,7 +658,7 @@ where
|
||||
#[inline]
|
||||
fn end_inner(self) -> Result<()> {
|
||||
if self.needs_eof {
|
||||
self.ser.writer.write_all(&[0xff]).map_err(|e| e.into())
|
||||
self.ser.inner.write_all(&[0xff]).map_err(|e| e.into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user