ser_write/
lib.rs

1//! Tools for implementing writer style serializers dedicated for `no_std` targets.
2//!
3//! Features a [trait][SerWrite] for objects which are byte-oriented sinks, akin to `std::io::Write`.
4//!
5//! Serializers can be implemented using this trait as a writer.
6//!
7//! Embedded or otherwise `no_std` projects can implement [`SerWrite`] for custom sinks.
8//!
9//! Some [implemenentations] for foreign types are provided depending on the enabled features.
10//!
11//! [implemenentations]: SerWrite#foreign-impls
12#![no_std]
13#![cfg_attr(not(test), forbid(unsafe_code))]
14#![cfg_attr(docsrs, feature(doc_cfg))]
15
16#[cfg(feature = "std")]
17extern crate std;
18
19#[cfg(all(feature = "alloc",not(feature = "std")))]
20extern crate alloc;
21
22use core::fmt;
23
24mod foreign;
25
26pub type SerResult<T> = Result<T, SerError>;
27
28/// A simple error type that can be used for [`SerWrite::Error`] implementations.
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
30#[non_exhaustive]
31pub enum SerError {
32    /// Buffer is full
33    BufferFull,
34}
35
36impl fmt::Display for SerError {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        match self {
39            SerError::BufferFull => f.write_str("buffer is full"),
40        }
41    }
42}
43
44impl core::error::Error for SerError {}
45
46/// Serializers should write data to the implementations of this trait.
47pub trait SerWrite {
48    /// An error type returned from the trait methods.
49    type Error;
50    /// Write **all** bytes from `buf` to the internal buffer.
51    ///
52    /// Otherwise return an error.
53    fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error>;
54    /// Write a single `byte` to the internal buffer.
55    ///
56    /// Return an error if the operation could not succeed.
57    #[inline]
58    fn write_byte(&mut self, byte: u8) -> Result<(), Self::Error> {
59        self.write(core::slice::from_ref(&byte))
60    }
61    /// Write a **whole** string to the internal buffer.
62    ///
63    /// Otherwise return an error.
64    #[inline]
65    fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
66        self.write(s.as_bytes())
67    }
68}
69
70impl<T: SerWrite> SerWrite for &'_ mut T {
71    type Error = T::Error;
72
73    #[inline(always)]
74    fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
75        (*self).write(buf)
76    }
77
78    #[inline(always)]
79    fn write_byte(&mut self, byte: u8) -> Result<(), Self::Error> {
80        (*self).write_byte(byte)
81    }
82
83    #[inline(always)]
84    fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
85        (*self).write_str(s)
86    }
87}
88
89/// A simple slice writer (example implementation)
90#[derive(Debug, PartialEq)]
91pub struct SliceWriter<'a> {
92    pub buf: &'a mut [u8],
93    pub len: usize
94}
95
96impl<'a> AsRef<[u8]> for SliceWriter<'a> {
97    /// Returns a populated portion of the slice
98    fn as_ref(&self) -> &[u8] {
99        &self.buf[..self.len]
100    }
101}
102
103impl<'a> AsMut<[u8]> for SliceWriter<'a> {
104    /// Returns a populated portion of the slice
105    fn as_mut(&mut self) -> &mut [u8] {
106        &mut self.buf[..self.len]
107    }
108}
109
110impl<'a> SliceWriter<'a> {
111    /// Create a new instance
112    pub fn new(buf: &'a mut [u8]) -> Self {
113        SliceWriter { buf, len: 0 }
114    }
115    /// Return populated length
116    pub fn len(&self) -> usize {
117        self.len
118    }
119    /// Return whether the output is not populated.
120    pub fn is_empty(&self) -> bool {
121        self.len == 0
122    }
123    /// Return total capacity of the container
124    pub fn capacity(&self) -> usize {
125        self.buf.len()
126    }
127    /// Return remaining free capacity
128    pub fn rem_capacity(&self) -> usize {
129        self.buf.len() - self.len
130    }
131    /// Reset cursor to the beginning of a container slice
132    pub fn clear(&mut self) {
133        self.len = 0;
134    }
135    /// Split the underlying buffer and return the portion of the populated buffer
136    /// with an underlying buffer's borrowed lifetime.
137    ///
138    /// Once a [`SliceWriter`] is dropped the slice stays borrowed as long as the
139    /// original container lives.
140    pub fn split(self) -> (&'a mut[u8], Self) {
141        let (res, buf) = self.buf.split_at_mut(self.len);
142        (res, Self { buf, len: 0 })
143    }
144}
145
146impl SerWrite for SliceWriter<'_> {
147    type Error = SerError;
148
149    fn write(&mut self, buf: &[u8]) -> SerResult<()> {
150        let end = self.len + buf.len();
151        match self.buf.get_mut(self.len..end) {
152            Some(chunk) => {
153                chunk.copy_from_slice(buf);
154                self.len = end;
155                Ok(())
156            }
157            None => Err(SerError::BufferFull)
158        }
159    }
160}
161
162impl<'a> fmt::Write for SliceWriter<'a> {
163    fn write_str(&mut self, s: &str) -> fmt::Result {
164        SerWrite::write_str(self, s).map_err(|_| fmt::Error)
165    }
166}
167
168#[cfg(test)]
169mod tests {
170    use core::fmt::Write;
171    use super::*;
172
173    #[test]
174    fn test_ser_error() {
175        #[cfg(feature = "std")]
176        {
177            assert_eq!(std::format!("{}", SerError::BufferFull), "buffer is full");
178        }
179        let mut buf = [0u8;0];
180        let mut writer = SliceWriter::new(&mut buf);
181        assert_eq!(write!(writer, "!"), Err(fmt::Error));
182    }
183
184    #[test]
185    fn test_slice_writer() {
186        let mut buf = [0u8;22];
187        let mut writer = SliceWriter::new(&mut buf);
188        assert_eq!(writer.capacity(), 22);
189        assert_eq!(writer.rem_capacity(), 22);
190        assert_eq!(writer.len(), 0);
191        assert_eq!(writer.is_empty(), true);
192        writer.write(b"Hello World!").unwrap();
193        assert_eq!(writer.rem_capacity(), 10);
194        assert_eq!(writer.len(), 12);
195        assert_eq!(writer.is_empty(), false);
196        writer.write_byte(b' ').unwrap();
197        assert_eq!(writer.rem_capacity(), 9);
198        assert_eq!(writer.len(), 13);
199        assert_eq!(writer.is_empty(), false);
200        SerWrite::write_str(&mut writer, "Good Bye!").unwrap();
201        let expected = b"Hello World! Good Bye!";
202        assert_eq!(writer.as_ref(), expected);
203        assert_eq!(writer.as_mut(), expected);
204        assert_eq!(writer.capacity(), 22);
205        assert_eq!(writer.rem_capacity(), 0);
206        assert_eq!(writer.is_empty(), false);
207        assert_eq!(writer.len(), 22);
208        let (head, mut writer) = writer.split();
209        assert_eq!(head, expected);
210        assert_eq!(writer.write_byte(b' ').unwrap_err(), SerError::BufferFull);
211    }
212}