//! This module introduces [`Option`]-like concepts into RADN typesystem using [`Nullable`]. use super::inlining::*; use super::point::*; 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, } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Serializable for Nullable<'a, Ctx, A> { fn serialize(&self, serializer: &mut dyn Serializer) { serializer.write(match self { Nullable::Null(_) => &HASH_ZEROS, Nullable::NotNull(point) => &point.point, }) } } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Mentionable<'a, Ctx> for Nullable<'a, Ctx, A> { type Fctr = NullableFactory<'a, Ctx, A>; fn factory(&self) -> Self::Fctr { match self { Nullable::Null(factory) => NullableFactory { factory: factory.clone(), }, Nullable::NotNull(point) => NullableFactory { factory: point.origin.factory(), }, } } fn points(&self, points: &mut Vec>>) { match self { Nullable::Null(_) => {} Nullable::NotNull(point) => points.push(point.typeless()), }; } } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Clone for NullableFactory<'a, Ctx, A> { fn clone(&self) -> Self { Self { factory: self.factory.clone(), } } } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Factory<'a, Ctx> for NullableFactory<'a, Ctx, A> { type Mtbl = Nullable<'a, Ctx, A>; type ParseError = PointParseError; fn deserialize( &self, deserializer: &mut dyn Deserializer, resolver: std::rc::Rc>, addresses: &mut Addresses, ) -> ParseResult<'a, Ctx, Self> { let factory = self.factory.clone(); let address = addresses.next(deserializer)?; Ok(if address.point == HASH_ZEROS { Nullable::Null(factory) } else { Nullable::NotNull(Point::from_address(address, factory, resolver)) }) } fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError { PointParseError::WrongLength(HASH_SIZE + tail.len()) } } 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) => { let NullableFactory { factory } = nullable_factory; Ctx::T::pure(Ok(Rc::new(Nullable::Null(factory.clone())))) } Nullable::NotNull(point) => point.resolve(), } } } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> NullableFactory<'a, Ctx, A> { pub fn new(factory: A::Fctr) -> Self { Self { factory } } } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Clone for Nullable<'a, Ctx, A> { fn clone(&self) -> Self { match self { Self::Null(factory) => Self::Null(factory.clone()), Self::NotNull(point) => Self::NotNull(point.clone()), } } } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> AlwaysConstSize for NullableFactory<'a, Ctx, A> { const _SIZE: usize = HASH_SIZE; }