simplified API
| -rw-r--r-- | src/build.rs | 4 | ||||
| -rw-r--r-- | src/impls/core.rs | 7 | ||||
| -rw-r--r-- | src/impls/core/bool.rs | 61 | ||||
| -rw-r--r-- | src/impls/core/iterator.rs | 73 | ||||
| -rw-r--r-- | src/impls/core/reference.rs | 139 | ||||
| -rw-r--r-- | src/impls/core/reference_mut.rs | 82 | ||||
| -rw-r--r-- | src/impls/core/str.rs | 45 | ||||
| -rw-r--r-- | src/lib.rs | 100 | ||||
| -rw-r--r-- | src/protocol.rs | 341 | ||||
| -rw-r--r-- | src/protocols.rs | 611 | ||||
| -rw-r--r-- | src/transform.rs | 2 | ||||
| -rw-r--r-- | src/walk.rs | 12 | ||||
| -rw-r--r-- | tests/demo.rs | 77 |
13 files changed, 982 insertions, 572 deletions
diff --git a/src/build.rs b/src/build.rs index 8b34512..1c28354 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1,4 +1,4 @@ -use crate::Visitor; +use crate::protocol::Implementer; /// A type buildable from a walker. pub trait Build<'ctx> { @@ -14,7 +14,7 @@ pub trait Builder<'ctx>: Default { type Value; /// As a visitor. - fn as_visitor(&mut self) -> &mut dyn Visitor<'ctx>; + fn as_visitor(&mut self) -> &mut dyn Implementer<'ctx>; /// Finish the value. fn build(self) -> Result<Self::Value, Self::Error>; diff --git a/src/impls/core.rs b/src/impls/core.rs index 303fdfd..3cab3a0 100644 --- a/src/impls/core.rs +++ b/src/impls/core.rs @@ -1,4 +1,5 @@ +pub mod bool; pub mod iterator; -pub mod reference; -pub mod reference_mut; -pub mod str; +// pub mod reference; +// pub mod reference_mut; +// pub mod str; diff --git a/src/impls/core/bool.rs b/src/impls/core/bool.rs new file mode 100644 index 0000000..2e3aba9 --- /dev/null +++ b/src/impls/core/bool.rs @@ -0,0 +1,61 @@ +use crate::{ + build::{Build, Builder}, + implementer, + protocol::{ImplementerExt, Implementer}, + protocols::{bool, ControlFlow}, + walk::WalkOnce, +}; + +#[derive(thiserror::Error, Debug)] +#[error("The value is complete.")] +pub struct IncompleteValue; + +#[derive(Default)] +pub struct BoolBuilder(Option<bool>); + +impl<'ctx> Build<'ctx> for bool { + type Builder = BoolBuilder; +} + +impl<'ctx> Builder<'ctx> for BoolBuilder { + type Error = IncompleteValue; + + type Value = bool; + + fn as_visitor(&mut self) -> &mut dyn crate::protocol::Implementer<'ctx> { + self + } + + fn build(self) -> Result<Self::Value, Self::Error> { + match self.0 { + Some(value) => Ok(value), + None => Err(IncompleteValue), + } + } +} + +implementer! { + impl['ctx] BoolBuilder = [bool::Bool]; +} + +impl<'ctx> bool::Object<'ctx> for BoolBuilder { + fn visit(&mut self, value: bool) -> crate::protocols::ControlFlow { + self.0 = Some(value); + ControlFlow::Done + } +} + +impl<'ctx> WalkOnce<'ctx> for bool { + type Error = (); + + type Value = (); + + #[inline] + fn walk_once(self, visitor: &mut dyn Implementer<'ctx>) -> Result<Self::Value, Self::Error> { + if let Some(interface) = visitor.interface_for::<bool::Bool>() { + interface.as_object().visit(self); + } + + Ok(()) + } +} diff --git a/src/impls/core/iterator.rs b/src/impls/core/iterator.rs index 1bd39b6..cdcd71b 100644 --- a/src/impls/core/iterator.rs +++ b/src/impls/core/iterator.rs @@ -1,49 +1,76 @@ -use crate::{Walker, ControlFlow, walk::WalkOnce, protocol::lookup_visit, protocols::sequence}; +use crate::protocol::ImplementerExt; +use crate::protocols::{sequence, ControlFlow}; +use crate::walk::WalkOnce; -pub struct IterWalker<I> { +pub struct IterWalker<'ctx, I> +where + I: Iterator, + <I as Iterator>::Item: WalkOnce<'ctx>, +{ iter: I, + err: Option<<<I as Iterator>::Item as WalkOnce<'ctx>>::Error>, } -impl<I> IterWalker<I>{ +impl<'ctx, I> IterWalker<'ctx, I> +where + I: Iterator, + <I as Iterator>::Item: WalkOnce<'ctx>, +{ pub fn new<T: IntoIterator<IntoIter = I>>(iter: T) -> Self { Self { - iter: iter.into_iter() + iter: iter.into_iter(), + err: None, } } } -impl<'ctx, I> Walker<'ctx> for IterWalker<I> +impl<'ctx, I> WalkOnce<'ctx> for IterWalker<'ctx, I> where I: Iterator, - <I as Iterator>::Item: WalkOnce<'ctx> + <I as Iterator>::Item: WalkOnce<'ctx>, { - 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 - }, + type Error = <<I as Iterator>::Item as WalkOnce<'ctx>>::Error; + + type Value = (); + + #[inline] + fn walk_once( + mut self, + visitor: &mut dyn crate::protocol::Implementer<'ctx>, + ) -> Result<Self::Value, Self::Error> { + if let Some(interface) = visitor.interface_for::<sequence::Sequence>() { + match interface.as_object().visit(&mut self) { + ControlFlow::Done => Ok(()), + ControlFlow::Error => match self.err { + Some(err) => Err(err), + None => Ok(()), + }, + } + } else { + Ok(()) } } } -impl<'ctx, I> sequence::Accessor<'ctx> for IterWalker<I> +impl<'ctx, I> sequence::Accessor<'ctx> for IterWalker<'ctx, I> where I: Iterator, - <I as Iterator>::Item: WalkOnce<'ctx> + <I as Iterator>::Item: WalkOnce<'ctx>, { - 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, + fn next( + &mut self, + visitor: &mut dyn crate::protocol::Implementer<'ctx>, + ) -> sequence::ControlFlow { + if let Some(item) = self.iter.next() { + match item.walk_once(visitor) { + Ok(_) => sequence::ControlFlow::Continue, Err(err) => { - ControlFlow::Error - }, + self.err = Some(err); + sequence::ControlFlow::Error + } } } else { - ControlFlow::Done + sequence::ControlFlow::Done } } } diff --git a/src/impls/core/reference.rs b/src/impls/core/reference.rs index 4016a26..0f5038d 100644 --- a/src/impls/core/reference.rs +++ b/src/impls/core/reference.rs @@ -1,15 +1,19 @@ 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}, + build::{Build, Builder}, + protocol::{ + lookup_hint, lookup_visit, AnyHint, AnyVisit, Hint, ProtocolId, Visit, + VisitorMissingProtocol, WalkerMissingProtocol, + }, + protocols::{recoverable, reference}, + walk::{Walk, WalkMut, WalkOnce}, + ControlFlow, Visitor, Walker, }; impl<'borrow, 'ctx, T> WalkOnce<'ctx> for &'borrow T where - T: Walk<'borrow, 'ctx> + T: Walk<'borrow, 'ctx>, { type Error = T::Error; @@ -20,18 +24,21 @@ where } } -impl<'borrow, 'a, 'ctx, T> WalkMut<'borrow, 'ctx> for &'a T -where - T: Walk<'a, 'ctx> +impl<'borrow, 'a, 'ctx, T> WalkMut<'borrow, 'ctx> for &'a T +where + T: Walk<'a, 'ctx>, { - fn walk_mut(&'borrow mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + fn walk_mut( + &'borrow mut self, + visitor: &mut dyn Visitor<'ctx>, + ) -> Result<Self::Value, Self::Error> { T::walk(self, visitor) } } -impl<'borrow, 'a, 'ctx, T> Walk<'borrow, 'ctx> for &'a T +impl<'borrow, 'a, 'ctx, T> Walk<'borrow, 'ctx> for &'a T where - T: Walk<'a, 'ctx> + T: Walk<'a, 'ctx>, { fn walk(&'borrow self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { T::walk(self, visitor) @@ -49,27 +56,88 @@ pub struct RefWalker<'ctx, T: ?Sized> { impl<'ctx, T: ?Sized> RefWalker<'ctx, T> { pub fn new(value: &'ctx T) -> Self { - Self { - value, - error: None, + Self { value, error: None } + } +} + +impl<'ctx, T: ?Sized + Any> WalkOnce<'ctx> for RefWalker<'ctx, T> { + type Error = VisitorMissingProtocol; + + type Value = (); + + fn walk_once(mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + match visitor.request_hint(&mut self, false) { + ControlFlow::Continue => { + Hint::<reference::Reference<T>>::hint( + &mut self, + visitor, + reference::Hint { + kind: None, + min_len: None, + max_len: None, + }, + ); + } + _ => {} + } + + if let Some(err) = self.error { + Err(err) + } else { + Ok(()) } } +} - pub fn into_error(self) -> Option<VisitorMissingProtocol> { - self.error +impl<'ctx, T: ?Sized + Any> Walker<'ctx> for RefWalker<'ctx, T> { + fn protocol(&mut self, id: ProtocolId) -> Option<crate::protocol::AnyHint<'_, 'ctx>> { + if id == ProtocolId::of::<reference::Reference<T>>() { + Some(AnyHint::new::<reference::Reference<T>>(self)) + } else if id == ProtocolId::of::<reference::Reference<T>>() { + Some(AnyHint::new::<recoverable::Recoverable>(self)) + } else { + None + } } } -impl<'ctx:, T: ?Sized + Any> Walker<'ctx> for RefWalker<'ctx, T> { - fn walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow { +impl<'ctx, T: ?Sized + Any> Hint<'ctx, reference::Reference<T>> for RefWalker<'ctx, T> { + fn hint(&mut self, visitor: &mut dyn Visitor<'ctx>, _hint: reference::Hint) -> 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 - }, + } + } + } + + fn known(&mut self, _hint: &reference::Hint) -> reference::Known { + reference::Known { + kind: Some(reference::Kind::Context), + len: None, + } + } +} + +impl<'ctx, T: ?Sized + Any> Hint<'ctx, recoverable::Recoverable> for RefWalker<'ctx, T> { + fn hint(&mut self, visitor: &mut dyn Visitor<'ctx>, _hint: ()) -> ControlFlow { + match lookup_visit::<recoverable::Recoverable, _>(visitor) { + Ok(visit) => visit.visit(self).to_done(), + Err(err) => { + self.error = Some(err); + ControlFlow::Error + } } } + + fn known(&mut self, _hint: &()) {} +} + +impl<'ctx, T: ?Sized + Any> recoverable::Accessor<'ctx> for RefWalker<'ctx, T> { + fn new_walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow { + todo!() + } } #[derive(thiserror::Error, Debug)] @@ -81,7 +149,7 @@ pub enum Error { ShortLifetime, #[error(transparent)] - MissingProtocol(#[from] WalkerMissingProtocol) + MissingProtocol(#[from] WalkerMissingProtocol), } pub struct RefBuilder<'ctx, T: ?Sized> { @@ -115,19 +183,22 @@ impl<'ctx, T: ?Sized + Any> Builder<'ctx> for RefBuilder<'ctx, T> { impl<'ctx, T: ?Sized + Any> Visitor<'ctx> for RefBuilder<'ctx, T> { fn request_hint( &mut self, - hints: &mut dyn crate::WalkerHints<'ctx>, + hints: &mut dyn crate::Walker<'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, - }), + 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 - }, + } } } @@ -148,12 +219,11 @@ impl<'ctx, T: ?Sized + Any> Visit<'ctx, reference::Reference<T>> for RefBuilder< reference::Ref::Walking(_) => { self.value = Some(Err(Error::ShortLifetime)); ControlFlow::Error - }, - reference::Ref::Context(value) | - reference::Ref::Static(value) => { + } + reference::Ref::Context(value) | reference::Ref::Static(value) => { self.value = Some(Ok(value)); ControlFlow::Done - }, + } } } } @@ -164,12 +234,11 @@ impl<'ctx, T: ?Sized + Any> Visit<'ctx, reference::ReferenceMut<T>> for RefBuild reference::Mut::Walking(_) => { self.value = Some(Err(Error::ShortLifetime)); ControlFlow::Error - }, - reference::Mut::Context(value) | - reference::Mut::Static(value) => { + } + 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 index 5f0eff7..98427fe 100644 --- a/src/impls/core/reference_mut.rs +++ b/src/impls/core/reference_mut.rs @@ -1,15 +1,19 @@ use core::any::Any; use crate::{ - protocol::{lookup_visit, VisitorMissingProtocol, WalkerMissingProtocol, lookup_hint, ProtocolId, AnyVisit, Visit}, + build::{Build, Builder}, + protocol::{ + lookup_hint, lookup_visit, AnyVisit, ProtocolId, Visit, VisitorMissingProtocol, + WalkerMissingProtocol, + }, protocols::reference, - walk::{WalkMut, WalkOnce, Walk}, - Visitor, Walker, ControlFlow, build::{Builder, Build}, + walk::{Walk, WalkMut, WalkOnce}, + ControlFlow, Visitor, Walker, }; impl<'borrow, 'ctx, T> WalkOnce<'ctx> for &'borrow mut T where - T: WalkMut<'borrow, 'ctx> + T: WalkMut<'borrow, 'ctx>, { type Error = T::Error; @@ -20,18 +24,21 @@ where } } -impl<'borrow, 'ctx, T> WalkMut<'borrow, 'ctx> for &'borrow mut T -where - T: WalkMut<'borrow, 'ctx> +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> { + 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> +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) @@ -44,35 +51,27 @@ impl<'ctx, T: ?Sized + Any> Build<'ctx> for &'ctx mut 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 { +impl<'ctx, T: ?Sized + Any> WalkOnce<'ctx> for MutWalker<'ctx, T> { + type Error = VisitorMissingProtocol; + + type Value = (); + + fn walk_once(mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { 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 + let visit = lookup_visit::<reference::ReferenceMut<T>, _>(visitor)?; + visit.visit(reference::Mut::Context(value)); } + Ok(()) } } @@ -85,7 +84,7 @@ pub enum Error { ShortLifetime, #[error(transparent)] - MissingProtocol(#[from] WalkerMissingProtocol) + MissingProtocol(#[from] WalkerMissingProtocol), } pub struct MutBuilder<'ctx, T: ?Sized> { @@ -119,19 +118,22 @@ impl<'ctx, T: ?Sized + Any> Builder<'ctx> for MutBuilder<'ctx, T> { impl<'ctx, T: ?Sized + Any> Visitor<'ctx> for MutBuilder<'ctx, T> { fn request_hint( &mut self, - hints: &mut dyn crate::WalkerHints<'ctx>, + hints: &mut dyn crate::Walker<'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, - }), + 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 - }, + } } } @@ -150,13 +152,11 @@ impl<'ctx, T: ?Sized + Any> Visit<'ctx, reference::ReferenceMut<T>> for MutBuild reference::Mut::Walking(_) => { self.value = Some(Err(Error::ShortLifetime)); ControlFlow::Continue - }, - reference::Mut::Context(value) | - reference::Mut::Static(value) => { + } + 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 e09b219..0ff2de8 100644 --- a/src/impls/core/str.rs +++ b/src/impls/core/str.rs @@ -1,4 +1,8 @@ -use crate::{walk::{Walk, WalkOnce, WalkMut}, protocol::VisitorMissingProtocol, Walker, Visitor}; +use crate::{ + protocol::VisitorMissingProtocol, + walk::{Walk, WalkMut, WalkOnce}, + Visitor, Walker, +}; use super::{reference::RefWalker, reference_mut::MutWalker}; @@ -15,7 +19,10 @@ impl<'ctx> WalkOnce<'ctx> for &'ctx str { 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> { + fn walk_mut( + &'borrow mut self, + visitor: &mut dyn Visitor<'ctx>, + ) -> Result<Self::Value, Self::Error> { self.walk(visitor) } } @@ -23,12 +30,7 @@ impl<'borrow, 'ctx> WalkMut<'borrow, 'ctx> for &'ctx str { 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(()), - } + RefWalker::new(*self).walk_once(visitor) } } @@ -39,36 +41,23 @@ impl<'ctx> WalkOnce<'ctx> for &'ctx mut str { #[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(()), - } + MutWalker::new(self).walk_once(visitor) } } 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(()), - } + fn walk_mut( + &'ctx mut self, + visitor: &mut dyn Visitor<'ctx>, + ) -> Result<Self::Value, Self::Error> { + MutWalker::new(*self).walk_once(visitor) } } 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(()), - } + RefWalker::new(*self).walk_once(visitor) } } - @@ -1,103 +1,17 @@ +//! # Design +//! + #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "alloc")] extern crate alloc; -pub mod build; +mod build; pub mod impls; pub mod protocol; pub mod protocols; pub mod transform; -pub mod walk; - -use protocol::{AnyHint, AnyVisit, Hint, ProtocolId, Visit}; - -/// Signal to a walker or visitor that it should exit early or continue. -/// -/// [`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, - - Done, - - Error, -} - -impl ControlFlow { - pub fn to_done(self) -> Self { - match self { - ControlFlow::Continue => ControlFlow::Done, - ControlFlow::Done => ControlFlow::Done, - ControlFlow::Error => ControlFlow::Error, - } - } - - pub fn to_continue(self) -> Self { - match self { - ControlFlow::Continue => ControlFlow::Continue, - ControlFlow::Done => ControlFlow::Continue, - ControlFlow::Error => ControlFlow::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 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 provide a hint for what protocol to use. - /// - /// 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. - /// - /// 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, - ) -> ControlFlow; +mod walk; - /// Query the visitor for a given protocol. - /// - /// If the visitor doesn't support the protocol then a `None` is returned. - /// 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>>; -} +pub use build::*; +pub use walk::*; diff --git a/src/protocol.rs b/src/protocol.rs index 617cc4d..2b48fc8 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -1,289 +1,93 @@ -use core::any::{type_name, Any}; +use core::any::{Any, TypeId}; -pub use any_hint::AnyHint; -pub use any_visit::AnyVisit; -pub use id::ProtocolId; +pub use any_implementation::AnyImpl; -use crate::{ControlFlow, Visitor, WalkerHints}; - -/// A protocol between a walker and visitor. -/// -/// On the walker side this takes the form of hints a visitor can give. -/// On the visitor side this takes the form of visits a walker can inject values into. -/// -/// When a visitor hints a walker should use a particular protocol, its expected -/// that the walker visits using that protocol. -/// -/// 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: 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<'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<'ctx>; - - /// The visit data the walker provides to the visitor. - /// - /// This may be actual data or another walker for a part of the bigger value. - /// 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, 'ctx: 'walking>; -} - -/// 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>) -> ControlFlow; - - /// Any information the walker has for the protocol. - /// - /// This information should be easy to get inside the walker, and should - /// only be used when making a decision of what protocol to hint as a visitor. - /// This can be helpful for doing things like preallocating space in the visitor. - /// - /// 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>; -} - -/// 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. - /// - /// 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; -} - -#[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, -} - -#[derive(thiserror::Error, Debug)] -pub enum WalkerMissingProtocol { - #[error("Walker doesn't support the protocol `{0}`.")] - Missing(&'static str), - - #[error(transparent)] - Wrong(#[from] WalkerWrongProtocol), -} - -#[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, -} - -#[derive(thiserror::Error, Debug)] -pub enum VisitorMissingProtocol { - #[error("Visitor doesn't support the protocol `{0}`.")] - Missing(&'static str), - - #[error(transparent)] - Wrong(#[from] VisitorWrongProtocol), + type Object<'a, 'ctx: 'a>; } -/// 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) => Ok(Some(hint)), - Err(hint) => Err(WalkerWrongProtocol { - got: hint.protocol_type_name(), - expected: type_name::<P>(), - }), - }, - None => Ok(None), - } +pub trait Implementer<'ctx> { + fn interface(&mut self, id: TypeId) -> Option<AnyImpl<'_, 'ctx>>; } -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 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) => Ok(Some(visit)), - Err(visit) => Err(VisitorWrongProtocol { - got: visit.protocol_type_name(), - expected: type_name::<P>(), - }), - }, - None => Ok(None), - } +pub trait Implementation<'ctx, P: Protocol> { + fn as_object(&mut self) -> P::Object<'_, 'ctx>; } -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>())) +pub trait ImplementerExt<'ctx>: Implementer<'ctx> { + fn interface_for<P: Protocol>(&mut self) -> Option<&mut dyn Implementation<'ctx, P>>; } -mod id { - use super::Protocol; - use core::any::TypeId; - - /// ID of a protocol. - /// - /// This can be used to query if a walker or visitor supports a protocol. - #[derive(PartialEq, Eq, Hash, Ord, PartialOrd, Debug, Copy, Clone)] - pub struct ProtocolId(TypeId); - - impl ProtocolId { - /// Get the ID of a protocol. - /// - /// The ID is unique per protocol. - pub fn of<P: Protocol>() -> Self { - Self(TypeId::of::<P>()) +impl<'ctx, T: Implementer<'ctx> + ?Sized> ImplementerExt<'ctx> for T { + fn interface_for<P: Protocol>(&mut self) -> Option<&mut dyn Implementation<'ctx, P>> { + match self.interface(TypeId::of::<P>()) { + Some(interface) => match interface.downcast::<P>() { + Ok(implementation) => Some(implementation), + Err(interface) => panic!( + "unexpected type ID for protocol implementation: `{:?}`, expected: `{:?}`", + interface.id(), + TypeId::of::<P>() + ), + }, + None => None, } } } -mod any_hint { - use core::{ - any::{type_name, Any}, - marker::PhantomData, - mem::MaybeUninit, - }; - - use crate::Hint; - - 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>>(); - - /// Type erased form of `&'walking mut dyn Hint<'value, P, Err>` where `P` is erased. - pub struct AnyHint<'walking, 'ctx> { - /// ID of `P`. - id: ProtocolId, - name: &'static str, - - /// 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<'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 { - Self { - 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) }, - _marker: PhantomData, +#[doc(hidden)] +#[macro_export] +macro_rules! implementer { + { + impl[$ctx:lifetime $($generic:tt)*] $name:ty = [$($protocol:ty),* $(,)?]; + } => { + impl<$ctx $($generic)*> $crate::protocol::Implementer<$ctx> for $name { + #[inline] + fn interface(&mut self, id: ::core::any::TypeId) -> ::core::option::Option<$crate::protocol::AnyImpl<'_, $ctx>> { + match id { + $(id if id == ::core::any::TypeId::of::<$protocol>() => Some($crate::protocol::AnyImpl::new::<$protocol>(self)),)* + _ => None + } } } - /// 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 == 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. - // - // An important note is this method takes ownership. Which allows it to return - // the borrow with the `'walking` lifetime instead of a sub-borrow. - Ok(unsafe { core::mem::transmute(self.fat_ptr) }) - } else { - Err(self) + $(impl<$ctx> $crate::protocol::Implementation<$ctx, $protocol> for $name { + fn as_object(&mut self) -> <$protocol as $crate::protocol::Protocol>::Object<'_, $ctx> { + self } - } - - pub fn protocol_type_name(&self) -> &'static str { - self.name - } + })* } } +#[doc(inline)] +pub use implementer; -mod any_visit { - use core::{ - any::{type_name, Any}, - marker::PhantomData, - mem::MaybeUninit, - }; - - use crate::Visit; +mod any_implementation { + use core::{any::TypeId, marker::PhantomData, mem::MaybeUninit}; - use super::{Protocol, ProtocolId}; + use super::{Implementation, Protocol}; - /// Form of `Visit` without `P`. - trait ErasedVisit<'ctx>: Any {} + trait ErasedImplementation<'ctx> {} - /// 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 ErasedImplementation<'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: ProtocolId, - name: &'static str, - - /// This field stores a `&'walking mut dyn Visit<'value, P, Err>`. + pub struct AnyImpl<'a, 'ctx> { + id: TypeId, fat_ptr: MaybeUninit<[u8; DYN_PTR_SIZE]>, - - /// Mimick what we actually store with a trait without `P`. - _marker: PhantomData<&'walking mut dyn ErasedVisit<'ctx>>, + _marker: PhantomData<&'a mut dyn ErasedImplementation<'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 { + impl<'a, 'ctx> AnyImpl<'a, 'ctx> { + pub fn new<P: Protocol>(implementation: &'a mut dyn Implementation<'ctx, P>) -> Self { Self { - id: ProtocolId::of::<P>(), - name: type_name::<P>(), + id: TypeId::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) }, + fat_ptr: unsafe { core::mem::transmute(implementation) }, _marker: PhantomData, } } - /// 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 == ProtocolId::of::<P>() { + pub fn downcast<P: Protocol>(self) -> Result<&'a mut dyn Implementation<'ctx, P>, Self> { + if self.id == TypeId::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. @@ -296,41 +100,8 @@ mod any_visit { } } - pub fn protocol_type_name(&self) -> &'static str { - self.name - } - } -} - -/// The following shows a safe form of the generic types in this module. -/// This shows how the lifetimes are correct. -#[cfg(test)] -#[allow(unused)] -mod generic_example { - use crate::Hint; - - use super::{Protocol, ProtocolId}; - - pub struct Generic<'walking, 'ctx, P> { - id: ProtocolId, - 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 { - Self { - id: ProtocolId::of::<P>(), - fat_ptr: visit, - } - } - - 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) - } else { - Err(self) - } + pub fn id(&self) -> TypeId { + self.id } } } diff --git a/src/protocols.rs b/src/protocols.rs index cd0164e..6e0ae5f 100644 --- a/src/protocols.rs +++ b/src/protocols.rs @@ -1,23 +1,120 @@ +pub enum ControlFlow { + Done, + Error, +} + +pub mod hint { + use crate::protocol::{Implementer, Protocol}; + + pub enum ControlFlow { + HintGiven, + NoHint, + Error, + } + + pub trait Object<'ctx> { + fn request_hint(&mut self, hints: &mut dyn Implementer<'ctx>) -> ControlFlow; + } + + pub enum RequestHint {} + + impl Protocol for RequestHint { + type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>; + } + + pub trait HintObject<'ctx> { + fn hint(&mut self, visitor: &mut dyn Implementer<'ctx>) -> ControlFlow; + } +} + pub mod recoverable { - use crate::{protocol::Protocol, ControlFlow, Visitor}; + use crate::protocol::{Implementer, Protocol}; + + use super::{hint::HintObject, ControlFlow}; pub trait Accessor<'ctx> { - /// Each time this is called the walker resets. - fn new_walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow; + fn new_walk(&mut self, visitor: &mut dyn Implementer<'ctx>) -> ControlFlow; + } + + pub trait Object<'ctx> { + fn visit(&mut self, accessor: &mut dyn Accessor<'ctx>) -> ControlFlow; } pub enum Recoverable {} impl Protocol for Recoverable { - type Hint<'ctx> = (); + type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>; + } - type Known<'ctx> = (); + pub enum Hint {} - type Accessor<'walking, 'ctx: 'walking> = &'walking mut dyn Accessor<'ctx>; + impl Protocol for Hint { + type Object<'a, 'ctx: 'a> = &'a mut dyn HintObject<'ctx>; } } pub mod sequence { + use crate::protocol::{Implementer, Protocol}; + + pub enum ControlFlow { + Done, + Continue, + Error, + } + + pub trait Accessor<'ctx> { + fn next(&mut self, visitor: &mut dyn Implementer<'ctx>) -> ControlFlow; + } + + pub trait Object<'ctx> { + fn visit(&mut self, accessor: &mut dyn Accessor<'ctx>) -> super::ControlFlow; + } + + pub enum Sequence {} + + impl Protocol for Sequence { + type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>; + } + + pub trait HintObject<'ctx> { + fn hint(&mut self, visitor: &mut dyn Implementer<'ctx>) -> super::ControlFlow; + + fn len(&mut self) -> (usize, Option<usize>) { + (0, None) + } + } + + pub enum Hint {} + + impl Protocol for Hint { + type Object<'a, 'ctx: 'a> = &'a mut dyn HintObject<'ctx>; + } +} + +pub mod bool { + use crate::protocol::Protocol; + + use super::{hint::HintObject, ControlFlow}; + + pub trait Object<'ctx> { + fn visit(&mut self, value: bool) -> ControlFlow; + } + + pub enum Bool {} + + impl Protocol for Bool { + type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>; + } + + pub enum Hint {} + + impl Protocol for Hint { + type Object<'a, 'ctx: 'a> = &'a mut dyn HintObject<'ctx>; + } +} + +/* +pub mod map { use crate::{protocol::Protocol, ControlFlow, Visitor}; pub struct Hint { @@ -30,15 +127,16 @@ pub mod sequence { } pub trait Accessor<'ctx> { - fn next(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow; + fn next_key(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow; + fn value(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow; } - pub enum Sequence {} + pub enum Map {} - impl Protocol for Sequence { - type Hint<'ctx> = Hint; + impl Protocol for Map { + type Hint<'walking, 'ctx: 'walking> = Hint; - type Known<'ctx> = Known; + type Known<'walking, 'ctx: 'walking> = Known; type Accessor<'walking, 'ctx: 'walking> = &'walking mut dyn Accessor<'ctx>; } @@ -86,18 +184,501 @@ pub mod reference { pub struct ReferenceMut<T: ?Sized + Any>(PhantomData<fn() -> T>); impl<T: ?Sized + Any> Protocol for Reference<T> { - type Hint<'ctx> = Hint; + type Hint<'walking, 'ctx: 'walking> = Hint; - type Known<'ctx> = Known; + type Known<'walking, 'ctx: 'walking> = Known; type Accessor<'walking, 'ctx: 'walking> = Ref<'walking, 'ctx, T>; } impl<T: ?Sized + Any> Protocol for ReferenceMut<T> { - type Hint<'ctx> = Hint; + type Hint<'walking, 'ctx: 'walking> = Hint; - type Known<'ctx> = Known; + type Known<'walking, 'ctx: 'walking> = Known; type Accessor<'walking, 'ctx: 'walking> = Mut<'walking, 'ctx, T>; } } + +pub mod bool { + use crate::protocol::Protocol; + + pub enum Bool {} + + impl Protocol for Bool { + type Hint<'walking, 'ctx: 'walking> = (); + + type Known<'walking, 'ctx: 'walking> = (); + + type Accessor<'walking, 'ctx: 'walking> = bool; + } +} + +pub mod int { + use core::num::TryFromIntError; + + use crate::protocol::Protocol; + + pub enum Kind { + I8, + I16, + I32, + I64, + I128, + Isize, + U8, + U16, + U32, + U64, + U128, + Usize, + } + + pub enum Value { + I8(i8), + I16(i16), + I32(i32), + I64(i64), + I128(i128), + Isize(isize), + U8(u8), + U16(u16), + U32(u32), + U64(u64), + U128(u128), + Usize(usize), + } + + pub enum Int {} + + impl Protocol for Int { + type Hint<'walking, 'ctx: 'walking> = Option<Kind>; + + type Known<'walking, 'ctx: 'walking> = Option<Kind>; + + type Accessor<'walking, 'ctx: 'walking> = Value; + } + + impl From<i8> for Value { + fn from(value: i8) -> Self { + Self::I8(value) + } + } + + impl From<i16> for Value { + fn from(value: i16) -> Self { + Self::I16(value) + } + } + + impl From<i32> for Value { + fn from(value: i32) -> Self { + Self::I32(value) + } + } + + impl From<i64> for Value { + fn from(value: i64) -> Self { + Self::I64(value) + } + } + + impl From<i128> for Value { + fn from(value: i128) -> Self { + Self::I128(value) + } + } + + impl From<isize> for Value { + fn from(value: isize) -> Self { + Self::Isize(value) + } + } + + impl From<u8> for Value { + fn from(value: u8) -> Self { + Self::U8(value) + } + } + + impl From<u16> for Value { + fn from(value: u16) -> Self { + Self::U16(value) + } + } + + impl From<u32> for Value { + fn from(value: u32) -> Self { + Self::U32(value) + } + } + + impl From<u64> for Value { + fn from(value: u64) -> Self { + Self::U64(value) + } + } + + impl From<u128> for Value { + fn from(value: u128) -> Self { + Self::U128(value) + } + } + + impl From<usize> for Value { + fn from(value: usize) -> Self { + Self::Usize(value) + } + } + + impl TryFrom<Value> for i8 { + type Error = TryFromIntError; + + fn try_from(value: Value) -> Result<Self, Self::Error> { + match value { + Value::I8(value) => Ok(value), + Value::I16(value) => value.try_into(), + Value::I32(value) => value.try_into(), + Value::I64(value) => value.try_into(), + Value::I128(value) => value.try_into(), + Value::Isize(value) => value.try_into(), + Value::U8(value) => value.try_into(), + Value::U16(value) => value.try_into(), + Value::U32(value) => value.try_into(), + Value::U64(value) => value.try_into(), + Value::U128(value) => value.try_into(), + Value::Usize(value) => value.try_into(), + } + } + } + + impl TryFrom<Value> for i16 { + type Error = TryFromIntError; + + fn try_from(value: Value) -> Result<Self, Self::Error> { + match value { + Value::I8(value) => Ok(value.into()), + Value::I16(value) => Ok(value), + Value::I32(value) => value.try_into(), + Value::I64(value) => value.try_into(), + Value::I128(value) => value.try_into(), + Value::Isize(value) => value.try_into(), + Value::U8(value) => Ok(value.into()), + Value::U16(value) => value.try_into(), + Value::U32(value) => value.try_into(), + Value::U64(value) => value.try_into(), + Value::U128(value) => value.try_into(), + Value::Usize(value) => value.try_into(), + } + } + } + + impl TryFrom<Value> for i32 { + type Error = TryFromIntError; + + fn try_from(value: Value) -> Result<Self, Self::Error> { + match value { + Value::I8(value) => Ok(value.into()), + Value::I16(value) => Ok(value.into()), + Value::I32(value) => Ok(value), + Value::I64(value) => value.try_into(), + Value::I128(value) => value.try_into(), + Value::Isize(value) => value.try_into(), + Value::U8(value) => Ok(value.into()), + Value::U16(value) => Ok(value.into()), + Value::U32(value) => value.try_into(), + Value::U64(value) => value.try_into(), + Value::U128(value) => value.try_into(), + Value::Usize(value) => value.try_into(), + } + } + } + + impl TryFrom<Value> for i64 { + type Error = TryFromIntError; + + fn try_from(value: Value) -> Result<Self, Self::Error> { + match value { + Value::I8(value) => Ok(value.into()), + Value::I16(value) => Ok(value.into()), + Value::I32(value) => Ok(value.into()), + Value::I64(value) => Ok(value), + Value::I128(value) => value.try_into(), + Value::Isize(value) => value.try_into(), + Value::U8(value) => Ok(value.into()), + Value::U16(value) => Ok(value.into()), + Value::U32(value) => Ok(value.into()), + Value::U64(value) => value.try_into(), + Value::U128(value) => value.try_into(), + Value::Usize(value) => value.try_into(), + } + } + } + + impl TryFrom<Value> for i128 { + type Error = TryFromIntError; + + fn try_from(value: Value) -> Result<Self, Self::Error> { + match value { + Value::I8(value) => Ok(value.into()), + Value::I16(value) => Ok(value.into()), + Value::I32(value) => Ok(value.into()), + Value::I64(value) => Ok(value.into()), + Value::I128(value) => Ok(value), + Value::Isize(value) => value.try_into(), + Value::U8(value) => Ok(value.into()), + Value::U16(value) => Ok(value.into()), + Value::U32(value) => Ok(value.into()), + Value::U64(value) => Ok(value.into()), + Value::U128(value) => value.try_into(), + Value::Usize(value) => value.try_into(), + } + } + } + + impl TryFrom<Value> for isize { + type Error = TryFromIntError; + + fn try_from(value: Value) -> Result<Self, Self::Error> { + match value { + Value::I8(value) => Ok(value.into()), + Value::I16(value) => Ok(value.into()), + Value::I32(value) => value.try_into(), + Value::I64(value) => value.try_into(), + Value::I128(value) => value.try_into(), + Value::Isize(value) => Ok(value), + Value::U8(value) => Ok(value.into()), + Value::U16(value) => value.try_into(), + Value::U32(value) => value.try_into(), + Value::U64(value) => value.try_into(), + Value::U128(value) => value.try_into(), + Value::Usize(value) => value.try_into(), + } + } + } + + impl TryFrom<Value> for u8 { + type Error = TryFromIntError; + + fn try_from(value: Value) -> Result<Self, Self::Error> { + match value { + Value::U8(value) => Ok(value), + Value::U16(value) => value.try_into(), + Value::U32(value) => value.try_into(), + Value::U64(value) => value.try_into(), + Value::U128(value) => value.try_into(), + Value::Usize(value) => value.try_into(), + Value::I8(value) => value.try_into(), + Value::I16(value) => value.try_into(), + Value::I32(value) => value.try_into(), + Value::I64(value) => value.try_into(), + Value::I128(value) => value.try_into(), + Value::Isize(value) => value.try_into(), + } + } + } + + impl TryFrom<Value> for u16 { + type Error = TryFromIntError; + + fn try_from(value: Value) -> Result<Self, Self::Error> { + match value { + Value::U8(value) => Ok(value.into()), + Value::U16(value) => Ok(value), + Value::U32(value) => value.try_into(), + Value::U64(value) => value.try_into(), + Value::U128(value) => value.try_into(), + Value::Usize(value) => value.try_into(), + Value::I8(value) => value.try_into(), + Value::I16(value) => value.try_into(), + Value::I32(value) => value.try_into(), + Value::I64(value) => value.try_into(), + Value::I128(value) => value.try_into(), + Value::Isize(value) => value.try_into(), + } + } + } + + impl TryFrom<Value> for u32 { + type Error = TryFromIntError; + + fn try_from(value: Value) -> Result<Self, Self::Error> { + match value { + Value::U8(value) => Ok(value.into()), + Value::U16(value) => Ok(value.into()), + Value::U32(value) => Ok(value), + Value::U64(value) => value.try_into(), + Value::U128(value) => value.try_into(), + Value::Usize(value) => value.try_into(), + Value::I8(value) => value.try_into(), + Value::I16(value) => value.try_into(), + Value::I32(value) => value.try_into(), + Value::I64(value) => value.try_into(), + Value::I128(value) => value.try_into(), + Value::Isize(value) => value.try_into(), + } + } + } + + impl TryFrom<Value> for u64 { + type Error = TryFromIntError; + + fn try_from(value: Value) -> Result<Self, Self::Error> { + match value { + Value::U8(value) => Ok(value.into()), + Value::U16(value) => Ok(value.into()), + Value::U32(value) => Ok(value.into()), + Value::U64(value) => Ok(value), + Value::U128(value) => value.try_into(), + Value::Usize(value) => value.try_into(), + Value::I8(value) => value.try_into(), + Value::I16(value) => value.try_into(), + Value::I32(value) => value.try_into(), + Value::I64(value) => value.try_into(), + Value::I128(value) => value.try_into(), + Value::Isize(value) => value.try_into(), + } + } + } + + impl TryFrom<Value> for u128 { + type Error = TryFromIntError; + + fn try_from(value: Value) -> Result<Self, Self::Error> { + match value { + Value::U8(value) => Ok(value.into()), + Value::U16(value) => Ok(value.into()), + Value::U32(value) => Ok(value.into()), + Value::U64(value) => Ok(value.into()), + Value::U128(value) => Ok(value), + Value::Usize(value) => value.try_into(), + Value::I8(value) => value.try_into(), + Value::I16(value) => value.try_into(), + Value::I32(value) => value.try_into(), + Value::I64(value) => value.try_into(), + Value::I128(value) => value.try_into(), + Value::Isize(value) => value.try_into(), + } + } + } + + impl TryFrom<Value> for usize { + type Error = TryFromIntError; + + fn try_from(value: Value) -> Result<Self, Self::Error> { + match value { + Value::U8(value) => Ok(value.into()), + Value::U16(value) => Ok(value.into()), + Value::U32(value) => value.try_into(), + Value::U64(value) => value.try_into(), + Value::U128(value) => value.try_into(), + Value::Usize(value) => Ok(value), + Value::I8(value) => value.try_into(), + Value::I16(value) => value.try_into(), + Value::I32(value) => value.try_into(), + Value::I64(value) => value.try_into(), + Value::I128(value) => value.try_into(), + Value::Isize(value) => value.try_into(), + } + } + } +} + +pub mod optional { + use crate::{protocol::Protocol, Walker}; + + pub enum Kind { + Some, + None, + } + + pub enum Optional {} + + impl Protocol for Optional { + type Hint<'walking, 'ctx: 'walking> = Option<Kind>; + + type Known<'walking, 'ctx: 'walking> = Option<Kind>; + + type Accessor<'walking, 'ctx: 'walking> = Option<&'walking mut dyn Walker<'ctx>>; + } +} + +pub mod unit { + use crate::protocol::Protocol; + + pub enum Unit {} + + impl Protocol for Unit { + type Hint<'walking, 'ctx: 'walking> = (); + + type Known<'walking, 'ctx: 'walking> = (); + + type Accessor<'walking, 'ctx: 'walking> = (); + } +} + +pub mod r#struct { + use core::any::TypeId; + + use crate::protocol::Protocol; + + pub struct Hint<'walking> { + pub name: Option<&'static str>, + pub type_name: Option<&'static str>, + pub id: Option<TypeId>, + pub fields: Option<&'walking [&'walking str]>, + } + + pub struct Known<'walking> { + pub name: Option<&'static str>, + pub type_name: Option<&'static str>, + pub id: Option<TypeId>, + pub fields: Option<&'walking [&'walking str]>, + } + + pub enum Struct {} + + impl Protocol for Struct { + type Hint<'walking, 'ctx: 'walking> = Hint<'walking>; + + type Known<'walking, 'ctx: 'walking> = Known<'walking>; + + type Accessor<'walking, 'ctx: 'walking> = &'walking mut dyn super::map::Accessor<'ctx>; + } +} + +pub mod r#enum { + use core::any::TypeId; + + use crate::{protocol::Protocol, ControlFlow, Visitor}; + + pub struct Hint<'walking> { + pub name: Option<&'static str>, + pub type_name: Option<&'static str>, + pub id: Option<TypeId>, + pub variants: Option<&'walking [&'walking str]>, + } + + pub struct Known<'walking> { + pub name: Option<&'static str>, + pub type_name: Option<&'static str>, + pub id: Option<TypeId>, + pub variant: Option<&'walking str>, + } + + pub trait Accessor<'ctx> { + fn variant(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow; + fn walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow; + } + + pub enum Enum {} + + impl Protocol for Enum { + type Hint<'walking, 'ctx: 'walking> = Hint<'walking>; + + type Known<'walking, 'ctx: 'walking> = Known<'walking>; + + type Accessor<'walking, 'ctx: 'walking> = &'walking mut dyn Accessor<'ctx>; + } +} +*/ diff --git a/src/transform.rs b/src/transform.rs index 2999ad7..325b9ec 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -1,6 +1,6 @@ use crate::{ build::{Build, Builder}, - walk::{WalkOnce, WalkMut, Walk}, + walk::{Walk, WalkMut, WalkOnce}, }; #[derive(thiserror::Error, Debug)] diff --git a/src/walk.rs b/src/walk.rs index 7b2ddc1..9d218b1 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -1,16 +1,20 @@ -use crate::Visitor; +use crate::protocol::Implementer; pub trait WalkOnce<'ctx> { type Error; type Value; - fn walk_once(self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error>; + fn walk_once(self, visitor: &mut dyn Implementer<'ctx>) -> Result<Self::Value, Self::Error>; } pub trait WalkMut<'borrow, 'ctx>: WalkOnce<'ctx> { - fn walk_mut(&'borrow mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error>; + fn walk_mut( + &'borrow mut self, + visitor: &mut dyn Implementer<'ctx>, + ) -> Result<Self::Value, Self::Error>; } pub trait Walk<'borrow, 'ctx>: WalkMut<'borrow, 'ctx> { - fn walk(&'borrow self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error>; + fn walk(&'borrow self, visitor: &mut dyn Implementer<'ctx>) + -> Result<Self::Value, Self::Error>; } diff --git a/tests/demo.rs b/tests/demo.rs index 81b4875..65b1083 100644 --- a/tests/demo.rs +++ b/tests/demo.rs @@ -1,70 +1,63 @@ -use uniserde::{transform::from, build::{Builder, Build}, Visitor, ControlFlow, protocol::{ProtocolId, AnyVisit, Visit}, protocols::sequence, impls::core::iterator::IterWalker, Walker}; +use std::any::TypeId; + +use uniserde::{ + Build, Builder, + impls::core::iterator::IterWalker, + protocol::{implementer, AnyImpl, Implementation, Implementer}, + protocols::{sequence, ControlFlow}, + transform, + WalkOnce, +}; #[test] fn demo() { - let x = ["1", "2", "3"]; + let a = vec![true, false, true]; - let mut builder = VecBuilder::default(); - IterWalker::new(x.iter()).walk(builder.as_visitor()); + let mut builder = ArrayBuilder::default(); + IterWalker::new(a).walk_once(builder.as_visitor()); dbg!(builder.build()); - todo!(); + todo!() } #[no_mangle] -pub fn example<'a>(x: &'a str) -> &'a str { - from(x).unwrap() +fn example(a: [bool; 3]) -> [bool; 3] { + let mut builder = ArrayBuilder::default(); + let _ = IterWalker::new(a).walk_once(builder.as_visitor()); + builder.build().unwrap() } #[derive(Default)] -pub struct VecBuilder(Vec<&'static str>); +struct ArrayBuilder([Option<bool>; 3]); -impl Builder<'static> for VecBuilder { +impl<'ctx> Builder<'ctx> for ArrayBuilder { type Error = (); - type Value = Vec<&'static str>; + type Value = [bool; 3]; - fn as_visitor(&mut self) -> &mut dyn uniserde::Visitor<'static> { + fn as_visitor(&mut self) -> &mut dyn uniserde::protocol::Implementer<'ctx> { self } fn build(self) -> Result<Self::Value, Self::Error> { - Ok(self.0) + Ok([self.0[0].unwrap(), self.0[1].unwrap(), self.0[2].unwrap()]) } } -impl Visitor<'static> for VecBuilder { - fn request_hint( - &mut self, - _hints: &mut dyn uniserde::WalkerHints<'static>, - _need_hint: bool, - ) -> uniserde::ControlFlow { - ControlFlow::Continue - } - - 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 - } - } +implementer! { + impl['ctx] ArrayBuilder = [sequence::Sequence]; } -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, - } +impl<'ctx> sequence::Object<'ctx> for ArrayBuilder { + fn visit( + &mut self, + accessor: &mut dyn sequence::Accessor<'ctx>, + ) -> uniserde::protocols::ControlFlow { + for slot in &mut self.0 { + let mut builder = <bool as Build>::Builder::default(); + accessor.next(builder.as_visitor()); + *slot = Some(builder.build().unwrap()); } + ControlFlow::Done } } |