Bump minor; Document errors; Rename: ArrayLengthMismatch -> ArrayTooShort; Remove error FixedStringTooShort; Rename: InvalidUtf8 -> BadString; Rework errors; Rename methods: as_d_stream -> as_dstream, to_s_stream -> to_sstream; Add SERIALISATION_LIMIT constant to Serialise; Make some deserialisations infallible; Add method append_byte to SStream; Add method take_byte to DStream; Rename SStream -> Sstream, DStream -> Dstream; Update readme; Update documentation; Make Deserialise require Serialise; Fix copyright/license notice in "src/serialise/test.rs";

This commit is contained in:
Gabriel Bjørnager Jensen 2024-06-09 14:15:01 +02:00
parent 05123b9cd8
commit 093f6f013b
12 changed files with 313 additions and 120 deletions

View file

@ -1,3 +1,22 @@
# 0.3.0
* Bump minor
* Document errors
* Rename: `ArrayLengthMismatch` -> `ArrayTooShort`
* Remove error `FixedStringTooShort`
* Rename: `InvalidUtf8` -> `BadString`
* Rework errors
* Rename methods: `as_d_stream` -> `as_dstream`, `to_s_stream` -> `to_sstream`
* Add `SERIALISATION_LIMIT` constant to `Serialise`
* Make some deserialisations infallible
* Add method `append_byte` to `SStream`
* Add method `take_byte` to `DStream`
* Rename `SStream` -> `Sstream`, `DStream` -> `Dstream`
* Update readme
* Update documentation
* Make `Deserialise` require `Serialise`
* Fix copyright/license notice in `"src/serialise/test.rs"`
# 0.2.0
* Clean up code

View file

@ -1,6 +1,6 @@
[package]
name = "bzipper"
version = "0.2.0"
version = "0.3.0"
authors = ["Gabriel Bjørnager Jensen"]
edition = "2021"
description = "Binary (de)serialiser."

View file

