removed associated errors, now using side channel error tracking
Konnor Andrews 2024-01-10
parent c73a913 · commit 7b74883
-rw-r--r--src/build.rs45
-rw-r--r--src/error.rs101
-rw-r--r--src/impls/core.rs1
-rw-r--r--src/impls/core/iterator.rs56
-rw-r--r--src/impls/core/reference.rs471
-rw-r--r--src/impls/core/str.rs133
-rw-r--r--src/lib.rs91
-rw-r--r--src/protocol.rs282
-rw-r--r--src/protocols.rs82
-rw-r--r--src/transform.rs98
-rw-r--r--src/walk.rs50
-rw-r--r--tests/demo.rs108
12 files changed, 775 insertions, 743 deletions
diff --git a/src/build.rs b/src/build.rs
index 6342309..d4dc676 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -1,46 +1,15 @@
-use crate::{UniError, Visitor, WalkStatus, Walker};
+use crate::Visitor;
/// A type buildable from a walker.
-pub trait Build<'value, 'ctx: 'value, WalkerErr>: Sized {
+pub trait Build<'value, 'ctx>: Sized {
type Error;
/// The builder that can be used to build a value.
- type Builder: Builder<'value, 'ctx, WalkerErr, Value = Self, Error = Self::Error>;
+ type Builder: Builder<'value, 'ctx, Value = Self, Error = Self::Error>;
}
-// /// Build a [`Buildable`] type from a walker.
-// ///
-// /// This calls [`Walker::walk`] on the walker.
-// pub fn build<
-// 'value,
-// 'ctx: 'value,
-// T: Build<'value, 'ctx, W::Error, Error = VisitorErr>,
-// VisitorErr,
-// W: ?Sized + Walker<'value, 'ctx, VisitorErr>,
-// >(
-// walker: &mut W,
-// ) -> Result<(T, WalkStatus), UniError<W::Error, VisitorErr>> {
-// T::Builder::build(walker)
-// }
-//
-// pub trait BuilderExt<'value, 'ctx: 'value, WalkerErr>: Builder<'value, 'ctx, WalkerErr> {
-// fn build<W: ?Sized + Walker<'value, 'ctx, Self::Error, Error = WalkerErr>>(
-// walker: &mut W,
-// ) -> Result<(Self::Value, WalkStatus), UniError<WalkerErr, Self::Error>>;
-// }
-//
-// impl<'value, 'ctx: 'value, WalkerErr, T: Builder<'value, 'ctx, WalkerErr>> BuilderExt<'value, 'ctx, WalkerErr> for T {
-// fn build<W: ?Sized + Walker<'value, 'ctx, Self::Error, Error = WalkerErr>>(
-// walker: &mut W,
-// ) -> Result<(Self::Value, WalkStatus), UniError<WalkerErr, Self::Error>> {
-// let mut builder = Self::init();
-// let status = walker.walk(builder.as_visitor())?;
-// Ok((builder.finish()?, status))
-// }
-// }
-
/// Extension to [`Visitor`] that allows constructing and finishing the visitor.
-pub trait Builder<'value, 'ctx: 'value, WalkerErr> {
+pub trait Builder<'value, 'ctx> {
type Error;
/// Type to be built.
@@ -52,10 +21,12 @@ pub trait Builder<'value, 'ctx: 'value, WalkerErr> {
Self: Sized;
/// As a visitor.
- fn as_visitor(&mut self) -> &mut dyn Visitor<'value, 'ctx, WalkerErr, Error = Self::Error>;
+ fn as_visitor<WalkerErr: 'value>(
+ &mut self,
+ ) -> &mut dyn Visitor<'value, 'ctx, WalkerErr, Error = Self::Error>;
/// Finish the value.
- fn finish(self) -> Result<Self::Value, UniError<WalkerErr, Self::Error>>
+ fn finish(self) -> Result<Self::Value, Self::Error>
where
Self: Sized;
}
diff --git a/src/error.rs b/src/error.rs
index 2e30c9f..e69de29 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,101 +0,0 @@
-use crate::protocol::{Protocol, ProtocolDescription};
-
-pub trait WalkerError<'value, 'ctx: 'value> {
- fn wrong_visit<P: Protocol<'value, 'ctx>>() -> Self;
- fn needs_hint() -> Self;
-}
-
-pub trait VisitorError<'value, 'ctx: 'value> {
- fn wrong_hint<P: Protocol<'value, 'ctx>>() -> Self;
-}
-
-pub struct A<'value>(&'value str);
-
-impl<'value, 'ctx: 'value> VisitorError<'value, 'ctx> for A<'value> {
- fn wrong_hint<P: Protocol<'value, 'ctx>>() -> Self {
- todo!()
- }
-}
-
-#[derive(thiserror::Error, Debug)]
-pub enum UniError<WalkerErr, VisitorErr> {
- #[error(transparent)]
- Walker(WalkerErr),
-
- #[error(transparent)]
- Visitor(VisitorErr),
-}
-
-#[derive(thiserror::Error, Debug)]
-#[error("{message}")]
-pub struct BasicError {
- message: &'static str,
-}
-
-impl BasicError {
- pub fn new(message: &'static str) -> Self {
- Self { message }
- }
-
- pub fn message(&self) -> &'static str {
- self.message
- }
-}
-
-impl<'value, 'ctx: 'value> WalkerError<'value, 'ctx> for BasicError {
- fn wrong_visit<P: Protocol<'value, 'ctx>>() -> Self {
- Self::new("wrong protocol for visit")
- }
-
- fn needs_hint() -> Self {
- Self::new("walker needs hint from visitor")
- }
-}
-
-impl<'value, 'ctx: 'value> VisitorError<'value, 'ctx> for BasicError {
- fn wrong_hint<P: Protocol<'value, 'ctx>>() -> Self {
- Self::new("wrong protocol for hint")
- }
-}
-
-/// Error wrapper that adds a missing variant.
-#[derive(thiserror::Error, Debug)]
-pub enum Missing<E> {
- /// The value was never visted.
- #[error("value is missing after walking")]
- Missing,
-
- /// Another error.
- #[error(transparent)]
- Error(#[from] E),
-}
-
-impl<'value, 'ctx: 'value, E: VisitorError<'value, 'ctx>> VisitorError<'value, 'ctx>
- for Missing<E>
-{
- fn wrong_hint<P: Protocol<'value, 'ctx>>() -> Self {
- E::wrong_hint::<P>().into()
- }
-}
-
-#[derive(thiserror::Error, Debug)]
-pub enum WrongProtocol<E> {
- /// The wrong protocol was given in a query.
- #[error("wrong protocol, expected: `{expected}`, got: `{got}`")]
- WrongProtocol {
- expected: ProtocolDescription,
- got: ProtocolDescription,
- },
-
- /// Another error.
- #[error(transparent)]
- Error(#[from] E),
-}
-
-impl<'value, 'ctx: 'value, E: VisitorError<'value, 'ctx>> VisitorError<'value, 'ctx>
- for WrongProtocol<E>
-{
- fn wrong_hint<P: Protocol<'value, 'ctx>>() -> Self {
- E::wrong_hint::<P>().into()
- }
-}
diff --git a/src/impls/core.rs b/src/impls/core.rs
index f9135be..7a918f1 100644
--- a/src/impls/core.rs
+++ b/src/impls/core.rs
@@ -1,2 +1,3 @@
+pub mod iterator;
pub mod reference;
pub mod str;
diff --git a/src/impls/core/iterator.rs b/src/impls/core/iterator.rs
new file mode 100644
index 0000000..713b66e
--- /dev/null
+++ b/src/impls/core/iterator.rs
@@ -0,0 +1,56 @@
+use core::marker::PhantomData;
+
+use crate::{
+ error::UniError, protocol::ProtocolDescription, protocols::sequence, walk::WalkOnce, Fallible,
+ Visitor, WalkStatus, Walker,
+};
+
+pub struct IterWalker<'value, 'ctx, I: Iterator, WalkerErr, VisitorErr>(
+ I,
+ fn(
+ I::Item,
+ &mut dyn Visitor<'value, 'ctx, WalkerErr, Error = VisitorErr>,
+ ) -> Result<WalkStatus, UniError<WalkerErr, VisitorErr>>,
+ PhantomData<&'value &'ctx ()>,
+);
+
+impl<'value, 'ctx, I, WalkerErr, VisitorErr: 'value>
+ IterWalker<'value, 'ctx, I, WalkerErr, VisitorErr>
+where
+ I: Iterator,
+{
+ pub fn new<T>(into_iter: T) -> Self
+ where
+ T: IntoIterator<IntoIter = I>,
+ <I as Iterator>::Item: WalkOnce<'value, 'ctx, Error = WalkerErr>,
+ {
+ Self(
+ into_iter.into_iter(),
+ |item, visitor| item.into_walker().walk(visitor),
+ PhantomData,
+ )
+ }
+}
+
+impl<'value, 'ctx, I: Iterator, WalkerErr, VisitorErr> Fallible
+ for IterWalker<'value, 'ctx, I, WalkerErr, VisitorErr>
+{
+ type Error = WalkerErr;
+}
+
+impl<'value, 'ctx, I, WalkerErr, VisitorErr> Walker<'value, 'ctx, VisitorErr>
+ for IterWalker<'value, 'ctx, I, WalkerErr, VisitorErr>
+where
+ I: Iterator,
+{
+ fn walk(
+ &mut self,
+ visitor: &mut dyn Visitor<'value, 'ctx, Self::Error, Error = VisitorErr>,
+ ) -> Result<WalkStatus, UniError<Self::Error, VisitorErr>> {
+ while let Some(item) = self.0.next() {
+ (self.1)(item, visitor)?;
+ }
+
+ Ok(WalkStatus::Done)
+ }
+}
diff --git a/src/impls/core/reference.rs b/src/impls/core/reference.rs
index d1fe29e..69c8f08 100644
--- a/src/impls/core/reference.rs
+++ b/src/impls/core/reference.rs
@@ -1,139 +1,165 @@
-//! Impls for references `&T` and `&mut T`.
-//!
-//! ## Walk
-//!
-//! `&T` implements [`WalkOnce`], [`WalkMut`], and [`Walk`] if `T` implements [`Walk`].
-//!
-//! `&mut T` implements [`WalkOnce`], and [`WalkMut`] if `T` implements [`WalkMut`].
-//!
-//! ## Build
-
-// === &T ===
-
use core::{any::Any, marker::PhantomData};
use crate::{
build::{Build, Builder},
- error::{Missing, UniError, WalkerError, WrongProtocol},
- protocol::{AnyVisit, ProtocolId, Visit},
- protocol_list,
- protocols::reference::{self, Reference},
+ error::{Missing, PrimitiveTypeError, UniError},
+ protocol::{lookup_visit, AnyProtocolVisit, AnyVisit, ProtocolDescription, ProtocolId, Visit},
+ protocols::reference,
walk::{Walk, WalkMut, WalkOnce},
+ Fallible, Visitor, WalkStatus, Walker,
};
-// impl<'value, 'ctx: 'value, VisitorErr: 'ctx, T: ?Sized> WalkOnce<'value, 'ctx, VisitorErr>
-// for &'ctx T
-// where
-// T: Walk<'value, 'ctx, VisitorErr>,
-// {
-// type ErrorOnce = T::Error;
-// type WalkerOnce = T::Walker;
-//
-// fn into_walker(self) -> T::Walker {
-// T::walker(self)
-// }
-// }
-//
-// impl<'value, 'ctx: 'value, VisitorErr: 'ctx, T: ?Sized> WalkMut<'value, 'ctx, VisitorErr>
-// for &'ctx T
-// where
-// T: Walk<'value, 'ctx, VisitorErr>,
-// {
-// type ErrorMut = T::Error;
-// type WalkerMut = T::Walker;
-//
-// fn walker_mut(&'value mut self) -> T::Walker {
-// T::walker(*self)
-// }
-// }
-
-// pub struct Error<'value, 'ctx, E>(E, PhantomData<&'value &'ctx ()>);
-//
-// impl<'value, 'ctx, E: WalkerError<'ctx, 'static>> WalkerError<'value, 'ctx> for Error<'value, 'ctx, E> {
-// fn wrong_visit<P: crate::protocol::Protocol<'value, 'ctx>>() -> Self {
-// todo!()
-// }
-//
-// fn needs_hint() -> Self {
-// todo!()
-// }
-// }
-//
-// pub struct Walker<'value, 'ctx, 'root, W>(W, PhantomData<&'value &'ctx &'root ()>);
-//
-// impl<'value, 'ctx: 'value, 'root: 'ctx, W: crate::Walker<'value, 'ctx, VisitorErr>, VisitorErr> crate::Walker<'value, 'ctx, VisitorErr> for Walker<'value, 'ctx, 'root, W>
-// {
-// type Error = Error<'value, 'ctx, 'root, W::Error>;
-//
-// fn walk(
-// &mut self,
-// visitor: &mut dyn crate::Visitor<'value, 'ctx, Self::Error, Error = VisitorErr>,
-// ) -> Result<crate::WalkStatus, UniError<Self::Error, VisitorErr>> {
-// todo!()
-// }
-//
-// fn all_protocols() -> impl Iterator<Item = crate::protocol::ProtocolDescription>
-// where
-// Self: Sized {
-// W::all_protocols()
-// }
-// }
-
-/// `'value` and `'ctx` form the bounds of the possible lifetimes.
-/// These are what the walker will actually work with.
-///
-/// `'value`` < `'borrow` < `'ctx`
-/// `'borrow` allows &'value &'borrow T to forward to T's &'borrow T
-impl<'value, 'method: 'value, 'borrow: 'method, 'ctx: 'borrow, VisitorErr, T: ?Sized> Walk<'value, 'method, 'ctx, VisitorErr> for &'borrow T
+pub trait LifetimeBound {}
+
+pub enum ValueLifetime {}
+pub enum ContextLifetime {}
+pub enum StaticLifetime {}
+
+impl LifetimeBound for ValueLifetime {}
+impl LifetimeBound for ContextLifetime {}
+impl LifetimeBound for StaticLifetime {}
+
+pub struct RefWalker<'a, T: ?Sized, Lt: LifetimeBound>(&'a T, PhantomData<Lt>);
+
+impl<'a, T: ?Sized, Lt: LifetimeBound> RefWalker<'a, T, Lt> {
+ pub fn new(value: &'a T) -> Self {
+ Self(value, PhantomData)
+ }
+}
+
+impl<'ctx, T: ?Sized, Lt: LifetimeBound> Fallible for RefWalker<'ctx, T, Lt> {
+ type Error = PrimitiveTypeError;
+}
+
+impl<'value, 'borrow: 'value, 'ctx: 'borrow, T: ?Sized + Any, VisitorErr: 'value>
+ Walker<'value, 'ctx, VisitorErr> for RefWalker<'borrow, T, ValueLifetime>
+{
+ fn walk(
+ &mut self,
+ visitor: &mut dyn Visitor<'value, 'ctx, Self::Error, Error = VisitorErr>,
+ ) -> Result<WalkStatus, UniError<Self::Error, VisitorErr>> {
+ let mut protocol =
+ lookup_visit::<reference::Reference<T>, _, _>(visitor).map_err(UniError::Walker)?;
+
+ protocol.visit(reference::Ref::Value(self.0))?;
+
+ Ok(WalkStatus::Repeat)
+ }
+}
+
+impl<'value, 'ctx: 'value, 'borrow: 'ctx, T: ?Sized + Any, VisitorErr: 'value>
+ Walker<'value, 'ctx, VisitorErr> for RefWalker<'borrow, T, ContextLifetime>
+{
+ fn walk(
+ &mut self,
+ visitor: &mut dyn Visitor<'value, 'ctx, Self::Error, Error = VisitorErr>,
+ ) -> Result<WalkStatus, UniError<Self::Error, VisitorErr>> {
+ let mut protocol =
+ lookup_visit::<reference::Reference<T>, _, _>(visitor).map_err(UniError::Walker)?;
+
+ protocol.visit(reference::Ref::Context(self.0))?;
+
+ Ok(WalkStatus::Repeat)
+ }
+}
+
+impl<'value, 'ctx: 'value, 'borrow: 'ctx, T: ?Sized + Any, VisitorErr: 'value>
+ Walker<'value, 'ctx, VisitorErr> for RefWalker<'static, T, StaticLifetime>
+{
+ fn walk(
+ &mut self,
+ visitor: &mut dyn Visitor<'value, 'ctx, Self::Error, Error = VisitorErr>,
+ ) -> Result<WalkStatus, UniError<Self::Error, VisitorErr>> {
+ let mut protocol =
+ lookup_visit::<reference::Reference<T>, _, _>(visitor).map_err(UniError::Walker)?;
+
+ protocol.visit(reference::Ref::Static(self.0))?;
+
+ Ok(WalkStatus::Repeat)
+ }
+}
+
+impl<'value, 'borrow: 'value, 'ctx: 'borrow, T: ?Sized> WalkOnce<'value, 'ctx> for &'borrow T
+where
+ T: Walk<'value, 'borrow, 'ctx>,
+{
+ type Error = T::Error;
+
+ type Walker<VisitorErr: 'value> = T::Walker<VisitorErr>;
+
+ fn into_walker<VisitorErr: 'value>(self) -> Self::Walker<VisitorErr> {
+ T::walker(self)
+ }
+}
+
+impl<'value, 'method: 'value, 'borrow: 'method, 'ctx: 'borrow, T: ?Sized>
+ WalkMut<'value, 'method, 'ctx> for &'borrow T
where
- T: Walk<'value, 'borrow, 'ctx, VisitorErr>,
+ T: Walk<'value, 'borrow, 'ctx>,
{
type Error = T::Error;
- type Walker = T::Walker;
- fn walker(&'method self) -> Self::Walker {
+ type Walker<VisitorErr: 'value> = T::Walker<VisitorErr>;
+
+ fn walker_mut<VisitorErr: 'value>(&'method mut self) -> Self::Walker<VisitorErr> {
T::walker(self)
}
}
-/// Error when building a reference.
-///
-/// References can only be built if the walker gives a
-/// long enough lifetime reference. See the [`Reference`]
-/// protocol.
-#[derive(thiserror::Error, Debug)]
-pub enum ShortLifetime {
- /// The walker gave a `'walking` lifetime reference
- /// but a longer lifetime was needed.
- #[error("got `'walking` lifetime")]
- Walking,
+impl<'value, 'method: 'value, 'borrow: 'method, 'ctx: 'borrow, T: ?Sized>
+ Walk<'value, 'method, 'ctx> for &'borrow T
+where
+ T: Walk<'value, 'borrow, 'ctx>,
+{
+ type Error = T::Error;
- /// The walker gave a `'value` lifetime reference
- /// but a longer lifetime was needed.
- #[error("got `'value` lifetime")]
- Value,
+ type Walker<VisitorErr: 'value> = T::Walker<VisitorErr>;
- /// The walker gave a `'context` lifetime reference
- /// but a longer lifetime was needed.
- #[error("got `'ctx` lifetime")]
- Context,
+ fn walker<VisitorErr: 'value>(&'method self) -> Self::Walker<VisitorErr> {
+ T::walker(self)
+ }
}
-#[derive(Debug)]
-pub struct BuilderRefValue<'value, T: ?Sized>(Option<&'value T>);
+impl<'value, 'borrow: 'value, 'ctx: 'borrow, T: ?Sized> WalkOnce<'value, 'ctx> for &'borrow mut T
+where
+ T: WalkMut<'value, 'borrow, 'ctx>,
+{
+ type Error = T::Error;
+
+ type Walker<VisitorErr: 'value> = T::Walker<VisitorErr>;
+
+ fn into_walker<VisitorErr: 'value>(self) -> Self::Walker<VisitorErr> {
+ T::walker_mut(self)
+ }
+}
-impl<'value, 'ctx: 'value, WalkerErr: 'value, T: ?Sized + Any> Build<'value, 'ctx, WalkerErr>
- for &'value T
+impl<'value, 'borrow: 'value, 'ctx: 'borrow, T: ?Sized> WalkMut<'value, 'borrow, 'ctx>
+ for &'borrow mut T
+where
+ T: WalkMut<'value, 'borrow, 'ctx>,
{
- type Error = Missing<WrongProtocol<ShortLifetime>>;
+ type Error = T::Error;
+
+ type Walker<VisitorErr: 'value> = T::Walker<VisitorErr>;
+
+ fn walker_mut<VisitorErr: 'value>(&'borrow mut self) -> Self::Walker<VisitorErr> {
+ T::walker_mut(self)
+ }
+}
- type Builder = BuilderRefValue<'value, T>;
+#[derive(thiserror::Error, Debug)]
+pub enum LifetimeIsShort<'value, 'ctx, T: ?Sized> {
+ Walking,
+ Value(&'value T),
+ Context(&'ctx T),
}
-impl<'value, 'ctx: 'value, WalkerErr: 'value, T: ?Sized + Any> Builder<'value, 'ctx, WalkerErr>
- for BuilderRefValue<'value, T>
+pub struct RefBuilder<'value, T: ?Sized, Lt: LifetimeBound>(Option<&'value T>, PhantomData<Lt>);
+
+impl<'value, 'ctx: 'value, T: ?Sized + Any> Builder<'value, 'ctx>
+ for RefBuilder<'value, T, ValueLifetime>
{
- type Error = Missing<WrongProtocol<ShortLifetime>>;
+ type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>;
type Value = &'value T;
@@ -141,81 +167,73 @@ impl<'value, 'ctx: 'value, WalkerErr: 'value, T: ?Sized + Any> Builder<'value, '
where
Self: Sized,
{
- Self(None)
+ Self(None, PhantomData)
}
- fn as_visitor(
+ fn as_visitor<WalkerErr: 'value>(
&mut self,
- ) -> &mut dyn crate::Visitor<'value, 'ctx, WalkerErr, Error = Self::Error> {
+ ) -> &mut dyn Visitor<'value, 'ctx, WalkerErr, Error = Self::Error> {
self
}
- fn finish(self) -> Result<Self::Value, crate::error::UniError<WalkerErr, Self::Error>>
+ fn finish(self) -> Result<Self::Value, Self::Error>
where
Self: Sized,
{
- self.0.ok_or(UniError::Visitor(Missing::Missing))
+ if let Some(value) = self.0 {
+ Ok(value)
+ } else {
+ Err(Missing::Missing)
+ }
}
}
-impl<'value, 'ctx: 'value, WalkerErr: 'value, T: ?Sized + Any>
- crate::Visitor<'value, 'ctx, WalkerErr> for BuilderRefValue<'value, T>
+impl<'value, 'ctx: 'value, T: ?Sized + Any, WalkerErr: 'value> Visitor<'value, 'ctx, WalkerErr>
+ for RefBuilder<'value, T, ValueLifetime>
{
- type Error = Missing<WrongProtocol<ShortLifetime>>;
+ type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>;
fn protocol(
&mut self,
- id: crate::protocol::ProtocolId,
- ) -> Option<crate::protocol::AnyVisit<'_, 'value, 'ctx, WalkerErr, Self::Error>> {
+ id: ProtocolId,
+ ) -> Option<AnyProtocolVisit<'_, 'value, 'ctx, WalkerErr, Self::Error>> {
match id {
- id if id == ProtocolId::of::<Reference<T>>() => Some(AnyVisit::new(self)),
+ id if id == ProtocolId::of::<reference::Reference<T>>() => {
+ Some(AnyVisit::new(self).erase())
+ }
_ => None,
}
}
-
- fn all_protocols() -> impl Iterator<Item = crate::protocol::ProtocolDescription>
- where
- Self: Sized,
- {
- protocol_list![Reference<T>]
- }
}
-impl<'value, 'ctx: 'value, WalkerErr: 'value, T: ?Sized + Any>
- Visit<'value, 'ctx, Reference<T>, WalkerErr> for BuilderRefValue<'value, T>
+impl<'value, 'ctx: 'value, T: ?Sized + Any, WalkerErr>
+ Visit<'value, 'ctx, reference::Reference<T>, WalkerErr>
+ for RefBuilder<'value, T, ValueLifetime>
{
- type Error = Missing<WrongProtocol<ShortLifetime>>;
+ type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>;
fn visit<'walking>(
&'walking mut self,
- accessor: <Reference<T> as crate::protocol::Protocol<'value, 'ctx>>::Accessor<
- 'walking,
- WalkerErr,
- Self::Error,
- >,
+ accessor: reference::Ref<'walking, 'value, 'ctx, T>,
) -> Result<(), UniError<WalkerErr, Self::Error>> {
- use reference::Ref::*;
-
match accessor {
- Walking(_) => Err(UniError::Visitor(Missing::Error(WrongProtocol::Error(
- ShortLifetime::Walking,
- )))),
- Value(value) | Context(value) | Static(value) => {
+ reference::Ref::Walking(_) => {
+ Err(UniError::Visitor(Missing::Error(LifetimeIsShort::Walking)))
+ }
+ reference::Ref::Value(value)
+ | reference::Ref::Context(value)
+ | reference::Ref::Static(value) => {
self.0 = Some(value);
-
Ok(())
}
}
}
}
-#[derive(Debug)]
-pub struct BuilderRefContext<'ctx, T: ?Sized>(Option<&'ctx T>);
-
-impl<'value, 'ctx: 'value, WalkerErr: 'value, T: ?Sized + Any> Builder<'value, 'ctx, WalkerErr>
- for BuilderRefContext<'ctx, T>
+impl<'value, 'ctx: 'value, T: ?Sized + Any> Builder<'value, 'ctx>
+ for RefBuilder<'ctx, T, ContextLifetime>
{
- type Error = Missing<WrongProtocol<ShortLifetime>>;
+ type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>;
type Value = &'ctx T;
@@ -223,99 +241,150 @@ impl<'value, 'ctx: 'value, WalkerErr: 'value, T: ?Sized + Any> Builder<'value, '
where
Self: Sized,
{
- Self(None)
+ Self(None, PhantomData)
}
- fn as_visitor(
+ fn as_visitor<WalkerErr: 'value>(
&mut self,
- ) -> &mut dyn crate::Visitor<'value, 'ctx, WalkerErr, Error = Self::Error> {
+ ) -> &mut dyn Visitor<'value, 'ctx, WalkerErr, Error = Self::Error> {
self
}
- fn finish(self) -> Result<Self::Value, crate::error::UniError<WalkerErr, Self::Error>>
+ fn finish(self) -> Result<Self::Value, Self::Error>
where
Self: Sized,
{
- self.0.ok_or(UniError::Visitor(Missing::Missing))
+ if let Some(value) = self.0 {
+ Ok(value)
+ } else {
+ Err(Missing::Missing)
+ }
}
}
-impl<'value, 'ctx: 'value, WalkerErr: 'value, T: ?Sized + Any>
- crate::Visitor<'value, 'ctx, WalkerErr> for BuilderRefContext<'ctx, T>
+impl<'value, 'ctx: 'value, T: ?Sized + Any, WalkerErr: 'value> Visitor<'value, 'ctx, WalkerErr>
+ for RefBuilder<'ctx, T, ContextLifetime>
{
- type Error = Missing<WrongProtocol<ShortLifetime>>;
+ type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>;
fn protocol(
&mut self,
- id: crate::protocol::ProtocolId,
- ) -> Option<crate::protocol::AnyVisit<'_, 'value, 'ctx, WalkerErr, Self::Error>> {
+ id: ProtocolId,
+ ) -> Option<AnyProtocolVisit<'_, 'value, 'ctx, WalkerErr, Self::Error>> {
match id {
- id if id == ProtocolId::of::<Reference<T>>() => Some(AnyVisit::new(self)),
+ id if id == ProtocolId::of::<reference::Reference<T>>() => {
+ Some(AnyVisit::new(self).erase())
+ }
_ => None,
}
}
-
- fn all_protocols() -> impl Iterator<Item = crate::protocol::ProtocolDescription>
- where
- Self: Sized,
- {
- protocol_list![Reference<T>]
- }
}
-impl<'value, 'ctx: 'value, WalkerErr: 'value, T: ?Sized + Any>
- Visit<'value, 'ctx, Reference<T>, WalkerErr> for BuilderRefContext<'ctx, T>
+impl<'value, 'ctx: 'value, T: ?Sized + Any, WalkerErr>
+ Visit<'value, 'ctx, reference::Reference<T>, WalkerErr>
+ for RefBuilder<'ctx, T, ContextLifetime>
{
- type Error = Missing<WrongProtocol<ShortLifetime>>;
+ type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>;
fn visit<'walking>(
&'walking mut self,
- accessor: <Reference<T> as crate::protocol::Protocol<'value, 'ctx>>::Accessor<
- 'walking,
- WalkerErr,
- Self::Error,
- >,
+ accessor: reference::Ref<'walking, 'value, 'ctx, T>,
) -> Result<(), UniError<WalkerErr, Self::Error>> {
- use reference::Ref::*;
-
match accessor {
- Walking(_) => Err(UniError::Visitor(Missing::Error(WrongProtocol::Error(
- ShortLifetime::Walking,
- )))),
- Value(_) => Err(UniError::Visitor(Missing::Error(WrongProtocol::Error(
- ShortLifetime::Value,
- )))),
- Context(value) | Static(value) => {
+ reference::Ref::Walking(_) => {
+ Err(UniError::Visitor(Missing::Error(LifetimeIsShort::Walking)))
+ }
+ reference::Ref::Value(value) => Err(UniError::Visitor(Missing::Error(
+ LifetimeIsShort::Value(value),
+ ))),
+ reference::Ref::Context(value) | reference::Ref::Static(value) => {
self.0 = Some(value);
-
Ok(())
}
}
}
}
-// === &mut T ===
+impl<'value, 'ctx: 'value, T: ?Sized + Any> Builder<'value, 'ctx>
+ for RefBuilder<'static, T, StaticLifetime>
+{
+ type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>;
+
+ type Value = &'static T;
-impl<'value, 'ctx: 'value, VisitorErr: 'ctx, T> WalkOnce<'value, 'ctx, VisitorErr> for &'ctx mut T
-where
- T: WalkMut<'value, 'ctx, VisitorErr>,
+ fn init() -> Self
+ where
+ Self: Sized,
+ {
+ Self(None, PhantomData)
+ }
+
+ fn as_visitor<WalkerErr: 'value>(
+ &mut self,
+ ) -> &mut dyn Visitor<'value, 'ctx, WalkerErr, Error = Self::Error> {
+ self
+ }
+
+ fn finish(self) -> Result<Self::Value, Self::Error>
+ where
+ Self: Sized,
+ {
+ if let Some(value) = self.0 {
+ Ok(value)
+ } else {
+ Err(Missing::Missing)
+ }
+ }
+}
+
+impl<'value, 'ctx: 'value, T: ?Sized + Any, WalkerErr: 'value> Visitor<'value, 'ctx, WalkerErr>
+ for RefBuilder<'static, T, StaticLifetime>
{
- type ErrorOnce = T::ErrorMut;
- type WalkerOnce = T::WalkerMut;
+ type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>;
- fn into_walker(self) -> T::WalkerMut {
- T::walker_mut(self)
+ fn protocol(
+ &mut self,
+ id: ProtocolId,
+ ) -> Option<AnyProtocolVisit<'_, 'value, 'ctx, WalkerErr, Self::Error>> {
+ match id {
+ id if id == ProtocolId::of::<reference::Reference<T>>() => {
+ Some(AnyVisit::new(self).erase())
+ }
+ _ => None,
+ }
}
}
-impl<'value, 'ctx: 'value, VisitorErr: 'ctx, T> WalkMut<'value, 'ctx, VisitorErr> for &'ctx mut T
-where
- T: WalkMut<'value, 'ctx, VisitorErr>,
+impl<'value, 'ctx: 'value, T: ?Sized + Any, WalkerErr>
+ Visit<'value, 'ctx, reference::Reference<T>, WalkerErr>
+ for RefBuilder<'static, T, StaticLifetime>
{
- type ErrorMut = T::ErrorMut;
- type WalkerMut = T::WalkerMut;
+ type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>;
- fn walker_mut(&'value mut self) -> T::WalkerMut {
- T::walker_mut(self)
+ fn visit<'walking>(
+ &'walking mut self,
+ accessor: reference::Ref<'walking, 'value, 'ctx, T>,
+ ) -> Result<(), UniError<WalkerErr, Self::Error>> {
+ match accessor {
+ reference::Ref::Walking(_) => {
+ Err(UniError::Visitor(Missing::Error(LifetimeIsShort::Walking)))
+ }
+ reference::Ref::Value(value) => Err(UniError::Visitor(Missing::Error(
+ LifetimeIsShort::Value(value),
+ ))),
+ reference::Ref::Context(value) => Err(UniError::Visitor(Missing::Error(
+ LifetimeIsShort::Context(value),
+ ))),
+ reference::Ref::Static(value) => {
+ self.0 = Some(value);
+ Ok(())
+ }
+ }
}
}
+
+impl<'value, 'ctx: 'value, T: ?Sized + Any> Build<'value, 'ctx> for &'value T {
+ type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>;
+
+ type Builder = RefBuilder<'value, T, ValueLifetime>;
+}
diff --git a/src/impls/core/str.rs b/src/impls/core/str.rs
index 6eec1e1..021fc11 100644
--- a/src/impls/core/str.rs
+++ b/src/impls/core/str.rs
@@ -1,132 +1,13 @@
-use core::marker::PhantomData;
+use crate::{error::PrimitiveTypeError, walk::Walk};
-use crate::{
- build::{Build, Builder},
- error::{BasicError, UniError},
- protocol::{
- lookup_hint, lookup_visit, AnyHint, AnyVisit, Hint, Protocol, ProtocolDescription,
- ProtocolId,
- },
- protocol_list,
- protocols::reference::{self, Reference},
- walk::{Walk, WalkMut, WalkOnce},
- walk_with_hints, HintGiven, WalkerHints,
-};
+use super::reference::{RefWalker, ValueLifetime};
-use super::reference::BuilderRefValue;
+impl<'value, 'borrow: 'value, 'ctx: 'borrow> Walk<'value, 'borrow, 'ctx> for str {
+ type Error = PrimitiveTypeError;
-pub struct Walker<'value>(&'value str);
+ type Walker<VisitorErr: 'value> = RefWalker<'borrow, str, ValueLifetime>;
-impl<'value, 'ctx: 'value, VisitorErr: 'value> crate::Walker<'value, 'ctx, VisitorErr>
- for Walker<'ctx>
-{
- type Error = BasicError;
-
- fn walk(
- &mut self,
- visitor: &mut dyn crate::Visitor<'value, 'ctx, Self::Error, Error = VisitorErr>,
- ) -> Result<crate::WalkStatus, UniError<Self::Error, VisitorErr>> {
- match lookup_visit::<Reference<str>, _, _>(visitor).map_err(UniError::Walker)? {
- Some(visitor) => {
- visitor.visit(reference::Ref::Context(self.0))?;
- Ok(crate::WalkStatus::Continue)
- }
- None => Err(UniError::Walker(BasicError::new(
- "visitor needs the reference protocol for `str`",
- ))),
- }
- }
-
- fn all_protocols() -> impl Iterator<Item = ProtocolDescription>
- where
- Self: Sized,
- {
- protocol_list![Reference<str>]
+ fn walker<VisitorErr: 'value>(&'borrow self) -> Self::Walker<VisitorErr> {
+ RefWalker::new(self)
}
}
-
-impl<'value, 'ctx: 'value, VisitorErr: 'value> WalkerHints<'value, 'ctx, VisitorErr>
- for Walker<'ctx>
-{
- type Error = BasicError;
-
- fn protocol(
- &mut self,
- id: ProtocolId,
- ) -> Option<AnyHint<'_, 'value, 'ctx, Self::Error, VisitorErr>> {
- match id {
- id if id == ProtocolId::of::<Reference<str>>() => Some(AnyHint::new(self)),
- _ => None,
- }
- }
-}
-
-impl<'value, 'ctx: 'value, VisitorErr: 'value> Hint<'value, 'ctx, Reference<str>, VisitorErr>
- for Walker<'ctx>
-{
- type Error = BasicError;
-
- fn hint(
- &mut self,
- visitor: &mut dyn crate::Visitor<'value, 'ctx, Self::Error, Error = VisitorErr>,
- _hint: <Reference<str> as crate::protocol::Protocol<'value, 'ctx>>::Hint,
- ) -> Result<HintGiven, UniError<Self::Error, VisitorErr>> {
- lookup_visit::<Reference<str>, _, _>(visitor)
- .map_err(UniError::Walker)?
- .ok_or_else(|| {
- UniError::Walker(BasicError::new("visitor is missing the str protocol"))
- })?
- .visit(reference::Ref::Context(self.0))?;
-
- Ok(HintGiven)
- }
-
- fn known(
- &mut self,
- _hint: &<Reference<str> as crate::protocol::Protocol<'value, 'ctx>>::Hint,
- ) -> Result<<Reference<str> as crate::protocol::Protocol<'value, 'ctx>>::Known, BasicError>
- {
- Ok(reference::Known {
- len: Some(self.0.len()),
- kind: Some(reference::Kind::Context),
- })
- }
-}
-
-// impl<'value, 'ctx: 'value, VisitorErr: 'ctx> WalkMut<'value, 'ctx, VisitorErr> for str {
-// type ErrorMut = BasicError;
-// type WalkerMut = Walker<'value, 'ctx>;
-//
-// fn walker_mut(&'value mut self) -> Self::WalkerMut {
-// Walker(self, PhantomData)
-// }
-// }
-
-// impl<'value, 'borrow: 'value, 'ctx: 'borrow, VisitorErr: 'value> Walk<'value, 'borrow, 'ctx, VisitorErr> for str {
-// type Error = BasicError;
-// type Walker = Walker<'borrow>;
-//
-// fn walker(&'borrow self) -> Self::Walker {
-// Walker(self)
-// }
-// }
-
-impl<'value, 'borrow: 'value, 'ctx: 'borrow, VisitorErr: 'value> Walk<'value, 'ctx, 'ctx, VisitorErr> for str {
- type Error = BasicError;
- type Walker = Walker<'ctx>;
-
- fn walker(&'ctx self) -> Self::Walker {
- Walker(self)
- }
-}
-
-//
-// impl<'value, 'ctx: 'value, VisitorErr: 'value> Walk<'value, 'value, 'ctx, VisitorErr> for i32 {
-// type Error = BasicError;
-// type Walker = Walker<'value, 'ctx>;
-//
-// fn walker(&'value self) -> Self::Walker {
-// // Walker(self, PhantomData)
-// todo!()
-// }
-// }
diff --git a/src/lib.rs b/src/lib.rs
index f74cd44..cba864c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,34 +3,20 @@
#[cfg(feature = "alloc")]
extern crate alloc;
-pub mod build;
+// pub mod build;
pub mod error;
-pub mod impls;
+// pub mod impls;
pub mod protocol;
-pub mod protocols;
-pub mod transform;
-pub mod walk;
+// pub mod protocols;
+// pub mod transform;
+// pub mod walk;
// use buildable::Buildable;
-use error::{UniError, WalkerError};
-use protocol::{AnyHint, AnyVisit, Hint, ProtocolDescription, ProtocolId, Visit};
+use protocol::{AnyHint, Hint, ProtocolId, Visit, AnyVisit};
// pub use buildable::Buildable;
// pub use walkable::{Walkable, WalkableMut, WalkableRef};
-/// Token value showing a hint was given.
-///
-/// This is used by [`Visitor::request_hint`] to tell the walker if a hint
-/// was given or not. A `Some(HintGiven)` means the visitor gave a hint by
-/// calling a [`Hint::hint`] method. A `None` means the visitor did not
-/// give a hint to the walker for what protocol to use.
-///
-/// [`Hint::hint`] methods return an instance of this type so [`Visitor::request_hint`]
-/// can just return that instance.
-#[must_use]
-#[derive(Debug)]
-pub struct HintGiven;
-
/// Status of a walker after walking using a visitor.
///
/// Some walkers can be walked multiple times to extract multiple
@@ -41,15 +27,17 @@ pub enum WalkStatus {
/// Attemping to call `walk` is likely to result in an error.
Done,
- /// The walker can continue.
- Continue,
+ /// The walker has more values to walk.
+ More,
+
+ /// The walker will repeat values.
+ Repeat,
+
+ Error,
}
/// Walker over a value with lifetime `'value`.
-pub trait Walker<'value, 'ctx: 'value, VisitorErr> {
- /// Error type the walker generates.
- type Error;
-
+pub trait Walker<'ctx> {
/// Walk the walker over the value.
///
/// This is the main entrypoint for walking a value.
@@ -61,34 +49,33 @@ pub trait Walker<'value, 'ctx: 'value, VisitorErr> {
/// [`Visitor::request_hint`] before using walker specific logic to pick a protocol.
fn walk(
&mut self,
- visitor: &mut dyn Visitor<'value, 'ctx, Self::Error, Error = VisitorErr>,
- ) -> Result<WalkStatus, UniError<Self::Error, VisitorErr>>;
+ visitor: &mut dyn Visitor<'ctx>,
+ ) -> WalkStatus;
+}
- fn all_protocols() -> impl Iterator<Item = ProtocolDescription>
- where
- Self: Sized;
+pub trait ErrorNeedsHint {
+ fn error_needs_hint(&mut self);
}
-pub fn walk_with_hints<'value, 'ctx: 'value, VisitorErr, H: WalkerHints<'value, 'ctx, VisitorErr>>(
+pub fn walk_with_hints<'ctx, H: WalkerHints<'ctx>>(
hints: &mut H,
- visitor: &mut dyn Visitor<'value, 'ctx, H::Error, Error = VisitorErr>,
-) -> Result<WalkStatus, UniError<H::Error, VisitorErr>>
+ visitor: &mut dyn Visitor<'ctx>,
+) -> WalkStatus
where
- H::Error: WalkerError<'value, 'ctx>,
+ H: ErrorNeedsHint,
{
// Request that the visitor give us a hint of what protocol to use.
- match visitor.request_hint(hints, true)? {
- Some(HintGiven) => Ok(WalkStatus::Done),
- None => Err(UniError::Walker(
- <H::Error as WalkerError<'value, 'ctx>>::needs_hint(),
- )),
+ match visitor.request_hint(hints, true) {
+ Some(status) => status,
+ None => {
+ hints.error_needs_hint();
+ WalkStatus::Error
+ },
}
}
/// Hint lookup for a walker.
-pub trait WalkerHints<'value, 'ctx: 'value, VisitorErr> {
- type Error;
-
+pub trait WalkerHints<'ctx> {
/// Query the walker for a given protocol.
///
/// If the walker doesn't support the protocol then a `None` is returned.
@@ -97,13 +84,11 @@ pub trait WalkerHints<'value, 'ctx: 'value, VisitorErr> {
fn protocol(
&mut self,
id: ProtocolId,
- ) -> Option<AnyHint<'_, 'value, 'ctx, Self::Error, VisitorErr>>;
+ ) -> Option<AnyHint<'_, 'ctx>>;
}
/// Visitor over a value to be built.
-pub trait Visitor<'value, 'ctx: 'value, WalkerErr> {
- type Error;
-
+pub trait Visitor<'ctx> {
/// Request the visitor hint what protocol to use.
///
/// It is not recommended to call this while in a protocol hint as a walker.
@@ -115,12 +100,12 @@ pub trait Visitor<'value, 'ctx: 'value, WalkerErr> {
/// A return value of `Ok(None)` means no hint was given to the walker.
fn request_hint(
&mut self,
- hints: &mut dyn WalkerHints<'value, 'ctx, Self::Error, Error = WalkerErr>,
+ hints: &mut dyn WalkerHints<'ctx>,
need_hint: bool,
- ) -> Result<Option<HintGiven>, UniError<WalkerErr, Self::Error>> {
+ ) -> Option<WalkStatus> {
let _ = hints;
let _ = need_hint;
- Ok(None)
+ None
}
/// Query the visitor for a given protocol.
@@ -129,9 +114,5 @@ pub trait Visitor<'value, 'ctx: 'value, WalkerErr> {
fn protocol(
&mut self,
id: ProtocolId,
- ) -> Option<AnyVisit<'_, 'value, 'ctx, WalkerErr, Self::Error>>;
-
- fn all_protocols() -> impl Iterator<Item = ProtocolDescription>
- where
- Self: Sized;
+ ) -> Option<AnyVisit<'_, 'ctx>>;
}
diff --git a/src/protocol.rs b/src/protocol.rs
index 01336db..a74e791 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -4,7 +4,7 @@ pub use any_hint::AnyHint;
pub use any_visit::AnyVisit;
pub use id::ProtocolId;
-use crate::{error::VisitorError, HintGiven, UniError, Visitor, WalkerError, WalkerHints};
+use crate::{Visitor, WalkerHints, WalkStatus};
/// A protocol between a walker and visitor.
///
@@ -16,18 +16,18 @@ use crate::{error::VisitorError, HintGiven, UniError, Visitor, WalkerError, Walk
///
/// A protocol never needs to be a value, so it's recommended to use an uninhabited type
/// like an empty enum to represent them.
-pub trait Protocol<'value, 'ctx: 'value>: Any {
+pub trait Protocol: Any {
/// Arbitrary hint metadata for the protocol.
///
/// This allows a visitor to give extra information to a walker when hinting to
/// use the protocol.
- type Hint;
+ type Hint<'ctx>;
/// Data known about the protocol before hinting.
///
/// This allows a walker to give extra information to a visitor to make a
/// better decision when selecting a hint.
- type Known;
+ type Known<'ctx>;
/// The visit data the walker provides to the visitor.
///
@@ -35,27 +35,20 @@ pub trait Protocol<'value, 'ctx: 'value>: Any {
/// The '`walking` lifetime is only alive while the walker is walking.
/// As such, a visitor cannot borrow from a `'walking` lifetime containing type
/// for it's output.
- type Accessor<'walking, WalkerErr: 'value, VisitorErr: 'value>
- where
- 'value: 'walking;
-
- fn description() -> Option<&'static str> {
- None
- }
+ type Accessor<'walking, 'ctx: 'walking>;
}
+#[derive(Copy, Clone)]
pub struct ProtocolDescription {
id: fn() -> ProtocolId,
name: fn() -> &'static str,
- description: fn() -> Option<&'static str>,
}
impl ProtocolDescription {
- pub const fn of<'value, 'ctx: 'value, P: Protocol<'value, 'ctx>>() -> Self {
+ pub const fn of<P: Protocol>() -> Self {
Self {
id: || ProtocolId::of::<P>(),
name: || core::any::type_name::<P>(),
- description: P::description,
}
}
@@ -67,17 +60,11 @@ impl ProtocolDescription {
(self.name)()
}
- pub fn description(&self) -> Option<&'static str> {
- (self.description)()
- }
}
impl core::fmt::Display for ProtocolDescription {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- match self.description() {
- Some(description) => write!(f, "{} - {}", self.name(), description),
- None => write!(f, "{}", self.name()),
- }
+ write!(f, "{}", self.name())
}
}
@@ -86,43 +73,27 @@ impl core::fmt::Debug for ProtocolDescription {
f.debug_struct("ProtocolDescription")
.field("id", &self.id())
.field("name", &self.name())
- .field("description", &self.description())
.finish()
}
}
-#[macro_export]
-#[doc(hidden)]
-macro_rules! protocol_list {
- ($($protocol:ty),* $(,)?) => {{
- [
- $($crate::protocol::ProtocolDescription::of::<$protocol>()),*
- ].into_iter()
- }}
-}
-
-#[doc(inline)]
-pub use protocol_list;
-
-pub type HintOps<'walking, 'value, 'ctx, P, WalkerErr, VisitorErr> =
- &'walking mut dyn Hint<'value, 'ctx, P, VisitorErr, Error = WalkerErr>;
+pub type HintOps<'walking, 'ctx, P> =
+ &'walking mut dyn Hint<'ctx, P>;
-pub type VisitOps<'walking, 'value, 'ctx, P, WalkerErr, VisitorErr> =
- &'walking mut dyn Visit<'value, 'ctx, P, WalkerErr, Error = VisitorErr>;
+pub type VisitOps<'walking, 'ctx, P> =
+ &'walking mut dyn Visit<'ctx, P>;
/// Protocol specific hint for a walker.
-pub trait Hint<'value, 'ctx: 'value, P: Protocol<'value, 'ctx>, VisitorErr> {
- type Error;
-
+pub trait Hint<'ctx, P: Protocol> {
/// Hint that protocol `P` should be used.
///
/// After hinting a protocol, a walker should invoke only the same protocol on the visitor.
/// This is not forced though.
fn hint(
&mut self,
- visitor: &mut dyn Visitor<'value, 'ctx, Self::Error, Error = VisitorErr>,
- hint: P::Hint,
- ) -> Result<HintGiven, UniError<Self::Error, VisitorErr>>;
+ visitor: &mut dyn Visitor<'ctx>,
+ hint: P::Hint<'ctx>,
+ ) -> WalkStatus;
/// Any information the walker has for the protocol.
///
@@ -132,61 +103,120 @@ pub trait Hint<'value, 'ctx: 'value, P: Protocol<'value, 'ctx>, VisitorErr> {
///
/// Most protocols will allow returning a value representing no knowledge is known by the
/// walker.
- fn known(&mut self, hint: &P::Hint) -> Result<P::Known, Self::Error>;
+ fn known(
+ &mut self,
+ hint: &P::Hint<'ctx>,
+ ) -> P::Known<'ctx>;
}
/// Protocol specific visit for a visitor.
-pub trait Visit<'value, 'ctx: 'value, P: Protocol<'value, 'ctx>, WalkerErr> {
- type Error;
-
+pub trait Visit<'ctx, P: Protocol> {
/// Visit a value from the walker.
fn visit<'walking>(
&'walking mut self,
- accessor: P::Accessor<'walking, WalkerErr, Self::Error>,
- ) -> Result<(), UniError<WalkerErr, Self::Error>>;
+ accessor: P::Accessor<'walking, 'ctx>,
+ );
+}
+
+pub trait ErrorWrongProtocol {
+ fn error_wrong_protocol<Expected: Protocol>(&mut self, got: ProtocolDescription);
+}
+
+pub trait ErrorMissingProtocol {
+ fn error_missing_protocol<P: Protocol>(&mut self);
+}
+
+pub fn try_lookup_hint<
+ 'a,
+ 'ctx,
+ P: Protocol,
+ E: ErrorWrongProtocol,
+ H: ?Sized + WalkerHints<'ctx>,
+>(
+ hints: &'a mut H,
+ error_report: &mut E,
+) -> Option<HintOps<'a, 'ctx, P>> {
+ match hints.protocol(ProtocolId::of::<P>()) {
+ Some(protocol) => match protocol.downcast::<P>() {
+ Ok(hint) => Some(hint),
+ Err(hint) => {
+ error_report.error_wrong_protocol::<P>(hint.description());
+ None
+ }
+ },
+ None => None,
+ }
}
-/// Helper to lookup a protocol's hint on a walker.
-///
-/// A `Ok(None)` is returned if the walker doesn't support the protocol.
-/// A `Err(...)` is returned if the walker returns a hint instance not for the protocol.
pub fn lookup_hint<
- 'value,
- 'ctx: 'value,
- P: Protocol<'value, 'ctx>,
- VisitorErr: VisitorError<'value, 'ctx>,
- H: ?Sized + WalkerHints<'value, 'ctx, VisitorErr>,
+ 'a,
+ 'ctx,
+ P: Protocol,
+ E: ErrorWrongProtocol + ErrorMissingProtocol,
+ H: ?Sized + WalkerHints<'ctx>,
>(
- hints: &mut H,
-) -> Result<Option<HintOps<'_, 'value, 'ctx, P, H::Error, VisitorErr>>, VisitorErr> {
+ hints: &'a mut H,
+ error_report: &mut E,
+) -> Option<HintOps<'a, 'ctx, P>> {
match hints.protocol(ProtocolId::of::<P>()) {
- Some(hint) => match hint.downcast::<P>() {
- Ok(hint) => Ok(Some(hint)),
- Err(_) => Err(VisitorErr::wrong_hint::<P>()),
+ Some(protocol) => match protocol.downcast::<P>() {
+ Ok(hint) => Some(hint),
+ Err(hint) => {
+ error_report.error_wrong_protocol::<P>(hint.description());
+ None
+ }
+ },
+ None => {
+ error_report.error_missing_protocol::<P>();
+ None
},
- None => Ok(None),
}
}
-/// Helper to lookup a protocol's visit on a visitor.
-///
-/// A `Ok(None)` is returned if the visitor doesn't support the protocol.
-/// A `Err(...)` is returned if the visitor returns a visit instance not for the protocol.
+pub fn try_lookup_visit<
+ 'a,
+ 'ctx,
+ P: Protocol,
+ E: ErrorWrongProtocol,
+ V: ?Sized + Visitor<'ctx>,
+>(
+ visitor: &'a mut V,
+ error_report: &mut E,
+) -> Option<VisitOps<'a, 'ctx, P>> {
+ match visitor.protocol(ProtocolId::of::<P>()) {
+ Some(protocol) => match protocol.downcast::<P>() {
+ Ok(visit) => Some(visit),
+ Err(visit) => {
+ error_report.error_wrong_protocol::<P>(visit.description());
+ None
+ }
+ },
+ None => None,
+ }
+}
+
pub fn lookup_visit<
- 'value,
+ 'a,
'ctx,
- P: Protocol<'value, 'ctx>,
- WalkerErr: WalkerError<'value, 'ctx>,
- V: ?Sized + Visitor<'value, 'ctx, WalkerErr>,
+ P: Protocol,
+ E: ErrorWrongProtocol + ErrorMissingProtocol,
+ V: ?Sized + Visitor<'ctx>,
>(
- visitor: &mut V,
-) -> Result<Option<VisitOps<'_, 'value, 'ctx, P, WalkerErr, V::Error>>, WalkerErr> {
+ visitor: &'a mut V,
+ error_report: &mut E,
+) -> Option<VisitOps<'a, 'ctx, P>> {
match visitor.protocol(ProtocolId::of::<P>()) {
- Some(visit) => match visit.downcast::<P>() {
- Ok(visit) => Ok(Some(visit)),
- Err(_) => Err(WalkerError::wrong_visit::<P>()),
+ Some(protocol) => match protocol.downcast::<P>() {
+ Ok(visit) => Some(visit),
+ Err(visit) => {
+ error_report.error_wrong_protocol::<P>(visit.description());
+ None
+ }
+ },
+ None => {
+ error_report.error_missing_protocol::<P>();
+ None
},
- None => Ok(None),
}
}
@@ -204,7 +234,7 @@ mod id {
/// Get the ID of a protocol.
///
/// The ID is unique per protocol.
- pub fn of<'value, 'ctx: 'value, P: Protocol<'value, 'ctx>>() -> Self {
+ pub fn of<P: Protocol>() -> Self {
Self(TypeId::of::<P>())
}
}
@@ -215,38 +245,38 @@ mod any_hint {
use crate::Hint;
- use super::{Protocol, ProtocolId};
+ use super::{Protocol, ProtocolDescription, ProtocolId};
/// Form of `Hint` without `P`.
- trait ErasedHint<'value, 'ctx: 'value, WalkerErr, VisitorErr>: Any {}
+ trait ErasedHint<'ctx>: Any {}
/// Get the size of pointers to trait objects for this target.
const DYN_PTR_SIZE: usize =
- core::mem::size_of::<&mut dyn ErasedHint<'static, 'static, (), ()>>();
+ core::mem::size_of::<&mut dyn ErasedHint<'static>>();
/// Type erased form of `&'walking mut dyn Hint<'value, P, Err>` where `P` is erased.
- pub struct AnyHint<'walking, 'value: 'walking, 'ctx: 'value, WalkerErr, VisitorErr> {
+ pub struct AnyHint<'walking, 'ctx> {
/// ID of `P`.
- id: ProtocolId,
+ id: ProtocolDescription,
/// This field stores a `&'walking mut dyn Hint<'value, P, Err>`.
fat_ptr: MaybeUninit<[u8; DYN_PTR_SIZE]>,
/// Mimick what we actually store with a trait without `P`.
- _marker: PhantomData<&'walking mut dyn ErasedHint<'value, 'ctx, VisitorErr, WalkerErr>>,
+ _marker: PhantomData<&'walking mut dyn ErasedHint<'ctx>>,
}
- impl<'walking, 'value, 'ctx: 'value, WalkerErr, VisitorErr>
- AnyHint<'walking, 'value, 'ctx, WalkerErr, VisitorErr>
+ impl<'walking, 'ctx>
+ AnyHint<'walking, 'ctx>
{
/// Erase the `P` in a hint.
///
/// This allows returning a hint from a object safe method.
- pub fn new<P: Protocol<'value, 'ctx>>(
- visit: &'walking mut dyn Hint<'value, 'ctx, P, VisitorErr, Error = WalkerErr>,
+ pub fn new<P: Protocol>(
+ visit: &'walking mut dyn Hint<'ctx, P>,
) -> Self {
Self {
- id: ProtocolId::of::<P>(),
+ id: ProtocolDescription::of::<P>(),
// SAFETY: A maybe uninit array of bytes can hold any pointer.
// Additionally, transmute makes sure the size is correct.
fat_ptr: unsafe { core::mem::transmute(visit) },
@@ -257,11 +287,11 @@ mod any_hint {
/// Try to downcast the hint for the given protocol.
///
/// If the hint is of the wrong type then `None` is returned.
- pub fn downcast<P: Protocol<'value, 'ctx>>(
+ pub fn downcast<P: Protocol>(
self,
- ) -> Result<&'walking mut dyn Hint<'value, 'ctx, P, VisitorErr, Error = WalkerErr>, Self>
+ ) -> Result<&'walking mut dyn Hint<'ctx, P>, Self>
{
- if self.id == ProtocolId::of::<P>() {
+ if self.id.id() == ProtocolId::of::<P>() {
// SAFETY: Only `new` can make a value of this type, and it stores the ID of `P`.
// If the IDs are equal then we can act like any and downcast back to the real
// type.
@@ -273,6 +303,10 @@ mod any_hint {
Err(self)
}
}
+
+ pub fn description(&self) -> ProtocolDescription {
+ self.id
+ }
}
}
@@ -281,38 +315,38 @@ mod any_visit {
use crate::Visit;
- use super::{Protocol, ProtocolId};
+ use super::{Protocol, ProtocolDescription, ProtocolId};
/// Form of `Visit` without `P`.
- trait ErasedVisit<'value, 'ctx: 'value, WalkerErr, VisitorErr>: Any {}
+ trait ErasedVisit<'ctx>: Any {}
/// Get the size of pointers to trait objects for this target.
const DYN_PTR_SIZE: usize =
- core::mem::size_of::<&mut dyn ErasedVisit<'static, 'static, (), ()>>();
+ core::mem::size_of::<&mut dyn ErasedVisit<'static>>();
/// Type erased form of `&'walking mut dyn Visit<'value, P, Err>` where `P` is erased.
- pub struct AnyVisit<'walking, 'value: 'walking, 'ctx: 'value, WalkerErr, VisitorErr> {
+ pub struct AnyVisit<'walking, 'ctx> {
/// ID of `P`.
- id: ProtocolId,
+ id: ProtocolDescription,
/// This field stores a `&'walking mut dyn Visit<'value, P, Err>`.
fat_ptr: MaybeUninit<[u8; DYN_PTR_SIZE]>,
/// Mimick what we actually store with a trait without `P`.
- _marker: PhantomData<&'walking mut dyn ErasedVisit<'value, 'ctx, WalkerErr, VisitorErr>>,
+ _marker: PhantomData<&'walking mut dyn ErasedVisit<'ctx>>,
}
- impl<'walking, 'value: 'walking, 'ctx: 'value, WalkerErr, VisitorErr>
- AnyVisit<'walking, 'value, 'ctx, WalkerErr, VisitorErr>
+ impl<'walking, 'ctx>
+ AnyVisit<'walking, 'ctx>
{
- /// Erase the `P` in a visit.
+ /// Erase the `P` in a Visit.
///
- /// This allows returning a visit from a object safe method.
- pub fn new<P: Protocol<'value, 'ctx>>(
- visit: &'walking mut dyn Visit<'value, 'ctx, P, WalkerErr, Error = VisitorErr>,
+ /// This allows returning a Visit from a object safe method.
+ pub fn new<P: Protocol>(
+ visit: &'walking mut dyn Visit<'ctx, P>,
) -> Self {
Self {
- id: ProtocolId::of::<P>(),
+ id: ProtocolDescription::of::<P>(),
// SAFETY: A maybe uninit array of bytes can hold any pointer.
// Additionally, transmute makes sure the size is correct.
fat_ptr: unsafe { core::mem::transmute(visit) },
@@ -320,14 +354,14 @@ mod any_visit {
}
}
- /// Try to downcast the visit for the given protocol.
+ /// Try to downcast the Visit for the given protocol.
///
- /// If the visit is of the wrong type then `None` is returned.
- pub fn downcast<P: Protocol<'value, 'ctx>>(
+ /// If the Visit is of the wrong type then `None` is returned.
+ pub fn downcast<P: Protocol>(
self,
- ) -> Result<&'walking mut dyn Visit<'value, 'ctx, P, WalkerErr, Error = VisitorErr>, Self>
+ ) -> Result<&'walking mut dyn Visit<'ctx, P>, Self>
{
- if self.id == ProtocolId::of::<P>() {
+ if self.id.id() == ProtocolId::of::<P>() {
// SAFETY: Only `new` can make a value of this type, and it stores the ID of `P`.
// If the IDs are equal then we can act like any and downcast back to the real
// type.
@@ -339,6 +373,10 @@ mod any_visit {
Err(self)
}
}
+
+ pub fn description(&self) -> ProtocolDescription {
+ self.id
+ }
}
}
@@ -351,22 +389,16 @@ mod generic_example {
use super::{Protocol, ProtocolId};
- pub struct Generic<'walking, 'value: 'walking, 'ctx: 'value, P, WalkerErr, VisitorErr> {
+ pub struct Generic<'walking, 'ctx, P> {
id: ProtocolId,
- fat_ptr: &'walking mut dyn Hint<'value, 'ctx, P, VisitorErr, Error = WalkerErr>,
+ fat_ptr: &'walking mut dyn Hint<'ctx, P>,
}
- impl<
- 'walking,
- 'value: 'walking,
- 'ctx: 'value,
- P: Protocol<'value, 'ctx>,
- WalkerErr,
- VisitorErr,
- > Generic<'walking, 'value, 'ctx, P, WalkerErr, VisitorErr>
+ impl<'walking, 'ctx, P: Protocol>
+ Generic<'walking, 'ctx, P>
{
pub fn new(
- visit: &'walking mut dyn Hint<'value, 'ctx, P, VisitorErr, Error = WalkerErr>,
+ visit: &'walking mut dyn Hint<'ctx, P>,
) -> Self {
Self {
id: ProtocolId::of::<P>(),
@@ -376,7 +408,7 @@ mod generic_example {
pub fn downcast(
self,
- ) -> Result<&'walking mut dyn Hint<'value, 'ctx, P, VisitorErr, Error = WalkerErr>, Self>
+ ) -> Result<&'walking mut dyn Hint<'ctx, P>, Self>
{
if self.id == ProtocolId::of::<P>() {
// Notice how this is valid.
diff --git a/src/protocols.rs b/src/protocols.rs
index ba1e6ff..e5f0ae4 100644
--- a/src/protocols.rs
+++ b/src/protocols.rs
@@ -11,14 +11,54 @@ pub mod recoverable {
pub enum Recoverable {}
- impl<'value, 'ctx: 'value> Protocol<'value, 'ctx> for Recoverable {
- type Hint = ();
+ impl Protocol for Recoverable {
+ type Hint<'value, 'ctx: 'value> = ();
+
+ type Known<'value, 'ctx: 'value> = ();
+
+ type Accessor<
+ 'walking,
+ 'value: 'walking,
+ 'ctx: 'value,
+ WalkerErr: 'value,
+ VisitorErr: 'value,
+ > = &'walking mut dyn Accessor<'value, 'ctx, WalkerErr, VisitorErr>;
+ }
+}
- type Known = ();
+pub mod sequence {
+ use crate::{error::UniError, protocol::Protocol, Visitor};
- type Accessor<'walking, WalkerErr: 'value, VisitorErr: 'value> = &'walking dyn Accessor<'value, 'ctx, WalkerErr, VisitorErr>
- where
- 'value: 'walking;
+ pub struct Hint {
+ pub min_len: Option<usize>,
+ pub max_len: Option<usize>,
+ }
+
+ pub struct Known {
+ pub len: Option<usize>,
+ }
+
+ pub trait Accessor<'value, 'ctx: 'value, WalkerErr, VisitorErr> {
+ fn next(
+ &mut self,
+ visitor: &mut dyn Visitor<'value, 'ctx, WalkerErr, Error = VisitorErr>,
+ ) -> Result<(), UniError<WalkerErr, VisitorErr>>;
+ }
+
+ pub enum Sequence {}
+
+ impl Protocol for Sequence {
+ type Hint<'value, 'ctx: 'value> = Hint;
+
+ type Known<'value, 'ctx: 'value> = Known;
+
+ type Accessor<
+ 'walking,
+ 'value: 'walking,
+ 'ctx: 'value,
+ WalkerErr: 'value,
+ VisitorErr: 'value,
+ > = &'walking mut dyn Accessor<'value, 'ctx, WalkerErr, VisitorErr>;
}
}
@@ -66,13 +106,31 @@ pub mod reference {
pub struct ReferenceMut<T: ?Sized + Any>(PhantomData<fn() -> T>);
- impl<'value, 'ctx: 'value, T: ?Sized + Any> Protocol<'value, 'ctx> for Reference<T> {
- type Hint = Hint;
+ impl<T: ?Sized + Any> Protocol for Reference<T> {
+ type Hint<'value, 'ctx: 'value> = Hint;
+
+ type Known<'value, 'ctx: 'value> = Known;
+
+ type Accessor<
+ 'walking,
+ 'value: 'walking,
+ 'ctx: 'value,
+ WalkerErr: 'value,
+ VisitorErr: 'value,
+ > = Ref<'walking, 'value, 'ctx, T>;
+ }
+
+ impl<T: ?Sized + Any> Protocol for ReferenceMut<T> {
+ type Hint<'value, 'ctx: 'value> = Hint;
- type Known = Known;
+ type Known<'value, 'ctx: 'value> = Known;
- type Accessor<'walking, WalkerErr: 'value, VisitorErr: 'value> = Ref<'walking, 'value, 'ctx, T>
- where
- 'value: 'walking;
+ type Accessor<
+ 'walking,
+ 'value: 'walking,
+ 'ctx: 'value,
+ WalkerErr: 'value,
+ VisitorErr: 'value,
+ > = Mut<'walking, 'value, 'ctx, T>;
}
}
diff --git a/src/transform.rs b/src/transform.rs
index cd46681..bb2efcf 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -4,83 +4,83 @@ use crate::{
UniError, Walker,
};
-pub fn from<'value, 'ctx: 'value, U, T, VisitorErr>(
+pub fn from<'value, 'ctx, U, T>(
value: T,
-) -> Result<U, UniError<<T as WalkOnce<'value, 'ctx, VisitorErr>>::ErrorOnce, VisitorErr>>
+) -> Result<U, UniError<<T as WalkOnce<'value, 'ctx>>::Error, <U as Build<'value, 'ctx>>::Error>>
where
- U: Build<
- 'value,
- 'ctx,
- <T as WalkOnce<'value, 'ctx, VisitorErr>>::ErrorOnce,
- Error = VisitorErr,
- >,
- T: WalkOnce<'value, 'ctx, VisitorErr>,
+ U: Build<'value, 'ctx>,
+ <U as Build<'value, 'ctx>>::Error: 'value,
+ T: WalkOnce<'value, 'ctx>,
+ <T as WalkOnce<'value, 'ctx>>::Error: 'value,
{
- build_from::<U::Builder, _, _>(value)
+ build_from::<U::Builder, _>(value)
}
-pub fn from_mut<'value, 'ctx, U, T, VisitorErr>(
- value: &'value mut T,
-) -> Result<U, UniError<<T as WalkMut<'value, 'ctx, VisitorErr>>::ErrorMut, VisitorErr>>
+pub fn from_mut<'borrow, 'value, 'ctx, U, T: ?Sized>(
+ value: &'borrow mut T,
+) -> Result<
+ U,
+ UniError<<T as WalkMut<'value, 'borrow, 'ctx>>::Error, <U as Build<'value, 'ctx>>::Error>,
+>
where
- U: Build<'value, 'ctx, <T as WalkMut<'value, 'ctx, VisitorErr>>::ErrorMut, Error = VisitorErr>,
- T: WalkMut<'value, 'ctx, VisitorErr>,
+ U: Build<'value, 'ctx>,
+ <U as Build<'value, 'ctx>>::Error: 'value,
+ T: WalkMut<'value, 'borrow, 'ctx>,
+ <T as WalkMut<'value, 'borrow, 'ctx>>::Error: 'value,
{
- build_from_mut::<U::Builder, _, _>(value)
+ build_from_mut::<U::Builder, _>(value)
}
-pub fn from_ref<'value, 'ctx: 'value, U, T: ?Sized, VisitorErr>(
- value: &'value T,
-) -> Result<U, UniError<<T as Walk<'value, 'value, 'ctx, VisitorErr>>::Error, VisitorErr>>
+pub fn from_ref<'borrow, 'value, 'ctx, U, T: ?Sized>(
+ value: &'borrow T,
+) -> Result<U, UniError<<T as Walk<'value, 'borrow, 'ctx>>::Error, <U as Build<'value, 'ctx>>::Error>>
where
- U: Build<'value, 'ctx, <T as Walk<'value, 'value, 'ctx, VisitorErr>>::Error, Error = VisitorErr>,
- T: Walk<'value, 'value, 'ctx, VisitorErr>,
+ U: Build<'value, 'ctx>,
+ <U as Build<'value, 'ctx>>::Error: 'value,
+ T: Walk<'value, 'borrow, 'ctx>,
+ <T as Walk<'value, 'borrow, 'ctx>>::Error: 'value,
{
- build_from_ref::<U::Builder, _, _>(value)
+ build_from_ref::<U::Builder, _>(value)
}
-pub fn build_from<'value, 'ctx: 'value, B, T, VisitorErr>(
+pub fn build_from<'value, 'ctx, B, T>(
value: T,
-) -> Result<B::Value, UniError<<T as WalkOnce<'value, 'ctx, VisitorErr>>::ErrorOnce, VisitorErr>>
+) -> Result<B::Value, UniError<<T as WalkOnce<'value, 'ctx>>::Error, B::Error>>
where
- B: Builder<
- 'value,
- 'ctx,
- <T as WalkOnce<'value, 'ctx, VisitorErr>>::ErrorOnce,
- Error = VisitorErr,
- >,
- T: WalkOnce<'value, 'ctx, VisitorErr>,
+ B: Builder<'value, 'ctx>,
+ <B as Builder<'value, 'ctx>>::Error: 'value,
+ T: WalkOnce<'value, 'ctx>,
+ <T as WalkOnce<'value, 'ctx>>::Error: 'value,
{
let mut builder = B::init();
value.into_walker().walk(builder.as_visitor())?;
- builder.finish()
+ builder.finish().map_err(UniError::Visitor)
}
-pub fn build_from_mut<'value, 'ctx: 'value, B, T, VisitorErr>(
- value: &'value mut T,
-) -> Result<B::Value, UniError<<T as WalkMut<'value, 'ctx, VisitorErr>>::ErrorMut, VisitorErr>>
+pub fn build_from_mut<'borrow, 'value, 'ctx, B, T: ?Sized>(
+ value: &'borrow mut T,
+) -> Result<B::Value, UniError<<T as WalkMut<'value, 'borrow, 'ctx>>::Error, B::Error>>
where
- B: Builder<
- 'value,
- 'ctx,
- <T as WalkMut<'value, 'ctx, VisitorErr>>::ErrorMut,
- Error = VisitorErr,
- >,
- T: WalkMut<'value, 'ctx, VisitorErr>,
+ B: Builder<'value, 'ctx>,
+ <B as Builder<'value, 'ctx>>::Error: 'value,
+ T: WalkMut<'value, 'borrow, 'ctx>,
+ <T as WalkMut<'value, 'borrow, 'ctx>>::Error: 'value,
{
let mut builder = B::init();
value.walker_mut().walk(builder.as_visitor())?;
- builder.finish()
+ builder.finish().map_err(UniError::Visitor)
}
-pub fn build_from_ref<'value, 'ctx: 'value, B, T: ?Sized, VisitorErr>(
- value: &'value T,
-) -> Result<B::Value, UniError<<T as Walk<'value, 'value, 'ctx, VisitorErr>>::Error, VisitorErr>>
+pub fn build_from_ref<'borrow, 'value, 'ctx, B, T: ?Sized>(
+ value: &'borrow T,
+) -> Result<B::Value, UniError<<T as Walk<'value, 'borrow, 'ctx>>::Error, B::Error>>
where
- B: Builder<'value, 'ctx, <T as Walk<'value, 'value, 'ctx, VisitorErr>>::Error, Error = VisitorErr>,
- T: Walk<'value, 'value, 'ctx, VisitorErr>,
+ B: Builder<'value, 'ctx>,
+ <B as Builder<'value, 'ctx>>::Error: 'value,
+ T: Walk<'value, 'borrow, 'ctx>,
+ <T as Walk<'value, 'borrow, 'ctx>>::Error: 'value,
{
let mut builder = B::init();
value.walker().walk(builder.as_visitor())?;
- builder.finish()
+ builder.finish().map_err(UniError::Visitor)
}
diff --git a/src/walk.rs b/src/walk.rs
index 7f8c82a..d93316c 100644
--- a/src/walk.rs
+++ b/src/walk.rs
@@ -1,4 +1,4 @@
-use crate::{error::WalkerError, Walker};
+use crate::Walker;
/// A type that can be walked once.
///
@@ -9,17 +9,17 @@ use crate::{error::WalkerError, Walker};
///
/// [`WalkableOnce`], [`WalkableMut`], and [`Walkable`] form a family of traits
/// similar to the [`FnOnce`], [`FnMut`], [`Fn`] family of traits.
-pub trait WalkOnce<'value, 'ctx: 'value, VisitorErr> {
+pub trait WalkOnce<'value, 'ctx> {
/// Error the walker can return during the walk.
- type ErrorOnce: WalkerError<'value, 'ctx>;
+ type Error;
/// Walker over an instance of the type.
- type WalkerOnce: Walker<'value, 'ctx, VisitorErr, Error = Self::ErrorOnce>;
+ type Walker<VisitorErr: 'value>: Walker<'value, 'ctx, VisitorErr, Error = Self::Error>;
/// Create a walker over a value of the type.
///
/// Walking over the value is able to transfer ownership to the visitor.
- fn into_walker(self) -> Self::WalkerOnce;
+ fn into_walker<VisitorErr: 'value>(self) -> Self::Walker<VisitorErr>;
}
/// A type that can be walked using a mutable borrow.
@@ -31,40 +31,44 @@ pub trait WalkOnce<'value, 'ctx: 'value, VisitorErr> {
///
/// [`WalkableOnce`], [`WalkableMut`], and [`Walkable`] form a family of traits
/// similar to the [`FnOnce`], [`FnMut`], [`Fn`] family of traits.
-pub trait WalkMut<'value, 'ctx: 'value, VisitorErr> {
+pub trait WalkMut<'value, 'borrow, 'ctx> {
/// Error the walker can return during the walk.
- type ErrorMut: WalkerError<'value, 'ctx>;
+ type Error;
/// Walker over an instance of the type.
- type WalkerMut: Walker<'value, 'ctx, VisitorErr, Error = Self::ErrorMut>;
+ type Walker<VisitorErr: 'value>: Walker<'value, 'ctx, VisitorErr, Error = Self::Error>
+ where
+ Self: 'borrow;
- fn walker_mut(&'value mut self) -> Self::WalkerMut;
+ fn walker_mut<VisitorErr: 'value>(&'borrow mut self) -> Self::Walker<VisitorErr>;
}
/// `'borrow` is a lifetime between `'value` and `'ctx`.
/// `'borrow` is the lifetime self will be borrowed from to make the walker.
/// This allows references to raise their lifetime to `'ctx`.
-pub trait Walk<'value, 'borrow: 'value, 'ctx: 'borrow, VisitorErr> /*WalkMut<'value, 'ctx, VisitorErr>*/ {
- type Error: WalkerError<'value, 'ctx>;
- type Walker: Walker<'value, 'ctx, VisitorErr, Error = Self::Error>;
+pub trait Walk<'value, 'borrow, 'ctx> {
+ type Error;
+ type Walker<VisitorErr: 'value>: Walker<'value, 'ctx, VisitorErr, Error = Self::Error>
+ where
+ Self: 'borrow;
- fn walker(&'borrow self) -> Self::Walker;
+ fn walker<VisitorErr: 'value>(&'borrow self) -> Self::Walker<VisitorErr>;
}
-pub fn walker_once<'value, 'ctx: 'value, VisitorErr, W: WalkOnce<'value, 'ctx, VisitorErr>>(
+pub fn walker_once<'value, 'ctx, VisitorErr: 'value, W: WalkOnce<'value, 'ctx>>(
value: W,
-) -> W::WalkerOnce {
+) -> W::Walker<VisitorErr> {
value.into_walker()
}
-pub fn walker_mut<'value, 'ctx: 'value, VisitorErr, W: WalkMut<'value, 'ctx, VisitorErr>>(
- value: &'value mut W,
-) -> W::WalkerMut {
+pub fn walker_mut<'borrow, 'value, 'ctx, VisitorErr: 'value, W: WalkMut<'value, 'borrow, 'ctx>>(
+ value: &'borrow mut W,
+) -> W::Walker<VisitorErr> {
value.walker_mut()
}
-// pub fn walker<'value, 'ctx: 'value, 'root: 'ctx, VisitorErr, W: Walk<'value, 'ctx, 'root, VisitorErr>>(
-// value: &'value W,
-// ) -> W::Walker {
-// value.walker()
-// }
+pub fn walker<'borrow, 'value, 'ctx, VisitorErr: 'value, W: Walk<'value, 'borrow, 'ctx>>(
+ value: &'borrow W,
+) -> W::Walker<VisitorErr> {
+ value.walker()
+}
diff --git a/tests/demo.rs b/tests/demo.rs
index c0fe77e..263a766 100644
--- a/tests/demo.rs
+++ b/tests/demo.rs
@@ -1,24 +1,104 @@
-use uniserde::{impls::core::reference::{BuilderRefValue, BuilderRefContext}, transform::build_from_ref};
+use std::marker::PhantomData;
+
+use uniserde::{
+ build::{Build, Builder},
+ error::BasicError,
+ impls::core::{
+ iterator::IterWalker,
+ reference::{ContextLifetime, RefBuilder, RefWalker, StaticLifetime, ValueLifetime},
+ },
+ protocol::{AnyVisit, ProtocolId, Visit},
+ protocols::{reference, sequence},
+ transform::{build_from, build_from_ref},
+ Visitor, Walker,
+};
#[test]
fn demo() {
- let x = String::from("a");
- // let y: &str = build_from_ref::<'_, 'static, BuilderRefValue<str>, _, _>(&*x).unwrap();
- let y: &str = uniserde::transform::from_ref(&*x).unwrap();
- dbg!(y);
- let y: &str = example(&&&&&&&*x);
- dbg!(y);
+ let x = vec!["a", "b", "c"];
- // let y: &String = uniserde::transform::from(&*x).unwrap();
- // dbg!(y);
+ let mut w = IterWalker::new(x);
+ let mut b = VecBuilder::init();
+ w.walk(b.as_visitor()).unwrap();
+ dbg!(b.finish().unwrap());
todo!();
}
-#[no_mangle]
-pub fn example<'a>(a: &&&&&&'a str) -> &'a str {
- // uniserde::transform::from(a).unwrap()
- build_from_ref::<BuilderRefContext<str>, _, _>(a).unwrap()
+pub struct VecBuilder(Vec<&'static str>);
+
+impl<'value, 'ctx> Builder<'value, 'ctx> for VecBuilder {
+ type Error = BasicError;
+
+ type Value = Vec<&'static str>;
+
+ fn init() -> Self
+ where
+ Self: Sized,
+ {
+ Self(Vec::new())
+ }
+
+ fn as_visitor<WalkerErr: 'value>(
+ &mut self,
+ ) -> &mut dyn uniserde::Visitor<'value, 'ctx, WalkerErr, Error = Self::Error> {
+ self
+ }
+
+ fn finish(self) -> Result<Self::Value, Self::Error>
+ where
+ Self: Sized,
+ {
+ Ok(self.0)
+ }
}
-// default everything to value, have wrappers for context and static borrows
+impl<'value, 'ctx, WalkerErr> Visitor<'value, 'ctx, WalkerErr> for VecBuilder {
+ type Error = BasicError;
+
+ fn protocol(
+ &mut self,
+ id: uniserde::protocol::ProtocolId,
+ ) -> Option<uniserde::protocol::AnyProtocolVisit<'_, 'value, 'ctx, WalkerErr, Self::Error>> {
+ match id {
+ id if id == ProtocolId::of::<sequence::Sequence>() => Some(AnyVisit::new(self).erase()),
+ _ => None,
+ }
+ }
+}
+
+pub struct MapError<V, F, E>(V, F, PhantomData<fn() -> E>);
+
+impl<'value, 'ctx, V, F, E, WalkerErr> Visitor<'value, 'ctx, WalkerErr> for MapError<V, F, E>
+where
+ V: Visitor<'value, 'ctx, WalkerErr>,
+ F: Fn(V::Error) -> E,
+{
+ type Error = E;
+
+ fn protocol(
+ &mut self,
+ id: uniserde::protocol::ProtocolId,
+ ) -> Option<uniserde::protocol::AnyProtocolVisit<'_, 'value, 'ctx, WalkerErr, Self::Error>> {
+ match self.0.protocol(id) {
+ Some(visit) => Some(AnyVisit::new_with_wrapper(visit))),
+ None => todo!(),
+ }
+ }
+}
+
+impl<'value, 'ctx: 'value, WalkerErr> Visit<'value, 'ctx, sequence::Sequence, WalkerErr>
+ for VecBuilder
+{
+ type Error = BasicError;
+
+ fn visit<'walking>(
+ &'walking mut self,
+ accessor: &'walking mut dyn sequence::Accessor<'value, 'ctx, WalkerErr, Self::Error>,
+ ) -> Result<(), uniserde::error::UniError<WalkerErr, Self::Error>> {
+ let mut b = <&str as Build>::Builder::init();
+ accessor.next(&mut b)?;
+ self.0.push(b.finish().unwrap());
+ Ok(())
+ }
+}