120 lines
3.7 KiB
Rust
120 lines
3.7 KiB
Rust
//! 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<Point<'a, Ctx, TypelessMentionable<'a, Ctx>>>) {
|
|
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<dyn Resolver<'a, Ctx>>,
|
|
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;
|
|
}
|