1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
// 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/>.
#[cfg(test)]
mod test;
use crate::{Deserialise, Result, Serialise};
use alloc::vec;
use alloc::boxed::Box;
use core::fmt::{Debug, Formatter};
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
// We cannot use arrays for the `Buffer` type as
// that would require `generic_const_exprs`.
/// Typed (de)serialisation buffer.
///
/// This structure is intended as a lightweight wrapper around byte buffers for specific (de)serialisations of specific types.
///
/// The methods [`write`](Self::write) and [`read`](Self::read) can be used to <interpreting> the internal buffer.
/// Other methods exist for accessing the internal buffer directly.
///
/// # Examples
///
/// Create a buffer for holding a `Request` enumeration:
///
/// ```
/// use bzipper::{Buffer, FixedString, Serialise};
///
/// #[derive(Serialise)]
/// enum Request {
/// Join { username: FixedString<0x10> },
///
/// Quit { username: FixedString<0x10> },
///
/// SendMessage { message: FixedString<0x20> },
/// }
///
/// use Request::*;
///
/// let join_request = Join { username: FixedString::try_from("epsiloneridani").unwrap() };
///
/// let mut buf = Buffer::<Request>::new();
/// buf.write(&join_request);
///
/// // Do something with the buffer...
/// ```
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
#[derive(Clone, Eq, PartialEq)]
pub struct Buffer<T: Serialise> {
buf: Box<[u8]>,
_phanton: PhantomData<T>
}
impl<T: Serialise> Buffer<T> {
/// Allocates a new buffer suitable for (de)serialisation.
#[must_use]
pub fn new() -> Self { Self { buf: vec![0x00; T::SERIALISED_SIZE].into(), _phanton: PhantomData } }
/// Serialises into the contained buffer.
#[inline(always)]
pub fn write(&mut self, value: &T) -> Result<()> { value.serialise(&mut self.buf) }
/// Retrieves a pointer to the first byte.
#[inline(always)]
#[must_use]
pub const fn as_ptr(&self) -> *const u8 { self.buf.as_ptr() }
/// Retrieves a mutable pointer to the first byte.
#[inline(always)]
#[must_use]
pub fn as_mut_ptr(&mut self) -> *mut u8 { self.buf.as_mut_ptr() }
/// Gets a slice of the internal buffer.
#[inline(always)]
#[must_use]
pub const fn as_slice(&self) -> &[u8] { unsafe { core::slice::from_raw_parts(self.as_ptr(), self.len()) } }
/// Gets a mutable slice of the internal buffer.
#[inline(always)]
#[must_use]
pub fn as_mut_slice(&mut self) -> &mut [u8] { &mut self.buf }
/// Gets the length of the buffer.
///
/// This is defined as (and therefore always equal to) the value of [SERIALISED_SIZE](Serialise::SERIALISED_SIZE) as specified by `T`.
#[allow(clippy::len_without_is_empty)]
#[inline(always)]
#[must_use]
pub const fn len(&self) -> usize { T::SERIALISED_SIZE }
}
impl<T: Deserialise> Buffer<T> {
/// Deserialises from the contained buffer.
#[inline(always)]
pub fn read(&self) -> Result<T> { T::deserialise(&self.buf) }
}
impl<T: Serialise> AsMut<[u8]> for Buffer<T> {
#[inline(always)]
fn as_mut(&mut self) -> &mut [u8] { self.as_mut_slice() }
}
impl<T: Serialise> AsRef<[u8]> for Buffer<T> {
#[inline(always)]
fn as_ref(&self) -> &[u8] { self.as_slice() }
}
impl<T: Serialise> Debug for Buffer<T> {
#[inline(always)]
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { write!(f, "{:?}", self.as_slice()) }
}
impl<T: Serialise> Default for Buffer<T> {
#[inline(always)]
fn default() -> Self { Self::new() }
}
impl<T: Serialise> Deref for Buffer<T> {
type Target = [u8];
#[inline(always)]
fn deref(&self) -> &Self::Target { self.as_slice() }
}
impl<T: Serialise> DerefMut for Buffer<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_slice() }
}
impl<T: Serialise> PartialEq<&[u8]> for Buffer<T> {
#[inline(always)]
fn eq(&self, other: &&[u8]) -> bool { self.as_slice() == *other }
}