diff --git a/src/std/atomic.rs b/src/std/atomic.rs index cc6354d..4beeb73 100644 --- a/src/std/atomic.rs +++ b/src/std/atomic.rs @@ -3,7 +3,7 @@ pub mod plain; -use std::{error::Error, marker::PhantomData, rc::Rc}; +use std::marker::PhantomData; use crate::core::*; use crate::std::*; diff --git a/src/std/atomic/plain.rs b/src/std/atomic/plain.rs index 0a1aea3..15169ef 100644 --- a/src/std/atomic/plain.rs +++ b/src/std/atomic/plain.rs @@ -1,7 +1,5 @@ //! [`Plain`] type for storing raw byte sequnces. -use std::fmt::Display; - use crate::std::atomic::*; /// Raw bytes storage. Use [`Plain::raw`] to get the data. diff --git a/src/std/collections.rs b/src/std/collections.rs index c93897d..3061a44 100644 --- a/src/std/collections.rs +++ b/src/std/collections.rs @@ -1 +1,3 @@ +//! Standard generic collections. + pub mod stack; diff --git a/src/std/collections/stack.rs b/src/std/collections/stack.rs index be3f01c..82bdd53 100644 --- a/src/std/collections/stack.rs +++ b/src/std/collections/stack.rs @@ -1,13 +1,20 @@ +//! Basic implementation of a stack/linked list. + use crate::core::*; +use crate::std::inlining::*; use crate::std::nullable::*; use crate::std::*; +/// Node containing a (nullable) reference to the next node and an element. pub struct StackNode<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> { + /// Reference comes first due to being inlineable. pub rest: Stack<'a, Ctx, A>, + /// Unlike the original implementation in Python, doesn't default to using Point. pub element: Rc, } -type Stack<'a, Ctx, A> = Nullable<'a, Ctx, StackNode<'a, Ctx, A>>; +/// Type representing a stack, an alias to a [Nullable] of a [StackNode]. +pub type Stack<'a, Ctx, A> = Nullable<'a, Ctx, StackNode<'a, Ctx, A>>; pub struct StackNodeFactory<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> { element_factory: A::Fctr, @@ -106,16 +113,26 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Factory<'a, Ctx> } } +/// See [`StackVecResult`]. pub type StackFaiure<'a, Ctx, A> = ResolutionFailure<'a, Ctx, StackNode<'a, Ctx, A>>; +/// See [`StackVecWrapped`]. pub type StackVecResult<'a, Ctx, A> = Result>, StackFaiure<'a, Ctx, A>>; +/// See [`ExtStack::vec`]. pub type StackVecWrapped<'a, Ctx, A> = Wrapped<'a, Ctx, StackVecResult<'a, Ctx, A>>; +/// Extention trait with helper methods for [Stack]s. pub trait ExtStack<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>: Mentionable<'a, Ctx> { + /// Get an empty stack ([`Nullable::Null`]). fn empty(factory: A::Fctr) -> Self; + /// Get the corresponding factory. fn f(factory: A::Fctr) -> Self::Fctr; + /// Add one element. + /// + /// Note: consumes the stack. For non-consuming version do `.clone()` before adding. fn add(self, element: A) -> Self; + /// Collect all the elements into a [`Vec`]. fn vec(self) -> StackVecWrapped<'a, Ctx, A>; } @@ -204,3 +221,28 @@ mod tests { Ok(()) } } + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> InlineableFactory + for StackNodeFactory<'a, Ctx, A> +where + A::Fctr: InlineableFactory, +{ +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> FixedSizeFactory + for StackNodeFactory<'a, Ctx, A> +where + A::Fctr: FixedSizeFactory, +{ + fn size(&self) -> usize { + Stack::<'a, Ctx, A>::SIZE + self.element_factory.size() + } +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> ConstSizeFactory + for StackNodeFactory<'a, Ctx, A> +where + A::Fctr: ConstSizeFactory, +{ + const SIZE: usize = { Stack::<'a, Ctx, A>::SIZE + A::Fctr::SIZE }; +} diff --git a/src/std/inlining.rs b/src/std/inlining.rs index 8b13789..478d7b2 100644 --- a/src/std/inlining.rs +++ b/src/std/inlining.rs @@ -1 +1,191 @@ +pub mod staticpair; +use super::atomic::*; +use crate::core::*; +use crate::std::*; + +pub trait InlineableFactory {} + +pub trait FixedSizeFactory: InlineableFactory { + fn size(&self) -> usize; +} + +pub trait ConstSizeFactory: FixedSizeFactory { + const SIZE: usize; +} + +pub trait InlineableObject<'a, Ctx: 'a + Context>: 'a {} + +pub trait FixedSizeObject<'a, Ctx: 'a + Context>: InlineableObject<'a, Ctx> { + fn size(&self) -> usize; +} + +pub trait ConstSizeObject<'a, Ctx: 'a + Context>: FixedSizeObject<'a, Ctx> { + const SIZE: usize; +} + +pub trait InlineableAtomic {} + +pub trait ConstSizeAtomic: InlineableAtomic { + const SIZE: usize; +} + +impl InlineableFactory for AtomicFactory {} + +impl FixedSizeFactory for AtomicFactory { + fn size(&self) -> usize { + A::SIZE + } +} + +impl ConstSizeFactory for AtomicFactory { + const SIZE: usize = A::SIZE; +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> InlineableObject<'a, Ctx> for A where + A::Fctr: InlineableFactory +{ +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> FixedSizeObject<'a, Ctx> for A +where + A::Fctr: FixedSizeFactory, +{ + fn size(&self) -> usize { + self.factory().size() + } +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> ConstSizeObject<'a, Ctx> for A +where + A::Fctr: ConstSizeFactory, +{ + const SIZE: usize = A::Fctr::SIZE; +} + +#[derive(Debug)] +pub struct SizeError { + expected: usize, + received: usize, +} + +impl Display for SizeError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!( + "expected {} bytes, read/wrote {} instead.", + self.expected, self.received + )) + } +} + +impl Error for SizeError {} + +#[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 { + CheckedParseError::Parse(parse_error) => f.write_fmt(format_args!("{}", parse_error)), + CheckedParseError::Size(size_error) => { + f.write_fmt(format_args!("size check failed: {}", size_error)) + } + } + } +} + +impl From

