359 lines
11 KiB
Rust
359 lines
11 KiB
Rust
//! Core module for ADN functionality.
|
|
//! Brings [`Mentionable`]/[`Factory`]/[`Origin`] concepts from the original implementation in Python.
|
|
//! Allows for more generic behaviour via [`Context`], as opposed to original async-only.
|
|
|
|
use std::{error::Error, fmt::Display, rc::Rc};
|
|
|
|
use crate::func::*;
|
|
|
|
/// Execution context.
|
|
pub trait Context {
|
|
/// Type to provide for [Monad]ic representation of computation, mostly that of resolution ([`Resolution`]).
|
|
type T: Monad;
|
|
|
|
/// Type to represent resolution errors mainly arising in [`Resolver::resolve`].
|
|
type LookupError<'a>: 'a + Error;
|
|
|
|
/// Get [type@Hash] of a slice, mostly for use in [`Point`].
|
|
fn hash(s: &[u8]) -> Hash;
|
|
}
|
|
|
|
/// Failure yielded by [`Origin`].
|
|
#[derive(Debug)]
|
|
pub enum ResolutionError<L, P> {
|
|
Lookup(L),
|
|
Parse(P),
|
|
}
|
|
|
|
/// See [`ResolutionResult`].
|
|
pub type ResolutionFailure<'a, Ctx, A> = ResolutionError<
|
|
<Ctx as Context>::LookupError<'a>,
|
|
<<A as Mentionable<'a, Ctx>>::Fctr as Factory<'a, Ctx>>::ParseError,
|
|
>;
|
|
|
|
/// Result yielded by [`Origin`].
|
|
pub type ResolutionResult<'a, Ctx, A> = Result<Rc<A>, ResolutionFailure<'a, Ctx, A>>;
|
|
|
|
/// Helper alias for [`WeakFunctor::F`] of [`Context::T`].
|
|
pub type Wrapped<'a, Ctx, A> = <<Ctx as Context>::T as WeakFunctor>::F<'a, A>;
|
|
|
|
/// Wrapped result returned by [`Origin`].
|
|
pub type Resolution<'a, Ctx, A> = Wrapped<'a, Ctx, ResolutionResult<'a, Ctx, A>>;
|
|
|
|
/// Fixed [type@Hash] length.
|
|
pub const HASH_SIZE: usize = 32;
|
|
|
|
/// Zeroed out array of the same length as [`type@Hash`].
|
|
/// Used in [`crate::std::nullable`].
|
|
pub const HASH_ZEROS: [u8; HASH_SIZE] = [0; HASH_SIZE];
|
|
|
|
/// For use in [`Point`]/[`Address`].
|
|
pub type Hash = [u8; HASH_SIZE];
|
|
|
|
/// Serialisation mechanism that is chosen over bytestring concatenation
|
|
/// both for performance and simplicity.
|
|
///
|
|
/// See [`Serializable`].
|
|
pub trait Serializer {
|
|
/// Writes bytes from a slice. Should advance value of [`Serializer::tell()`] by `buf.len()`.
|
|
fn write(&mut self, buf: &[u8]);
|
|
/// Current position of the stream. It's expected to be used by [`crate::std::inlining`]
|
|
fn tell(&self) -> usize;
|
|
}
|
|
|
|
impl Serializer for Vec<u8> {
|
|
fn write(&mut self, buf: &[u8]) {
|
|
self.extend(buf);
|
|
}
|
|
|
|
fn tell(&self) -> usize {
|
|
self.len()
|
|
}
|
|
}
|
|
|
|
/// See [`Serializer`].
|
|
pub trait Serializable {
|
|
/// Expected to use [`Serializer::write`].
|
|
fn serialize(&self, serializer: &mut dyn Serializer);
|
|
}
|
|
|
|
/// Fundamental trait for ADN objects.
|
|
pub trait Mentionable<'a, Ctx: 'a + Context>: 'a + Serializable {
|
|
/// Type of the associated factory.
|
|
type Fctr: Factory<'a, Ctx, Mtbl = Self>;
|
|
|
|
/// Value of the associated factory.
|
|
fn factory(&self) -> Self::Fctr;
|
|
/// See implementation for the definition.
|
|
/// Hash of all the references' points concatenated, ordered, non-unique.
|
|
/// Used for walking over object trees to ensure two objects with different references don't collide.
|
|
fn topology(&self) -> Hash {
|
|
let mut vec = Vec::new();
|
|
for point in self.points() {
|
|
vec.extend(point.point);
|
|
}
|
|
Ctx::hash(&vec)
|
|
}
|
|
/// References ([Point]s) to other objects.
|
|
fn points(&self) -> Vec<Point<'a, Ctx, TypelessMentionable<'a, Ctx>>>;
|
|
}
|
|
|
|
/// Short-hand for the type of values returned by [`Resolver::resolve`].
|
|
pub type HashResolution<'a, Ctx> = Wrapped<
|
|
'a,
|
|
Ctx,
|
|
Result<(Vec<u8>, Rc<dyn Resolver<'a, Ctx>>), <Ctx as Context>::LookupError<'a>>,
|
|
>;
|
|
|
|
/// Value accepted by [`Resolver::resolve`]. Includes index to make it order-sensitive.
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct Address {
|
|
pub point: Hash,
|
|
/// Index of the point in the [`Mentionable::points()`].
|
|
pub index: usize,
|
|
}
|
|
|
|
/// Trait representing the "rainbow table" behaviour.
|
|
pub trait Resolver<'a, Ctx: 'a + Context>: 'a {
|
|
/// Successfully returned value should be the inverse of the point passed
|
|
/// with topology header ([`Mentionable::topology()`]) omitted.
|
|
fn resolve(self: Rc<Self>, address: Address) -> HashResolution<'a, Ctx>;
|
|
}
|
|
|
|
/// Trait representing a readable stream used for parsing.
|
|
///
|
|
/// See [`Serializer`], [`Factory::deserialize`].
|
|
pub trait Deserializer {
|
|
/// Read at most `n` bytes.
|
|
fn read_n(&mut self, n: usize) -> &[u8];
|
|
/// Read til the end of the stream.
|
|
fn read_all(&mut self) -> &[u8];
|
|
/// See [`Serializer::tell`].
|
|
fn tell(&self) -> usize;
|
|
}
|
|
|
|
/// Short-hand for the type of vaalues returned by [`Factory::deserialize`].
|
|
pub type ParseResult<'a, Ctx, F> =
|
|
Result<<F as Factory<'a, Ctx>>::Mtbl, <F as Factory<'a, Ctx>>::ParseError>;
|
|
|
|
/// Trait representing deserialisation rules for [Mentionable]s.
|
|
/// Crucial for [`TypelessMentionable`] and therefore [`Mentionable::points`].
|
|
pub trait Factory<'a, Ctx: 'a + Context>: Clone + 'a {
|
|
/// Type of the associated objects.
|
|
type Mtbl: Mentionable<'a, Ctx, Fctr = Self>;
|
|
/// Type of an error that [`Factory::deserialize`] can fail with.
|
|
type ParseError: 'a + Error;
|
|
|
|
/// See [`Deserializer`], [`Resolver`].
|
|
fn deserialize(
|
|
&self,
|
|
deserializer: &mut dyn Deserializer,
|
|
resolver: Rc<dyn Resolver<'a, Ctx>>,
|
|
) -> ParseResult<'a, Ctx, Self>;
|
|
/// Called by finite stream parsers if there's any data left.
|
|
fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError;
|
|
}
|
|
|
|
/// Represents a potentially resolvable [`Mentionable`].
|
|
pub trait Origin<'a, Ctx: 'a + Context>: 'a {
|
|
/// Type of the associated object.
|
|
type Mtbl: Mentionable<'a, Ctx>;
|
|
/// Value of the associated factory.
|
|
fn factory(&self) -> <Self::Mtbl as Mentionable<'a, Ctx>>::Fctr;
|
|
/// Try resolving the value.
|
|
fn resolve(self: Rc<Self>) -> Resolution<'a, Ctx, Self::Mtbl>;
|
|
}
|
|
|
|
struct LocalOrigin<A>(Rc<A>);
|
|
|
|
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Origin<'a, Ctx> for LocalOrigin<A> {
|
|
type Mtbl = A;
|
|
|
|
fn factory(&self) -> A::Fctr {
|
|
self.0.factory()
|
|
}
|
|
|
|
fn resolve(self: Rc<Self>) -> Resolution<'a, Ctx, Self::Mtbl> {
|
|
Ctx::T::pure(Ok(self.0.clone()))
|
|
}
|
|
}
|
|
|
|
impl<A> From<A> for LocalOrigin<A> {
|
|
fn from(value: A) -> Self {
|
|
LocalOrigin(value.into())
|
|
}
|
|
}
|
|
|
|
/// The main way to represent a reference in ADN.
|
|
pub struct Point<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> {
|
|
pub point: Hash,
|
|
pub origin: Rc<dyn Origin<'a, Ctx, Mtbl = A>>,
|
|
}
|
|
|
|
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Clone for Point<'a, Ctx, A> {
|
|
fn clone(&self) -> Self {
|
|
Self {
|
|
point: self.point,
|
|
origin: self.origin.clone(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Point<'a, Ctx, A> {
|
|
fn prepare_bytes_for_hashing(mentioned: &A) -> Vec<u8> {
|
|
let mut vec = mentioned.topology().to_vec();
|
|
mentioned.serialize(&mut vec);
|
|
vec
|
|
}
|
|
|
|
fn from_fields(point: Hash, origin: Rc<dyn Origin<'a, Ctx, Mtbl = A>>) -> Self {
|
|
Point { point, origin }
|
|
}
|
|
|
|
fn from_values<O: Origin<'a, Ctx, Mtbl = A>>(point: Hash, origin: O) -> Self {
|
|
Self::from_fields(point, Rc::new(origin))
|
|
}
|
|
|
|
/// See [`Origin::resolve`].
|
|
pub fn resolve(&self) -> Resolution<'a, Ctx, A> {
|
|
self.origin.clone().resolve()
|
|
}
|
|
|
|
fn from_mentionable(mentionable: A) -> Self {
|
|
Self::from_values(
|
|
Ctx::hash(Self::prepare_bytes_for_hashing(&mentionable).as_slice()),
|
|
LocalOrigin::from(mentionable),
|
|
)
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> From<A> for Point<'a, Ctx, A> {
|
|
fn from(value: A) -> Self {
|
|
Self::from_mentionable(value)
|
|
}
|
|
}
|
|
|
|
type TypelessSerialize<'a> = dyn 'a + Fn(&mut dyn Serializer);
|
|
|
|
/// See [`Mentionable::points`].
|
|
pub struct TypelessMentionable<'a, Ctx: 'a + Context> {
|
|
t_serialize: Box<TypelessSerialize<'a>>,
|
|
t_factory: TypelessFactory<'a, Ctx>,
|
|
t_topology: Hash,
|
|
t_points: Vec<Point<'a, Ctx, TypelessMentionable<'a, Ctx>>>,
|
|
}
|
|
|
|
type TypelessParsed<'a, Ctx> = Result<TypelessMentionable<'a, Ctx>, Box<dyn 'a + Error>>;
|
|
|
|
type TypelessDeserialize<'a, Ctx> =
|
|
dyn 'a + Fn(&mut dyn Deserializer, Rc<dyn Resolver<'a, Ctx>>) -> TypelessParsed<'a, Ctx>;
|
|
|
|
type TypelessUnexpectedTail<'a> = dyn 'a + Fn(&[u8]) -> TypelessError<'a>;
|
|
|
|
/// See [`Mentionable::points`]/[`TypelessMentionable`].
|
|
pub struct TypelessFactory<'a, Ctx: 'a + Context> {
|
|
t_deserialize: Rc<TypelessDeserialize<'a, Ctx>>,
|
|
t_unexpected_tail: Rc<TypelessUnexpectedTail<'a>>,
|
|
}
|
|
|
|
impl<'a, Ctx: 'a + Context> Serializable for TypelessMentionable<'a, Ctx> {
|
|
fn serialize(&self, serializer: &mut dyn Serializer) {
|
|
(self.t_serialize)(serializer);
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: 'a + Context> Mentionable<'a, Ctx> for TypelessMentionable<'a, Ctx> {
|
|
type Fctr = TypelessFactory<'a, Ctx>;
|
|
|
|
fn factory(&self) -> Self::Fctr {
|
|
self.t_factory.clone()
|
|
}
|
|
|
|
fn topology(&self) -> Hash {
|
|
self.t_topology
|
|
}
|
|
|
|
fn points(&self) -> Vec<Point<'a, Ctx, TypelessMentionable<'a, Ctx>>> {
|
|
self.t_points.clone()
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: 'a + Context> Clone for TypelessFactory<'a, Ctx> {
|
|
fn clone(&self) -> Self {
|
|
Self {
|
|
t_deserialize: self.t_deserialize.clone(),
|
|
t_unexpected_tail: self.t_unexpected_tail.clone(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// See [`Mentionable::points`]/[`TypelessFactory`].
|
|
#[derive(Debug)]
|
|
pub struct TypelessError<'a>(Box<dyn 'a + Error>);
|
|
|
|
impl<'a> Display for TypelessError<'a> {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_fmt(format_args!("typeless error: {}", self.0))
|
|
}
|
|
}
|
|
|
|
impl<'a> Error for TypelessError<'a> {}
|
|
|
|
impl<'a, Ctx: 'a + Context> Factory<'a, Ctx> for TypelessFactory<'a, Ctx> {
|
|
type Mtbl = TypelessMentionable<'a, Ctx>;
|
|
|
|
type ParseError = TypelessError<'a>;
|
|
|
|
fn deserialize(
|
|
&self,
|
|
deserializer: &mut dyn Deserializer,
|
|
resolver: Rc<dyn Resolver<'a, Ctx>>,
|
|
) -> ParseResult<'a, Ctx, Self> {
|
|
match (self.t_deserialize)(deserializer, resolver) {
|
|
Ok(mentionable) => Ok(mentionable),
|
|
Err(error) => Err(TypelessError(error)),
|
|
}
|
|
}
|
|
|
|
fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError {
|
|
(self.t_unexpected_tail)(tail)
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: 'a + Context> TypelessMentionable<'a, Ctx> {
|
|
pub fn from_typed<A: Mentionable<'a, Ctx>>(mentionable: Rc<A>) -> Self {
|
|
let factory = TypelessFactory::from_typed(mentionable.factory());
|
|
let topology = mentionable.topology();
|
|
let points = mentionable.points();
|
|
TypelessMentionable {
|
|
t_serialize: Box::new(move |serializer| mentionable.serialize(serializer)),
|
|
t_factory: factory,
|
|
t_topology: topology,
|
|
t_points: points,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: 'a + Context> TypelessFactory<'a, Ctx> {
|
|
pub fn from_typed<F: Factory<'a, Ctx>>(factory: F) -> Self {
|
|
let tail_factory = factory.clone();
|
|
TypelessFactory {
|
|
t_deserialize: Rc::new(move |deserializer, resolver| {
|
|
match factory.deserialize(deserializer, resolver) {
|
|
Ok(mentionable) => Ok(TypelessMentionable::from_typed(Rc::new(mentionable))),
|
|
Err(error) => Err(Box::new(error)),
|
|
}
|
|
}),
|
|
t_unexpected_tail: Rc::new(move |tail| {
|
|
TypelessError::from_typed(tail_factory.unexpected_tail(tail))
|
|
}),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> TypelessError<'a> {
|
|
pub fn from_typed<E: 'a + Error>(error: E) -> Self {
|
|
TypelessError(Box::new(error))
|
|
}
|
|
}
|