| -rw-r--r-- | src/build.rs | 45 | ||||
| -rw-r--r-- | src/error.rs | 101 | ||||
| -rw-r--r-- | src/impls/core.rs | 1 | ||||
| -rw-r--r-- | src/impls/core/iterator.rs | 56 | ||||
| -rw-r--r-- | src/impls/core/reference.rs | 471 | ||||
| -rw-r--r-- | src/impls/core/str.rs | 133 | ||||
| -rw-r--r-- | src/lib.rs | 91 | ||||
| -rw-r--r-- | src/protocol.rs | 282 | ||||
| -rw-r--r-- | src/protocols.rs | 82 | ||||
| -rw-r--r-- | src/transform.rs | 98 | ||||
| -rw-r--r-- | src/walk.rs | 50 | ||||
| -rw-r--r-- | tests/demo.rs | 108 |
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!() -// } -// } @@ -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(()) + } +} |