@ -1,7 +1,7 @@
[`bzipper`](https://crates.io/crates/bzipper) is a binary (de)serialiser.
[`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 without inflating the resulting binary sequence.
As such, one may consider this crate to be more low-level.
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.
Therefore, this crate may be more suited for networking or other cases where a fixed-sized buffer is needed.
Keep in mind that this project is still work-in-progress.

View file

@ -22,7 +22,7 @@
#[cfg(test)]
mod test;
use crate::{DStream, Error};
use crate::{Dstream, Error, Serialise};
use std::convert::Infallible;
use std::error::Error as StdError;
@ -30,15 +30,18 @@ use std::mem::size_of;
use std::num::NonZero;
/// Denotes a type capable of being deserialised.
pub trait Deserialise: Sized {
pub trait Deserialise: Serialise + Sized {
type Error;
/// Deserialises the byte stream to an object.
///
/// This function should not take *more* bytes than specified by [`SERIALISE_LIMIT`](Serialise::SERIALISE_LIMIT).
/// Doing so is considered a logic error.
///
/// # Errors
///
/// If deserialisation failed, e.g. by an invalid value being found, an error is returned.
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error>;
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error>;
}
macro_rules! impl_float {
@ -46,7 +49,7 @@ macro_rules! impl_float {
impl Deserialise for $type {
type Error = Error;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
let data = stream
.take(size_of::<Self>())?
.try_into()
@ -63,7 +66,7 @@ macro_rules! impl_int {
impl Deserialise for $type {
type Error = Error;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
let data = stream
.take(size_of::<Self>())?
.try_into()
@ -76,7 +79,7 @@ macro_rules! impl_int {
impl Deserialise for NonZero<$type> {
type Error = Error;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
let value = <$type>::deserialise(stream)?;
NonZero::new(value)
@ -92,7 +95,7 @@ where
T1: Deserialise<Error: StdError + 'static>, {
type Error = Box<dyn StdError>;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
Ok((
Deserialise::deserialise(stream)?,
Deserialise::deserialise(stream)?,
@ -107,7 +110,7 @@ where
T2: Deserialise<Error: StdError + 'static>, {
type Error = Box<dyn StdError>;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
Ok((
Deserialise::deserialise(stream)?,
Deserialise::deserialise(stream)?,
@ -124,7 +127,7 @@ where
T3: Deserialise<Error: StdError + 'static>, {
type Error = Box<dyn StdError>;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
Ok((
Deserialise::deserialise(stream)?,
Deserialise::deserialise(stream)?,
@ -143,7 +146,7 @@ where
T4: Deserialise<Error: StdError + 'static>, {
type Error = Box<dyn StdError>;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
Ok((
Deserialise::deserialise(stream)?,
Deserialise::deserialise(stream)?,
@ -164,7 +167,7 @@ where
T5: Deserialise<Error: StdError + 'static>, {
type Error = Box<dyn StdError>;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
Ok((
Deserialise::deserialise(stream)?,
Deserialise::deserialise(stream)?,
@ -187,7 +190,7 @@ where
T6: Deserialise<Error: StdError + 'static>, {
type Error = Box<dyn StdError>;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
Ok((
Deserialise::deserialise(stream)?,
Deserialise::deserialise(stream)?,
@ -212,7 +215,7 @@ where
T7: Deserialise<Error: StdError + 'static>, {
type Error = Box<dyn StdError>;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
Ok((
Deserialise::deserialise(stream)?,
Deserialise::deserialise(stream)?,
@ -239,7 +242,7 @@ where
T8: Deserialise<Error: StdError + 'static>, {
type Error = Box<dyn StdError>;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
Ok((
Deserialise::deserialise(stream)?,
Deserialise::deserialise(stream)?,
@ -268,7 +271,7 @@ where
T9: Deserialise<Error: StdError + 'static>, {
type Error = Box<dyn StdError>;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
Ok((
Deserialise::deserialise(stream)?,
Deserialise::deserialise(stream)?,
@ -299,7 +302,7 @@ where
T10: Deserialise<Error: StdError + 'static>, {
type Error = Box<dyn StdError>;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
Ok((
Deserialise::deserialise(stream)?,
Deserialise::deserialise(stream)?,
@ -332,7 +335,7 @@ where
T11: Deserialise<Error: StdError + 'static>, {
type Error = Box<dyn StdError>;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
Ok((
Deserialise::deserialise(stream)?,
Deserialise::deserialise(stream)?,
@ -353,9 +356,9 @@ where
impl<T: Deserialise<Error: StdError + 'static>, const N: usize> Deserialise for [T; N] {
type Error = Box<dyn StdError>;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
let len = usize::try_from(u64::deserialise(stream)?).unwrap();
if len != N { return Err(Box::new(Error::ArrayLengthMismatch { len, ok_len: N })) };
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)?); }
@ -367,15 +370,15 @@ impl<T: Deserialise<Error: StdError + 'static>, const N: usize> Deserialise for
}
impl Deserialise for () {
type Error = Error;
type Error = Infallible;
fn deserialise(_stream: &mut DStream) -> Result<Self, Self::Error> { Ok(()) }
fn deserialise(_stream: &mut Dstream) -> Result<Self, Self::Error> { Ok(()) }
}
impl Deserialise for bool {
type Error = Error;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
let value = u8::deserialise(stream)?;
match value {
@ -389,7 +392,7 @@ impl Deserialise for bool {
impl Deserialise for char {
type Error = Error;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
let value = u32::deserialise(stream)?;
Self::from_u32(value)
@ -398,15 +401,15 @@ impl Deserialise for char {
}
impl Deserialise for Infallible {
type Error = Error;
type Error = Self;
fn deserialise(_stream: &mut DStream) -> Result<Self, Self::Error> { unreachable!() }
fn deserialise(_stream: &mut Dstream) -> Result<Self, Self::Error> { unreachable!() }
}
impl<T: Deserialise<Error: StdError + 'static>> Deserialise for Option<T> {
type Error = Box<dyn StdError>;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
let sign = bool::deserialise(stream)?;
if sign {
@ -423,7 +426,7 @@ where
<E as Deserialise>::Error: StdError + 'static, {
type Error = Box<dyn StdError>;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
let sign = bool::deserialise(stream)?;
let value = if sign {

View file

@ -19,7 +19,7 @@
// er General Public License along with bzipper. If
// not, see <https://www.gnu.org/licenses/>.
use crate::{Deserialise, DStream, FixedString};
use crate::{Deserialise, Dstream, FixedString};
#[test]
fn test_deserialise() {
@ -35,7 +35,7 @@ fn test_deserialise() {
0x00, 0x00, 0x01, 0x80,
];
let mut stream = DStream::from(&data);
let mut stream = Dstream::from(&data);
assert_eq!(
u8::deserialise(&mut stream).unwrap(),

View file

@ -19,20 +19,22 @@
// er General Public License along with bzipper. If
// not, see <https://www.gnu.org/licenses/>.
use crate::{Error, Result, SStream};
use crate::{Error, Result, Sstream};
use std::fmt::{Debug, Formatter};
/// Byte stream for deserialisation.
///
/// This type borrows a byte slice (hence [`new`](DStream::new)), keeping track internally of the used bytes.
/// 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> {
pub struct Dstream<'a> {
data: &'a [u8],
len: usize,
}
impl<'a> DStream<'a> {
impl<'a> Dstream<'a> {
/// Constructs a new byte stream.
#[inline(always)]
#[must_use]
@ -47,7 +49,7 @@ impl<'a> DStream<'a> {
///
/// 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 { len: self.len, ok_len: len } ) }
if self.len < len { return Err(Error::EndOfDStream { req: len, rem: self.len } ) }
let start = self.data.len() - self.len;
let stop = start + len;
@ -57,6 +59,22 @@ impl<'a> DStream<'a> {
Ok(&self.data[start..stop])
}
/// Takes a single byte from the stream.
///
/// # 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_byte(&mut self) -> Result<u8> {
const LEN: usize = 0x1;
if self.len < LEN { return Err(Error::EndOfDStream { 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] {
@ -66,17 +84,17 @@ impl<'a> DStream<'a> {
&self.data[start..stop]
}
/// Converts the stream to a `SStream` object.
/// Converts the stream to a `Sstream` object.
///
/// The returned object owns a copy of the remaining data.
#[inline(always)]
#[must_use]
pub fn to_s_stream(&self) -> SStream {
SStream(self.as_slice().to_vec())
pub fn to_sstream(&self) -> Sstream {
Sstream(self.as_slice().to_vec())
}
}
impl Debug for DStream<'_> {
impl Debug for Dstream<'_> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "[")?;
@ -88,10 +106,10 @@ impl Debug for DStream<'_> {
}
}
impl<'a> From<&'a [u8]> for DStream<'a> {
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> {
impl<'a, const N: usize> From<&'a [u8; N]> for Dstream<'a> {
fn from(value: &'a [u8; N]) -> Self { Self::new(value) }
}

View file

@ -19,8 +19,6 @@
// er General Public License along with bzipper. If
// not, see <https://www.gnu.org/licenses/>.
//! Error handling.
use std::error::Error as StdError;
use std::fmt::{Display, Formatter};
use std::str::Utf8Error;
@ -30,22 +28,28 @@ pub type Result<T> = std::result::Result<T, Error>;
/// Denotes an error.
///
/// These variants are used when a deserialisation fails.
/// These variants are used when deserialisation fails.
/// Serialisations are assumed infallible.
#[derive(Debug)]
pub enum Error {
ArrayLengthMismatch { len: usize, ok_len: usize },
/// An array could not hold the requested ammount of elements.
ArrayTooShort { req: usize, len: usize },
EndOfDStream { len: usize, ok_len: usize },
/// A string encountered an invalid UTF-8 sequence.
BadString { source: Utf8Error },
FixedStringTooShort { len: usize, s: String },
/// Bytes were requested on an empty stream.
EndOfDStream { req: usize, rem: usize },
/// A boolean encountered a value outside (0) and (1).
InvalidBoolean { value: u8 },
/// An invalid code point was encountered.
///
/// This includes surrogate points in the inclusive range `U+D800` to `U+DFFF`, as well as values larger than `U+10FFFF`.
InvalidCodePoint { value: u32 },
InvalidUtf8 { source: Utf8Error },
/// A non-zero integer encountered the value (0).
NullInteger,
}
@ -54,16 +58,16 @@ impl Display for Error {
use Error::*;
match *self {
ArrayLengthMismatch { len, ok_len } => {
write!(f, "expected array of length ({ok_len}) but got ({len}) elements")
ArrayTooShort { req, len } => {
write!(f, "array of ({len}) element(s) cannot hold ({req})")
},
EndOfDStream { len, ok_len } => {
write!(f, "({ok_len}) byte(s) were requested but only ({len}) byte(s) were left")
BadString { ref source } =>{
write!(f, "unable to parse utf8: \"{source}\"")
},
FixedStringTooShort { len, ref s } => {
write!(f, "fixed string with `N = {len}` cannot hold {s:?}")
EndOfDStream { req, rem } => {
write!(f, "({req}) byte(s) were requested but only ({rem}) byte(s) were left")
},
InvalidBoolean { value } => {
@ -74,10 +78,6 @@ impl Display for Error {
write!(f, "code point U+{value:04X} is not valid")
},
InvalidUtf8 { ref source } =>{
write!(f, "unable to parse utf8: \"{source}\"")
},
NullInteger => {
write!(f, "expected non-zero integer but got (0)")
},
@ -90,7 +90,7 @@ impl StdError for Error {
use Error::*;
match *self {
InvalidUtf8 { ref source } => Some(source),
BadString { ref source } => Some(source),
_ => None,
}

View file

@ -24,11 +24,11 @@ mod test;
use crate::{
Deserialise,
DStream,
Dstream,
Error,
FixedStringIter,
Serialise,
SStream,
Sstream,
};
use std::cmp::Ordering;
@ -53,13 +53,13 @@ impl<const N: usize> FixedString<N> {
///
/// # Errors
///
/// If the given string `s` cannot fit into `N` characters, a [`FixedStringTooShort`](Error::FixedStringTooShort) error is returned.
/// If the given string `s` cannot fit into `N` characters, an [`ArrayTooShort`](Error::ArrayTooShort) error is returned.
pub fn new(s: &str) -> Result<Self, Error> {
let mut buf = ['\0'; N];
let len = s.chars().count();
for (i, c) in s.chars().enumerate() {
if i >= N { return Err(Error::FixedStringTooShort { len: N, s: s.to_owned() }) }
if i >= N { return Err(Error::ArrayTooShort { req: len, len: N }) }
buf[i] = c;
}
@ -127,16 +127,16 @@ impl<const N: usize> Debug for FixedString<N> {
impl<const N: usize> Deserialise for FixedString<N> {
type Error = Error;
fn deserialise(stream: &mut DStream) -> Result<Self, Self::Error> {
fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> {
let len = usize::try_from(u64::deserialise(stream)?).unwrap();
let data = stream.take(len)?;
let s = std::str::from_utf8(data)
.map_err(|e| Error::InvalidUtf8 { source: e })?;
.map_err(|e| Error::BadString { source: e })?;
let len = s.chars().count();
if len > N {
return Err(Error::FixedStringTooShort { len, s: s.to_owned() });
return Err(Error::ArrayTooShort { req: len, len: N });
}
let mut buf = ['\0'; N];
@ -272,7 +272,9 @@ impl<const N: usize, const M: usize> PartialOrd<FixedString<M>> for FixedString<
}
impl<const N: usize> Serialise for FixedString<N> {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize = 0x4 * N;
fn serialise(&self, stream: &mut Sstream) {
let s: String = self.iter().collect();
let len = u64::try_from(s.len()).unwrap();

View file

@ -21,8 +21,8 @@
//! Binary (de)serialisation.
//!
//! Contrary to [Serde](https://crates.io/crates/serde/)/[Bincode](https://crates.io/crates/bincode/), the goal of `bzipper` is to serialise data without inflating the resulting binary sequence.
//! As such, one may consider this crate to be more low-level.
//! Contrary to [Serde](https://crates.io/crates/serde/)/[Bincode](https://crates.io/crates/bincode/), the goal of `bzipper` is to serialise with a known size constraint.
//! Therefore, this crate may be more suited for networking or other cases where a fixed-sized buffer is needed.
//!
//! Keep in mind that this project is still work-in-progress.
//!
@ -36,10 +36,10 @@ macro_rules! use_mod {
}
pub(in crate) use use_mod;
use_mod!(pub d_stream);
use_mod!(pub deserialise);
use_mod!(pub dstream);
use_mod!(pub error);
use_mod!(pub fixed_string);
use_mod!(pub fixed_string_iter);
use_mod!(pub s_stream);
use_mod!(pub serialise);
use_mod!(pub sstream);

View file

@ -22,7 +22,7 @@
#[cfg(test)]
mod test;
use crate::SStream;
use crate::Sstream;
use std::convert::Infallible;
use std::mem::size_of;
@ -30,17 +30,22 @@ use std::num::NonZero;
/// Denotes a type capable of being serialised.
pub trait Serialise: Sized {
/// The maximum ammount of bytes that can result from serialisation.
const SERIALISE_LIMIT: usize;
/// Serialises `self` into a byte stream.
///
/// One may assume that the resulting stream has at most the same ammount of bytes as before serialisation.
/// Therefore, not observing this rule is a logic error.
fn serialise(&self, stream: &mut SStream);
/// 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);
}
macro_rules! impl_float {
($type:ty) => {
impl Serialise for $type {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize = size_of::<$type>();
fn serialise(&self, stream: &mut Sstream) {
stream.append(&self.to_be_bytes())
}
}
@ -50,13 +55,17 @@ macro_rules! impl_float {
macro_rules! impl_int {
($type:ty) => {
impl Serialise for $type {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize = size_of::<$type>();
fn serialise(&self, stream: &mut Sstream) {
stream.append(&self.to_be_bytes())
}
}
impl Serialise for NonZero<$type> {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize = size_of::<$type>();
fn serialise(&self, stream: &mut Sstream) {
self.get().serialise(stream)
}
}
@ -67,7 +76,11 @@ impl<T0, T1> Serialise for (T0, T1)
where
T0: Serialise,
T1: Serialise, {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize =
T0::SERIALISE_LIMIT
+ T1::SERIALISE_LIMIT;
fn serialise(&self, stream: &mut Sstream) {
self.0.serialise(stream);
self.1.serialise(stream);
}
@ -78,7 +91,12 @@ where
T0: Serialise,
T1: Serialise,
T2: Serialise, {
fn serialise(&self, stream: &mut SStream) {
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);
@ -91,7 +109,13 @@ where
T1: Serialise,
T2: Serialise,
T3: Serialise, {
fn serialise(&self, stream: &mut SStream) {
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);
@ -106,7 +130,14 @@ where
T2: Serialise,
T3: Serialise,
T4: Serialise, {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize =
T0::SERIALISE_LIMIT
+ T1::SERIALISE_LIMIT
+ T2::SERIALISE_LIMIT
+ T3::SERIALISE_LIMIT
+ T4::SERIALISE_LIMIT;
fn serialise(&self, stream: &mut Sstream) {
self.0.serialise(stream);
self.1.serialise(stream);
self.2.serialise(stream);
@ -123,7 +154,15 @@ where
T3: Serialise,
T4: Serialise,
T5: Serialise, {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize =
T0::SERIALISE_LIMIT
+ T1::SERIALISE_LIMIT
+ T2::SERIALISE_LIMIT
+ T3::SERIALISE_LIMIT
+ T4::SERIALISE_LIMIT
+ T5::SERIALISE_LIMIT;
fn serialise(&self, stream: &mut Sstream) {
self.0.serialise(stream);
self.1.serialise(stream);
self.2.serialise(stream);
@ -142,7 +181,16 @@ where
T4: Serialise,
T5: Serialise,
T6: Serialise, {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize =
T0::SERIALISE_LIMIT
+ T1::SERIALISE_LIMIT
+ T2::SERIALISE_LIMIT
+ T3::SERIALISE_LIMIT
+ T4::SERIALISE_LIMIT
+ T5::SERIALISE_LIMIT
+ T6::SERIALISE_LIMIT;
fn serialise(&self, stream: &mut Sstream) {
self.0.serialise(stream);
self.1.serialise(stream);
self.2.serialise(stream);
@ -163,7 +211,17 @@ where
T5: Serialise,
T6: Serialise,
T7: Serialise, {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize =
T0::SERIALISE_LIMIT
+ T1::SERIALISE_LIMIT
+ T2::SERIALISE_LIMIT
+ T3::SERIALISE_LIMIT
+ T4::SERIALISE_LIMIT
+ T5::SERIALISE_LIMIT
+ T6::SERIALISE_LIMIT
+ T7::SERIALISE_LIMIT;
fn serialise(&self, stream: &mut Sstream) {
self.0.serialise(stream);
self.1.serialise(stream);
self.2.serialise(stream);
@ -186,7 +244,18 @@ where
T6: Serialise,
T7: Serialise,
T8: Serialise, {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize =
T0::SERIALISE_LIMIT
+ T1::SERIALISE_LIMIT
+ T2::SERIALISE_LIMIT
+ T3::SERIALISE_LIMIT
+ T4::SERIALISE_LIMIT
+ T5::SERIALISE_LIMIT
+ T6::SERIALISE_LIMIT
+ T7::SERIALISE_LIMIT
+ T8::SERIALISE_LIMIT;
fn serialise(&self, stream: &mut Sstream) {
self.0.serialise(stream);
self.1.serialise(stream);
self.2.serialise(stream);
@ -211,7 +280,19 @@ where
T7: Serialise,
T8: Serialise,
T9: Serialise, {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize =
T0::SERIALISE_LIMIT
+ T1::SERIALISE_LIMIT
+ T2::SERIALISE_LIMIT
+ T3::SERIALISE_LIMIT
+ T4::SERIALISE_LIMIT
+ T5::SERIALISE_LIMIT
+ T6::SERIALISE_LIMIT
+ T7::SERIALISE_LIMIT
+ T8::SERIALISE_LIMIT
+ T9::SERIALISE_LIMIT;
fn serialise(&self, stream: &mut Sstream) {
self.0.serialise(stream);
self.1.serialise(stream);
self.2.serialise(stream);
@ -238,7 +319,20 @@ where
T8: Serialise,
T9: Serialise,
T10: Serialise, {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize =
T0::SERIALISE_LIMIT
+ T1::SERIALISE_LIMIT
+ T2::SERIALISE_LIMIT
+ T3::SERIALISE_LIMIT
+ T4::SERIALISE_LIMIT
+ T5::SERIALISE_LIMIT
+ T6::SERIALISE_LIMIT
+ T7::SERIALISE_LIMIT
+ T8::SERIALISE_LIMIT
+ T9::SERIALISE_LIMIT
+ T10::SERIALISE_LIMIT;
fn serialise(&self, stream: &mut Sstream) {
self.0.serialise(stream);
self.1.serialise(stream);
self.2.serialise(stream);
@ -267,7 +361,21 @@ where
T9: Serialise,
T10: Serialise,
T11: Serialise, {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize =
T0::SERIALISE_LIMIT
+ T1::SERIALISE_LIMIT
+ T2::SERIALISE_LIMIT
+ T3::SERIALISE_LIMIT
+ T4::SERIALISE_LIMIT
+ T5::SERIALISE_LIMIT
+ T6::SERIALISE_LIMIT
+ T7::SERIALISE_LIMIT
+ T8::SERIALISE_LIMIT
+ T9::SERIALISE_LIMIT
+ T10::SERIALISE_LIMIT
+ T11::SERIALISE_LIMIT;
fn serialise(&self, stream: &mut Sstream) {
self.0.serialise(stream);
self.1.serialise(stream);
self.2.serialise(stream);
@ -284,7 +392,9 @@ where
}
impl<T: Serialise, const N: usize> Serialise for [T; N] {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize = T::SERIALISE_LIMIT * N;
fn serialise(&self, stream: &mut Sstream) {
u64::try_from(self.len()).unwrap().serialise(stream);
for v in self { v.serialise(stream) }
@ -292,35 +402,45 @@ impl<T: Serialise, const N: usize> Serialise for [T; N] {
}
impl Serialise for () {
fn serialise(&self, _stream: &mut SStream) { }
const SERIALISE_LIMIT: usize = size_of::<Self>();
fn serialise(&self, _stream: &mut Sstream) { }
}
impl Serialise for bool {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize = size_of::<Self>();
fn serialise(&self, stream: &mut Sstream) {
u8::from(*self).serialise(stream)
}
}
impl Serialise for char {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize = size_of::<Self>();
fn serialise(&self, stream: &mut Sstream) {
u32::from(*self).serialise(stream)
}
}
impl Serialise for Infallible {
fn serialise(&self, _stream: &mut SStream) { unreachable!() }
const SERIALISE_LIMIT: usize = size_of::<Self>();
fn serialise(&self, _stream: &mut Sstream) { unreachable!() }
}
impl<T: Serialise> Serialise for Option<T> {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize = T::SERIALISE_LIMIT + 0x1;
fn serialise(&self, stream: &mut Sstream) {
match *self {
None => {
stream.append(&[0x00]);
stream.append_byte(0x00);
stream.append(&vec![0x00; size_of::<T>()]);
},
Some(ref v) => {
stream.append(&[0x01]);
stream.append_byte(0x01);
v.serialise(stream);
},
};
@ -328,15 +448,23 @@ impl<T: Serialise> Serialise for Option<T> {
}
impl<T: Serialise, E: Serialise> Serialise for Result<T, E> {
fn serialise(&self, stream: &mut SStream) {
const SERIALISE_LIMIT: usize = const {
if size_of::<T>() > size_of::<T>() {
size_of::<T>()
} else {
size_of::<E>()
}
};
fn serialise(&self, stream: &mut Sstream) {
match *self {
Ok(ref v) => {
stream.append(&[0x00]);
stream.append_byte(0x00);
v.serialise(stream);
},
Err(ref e) => {
stream.append(&[0x01]);
stream.append_byte(0x01);
e.serialise(stream);
},
};

View file

@ -1,10 +1,29 @@
// Copyright 2022-2024 Gabriel Bjørnager Jensen.
// 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 implied warranty of MERCHANTABILITY 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::{FixedString, SStream, Serialise};
use crate::{FixedString, Serialise, Sstream};
#[test]
fn test_serialise() {
let mut stream = SStream::new();
let mut stream = Sstream::new();
0x00_u8.serialise(&mut stream);
0xFF_u8.serialise(&mut stream);

View file

@ -19,7 +19,7 @@
// er General Public License along with bzipper. If
// not, see <https://www.gnu.org/licenses/>.
use crate::{DStream, Serialise};
use crate::{Dstream, Serialise};
use std::fmt::{Debug, Formatter};
use std::mem::size_of;
@ -27,36 +27,40 @@ use std::mem::size_of;
/// Byte stream for serialisation.
///
/// The bytes themselves are contained by the type.
/// The stream can
/// 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>);
pub struct Sstream(pub(in crate) Vec<u8>);
impl SStream {
impl Sstream {
/// Constructs a new, empty byte stream.
#[inline(always)]
#[must_use]
pub const fn new() -> Self { Self(Vec::new()) }
/// Extends the byte stream.
#[inline(always)]
pub fn append(&mut self, extra: &[u8]) {
self.0.extend(extra);
}
/// Converts the stream to a `DStream` object.
/// Extends the byte stream by a single byte.
pub fn append_byte(&mut self, extra: u8) {
self.0.push(extra);
}
/// Converts the stream to a `Dstream` object.
///
/// The returned object references the original stream.
#[inline(always)]
#[must_use]
pub fn as_d_stream(&self) -> DStream { DStream::new(&self.0) }
pub fn as_dstream(&self) -> Dstream { Dstream::new(&self.0) }
}
impl AsRef<[u8]> for SStream {
impl AsRef<[u8]> for Sstream {
#[inline(always)]
fn as_ref(&self) -> &[u8] { self.0.as_ref() }
}
impl Debug for SStream {
impl Debug for Sstream {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "[")?;
@ -68,12 +72,12 @@ impl Debug for SStream {
}
}
impl Default for SStream {
impl Default for Sstream {
#[inline(always)]
fn default() -> Self { Self::new() }
}
impl<T: Serialise> From<&T> for SStream {
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);
@ -82,7 +86,7 @@ impl<T: Serialise> From<&T> for SStream {
}
}
impl From<SStream> for Box<[u8]> {
impl From<Sstream> for Box<[u8]> {
#[inline(always)]
fn from(value: SStream) -> Self { value.0.into_boxed_slice() }
fn from(value: Sstream) -> Self { value.0.into_boxed_slice() }
}