ibind/IState
This commit is contained in:
parent
8a3f9ac25f
commit
eb153d6396
22
src/core.rs
22
src/core.rs
@ -19,20 +19,21 @@ pub trait Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Failure yielded by [`Origin`].
|
/// Failure yielded by [`Origin`].
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ResolutionError<L, P> {
|
pub enum ResolutionError<L, P> {
|
||||||
Lookup(L),
|
Lookup(L),
|
||||||
Parse(P),
|
Parse(P),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Result yielded by [`Origin`].
|
/// See [`ResolutionResult`].
|
||||||
pub type ResolutionResult<'a, Ctx, A> = Result<
|
pub type ResolutionFailure<'a, Ctx, A> = ResolutionError<
|
||||||
Rc<A>,
|
<Ctx as Context>::LookupError<'a>,
|
||||||
ResolutionError<
|
<<A as Mentionable<'a, Ctx>>::Fctr as Factory<'a, Ctx>>::ParseError,
|
||||||
<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`].
|
/// Helper alias for [`WeakFunctor::F`] of [`Context::T`].
|
||||||
pub type Wrapped<'a, Ctx, A> = <<Ctx as Context>::T as WeakFunctor>::F<'a, A>;
|
pub type Wrapped<'a, Ctx, A> = <<Ctx as Context>::T as WeakFunctor>::F<'a, A>;
|
||||||
|
|
||||||
@ -98,8 +99,11 @@ pub trait Mentionable<'a, Ctx: 'a + Context>: 'a + Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Short-hand for the type of values returned by [`Resolver::resolve`].
|
/// Short-hand for the type of values returned by [`Resolver::resolve`].
|
||||||
pub type HashResolution<'a, Ctx> =
|
pub type HashResolution<'a, Ctx> = Wrapped<
|
||||||
Wrapped<'a, Ctx, Result<(Vec<u8>, Rc<dyn Resolver<'a, Ctx>>), <Ctx as Context>::LookupError<'a>>>;
|
'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.
|
/// Value accepted by [`Resolver::resolve`]. Includes index to make it order-sensitive.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
20
src/func.rs
20
src/func.rs
@ -147,6 +147,14 @@ pub trait Applicative: Functor + ApplicativeSeq + ApplicativeLA2 + ApplicativeTu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents iteration state.
|
||||||
|
pub enum IState<A, B> {
|
||||||
|
/// Loop running.
|
||||||
|
Pending(A),
|
||||||
|
/// Loop finished.
|
||||||
|
Done(B),
|
||||||
|
}
|
||||||
|
|
||||||
/// Equivalent of Haskell's `Monad`.
|
/// Equivalent of Haskell's `Monad`.
|
||||||
///
|
///
|
||||||
/// <https://hackage.haskell.org/package/base-4.18.0.0/docs/Control-Monad.html>
|
/// <https://hackage.haskell.org/package/base-4.18.0.0/docs/Control-Monad.html>
|
||||||
@ -159,6 +167,18 @@ pub trait Monad: Applicative {
|
|||||||
where
|
where
|
||||||
Self: 'a;
|
Self: 'a;
|
||||||
|
|
||||||
|
/// Kleisli category composition special case used to represent loops.
|
||||||
|
/// Included for optimisation and clarity.
|
||||||
|
/// Generally, [`Monad::bind`] should be enough implement it.
|
||||||
|
/// See [`classes::stackless::StacklessClass::ibind`] for a generic, though less-than ideal, blanket implementation.
|
||||||
|
/// On practice, you shouldn't be using [`Monad::bind`]/[`Applicative::pure`]/[`Functor::fmap`] here.
|
||||||
|
fn ibind<'a, A: 'a, B: 'a>(
|
||||||
|
a: A,
|
||||||
|
f: impl 'a + FnMut(A) -> Self::F<'a, IState<A, B>>,
|
||||||
|
) -> Self::F<'a, B>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
|
||||||
/// Equivalent of Haskell's `join`.
|
/// Equivalent of Haskell's `join`.
|
||||||
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A>
|
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A>
|
||||||
where
|
where
|
||||||
|
@ -84,6 +84,23 @@ impl Monad for FutureClass {
|
|||||||
Box::pin(async { f(fa.await).await })
|
Box::pin(async { f(fa.await).await })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ibind<'a, A: 'a, B: 'a>(
|
||||||
|
mut a: A,
|
||||||
|
mut f: impl 'a + FnMut(A) -> Self::F<'a, IState<A, B>>,
|
||||||
|
) -> Self::F<'a, B>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
{
|
||||||
|
Box::pin(async move {
|
||||||
|
loop {
|
||||||
|
match f(a).await {
|
||||||
|
IState::Pending(next_a) => a = next_a,
|
||||||
|
IState::Done(b) => return b,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> {
|
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> {
|
||||||
Box::pin(async { ffa.await.await })
|
Box::pin(async { ffa.await.await })
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,21 @@ impl Monad for LazyClass {
|
|||||||
Box::new(|| f(fa())())
|
Box::new(|| f(fa())())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ibind<'a, A: 'a, B: 'a>(
|
||||||
|
mut a: A,
|
||||||
|
mut f: impl 'a + FnMut(A) -> Self::F<'a, IState<A, B>>,
|
||||||
|
) -> Self::F<'a, B>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
{
|
||||||
|
Box::new(move || loop {
|
||||||
|
match f(a)() {
|
||||||
|
IState::Pending(next_a) => a = next_a,
|
||||||
|
IState::Done(b) => return b,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> {
|
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> {
|
||||||
Box::new(|| ffa()())
|
Box::new(|| ffa()())
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,21 @@ impl Monad for OptionClass {
|
|||||||
f(fa?)
|
f(fa?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ibind<'a, A: 'a, B: 'a>(
|
||||||
|
mut a: A,
|
||||||
|
mut f: impl 'a + FnMut(A) -> Self::F<'a, IState<A, B>>,
|
||||||
|
) -> Self::F<'a, B>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
{
|
||||||
|
loop {
|
||||||
|
match f(a)? {
|
||||||
|
IState::Pending(next_a) => a = next_a,
|
||||||
|
IState::Done(b) => return Self::pure(b),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> {
|
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> {
|
||||||
ffa?
|
ffa?
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,21 @@ impl<E> Monad for ResultClass<E> {
|
|||||||
f(fa?)
|
f(fa?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ibind<'a, A: 'a, B: 'a>(
|
||||||
|
mut a: A,
|
||||||
|
mut f: impl 'a + FnMut(A) -> Self::F<'a, IState<A, B>>,
|
||||||
|
) -> Self::F<'a, B>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
{
|
||||||
|
loop {
|
||||||
|
match f(a)? {
|
||||||
|
IState::Pending(next_a) => a = next_a,
|
||||||
|
IState::Done(b) => return Self::pure(b),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> {
|
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> {
|
||||||
ffa?
|
ffa?
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,21 @@ impl Monad for SoloClass {
|
|||||||
f(fa)
|
f(fa)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ibind<'a, A: 'a, B: 'a>(
|
||||||
|
mut a: A,
|
||||||
|
mut f: impl 'a + FnMut(A) -> Self::F<'a, IState<A, B>>,
|
||||||
|
) -> Self::F<'a, B>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
{
|
||||||
|
loop {
|
||||||
|
match f(a) {
|
||||||
|
IState::Pending(next_a) => a = next_a,
|
||||||
|
IState::Done(b) => return b,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> {
|
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> {
|
||||||
ffa
|
ffa
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ impl<'a, A: 'a> From<A> for Stackless<'a, A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StacklessClass;
|
pub struct StacklessClass;
|
||||||
|
|
||||||
impl WeakFunctor for StacklessClass {
|
impl WeakFunctor for StacklessClass {
|
||||||
type F<'a, A: 'a> = Stackless<'a, A>;
|
type F<'a, A: 'a> = Stackless<'a, A>;
|
||||||
@ -221,6 +221,22 @@ impl Monad for StacklessClass {
|
|||||||
{
|
{
|
||||||
fa.bind(f)
|
fa.bind(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ibind<'a, A: 'a, B: 'a>(
|
||||||
|
a: A,
|
||||||
|
mut f: impl 'a + FnMut(A) -> Self::F<'a, IState<A, B>>,
|
||||||
|
) -> Self::F<'a, B>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
{
|
||||||
|
Self::pure(a).bind(move |a| {
|
||||||
|
f(a).bind(|state| match state {
|
||||||
|
IState::Pending(a) => Self::ibind(a, f),
|
||||||
|
IState::Done(b) => Self::pure(b),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A>
|
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A>
|
||||||
where
|
where
|
||||||
Self::F<'a, A>: 'a,
|
Self::F<'a, A>: 'a,
|
||||||
|
@ -344,11 +344,11 @@ impl Display for Address {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait ExtSerializable: Serializable {
|
pub trait ExtSerializable: Serializable {
|
||||||
fn to_vec(&self) -> Vec<u8>;
|
fn bytes(&self) -> Vec<u8>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Serializable> ExtSerializable for S {
|
impl<S: Serializable> ExtSerializable for S {
|
||||||
fn to_vec(&self) -> Vec<u8> {
|
fn bytes(&self) -> Vec<u8> {
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
self.serialize(&mut vec);
|
self.serialize(&mut vec);
|
||||||
vec
|
vec
|
||||||
|
@ -3,12 +3,12 @@ use std::fmt::Display;
|
|||||||
use crate::std::atomic::*;
|
use crate::std::atomic::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Plain {
|
pub struct Plain {
|
||||||
pub data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum PlainParseError {}
|
pub enum PlainParseError {}
|
||||||
|
|
||||||
impl Display for PlainParseError {
|
impl Display for PlainParseError {
|
||||||
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
@ -28,9 +28,7 @@ impl Atomic for Plain {
|
|||||||
type ParseError = PlainParseError;
|
type ParseError = PlainParseError;
|
||||||
|
|
||||||
fn deserialize(deserializer: &mut dyn Deserializer) -> Result<Self, Self::ParseError> {
|
fn deserialize(deserializer: &mut dyn Deserializer) -> Result<Self, Self::ParseError> {
|
||||||
Ok(Plain {
|
Ok(Plain::from_slice(deserializer.read_all()))
|
||||||
data: deserializer.read_all().into(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unexpected_tail(tail: &[u8]) -> Self::ParseError {
|
fn unexpected_tail(tail: &[u8]) -> Self::ParseError {
|
||||||
@ -41,15 +39,21 @@ impl Atomic for Plain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Plain {
|
||||||
|
pub fn from_slice(slice: &[u8]) -> Self {
|
||||||
|
Plain { data: slice.into() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::std::*;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::std::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_plain() -> Result<(), PlainParseError> {
|
fn test_plain() -> Result<(), PlainParseError> {
|
||||||
let plain = Plain::parse_slice(b"slice")?;
|
let plain = Plain::parse_slice(b"slice")?;
|
||||||
assert_eq!(plain.to_vec().as_slice(), b"slice");
|
assert_eq!(plain.bytes().as_slice(), b"slice");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,13 @@ struct CastResolver<'a, Ctx: 'a + Context> {
|
|||||||
points: Vec<Point<'a, Ctx, TypelessMentionable<'a, Ctx>>>,
|
points: Vec<Point<'a, Ctx, TypelessMentionable<'a, Ctx>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum CastError<'a> {
|
pub enum CastError<'a> {
|
||||||
Typeless(TypelessError<'a>),
|
Typeless(TypelessError<'a>),
|
||||||
AddressIndexOutOfBounds(usize),
|
AddressIndexOutOfBounds {
|
||||||
|
index: usize,
|
||||||
|
length: usize,
|
||||||
|
},
|
||||||
AddressPointMismatch {
|
AddressPointMismatch {
|
||||||
expected: Hash,
|
expected: Hash,
|
||||||
received: Hash,
|
received: Hash,
|
||||||
@ -15,6 +19,30 @@ pub enum CastError<'a> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> Display for CastError<'a> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
CastError::Typeless(typeless_error) => {
|
||||||
|
f.write_fmt(format_args!("typeless cast error: {}", typeless_error))
|
||||||
|
}
|
||||||
|
CastError::AddressIndexOutOfBounds { index, length } => f.write_fmt(format_args!(
|
||||||
|
"cast index out of bound: {}>={}",
|
||||||
|
index, length
|
||||||
|
)),
|
||||||
|
CastError::AddressPointMismatch {
|
||||||
|
expected,
|
||||||
|
received,
|
||||||
|
index,
|
||||||
|
} => f.write_fmt(format_args!(
|
||||||
|
"address mismatch at index {}: {}>={}",
|
||||||
|
index,
|
||||||
|
hex::encode(expected),
|
||||||
|
hex::encode(received),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, Ctx: 'a + Context> Resolver<'a, Ctx> for CastResolver<'a, Ctx>
|
impl<'a, Ctx: 'a + Context> Resolver<'a, Ctx> for CastResolver<'a, Ctx>
|
||||||
where
|
where
|
||||||
Ctx::LookupError<'a>: From<CastError<'a>>,
|
Ctx::LookupError<'a>: From<CastError<'a>>,
|
||||||
@ -23,7 +51,11 @@ where
|
|||||||
let point = match self.points.get(address.index) {
|
let point = match self.points.get(address.index) {
|
||||||
Some(point) => point,
|
Some(point) => point,
|
||||||
None => {
|
None => {
|
||||||
return Ctx::T::pure(Err(CastError::AddressIndexOutOfBounds(address.index).into()));
|
return Ctx::T::pure(Err(CastError::AddressIndexOutOfBounds {
|
||||||
|
index: address.index,
|
||||||
|
length: self.points.len(),
|
||||||
|
}
|
||||||
|
.into()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if point.point != address.point {
|
if point.point != address.point {
|
||||||
@ -40,7 +72,7 @@ where
|
|||||||
let resolver: Rc<dyn Resolver<'a, Ctx>> = Rc::new(CastResolver {
|
let resolver: Rc<dyn Resolver<'a, Ctx>> = Rc::new(CastResolver {
|
||||||
points: mentionable.points(),
|
points: mentionable.points(),
|
||||||
});
|
});
|
||||||
Ok((mentionable.to_vec(), resolver))
|
Ok((mentionable.bytes(), resolver))
|
||||||
}
|
}
|
||||||
Err(error) => Err(match error {
|
Err(error) => Err(match error {
|
||||||
ResolutionError::Lookup(lookup_error) => lookup_error,
|
ResolutionError::Lookup(lookup_error) => lookup_error,
|
||||||
@ -60,7 +92,7 @@ where
|
|||||||
{
|
{
|
||||||
pub fn cast<A: Mentionable<'a, Ctx>>(&self, factory: A::Fctr) -> CastResult<'a, Ctx, A> {
|
pub fn cast<A: Mentionable<'a, Ctx>>(&self, factory: A::Fctr) -> CastResult<'a, Ctx, A> {
|
||||||
factory.parse_slice(
|
factory.parse_slice(
|
||||||
&self.to_vec(),
|
&self.bytes(),
|
||||||
Rc::new(CastResolver {
|
Rc::new(CastResolver {
|
||||||
points: self.points(),
|
points: self.points(),
|
||||||
}),
|
}),
|
||||||
|
@ -4,7 +4,7 @@ use crate::std::*;
|
|||||||
|
|
||||||
pub struct StackNode<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> {
|
pub struct StackNode<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> {
|
||||||
pub rest: Stack<'a, Ctx, A>,
|
pub rest: Stack<'a, Ctx, A>,
|
||||||
pub element: A,
|
pub element: Rc<A>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Stack<'a, Ctx, A> = Nullable<'a, Ctx, StackNode<'a, Ctx, A>>;
|
type Stack<'a, Ctx, A> = Nullable<'a, Ctx, StackNode<'a, Ctx, A>>;
|
||||||
@ -90,12 +90,14 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Factory<'a, Ctx>
|
|||||||
return Err(StackParseError::Point(ppe));
|
return Err(StackParseError::Point(ppe));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let element = match self.element_factory.deserialize(deserializer, resolver) {
|
let element = Rc::new(
|
||||||
Ok(element) => element,
|
match self.element_factory.deserialize(deserializer, resolver) {
|
||||||
Err(epe) => {
|
Ok(element) => element,
|
||||||
return Err(StackParseError::Element(epe));
|
Err(epe) => {
|
||||||
}
|
return Err(StackParseError::Element(epe));
|
||||||
};
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
Ok(StackNode { rest, element })
|
Ok(StackNode { rest, element })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,10 +106,17 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Factory<'a, Ctx>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type StackFaiure<'a, Ctx, A> = ResolutionFailure<'a, Ctx, StackNode<'a, Ctx, A>>;
|
||||||
|
|
||||||
|
pub type StackVecResult<'a, Ctx, A> = Result<Vec<Rc<A>>, StackFaiure<'a, Ctx, A>>;
|
||||||
|
|
||||||
|
pub type StackVecWrapped<'a, Ctx, A> = Wrapped<'a, Ctx, StackVecResult<'a, Ctx, A>>;
|
||||||
|
|
||||||
pub trait ExtStack<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>: Mentionable<'a, Ctx> {
|
pub trait ExtStack<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>: Mentionable<'a, Ctx> {
|
||||||
fn empty(factory: A::Fctr) -> Self;
|
fn empty(factory: A::Fctr) -> Self;
|
||||||
fn f(factory: A::Fctr) -> Self::Fctr;
|
fn f(factory: A::Fctr) -> Self::Fctr;
|
||||||
fn add(self, element: A) -> Self;
|
fn add(self, element: A) -> Self;
|
||||||
|
fn vec(self) -> StackVecWrapped<'a, Ctx, A>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> ExtStack<'a, Ctx, A> for Stack<'a, Ctx, A> {
|
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> ExtStack<'a, Ctx, A> for Stack<'a, Ctx, A> {
|
||||||
@ -121,9 +130,77 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> ExtStack<'a, Ctx, A> for St
|
|||||||
Nullable::NotNull(
|
Nullable::NotNull(
|
||||||
StackNode {
|
StackNode {
|
||||||
rest: self,
|
rest: self,
|
||||||
element,
|
element: Rc::new(element),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
fn vec(self) -> StackVecWrapped<'a, Ctx, A> {
|
||||||
|
Ctx::T::ibind((vec![], self), |(mut vec, stack)| match stack {
|
||||||
|
Nullable::Null(_) => Ctx::T::pure(IState::Done(Ok(vec))),
|
||||||
|
Nullable::NotNull(point) => Ctx::T::fmap(
|
||||||
|
|resolved| {
|
||||||
|
let node = match resolved {
|
||||||
|
Ok(node) => node,
|
||||||
|
Err(error) => {
|
||||||
|
return IState::Done(Err(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
vec.push(node.element.clone());
|
||||||
|
IState::Pending((vec, node.rest.clone()))
|
||||||
|
},
|
||||||
|
point.resolve(),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::std::atomic::plain::*;
|
||||||
|
use crate::std::atomic::*;
|
||||||
|
use crate::testing::*;
|
||||||
|
|
||||||
|
type T = Stack<'static, TestContext, Plain>;
|
||||||
|
|
||||||
|
fn unstack(stack: &T) -> Result<Vec<Vec<u8>>, StackFaiure<'static, TestContext, Plain>> {
|
||||||
|
Ok(stack
|
||||||
|
.clone()
|
||||||
|
.vec()?
|
||||||
|
.iter()
|
||||||
|
.map(|plain| plain.bytes())
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_stack() -> T {
|
||||||
|
let stack: T = Stack::empty(Plain::f());
|
||||||
|
|
||||||
|
let stack: T = stack.add(Plain::from_slice(b"A0"));
|
||||||
|
let stack: T = stack.add(Plain::from_slice(b"B1"));
|
||||||
|
let stack: T = stack.add(Plain::from_slice(b"C2"));
|
||||||
|
|
||||||
|
stack
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_stack(stack: &T) {
|
||||||
|
let mut vec: Vec<Vec<u8>> = unstack(stack).unwrap();
|
||||||
|
vec.reverse();
|
||||||
|
assert_eq!(vec, vec![b"A0".to_vec(), b"B1".to_vec(), b"C2".to_vec()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_stack() -> Result<(), StackFaiure<'static, TestContext, Plain>> {
|
||||||
|
let stack: T = make_stack();
|
||||||
|
|
||||||
|
validate_stack(&stack);
|
||||||
|
|
||||||
|
let stack: T = TypelessMentionable::from_typed(stack.into())
|
||||||
|
.cast(Stack::f(Plain::f()))
|
||||||
|
.expect("cast failed");
|
||||||
|
|
||||||
|
validate_stack(&stack);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,13 +65,13 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Factory<'a, Ctx>
|
|||||||
deserializer: &mut dyn Deserializer,
|
deserializer: &mut dyn Deserializer,
|
||||||
resolver: std::rc::Rc<dyn Resolver<'a, Ctx>>,
|
resolver: std::rc::Rc<dyn Resolver<'a, Ctx>>,
|
||||||
) -> ParseResult<'a, Ctx, Self> {
|
) -> ParseResult<'a, Ctx, Self> {
|
||||||
let point = deserializer.read_n_const::<HASH_SIZE>()?;
|
let mut addresses = Addresses::start();
|
||||||
let factory = self.factory.clone();
|
let factory = self.factory.clone();
|
||||||
Ok(if point == HASH_ZEROS {
|
let address = addresses.next(deserializer)?;
|
||||||
|
Ok(if address.point == HASH_ZEROS {
|
||||||
Nullable::Null(factory)
|
Nullable::Null(factory)
|
||||||
} else {
|
} else {
|
||||||
let mut addresses = Addresses::start();
|
Nullable::NotNull(Point::from_point(address, factory, resolver))
|
||||||
Nullable::NotNull(addresses.next_point(deserializer, resolver, factory)?)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,10 +86,8 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Nullable<'a, Ctx, Nullable<
|
|||||||
Nullable::Null(nullable_factory) => {
|
Nullable::Null(nullable_factory) => {
|
||||||
let NullableFactory { factory } = nullable_factory;
|
let NullableFactory { factory } = nullable_factory;
|
||||||
Ctx::T::pure(Ok(Rc::new(Nullable::Null(factory.clone()))))
|
Ctx::T::pure(Ok(Rc::new(Nullable::Null(factory.clone()))))
|
||||||
},
|
}
|
||||||
Nullable::NotNull(point) => {
|
Nullable::NotNull(point) => point.resolve(),
|
||||||
point.resolve()
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,3 +97,12 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> NullableFactory<'a, Ctx, A>
|
|||||||
Self { factory }
|
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()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ use std::fmt::Display;
|
|||||||
|
|
||||||
use crate::core::*;
|
use crate::core::*;
|
||||||
use crate::func::*;
|
use crate::func::*;
|
||||||
|
use crate::std::cast::CastError;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
pub struct TestContext;
|
pub struct TestContext;
|
||||||
@ -10,6 +11,7 @@ pub struct TestContext;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TestLookupError<'a> {
|
pub enum TestLookupError<'a> {
|
||||||
Typeless(TypelessError<'a>),
|
Typeless(TypelessError<'a>),
|
||||||
|
Cast(CastError<'a>),
|
||||||
EmptyResolverAccess(Address),
|
EmptyResolverAccess(Address),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,12 +21,21 @@ impl<'a> From<TypelessError<'a>> for TestLookupError<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> From<CastError<'a>> for TestLookupError<'a> {
|
||||||
|
fn from(value: CastError<'a>) -> Self {
|
||||||
|
Self::Cast(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Display for TestLookupError<'a> {
|
impl<'a> Display for TestLookupError<'a> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
TestLookupError::Typeless(typeless_error) => {
|
TestLookupError::Typeless(typeless_error) => {
|
||||||
f.write_fmt(format_args!("typeless lookup failure: {}", typeless_error))
|
f.write_fmt(format_args!("typeless lookup failure: {}", typeless_error))
|
||||||
}
|
}
|
||||||
|
TestLookupError::Cast(cast_error) => {
|
||||||
|
f.write_fmt(format_args!("cast failure: {}", cast_error))
|
||||||
|
}
|
||||||
TestLookupError::EmptyResolverAccess(address) => f.write_fmt(format_args!(
|
TestLookupError::EmptyResolverAccess(address) => f.write_fmt(format_args!(
|
||||||
"accessed an empty resolved at address {}.",
|
"accessed an empty resolved at address {}.",
|
||||||
address
|
address
|
||||||
|
Loading…
Reference in New Issue
Block a user