rebuilt API without errors and working iterator walker
| -rw-r--r-- | src/build.rs | 23 | ||||
| -rw-r--r-- | src/error.rs | 0 | ||||
| -rw-r--r-- | src/impls/core.rs | 1 | ||||
| -rw-r--r-- | src/impls/core/iterator.rs | 75 | ||||
| -rw-r--r-- | src/impls/core/reference.rs | 429 | ||||
| -rw-r--r-- | src/impls/core/reference_mut.rs | 162 | ||||
| -rw-r--r-- | src/impls/core/str.rs | 75 | ||||
| -rw-r--r-- | src/lib.rs | 143 | ||||
| -rw-r--r-- | src/protocol.rs | 295 | ||||
| -rw-r--r-- | src/protocols.rs | 73 | ||||
| -rw-r--r-- | src/transform.rs | 97 | ||||
| -rw-r--r-- | src/walk.rs | 74 | ||||
| -rw-r--r-- | tests/demo.rs | 116 |
13 files changed, 646 insertions, 917 deletions
diff --git a/src/build.rs b/src/build.rs index d4dc676..8b34512 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1,32 +1,21 @@ use crate::Visitor; /// A type buildable from a walker. -pub trait Build<'value, 'ctx>: Sized { - type Error; - +pub trait Build<'ctx> { /// The builder that can be used to build a value. - type Builder: Builder<'value, 'ctx, Value = Self, Error = Self::Error>; + type Builder: Builder<'ctx, Value = Self>; } /// Extension to [`Visitor`] that allows constructing and finishing the visitor. -pub trait Builder<'value, 'ctx> { +pub trait Builder<'ctx>: Default { type Error; /// Type to be built. - type Value: Sized; - - /// Init a new builder. - fn init() -> Self - where - Self: Sized; + type Value; /// As a visitor. - fn as_visitor<WalkerErr: 'value>( - &mut self, - ) -> &mut dyn Visitor<'value, 'ctx, WalkerErr, Error = Self::Error>; + fn as_visitor(&mut self) -> &mut dyn Visitor<'ctx>; /// Finish the value. - fn finish(self) -> Result<Self::Value, Self::Error> - where - Self: Sized; + fn build(self) -> Result<Self::Value, Self::Error>; } diff --git a/src/error.rs b/src/error.rs deleted file mode 100644 index e69de29..0000000 --- a/src/error.rs +++ /dev/null diff --git a/src/impls/core.rs b/src/impls/core.rs index 7a918f1..303fdfd 100644 --- a/src/impls/core.rs +++ b/src/impls/core.rs @@ -1,3 +1,4 @@ pub mod iterator; pub mod reference; +pub mod reference_mut; pub mod str; diff --git a/src/impls/core/iterator.rs b/src/impls/core/iterator.rs index 713b66e..1bd39b6 100644 --- a/src/impls/core/iterator.rs +++ b/src/impls/core/iterator.rs @@ -1,56 +1,49 @@ -use core::marker::PhantomData; +use crate::{Walker, ControlFlow, walk::WalkOnce, protocol::lookup_visit, protocols::sequence}; -use crate::{ - error::UniError, protocol::ProtocolDescription, protocols::sequence, walk::WalkOnce, Fallible, - Visitor, WalkStatus, Walker, -}; +pub struct IterWalker<I> { + iter: I, +} -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<I> IterWalker<I>{ + pub fn new<T: IntoIterator<IntoIter = I>>(iter: T) -> Self { + Self { + iter: iter.into_iter() + } + } +} -impl<'value, 'ctx, I, WalkerErr, VisitorErr: 'value> - IterWalker<'value, 'ctx, I, WalkerErr, VisitorErr> +impl<'ctx, I> Walker<'ctx> for IterWalker<I> where I: Iterator, + <I as Iterator>::Item: WalkOnce<'ctx> { - 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, - ) + fn walk(&mut self, visitor: &mut dyn crate::Visitor<'ctx>) -> ControlFlow { + match lookup_visit::<sequence::Sequence, _>(visitor) { + Ok(visit) => { + visit.visit(self).to_done() + }, + Err(err) => { + ControlFlow::Error + }, + } } } -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> +impl<'ctx, I> sequence::Accessor<'ctx> for IterWalker<I> where I: Iterator, + <I as Iterator>::Item: WalkOnce<'ctx> { - 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)?; + fn next(&mut self, visitor: &mut dyn crate::Visitor<'ctx>) -> ControlFlow { + if let Some(value) = self.iter.next() { + match value.walk_once(visitor) { + Ok(_) => ControlFlow::Continue, + Err(err) => { + ControlFlow::Error + }, + } + } else { + ControlFlow::Done } - - Ok(WalkStatus::Done) } } diff --git a/src/impls/core/reference.rs b/src/impls/core/reference.rs index 69c8f08..4016a26 100644 --- a/src/impls/core/reference.rs +++ b/src/impls/core/reference.rs @@ -1,390 +1,175 @@ -use core::{any::Any, marker::PhantomData}; +use core::any::Any; use crate::{ - build::{Build, Builder}, - error::{Missing, PrimitiveTypeError, UniError}, - protocol::{lookup_visit, AnyProtocolVisit, AnyVisit, ProtocolDescription, ProtocolId, Visit}, + protocol::{lookup_visit, VisitorMissingProtocol, WalkerMissingProtocol, lookup_hint, ProtocolId, AnyVisit, Visit}, protocols::reference, - walk::{Walk, WalkMut, WalkOnce}, - Fallible, Visitor, WalkStatus, Walker, + walk::{WalkMut, WalkOnce, Walk}, + Visitor, Walker, ControlFlow, build::{Builder, Build}, }; -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 +impl<'borrow, 'ctx, T> WalkOnce<'ctx> for &'borrow T where - T: Walk<'value, 'borrow, 'ctx>, + T: Walk<'borrow, 'ctx> { type Error = T::Error; - type Walker<VisitorErr: 'value> = T::Walker<VisitorErr>; + type Value = T::Value; - fn into_walker<VisitorErr: 'value>(self) -> Self::Walker<VisitorErr> { - T::walker(self) + fn walk_once(self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + T::walk(self, visitor) } } -impl<'value, 'method: 'value, 'borrow: 'method, 'ctx: 'borrow, T: ?Sized> - WalkMut<'value, 'method, 'ctx> for &'borrow T -where - T: Walk<'value, 'borrow, 'ctx>, +impl<'borrow, 'a, 'ctx, T> WalkMut<'borrow, 'ctx> for &'a T +where + T: Walk<'a, 'ctx> { - type Error = T::Error; - - type Walker<VisitorErr: 'value> = T::Walker<VisitorErr>; - - fn walker_mut<VisitorErr: 'value>(&'method mut self) -> Self::Walker<VisitorErr> { - T::walker(self) + fn walk_mut(&'borrow mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + T::walk(self, visitor) } } -impl<'value, 'method: 'value, 'borrow: 'method, 'ctx: 'borrow, T: ?Sized> - Walk<'value, 'method, 'ctx> for &'borrow T +impl<'borrow, 'a, 'ctx, T> Walk<'borrow, 'ctx> for &'a T where - T: Walk<'value, 'borrow, 'ctx>, + T: Walk<'a, 'ctx> { - type Error = T::Error; - - type Walker<VisitorErr: 'value> = T::Walker<VisitorErr>; - - fn walker<VisitorErr: 'value>(&'method self) -> Self::Walker<VisitorErr> { - T::walker(self) + fn walk(&'borrow self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + T::walk(self, visitor) } } -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<'ctx, T: ?Sized + Any> Build<'ctx> for &'ctx T { + type Builder = RefBuilder<'ctx, 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 = T::Error; - - type Walker<VisitorErr: 'value> = T::Walker<VisitorErr>; - - fn walker_mut<VisitorErr: 'value>(&'borrow mut self) -> Self::Walker<VisitorErr> { - T::walker_mut(self) - } +pub struct RefWalker<'ctx, T: ?Sized> { + value: &'ctx T, + error: Option<VisitorMissingProtocol>, } -#[derive(thiserror::Error, Debug)] -pub enum LifetimeIsShort<'value, 'ctx, T: ?Sized> { - Walking, - Value(&'value T), - Context(&'ctx 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<LifetimeIsShort<'value, 'ctx, T>>; - - type Value = &'value T; - - fn init() -> Self - where - Self: Sized, - { - Self(None, PhantomData) +impl<'ctx, T: ?Sized> RefWalker<'ctx, T> { + pub fn new(value: &'ctx T) -> Self { + Self { + value, + error: None, + } } - fn as_visitor<WalkerErr: 'value>( - &mut self, - ) -> &mut dyn Visitor<'value, 'ctx, WalkerErr, Error = Self::Error> { - self + pub fn into_error(self) -> Option<VisitorMissingProtocol> { + self.error } +} - fn finish(self) -> Result<Self::Value, Self::Error> - where - Self: Sized, - { - if let Some(value) = self.0 { - Ok(value) - } else { - Err(Missing::Missing) +impl<'ctx:, T: ?Sized + Any> Walker<'ctx> for RefWalker<'ctx, T> { + fn walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow { + match lookup_visit::<reference::Reference<T>, _>(visitor) { + Ok(visit) => visit.visit(reference::Ref::Context(self.value)).to_done(), + Err(err) => { + self.error = Some(err); + ControlFlow::Error + }, } } } -impl<'value, 'ctx: 'value, T: ?Sized + Any, WalkerErr: 'value> Visitor<'value, 'ctx, WalkerErr> - for RefBuilder<'value, T, ValueLifetime> -{ - type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>; +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Missing value after walk.")] + MissingValue, - 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, - } - } + #[error("A value with a lifetime to short was given.")] + ShortLifetime, + + #[error(transparent)] + MissingProtocol(#[from] WalkerMissingProtocol) } -impl<'value, 'ctx: 'value, T: ?Sized + Any, WalkerErr> - Visit<'value, 'ctx, reference::Reference<T>, WalkerErr> - for RefBuilder<'value, T, ValueLifetime> -{ - type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>; +pub struct RefBuilder<'ctx, T: ?Sized> { + value: Option<Result<&'ctx T, Error>>, +} - 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) - | reference::Ref::Context(value) - | reference::Ref::Static(value) => { - self.0 = Some(value); - Ok(()) - } - } +impl<'ctx, T: ?Sized> Default for RefBuilder<'ctx, T> { + fn default() -> Self { + Self { value: None } } } -impl<'value, 'ctx: 'value, T: ?Sized + Any> Builder<'value, 'ctx> - for RefBuilder<'ctx, T, ContextLifetime> -{ - type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>; +impl<'ctx, T: ?Sized + Any> Builder<'ctx> for RefBuilder<'ctx, T> { + type Error = Error; type Value = &'ctx T; - 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> { + fn as_visitor(&mut self) -> &mut dyn Visitor<'ctx> { self } - fn finish(self) -> Result<Self::Value, Self::Error> - where - Self: Sized, - { - if let Some(value) = self.0 { - Ok(value) - } else { - Err(Missing::Missing) + fn build(self) -> Result<Self::Value, Self::Error> { + match self.value { + Some(Ok(value)) => Ok(value), + Some(Err(err)) => Err(err.into()), + None => Err(Error::MissingValue), } } } -impl<'value, 'ctx: 'value, T: ?Sized + Any, WalkerErr: 'value> Visitor<'value, 'ctx, WalkerErr> - for RefBuilder<'ctx, T, ContextLifetime> -{ - type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>; - - fn protocol( +impl<'ctx, T: ?Sized + Any> Visitor<'ctx> for RefBuilder<'ctx, T> { + fn request_hint( &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, + hints: &mut dyn crate::WalkerHints<'ctx>, + _need_hint: bool, + ) -> ControlFlow { + match lookup_hint::<reference::Reference<T>, _>(hints) { + Ok(hint) => hint.hint(self, reference::Hint { + kind: Some(reference::Kind::Context), + min_len: None, + max_len: None, + }), + Err(err) => { + self.value = Some(Err(err.into())); + ControlFlow::Error + }, } } -} -impl<'value, 'ctx: 'value, T: ?Sized + Any, WalkerErr> - Visit<'value, 'ctx, reference::Reference<T>, WalkerErr> - for RefBuilder<'ctx, T, ContextLifetime> -{ - type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>; - - 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) | reference::Ref::Static(value) => { - self.0 = Some(value); - Ok(()) - } - } - } -} - -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; - - 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) + fn protocol(&mut self, id: crate::protocol::ProtocolId) -> Option<AnyVisit<'_, 'ctx>> { + if id == ProtocolId::of::<reference::Reference<T>>() { + Some(AnyVisit::new::<reference::Reference<T>>(self)) + } else if id == ProtocolId::of::<reference::ReferenceMut<T>>() { + Some(AnyVisit::new::<reference::ReferenceMut<T>>(self)) } else { - Err(Missing::Missing) + None } } } -impl<'value, 'ctx: 'value, T: ?Sized + Any, WalkerErr: 'value> Visitor<'value, 'ctx, WalkerErr> - for RefBuilder<'static, T, StaticLifetime> -{ - type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>; - - 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, T: ?Sized + Any, WalkerErr> - Visit<'value, 'ctx, reference::Reference<T>, WalkerErr> - for RefBuilder<'static, T, StaticLifetime> -{ - type Error = Missing<LifetimeIsShort<'value, 'ctx, T>>; - - fn visit<'walking>( - &'walking mut self, - accessor: reference::Ref<'walking, 'value, 'ctx, T>, - ) -> Result<(), UniError<WalkerErr, Self::Error>> { +impl<'ctx, T: ?Sized + Any> Visit<'ctx, reference::Reference<T>> for RefBuilder<'ctx, T> { + fn visit(&mut self, accessor: reference::Ref<'_, 'ctx, T>) -> ControlFlow { 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), - ))), + self.value = Some(Err(Error::ShortLifetime)); + ControlFlow::Error + }, + reference::Ref::Context(value) | reference::Ref::Static(value) => { - self.0 = Some(value); - Ok(()) - } + self.value = Some(Ok(value)); + ControlFlow::Done + }, } } } -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>; +impl<'ctx, T: ?Sized + Any> Visit<'ctx, reference::ReferenceMut<T>> for RefBuilder<'ctx, T> { + fn visit(&mut self, accessor: reference::Mut<'_, 'ctx, T>) -> ControlFlow { + match accessor { + reference::Mut::Walking(_) => { + self.value = Some(Err(Error::ShortLifetime)); + ControlFlow::Error + }, + reference::Mut::Context(value) | + reference::Mut::Static(value) => { + self.value = Some(Ok(value)); + ControlFlow::Done + }, + } + } } diff --git a/src/impls/core/reference_mut.rs b/src/impls/core/reference_mut.rs new file mode 100644 index 0000000..5f0eff7 --- /dev/null +++ b/src/impls/core/reference_mut.rs @@ -0,0 +1,162 @@ +use core::any::Any; + +use crate::{ + protocol::{lookup_visit, VisitorMissingProtocol, WalkerMissingProtocol, lookup_hint, ProtocolId, AnyVisit, Visit}, + protocols::reference, + walk::{WalkMut, WalkOnce, Walk}, + Visitor, Walker, ControlFlow, build::{Builder, Build}, +}; + +impl<'borrow, 'ctx, T> WalkOnce<'ctx> for &'borrow mut T +where + T: WalkMut<'borrow, 'ctx> +{ + type Error = T::Error; + + type Value = T::Value; + + fn walk_once(self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + T::walk_mut(self, visitor) + } +} + +impl<'borrow, 'ctx, T> WalkMut<'borrow, 'ctx> for &'borrow mut T +where + T: WalkMut<'borrow, 'ctx> +{ + fn walk_mut(&'borrow mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + T::walk_mut(self, visitor) + } +} + +impl<'borrow, 'ctx, T> Walk<'borrow, 'ctx> for &'borrow mut T +where + T: Walk<'borrow, 'ctx> +{ + fn walk(&'borrow self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + T::walk(self, visitor) + } +} + +impl<'ctx, T: ?Sized + Any> Build<'ctx> for &'ctx mut T { + type Builder = MutBuilder<'ctx, T>; +} + +pub struct MutWalker<'ctx, T: ?Sized> { + value: Option<&'ctx mut T>, + error: Option<VisitorMissingProtocol>, +} + +impl<'ctx, T: ?Sized> MutWalker<'ctx, T> { + pub fn new(value: &'ctx mut T) -> Self { + Self { + value: Some(value), + error: None, + } + } + + pub fn into_error(self) -> Option<VisitorMissingProtocol> { + self.error + } +} + +impl<'ctx:, T: ?Sized + Any> Walker<'ctx> for MutWalker<'ctx, T> { + fn walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow { + if let Some(value) = self.value.take() { + match lookup_visit::<reference::ReferenceMut<T>, _>(visitor) { + Ok(visit) => visit.visit(reference::Mut::Context(value)).to_done(), + Err(err) => { + self.error = Some(err); + ControlFlow::Continue + }, + } + } else { + ControlFlow::Done + } + } +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Missing value after walk.")] + MissingValue, + + #[error("A value with a lifetime to short was given.")] + ShortLifetime, + + #[error(transparent)] + MissingProtocol(#[from] WalkerMissingProtocol) +} + +pub struct MutBuilder<'ctx, T: ?Sized> { + value: Option<Result<&'ctx mut T, Error>>, +} + +impl<'ctx, T: ?Sized> Default for MutBuilder<'ctx, T> { + fn default() -> Self { + Self { value: None } + } +} + +impl<'ctx, T: ?Sized + Any> Builder<'ctx> for MutBuilder<'ctx, T> { + type Error = Error; + + type Value = &'ctx mut T; + + fn as_visitor(&mut self) -> &mut dyn Visitor<'ctx> { + self + } + + fn build(self) -> Result<Self::Value, Self::Error> { + match self.value { + Some(Ok(value)) => Ok(value), + Some(Err(err)) => Err(err.into()), + None => Err(Error::MissingValue), + } + } +} + +impl<'ctx, T: ?Sized + Any> Visitor<'ctx> for MutBuilder<'ctx, T> { + fn request_hint( + &mut self, + hints: &mut dyn crate::WalkerHints<'ctx>, + _need_hint: bool, + ) -> ControlFlow { + match lookup_hint::<reference::Reference<T>, _>(hints) { + Ok(hint) => hint.hint(self, reference::Hint { + kind: Some(reference::Kind::Context), + min_len: None, + max_len: None, + }), + Err(err) => { + self.value = Some(Err(err.into())); + ControlFlow::Error + }, + } + } + + fn protocol(&mut self, id: crate::protocol::ProtocolId) -> Option<AnyVisit<'_, 'ctx>> { + if id == ProtocolId::of::<reference::ReferenceMut<T>>() { + Some(AnyVisit::new(self)) + } else { + None + } + } +} + +impl<'ctx, T: ?Sized + Any> Visit<'ctx, reference::ReferenceMut<T>> for MutBuilder<'ctx, T> { + fn visit(&mut self, accessor: reference::Mut<'_, 'ctx, T>) -> ControlFlow { + match accessor { + reference::Mut::Walking(_) => { + self.value = Some(Err(Error::ShortLifetime)); + ControlFlow::Continue + }, + reference::Mut::Context(value) | + reference::Mut::Static(value) => { + self.value = Some(Ok(value)); + ControlFlow::Done + }, + } + + } +} diff --git a/src/impls/core/str.rs b/src/impls/core/str.rs index 021fc11..e09b219 100644 --- a/src/impls/core/str.rs +++ b/src/impls/core/str.rs @@ -1,13 +1,74 @@ -use crate::{error::PrimitiveTypeError, walk::Walk}; +use crate::{walk::{Walk, WalkOnce, WalkMut}, protocol::VisitorMissingProtocol, Walker, Visitor}; -use super::reference::{RefWalker, ValueLifetime}; +use super::{reference::RefWalker, reference_mut::MutWalker}; -impl<'value, 'borrow: 'value, 'ctx: 'borrow> Walk<'value, 'borrow, 'ctx> for str { - type Error = PrimitiveTypeError; +impl<'ctx> WalkOnce<'ctx> for &'ctx str { + type Error = VisitorMissingProtocol; - type Walker<VisitorErr: 'value> = RefWalker<'borrow, str, ValueLifetime>; + type Value = (); - fn walker<VisitorErr: 'value>(&'borrow self) -> Self::Walker<VisitorErr> { - RefWalker::new(self) + #[inline] + fn walk_once(self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + self.walk(visitor) } } + +impl<'borrow, 'ctx> WalkMut<'borrow, 'ctx> for &'ctx str { + #[inline] + fn walk_mut(&'borrow mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + self.walk(visitor) + } +} + +impl<'borrow, 'ctx> Walk<'borrow, 'ctx> for &'ctx str { + #[inline] + fn walk(&'borrow self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + let mut walker = RefWalker::new(*self); + let _ = walker.walk(visitor); + match walker.into_error() { + Some(err) => Err(err), + None => Ok(()), + } + } +} + +impl<'ctx> WalkOnce<'ctx> for &'ctx mut str { + type Error = VisitorMissingProtocol; + + type Value = (); + + #[inline] + fn walk_once(self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + let mut walker = MutWalker::new(self); + let _ = walker.walk(visitor); + match walker.into_error() { + Some(err) => Err(err), + None => Ok(()), + } + } +} + +impl<'ctx> WalkMut<'ctx, 'ctx> for &'ctx mut str { + #[inline] + fn walk_mut(&'ctx mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + let mut walker = MutWalker::new(*self); + let _ = walker.walk(visitor); + match walker.into_error() { + Some(err) => Err(err), + None => Ok(()), + } + } +} + +impl<'ctx> Walk<'ctx, 'ctx> for &'ctx mut str { + #[inline] + fn walk(&'ctx self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + let mut walker = RefWalker::new(*self); + let _ = walker.walk(visitor); + match walker.into_error() { + Some(err) => Err(err), + None => Ok(()), + } + } +} + @@ -3,116 +3,101 @@ #[cfg(feature = "alloc")] extern crate alloc; -// pub mod build; -pub mod error; -// pub mod impls; +pub mod build; +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 protocol::{AnyHint, Hint, ProtocolId, Visit, AnyVisit}; +use protocol::{AnyHint, AnyVisit, Hint, ProtocolId, Visit}; -// pub use buildable::Buildable; -// pub use walkable::{Walkable, WalkableMut, WalkableRef}; - -/// Status of a walker after walking using a visitor. +/// Signal to a walker or visitor that it should exit early or continue. /// -/// Some walkers can be walked multiple times to extract multiple -/// values. -pub enum WalkStatus { - /// The walker is done. - /// - /// Attemping to call `walk` is likely to result in an error. - Done, +/// [`Walker`] and [`Visitor`] can't signal an error condition with a +/// [`Result`] so instead they can use this. +#[must_use] +#[derive(Copy, Clone, Debug)] +pub enum ControlFlow { + /// Continue the walk as normal. + Continue, - /// The walker has more values to walk. - More, - - /// The walker will repeat values. - Repeat, + Done, Error, } -/// Walker over a value with lifetime `'value`. -pub trait Walker<'ctx> { - /// Walk the walker over the value. - /// - /// This is the main entrypoint for walking a value. - /// The walker should call [`Visit::visit`] on the provided visitor as it walks. - /// - /// The default impl calls [`Visitor::request_hint`] then returns an error if no hint - /// was given. Self describing formats can replace the default impl to fall back to - /// their own logic if no hint is given. It is recommended to keep the call to - /// [`Visitor::request_hint`] before using walker specific logic to pick a protocol. - fn walk( - &mut self, - visitor: &mut dyn Visitor<'ctx>, - ) -> WalkStatus; -} +impl ControlFlow { + pub fn to_done(self) -> Self { + match self { + ControlFlow::Continue => ControlFlow::Done, + ControlFlow::Done => ControlFlow::Done, + ControlFlow::Error => ControlFlow::Error, + } + } -pub trait ErrorNeedsHint { - fn error_needs_hint(&mut self); + pub fn to_continue(self) -> Self { + match self { + ControlFlow::Continue => ControlFlow::Continue, + ControlFlow::Done => ControlFlow::Continue, + ControlFlow::Error => ControlFlow::Error, + } + } } -pub fn walk_with_hints<'ctx, H: WalkerHints<'ctx>>( - hints: &mut H, - visitor: &mut dyn Visitor<'ctx>, -) -> WalkStatus -where - H: ErrorNeedsHint, -{ - // Request that the visitor give us a hint of what protocol to use. - match visitor.request_hint(hints, true) { - Some(status) => status, - None => { - hints.error_needs_hint(); - WalkStatus::Error - }, - } +/// Walker over a value. +/// +/// The walker can give out borrows with a lifetime of `'ctx` to the visitor. +pub trait Walker<'ctx> { + /// Walk the value. + /// + /// The walker will call [`Visit::visit`] methods for one or more + /// [`Protocol`][protocol::Protocol] on the given `visitor`. + fn walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow; } /// Hint lookup for a walker. +/// +/// Some walkers may need a hint for what the value it's walking actually is. +/// To support this, a [`Walker`] will call the visitor's [`Visitor::request_hint`] +/// method and the visitor can call a [`Hint::hint`] method for a +/// [`Protocol`][protocol::Protocol] that the walker supports. pub trait WalkerHints<'ctx> { /// Query the walker for a given protocol. /// /// If the walker doesn't support the protocol then a `None` is returned. - /// Note, a walker can return `None` if it can't handle a hint of the protocol for the given - /// value. - fn protocol( - &mut self, - id: ProtocolId, - ) -> Option<AnyHint<'_, 'ctx>>; + /// Note, a walker may return a `None` for a particular value but support + /// the protocol for other values. + /// + /// Use [`lookup_hint`][protocol::lookup_hint], or manually call + /// [`AnyHint::downcast`] on the returned value to access the [`Hint`]. + fn protocol(&mut self, id: ProtocolId) -> Option<AnyHint<'_, 'ctx>>; } /// Visitor over a value to be built. 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. - /// Calling this method when already processing a hint can cause a infinite loop. + /// Request the visitor provide a hint for what protocol to use. /// - /// The visitor will hint the protocol by calling the [`Hint::hint`] method on the - /// the walker's returned hint instance for the protocol. + /// Some walkers may need a hint for what the value it's walking actually is. + /// To support this, a [`Walker`] will call this method + /// and the visitor can call a [`Hint::hint`] method for a + /// [`Protocol`][protocol::Protocol] that the walker supports. /// - /// A return value of `Ok(None)` means no hint was given to the walker. + /// Returning a `None` means the visitor gave no hint. The `need_hint` will + /// be `true` if the walker needs a hint to not encounter an error. fn request_hint( &mut self, hints: &mut dyn WalkerHints<'ctx>, need_hint: bool, - ) -> Option<WalkStatus> { - let _ = hints; - let _ = need_hint; - None - } + ) -> ControlFlow; /// Query the visitor for a given protocol. /// /// If the visitor doesn't support the protocol then a `None` is returned. - fn protocol( - &mut self, - id: ProtocolId, - ) -> Option<AnyVisit<'_, 'ctx>>; + /// Note, a visitor may return a `None` if it doesn't support the protocol + /// for it's current internal state but could otherwise. + /// + /// Use [`lookup_visit`][protocol::lookup_visit], or manually call + /// [`AnyVisit::downcast`] on the returned value to access the [`Visit`]. + fn protocol(&mut self, id: ProtocolId) -> Option<AnyVisit<'_, 'ctx>>; } diff --git a/src/protocol.rs b/src/protocol.rs index a74e791..617cc4d 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -1,10 +1,10 @@ -use core::any::Any; +use core::any::{type_name, Any}; pub use any_hint::AnyHint; pub use any_visit::AnyVisit; pub use id::ProtocolId; -use crate::{Visitor, WalkerHints, WalkStatus}; +use crate::{ControlFlow, Visitor, WalkerHints}; /// A protocol between a walker and visitor. /// @@ -38,62 +38,15 @@ pub trait Protocol: Any { type Accessor<'walking, 'ctx: 'walking>; } -#[derive(Copy, Clone)] -pub struct ProtocolDescription { - id: fn() -> ProtocolId, - name: fn() -> &'static str, -} - -impl ProtocolDescription { - pub const fn of<P: Protocol>() -> Self { - Self { - id: || ProtocolId::of::<P>(), - name: || core::any::type_name::<P>(), - } - } - - pub fn id(&self) -> ProtocolId { - (self.id)() - } - - pub fn name(&self) -> &'static str { - (self.name)() - } - -} - -impl core::fmt::Display for ProtocolDescription { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.name()) - } -} - -impl core::fmt::Debug for ProtocolDescription { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("ProtocolDescription") - .field("id", &self.id()) - .field("name", &self.name()) - .finish() - } -} - -pub type HintOps<'walking, 'ctx, P> = - &'walking mut dyn Hint<'ctx, P>; - -pub type VisitOps<'walking, 'ctx, P> = - &'walking mut dyn Visit<'ctx, P>; - /// Protocol specific hint for a walker. +/// +/// A walker can implement any number of these for any protocols it supports. 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<'ctx>, - hint: P::Hint<'ctx>, - ) -> WalkStatus; + fn hint(&mut self, visitor: &mut dyn Visitor<'ctx>, hint: P::Hint<'ctx>) -> ControlFlow; /// Any information the walker has for the protocol. /// @@ -103,123 +56,96 @@ pub trait Hint<'ctx, P: Protocol> { /// /// Most protocols will allow returning a value representing no knowledge is known by the /// walker. - fn known( - &mut self, - hint: &P::Hint<'ctx>, - ) -> P::Known<'ctx>; + fn known(&mut self, hint: &P::Hint<'ctx>) -> P::Known<'ctx>; } /// Protocol specific visit for a visitor. +/// +/// A visitor can implement any number of these for any protocols it supports. pub trait Visit<'ctx, P: Protocol> { /// Visit a value from the walker. - fn visit<'walking>( - &'walking mut self, - accessor: P::Accessor<'walking, 'ctx>, - ); + /// + /// The `accessor` will either be a concrete value or another walker. + /// This is dependant on the protocol `P`. The visitor can do whatever it wants + /// with the `accessor` during the function call. + fn visit(&mut self, accessor: P::Accessor<'_, 'ctx>) -> ControlFlow; } -pub trait ErrorWrongProtocol { - fn error_wrong_protocol<Expected: Protocol>(&mut self, got: ProtocolDescription); +#[derive(thiserror::Error, Debug)] +#[error("Expected Hint to be for `{expected}` but got one for `{got}`.")] +pub struct WalkerWrongProtocol { + pub got: &'static str, + pub expected: &'static str, } -pub trait ErrorMissingProtocol { - fn error_missing_protocol<P: Protocol>(&mut self); +#[derive(thiserror::Error, Debug)] +pub enum WalkerMissingProtocol { + #[error("Walker doesn't support the protocol `{0}`.")] + Missing(&'static str), + + #[error(transparent)] + Wrong(#[from] WalkerWrongProtocol), } -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, - } +#[derive(thiserror::Error, Debug)] +#[error("Expected Visit to be for `{expected}` but got one for `{got}`.")] +pub struct VisitorWrongProtocol { + pub got: &'static str, + pub expected: &'static str, } -pub fn lookup_hint< - 'a, - 'ctx, - P: Protocol, - E: ErrorWrongProtocol + ErrorMissingProtocol, - H: ?Sized + WalkerHints<'ctx>, ->( - hints: &'a mut H, - error_report: &mut E, -) -> Option<HintOps<'a, 'ctx, P>> { +#[derive(thiserror::Error, Debug)] +pub enum VisitorMissingProtocol { + #[error("Visitor doesn't support the protocol `{0}`.")] + Missing(&'static str), + + #[error(transparent)] + Wrong(#[from] VisitorWrongProtocol), +} + +/// Try to lookup a [`Hint`] on a walker. +pub fn try_lookup_hint<'ctx, P: Protocol, H: ?Sized + WalkerHints<'ctx>>( + hints: &mut H, +) -> Result<Option<&mut dyn Hint<'ctx, P>>, WalkerWrongProtocol> { 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 => { - error_report.error_missing_protocol::<P>(); - None + Ok(hint) => Ok(Some(hint)), + Err(hint) => Err(WalkerWrongProtocol { + got: hint.protocol_type_name(), + expected: type_name::<P>(), + }), }, + None => Ok(None), } } -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_hint<'ctx, P: Protocol, H: ?Sized + WalkerHints<'ctx>>( + hints: &mut H, +) -> Result<&mut dyn Hint<'ctx, P>, WalkerMissingProtocol> { + try_lookup_hint(hints)?.ok_or(WalkerMissingProtocol::Missing(type_name::<P>())) } -pub fn lookup_visit< - 'a, - 'ctx, - P: Protocol, - E: ErrorWrongProtocol + ErrorMissingProtocol, - V: ?Sized + Visitor<'ctx>, ->( - visitor: &'a mut V, - error_report: &mut E, -) -> Option<VisitOps<'a, 'ctx, P>> { +pub fn try_lookup_visit<'ctx, P: Protocol, V: ?Sized + Visitor<'ctx>>( + visitor: &mut V, +) -> Result<Option<&mut dyn Visit<'ctx, P>>, VisitorWrongProtocol> { 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 => { - error_report.error_missing_protocol::<P>(); - None + Ok(visit) => Ok(Some(visit)), + Err(visit) => Err(VisitorWrongProtocol { + got: visit.protocol_type_name(), + expected: type_name::<P>(), + }), }, + None => Ok(None), } } +pub fn lookup_visit<'ctx, P: Protocol, V: ?Sized + Visitor<'ctx>>( + visitor: &mut V, +) -> Result<&mut dyn Visit<'ctx, P>, VisitorMissingProtocol> { + try_lookup_visit(visitor)?.ok_or(VisitorMissingProtocol::Missing(type_name::<P>())) +} + mod id { use super::Protocol; use core::any::TypeId; @@ -241,23 +167,27 @@ mod id { } mod any_hint { - use core::{any::Any, marker::PhantomData, mem::MaybeUninit}; + use core::{ + any::{type_name, Any}, + marker::PhantomData, + mem::MaybeUninit, + }; use crate::Hint; - use super::{Protocol, ProtocolDescription, ProtocolId}; + use super::{Protocol, ProtocolId}; /// Form of `Hint` without `P`. 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>>(); + const DYN_PTR_SIZE: usize = 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, 'ctx> { /// ID of `P`. - id: ProtocolDescription, + id: ProtocolId, + name: &'static str, /// This field stores a `&'walking mut dyn Hint<'value, P, Err>`. fat_ptr: MaybeUninit<[u8; DYN_PTR_SIZE]>, @@ -266,17 +196,14 @@ mod any_hint { _marker: PhantomData<&'walking mut dyn ErasedHint<'ctx>>, } - impl<'walking, 'ctx> - AnyHint<'walking, 'ctx> - { + 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>( - visit: &'walking mut dyn Hint<'ctx, P>, - ) -> Self { + pub fn new<P: Protocol>(visit: &'walking mut dyn Hint<'ctx, P>) -> Self { Self { - id: ProtocolDescription::of::<P>(), + id: ProtocolId::of::<P>(), + name: type_name::<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) }, @@ -287,11 +214,8 @@ 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>( - self, - ) -> Result<&'walking mut dyn Hint<'ctx, P>, Self> - { - if self.id.id() == ProtocolId::of::<P>() { + pub fn downcast<P: Protocol>(self) -> Result<&'walking mut dyn Hint<'ctx, P>, Self> { + if self.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. @@ -304,30 +228,34 @@ mod any_hint { } } - pub fn description(&self) -> ProtocolDescription { - self.id + pub fn protocol_type_name(&self) -> &'static str { + self.name } } } mod any_visit { - use core::{any::Any, marker::PhantomData, mem::MaybeUninit}; + use core::{ + any::{type_name, Any}, + marker::PhantomData, + mem::MaybeUninit, + }; use crate::Visit; - use super::{Protocol, ProtocolDescription, ProtocolId}; + use super::{Protocol, ProtocolId}; /// Form of `Visit` without `P`. 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>>(); + const DYN_PTR_SIZE: usize = 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, 'ctx> { /// ID of `P`. - id: ProtocolDescription, + id: ProtocolId, + name: &'static str, /// This field stores a `&'walking mut dyn Visit<'value, P, Err>`. fat_ptr: MaybeUninit<[u8; DYN_PTR_SIZE]>, @@ -336,17 +264,14 @@ mod any_visit { _marker: PhantomData<&'walking mut dyn ErasedVisit<'ctx>>, } - impl<'walking, 'ctx> - AnyVisit<'walking, 'ctx> - { + impl<'walking, 'ctx> AnyVisit<'walking, 'ctx> { /// Erase the `P` in a Visit. /// /// This allows returning a Visit from a object safe method. - pub fn new<P: Protocol>( - visit: &'walking mut dyn Visit<'ctx, P>, - ) -> Self { + pub fn new<P: Protocol>(visit: &'walking mut dyn Visit<'ctx, P>) -> Self { Self { - id: ProtocolDescription::of::<P>(), + id: ProtocolId::of::<P>(), + name: type_name::<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) }, @@ -357,11 +282,8 @@ mod any_visit { /// 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>( - self, - ) -> Result<&'walking mut dyn Visit<'ctx, P>, Self> - { - if self.id.id() == ProtocolId::of::<P>() { + pub fn downcast<P: Protocol>(self) -> Result<&'walking mut dyn Visit<'ctx, P>, Self> { + if self.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. @@ -374,8 +296,8 @@ mod any_visit { } } - pub fn description(&self) -> ProtocolDescription { - self.id + pub fn protocol_type_name(&self) -> &'static str { + self.name } } } @@ -394,22 +316,15 @@ mod generic_example { fat_ptr: &'walking mut dyn Hint<'ctx, P>, } - impl<'walking, 'ctx, P: Protocol> - Generic<'walking, 'ctx, P> - { - pub fn new( - visit: &'walking mut dyn Hint<'ctx, P>, - ) -> Self { + impl<'walking, 'ctx, P: Protocol> Generic<'walking, 'ctx, P> { + pub fn new(visit: &'walking mut dyn Hint<'ctx, P>) -> Self { Self { id: ProtocolId::of::<P>(), fat_ptr: visit, } } - pub fn downcast( - self, - ) -> Result<&'walking mut dyn Hint<'ctx, P>, Self> - { + pub fn downcast(self) -> Result<&'walking mut dyn Hint<'ctx, P>, Self> { if self.id == ProtocolId::of::<P>() { // Notice how this is valid. Ok(self.fat_ptr) diff --git a/src/protocols.rs b/src/protocols.rs index e5f0ae4..cd0164e 100644 --- a/src/protocols.rs +++ b/src/protocols.rs @@ -1,33 +1,24 @@ pub mod recoverable { - use crate::{error::UniError, protocol::Protocol, Visitor}; + use crate::{protocol::Protocol, ControlFlow, Visitor}; - pub trait Accessor<'value, 'ctx: 'value, WalkerErr, VisitorErr> { + pub trait Accessor<'ctx> { /// Each time this is called the walker resets. - fn walk_new( - &mut self, - visitor: &mut dyn Visitor<'value, 'ctx, WalkerErr, Error = VisitorErr>, - ) -> Result<(), UniError<WalkerErr, VisitorErr>>; + fn new_walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow; } pub enum Recoverable {} impl Protocol for Recoverable { - type Hint<'value, 'ctx: 'value> = (); + type Hint<'ctx> = (); - type Known<'value, 'ctx: 'value> = (); + type Known<'ctx> = (); - type Accessor< - 'walking, - 'value: 'walking, - 'ctx: 'value, - WalkerErr: 'value, - VisitorErr: 'value, - > = &'walking mut dyn Accessor<'value, 'ctx, WalkerErr, VisitorErr>; + type Accessor<'walking, 'ctx: 'walking> = &'walking mut dyn Accessor<'ctx>; } } pub mod sequence { - use crate::{error::UniError, protocol::Protocol, Visitor}; + use crate::{protocol::Protocol, ControlFlow, Visitor}; pub struct Hint { pub min_len: Option<usize>, @@ -38,27 +29,18 @@ pub mod sequence { 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 trait Accessor<'ctx> { + fn next(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow; } pub enum Sequence {} impl Protocol for Sequence { - type Hint<'value, 'ctx: 'value> = Hint; + type Hint<'ctx> = Hint; - type Known<'value, 'ctx: 'value> = Known; + type Known<'ctx> = Known; - type Accessor< - 'walking, - 'value: 'walking, - 'ctx: 'value, - WalkerErr: 'value, - VisitorErr: 'value, - > = &'walking mut dyn Accessor<'value, 'ctx, WalkerErr, VisitorErr>; + type Accessor<'walking, 'ctx: 'walking> = &'walking mut dyn Accessor<'ctx>; } } @@ -69,7 +51,6 @@ pub mod reference { pub enum Kind { Walking, - Value, Context, Static, } @@ -88,16 +69,14 @@ pub mod reference { pub len: Option<usize>, } - pub enum Ref<'walking, 'value: 'walking, 'ctx: 'value, T: ?Sized + 'static> { + pub enum Ref<'walking, 'ctx, T: ?Sized + Any> { Walking(&'walking T), - Value(&'value T), Context(&'ctx T), Static(&'static T), } - pub enum Mut<'walking, 'value: 'walking, 'ctx: 'value, T: ?Sized + 'static> { + pub enum Mut<'walking, 'ctx, T: ?Sized + Any> { Walking(&'walking mut T), - Value(&'value mut T), Context(&'ctx mut T), Static(&'static mut T), } @@ -107,30 +86,18 @@ pub mod reference { pub struct ReferenceMut<T: ?Sized + Any>(PhantomData<fn() -> T>); impl<T: ?Sized + Any> Protocol for Reference<T> { - type Hint<'value, 'ctx: 'value> = Hint; + type Hint<'ctx> = Hint; - type Known<'value, 'ctx: 'value> = Known; + type Known<'ctx> = Known; - type Accessor< - 'walking, - 'value: 'walking, - 'ctx: 'value, - WalkerErr: 'value, - VisitorErr: 'value, - > = Ref<'walking, 'value, 'ctx, T>; + type Accessor<'walking, 'ctx: 'walking> = Ref<'walking, 'ctx, T>; } impl<T: ?Sized + Any> Protocol for ReferenceMut<T> { - type Hint<'value, 'ctx: 'value> = Hint; + type Hint<'ctx> = Hint; - type Known<'value, 'ctx: 'value> = Known; + type Known<'ctx> = Known; - type Accessor< - 'walking, - 'value: 'walking, - 'ctx: 'value, - WalkerErr: 'value, - VisitorErr: 'value, - > = Mut<'walking, 'value, 'ctx, T>; + type Accessor<'walking, 'ctx: 'walking> = Mut<'walking, 'ctx, T>; } } diff --git a/src/transform.rs b/src/transform.rs index bb2efcf..2999ad7 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -1,86 +1,49 @@ use crate::{ build::{Build, Builder}, - walk::{Walk, WalkMut, WalkOnce}, - UniError, Walker, + walk::{WalkOnce, WalkMut, Walk}, }; -pub fn from<'value, 'ctx, U, T>( - value: T, -) -> Result<U, UniError<<T as WalkOnce<'value, 'ctx>>::Error, <U as Build<'value, 'ctx>>::Error>> -where - 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) -} - -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>, - <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) -} +#[derive(thiserror::Error, Debug)] +pub enum Either<A, B> { + #[error(transparent)] + A(A), -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>, - <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) + #[error(transparent)] + B(B), } -pub fn build_from<'value, 'ctx, B, T>( +pub fn from<'ctx, U, T>( value: T, -) -> Result<B::Value, UniError<<T as WalkOnce<'value, 'ctx>>::Error, B::Error>> +) -> Result<U, Either<T::Error, <U::Builder as Builder<'ctx>>::Error>> where - B: Builder<'value, 'ctx>, - <B as Builder<'value, 'ctx>>::Error: 'value, - T: WalkOnce<'value, 'ctx>, - <T as WalkOnce<'value, 'ctx>>::Error: 'value, + T: WalkOnce<'ctx>, + U: Build<'ctx>, { - let mut builder = B::init(); - value.into_walker().walk(builder.as_visitor())?; - builder.finish().map_err(UniError::Visitor) + let mut builder = U::Builder::default(); + value.walk_once(builder.as_visitor()).map_err(Either::A)?; + builder.build().map_err(Either::B) } -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>> +pub fn from_mut<'a, 'ctx, U, T>( + value: &'a mut T, +) -> Result<U, Either<T::Error, <U::Builder as Builder<'ctx>>::Error>> where - B: Builder<'value, 'ctx>, - <B as Builder<'value, 'ctx>>::Error: 'value, - T: WalkMut<'value, 'borrow, 'ctx>, - <T as WalkMut<'value, 'borrow, 'ctx>>::Error: 'value, + T: WalkMut<'a, 'ctx>, + U: Build<'ctx>, { - let mut builder = B::init(); - value.walker_mut().walk(builder.as_visitor())?; - builder.finish().map_err(UniError::Visitor) + let mut builder = U::Builder::default(); + value.walk_mut(builder.as_visitor()).map_err(Either::A)?; + builder.build().map_err(Either::B) } -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>> +pub fn from_ref<'a, 'ctx, U, T>( + value: &'a T, +) -> Result<U, Either<T::Error, <U::Builder as Builder<'ctx>>::Error>> where - B: Builder<'value, 'ctx>, - <B as Builder<'value, 'ctx>>::Error: 'value, - T: Walk<'value, 'borrow, 'ctx>, - <T as Walk<'value, 'borrow, 'ctx>>::Error: 'value, + T: Walk<'a, 'ctx>, + U: Build<'ctx>, { - let mut builder = B::init(); - value.walker().walk(builder.as_visitor())?; - builder.finish().map_err(UniError::Visitor) + let mut builder = U::Builder::default(); + value.walk(builder.as_visitor()).map_err(Either::A)?; + builder.build().map_err(Either::B) } diff --git a/src/walk.rs b/src/walk.rs index d93316c..7b2ddc1 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -1,74 +1,16 @@ -use crate::Walker; +use crate::Visitor; -/// A type that can be walked once. -/// -/// A walkable type has one canonical walker type, but other walkers -/// can operate on the same walkable type. This trait gives the canonical -/// walker for an owned instance of the value. The `'value` lifetime -/// is the lifetime of the value itself. -/// -/// [`WalkableOnce`], [`WalkableMut`], and [`Walkable`] form a family of traits -/// similar to the [`FnOnce`], [`FnMut`], [`Fn`] family of traits. -pub trait WalkOnce<'value, 'ctx> { - /// Error the walker can return during the walk. +pub trait WalkOnce<'ctx> { type Error; + type Value; - /// Walker over an instance of the type. - 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<VisitorErr: 'value>(self) -> Self::Walker<VisitorErr>; -} - -/// A type that can be walked using a mutable borrow. -/// -/// This trait gives the canonical walker for a mutably borrowed -/// instance of the value. The `'value` lifetime is the lifetime of -/// the value itself. The `'walking` lifetime can be used by -/// [`Self::ErrorMut`] to reference the value using the passed mutable borrow. -/// -/// [`WalkableOnce`], [`WalkableMut`], and [`Walkable`] form a family of traits -/// similar to the [`FnOnce`], [`FnMut`], [`Fn`] family of traits. -pub trait WalkMut<'value, 'borrow, 'ctx> { - /// Error the walker can return during the walk. - type Error; - - /// Walker over an instance of the type. - type Walker<VisitorErr: 'value>: Walker<'value, 'ctx, VisitorErr, Error = Self::Error> - where - Self: 'borrow; - - 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, 'ctx> { - type Error; - type Walker<VisitorErr: 'value>: Walker<'value, 'ctx, VisitorErr, Error = Self::Error> - where - Self: 'borrow; - - fn walker<VisitorErr: 'value>(&'borrow self) -> Self::Walker<VisitorErr>; -} - -pub fn walker_once<'value, 'ctx, VisitorErr: 'value, W: WalkOnce<'value, 'ctx>>( - value: W, -) -> W::Walker<VisitorErr> { - value.into_walker() + fn walk_once(self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error>; } -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 trait WalkMut<'borrow, 'ctx>: WalkOnce<'ctx> { + fn walk_mut(&'borrow mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error>; } -pub fn walker<'borrow, 'value, 'ctx, VisitorErr: 'value, W: Walk<'value, 'borrow, 'ctx>>( - value: &'borrow W, -) -> W::Walker<VisitorErr> { - value.walker() +pub trait Walk<'borrow, 'ctx>: WalkMut<'borrow, 'ctx> { + fn walk(&'borrow self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error>; } diff --git a/tests/demo.rs b/tests/demo.rs index 263a766..81b4875 100644 --- a/tests/demo.rs +++ b/tests/demo.rs @@ -1,104 +1,70 @@ -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, -}; +use uniserde::{transform::from, build::{Builder, Build}, Visitor, ControlFlow, protocol::{ProtocolId, AnyVisit, Visit}, protocols::sequence, impls::core::iterator::IterWalker, Walker}; #[test] fn demo() { - let x = vec!["a", "b", "c"]; + let x = ["1", "2", "3"]; - let mut w = IterWalker::new(x); - let mut b = VecBuilder::init(); - w.walk(b.as_visitor()).unwrap(); - dbg!(b.finish().unwrap()); + let mut builder = VecBuilder::default(); + IterWalker::new(x.iter()).walk(builder.as_visitor()); + dbg!(builder.build()); todo!(); } +#[no_mangle] +pub fn example<'a>(x: &'a str) -> &'a str { + from(x).unwrap() +} + +#[derive(Default)] pub struct VecBuilder(Vec<&'static str>); -impl<'value, 'ctx> Builder<'value, 'ctx> for VecBuilder { - type Error = BasicError; +impl Builder<'static> for VecBuilder { + type Error = (); 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> { + fn as_visitor(&mut self) -> &mut dyn uniserde::Visitor<'static> { self } - fn finish(self) -> Result<Self::Value, Self::Error> - where - Self: Sized, - { + fn build(self) -> Result<Self::Value, Self::Error> { Ok(self.0) } } -impl<'value, 'ctx, WalkerErr> Visitor<'value, 'ctx, WalkerErr> for VecBuilder { - type Error = BasicError; - - fn protocol( +impl Visitor<'static> for VecBuilder { + fn request_hint( &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, - } + _hints: &mut dyn uniserde::WalkerHints<'static>, + _need_hint: bool, + ) -> uniserde::ControlFlow { + ControlFlow::Continue } -} - -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!(), + fn protocol(&mut self, id: uniserde::protocol::ProtocolId) -> Option<uniserde::protocol::AnyVisit<'_, 'static>> { + if id == ProtocolId::of::<sequence::Sequence>() { + Some(AnyVisit::new(self)) + } else { + None } } } -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(()) +impl Visit<'static, sequence::Sequence> for VecBuilder { + fn visit(&mut self, accessor: <sequence::Sequence as uniserde::protocol::Protocol>::Accessor<'_, 'static>) -> ControlFlow { + loop { + let mut builder = <&'static str as Build<'static>>::Builder::default(); + match accessor.next(builder.as_visitor()) { + ControlFlow::Continue => {}, + ControlFlow::Done => {}, + ControlFlow::Error => break ControlFlow::Error, + } + + match builder.build() { + Ok(value) => self.0.push(value), + Err(err) => break ControlFlow::Error, + } + } } } |