summaryrefslogtreecommitdiff
path: root/bzipper/src/sstream/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'bzipper/src/sstream/mod.rs')
-rw-r--r--bzipper/src/sstream/mod.rs93
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 } }
}