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