split up protocols and make Owned a protocol
Konnor Andrews 2024-01-25
parent 5fba976 · commit 24bc7f1
-rw-r--r--src/build.rs7
-rw-r--r--src/build/builders.rs7
-rw-r--r--src/build/builders/owned.rs56
-rw-r--r--src/build/protocols.rs289
-rw-r--r--src/impls/core.rs2
-rw-r--r--src/impls/core/bool.rs64
-rw-r--r--src/lib.rs13
-rw-r--r--src/protocol.rs37
-rw-r--r--src/protocol/id.rs67
-rw-r--r--src/protocols.rs685
-rw-r--r--src/transform.rs35
-rw-r--r--src/walk.rs23
-rw-r--r--src/walk/protocols.rs43
-rw-r--r--src/walk/walkers.rs11
-rw-r--r--src/walk/walkers/owned.rs41
-rw-r--r--src/walk/walkers/owned_clone.rs217
-rw-r--r--tests/demo.rs11
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>;
}
diff --git a/src/lib.rs b/src/lib.rs
index 1a7aef4..703db86 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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(", ");
}