Skip to content

Commit

Permalink
Serializer: Factor-out slice writing to SerializerBackend trait impl
Browse files Browse the repository at this point in the history
This allows implementing different writing backends.
  • Loading branch information
elrafoon committed Jan 20, 2024
1 parent e695aa6 commit 985541e
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 29 deletions.
42 changes: 13 additions & 29 deletions src/ser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ use heapless::{String, Vec};

use self::map::SerializeMap;
use self::seq::SerializeSeq;
use self::ser_backend::{SerializerBackend, SliceSerializer};
use self::struct_::{SerializeStruct, SerializeStructVariant};

mod map;
mod seq;
mod struct_;
mod ser_backend;

/// Serialization result
pub type Result<T> = ::core::result::Result<T, Error>;
Expand Down Expand Up @@ -49,50 +51,31 @@ impl fmt::Display for Error {
}
}


/// A structure that serializes Rust values as JSON into a buffer.
pub struct Serializer<'a> {
buf: &'a mut [u8],
current_length: usize,
backend: &'a mut dyn SerializerBackend
}

impl<'a> Serializer<'a> {
/// Create a new `Serializer`
pub fn new(buf: &'a mut [u8]) -> Self {
Serializer {
buf,
current_length: 0,
pub fn new(backend: &'a mut dyn SerializerBackend) -> Self {
Self {
backend
}
}

/// Return the current amount of serialized data in the buffer
pub fn end(&self) -> usize {
self.current_length
self.backend.end()
}

fn push(&mut self, c: u8) -> Result<()> {
if self.current_length < self.buf.len() {
unsafe { self.push_unchecked(c) };
Ok(())
} else {
Err(Error::BufferFull)
}
}

unsafe fn push_unchecked(&mut self, c: u8) {
self.buf[self.current_length] = c;
self.current_length += 1;
self.backend.push(c)
}

fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> {
if self.current_length + other.len() > self.buf.len() {
// won't fit in the buf; don't modify anything and return an error
Err(Error::BufferFull)
} else {
for c in other {
unsafe { self.push_unchecked(*c) };
}
Ok(())
}
self.backend.extend_from_slice(other)
}
}

Expand Down Expand Up @@ -469,9 +452,10 @@ pub fn to_slice<T>(value: &T, buf: &mut [u8]) -> Result<usize>
where
T: ser::Serialize + ?Sized,
{
let mut ser = Serializer::new(buf);
let mut backend = SliceSerializer::new(buf);
let mut ser = Serializer::new(&mut backend);
value.serialize(&mut ser)?;
Ok(ser.current_length)
Ok(backend.current_length)
}

impl ser::Error for Error {
Expand Down
55 changes: 55 additions & 0 deletions src/ser/ser_backend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use super::{Result, Error};

pub trait SerializerBackend {
/// Return the current amount of serialized data in the buffer
fn end(&self) -> usize;
fn push(&mut self, c: u8) -> Result<()>;
fn extend_from_slice(&mut self, other: &[u8]) -> Result<()>;
}

pub struct SliceSerializer<'a> {
buf: &'a mut [u8],
pub(crate) current_length: usize,
}

impl<'a> SliceSerializer<'a> {
/// Create a new `Serializer`
pub fn new(buf: &'a mut [u8]) -> Self {
Self {
buf,
current_length: 0,
}
}

unsafe fn push_unchecked(&mut self, c: u8) {
self.buf[self.current_length] = c;
self.current_length += 1;
}
}

impl<'a> SerializerBackend for SliceSerializer<'a> {
fn end(&self) -> usize {
self.current_length
}

fn push(&mut self, c: u8) -> Result<()> {
if self.current_length < self.buf.len() {
unsafe { self.push_unchecked(c) };
Ok(())
} else {
Err(Error::BufferFull)
}
}

fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> {
if self.current_length + other.len() > self.buf.len() {
// won't fit in the buf; don't modify anything and return an error
Err(Error::BufferFull)
} else {
for c in other {
unsafe { self.push_unchecked(*c) };
}
Ok(())
}
}
}

0 comments on commit 985541e

Please sign in to comment.