//! Traits to better express parsing semantics. mod modes; pub mod static_pair; use crate::rcore::*; use super::{ atomic::{atomic_object::*, *}, *, }; pub use self::modes::InliningMode; pub type IParseResult<'a, Ctx, F, I> = Result<(Mtbl<'a, Ctx, F>, I), ParseError<'a, Ctx, F>>; /// This factory should return an error on EOF. pub trait InlineableFactory<'a, Ctx: Context<'a>>: FactoryBase<'a, Ctx> + ParseMode { fn extension_error(&self, tail: &[u8]) -> Self::ParseError; fn ideserialize>(&self, inctx: I) -> IParseResult<'a, Ctx, Self, I>; } /// This factory always reads the same amount of bytes or returns error. pub trait FixedSizeFactory<'a, Ctx: Context<'a>>: InlineableFactory<'a, Ctx> { /// For [`ConstSizeFactory`] this must return [`ConstSizeFactory::SIZE`]. fn size(&self) -> usize; } /// Compile-time analogue of [`FixedSizeFactory`]. pub trait ConstSizeFactory<'a, Ctx: Context<'a>>: FixedSizeFactory<'a, Ctx> { /// Must be equal to [`FixedSizeFactory::size()`]. const SIZE: usize; } /// Object analogue of [`InlineableFactory`]. pub trait InlineableObject<'a, Ctx: Context<'a>>: Mentionable<'a, Ctx> {} /// Object analogue of [`FixedSizeFactory`]. pub trait FixedSizeObject<'a, Ctx: Context<'a>>: InlineableObject<'a, Ctx> { /// For [`ConstSizeObject`] this must return [`ConstSizeObject::SIZE`]. fn size(&self) -> usize; } /// Object analogue of [`ConstSizeFactory`]. pub trait ConstSizeObject<'a, Ctx: Context<'a>>: FixedSizeObject<'a, Ctx> { /// Must be equal to [`FixedSizeObject::size()`]. const SIZE: usize; } pub type ADParseResult = Result<(A, D), AParseError>; /// Atomic analogue of [`InlineableFactory`]/[`InlineableObject`]. pub trait InlineableAtomic: AtomicBase + ImplMode { fn a_extension_error(tail: &[u8]) -> Self::AParseError; fn a_ideserialize(inlining: D) -> ADParseResult; } /// Atomic analogue of [`ConstSizeFactory`]/[`ConstSizeObject`]. /// /// Note: `FixedSizeAtomic` doesn't exist because it would /// either be const anyway /// or have a very undesireable implementation. pub trait ConstSizeAtomic: InlineableAtomic { const SIZE: usize; } impl<'a, Ctx: Context<'a>, A: InlineableAtomic> InlineableFactory<'a, Ctx> for AtomicFactory where ::WithMode: AoProxy<'a, Ctx, Fctr = Self, A = A>, { fn extension_error(&self, tail: &[u8]) -> Self::ParseError { A::a_extension_error(tail) } fn ideserialize>(&self, inctx: I) -> IParseResult<'a, Ctx, Self, I> { let (a, inctx) = A::a_ideserialize(inctx)?; Ok(( <::WithMode as AoProxy<'a, Ctx>>::wrap(a), inctx, )) } } impl<'a, Ctx: Context<'a>, A: ConstSizeAtomic> FixedSizeFactory<'a, Ctx> for AtomicFactory where ::WithMode: AoProxy<'a, Ctx, Fctr = Self, A = A>, { fn size(&self) -> usize { A::SIZE } } impl<'a, Ctx: Context<'a>, A: ConstSizeAtomic> ConstSizeFactory<'a, Ctx> for AtomicFactory where ::WithMode: AoProxy<'a, Ctx, Fctr = Self, A = A>, { const SIZE: usize = A::SIZE; } impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> InlineableObject<'a, Ctx> for A where A::Fctr: InlineableFactory<'a, Ctx> { } impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> FixedSizeObject<'a, Ctx> for A where A::Fctr: FixedSizeFactory<'a, Ctx>, { fn size(&self) -> usize { self.factory().size() } } impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> ConstSizeObject<'a, Ctx> for A where A::Fctr: ConstSizeFactory<'a, Ctx>, { const SIZE: usize = A::Fctr::SIZE; } /// Error returned by [`CheckedParse::deserialize_checked`]/[`CheckedSerialize::serialize_checked`]. #[derive(Debug)] pub struct SizeError { expected: usize, received: usize, } impl Display for SizeError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "expected {} bytes, read/wrote {} instead", self.expected, self.received ) } } impl Error for SizeError {} /// Wrapper for [`SizeError`]/[`FactoryBase::ParseError`]. #[derive(Debug)] pub enum CheckedParseError { Parse(P), Size(SizeError), } impl Display for CheckedParseError

{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Parse(parse_error) => write!(f, "{}", parse_error), Self::Size(size_error) => { write!(f, "size check failed: {}", size_error) } } } } impl From

for CheckedParseError

{ fn from(value: P) -> Self { Self::Parse(value) } } pub type CheckedParseFailure<'a, Ctx, F> = CheckedParseError>; /// Returned by [`CheckedParse::deserialize_checked`]. pub type CheckedParseResult<'a, Ctx, F> = Result, CheckedParseFailure<'a, Ctx, F>>; /// Extension trait for factories that ensures fixed size read. pub trait CheckedParse<'a, Ctx: Context<'a>>: FixedSizeFactory<'a, Ctx> { /// Verify proper read length using [`Deserializer::tell`]. fn deserialize_checked(&self, inctx: impl InCtx<'a, Ctx>) -> CheckedParseResult<'a, Ctx, Self> { let expected_size = self.size(); let start = inctx.itell(); let (result, inctx) = self.ideserialize(inctx)?; let end = inctx.itell(); let received_size = end - start; if received_size == expected_size { Ok(result) } else { Err(CheckedParseError::Size(SizeError { expected: expected_size, received: received_size, })) } } } /// Extension trait for factories that ensures fixed size write. pub trait CheckedSerialize<'a, Ctx: Context<'a>>: Serializable + FixedSizeObject<'a, Ctx> { /// Verify proper write length using [`Serializer::tell`]. fn serialize_checked(&self, serializer: &mut dyn Serializer) -> Result<(), SizeError> { let expected_size = self.size(); let start = serializer.tell(); self.serialize(serializer); let end = serializer.tell(); let received_size = end - start; if received_size == expected_size { Ok(()) } else { Err(SizeError { expected: expected_size, received: received_size, }) } } } impl<'a, Ctx: Context<'a>, F: FixedSizeFactory<'a, Ctx>> CheckedParse<'a, Ctx> for F {} impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx> + FixedSizeObject<'a, Ctx>> CheckedSerialize<'a, Ctx> for A { } /// Trait useful for objects which aren't influenced by /// whether some other type (for example, a generic parameter type) /// is fixed-size or not. pub trait AlwaysFixedSize { fn _size(&self) -> usize; } impl<'a, Ctx: Context<'a>, F: AlwaysFixedSize + InlineableFactory<'a, Ctx>> FixedSizeFactory<'a, Ctx> for F { fn size(&self) -> usize { self._size() } } /// Compile-time analogue of [`AlwaysFixedSize`]. pub trait AlwaysConstSize { const _SIZE: usize; } impl AlwaysFixedSize for F { fn _size(&self) -> usize { Self::_SIZE } } impl<'a, Ctx: Context<'a>, F: AlwaysConstSize + InlineableFactory<'a, Ctx>> ConstSizeFactory<'a, Ctx> for F { const SIZE: usize = Self::_SIZE; }