stack + testing
This commit is contained in:
parent
4ababb524c
commit
8a3f9ac25f
@ -7,3 +7,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.3.26"
|
futures = "0.3.26"
|
||||||
|
hex = "0.4.3"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
sha2 = "0.10.6"
|
||||||
|
14
src/core.rs
14
src/core.rs
@ -12,7 +12,7 @@ pub trait Context {
|
|||||||
type T: Monad;
|
type T: Monad;
|
||||||
|
|
||||||
/// Type to represent resolution errors mainly arising in [`Resolver::resolve`].
|
/// Type to represent resolution errors mainly arising in [`Resolver::resolve`].
|
||||||
type LookupError: Error;
|
type LookupError<'a>: 'a + Error;
|
||||||
|
|
||||||
/// Get [type@Hash] of a slice, mostly for use in [`Point`].
|
/// Get [type@Hash] of a slice, mostly for use in [`Point`].
|
||||||
fn hash(s: &[u8]) -> Hash;
|
fn hash(s: &[u8]) -> Hash;
|
||||||
@ -28,7 +28,7 @@ pub enum ResolutionError<L, P> {
|
|||||||
pub type ResolutionResult<'a, Ctx, A> = Result<
|
pub type ResolutionResult<'a, Ctx, A> = Result<
|
||||||
Rc<A>,
|
Rc<A>,
|
||||||
ResolutionError<
|
ResolutionError<
|
||||||
<Ctx as Context>::LookupError,
|
<Ctx as Context>::LookupError<'a>,
|
||||||
<<A as Mentionable<'a, Ctx>>::Fctr as Factory<'a, Ctx>>::ParseError,
|
<<A as Mentionable<'a, Ctx>>::Fctr as Factory<'a, Ctx>>::ParseError,
|
||||||
>,
|
>,
|
||||||
>;
|
>;
|
||||||
@ -99,10 +99,10 @@ 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<'a, Ctx, Result<(Vec<u8>, Rc<dyn Resolver<'a, Ctx>>), <Ctx as Context>::LookupError>>;
|
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.
|
/// Value accepted by [`Resolver::resolve`]. Includes index to make it order-sensitive.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Address {
|
pub struct Address {
|
||||||
pub point: Hash,
|
pub point: Hash,
|
||||||
/// Index of the point in the [`Mentionable::points()`].
|
/// Index of the point in the [`Mentionable::points()`].
|
||||||
@ -165,12 +165,12 @@ struct LocalOrigin<A>(Rc<A>);
|
|||||||
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Origin<'a, Ctx> for LocalOrigin<A> {
|
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Origin<'a, Ctx> for LocalOrigin<A> {
|
||||||
type Mtbl = A;
|
type Mtbl = A;
|
||||||
|
|
||||||
fn factory(&self) -> <Self::Mtbl as Mentionable<'a, Ctx>>::Fctr {
|
fn factory(&self) -> A::Fctr {
|
||||||
self.0.factory()
|
self.0.factory()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve(self: Rc<Self>) -> Resolution<'a, Ctx, Self::Mtbl> {
|
fn resolve(self: Rc<Self>) -> Resolution<'a, Ctx, Self::Mtbl> {
|
||||||
<Ctx::T as Applicative>::pure(Ok(self.0.clone()))
|
Ctx::T::pure(Ok(self.0.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +289,7 @@ pub struct TypelessError<'a>(Box<dyn 'a + Error>);
|
|||||||
|
|
||||||
impl<'a> Display for TypelessError<'a> {
|
impl<'a> Display for TypelessError<'a> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.0.fmt(f)
|
f.write_fmt(format_args!("typeless error: {}", self.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,4 +2,6 @@ pub mod core;
|
|||||||
pub mod func;
|
pub mod func;
|
||||||
pub mod std;
|
pub mod std;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
mod testing;
|
||||||
|
#[cfg(test)]
|
||||||
mod xrcs;
|
mod xrcs;
|
||||||
|
21
src/std.rs
21
src/std.rs
@ -1,5 +1,6 @@
|
|||||||
pub mod atomic;
|
pub mod atomic;
|
||||||
pub mod cast;
|
pub mod cast;
|
||||||
|
pub mod collections;
|
||||||
pub mod inlining;
|
pub mod inlining;
|
||||||
pub mod nullable;
|
pub mod nullable;
|
||||||
|
|
||||||
@ -135,7 +136,7 @@ impl Display for PointParseError {
|
|||||||
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 {
|
||||||
PointParseError::WrongLength(length) => f.write_fmt(format_args!(
|
PointParseError::WrongLength(length) => f.write_fmt(format_args!(
|
||||||
"expected {} bytes, received {}",
|
"expected {} bytes, received {}.",
|
||||||
HASH_SIZE, length
|
HASH_SIZE, length
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
@ -335,3 +336,21 @@ impl<D: ?Sized + Deserializer> ExtDeserializer for D {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Address {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_fmt(format_args!("{}@{}", hex::encode(self.point), self.index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ExtSerializable: Serializable {
|
||||||
|
fn to_vec(&self) -> Vec<u8>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Serializable> ExtSerializable for S {
|
||||||
|
fn to_vec(&self) -> Vec<u8> {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
self.serialize(&mut vec);
|
||||||
|
vec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
//! This module allows to describe a primitive subset of [Mentionable] types, [Atomic]s,
|
//! This module allows to describe a primitive subset of [Mentionable] types, [Atomic]s,
|
||||||
//! simple static types, which are completely [Context]-independent.
|
//! simple static types, which are completely [Context]-independent.
|
||||||
|
|
||||||
|
pub mod plain;
|
||||||
|
|
||||||
use std::{error::Error, marker::PhantomData, rc::Rc};
|
use std::{error::Error, marker::PhantomData, rc::Rc};
|
||||||
|
|
||||||
use crate::core::*;
|
use crate::core::*;
|
||||||
|
use crate::std::*;
|
||||||
|
|
||||||
/// This trait combines functionality of [`Mentionable`] and [`Factory`],
|
/// This trait combines functionality of [`Mentionable`] and [`Factory`],
|
||||||
/// while limiting [`Mentionable::points`] (and corresponding [`Mentionable::topology`]) to an empty sequence.
|
/// while limiting [`Mentionable::points`] (and corresponding [`Mentionable::topology`]) to an empty sequence.
|
||||||
@ -64,3 +67,29 @@ impl<'a, Ctx: 'a + Context, A: Atomic> Factory<'a, Ctx> for AtomicFactory<A> {
|
|||||||
A::unexpected_tail(tail)
|
A::unexpected_tail(tail)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _parse_slice<A: Atomic>(slice: &[u8]) -> Result<A, A::ParseError> {
|
||||||
|
let mut deserializer = SliceDeserializer::from(slice);
|
||||||
|
let mentionable = A::deserialize(&mut deserializer)?;
|
||||||
|
let tail = deserializer.read_all();
|
||||||
|
if tail.is_empty() {
|
||||||
|
Ok(mentionable)
|
||||||
|
} else {
|
||||||
|
Err(A::unexpected_tail(tail))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ExtAtomic: Atomic {
|
||||||
|
fn f() -> AtomicFactory<Self>;
|
||||||
|
fn parse_slice(slice: &[u8]) -> Result<Self, Self::ParseError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Atomic> ExtAtomic for A {
|
||||||
|
fn f() -> AtomicFactory<Self> {
|
||||||
|
AtomicFactory::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_slice(slice: &[u8]) -> Result<Self, Self::ParseError> {
|
||||||
|
_parse_slice(slice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
55
src/std/atomic/plain.rs
Normal file
55
src/std/atomic/plain.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use crate::std::atomic::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Plain {
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum PlainParseError {}
|
||||||
|
|
||||||
|
impl Display for PlainParseError {
|
||||||
|
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for PlainParseError {}
|
||||||
|
|
||||||
|
impl Serializable for Plain {
|
||||||
|
fn serialize(&self, serializer: &mut dyn Serializer) {
|
||||||
|
serializer.write(&self.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Atomic for Plain {
|
||||||
|
type ParseError = PlainParseError;
|
||||||
|
|
||||||
|
fn deserialize(deserializer: &mut dyn Deserializer) -> Result<Self, Self::ParseError> {
|
||||||
|
Ok(Plain {
|
||||||
|
data: deserializer.read_all().into(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unexpected_tail(tail: &[u8]) -> Self::ParseError {
|
||||||
|
panic!(
|
||||||
|
"Plain must use read_all, therefore there must not be any extra tail (received {} bytes).",
|
||||||
|
tail.len()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::std::*;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_plain() -> Result<(), PlainParseError> {
|
||||||
|
let plain = Plain::parse_slice(b"slice")?;
|
||||||
|
assert_eq!(plain.to_vec().as_slice(), b"slice");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,7 @@ pub enum CastError<'a> {
|
|||||||
|
|
||||||
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: From<CastError<'a>>,
|
Ctx::LookupError<'a>: From<CastError<'a>>,
|
||||||
{
|
{
|
||||||
fn resolve(self: Rc<Self>, address: Address) -> HashResolution<'a, Ctx> {
|
fn resolve(self: Rc<Self>, address: Address) -> HashResolution<'a, Ctx> {
|
||||||
let point = match self.points.get(address.index) {
|
let point = match self.points.get(address.index) {
|
||||||
@ -37,12 +37,10 @@ where
|
|||||||
Ctx::T::fmap(
|
Ctx::T::fmap(
|
||||||
|resolved| match resolved {
|
|resolved| match resolved {
|
||||||
Ok(mentionable) => {
|
Ok(mentionable) => {
|
||||||
let mut vec = Vec::new();
|
|
||||||
mentionable.serialize(&mut vec);
|
|
||||||
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((vec, resolver))
|
Ok((mentionable.to_vec(), resolver))
|
||||||
}
|
}
|
||||||
Err(error) => Err(match error {
|
Err(error) => Err(match error {
|
||||||
ResolutionError::Lookup(lookup_error) => lookup_error,
|
ResolutionError::Lookup(lookup_error) => lookup_error,
|
||||||
@ -58,13 +56,11 @@ pub type CastResult<'a, Ctx, A> =
|
|||||||
Result<A, <<A as Mentionable<'a, Ctx>>::Fctr as Factory<'a, Ctx>>::ParseError>;
|
Result<A, <<A as Mentionable<'a, Ctx>>::Fctr as Factory<'a, Ctx>>::ParseError>;
|
||||||
impl<'a, Ctx: Context> TypelessMentionable<'a, Ctx>
|
impl<'a, Ctx: Context> TypelessMentionable<'a, Ctx>
|
||||||
where
|
where
|
||||||
Ctx::LookupError: From<CastError<'a>>,
|
Ctx::LookupError<'a>: From<CastError<'a>>,
|
||||||
{
|
{
|
||||||
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> {
|
||||||
let mut vec = Vec::new();
|
|
||||||
self.serialize(&mut vec);
|
|
||||||
factory.parse_slice(
|
factory.parse_slice(
|
||||||
&vec,
|
&self.to_vec(),
|
||||||
Rc::new(CastResolver {
|
Rc::new(CastResolver {
|
||||||
points: self.points(),
|
points: self.points(),
|
||||||
}),
|
}),
|
||||||
|
1
src/std/collections.rs
Normal file
1
src/std/collections.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod stack;
|
129
src/std/collections/stack.rs
Normal file
129
src/std/collections/stack.rs
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
use crate::core::*;
|
||||||
|
use crate::std::nullable::*;
|
||||||
|
use crate::std::*;
|
||||||
|
|
||||||
|
pub struct StackNode<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> {
|
||||||
|
pub rest: Stack<'a, Ctx, A>,
|
||||||
|
pub element: A,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Stack<'a, Ctx, A> = Nullable<'a, Ctx, StackNode<'a, Ctx, A>>;
|
||||||
|
|
||||||
|
pub struct StackNodeFactory<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> {
|
||||||
|
element_factory: A::Fctr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> StackNodeFactory<'a, Ctx, A> {
|
||||||
|
fn new(factory: A::Fctr) -> Self {
|
||||||
|
StackNodeFactory {
|
||||||
|
element_factory: factory,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Serializable for StackNode<'a, Ctx, A> {
|
||||||
|
fn serialize(&self, serializer: &mut dyn Serializer) {
|
||||||
|
self.rest.serialize(serializer);
|
||||||
|
self.element.serialize(serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Mentionable<'a, Ctx>
|
||||||
|
for StackNode<'a, Ctx, A>
|
||||||
|
{
|
||||||
|
type Fctr = StackNodeFactory<'a, Ctx, A>;
|
||||||
|
|
||||||
|
fn factory(&self) -> Self::Fctr {
|
||||||
|
StackNodeFactory::new(self.element.factory())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn points(&self) -> Vec<Point<'a, Ctx, TypelessMentionable<'a, Ctx>>> {
|
||||||
|
let mut points = self.rest.points();
|
||||||
|
points.extend(self.element.points());
|
||||||
|
points
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Clone for StackNodeFactory<'a, Ctx, A> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
StackNodeFactory::new(self.element_factory.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum StackParseError<ElementParseError: Error> {
|
||||||
|
Point(PointParseError),
|
||||||
|
Element(ElementParseError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<ElementParseError: Error> Display for StackParseError<ElementParseError> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
StackParseError::Point(ppe) => {
|
||||||
|
f.write_fmt(format_args!("can't parse stack's next pointer: {}", ppe))
|
||||||
|
}
|
||||||
|
StackParseError::Element(epe) => {
|
||||||
|
f.write_fmt(format_args!("can't parse stack's element: {}", epe))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<ElementParseError: Error> Error for StackParseError<ElementParseError> {}
|
||||||
|
|
||||||
|
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Factory<'a, Ctx>
|
||||||
|
for StackNodeFactory<'a, Ctx, A>
|
||||||
|
{
|
||||||
|
type Mtbl = StackNode<'a, Ctx, A>;
|
||||||
|
|
||||||
|
type ParseError = StackParseError<<A::Fctr as Factory<'a, Ctx>>::ParseError>;
|
||||||
|
|
||||||
|
fn deserialize(
|
||||||
|
&self,
|
||||||
|
deserializer: &mut dyn Deserializer,
|
||||||
|
resolver: Rc<dyn Resolver<'a, Ctx>>,
|
||||||
|
) -> ParseResult<'a, Ctx, Self> {
|
||||||
|
let rest =
|
||||||
|
match NullableFactory::new(self.clone()).deserialize(deserializer, resolver.clone()) {
|
||||||
|
Ok(rest) => rest,
|
||||||
|
Err(ppe) => {
|
||||||
|
return Err(StackParseError::Point(ppe));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let element = match self.element_factory.deserialize(deserializer, resolver) {
|
||||||
|
Ok(element) => element,
|
||||||
|
Err(epe) => {
|
||||||
|
return Err(StackParseError::Element(epe));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(StackNode { rest, element })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError {
|
||||||
|
StackParseError::Element(self.element_factory.unexpected_tail(tail))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ExtStack<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>: Mentionable<'a, Ctx> {
|
||||||
|
fn empty(factory: A::Fctr) -> Self;
|
||||||
|
fn f(factory: A::Fctr) -> Self::Fctr;
|
||||||
|
fn add(self, element: A) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> ExtStack<'a, Ctx, A> for Stack<'a, Ctx, A> {
|
||||||
|
fn empty(factory: A::Fctr) -> Self {
|
||||||
|
Nullable::Null(StackNodeFactory::new(factory.clone()))
|
||||||
|
}
|
||||||
|
fn f(factory: A::Fctr) -> Self::Fctr {
|
||||||
|
NullableFactory::new(StackNodeFactory::new(factory.clone()))
|
||||||
|
}
|
||||||
|
fn add(self, element: A) -> Self {
|
||||||
|
Nullable::NotNull(
|
||||||
|
StackNode {
|
||||||
|
rest: self,
|
||||||
|
element,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -79,3 +79,23 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Factory<'a, Ctx>
|
|||||||
PointParseError::WrongLength(HASH_SIZE + tail.len())
|
PointParseError::WrongLength(HASH_SIZE + tail.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Nullable<'a, Ctx, Nullable<'a, Ctx, A>> {
|
||||||
|
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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
56
src/testing.rs
Normal file
56
src/testing.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use crate::core::*;
|
||||||
|
use crate::func::*;
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
|
pub struct TestContext;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum TestLookupError<'a> {
|
||||||
|
Typeless(TypelessError<'a>),
|
||||||
|
EmptyResolverAccess(Address),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<TypelessError<'a>> for TestLookupError<'a> {
|
||||||
|
fn from(value: TypelessError<'a>) -> Self {
|
||||||
|
Self::Typeless(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Display for TestLookupError<'a> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
TestLookupError::Typeless(typeless_error) => {
|
||||||
|
f.write_fmt(format_args!("typeless lookup failure: {}", typeless_error))
|
||||||
|
}
|
||||||
|
TestLookupError::EmptyResolverAccess(address) => f.write_fmt(format_args!(
|
||||||
|
"accessed an empty resolved at address {}.",
|
||||||
|
address
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Error for TestLookupError<'a> {}
|
||||||
|
|
||||||
|
impl Context for TestContext {
|
||||||
|
type T = classes::solo::SoloClass;
|
||||||
|
|
||||||
|
type LookupError<'a> = TestLookupError<'a>;
|
||||||
|
|
||||||
|
fn hash(s: &[u8]) -> Hash {
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
hasher.update(s);
|
||||||
|
hasher.finalize().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EmptyResolver;
|
||||||
|
|
||||||
|
impl<'a> Resolver<'a, TestContext> for EmptyResolver {
|
||||||
|
fn resolve(self: std::rc::Rc<Self>, address: Address) -> HashResolution<'a, TestContext> {
|
||||||
|
Err(TestLookupError::EmptyResolverAccess(address))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user