164 lines
4.7 KiB
Rust
164 lines
4.7 KiB
Rust
//! This module introduces [`Option`]-like concepts into RADN typesystem using [`Nullable`].
|
|
|
|
use std::marker::PhantomData;
|
|
|
|
use crate::func::context::*;
|
|
use crate::mode::*;
|
|
use crate::rcore::*;
|
|
|
|
use super::{inlining::*, point::*, *};
|
|
|
|
/// Nullable reference type. Made for use as a linking element in data structures.
|
|
pub enum Nullable<'a, Ctx: Context<'a>, A: MentionableBase<'a>> {
|
|
/// 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<Ctx, F> {
|
|
/// Factory of the referenced object.
|
|
factory: F,
|
|
_ctx: PhantomData<Ctx>,
|
|
}
|
|
|
|
impl<Ctx, F: Clone> Clone for NullableFactory<Ctx, F> {
|
|
fn clone(&self) -> Self {
|
|
Self {
|
|
factory: self.factory.clone(),
|
|
_ctx: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, A: MentionableBase<'a>> Serializable for Nullable<'a, Ctx, A> {
|
|
fn serialize(&self, serializer: &mut dyn Serializer) {
|
|
serializer.write(match self {
|
|
Self::Null(_) => &HASH_ZEROS,
|
|
Self::NotNull(point) => &point.point,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, A: MentionableBase<'a>> MentionableBase<'a> for Nullable<'a, Ctx, A> {
|
|
type Fctr = NullableFactory<Ctx, A::Fctr>;
|
|
|
|
fn factory(&self) -> Self::Fctr {
|
|
match self {
|
|
Self::Null(factory) => NullableFactory::new(factory.clone()),
|
|
Self::NotNull(point) => NullableFactory::new(point.origin.factory()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> MentionableTop<'a, Ctx>
|
|
for Nullable<'a, Ctx, A>
|
|
{
|
|
fn points_typed(&self, points: &mut impl PointsVisitor<'a, Ctx>) {
|
|
match self {
|
|
Self::Null(_) => {}
|
|
Self::NotNull(point) => points.visit(point),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, F: FactoryBase<'a>> FactoryBase<'a> for NullableFactory<Ctx, F> {
|
|
type Mtbl = Nullable<'a, Ctx, F::Mtbl>;
|
|
|
|
type ParseError = PointParseError;
|
|
}
|
|
|
|
impl<Ctx, F> ImplMode for NullableFactory<Ctx, F> {
|
|
type Mode = InliningMode;
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, 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 {
|
|
Self::Null(nullable_factory) => {
|
|
let NullableFactory { factory, .. } = nullable_factory;
|
|
Ctx::pure(Ok(Arc::new(Nullable::Null(factory.clone()))))
|
|
}
|
|
Self::NotNull(point) => point.resolve(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> Nullable<'a, Ctx, A> {
|
|
fn from_mentionable(mentionable: Arc<A>) -> Self {
|
|
Self::NotNull(mentionable.into())
|
|
}
|
|
|
|
pub fn as_ref(&self) -> Option<&Point<'a, Ctx, A>> {
|
|
match self {
|
|
Nullable::Null(_) => None,
|
|
Nullable::NotNull(point) => Some(point),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, A: MentionableBase<'a>> Nullable<'a, Ctx, A> {
|
|
pub fn is_null(&self) -> bool {
|
|
match self {
|
|
Nullable::Null(_) => true,
|
|
Nullable::NotNull(_) => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<Ctx, F> NullableFactory<Ctx, F> {
|
|
pub fn new(factory: F) -> Self {
|
|
Self {
|
|
factory,
|
|
_ctx: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, A: MentionableBase<'a>> 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: Context<'a>, F: FactoryBase<'a>> CInliningFactory<'a, Ctx>
|
|
for NullableFactory<Ctx, F>
|
|
{
|
|
fn cextension_error(&self, tail: &[u8]) -> Self::ParseError {
|
|
PointParseError::WrongLength(HASH_SIZE + tail.len())
|
|
}
|
|
|
|
fn cideserialize<I: InCtx<'a, Ctx>>(&self, inctx: I) -> IParseResult<'a, Self, I> {
|
|
let factory = self.factory.clone();
|
|
let (address, inctx) = inctx.icnext_address(PointParseError::from_ref)?;
|
|
Ok((
|
|
if address.point == HASH_ZEROS {
|
|
Nullable::Null(factory)
|
|
} else {
|
|
Nullable::NotNull(Point::from_address(address, factory, inctx.iresolver()))
|
|
},
|
|
inctx,
|
|
))
|
|
}
|
|
}
|
|
|
|
impl<Ctx, F> AlwaysConstSize for NullableFactory<Ctx, F> {
|
|
const ASIZE: usize = HASH_SIZE;
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> From<Arc<A>> for Nullable<'a, Ctx, A> {
|
|
fn from(value: Arc<A>) -> Self {
|
|
Self::from_mentionable(value)
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> From<A> for Nullable<'a, Ctx, A> {
|
|
fn from(value: A) -> Self {
|
|
Self::from_mentionable(value.into())
|
|
}
|
|
}
|