//! Traits to better express parsing semantics. pub mod static_pair; use crate::rcore::*; use super::{ atomic::{atomic_object::*, *}, point::*, *, }; impl Inlining for &mut D { fn iread_n( self, n: usize, ok: impl FnOnce(&[u8]) -> A, err: impl FnOnce(&[u8]) -> E, ) -> Result<(A, Self), E> { let slice = self.read_n(n); if slice.len() == n { Ok((ok(slice), self)) } else { Err(err(slice)) } } fn iread_all(self, ok: impl FnOnce(&[u8]) -> A) -> A { ok(self.read_all()) } fn itell(&self) -> usize { self.tell() } } impl<'a: 'c, 'c, Ctx: Context<'a>> Inlining for &'c mut dyn DeCtx<'a, Ctx> { fn iread_n( self, n: usize, ok: impl FnOnce(&[u8]) -> A, err: impl FnOnce(&[u8]) -> E, ) -> Result<(A, Self), E> { match self.deserializer().iread_n(n, ok, err) { Ok((a, _)) => Ok((a, self)), Err(e) => Err(e), } } fn iread_all(self, ok: impl FnOnce(&[u8]) -> A) -> A { self.deserializer().iread_all(ok) } fn itell(&self) -> usize { self.tell() } } impl<'a: 'c, 'c, Ctx: Context<'a>> InCtx<'a, Ctx> for &'c mut dyn DeCtx<'a, Ctx> { fn icnext_address(self, err: impl FnOnce(&[u8]) -> E) -> Result<(Address, Self), E> { let (addresses, deserialiser, _) = self.adr(); match deserialiser.inext_address(addresses, err) { Ok((address, _)) => Ok((address, self)), Err(e) => Err(e), } } fn iresolver(&self) -> Rc> { self.resolver() } } pub type ResultDyn = Result<(A, I), Vec>; pub trait InCtxDyn<'a: 'c, 'c, Ctx: Context<'a>>: 'c { fn idread_n(self, n: usize) -> ResultDyn, Box>>; fn idread_all(self) -> Vec; fn idtell(&self) -> usize; fn idnext_address(self) -> ResultDyn>>; fn idresolver(&self) -> Rc>; } impl<'a: 'c, 'c, Ctx: Context<'a>, I: 'c + InCtx<'a, Ctx>> InCtxDyn<'a, 'c, Ctx> for I { fn idread_n(self, n: usize) -> ResultDyn, Box>> { let (vec, i) = self.iread_n(n, |slice| Vec::from(slice), |slice| Vec::from(slice))?; Ok((vec, Box::new(i))) } fn idread_all(self) -> Vec { self.iread_all(|slice| Vec::from(slice)) } fn idtell(&self) -> usize { self.itell() } fn idnext_address(self) -> ResultDyn>> { let (address, i) = self.icnext_address(|slice| Vec::from(slice))?; Ok((address, Box::new(i))) } fn idresolver(&self) -> Rc> { self.iresolver() } } impl<'a: 'c, 'c, Ctx: Context<'a>> Inlining for Box> { fn iread_n( self, n: usize, ok: impl FnOnce(&[u8]) -> A, err: impl FnOnce(&[u8]) -> E, ) -> Result<(A, Self), E> { let (vec, i) = self.idread_n(n).map_err(|vec| err(&vec))?; Ok((ok(&vec), i)) } fn iread_all(self, ok: impl FnOnce(&[u8]) -> A) -> A { ok(&self.idread_all()) } fn itell(&self) -> usize { self.idtell() } } impl<'a: 'c, 'c, Ctx: Context<'a>> InCtx<'a, Ctx> for Box> { fn icnext_address(self, err: impl FnOnce(&[u8]) -> E) -> Result<(Address, Self), E> { self.idnext_address().map_err(|vec| err(&vec)) } fn iresolver(&self) -> Rc> { self.idresolver() } } pub type IParseResult<'a, Ctx, F, I> = Result<(Mtbl<'a, Ctx, F>, I), >::ParseError>; /// This factory should return an error on EOF. pub trait InlineableFactory<'a, Ctx: Context<'a>>: Factory<'a, Ctx> { 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: Atomic { fn a_extension_error(tail: &[u8]) -> Self::AParseError; fn a_ideserialize(deserializer: 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 { 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((a.into(), inctx)) } } impl<'a, Ctx: Context<'a>, A: ConstSizeAtomic> FixedSizeFactory<'a, Ctx> for AtomicFactory { fn size(&self) -> usize { A::SIZE } } impl<'a, Ctx: Context<'a>, A: ConstSizeAtomic> ConstSizeFactory<'a, Ctx> for AtomicFactory { 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`]/[`Factory::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) } } /// Returned by [`CheckedParse::deserialize_checked`]. pub type CheckedParseResult<'a, Ctx, F> = Result, CheckedParseError>>; /// 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, dectx: &mut dyn DeCtx<'a, Ctx>, ) -> CheckedParseResult<'a, Ctx, Self> { let expected_size = self.size(); let start = dectx.deserializer().tell(); let result = self.deserialize(dectx)?; let end = dectx.deserializer().tell(); 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; } impl<'a, Ctx: Context<'a>, F: Factory<'a, Ctx>> InlineableFactory<'a, Ctx> for PointFactory { fn extension_error(&self, tail: &[u8]) -> Self::ParseError { PointParseError::WrongLength(HASH_SIZE + tail.len()) } fn ideserialize>(&self, inctx: I) -> IParseResult<'a, Ctx, Self, I> { inctx.icnext_point(self.inner(), |slice| PointParseError::from(slice)) } } impl AlwaysConstSize for PointFactory { const _SIZE: usize = HASH_SIZE; }