diff options
-rw-r--r-- | CHANGELOG.md | 35 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | README.md | 13 | ||||
-rw-r--r-- | bzipper.svg | 17 | ||||
-rw-r--r-- | src/buffer/mod.rs | 172 | ||||
-rw-r--r-- | src/deserialise/mod.rs | 92 | ||||
-rw-r--r-- | src/deserialise/test.rs | 16 | ||||
-rw-r--r-- | src/dstream/mod.rs | 59 | ||||
-rw-r--r-- | src/error/mod.rs | 32 | ||||
-rw-r--r-- | src/fixed_string/mod.rs | 46 | ||||
-rw-r--r-- | src/fixed_string/test.rs | 2 | ||||
-rw-r--r-- | src/lib.rs | 14 | ||||
-rw-r--r-- | src/serialise/mod.rs | 559 | ||||
-rw-r--r-- | src/serialise/test.rs | 53 | ||||
-rw-r--r-- | src/sstream/mod.rs | 99 |
15 files changed, 834 insertions, 377 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 67c5a1d..bf2ecba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,27 @@ -# 0.3.0 +# Changelog + +This is the changelog of `bzipper`. + +## 0.4.0 + +* Add logo +* Clean up code +* Fix array deserialisation (require `Default`) +* Bump minor +* Update commenting +* Make serialisations fallible +* Impl `Serialise` and `Deserialise` for `usize` and `isize` (restrict to 16 bits) +* Add new errors: `UsizeOutOfRange`, `IsizeOutOfRange` +* Rework sstreams +* Add buffer type +* Fix serialisation of `Option<T>` +* Disable `std` +* Rename error: `EndOfDStream` -> `EndOfStream` +* Update documentation +* Update readme +* Reformat changelog + +## 0.3.0 * Bump minor * Document errors @@ -17,7 +40,7 @@ * Make `Deserialise` require `Serialise` * Fix copyright/license notice in `"src/serialise/test.rs"` -# 0.2.0 +## 0.2.0 * Clean up code * Implement `Ord` and `PartialOrd` for `FixedString` @@ -27,7 +50,7 @@ * Bump minor * Implement `Serialise` and `Deserialise` for tuples -# 0.1.0 +## 0.1.0 * Bump minor * Export all in crate root @@ -37,17 +60,17 @@ * Add `as_d_stream` method to `SStream` * Add `to_s_stream` and `as_slice` methods to `DStream` -# 0.0.2 +## 0.0.2 * Add license files -# 0.0.1 +## 0.0.1 * Fix copyright notices * Add license notices * Update readme -# 0.0.0 +## 0.0.0 * Add changelog * Fork from `backspace` @@ -1,6 +1,6 @@ [package] name = "bzipper" -version = "0.3.0" +version = "0.4.0" authors = ["Gabriel Bjørnager Jensen"] edition = "2021" description = "Binary (de)serialiser." @@ -1,3 +1,5 @@ +# 'bzipper` + [`bzipper`](https://crates.io/crates/bzipper) is a binary (de)serialiser for the Rust language. Contrary to [Serde](https://crates.io/crates/serde/)/[Bincode](https://crates.io/crates/bincode/), the goal of this crate is to serialise data with a known size limit. @@ -7,7 +9,16 @@ Keep in mind that this project is still work-in-progress. This crate does not require any dependencies at the moment. -# Copyright & Licensing +## Data Model + +Most primitive types serialise losslessly, with the exception being `usize` and `isize`. +These serialise as `u16` and `i16`, respectively, for portability reasons. + +Unsized types, such as `str` and slices, are not supported. +Instead, array should be used. +For strings, the `FixedString` type is also provided. + +## Copyright & Licensing Copyright 2024 Gabriel Bjørnager Jensen. diff --git a/bzipper.svg b/bzipper.svg new file mode 100644 index 0000000..762e587 --- /dev/null +++ b/bzipper.svg @@ -0,0 +1,17 @@ +<svg height="96" width="96" xmlns="http://www.w3.org/2000/svg"> + <!-- gradients: --> + + <!-- clips: --> + + <!-- masks: --> + + <mask id="z"> + <polyline fill="none" points="20,28 20,20 78,20 36.970562748,76" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" /> + <polyline fill="none" points="76,68 76,76 20,76 59.029437252,20" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" /> + </mask> + + <!-- fills: --> + + <rect fill="#FFFFFF" mask="" height="96" width="96" x="0" y="0" /> + <rect fill="#B4202D" mask="url(#z)" height="96" width="96" x="0" y="0" /> +</svg> diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs new file mode 100644 index 0000000..3ce47bd --- /dev/null +++ b/src/buffer/mod.rs @@ -0,0 +1,172 @@ +// Copyright 2024 Gabriel Bjørnager Jensen. +// +// This file is part of bzipper. +// +// bzipper is free software: you can redistribute +// it and/or modify it under the terms of the GNU +// Lesser General Public License as published by +// the Free Software Foundation, either version 3 +// of the License, or (at your option) any later +// version. +// +// bzipper is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without +// even the impl<T: Serialise>ied warranty of MERCHANTABILITY<T> or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Less- +// er General Public License along with bzipper. If +// not, see <https://www.gnu.org/licenses/>. + +use crate::{Deserialise, Dstream, Serialise, Sstream}; + +use alloc::vec; +use alloc::boxed::Box; +use core::fmt::{Debug, Formatter}; +use core::marker::PhantomData; + +/// Container type for (de)serialisations. +/// +/// The purpose of this type is to easily hold a buffer than can fit any serialisation of a given type (hence the generic). +/// +/// Do note that the internal buffer does not guarantee the state of any padding bytes that occur as a result of different serialisation sizes. +/// Deserialisations, however, are not affected by these. +#[derive(Clone, Eq, PartialEq)] +pub struct Buffer<T> { + data: Box<[u8]>, + len: usize, + + _phantom: PhantomData<T>, +} + +impl<T> Buffer<T> { + /// Sets the internal length of the buffer without checks. + /// + /// For a safe alternative, see [`set_len`](Self::set_len). + /// + /// # Safety + /// + /// The new length must **not** exceed [`T::SERIALISE_LIMIT`](Serialise::SERIALISE_LIMIT). + #[inline(always)] + pub unsafe fn set_len_unchecked(&mut self, len: usize) { + self.len = len; + } + + /// Returns a slice of the internal buffer. + /// + /// This only includes bytes written by the last serialisation, or as set by [`set_len`](Self::set_len). + #[inline(always)] + #[must_use] + pub fn as_slice(&self) -> &[u8] { &self.data[0x0..self.len] } + + /// Returns a mutable slice of the entire internal buffer. + /// + /// This is in contrast to [`as_slice`](Self::as_slice), which only yields the last serialisation. + /// + /// The length of bytes written to this slice should be set using [`set_len`](Self::set_len). + #[inline(always)] + #[must_use] + pub fn as_mut_slice(&mut self) -> &mut [u8] { self.data.as_mut() } +} + +impl<T: Serialise> Buffer<T> { + /// Constructs a new, empty buffer. + /// + /// The internal buffer is allocated on the heap instantly with the size [`T::SERIALISE_LIMIT`](Serialise::SERIALISE_LIMIT). + #[inline(always)] + #[must_use] + pub fn new() -> Self { Self { + data: vec![Default::default(); T::SERIALISE_LIMIT].into(), + len: 0x0, + + _phantom: PhantomData + } } + + /// Sets the length of the current serialisation. + /// + /// This is specifically meant for cases where the buffer is set externally, as is the case for networking: + /// + /// ``` + /// use bzipper::{Buffer, FixedString}; + /// use std::net::{SocketAddr, UdpSocket}; + /// use std::str::FromStr; + /// + /// let destination = SocketAddr::from_str("127.0.0.1:37279")?; + /// + /// let sender = UdpSocket::bind("0.0.0.0:0")?; + /// let reciever = UdpSocket::bind(destination)?; + /// + /// // Create a buffer for holding a fixed string. + /// let mut buffer = Buffer::<FixedString<0x10>>::new(); + /// + /// // Serialise and write the string: + /// buffer.write(&FixedString::new("Hello there!")?); + /// sender.send_to(buffer.as_ref(), destination); + /// + /// // Recieve and deserialise the string: + /// let (count, _source) = reciever.recv_from(buffer.as_mut_slice())?; + /// buffer.set_len(count); + /// + /// assert_eq!(buffer.read()?, "Hello there!"); + /// + /// # Ok::<(), Box<dyn std::error::Error>>(()) + /// ``` + /// + /// # Panics + /// + /// Panics if `len` is larger than [`T::SERIALISE_LIMIT`](Serialise::SERIALISE_LIMIT). + /// See [`set_len_unchecked`](Self::set_len_unchecked). + #[inline] + pub fn set_len(&mut self, len: usize) { + assert!(len <= T::SERIALISE_LIMIT); + self.len = len; + } +} + +impl<T: Serialise> Buffer<T> { + /// Serialises into the buffer. + /// + /// The result of [`serialise`](Serialise::serialise) is used as the length. + /// + /// # Panics + /// + /// Panics if the amount of written bytes exceeds [`SERIALISE_LIMIT`](Serialise::SERIALISE_LIMIT). + /// This *should*, in theory, not occur, as the internal buffer can only fit up to this limit, making all writes past this limit fail. + #[allow(clippy::panic_in_result_fn)] + pub fn write(&mut self, value: &T) -> Result<(), <T as Serialise>::Error> { + let mut stream = Sstream::new(&mut self.data); + + let count = value.serialise(&mut stream)?; + assert!(count <= T::SERIALISE_LIMIT); + + self.len = count; + Ok(()) + } +} + +impl<T: Deserialise> Buffer<T> { + /// Deserialises the contained buffer. + /// + /// Only bytes from the last serialisation, or as set by [`set_len`](Self::set_len), are used. + pub fn read(&self) -> Result<T, <T as Deserialise>::Error> { + let mut stream = Dstream::new(self.as_ref()); + T::deserialise(&mut stream) + } +} + +impl<T> AsRef<[u8]> for Buffer<T> { + #[inline(always)] + fn as_ref(&self) -> &[u8] { self.as_slice() } +} + +impl<T> Debug for Buffer<T> { + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + self.data.fmt(f) + } +} + +impl<T: Serialise> Default for Buffer<T> { + #[inline(always)] + fn default() -> Self { Self::new() } +} diff --git a/src/deserialise/mod.rs b/src/deserialise/mod.rs index 59e2b69..eaebe2b 100644 --- a/src/deserialise/mod.rs +++ b/src/deserialise/mod.rs @@ -22,20 +22,25 @@ #[cfg(test)] mod test; -use crate::{Dstream, Error, Serialise}; - -use std::convert::Infallible; -use std::error::Error as StdError; -use std::mem::size_of; -use std::num::NonZero; - -/// Denotes a type capable of being deserialised. -pub trait Deserialise: Serialise + Sized { +use crate::{Error, Dstream}; + +use alloc::boxed::Box; +use core::convert::Infallible; +use core::error::Error as StdError; +use core::mem::{MaybeUninit, size_of}; +use core::num::NonZero; +use core::ptr::read; + +/// Types capable of being deserialised. +pub trait Deserialise: Sized { + /// The error of deserialisation. + /// + /// Use [`Infallible`] if **all** deserialisations are infallible, as is the case of zero-length types. type Error; /// Deserialises the byte stream to an object. /// - /// This function should not take *more* bytes than specified by [`SERIALISE_LIMIT`](Serialise::SERIALISE_LIMIT). + /// This function should **not** take more bytes than specified by [`T::SERIALISE_LIMIT`](crate::Serialise::SERIALISE_LIMIT). /// Doing so is considered a logic error. /// /// # Errors @@ -75,7 +80,11 @@ macro_rules! impl_int { Ok(Self::from_be_bytes(data)) } } + }; +} +macro_rules! impl_non_zero { + ($type:ty) => { impl Deserialise for NonZero<$type> { type Error = Error; @@ -353,19 +362,33 @@ where } } -impl<T: Deserialise<Error: StdError + 'static>, const N: usize> Deserialise for [T; N] { +impl<T, const N: usize> Deserialise for [T; N] +where + T: Default + Deserialise<Error: StdError + 'static>, { type Error = Box<dyn StdError>; fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> { - let len = usize::try_from(u64::deserialise(stream)?).unwrap(); + let len = usize::deserialise(stream)?; + if len != N { return Err(Box::new(Error::ArrayTooShort { req: len, len: N })) }; - let mut buf = Vec::with_capacity(len); - for _ in 0x0..len { buf.push(Deserialise::deserialise(stream)?); } + let mut buf: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() }; - // If we had used the checked unwrap, we would also - // have to require `T: Debug`. - Ok(unsafe { buf.try_into().unwrap_unchecked() }) + // Deserialise t + for item in buf.iter_mut().take(len) { + item.write(Deserialise::deserialise(stream)?); + } + + for item in buf.iter_mut().skip(len) { + item.write(Default::default()); + } + + // This should be safe as `MaybeUninit<T>` is + // transparent to `T`. The original buffer is + // NOT dropped automatically, so we can just + // forget about it from this point on. + let buf = unsafe { read(core::ptr::from_ref(&buf).cast::<[T; N]>()) }; + Ok(buf) } } @@ -406,6 +429,17 @@ impl Deserialise for Infallible { fn deserialise(_stream: &mut Dstream) -> Result<Self, Self::Error> { unreachable!() } } +impl Deserialise for isize { + type Error = Error; + + fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> { + let value = i16::deserialise(stream)? + .into(); + + Ok(value) + } +} + impl<T: Deserialise<Error: StdError + 'static>> Deserialise for Option<T> { type Error = Box<dyn StdError>; @@ -439,6 +473,17 @@ where } } +impl Deserialise for usize { + type Error = Error; + + fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> { + let value = u16::deserialise(stream)? + .into(); + + Ok(value) + } +} + impl_float!(f32); impl_float!(f64); @@ -452,3 +497,16 @@ impl_int!(u16); impl_int!(u32); impl_int!(u64); impl_int!(u8); + +impl_non_zero!(i128); +impl_non_zero!(i16); +impl_non_zero!(i32); +impl_non_zero!(i64); +impl_non_zero!(i8); +impl_non_zero!(isize); +impl_non_zero!(u128); +impl_non_zero!(u16); +impl_non_zero!(u32); +impl_non_zero!(u64); +impl_non_zero!(u8); +impl_non_zero!(usize); diff --git a/src/deserialise/test.rs b/src/deserialise/test.rs index 27acfda..70293cb 100644 --- a/src/deserialise/test.rs +++ b/src/deserialise/test.rs @@ -19,23 +19,21 @@ // er General Public License along with bzipper. If // not, see <https://www.gnu.org/licenses/>. -use crate::{Deserialise, Dstream, FixedString}; +use crate::{Deserialise, FixedString}; #[test] fn test_deserialise() { let data = [ 0x00, 0xFF, 0xFF, 0x0F, 0xEF, 0x1F, 0xDF, 0x2F, 0xCF, 0x3F, 0xBF, 0x4F, 0xAF, 0x5F, 0x9F, 0x6F, - 0x8F, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x09, 0x6D, 0xC3, 0xA1, 0x6E, 0x61, 0xC3, - 0xB0, 0x75, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, 0xBB, 0x00, - 0x00, 0x03, 0x91, 0x00, 0x00, 0x03, 0xBC, 0x00, - 0x00, 0x03, 0x94, 0x00, 0x00, 0x03, 0xB1, 0x01, - 0x00, 0x00, 0x01, 0x80, + 0x8F, 0x7F, 0x00, 0x09, 0x6D, 0xC3, 0xA1, 0x6E, + 0x61, 0xC3, 0xB0, 0x75, 0x72, 0x00, 0x05, 0x00, + 0x00, 0x03, 0xBB, 0x00, 0x00, 0x03, 0x91, 0x00, + 0x00, 0x03, 0xBC, 0x00, 0x00, 0x03, 0x94, 0x00, + 0x00, 0x03, 0xB1, 0x01, 0x00, 0x00, 0x01, 0x80, ]; - let mut stream = Dstream::from(&data); + let mut stream = From::from(&data); assert_eq!( u8::deserialise(&mut stream).unwrap(), diff --git a/src/dstream/mod.rs b/src/dstream/mod.rs index a9cfa89..ca7f619 100644 --- a/src/dstream/mod.rs +++ b/src/dstream/mod.rs @@ -19,15 +19,13 @@ // er General Public License along with bzipper. If // not, see <https://www.gnu.org/licenses/>. -use crate::{Error, Result, Sstream}; +use crate::{Error, Result}; -use std::fmt::{Debug, Formatter}; +use core::fmt::{Debug, Formatter}; /// Byte stream for deserialisation. /// /// This type borrows a byte slice (hence [`new`](Dstream::new)), keeping track internally of the used bytes. -/// -/// The stream may be converted to an [`Sstream`] using [`to_sstream`](Dstream::to_sstream). #[derive(Clone)] pub struct Dstream<'a> { data: &'a [u8], @@ -47,15 +45,16 @@ impl<'a> Dstream<'a> { /// /// # Errors /// - /// If the internal buffer doesn't hold at least the requested ammount of bytes, an [`EndOfDStream`](Error::EndOfDStream) error is returned. - pub fn take(&mut self, len: usize) -> Result<&[u8]> { - if self.len < len { return Err(Error::EndOfDStream { req: len, rem: self.len } ) } + /// If the internal buffer doesn't hold at least the requested amount of bytes, an [`EndOfStream`](Error::EndOfStream) error is returned. + pub fn take(&mut self, req: usize) -> Result<&[u8]> { + let rem = self.len; - let start = self.data.len() - self.len; - let stop = start + len; + if rem < req { return Err(Error::EndOfStream { req, rem } ) } - self.len -= len; + let start = self.data.len() - rem; + let stop = start + req; + self.len -= req; Ok(&self.data[start..stop]) } @@ -63,53 +62,25 @@ impl<'a> Dstream<'a> { /// /// # Errors /// - /// If the internal buffer doesn't hold at least the requested ammount of bytes, an [`EndOfDStream`](Error::EndOfDStream) error is returned. + /// If the internal buffer doesn't hold at least the requested amount of bytes, an [`EndOfStream`](Error::EndOfStream) error is returned. pub fn take_byte(&mut self) -> Result<u8> { const LEN: usize = 0x1; - if self.len < LEN { return Err(Error::EndOfDStream { req: LEN, rem: self.len } ) } + if self.len < LEN { return Err(Error::EndOfStream { req: LEN, rem: self.len } ) } self.len -= LEN; let index = self.data.len() - self.len; Ok(self.data[index]) } - - /// Takes a slice of the remaining data. - #[must_use] - pub fn as_slice(&self) -> &[u8] { - let stop = self.data.len(); - let start = stop - self.len; - - &self.data[start..stop] - } - - /// Converts the stream to a `Sstream` object. - /// - /// The returned object owns a copy of the remaining data. - #[inline(always)] - #[must_use] - pub fn to_sstream(&self) -> Sstream { - Sstream(self.as_slice().to_vec()) - } } impl Debug for Dstream<'_> { - fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { - write!(f, "[")?; - - for v in self.as_slice() { write!(f, "{v:#02X},")? }; - - write!(f, "]")?; - - Ok(()) + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + self.data.fmt(f) } } -impl<'a> From<&'a [u8]> for Dstream<'a> { - fn from(value: &'a [u8]) -> Self { Self::new(value) } -} - -impl<'a, const N: usize> From<&'a [u8; N]> for Dstream<'a> { - fn from(value: &'a [u8; N]) -> Self { Self::new(value) } +impl<'a, T: AsRef<[u8]>> From<&'a T> for Dstream<'a> { + fn from(value: &'a T) -> Self { Self::new(value) } } diff --git a/src/error/mod.rs b/src/error/mod.rs index d4df6ed..30e4c1e 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -19,12 +19,12 @@ // er General Public License along with bzipper. If // not, see <https://www.gnu.org/licenses/>. -use std::error::Error as StdError; -use std::fmt::{Display, Formatter}; -use std::str::Utf8Error; +use core::error::Error as StdError; +use core::fmt::{Display, Formatter}; +use core::str::Utf8Error; -/// Mapping of [`std::result::Result`]. -pub type Result<T> = std::result::Result<T, Error>; +/// Mapping of [`core::result::Result`]. +pub type Result<T> = core::result::Result<T, Error>; /// Denotes an error. /// @@ -32,14 +32,14 @@ pub type Result<T> = std::result::Result<T, Error>; /// Serialisations are assumed infallible. #[derive(Debug)] pub enum Error { - /// An array could not hold the requested ammount of elements. + /// An array could not hold the requested amount of elements. ArrayTooShort { req: usize, len: usize }, /// A string encountered an invalid UTF-8 sequence. BadString { source: Utf8Error }, /// Bytes were requested on an empty stream. - EndOfDStream { req: usize, rem: usize }, + EndOfStream { req: usize, rem: usize }, /// A boolean encountered a value outside (0) and (1). InvalidBoolean { value: u8 }, @@ -49,12 +49,18 @@ pub enum Error { /// This includes surrogate points in the inclusive range `U+D800` to `U+DFFF`, as well as values larger than `U+10FFFF`. InvalidCodePoint { value: u32 }, + /// An `isize` value couldn't fit into (16) bits. + IsizeOutOfRange { value: isize }, + /// A non-zero integer encountered the value (0). NullInteger, + + /// A `usize` value couldn't fit into (16) bits. + UsizeOutOfRange { value: usize }, } impl Display for Error { - fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { use Error::*; match *self { @@ -66,7 +72,7 @@ impl Display for Error { write!(f, "unable to parse utf8: \"{source}\"") }, - EndOfDStream { req, rem } => { + EndOfStream { req, rem } => { write!(f, "({req}) byte(s) were requested but only ({rem}) byte(s) were left") }, @@ -78,9 +84,17 @@ impl Display for Error { write!(f, "code point U+{value:04X} is not valid") }, + IsizeOutOfRange { value } => { + write!(f, "signed size value ({value}) cannot be serialised: must be in the range ({}) to ({})", i16::MIN, i16::MAX) + }, + NullInteger => { write!(f, "expected non-zero integer but got (0)") }, + + UsizeOutOfRange { value } => { + write!(f, "unsigned size value ({value}) cannot be serialised: must be at most ({})", u16::MAX) + }, } } } diff --git a/src/fixed_string/mod.rs b/src/fixed_string/mod.rs index 14226a1..b0342d3 100644 --- a/src/fixed_string/mod.rs +++ b/src/fixed_string/mod.rs @@ -31,10 +31,11 @@ use crate::{ Sstream, }; -use std::cmp::Ordering; -use std::fmt::{Debug, Display, Formatter, Write}; -use std::ops::{Index, IndexMut}; -use std::str::FromStr; +use alloc::string::String; +use core::cmp::Ordering; +use core::fmt::{Debug, Display, Formatter}; +use core::ops::{Index, IndexMut}; +use core::str::FromStr; /// Owned string with maximum size. /// @@ -107,18 +108,18 @@ impl<const N: usize> FixedString<N> { /// Returns an iterator to the contained characters. #[inline(always)] - pub fn iter(&self) -> std::slice::Iter<'_, char> { self.buf[0x0..self.len].iter() } + pub fn iter(&self) -> core::slice::Iter<'_, char> { self.buf[0x0..self.len].iter() } /// Returns a mutable iterator to the contained characters. #[inline(always)] - pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, char> { self.buf[0x0..self.len].iter_mut() } + pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, char> { self.buf[0x0..self.len].iter_mut() } } impl<const N: usize> Debug for FixedString<N> { - fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { - f.write_char('"')?; + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + write!(f, "\"")?; for c in self { write!(f, "{}", c.escape_debug())? } - f.write_char('"')?; + write!(f, "\"")?; Ok(()) } @@ -128,13 +129,14 @@ impl<const N: usize> Deserialise for FixedString<N> { type Error = Error; fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> { - let len = usize::try_from(u64::deserialise(stream)?).unwrap(); - + let len = usize::deserialise(stream)?; let data = stream.take(len)?; - let s = std::str::from_utf8(data) + + let s = core::str::from_utf8(data) .map_err(|e| Error::BadString { source: e })?; let len = s.chars().count(); + if len > N { return Err(Error::ArrayTooShort { req: len, len: N }); } @@ -157,7 +159,7 @@ impl<const N: usize> Default for FixedString<N> { } impl<const N: usize> Display for FixedString<N> { - fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { for c in self { write!(f, "{c}")? } Ok(()) @@ -207,7 +209,7 @@ impl<const N: usize> IntoIterator for FixedString<N> { impl<'a, const N: usize> IntoIterator for &'a FixedString<N> { type Item = &'a char; - type IntoIter = std::slice::Iter<'a, char>; + type IntoIter = core::slice::Iter<'a, char>; fn into_iter(self) -> Self::IntoIter { self.iter() } } @@ -215,7 +217,7 @@ impl<'a, const N: usize> IntoIterator for &'a FixedString<N> { impl<'a, const N: usize> IntoIterator for &'a mut FixedString<N> { type Item = &'a mut char; - type IntoIter = std::slice::IterMut<'a, char>; + type IntoIter = core::slice::IterMut<'a, char>; fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } @@ -272,15 +274,19 @@ impl<const N: usize, const M: usize> PartialOrd<FixedString<M>> for FixedString< } impl<const N: usize> Serialise for FixedString<N> { - const SERIALISE_LIMIT: usize = 0x4 * N; + type Error = Error; + + const SERIALISE_LIMIT: usize = N * 0x4; + + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let mut count = 0x0; - fn serialise(&self, stream: &mut Sstream) { let s: String = self.iter().collect(); - let len = u64::try_from(s.len()).unwrap(); + count += s.len().serialise(stream)?; + count += stream.add(&s.into_bytes())?; - stream.append(&len.to_be_bytes()); - stream.append(&s.into_bytes()); + Ok(count) } } diff --git a/src/fixed_string/test.rs b/src/fixed_string/test.rs index 1e3be42..1599efc 100644 --- a/src/fixed_string/test.rs +++ b/src/fixed_string/test.rs @@ -21,7 +21,7 @@ use crate::FixedString; -use std::cmp::Ordering; +use core::cmp::Ordering; #[test] fn test_fixed_string() { @@ -27,6 +27,19 @@ //! Keep in mind that this project is still work-in-progress. //! //! This crate does not require any dependencies at the moment. +//! +//! # Data model +//! +//! Most primitive types serialise losslessly, with the exception being [`usize`] and [`isize`]. +//! These serialise as [`u16`] and [`i16`], respectively, for portability reasons. +//! +//! Unsized types, such as [`str`] and [slices](slice), are not supported. +//! Instead, [arrays](array) should be used. +//! For strings, the [`FixedString`] type is also provided. + +#![no_std] + +extern crate alloc; macro_rules! use_mod { ($vis:vis $name:ident) => { @@ -36,6 +49,7 @@ macro_rules! use_mod { } pub(in crate) use use_mod; +use_mod!(pub buffer); use_mod!(pub deserialise); use_mod!(pub dstream); use_mod!(pub error); diff --git a/src/serialise/mod.rs b/src/serialise/mod.rs index 98c1417..0685323 100644 --- a/src/serialise/mod.rs +++ b/src/serialise/mod.rs @@ -22,31 +22,43 @@ #[cfg(test)] mod test; -use crate::Sstream; +use crate::{Error, Sstream}; -use std::convert::Infallible; -use std::mem::size_of; -use std::num::NonZero; +use alloc::boxed::Box; +use core::convert::Infallible; +use core::error::Error as StdError; +use core::mem::size_of; +use core::num::NonZero; -/// Denotes a type capable of being serialised. +/// Types capable of being serialised. pub trait Serialise: Sized { - /// The maximum ammount of bytes that can result from serialisation. + /// The error of serialisation. + /// + /// Use [`Infallible`] if **all** deserialisations are infallible, as is the case of zero-length types. + type Error; + + /// The maximum amount of bytes that can result from serialisation. const SERIALISE_LIMIT: usize; /// Serialises `self` into a byte stream. /// - /// This function should not append *more* bytes than specified in [`SERIALISE_LIMIT`](Serialise::SERIALISE_LIMIT). - /// Doing so is considered a logic error. - fn serialise(&self, stream: &mut Sstream); + /// The number of bytes written is returned. + /// This should **not** exceed [`SERIALISE_LIMIT`](Serialise::SERIALISE_LIMIT), and doing so is considered a logic error. + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error>; } macro_rules! impl_float { ($type:ty) => { impl Serialise for $type { + type Error = Error; + const SERIALISE_LIMIT: usize = size_of::<$type>(); - fn serialise(&self, stream: &mut Sstream) { - stream.append(&self.to_be_bytes()) + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let data = self.to_be_bytes(); + stream.add(&data)?; + + Ok(data.len()) } } }; @@ -55,17 +67,28 @@ macro_rules! impl_float { macro_rules! impl_int { ($type:ty) => { impl Serialise for $type { + type Error = Error; + const SERIALISE_LIMIT: usize = size_of::<$type>(); - fn serialise(&self, stream: &mut Sstream) { - stream.append(&self.to_be_bytes()) + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let data = self.to_be_bytes(); + stream.add(&data)?; + + Ok(data.len()) } } + }; +} +macro_rules! impl_non_zero { + ($type:ty) => { impl Serialise for NonZero<$type> { + type Error = <$type as Serialise>::Error; + const SERIALISE_LIMIT: usize = size_of::<$type>(); - fn serialise(&self, stream: &mut Sstream) { + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { self.get().serialise(stream) } } @@ -74,62 +97,82 @@ macro_rules! impl_int { impl<T0, T1> Serialise for (T0, T1) where - T0: Serialise, - T1: Serialise, { + T0: Serialise<Error: StdError + 'static>, + T1: Serialise<Error: StdError + 'static>, { + type Error = Box<dyn StdError>; + const SERIALISE_LIMIT: usize = T0::SERIALISE_LIMIT + T1::SERIALISE_LIMIT; - fn serialise(&self, stream: &mut Sstream) { - self.0.serialise(stream); - self.1.serialise(stream); + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let mut count = 0x0; + + count += self.0.serialise(stream)?; + count += self.1.serialise(stream)?; + + Ok(count) } } impl<T0, T1, T2> Serialise for (T0, T1, T2) where - T0: Serialise, - T1: Serialise, - T2: Serialise, { + T0: Serialise<Error: StdError + 'static>, + T1: Serialise<Error: StdError + 'static>, + T2: Serialise<Error: StdError + 'static>, { + type Error = Box<dyn StdError>; + const SERIALISE_LIMIT: usize = T0::SERIALISE_LIMIT + T1::SERIALISE_LIMIT + T2::SERIALISE_LIMIT; - fn serialise(&self, stream: &mut Sstream) { - self.0.serialise(stream); - self.1.serialise(stream); - self.2.serialise(stream); + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let mut count = 0x0; + + count += self.0.serialise(stream)?; + count += self.1.serialise(stream)?; + count += self.2.serialise(stream)?; + + Ok(count) } } impl<T0, T1, T2, T3> Serialise for (T0, T1, T2, T3) where - T0: Serialise, - T1: Serialise, - T2: Serialise, - T3: Serialise, { + T0: Serialise<Error: StdError + 'static>, + T1: Serialise<Error: StdError + 'static>, + T2: Serialise<Error: StdError + 'static>, + T3: Serialise<Error: StdError + 'static>, { + type Error = Box<dyn StdError>; + const SERIALISE_LIMIT: usize = T0::SERIALISE_LIMIT + T1::SERIALISE_LIMIT + T2::SERIALISE_LIMIT + T3::SERIALISE_LIMIT; - fn serialise(&self, stream: &mut Sstream) { - self.0.serialise(stream); - self.1.serialise(stream); - self.2.serialise(stream); - self.3.serialise(stream); + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let mut count = 0x0; + + count += self.0.serialise(stream)?; + count += self.1.serialise(stream)?; + count += self.2.serialise(stream)?; + count += self.3.serialise(stream)?; + + Ok(count) } } impl<T0, T1, T2, T3, T4> Serialise for (T0, T1, T2, T3, T4) where - T0: Serialise, - T1: Serialise, - T2: Serialise, - T3: Serialise, - T4: Serialise, { + T0: Serialise<Error: StdError + 'static>, + T1: Serialise<Error: StdError + 'static>, + T2: Serialise<Error: StdError + 'static>, + T3: Serialise<Error: StdError + 'static>, + T4: Serialise<Error: StdError + 'static>, { + type Error = Box<dyn StdError>; + const SERIALISE_LIMIT: usize = T0::SERIALISE_LIMIT + T1::SERIALISE_LIMIT @@ -137,23 +180,29 @@ where + T3::SERIALISE_LIMIT + T4::SERIALISE_LIMIT; - fn serialise(&self, stream: &mut Sstream) { - self.0.serialise(stream); - self.1.serialise(stream); - self.2.serialise(stream); - self.3.serialise(stream); - self.4.serialise(stream); + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let mut count = 0x0; + + count += self.0.serialise(stream)?; + count += self.1.serialise(stream)?; + count += self.2.serialise(stream)?; + count += self.3.serialise(stream)?; + count += self.4.serialise(stream)?; + + Ok(count) } } impl<T0, T1, T2, T3, T4, T5> Serialise for (T0, T1, T2, T3, T4, T5) where - T0: Serialise, - T1: Serialise, - T2: Serialise, - T3: Serialise, - T4: Serialise, - T5: Serialise, { + T0: Serialise<Error: StdError + 'static>, + T1: Serialise<Error: StdError + 'static>, + T2: Serialise<Error: StdError + 'static>, + T3: Serialise<Error: StdError + 'static>, + T4: Serialise<Error: StdError + 'static>, + T5: Serialise<Error: StdError + 'static>, { + type Error = Box<dyn StdError>; + const SERIALISE_LIMIT: usize = T0::SERIALISE_LIMIT + T1::SERIALISE_LIMIT @@ -162,25 +211,31 @@ where + T4::SERIALISE_LIMIT + T5::SERIALISE_LIMIT; - fn serialise(&self, stream: &mut Sstream) { - self.0.serialise(stream); - self.1.serialise(stream); - self.2.serialise(stream); - self.3.serialise(stream); - self.4.serialise(stream); - self.5.serialise(stream); + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let mut count = 0x0; + + count += self.0.serialise(stream)?; + count += self.1.serialise(stream)?; + count += self.2.serialise(stream)?; + count += self.3.serialise(stream)?; + count += self.4.serialise(stream)?; + count += self.5.serialise(stream)?; + + Ok(count) } } impl<T0, T1, T2, T3, T4, T5, T6> Serialise for (T0, T1, T2, T3, T4, T5, T6) where - T0: Serialise, - T1: Serialise, - T2: Serialise, - T3: Serialise, - T4: Serialise, - T5: Serialise, - T6: Serialise, { + T0: Serialise<Error: StdError + 'static>, + T1: Serialise<Error: StdError + 'static>, + T2: Serialise<Error: StdError + 'static>, + T3: Serialise<Error: StdError + 'static>, + T4: Serialise<Error: StdError + 'static>, + T5: Serialise<Error: StdError + 'static>, + T6: Serialise<Error: StdError + 'static>, { + type Error = Box<dyn StdError>; + const SERIALISE_LIMIT: usize = T0::SERIALISE_LIMIT + T1::SERIALISE_LIMIT @@ -190,27 +245,33 @@ where + T5::SERIALISE_LIMIT + T6::SERIALISE_LIMIT; - fn serialise(&self, stream: &mut Sstream) { - self.0.serialise(stream); - self.1.serialise(stream); - self.2.serialise(stream); - self.3.serialise(stream); - self.4.serialise(stream); - self.5.serialise(stream); - self.6.serialise(stream); + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let mut count = 0x0; + + count += self.0.serialise(stream)?; + count += self.1.serialise(stream)?; + count += self.2.serialise(stream)?; + count += self.3.serialise(stream)?; + count += self.4.serialise(stream)?; + count += self.5.serialise(stream)?; + count += self.6.serialise(stream)?; + + Ok(count) } } impl<T0, T1, T2, T3, T4, T5, T6, T7> Serialise for (T0, T1, T2, T3, T4, T5, T6, T7) where - T0: Serialise, - T1: Serialise, - T2: Serialise, - T3: Serialise, - T4: Serialise, - T5: Serialise, - T6: Serialise, - T7: Serialise, { + T0: Serialise<Error: StdError + 'static>, + T1: Serialise<Error: StdError + 'static>, + T2: Serialise<Error: StdError + 'static>, + T3: Serialise<Error: StdError + 'static>, + T4: Serialise<Error: StdError + 'static>, + T5: Serialise<Error: StdError + 'static>, + T6: Serialise<Error: StdError + 'static>, + T7: Serialise<Error: StdError + 'static>, { + type Error = Box<dyn StdError>; + const SERIALISE_LIMIT: usize = T0::SERIALISE_LIMIT + T1::SERIALISE_LIMIT @@ -221,29 +282,35 @@ where + T6::SERIALISE_LIMIT + T7::SERIALISE_LIMIT; - fn serialise(&self, stream: &mut Sstream) { - self.0.serialise(stream); - self.1.serialise(stream); - self.2.serialise(stream); - self.3.serialise(stream); - self.4.serialise(stream); - self.5.serialise(stream); - self.6.serialise(stream); - self.7.serialise(stream); + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let mut count = 0x0; + + count += self.0.serialise(stream)?; + count += self.1.serialise(stream)?; + count += self.2.serialise(stream)?; + count += self.3.serialise(stream)?; + count += self.4.serialise(stream)?; + count += self.5.serialise(stream)?; + count += self.6.serialise(stream)?; + count += self.7.serialise(stream)?; + + Ok(count) } } impl<T0, T1, T2, T3, T4, T5, T6, T7, T8> Serialise for (T0, T1, T2, T3, T4, T5, T6, T7, T8) where - T0: Serialise, - T1: Serialise, - T2: Serialise, - T3: Serialise, - T4: Serialise, - T5: Serialise, - T6: Serialise, - T7: Serialise, - T8: Serialise, { + T0: Serialise<Error: StdError + 'static>, + T1: Serialise<Error: StdError + 'static>, + T2: Serialise<Error: StdError + 'static>, + T3: Serialise<Error: StdError + 'static>, + T4: Serialise<Error: StdError + 'static>, + T5: Serialise<Error: StdError + 'static>, + T6: Serialise<Error: StdError + 'static>, + T7: Serialise<Error: StdError + 'static>, + T8: Serialise<Error: StdError + 'static>, { + type Error = Box<dyn StdError>; + const SERIALISE_LIMIT: usize = T0::SERIALISE_LIMIT + T1::SERIALISE_LIMIT @@ -255,31 +322,37 @@ where + T7::SERIALISE_LIMIT + T8::SERIALISE_LIMIT; - fn serialise(&self, stream: &mut Sstream) { - self.0.serialise(stream); - self.1.serialise(stream); - self.2.serialise(stream); - self.3.serialise(stream); - self.4.serialise(stream); - self.5.serialise(stream); - self.6.serialise(stream); - self.7.serialise(stream); - self.8.serialise(stream); + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let mut count = 0x0; + + count += self.0.serialise(stream)?; + count += self.1.serialise(stream)?; + count += self.2.serialise(stream)?; + count += self.3.serialise(stream)?; + count += self.4.serialise(stream)?; + count += self.5.serialise(stream)?; + count += self.6.serialise(stream)?; + count += self.7.serialise(stream)?; + count += self.8.serialise(stream)?; + + Ok(count) } } impl<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> Serialise for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) where - T0: Serialise, - T1: Serialise, - T2: Serialise, - T3: Serialise, - T4: Serialise, - T5: Serialise, - T6: Serialise, - T7: Serialise, - T8: Serialise, - T9: Serialise, { + T0: Serialise<Error: StdError + 'static>, + T1: Serialise<Error: StdError + 'static>, + T2: Serialise<Error: StdError + 'static>, + T3: Serialise<Error: StdError + 'static>, + T4: Serialise<Error: StdError + 'static>, + T5: Serialise<Error: StdError + 'static>, + T6: Serialise<Error: StdError + 'static>, + T7: Serialise<Error: StdError + 'static>, + T8: Serialise<Error: StdError + 'static>, + T9: Serialise<Error: StdError + 'static>, { + type Error = Box<dyn StdError>; + const SERIALISE_LIMIT: usize = T0::SERIALISE_LIMIT + T1::SERIALISE_LIMIT @@ -292,33 +365,39 @@ where + T8::SERIALISE_LIMIT + T9::SERIALISE_LIMIT; - fn serialise(&self, stream: &mut Sstream) { - self.0.serialise(stream); - self.1.serialise(stream); - self.2.serialise(stream); - self.3.serialise(stream); - self.4.serialise(stream); - self.5.serialise(stream); - self.6.serialise(stream); - self.7.serialise(stream); - self.8.serialise(stream); - self.9.serialise(stream); + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let mut count = 0x0; + + count += self.0.serialise(stream)?; + count += self.1.serialise(stream)?; + count += self.2.serialise(stream)?; + count += self.3.serialise(stream)?; + count += self.4.serialise(stream)?; + count += self.5.serialise(stream)?; + count += self.6.serialise(stream)?; + count += self.7.serialise(stream)?; + count += self.8.serialise(stream)?; + count += self.9.serialise(stream)?; + + Ok(count) } } impl<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Serialise for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) where - T0: Serialise, - T1: Serialise, - T2: Serialise, - T3: Serialise, - T4: Serialise, - T5: Serialise, - T6: Serialise, - T7: Serialise, - T8: Serialise, - T9: Serialise, - T10: Serialise, { + T0: Serialise<Error: StdError + 'static>, + T1: Serialise<Error: StdError + 'static>, + T2: Serialise<Error: StdError + 'static>, + T3: Serialise<Error: StdError + 'static>, + T4: Serialise<Error: StdError + 'static>, + T5: Serialise<Error: StdError + 'static>, + T6: Serialise<Error: StdError + 'static>, + T7: Serialise<Error: StdError + 'static>, + T8: Serialise<Error: StdError + 'static>, + T9: Serialise<Error: StdError + 'static>, + T10: Serialise<Error: StdError + 'static>, { + type Error = Box<dyn StdError>; + const SERIALISE_LIMIT: usize = T0::SERIALISE_LIMIT + T1::SERIALISE_LIMIT @@ -332,35 +411,41 @@ where + T9::SERIALISE_LIMIT + T10::SERIALISE_LIMIT; - fn serialise(&self, stream: &mut Sstream) { - self.0.serialise(stream); - self.1.serialise(stream); - self.2.serialise(stream); - self.3.serialise(stream); - self.4.serialise(stream); - self.5.serialise(stream); - self.6.serialise(stream); - self.7.serialise(stream); - self.8.serialise(stream); - self.9.serialise(stream); - self.10.serialise(stream); + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let mut count = 0x0; + + count += self.0.serialise(stream)?; + count += self.1.serialise(stream)?; + count += self.2.serialise(stream)?; + count += self.3.serialise(stream)?; + count += self.4.serialise(stream)?; + count += self.5.serialise(stream)?; + count += self.6.serialise(stream)?; + count += self.7.serialise(stream)?; + count += self.8.serialise(stream)?; + count += self.9.serialise(stream)?; + count += self.10.serialise(stream)?; + + Ok(count) } } impl<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Serialise for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) where - T0: Serialise, - T1: Serialise, - T2: Serialise, - T3: Serialise, - T4: Serialise, - T5: Serialise, - T6: Serialise, - T7: Serialise, - T8: Serialise, - T9: Serialise, - T10: Serialise, - T11: Serialise, { + T0: Serialise<Error: StdError + 'static>, + T1: Serialise<Error: StdError + 'static>, + T2: Serialise<Error: StdError + 'static>, + T3: Serialise<Error: StdError + 'static>, + T4: Serialise<Error: StdError + 'static>, + T5: Serialise<Error: StdError + 'static>, + T6: Serialise<Error: StdError + 'static>, + T7: Serialise<Error: StdError + 'static>, + T8: Serialise<Error: StdError + 'static>, + T9: Serialise<Error: StdError + 'static>, + T10: Serialise<Error: StdError + 'static>, + T11: Serialise<Error: StdError + 'static>, { + type Error = Box<dyn StdError>; + const SERIALISE_LIMIT: usize = T0::SERIALISE_LIMIT + T1::SERIALISE_LIMIT @@ -375,79 +460,124 @@ where + T10::SERIALISE_LIMIT + T11::SERIALISE_LIMIT; - fn serialise(&self, stream: &mut Sstream) { - self.0.serialise(stream); - self.1.serialise(stream); - self.2.serialise(stream); - self.3.serialise(stream); - self.4.serialise(stream); - self.5.serialise(stream); - self.6.serialise(stream); - self.7.serialise(stream); - self.8.serialise(stream); - self.9.serialise(stream); - self.10.serialise(stream); - self.11.serialise(stream); + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let mut count = 0x0; + + count += self.0.serialise(stream)?; + count += self.1.serialise(stream)?; + count += self.2.serialise(stream)?; + count += self.3.serialise(stream)?; + count += self.4.serialise(stream)?; + count += self.5.serialise(stream)?; + count += self.6.serialise(stream)?; + count += self.7.serialise(stream)?; + count += self.8.serialise(stream)?; + count += self.9.serialise(stream)?; + count += self.10.serialise(stream)?; + count += self.11.serialise(stream)?; + + Ok(count) } } -impl<T: Serialise, const N: usize> Serialise for [T; N] { +impl<T: Serialise<Error: StdError + 'static>, const N: usize> Serialise for [T; N] { + type Error = Box<dyn StdError>; + const SERIALISE_LIMIT: usize = T::SERIALISE_LIMIT * N; - fn serialise(&self, stream: &mut Sstream) { - u64::try_from(self.len()).unwrap().serialise(stream); + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let mut count = 0x0; - for v in self { v.serialise(stream) } + self.len().serialise(stream)?; + for v in self { count += v.serialise(stream)? } + + Ok(count) } } impl Serialise for () { + type Error = Infallible; + const SERIALISE_LIMIT: usize = size_of::<Self>(); - fn serialise(&self, _stream: &mut Sstream) { } + #[inline(always)] + fn serialise(&self, mut _stream: &mut Sstream) -> Result<usize, Self::Error> { + Ok(Self::SERIALISE_LIMIT) + } } impl Serialise for bool { + type Error = Error; + const SERIALISE_LIMIT: usize = size_of::<Self>(); - fn serialise(&self, stream: &mut Sstream) { + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { u8::from(*self).serialise(stream) } } impl Serialise for char { + type Error = Error; + const SERIALISE_LIMIT: usize = size_of::<Self>(); - fn serialise(&self, stream: &mut Sstream) { + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { u32::from(*self).serialise(stream) } } +// Especially useful for `Result<T, Infallible>`. impl Serialise for Infallible { + type Error = Self; + const SERIALISE_LIMIT: usize = size_of::<Self>(); - fn serialise(&self, _stream: &mut Sstream) { unreachable!() } + fn serialise(&self, mut _stream: &mut Sstream) -> Result<usize, Self::Error> { unreachable!() } +} + +impl Serialise for isize { + type Error = Error; + + const SERIALISE_LIMIT: usize = size_of::<i16>(); + + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let value = i16::try_from(*self) + .map_err(|_| Error::IsizeOutOfRange { value: *self })?; + + value.serialise(stream) + } } -impl<T: Serialise> Serialise for Option<T> { +impl<T: Serialise<Error: StdError + 'static>> Serialise for Option<T> { + type Error = Box<dyn StdError>; + const SERIALISE_LIMIT: usize = T::SERIALISE_LIMIT + 0x1; - fn serialise(&self, stream: &mut Sstream) { + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let mut count = 0x0; + match *self { None => { - stream.append_byte(0x00); - stream.append(&vec![0x00; size_of::<T>()]); + count += false.serialise(stream)?; + // No need to zero-fill. }, Some(ref v) => { - stream.append_byte(0x01); - v.serialise(stream); + count += true.serialise(stream)?; + count += v.serialise(stream)?; }, }; + + Ok(count) } } -impl<T: Serialise, E: Serialise> Serialise for Result<T, E> { +impl<T, E> Serialise for core::result::Result<T, E> +where + T: Serialise<Error: StdError + 'static>, + E: Serialise<Error: StdError + 'static>, { + type Error = Box<dyn StdError>; + const SERIALISE_LIMIT: usize = const { if size_of::<T>() > size_of::<T>() { size_of::<T>() @@ -456,18 +586,36 @@ impl<T: Serialise, E: Serialise> Serialise for Result<T, E> { } }; - fn serialise(&self, stream: &mut Sstream) { + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + // Remember the descriminant. + let mut count = 0x0; + match *self { Ok(ref v) => { - stream.append_byte(0x00); - v.serialise(stream); + count += false.serialise(stream)?; + count += v.serialise(stream)?; }, Err(ref e) => { - stream.append_byte(0x01); - e.serialise(stream); + count += true.serialise(stream)?; + count += e.serialise(stream)?; }, }; + + Ok(count) + } +} + +impl Serialise for usize { + type Error = Error; + + const SERIALISE_LIMIT: Self = size_of::<u16>(); + + fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { + let value = u16::try_from(*self) + .map_err(|_| Error::UsizeOutOfRange { value: *self })?; + + value.serialise(stream) } } @@ -484,3 +632,16 @@ impl_int!(u16); impl_int!(u32); impl_int!(u64); impl_int!(u8); + +impl_non_zero!(i128); +impl_non_zero!(i16); +impl_non_zero!(i32); +impl_non_zero!(i64); +impl_non_zero!(i8); +impl_non_zero!(isize); +impl_non_zero!(u128); +impl_non_zero!(u16); +impl_non_zero!(u32); +impl_non_zero!(u64); +impl_non_zero!(u8); +impl_non_zero!(usize); diff --git a/src/serialise/test.rs b/src/serialise/test.rs index 245c2c3..43f2b9f 100644 --- a/src/serialise/test.rs +++ b/src/serialise/test.rs @@ -21,34 +21,38 @@ use crate::{FixedString, Serialise, Sstream}; +use alloc::boxed::Box; +use alloc::vec; + #[test] fn test_serialise() { - let mut stream = Sstream::new(); + let mut buf = vec![0x00; 0x50]; + let mut stream = Sstream::new(&mut buf); - 0x00_u8.serialise(&mut stream); - 0xFF_u8.serialise(&mut stream); - 0x7F_u8.serialise(&mut stream); + 0x00_u8.serialise(&mut stream).unwrap(); + 0xFF_u8.serialise(&mut stream).unwrap(); + 0x7F_u8.serialise(&mut stream).unwrap(); - 0x0F_7E_u16.serialise(&mut stream); + 0x0F_7E_u16.serialise(&mut stream).unwrap(); - 0x00_2F_87_E7_u32.serialise(&mut stream); + 0x00_2F_87_E7_u32.serialise(&mut stream).unwrap(); - 0xF3_37_CF_8B_DB_03_2B_39_u64.serialise(&mut stream); + 0xF3_37_CF_8B_DB_03_2B_39_u64.serialise(&mut stream).unwrap(); - 0x45_A0_15_6A_36_77_17_8A_83_2E_3C_2C_84_10_58_1A_u128.serialise(&mut stream); + 0x45_A0_15_6A_36_77_17_8A_83_2E_3C_2C_84_10_58_1A_u128.serialise(&mut stream).unwrap(); - FixedString::<0x1>::new("A").unwrap().serialise(&mut stream); - FixedString::<0x8>::new("l\u{00F8}gma\u{00F0}ur").unwrap().serialise(&mut stream); + FixedString::<0x1>::new("A").unwrap().serialise(&mut stream).unwrap(); + FixedString::<0x8>::new("l\u{00F8}gma\u{00F0}ur").unwrap().serialise(&mut stream).unwrap(); - ['\u{03B4}', '\u{0190}', '\u{03BB}', '\u{03A4}', '\u{03B1}'].serialise(&mut stream); + ['\u{03B4}', '\u{0190}', '\u{03BB}', '\u{03A4}', '\u{03B1}'].serialise(&mut stream).unwrap(); - Result::<u16, char>::Ok(0x45_45).serialise(&mut stream); - Result::<u16, char>::Err(char::REPLACEMENT_CHARACTER).serialise(&mut stream); + Ok::<u16, char>(0x45_45).serialise(&mut stream).unwrap(); + Err::<u16, char>(char::REPLACEMENT_CHARACTER).serialise(&mut stream).unwrap(); - Option::<()>::None.serialise(&mut stream); - Option::<()>::Some(()).serialise(&mut stream); + None::<()>.serialise(&mut stream).unwrap(); + Some::<()>(()).serialise(&mut stream).unwrap(); - let data: Box<[u8]> = stream.into(); + let data: Box<[u8]> = buf.into(); assert_eq!( data.as_ref(), @@ -57,15 +61,12 @@ fn test_serialise() { 0xE7, 0xF3, 0x37, 0xCF, 0x8B, 0xDB, 0x03, 0x2B, 0x39, 0x45, 0xA0, 0x15, 0x6A, 0x36, 0x77, 0x17, 0x8A, 0x83, 0x2E, 0x3C, 0x2C, 0x84, 0x10, 0x58, - 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0A, 0x6C, 0xC3, 0xB8, 0x67, 0x6D, 0x61, - 0xC3, 0xB0, 0x75, 0x72, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, 0xB4, - 0x00, 0x00, 0x01, 0x90, 0x00, 0x00, 0x03, 0xBB, - 0x00, 0x00, 0x03, 0xA4, 0x00, 0x00, 0x03, 0xB1, - 0x00, 0x45, 0x45, 0x01, 0x00, 0x00, 0xFF, 0xFD, - 0x00, 0x01, - ] + 0x1A, 0x00, 0x01, 0x41, 0x00, 0x0A, 0x6C, 0xC3, + 0xB8, 0x67, 0x6D, 0x61, 0xC3, 0xB0, 0x75, 0x72, + 0x00, 0x05, 0x00, 0x00, 0x03, 0xB4, 0x00, 0x00, + 0x01, 0x90, 0x00, 0x00, 0x03, 0xBB, 0x00, 0x00, + 0x03, 0xA4, 0x00, 0x00, 0x03, 0xB1, 0x00, 0x45, + 0x45, 0x01, 0x00, 0x00, 0xFF, 0xFD, 0x00, 0x01, + ], ); }
\ No newline at end of file diff --git a/src/sstream/mod.rs b/src/sstream/mod.rs index f28875a..83536d0 100644 --- a/src/sstream/mod.rs +++ b/src/sstream/mod.rs @@ -19,74 +19,85 @@ // er General Public License along with bzipper. If // not, see <https://www.gnu.org/licenses/>. -use crate::{Dstream, Serialise}; +use crate::{Error, Result}; -use std::fmt::{Debug, Formatter}; -use std::mem::size_of; +use core::fmt::{Debug, Formatter}; /// Byte stream for serialisation. /// -/// The bytes themselves are contained by the type. -/// The stream may be converted to [`Dstream`] using [`as_dstream`](Sstream::as_dstream) -#[derive(Clone, Eq, PartialEq)] -pub struct Sstream(pub(in crate) Vec<u8>); +/// This type borrows a byte slice (hence [`new`](Sstream::new)), keeping track internally of the used bytes. +#[derive(Eq, PartialEq)] +pub struct Sstream<'a> { + data: &'a mut [u8], + len: usize +} -impl Sstream { - /// Constructs a new, empty byte stream. +impl<'a> Sstream<'a> { + /// Constructs a new byte stream. + /// + /// If the borrowed slice already contains data, this may overwritten by subsequent serialisations. #[inline(always)] #[must_use] - pub const fn new() -> Self { Self(Vec::new()) } + pub fn new(data: &'a mut [u8]) -> Self { Self { data, len: 0x0 } } /// Extends the byte stream. - pub fn append(&mut self, extra: &[u8]) { - self.0.extend(extra); + /// + /// # Errors + /// + /// If the stream cannot hold the requested bytes, an [`EndOfStream`](Error::EndOfStream) instance is returned. + pub fn add(&mut self, extra: &[u8]) -> Result<usize> { + let rem = self.data.len() - self.len; + let req = extra.len(); + + if rem.checked_sub(req).is_none() { + return Err(Error::EndOfStream { req, rem }); + } + + let start = self.len; + let stop = self.len + req; + + self.len += req; + self.data[start..stop].copy_from_slice(extra); + + Ok(req) } /// Extends the byte stream by a single byte. - pub fn append_byte(&mut self, extra: u8) { - self.0.push(extra); + /// + /// # Errors + /// + /// If the stream cannot hold the byte, an [`EndOfStream`](Error::EndOfStream) instance is returned. + pub fn add_byte(&mut self, extra: u8) -> Result<usize> { + self.add(&[extra]) } - /// Converts the stream to a `Dstream` object. + /// Yields the length of the stream. /// - /// The returned object references the original stream. + /// That is, the amount of bytes written so far. #[inline(always)] #[must_use] - pub fn as_dstream(&self) -> Dstream { Dstream::new(&self.0) } -} + pub const fn len(&self) -> usize { self.len } -impl AsRef<[u8]> for Sstream { + /// Tests if the stream is empty. #[inline(always)] - fn as_ref(&self) -> &[u8] { self.0.as_ref() } -} - -impl Debug for Sstream { - fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { - write!(f, "[")?; - - for v in &self.0 { write!(f, "{v:#02X},")? }; - - write!(f, "]")?; + #[must_use] + pub const fn is_empty(&self) -> bool { self.len == 0x0 } - Ok(()) - } + /// Returns a slice to the stream contents. + /// + /// This includes all previously written bytes. + #[inline(always)] + #[must_use] + pub fn as_slice(&self) -> &[u8] { &self.data[0x0..self.len] } } -impl Default for Sstream { +impl AsRef<[u8]> for Sstream<'_> { #[inline(always)] - fn default() -> Self { Self::new() } + fn as_ref(&self) -> &[u8] { self.as_slice() } } -impl<T: Serialise> From<&T> for Sstream { - fn from(value: &T) -> Self { - let mut stream = Self(Vec::with_capacity(size_of::<T>())); - value.serialise(&mut stream); - - stream +impl Debug for Sstream<'_> { + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + self.data.fmt(f) } } - -impl From<Sstream> for Box<[u8]> { - #[inline(always)] - fn from(value: Sstream) -> Self { value.0.into_boxed_slice() } -} |