split up protocols and make Owned a protocol
| -rw-r--r-- | src/build.rs | 7 | ||||
| -rw-r--r-- | src/build/builders.rs | 7 | ||||
| -rw-r--r-- | src/build/builders/owned.rs | 56 | ||||
| -rw-r--r-- | src/build/protocols.rs | 289 | ||||
| -rw-r--r-- | src/impls/core.rs | 2 | ||||
| -rw-r--r-- | src/impls/core/bool.rs | 64 | ||||
| -rw-r--r-- | src/lib.rs | 13 | ||||
| -rw-r--r-- | src/protocol.rs | 37 | ||||
| -rw-r--r-- | src/protocol/id.rs | 67 | ||||
| -rw-r--r-- | src/protocols.rs | 685 | ||||
| -rw-r--r-- | src/transform.rs | 35 | ||||
| -rw-r--r-- | src/walk.rs | 23 | ||||
| -rw-r--r-- | src/walk/protocols.rs | 43 | ||||
| -rw-r--r-- | src/walk/walkers.rs | 11 | ||||
| -rw-r--r-- | src/walk/walkers/owned.rs | 41 | ||||
| -rw-r--r-- | src/walk/walkers/owned_clone.rs | 217 | ||||
| -rw-r--r-- | tests/demo.rs | 11 |
17 files changed, 797 insertions, 811 deletions
diff --git a/src/build.rs b/src/build.rs index b5dfc75..b0b5750 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1,9 +1,10 @@ -use core::any::TypeId; +pub mod builders; +pub mod protocols; use crate::protocol::Implementer; /// A type buildable from a walker. -pub trait Build<'ctx> { +pub trait Build<'ctx>: Sized { /// The builder that can be used to build a value. type Builder: Builder<'ctx, Value = Self>; } @@ -20,6 +21,4 @@ pub trait Builder<'ctx>: Default { /// Finish the value. fn build(self) -> Result<Self::Value, Self::Error>; - - fn accepts(id: TypeId) -> bool; } diff --git a/src/build/builders.rs b/src/build/builders.rs new file mode 100644 index 0000000..4eb1f79 --- /dev/null +++ b/src/build/builders.rs @@ -0,0 +1,7 @@ +mod owned; + +pub use owned::*; + +#[derive(thiserror::Error, Debug)] +#[error("The value is not complete.")] +pub struct IncompleteValue; diff --git a/src/build/builders/owned.rs b/src/build/builders/owned.rs new file mode 100644 index 0000000..29098c8 --- /dev/null +++ b/src/build/builders/owned.rs @@ -0,0 +1,56 @@ +use crate::{build::protocols, implementer, protocol::ImplementerExt, walk, Builder}; + +use super::IncompleteValue; + +pub struct OwnedBuilder<T> { + value: Option<T>, +} + +impl<T> Default for OwnedBuilder<T> { + fn default() -> Self { + Self { value: None } + } +} + +impl<'ctx, T: 'static> Builder<'ctx> for OwnedBuilder<T> { + type Error = IncompleteValue; + + type Value = T; + + fn as_visitor(&mut self) -> &mut dyn crate::protocol::Implementer<'ctx> { + self + } + + fn build(self) -> Result<Self::Value, Self::Error> { + self.value.ok_or(IncompleteValue) + } +} + +implementer! { + impl['ctx, T: 'static] OwnedBuilder<T> = [ + protocols::owned::Owned<T>, + protocols::hint::RequestHint, + ]; +} + +impl<'ctx, T: 'static> protocols::hint::RequestHintObject<'ctx> for OwnedBuilder<T> { + fn request_hint( + &mut self, + hints: &mut dyn crate::protocol::Implementer<'ctx>, + ) -> Result<(), ()> { + if let Some(interface) = + hints.interface_for::<walk::protocols::hint::Hint<protocols::owned::Owned<T>>>() + { + interface.as_object().hint(self, ()) + } else { + Ok(()) + } + } +} + +impl<'ctx, T: 'static> protocols::owned::Object<'ctx, T> for OwnedBuilder<T> { + fn visit(&mut self, value: T) -> Result<(), ()> { + self.value = Some(value); + Ok(()) + } +} diff --git a/src/build/protocols.rs b/src/build/protocols.rs new file mode 100644 index 0000000..30dc074 --- /dev/null +++ b/src/build/protocols.rs @@ -0,0 +1,289 @@ +pub mod hint { + use crate::protocol::{Implementer, Protocol}; + + /// Protocol for requesting a visitor give a hint. + /// + /// This protocol is implemented by visitors. + /// + /// Some walkers don't know what the data they are walking actually represents. + /// This protocol allows such walkers to request the visitor to give a hint of what + /// it is expecting. + /// + /// This can also be paired with the [`Recoverable`][super::recoverable::Recoverable] + /// protocol to place the walker in a recoverable mode for the visitor to try multiple + /// protocols. + pub enum RequestHint {} + + /// Object implementing the [`RequestHint`] protocol. + pub trait RequestHintObject<'ctx> { + /// Call this to request a hint. + /// + /// `hints` is expected to be the walker. This is what the visitor (`Self`) + /// will call to give a hint using the [`Hint`] protocol. + /// + /// `needs_hints` can be `false` if the walker can continue without a hint. + fn request_hint(&mut self, hints: &mut dyn Implementer<'ctx>) -> Result<(), ()>; + } + + impl Protocol for RequestHint { + type Object<'a, 'ctx: 'a> = &'a mut dyn RequestHintObject<'ctx>; + } +} + +pub mod recoverable { + use crate::{ + protocol::{Implementer, Protocol}, + walk::protocols::hint::Meta, + }; + + /// Protocol for providing a recoverable walker. + /// + /// This protocol is implemented by visitors. + pub enum Recoverable {} + + /// Implemented by walkers that can be reset. + pub trait RecoverableWalker<'ctx> { + /// Start a new walk with the walker reset to it's starting state. + fn new_walk(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<(), ()>; + } + + /// Object implementing the [`Recoverable`] protocol. + pub trait Object<'ctx> { + /// Visit with a recoverable walker. + /// + /// The visitor can then use the `walker` to try multiple different ways + /// of walking. + fn visit(&mut self, walker: &mut dyn RecoverableWalker<'ctx>) -> Result<(), ()>; + } + + impl Protocol for Recoverable { + type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>; + } + + impl Meta for Recoverable { + type Known<'a, 'ctx: 'a> = (); + + type Hint<'a, 'ctx: 'a> = (); + } +} + +pub mod owned { + use core::marker::PhantomData; + + use crate::{protocol::Protocol, walk::protocols::hint::Meta}; + + pub struct Owned<T: 'static>(PhantomData<fn() -> T>); + + pub trait Object<'ctx, T: 'static> { + fn visit(&mut self, value: T) -> Result<(), ()>; + } + + impl<T: 'static> Protocol for Owned<T> { + type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx, T>; + } + + impl<T: 'static> Meta for Owned<T> { + type Known<'a, 'ctx: 'a> = (); + + type Hint<'a, 'ctx: 'a> = (); + } +} + +pub mod borrowed { + use core::marker::PhantomData; + + use crate::{protocol::Protocol, walk::protocols::hint::Meta}; + + pub struct Borrowed<T: 'static>(PhantomData<fn() -> T>); + + pub enum Value<'a, 'ctx, T: 'static> { + Temp(&'a T), + Context(&'ctx T), + Static(&'static T), + } + + pub trait Object<'ctx, T: 'static> { + fn visit(&mut self, value: Value<'_, 'ctx, T>) -> Result<(), ()>; + } + + impl<T: 'static> Protocol for Borrowed<T> { + type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx, T>; + } + + pub enum Kind { + Temp, + Context, + Static, + } + + pub struct Known { + pub kind: Option<Kind>, + } + + pub struct Hint { + pub kind: Option<Kind>, + } + + impl<T: 'static> Meta for Borrowed<T> { + type Known<'a, 'ctx: 'a> = Known; + + type Hint<'a, 'ctx: 'a> = Hint; + } +} + +pub mod borrowed_mut { + use core::marker::PhantomData; + + use crate::{protocol::Protocol, walk::protocols::hint::Meta}; + + pub struct BorrowedMut<T: 'static>(PhantomData<fn() -> T>); + + pub enum Value<'a, 'ctx, T: 'static> { + Temp(&'a mut T), + Context(&'ctx mut T), + Static(&'static mut T), + } + + pub trait Object<'ctx, T: 'static> { + fn visit(&mut self, value: Value<'_, 'ctx, T>) -> Result<(), ()>; + } + + impl<T: 'static> Protocol for BorrowedMut<T> { + type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx, T>; + } + + pub enum Kind { + Temp, + Context, + Static, + } + + pub struct Known { + pub kind: Option<Kind>, + } + + pub struct Hint { + pub kind: Option<Kind>, + } + + impl<T: 'static> Meta for BorrowedMut<T> { + type Known<'a, 'ctx: 'a> = Known; + + type Hint<'a, 'ctx: 'a> = Hint; + } +} + +pub mod tagged { + use crate::{ + protocol::{Implementer, Protocol}, + walk::protocols::hint::Meta, + }; + + pub enum Tagged {} + + pub trait TaggedWalker<'ctx> { + fn walk_tag(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<(), ()>; + + fn walk_value(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<(), ()>; + } + + pub trait Object<'ctx> { + fn visit(&mut self, walker: &mut dyn TaggedWalker<'ctx>) -> Result<(), ()>; + } + + impl Protocol for Tagged { + type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>; + } + + impl Meta for Tagged { + type Known<'a, 'ctx: 'a> = (); + + type Hint<'a, 'ctx: 'a> = (); + } +} + +pub mod sequence { + use crate::{ + protocol::{Implementer, Protocol}, + walk::protocols::hint::Meta, + }; + + pub enum Sequence {} + + #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)] + pub enum Status { + Done, + Continue, + } + + pub trait SequenceWalker<'ctx> { + fn next(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<Status, ()>; + } + + pub trait Object<'ctx> { + fn visit(&mut self, walker: &mut dyn SequenceWalker<'ctx>) -> Result<(), ()>; + } + + impl Protocol for Sequence { + type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>; + } + + #[derive(Default)] + pub struct Known { + pub len: (usize, Option<usize>), + } + + pub struct Hint { + pub len: (usize, Option<usize>), + } + + impl Meta for Sequence { + type Known<'a, 'ctx: 'a> = Known; + + type Hint<'a, 'ctx: 'a> = Hint; + } +} + +pub mod map { + use crate::{ + protocol::{Implementer, Protocol}, + walk::protocols::hint::Meta, + }; + + pub enum Map {} + + #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)] + pub enum Status { + Done, + Continue, + } + + pub trait MapWalker<'ctx> { + fn next_key(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<Status, ()>; + + fn value(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<(), ()>; + } + + pub trait Object<'ctx> { + fn visit(&mut self, walker: &mut dyn MapWalker<'ctx>) -> Result<(), ()>; + } + + impl Protocol for Map { + type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>; + } + + #[derive(Default)] + pub struct Known { + pub len: (usize, Option<usize>), + } + + pub struct Hint { + pub len: (usize, Option<usize>), + } + + impl Meta for Map { + type Known<'a, 'ctx: 'a> = Known; + + type Hint<'a, 'ctx: 'a> = Hint; + } +} diff --git a/src/impls/core.rs b/src/impls/core.rs index 3cab3a0..162635e 100644 --- a/src/impls/core.rs +++ b/src/impls/core.rs @@ -1,5 +1,5 @@ pub mod bool; -pub mod iterator; +// pub mod iterator; // pub mod reference; // pub mod reference_mut; // pub mod str; diff --git a/src/impls/core/bool.rs b/src/impls/core/bool.rs index cdc1337..e1460ee 100644 --- a/src/impls/core/bool.rs +++ b/src/impls/core/bool.rs @@ -1,67 +1,17 @@ -use core::any::TypeId; - use crate::{ - build::{Build, Builder}, - implementer, - protocol::{Implementer, ImplementerExt}, - protocols::{bool, ControlFlow}, - walk::WalkOnce, + build::{builders::OwnedBuilder, Build}, + walk::walkers::OwnedCloneWalker, + Walk, }; #[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), - } - } - - fn accepts(id: core::any::TypeId) -> bool { - id == TypeId::of::<bool::Bool>() - } +impl<'ctx> Walk<'ctx> for bool { + type Walker = OwnedCloneWalker<Self>; } -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(()) - } +impl<'ctx> Build<'ctx> for bool { + type Builder = OwnedBuilder<Self>; } @@ -6,12 +6,15 @@ #[cfg(feature = "alloc")] extern crate alloc; -mod build; +pub mod build; pub mod impls; pub mod protocol; -pub mod protocols; +// pub mod protocols; pub mod transform; -mod walk; +pub mod walk; -pub use build::*; -pub use walk::*; +pub use build::Build; +pub use build::Builder; + +pub use walk::Walk; +pub use walk::Walker; diff --git a/src/protocol.rs b/src/protocol.rs index 2535449..124d270 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -1,13 +1,24 @@ -use core::any::{Any, TypeId}; +mod id; pub use any_implementation::AnyImpl; +pub use id::ProtocolId; -pub trait Protocol: Any { +pub trait Protocol: 'static { type Object<'a, 'ctx: 'a>; } +pub trait ProtocolExt: Protocol { + fn id() -> ProtocolId; +} + +impl<T: Protocol> ProtocolExt for T { + fn id() -> ProtocolId { + ProtocolId::of::<T>() + } +} + pub trait Implementer<'ctx> { - fn interface(&mut self, id: TypeId) -> Option<AnyImpl<'_, 'ctx>>; + fn interface(&mut self, id: ProtocolId) -> Option<AnyImpl<'_, 'ctx>>; } pub trait Implementation<'ctx, P: Protocol> { @@ -20,13 +31,13 @@ pub trait ImplementerExt<'ctx>: Implementer<'ctx> { 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>()) { + match self.interface(P::id()) { 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>() + P::id() ), }, None => None, @@ -42,9 +53,9 @@ macro_rules! implementer { } => { 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>> { + fn interface(&mut self, id: $crate::protocol::ProtocolId) -> ::core::option::Option<$crate::protocol::AnyImpl<'_, $ctx>> { match id { - $(id if id == ::core::any::TypeId::of::<$protocol>() => Some($crate::protocol::AnyImpl::new::<$protocol>(self)),)* + $(id if id == $crate::protocol::ProtocolId::of::<$protocol>() => Some($crate::protocol::AnyImpl::new::<$protocol>(self)),)* _ => None } } @@ -75,16 +86,16 @@ macro_rules! implementer { pub use implementer; mod any_implementation { - use core::{any::TypeId, marker::PhantomData, mem::MaybeUninit}; + use core::{marker::PhantomData, mem::MaybeUninit}; - use super::{Implementation, Protocol}; + use super::{Implementation, Protocol, ProtocolExt, ProtocolId}; trait ErasedImplementation<'ctx> {} const DYN_PTR_SIZE: usize = core::mem::size_of::<&mut dyn ErasedImplementation<'static>>(); pub struct AnyImpl<'a, 'ctx> { - id: TypeId, + id: ProtocolId, fat_ptr: MaybeUninit<[u8; DYN_PTR_SIZE]>, _marker: PhantomData<&'a mut dyn ErasedImplementation<'ctx>>, } @@ -92,7 +103,7 @@ mod any_implementation { impl<'a, 'ctx> AnyImpl<'a, 'ctx> { pub fn new<P: Protocol>(implementation: &'a mut dyn Implementation<'ctx, P>) -> Self { Self { - id: TypeId::of::<P>(), + id: P::id(), // 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(implementation) }, @@ -101,7 +112,7 @@ mod any_implementation { } pub fn downcast<P: Protocol>(self) -> Result<&'a mut dyn Implementation<'ctx, P>, Self> { - if self.id == TypeId::of::<P>() { + if self.id == P::id() { // 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. @@ -114,7 +125,7 @@ mod any_implementation { } } - pub fn id(&self) -> TypeId { + pub fn id(&self) -> ProtocolId { self.id } } diff --git a/src/protocol/id.rs b/src/protocol/id.rs new file mode 100644 index 0000000..f1a1723 --- /dev/null +++ b/src/protocol/id.rs @@ -0,0 +1,67 @@ +use core::any::TypeId; + +use super::Protocol; + +#[derive(Copy, Clone)] +pub struct ProtocolId { + id: fn() -> TypeId, + name: fn() -> &'static str, +} + +impl ProtocolId { + pub const fn of<P: Protocol>() -> Self { + Self { + id: || core::any::TypeId::of::<P>(), + name: || core::any::type_name::<P>(), + } + } + + fn id(&self) -> TypeId { + (self.id)() + } + + fn name(&self) -> &'static str { + (self.name)() + } +} + +impl core::fmt::Debug for ProtocolId { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ProtocolId") + .field("id", &self.id()) + .field("name", &self.name()) + .finish() + } +} + +impl core::fmt::Display for ProtocolId { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.name().fmt(f) + } +} + +impl PartialEq for ProtocolId { + fn eq(&self, other: &Self) -> bool { + self.id() == other.id() + } +} + +impl Eq for ProtocolId {} + +impl PartialOrd for ProtocolId { + fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for ProtocolId { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.id().cmp(&other.id()) + } +} + +impl core::hash::Hash for ProtocolId { + fn hash<H: core::hash::Hasher>(&self, state: &mut H) { + self.id().hash(state); + } +} diff --git a/src/protocols.rs b/src/protocols.rs index 3f1d597..e69de29 100644 --- a/src/protocols.rs +++ b/src/protocols.rs @@ -1,685 +0,0 @@ -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::{Implementer, Protocol}; - - use super::{hint::HintObject, ControlFlow}; - - pub trait Accessor<'ctx> { - 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 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 sequence { - use crate::protocol::{Implementer, Protocol}; - - #[derive(PartialEq)] - 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 { - pub min_len: Option<usize>, - pub max_len: Option<usize>, - } - - pub struct Known { - pub len: Option<usize>, - } - - pub trait Accessor<'ctx> { - fn next_key(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow; - fn value(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow; - } - - pub enum Map {} - - impl Protocol for Map { - type Hint<'walking, 'ctx: 'walking> = Hint; - - type Known<'walking, 'ctx: 'walking> = Known; - - type Accessor<'walking, 'ctx: 'walking> = &'walking mut dyn Accessor<'ctx>; - } -} - -pub mod reference { - use core::{any::Any, marker::PhantomData}; - - use crate::protocol::Protocol; - - pub enum Kind { - Walking, - Context, - Static, - } - - pub struct Hint { - pub kind: Option<Kind>, - - pub min_len: Option<usize>, - pub max_len: Option<usize>, - } - - pub struct Known { - pub kind: Option<Kind>, - - /// For dynamically sized types. - pub len: Option<usize>, - } - - pub enum Ref<'walking, 'ctx, T: ?Sized + Any> { - Walking(&'walking T), - Context(&'ctx T), - Static(&'static T), - } - - pub enum Mut<'walking, 'ctx, T: ?Sized + Any> { - Walking(&'walking mut T), - Context(&'ctx mut T), - Static(&'static mut T), - } - - pub struct Reference<T: ?Sized + Any>(PhantomData<fn() -> T>); - - pub struct ReferenceMut<T: ?Sized + Any>(PhantomData<fn() -> T>); - - impl<T: ?Sized + Any> Protocol for Reference<T> { - type Hint<'walking, 'ctx: 'walking> = Hint; - - 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<'walking, 'ctx: 'walking> = Hint; - - 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 325b9ec..5fbcb79 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -1,6 +1,7 @@ use crate::{ build::{Build, Builder}, - walk::{Walk, WalkMut, WalkOnce}, + walk::Walk, + Walker, }; #[derive(thiserror::Error, Debug)] @@ -14,36 +15,14 @@ pub enum Either<A, B> { pub fn from<'ctx, U, T>( value: T, -) -> Result<U, Either<T::Error, <U::Builder as Builder<'ctx>>::Error>> +) -> Result<U, Either<<T::Walker as Walker<'ctx>>::Error, <U::Builder as Builder<'ctx>>::Error>> where - T: WalkOnce<'ctx>, + T: Walk<'ctx>, U: Build<'ctx>, { let mut builder = U::Builder::default(); - value.walk_once(builder.as_visitor()).map_err(Either::A)?; - builder.build().map_err(Either::B) -} - -pub fn from_mut<'a, 'ctx, U, T>( - value: &'a mut T, -) -> Result<U, Either<T::Error, <U::Builder as Builder<'ctx>>::Error>> -where - T: WalkMut<'a, 'ctx>, - U: Build<'ctx>, -{ - let mut builder = U::Builder::default(); - value.walk_mut(builder.as_visitor()).map_err(Either::A)?; - builder.build().map_err(Either::B) -} - -pub fn from_ref<'a, 'ctx, U, T>( - value: &'a T, -) -> Result<U, Either<T::Error, <U::Builder as Builder<'ctx>>::Error>> -where - T: Walk<'a, 'ctx>, - U: Build<'ctx>, -{ - let mut builder = U::Builder::default(); - value.walk(builder.as_visitor()).map_err(Either::A)?; + T::Walker::from(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 9d218b1..8f3907e 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -1,20 +1,15 @@ -use crate::protocol::Implementer; +pub mod protocols; +pub mod walkers; -pub trait WalkOnce<'ctx> { - type Error; - type Value; +use crate::protocol::Implementer; - fn walk_once(self, visitor: &mut dyn Implementer<'ctx>) -> Result<Self::Value, Self::Error>; +pub trait Walk<'ctx>: Sized { + type Walker: Walker<'ctx> + From<Self>; } -pub trait WalkMut<'borrow, 'ctx>: WalkOnce<'ctx> { - fn walk_mut( - &'borrow mut self, - visitor: &mut dyn Implementer<'ctx>, - ) -> Result<Self::Value, Self::Error>; -} +pub trait Walker<'ctx> { + type Error; + type Value; -pub trait Walk<'borrow, 'ctx>: WalkMut<'borrow, 'ctx> { - fn walk(&'borrow self, visitor: &mut dyn Implementer<'ctx>) - -> Result<Self::Value, Self::Error>; + fn walk(self, visitor: &mut dyn Implementer<'ctx>) -> Result<Self::Value, Self::Error>; } diff --git a/src/walk/protocols.rs b/src/walk/protocols.rs new file mode 100644 index 0000000..39e5faa --- /dev/null +++ b/src/walk/protocols.rs @@ -0,0 +1,43 @@ +pub mod hint { + use crate::protocol::{Implementer, Protocol}; + + /// Protocol for giving a hint to a walker. + /// + /// This protocol is implemented by walkers. + /// + /// A hint is for a particular protocol `P`. + pub struct Hint<P: Meta>(P); + + /// Meta information for the hint. + /// + /// This gives the visitor more information to work from when selecting a hint. + pub trait Meta: Protocol { + /// Information known by the walker. + /// + /// This should be information easy to get without changing the state of the walker + /// in a irreversable way. + type Known<'a, 'ctx: 'a>; + + /// Extra information the visitor can give to the walker about what it is expecting. + type Hint<'a, 'ctx: 'a>; + } + + /// Object implementing the [`Hint`] protocol. + pub trait Object<'ctx, P: Meta> { + /// Hint to the walker to use the `P` protocol. + /// + /// This should only be called once per [`RequestHint`]. + fn hint( + &mut self, + visitor: &mut dyn Implementer<'ctx>, + hint: P::Hint<'_, 'ctx>, + ) -> Result<(), ()>; + + /// Ask the walker for information about it's support of the protocol. + fn known(&mut self, hint: &P::Hint<'_, 'ctx>) -> Result<P::Known<'_, 'ctx>, ()>; + } + + impl<P: Meta> Protocol for Hint<P> { + type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx, P>; + } +} diff --git a/src/walk/walkers.rs b/src/walk/walkers.rs new file mode 100644 index 0000000..b4dd2cd --- /dev/null +++ b/src/walk/walkers.rs @@ -0,0 +1,11 @@ +use crate::protocol::ProtocolId; + +mod owned; +mod owned_clone; + +pub use owned::*; +pub use owned_clone::*; + +#[derive(thiserror::Error, Debug)] +#[error("The visitor is missing protocol: {0}")] +pub struct MissingProtocol(pub ProtocolId); diff --git a/src/walk/walkers/owned.rs b/src/walk/walkers/owned.rs new file mode 100644 index 0000000..6703625 --- /dev/null +++ b/src/walk/walkers/owned.rs @@ -0,0 +1,41 @@ +use crate::{ + build::protocols, + protocol::{Implementer, ImplementerExt, ProtocolExt}, + Walker, +}; + +use super::MissingProtocol; + +pub struct OwnedWalker<T> { + value: T, +} + +impl<T> OwnedWalker<T> { + pub const fn new(value: T) -> Self { + Self { value } + } +} + +impl<T> From<T> for OwnedWalker<T> { + fn from(value: T) -> Self { + Self::new(value) + } +} + +impl<'ctx, T: 'static> Walker<'ctx> for OwnedWalker<T> { + type Error = (MissingProtocol, T); + + type Value = (); + + fn walk(self, visitor: &mut dyn Implementer<'ctx>) -> Result<Self::Value, Self::Error> { + if let Some(interface) = visitor.interface_for::<protocols::owned::Owned<T>>() { + let _ = interface.as_object().visit(self.value); + Ok(()) + } else { + Err(( + MissingProtocol(protocols::owned::Owned::<T>::id()), + self.value, + )) + } + } +} diff --git a/src/walk/walkers/owned_clone.rs b/src/walk/walkers/owned_clone.rs new file mode 100644 index 0000000..27a323e --- /dev/null +++ b/src/walk/walkers/owned_clone.rs @@ -0,0 +1,217 @@ +use crate::build::protocols; +use crate::protocol::Implementer; +use crate::protocol::{ImplementerExt, ProtocolExt}; +use crate::{implementer, walk, Walker}; + +use super::MissingProtocol; + +pub struct OwnedCloneWalker<T> { + value: Option<T>, + error: Option<MissingProtocol>, + hint_given: bool, +} + +impl<T> OwnedCloneWalker<T> { + pub const fn new(value: T) -> Self { + Self { + value: Some(value), + error: None, + hint_given: false, + } + } +} + +impl<T> From<T> for OwnedCloneWalker<T> { + fn from(value: T) -> Self { + Self::new(value) + } +} + +impl<'ctx, T: 'static + Clone> Walker<'ctx> for OwnedCloneWalker<T> { + type Error = MissingProtocol; + + type Value = (); + + fn walk(mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<Self::Value, Self::Error> { + // Request the visitor give a hint. + // This allows the use of the recoverable protocol. + if let Some(interface) = visitor.interface_for::<protocols::hint::RequestHint>() { + match interface.as_object().request_hint(&mut self) { + Ok(()) => {} + Err(()) => { + return match self.error { + Some(err) => Err(err), + None => Ok(()), + }; + } + } + } + + // If no hint was given then just use the owned protocol. + if !self.hint_given { + let _ = walk::protocols::hint::Object::<protocols::owned::Owned<T>>::hint( + &mut self, + visitor, + (), + ); + } + + // Return an error if there was one. + match self.error { + Some(err) => Err(err), + None => Ok(()), + } + } +} + +implementer! { + impl['ctx, T: 'static + Clone] OwnedCloneWalker<T> = [ + walk::protocols::hint::Hint<protocols::owned::Owned<T>>, + walk::protocols::hint::Hint<protocols::recoverable::Recoverable>, + walk::protocols::hint::Hint<protocols::borrowed::Borrowed<T>>, + walk::protocols::hint::Hint<protocols::borrowed_mut::BorrowedMut<T>>, + ]; +} + +impl<'ctx, T: 'static + Clone> walk::protocols::hint::Object<'ctx, protocols::owned::Owned<T>> + for OwnedCloneWalker<T> +{ + fn hint(&mut self, visitor: &mut dyn Implementer<'ctx>, _hint: ()) -> Result<(), ()> { + self.hint_given = true; + + if let Some(interface) = visitor.interface_for::<protocols::owned::Owned<T>>() { + // If this happens it means the value was already visited and consumed. + let Some(value) = self.value.take() else { + return Ok(()); // We return Ok because the walker isn't in an error state. + }; + + // Visit the value. + interface.as_object().visit(value) + } else { + self.error = Some(MissingProtocol(protocols::owned::Owned::<T>::id())); + Err(()) + } + } + + fn known(&mut self, _hint: &()) -> Result<(), ()> { + Ok(()) + } +} + +impl<'ctx, T: 'static + Clone> walk::protocols::hint::Object<'ctx, protocols::borrowed::Borrowed<T>> + for OwnedCloneWalker<T> +{ + fn hint( + &mut self, + visitor: &mut dyn Implementer<'ctx>, + _hint: protocols::borrowed::Hint, + ) -> Result<(), ()> { + self.hint_given = true; + + if let Some(interface) = visitor.interface_for::<protocols::borrowed::Borrowed<T>>() { + // If this happens it means the value was already visited and consumed. + let Some(value) = &self.value else { + return Ok(()); // We return Ok because the walker isn't in an error state. + }; + + // Visit the value. + interface.as_object().visit(protocols::borrowed::Value::Temp(value)) + } else { + self.error = Some(MissingProtocol(protocols::owned::Owned::<T>::id())); + Err(()) + } + } + + fn known( + &mut self, + _hint: &protocols::borrowed::Hint, + ) -> Result<protocols::borrowed::Known, ()> { + Ok(protocols::borrowed::Known { + kind: Some(protocols::borrowed::Kind::Temp), + }) + } +} + +impl<'ctx, T: 'static + Clone> walk::protocols::hint::Object<'ctx, protocols::borrowed_mut::BorrowedMut<T>> + for OwnedCloneWalker<T> +{ + fn hint( + &mut self, + visitor: &mut dyn Implementer<'ctx>, + _hint: protocols::borrowed_mut::Hint, + ) -> Result<(), ()> { + self.hint_given = true; + + if let Some(interface) = visitor.interface_for::<protocols::borrowed_mut::BorrowedMut<T>>() { + // If this happens it means the value was already visited and consumed. + let Some(value) = &mut self.value else { + return Ok(()); // We return Ok because the walker isn't in an error state. + }; + + // Visit the value. + interface.as_object().visit(protocols::borrowed_mut::Value::Temp(value)) + } else { + self.error = Some(MissingProtocol(protocols::owned::Owned::<T>::id())); + Err(()) + } + } + + fn known( + &mut self, + _hint: &protocols::borrowed_mut::Hint, + ) -> Result<protocols::borrowed_mut::Known, ()> { + Ok(protocols::borrowed_mut::Known { + kind: Some(protocols::borrowed_mut::Kind::Temp), + }) + } +} + +impl<'ctx, T: 'static + Clone> + walk::protocols::hint::Object<'ctx, protocols::recoverable::Recoverable> + for OwnedCloneWalker<T> +{ + fn hint(&mut self, visitor: &mut dyn Implementer<'ctx>, _hint: ()) -> Result<(), ()> { + self.hint_given = true; + + if let Some(interface) = visitor.interface_for::<protocols::recoverable::Recoverable>() { + // This walker is already recoverable. + interface.as_object().visit(self) + } else { + self.error = Some(MissingProtocol(protocols::recoverable::Recoverable::id())); + Err(()) + } + } + + fn known(&mut self, _hint: &()) -> Result<(), ()> { + Ok(()) + } +} + +impl<'ctx, T: 'static + Clone> protocols::recoverable::RecoverableWalker<'ctx> + for OwnedCloneWalker<T> +{ + fn new_walk(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<(), ()> { + // Short circuit if the walker has an error. + if self.error.is_some() { + return Err(()); + } + + // Short circuit if the walker doesn't have a value. + // If this happens it means the value was already visited and consumed. + let Some(value) = &self.value else { + return Ok(()); // We return Ok because the walker isn't in an error state. + }; + + // Clone the value to put into a new walker instance. + let walker = Self::new(value.clone()); + + // Walk the walker. + match walker.walk(visitor) { + Ok(()) => Ok(()), // We don't know if the visitor had an issue. + Err(err) => { + self.error = Some(err); + Err(()) + } + } + } +} diff --git a/tests/demo.rs b/tests/demo.rs index 900ba42..6875f89 100644 --- a/tests/demo.rs +++ b/tests/demo.rs @@ -59,8 +59,8 @@ impl<'ctx> Builder<'ctx> for StringBuilder { } fn accepts(id: TypeId) -> bool { - id == TypeId::of::<uniserde::protocols::sequence::Sequence>() || - id == TypeId::of::<uniserde::protocols::bool::Bool>() + id == TypeId::of::<uniserde::protocols::sequence::Sequence>() + || id == TypeId::of::<uniserde::protocols::bool::Bool>() } } @@ -69,11 +69,14 @@ implementer! { } impl<'ctx> uniserde::protocols::sequence::Object<'ctx> for StringBuilder { - fn visit(&mut self, accessor: &mut dyn sequence::Accessor<'ctx>) -> uniserde::protocols::ControlFlow { + fn visit( + &mut self, + accessor: &mut dyn sequence::Accessor<'ctx>, + ) -> uniserde::protocols::ControlFlow { self.0.push('['); loop { if accessor.next(self) != uniserde::protocols::sequence::ControlFlow::Continue { - break + break; } self.0.push_str(", "); } |