Skip to content

Commit

Permalink
Add at serializer to_slice (FactbirdHQ#161)
Browse files Browse the repository at this point in the history
This change removes the buffer size generic on the serializer.
  • Loading branch information
rmja authored Jul 6, 2023
1 parent 355671f commit c826e26
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 73 deletions.
2 changes: 1 addition & 1 deletion serde_at/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub use serde;
#[doc(inline)]
pub use self::de::{from_slice, from_str, hex_str::HexStr};
#[doc(inline)]
pub use self::ser::{to_string, to_vec, SerializeOptions};
pub use self::ser::{to_slice, to_string, to_vec, SerializeOptions};

use core::mem::MaybeUninit;

Expand Down
24 changes: 12 additions & 12 deletions serde_at/src/ser/enum_.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
use crate::ser::{Error, Result, Serializer};
use serde::ser;

pub struct SerializeTupleVariant<'a, 'b, const B: usize> {
ser: &'a mut Serializer<'b, B>,
pub struct SerializeTupleVariant<'a, 'b> {
ser: &'a mut Serializer<'b>,
first: bool,
}

impl<'a, 'b, const B: usize> SerializeTupleVariant<'a, 'b, B> {
pub(crate) fn new(ser: &'a mut Serializer<'b, B>) -> Self {
impl<'a, 'b> SerializeTupleVariant<'a, 'b> {
pub(crate) fn new(ser: &'a mut Serializer<'b>) -> Self {
SerializeTupleVariant { ser, first: true }
}
}

impl<'a, 'b, const B: usize> ser::SerializeTupleVariant for SerializeTupleVariant<'a, 'b, B> {
impl<'a, 'b> ser::SerializeTupleVariant for SerializeTupleVariant<'a, 'b> {
type Ok = ();
type Error = Error;

Expand All @@ -21,7 +21,7 @@ impl<'a, 'b, const B: usize> ser::SerializeTupleVariant for SerializeTupleVarian
T: ser::Serialize + ?Sized,
{
if !self.first {
self.ser.buf.push(b',')?;
self.ser.push(b',')?;
}
self.first = false;

Expand All @@ -34,18 +34,18 @@ impl<'a, 'b, const B: usize> ser::SerializeTupleVariant for SerializeTupleVarian
}
}

pub struct SerializeStructVariant<'a, 'b, const B: usize> {
ser: &'a mut Serializer<'b, B>,
pub struct SerializeStructVariant<'a, 'b> {
ser: &'a mut Serializer<'b>,
first: bool,
}

impl<'a, 'b, const B: usize> SerializeStructVariant<'a, 'b, B> {
pub(crate) fn new(ser: &'a mut Serializer<'b, B>) -> Self {
impl<'a, 'b> SerializeStructVariant<'a, 'b> {
pub(crate) fn new(ser: &'a mut Serializer<'b>) -> Self {
SerializeStructVariant { ser, first: true }
}
}

impl<'a, 'b, const B: usize> ser::SerializeStructVariant for SerializeStructVariant<'a, 'b, B> {
impl<'a, 'b> ser::SerializeStructVariant for SerializeStructVariant<'a, 'b> {
type Ok = ();
type Error = Error;

Expand All @@ -54,7 +54,7 @@ impl<'a, 'b, const B: usize> ser::SerializeStructVariant for SerializeStructVari
T: ser::Serialize + ?Sized,
{
if !self.first {
self.ser.buf.push(b',')?;
self.ser.push(b',')?;
}
self.first = false;

Expand Down
155 changes: 103 additions & 52 deletions serde_at/src/ser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,38 +57,48 @@ pub enum Error {
BufferFull,
}

impl From<()> for Error {
fn from(_: ()) -> Self {
Self::BufferFull
}
}

impl From<u8> for Error {
fn from(_: u8) -> Self {
Self::BufferFull
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Buffer is full")
}
}

pub(crate) struct Serializer<'a, const B: usize> {
buf: Vec<u8, B>,
pub(crate) struct Serializer<'a> {
buf: &'a mut [u8],
written: usize,
cmd: &'a str,
options: SerializeOptions<'a>,
}

impl<'a, const B: usize> Serializer<'a, B> {
fn new(cmd: &'a str, options: SerializeOptions<'a>) -> Self {
impl<'a> Serializer<'a> {
fn new(buf: &'a mut [u8], cmd: &'a str, options: SerializeOptions<'a>) -> Self {
Serializer {
buf: Vec::new(),
buf,
written: 0,
cmd,
options,
}
}

fn push(&mut self, c: u8) -> Result<()> {
if self.written < self.buf.len() {
self.buf[self.written] = c;
self.written += 1;
Ok(())
} else {
Err(Error::BufferFull)
}
}

fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> {
if self.written + other.len() <= self.buf.len() {
self.buf[self.written..self.written + other.len()].copy_from_slice(other);
self.written += other.len();
Ok(())
} else {
Err(Error::BufferFull)
}
}
}

// NOTE(serialize_*signed) This is basically the numtoa implementation minus the lookup tables,
Expand All @@ -112,7 +122,7 @@ macro_rules! serialize_unsigned {
// SAFETY: The buffer was initialized from `i` to the end.
let out = unsafe { super::slice_assume_init_ref(&buf[i..]) };

$self.buf.extend_from_slice(out)?;
$self.extend_from_slice(out)?;
Ok(())
}};
}
Expand Down Expand Up @@ -150,7 +160,7 @@ macro_rules! serialize_signed {
// SAFETY: The buffer was initialized from `i` to the end.
let out = unsafe { super::slice_assume_init_ref(&buf[i..]) };

$self.buf.extend_from_slice(out)?;
$self.extend_from_slice(out)?;
Ok(())
}};
}
Expand All @@ -159,27 +169,27 @@ macro_rules! serialize_fmt {
($self:ident, $N:expr, $fmt:expr, $v:expr) => {{
let mut s: String<$N> = String::new();
write!(&mut s, $fmt, $v).unwrap();
$self.buf.extend_from_slice(s.as_bytes())?;
$self.extend_from_slice(s.as_bytes())?;
Ok(())
}};
}

impl<'a, 'b, const B: usize> ser::Serializer for &'a mut Serializer<'b, B> {
impl<'a, 'b> ser::Serializer for &'a mut Serializer<'b> {
type Ok = ();
type Error = Error;
type SerializeSeq = Unreachable;
type SerializeTuple = Unreachable;
type SerializeTupleStruct = Unreachable;
type SerializeTupleVariant = SerializeTupleVariant<'a, 'b, B>;
type SerializeTupleVariant = SerializeTupleVariant<'a, 'b>;
type SerializeMap = Unreachable;
type SerializeStruct = SerializeStruct<'a, 'b, B>;
type SerializeStructVariant = SerializeStructVariant<'a, 'b, B>;
type SerializeStruct = SerializeStruct<'a, 'b>;
type SerializeStructVariant = SerializeStructVariant<'a, 'b>;

fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
if v {
self.buf.extend_from_slice(b"true")?;
self.extend_from_slice(b"true")?;
} else {
self.buf.extend_from_slice(b"false")?;
self.extend_from_slice(b"false")?;
}

Ok(())
Expand Down Expand Up @@ -236,32 +246,32 @@ impl<'a, 'b, const B: usize> ser::Serializer for &'a mut Serializer<'b, B> {
fn serialize_char(self, v: char) -> Result<Self::Ok> {
let mut encoding_tmp = [0_u8; 4];
let encoded = v.encode_utf8(&mut encoding_tmp as &mut [u8]);
self.buf.extend_from_slice(encoded.as_bytes())?;
self.extend_from_slice(encoded.as_bytes())?;
Ok(())
}

fn serialize_str(self, v: &str) -> Result<Self::Ok> {
if self.options.quote_escape_strings {
self.buf.push(b'"')?;
self.push(b'"')?;
}
let mut encoding_tmp = [0_u8; 4];
for c in v.chars() {
let encoded = c.encode_utf8(&mut encoding_tmp as &mut [u8]);
self.buf.extend_from_slice(encoded.as_bytes())?;
self.extend_from_slice(encoded.as_bytes())?;
}
if self.options.quote_escape_strings {
self.buf.push(b'"')?;
self.push(b'"')?;
}
Ok(())
}

fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok> {
self.buf.extend_from_slice(v)?;
self.extend_from_slice(v)?;
Ok(())
}

fn serialize_none(self) -> Result<Self::Ok> {
self.buf.truncate(self.buf.len() - 1);
self.written -= 1;
Ok(())
}

Expand All @@ -277,11 +287,9 @@ impl<'a, 'b, const B: usize> ser::Serializer for &'a mut Serializer<'b, B> {
}

fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok> {
self.buf
.extend_from_slice(self.options.cmd_prefix.as_bytes())?;
self.buf.extend_from_slice(self.cmd.as_bytes())?;
self.buf
.extend_from_slice(self.options.termination.as_bytes())?;
self.extend_from_slice(self.options.cmd_prefix.as_bytes())?;
self.extend_from_slice(self.cmd.as_bytes())?;
self.extend_from_slice(self.options.termination.as_bytes())?;
Ok(())
}

Expand Down Expand Up @@ -312,7 +320,7 @@ impl<'a, 'b, const B: usize> ser::Serializer for &'a mut Serializer<'b, B> {
T: ser::Serialize + ?Sized,
{
self.serialize_u32(variant_index)?;
self.buf.push(b',')?;
self.push(b',')?;
value.serialize(self)
}

Expand Down Expand Up @@ -340,7 +348,7 @@ impl<'a, 'b, const B: usize> ser::Serializer for &'a mut Serializer<'b, B> {
_len: usize,
) -> Result<Self::SerializeTupleVariant> {
self.serialize_u32(variant_index)?;
self.buf.push(b',')?;
self.push(b',')?;
Ok(SerializeTupleVariant::new(self))
}

Expand All @@ -349,9 +357,8 @@ impl<'a, 'b, const B: usize> ser::Serializer for &'a mut Serializer<'b, B> {
}

fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
self.buf
.extend_from_slice(self.options.cmd_prefix.as_bytes())?;
self.buf.extend_from_slice(self.cmd.as_bytes())?;
self.extend_from_slice(self.options.cmd_prefix.as_bytes())?;
self.extend_from_slice(self.cmd.as_bytes())?;
Ok(SerializeStruct::new(self))
}

Expand All @@ -363,7 +370,7 @@ impl<'a, 'b, const B: usize> ser::Serializer for &'a mut Serializer<'b, B> {
_len: usize,
) -> Result<Self::SerializeStructVariant> {
self.serialize_u32(variant_index)?;
self.buf.push(b',')?;
self.push(b',')?;
Ok(SerializeStructVariant::new(self))
}

Expand All @@ -373,33 +380,49 @@ impl<'a, 'b, const B: usize> ser::Serializer for &'a mut Serializer<'b, B> {
}

/// Serializes the given data structure as a string
pub fn to_string<T, const B: usize>(
pub fn to_string<T, const N: usize>(
value: &T,
cmd: &str,
options: SerializeOptions<'_>,
) -> Result<String<B>>
) -> Result<String<N>>
where
T: ser::Serialize + ?Sized,
{
let mut ser = Serializer::<B>::new(cmd, options);
value.serialize(&mut ser)?;
let vec: Vec<u8, N> = to_vec(value, cmd, options)?;
Ok(String::from(unsafe {
core::str::from_utf8_unchecked(&ser.buf)
core::str::from_utf8_unchecked(&vec)
}))
}

/// Serializes the given data structure as a byte vector
pub fn to_vec<T, const B: usize>(
pub fn to_vec<T, const N: usize>(
value: &T,
cmd: &str,
options: SerializeOptions<'_>,
) -> Result<Vec<u8, B>>
) -> Result<Vec<u8, N>>
where
T: ser::Serialize + ?Sized,
{
let mut ser = Serializer::new(cmd, options);
let mut buf = Vec::new();
buf.resize_default(N).map_err(|_| Error::BufferFull)?;
let len = to_slice(value, cmd, &mut buf, options)?;
buf.truncate(len);
Ok(buf)
}

/// Serializes the given data structure to a buffer
pub fn to_slice<T>(
value: &T,
cmd: &str,
buf: &mut [u8],
options: SerializeOptions<'_>,
) -> Result<usize>
where
T: ser::Serialize + ?Sized,
{
let mut ser = Serializer::new(buf, cmd, options);
value.serialize(&mut ser)?;
Ok(ser.buf)
Ok(ser.written)
}

impl ser::Error for Error {
Expand Down Expand Up @@ -547,6 +570,34 @@ mod tests {
assert_eq!(s, String::<32>::from("15"));
}

#[test]
fn struct_with_none_option() {
#[derive(Clone, PartialEq, Serialize)]
pub struct WithOption<'a> {
s: Option<&'a str>,
}

let value = WithOption { s: None };

let s: String<32> = to_string(&value, "+CMD", SerializeOptions::default()).unwrap();

assert_eq!(s, String::<32>::from("AT+CMD\r\n"));
}

#[test]
fn struct_with_some_option() {
#[derive(Clone, PartialEq, Serialize)]
pub struct WithOption<'a> {
s: Option<&'a str>,
}

let value = WithOption { s: Some("value") };

let s: String<32> = to_string(&value, "+CMD", SerializeOptions::default()).unwrap();

assert_eq!(s, String::<32>::from("AT+CMD=\"value\"\r\n"));
}

#[test]
fn byte_serialize() {
#[derive(Clone, PartialEq, Serialize)]
Expand Down
Loading

0 comments on commit c826e26

Please sign in to comment.