for CheckedParseError

{ + fn from(value: P) -> Self { + Self::Parse(value) + } +} + +pub type CheckedParseResult<'a, Ctx, F> = + Result<>::Mtbl, CheckedParseError<>::ParseError>>; + +pub trait CheckedParse<'a, Ctx: 'a + Context>: FixedSizeFactory + Factory<'a, Ctx> { + fn deserialize_checked( + &self, + deserializer: &mut dyn Deserializer, + resolver: Rc>, + ) -> CheckedParseResult<'a, Ctx, Self>; +} + +pub trait CheckedSerialize<'a, Ctx: 'a + Context>: Serializable + FixedSizeObject<'a, Ctx> { + fn serialize_checked(&self, serializer: &mut dyn Serializer) -> Result<(), SizeError>; +} + +impl<'a, Ctx: 'a + Context, F: FixedSizeFactory + Factory<'a, Ctx>> CheckedParse<'a, Ctx> for F { + fn deserialize_checked( + &self, + deserializer: &mut dyn Deserializer, + resolver: Rc>, + ) -> CheckedParseResult<'a, Ctx, Self> { + let expected_size = self.size(); + let start = deserializer.tell(); + let result = self.deserialize(deserializer, resolver)?; + let end = 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, + })) + } + } +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx> + FixedSizeObject<'a, Ctx>> + CheckedSerialize<'a, Ctx> for A +{ + 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, + }) + } + } +} + +pub trait AlwaysFixedSize { + fn _size(&self) -> usize; +} + +impl InlineableFactory for F {} + +impl FixedSizeFactory for F { + fn size(&self) -> usize { + self._size() + } +} + +pub trait AlwaysConstSize { + const _SIZE: usize; +} + +impl AlwaysFixedSize for F { + fn _size(&self) -> usize { + Self::_SIZE + } +} + +impl ConstSizeFactory for F { + const SIZE: usize = Self::_SIZE; +} + +impl AlwaysConstSize for PointFactory { + const _SIZE: usize = HASH_SIZE; +} diff --git a/src/std/inlining/staticpair.rs b/src/std/inlining/staticpair.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/std/inlining/staticpair.rs @@ -0,0 +1 @@ + diff --git a/src/std/nullable.rs b/src/std/nullable.rs index 932d558..0f578f0 100644 --- a/src/std/nullable.rs +++ b/src/std/nullable.rs @@ -1,16 +1,19 @@ //! This module introduces [`Option`]-like concepts into RADN typesystem using [`Nullable`]. +use super::inlining::*; use crate::core::*; use crate::std::*; /// Nullable reference type. Made for use as a linking element in data structures. pub enum Nullable<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> { + /// Unlike original Python implementation, stores the factory only in the null case. Null(A::Fctr), NotNull(Point<'a, Ctx, A>), } /// Nullable reference factory. pub struct NullableFactory<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> { + /// Factory of the referenced object. factory: A::Fctr, } @@ -81,6 +84,7 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Factory<'a, Ctx> } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Nullable<'a, Ctx, Nullable<'a, Ctx, A>> { + /// Reduce [Nullable] nesting. pub fn join(&self) -> Resolution<'a, Ctx, Nullable<'a, Ctx, A>> { match self { Nullable::Null(nullable_factory) => { @@ -106,3 +110,9 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Clone for Nullable<'a, Ctx, } } } + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> AlwaysConstSize + for NullableFactory<'a, Ctx, A> +{ + const _SIZE: usize = HASH_SIZE; +}