diff options
Diffstat (limited to 'bzipper/src/sstream/mod.rs')
-rw-r--r-- | bzipper/src/sstream/mod.rs | 93 |
1 files changed, 79 insertions, 14 deletions
diff --git a/bzipper/src/sstream/mod.rs b/bzipper/src/sstream/mod.rs index 257be95..470a27f 100644 --- a/bzipper/src/sstream/mod.rs +++ b/bzipper/src/sstream/mod.rs @@ -19,16 +19,17 @@ // er General Public License along with bzipper. If // not, see <https://www.gnu.org/licenses/>. -use crate::{Error, Result, Serialise}; +use crate::{Dstream, Error, Result}; use core::cell::Cell; +use core::fmt::{Debug, Formatter}; -/// Byte stream for deserialisation. +/// Byte stream suitable for serialisation. /// -/// This type borrows a slice, keeping track internally of the used bytes. +/// This type mutably borrows a buffer, keeping track internally of the used bytes. pub struct Sstream<'a> { - buf: &'a mut [u8], - pos: Cell<usize>, + pub(in crate) buf: &'a mut [u8], + pub(in crate) pos: Cell<usize>, } impl<'a> Sstream<'a> { @@ -37,22 +38,86 @@ impl<'a> Sstream<'a> { #[must_use] pub fn new(buf: &'a mut [u8]) -> Self { Self { buf, pos: Cell::new(0x0) } } - /// Extends the stream by appending a new serialisation. - /// - /// # Errors - /// - /// If the stream cannot hold any arbitrary serialisation of `T`, an [`EndOfStream`](Error::EndOfStream) instance is returned. + /// Appends raw bytes to the stream. #[inline] - pub fn append<T: Serialise>(&mut self, value: &T) -> Result<()> { + pub fn write(&mut self, bytes: &[u8]) -> Result<()> { let rem = self.buf.len() - self.pos.get(); - let req = T::SERIALISED_SIZE; + let req = bytes.len(); - if rem < req { return Err(Error::EndOfStream { req, rem }) }; + if rem < req { return Err(Error::EndOfStream { req, rem }) } let start = self.pos.get(); let stop = start + req; self.pos.set(stop); - value.serialise(&mut self.buf[start..stop]) + + let buf = &mut self.buf[start..stop]; + buf.copy_from_slice(bytes); + + Ok(()) } + + /// Gets a pointer to the first byte in the stream. + #[inline(always)] + #[must_use] + pub const fn as_ptr(&self) -> *const u8 { self.buf.as_ptr() } + + /// Gets an immutable slice of the stream. + #[inline(always)] + #[must_use] + pub const fn as_slice(&self) -> &[u8] { + let ptr = self.as_ptr(); + let len = self.len(); + + unsafe { core::slice::from_raw_parts(ptr, len) } + } + + /// Gets the length of the stream. + #[inline(always)] + #[must_use] + pub const fn len(&self) -> usize { unsafe { self.pos.as_ptr().read() } } + + /// Tests if the stream is empty. + /// + /// If no serialisations have been made so far, this method returns `false`. + #[inline(always)] + #[must_use] + pub const fn is_empty(&self) -> bool { self.len() == 0x0 } + + /// Tests if the stream is full. + /// + /// Note that zero-sized types such as [`()`](unit) can still be serialised into this stream. + #[inline(always)] + #[must_use] + pub const fn is_full(&self) -> bool { self.len() == self.buf.len() } +} + +impl Debug for Sstream<'_> { + #[inline(always)] + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { Debug::fmt(self.as_slice(), f) } +} + +impl<'a> From<&'a mut [u8]> for Sstream<'a> { + #[inline(always)] + fn from(value: &'a mut [u8]) -> Self { Self::new(value) } +} + +impl PartialEq for Sstream<'_> { + #[inline(always)] + fn eq(&self, other: &Self) -> bool { self.as_slice() == other.as_slice() } +} + +impl PartialEq<&[u8]> for Sstream<'_> { + #[inline(always)] + fn eq(&self, other: &&[u8]) -> bool { self.as_slice() == *other } +} + +impl<const N: usize> PartialEq<[u8; N]> for Sstream<'_> { + #[inline(always)] + fn eq(&self, other: &[u8; N]) -> bool { self.as_slice() == other.as_slice() } +} + +impl<'a> From<Sstream<'a>> for Dstream<'a> { + #[inline(always)] + fn from(value: Sstream<'a>) -> Self { Self { data: value.buf, pos: value.pos } } } |