simplified API
Konnor Andrews 2024-01-16
parent f9d00cf · commit 8bbab64
-rw-r--r--src/build.rs4
-rw-r--r--src/impls/core.rs7
-rw-r--r--src/impls/core/bool.rs61
-rw-r--r--src/impls/core/iterator.rs73
-rw-r--r--src/impls/core/reference.rs139
-rw-r--r--src/impls/core/reference_mut.rs82
-rw-r--r--src/impls/core/str.rs45
-rw-r--r--src/lib.rs100
-rw-r--r--src/protocol.rs341
-rw-r--r--src/protocols.rs611
-rw-r--r--src/transform.rs2
-rw-r--r--src/walk.rs12
-rw-r--r--tests/demo.rs77
13 files changed, 982 insertions, 572 deletions
diff --git a/src/build.rs b/src/build.rs
index 8b34512..1c28354 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -1,4 +1,4 @@
-use crate::Visitor;
+use crate::protocol::Implementer;
/// A type buildable from a walker.
pub trait Build<'ctx> {
@@ -14,7 +14,7 @@ pub trait Builder<'ctx>: Default {
type Value;
/// As a visitor.
- fn as_visitor(&mut self) -> &mut dyn Visitor<'ctx>;
+ fn as_visitor(&mut self) -> &mut dyn Implementer<'ctx>;
/// Finish the value.
fn build(self) -> Result<Self::Value, Self::Error>;
diff --git a/src/impls/core.rs b/src/impls/core.rs
index 303fdfd..3cab3a0 100644
--- a/src/impls/core.rs
+++ b/src/impls/core.rs
@@ -1,4 +1,5 @@
+pub mod bool;
pub mod iterator;
-pub mod reference;
-pub mod reference_mut;
-pub mod str;
+// pub mod reference;
+// pub mod reference_mut;
+// pub mod str;
diff --git a/src/impls/core/bool.rs b/src/impls/core/bool.rs
new file mode 100644
index 0000000..2e3aba9
--- /dev/null
+++ b/src/impls/core/bool.rs
@@ -0,0 +1,61 @@
+use crate::{
+ build::{Build, Builder},
+ implementer,
+ protocol::{ImplementerExt, Implementer},
+ protocols::{bool, ControlFlow},
+ walk::WalkOnce,
+};
+
+#[derive(thiserror::Error, Debug)]
+#[error("The value is complete.")]
+pub struct IncompleteValue;
+
+#[derive(Default)]
+pub struct BoolBuilder(Option<bool>);
+
+impl<'ctx> Build<'ctx> for bool {
+ type Builder = BoolBuilder;
+}
+
+impl<'ctx> Builder<'ctx> for BoolBuilder {
+ type Error = IncompleteValue;
+
+ type Value = bool;
+
+ fn as_visitor(&mut self) -> &mut dyn crate::protocol::Implementer<'ctx> {
+ self
+ }
+
+ fn build(self) -> Result<Self::Value, Self::Error> {
+ match self.0 {
+ Some(value) => Ok(value),
+ None => Err(IncompleteValue),
+ }
+ }
+}
+
+implementer! {
+ impl['ctx] BoolBuilder = [bool::Bool];
+}
+
+impl<'ctx> bool::Object<'ctx> for BoolBuilder {
+ fn visit(&mut self, value: bool) -> crate::protocols::ControlFlow {
+ self.0 = Some(value);
+ ControlFlow::Done
+ }
+}
+
+impl<'ctx> WalkOnce<'ctx> for bool {
+ type Error = ();
+
+ type Value = ();
+
+ #[inline]
+ fn walk_once(self, visitor: &mut dyn Implementer<'ctx>) -> Result<Self::Value, Self::Error> {
+ if let Some(interface) = visitor.interface_for::<bool::Bool>() {
+ interface.as_object().visit(self);
+ }
+
+ Ok(())
+ }
+}
diff --git a/src/impls/core/iterator.rs b/src/impls/core/iterator.rs
index 1bd39b6..cdcd71b 100644
--- a/src/impls/core/iterator.rs
+++ b/src/impls/core/iterator.rs
@@ -1,49 +1,76 @@
-use crate::{Walker, ControlFlow, walk::WalkOnce, protocol::lookup_visit, protocols::sequence};
+use crate::protocol::ImplementerExt;
+use crate::protocols::{sequence, ControlFlow};
+use crate::walk::WalkOnce;
-pub struct IterWalker<I> {
+pub struct IterWalker<'ctx, I>
+where
+ I: Iterator,
+ <I as Iterator>::Item: WalkOnce<'ctx>,
+{
iter: I,
+ err: Option<<<I as Iterator>::Item as WalkOnce<'ctx>>::Error>,
}
-impl<I> IterWalker<I>{
+impl<'ctx, I> IterWalker<'ctx, I>
+where
+ I: Iterator,
+ <I as Iterator>::Item: WalkOnce<'ctx>,
+{
pub fn new<T: IntoIterator<IntoIter = I>>(iter: T) -> Self {
Self {
- iter: iter.into_iter()
+ iter: iter.into_iter(),
+ err: None,
}
}
}
-impl<'ctx, I> Walker<'ctx> for IterWalker<I>
+impl<'ctx, I> WalkOnce<'ctx> for IterWalker<'ctx, I>
where
I: Iterator,
- <I as Iterator>::Item: WalkOnce<'ctx>
+ <I as Iterator>::Item: WalkOnce<'ctx>,
{
- fn walk(&mut self, visitor: &mut dyn crate::Visitor<'ctx>) -> ControlFlow {
- match lookup_visit::<sequence::Sequence, _>(visitor) {
- Ok(visit) => {
- visit.visit(self).to_done()
- },
- Err(err) => {
- ControlFlow::Error
- },
+ type Error = <<I as Iterator>::Item as WalkOnce<'ctx>>::Error;
+
+ type Value = ();
+
+ #[inline]
+ fn walk_once(
+ mut self,
+ visitor: &mut dyn crate::protocol::Implementer<'ctx>,
+ ) -> Result<Self::Value, Self::Error> {
+ if let Some(interface) = visitor.interface_for::<sequence::Sequence>() {
+ match interface.as_object().visit(&mut self) {
+ ControlFlow::Done => Ok(()),
+ ControlFlow::Error => match self.err {
+ Some(err) => Err(err),
+ None => Ok(()),
+ },
+ }
+ } else {
+ Ok(())
}
}
}
-impl<'ctx, I> sequence::Accessor<'ctx> for IterWalker<I>
+impl<'ctx, I> sequence::Accessor<'ctx> for IterWalker<'ctx, I>
where
I: Iterator,
- <I as Iterator>::Item: WalkOnce<'ctx>
+ <I as Iterator>::Item: WalkOnce<'ctx>,
{
- fn next(&mut self, visitor: &mut dyn crate::Visitor<'ctx>) -> ControlFlow {
- if let Some(value) = self.iter.next() {
- match value.walk_once(visitor) {
- Ok(_) => ControlFlow::Continue,
+ fn next(
+ &mut self,
+ visitor: &mut dyn crate::protocol::Implementer<'ctx>,
+ ) -> sequence::ControlFlow {
+ if let Some(item) = self.iter.next() {
+ match item.walk_once(visitor) {
+ Ok(_) => sequence::ControlFlow::Continue,
Err(err) => {
- ControlFlow::Error
- },
+ self.err = Some(err);
+ sequence::ControlFlow::Error
+ }
}
} else {
- ControlFlow::Done
+ sequence::ControlFlow::Done
}
}
}
diff --git a/src/impls/core/reference.rs b/src/impls/core/reference.rs
index 4016a26..0f5038d 100644
--- a/src/impls/core/reference.rs
+++ b/src/impls/core/reference.rs
@@ -1,15 +1,19 @@
use core::any::Any;
use crate::{
- protocol::{lookup_visit, VisitorMissingProtocol, WalkerMissingProtocol, lookup_hint, ProtocolId, AnyVisit, Visit},
- protocols::reference,
- walk::{WalkMut, WalkOnce, Walk},
- Visitor, Walker, ControlFlow, build::{Builder, Build},
+ build::{Build, Builder},
+ protocol::{
+ lookup_hint, lookup_visit, AnyHint, AnyVisit, Hint, ProtocolId, Visit,
+ VisitorMissingProtocol, WalkerMissingProtocol,
+ },
+ protocols::{recoverable, reference},
+ walk::{Walk, WalkMut, WalkOnce},
+ ControlFlow, Visitor, Walker,
};
impl<'borrow, 'ctx, T> WalkOnce<'ctx> for &'borrow T
where
- T: Walk<'borrow, 'ctx>
+ T: Walk<'borrow, 'ctx>,
{
type Error = T::Error;
@@ -20,18 +24,21 @@ where
}
}
-impl<'borrow, 'a, 'ctx, T> WalkMut<'borrow, 'ctx> for &'a T
-where
- T: Walk<'a, 'ctx>
+impl<'borrow, 'a, 'ctx, T> WalkMut<'borrow, 'ctx> for &'a T
+where
+ T: Walk<'a, 'ctx>,
{
- fn walk_mut(&'borrow mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> {
+ fn walk_mut(
+ &'borrow mut self,
+ visitor: &mut dyn Visitor<'ctx>,
+ ) -> Result<Self::Value, Self::Error> {
T::walk(self, visitor)
}
}
-impl<'borrow, 'a, 'ctx, T> Walk<'borrow, 'ctx> for &'a T
+impl<'borrow, 'a, 'ctx, T> Walk<'borrow, 'ctx> for &'a T
where
- T: Walk<'a, 'ctx>
+ T: Walk<'a, 'ctx>,
{
fn walk(&'borrow self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> {
T::walk(self, visitor)
@@ -49,27 +56,88 @@ pub struct RefWalker<'ctx, T: ?Sized> {
impl<'ctx, T: ?Sized> RefWalker<'ctx, T> {
pub fn new(value: &'ctx T) -> Self {
- Self {
- value,
- error: None,
+ Self { value, error: None }
+ }
+}
+
+impl<'ctx, T: ?Sized + Any> WalkOnce<'ctx> for RefWalker<'ctx, T> {
+ type Error = VisitorMissingProtocol;
+
+ type Value = ();
+
+ fn walk_once(mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> {
+ match visitor.request_hint(&mut self, false) {
+ ControlFlow::Continue => {
+ Hint::<reference::Reference<T>>::hint(
+ &mut self,
+ visitor,
+ reference::Hint {
+ kind: None,
+ min_len: None,
+ max_len: None,
+ },
+ );
+ }
+ _ => {}
+ }
+
+ if let Some(err) = self.error {
+ Err(err)
+ } else {
+ Ok(())
}
}
+}
- pub fn into_error(self) -> Option<VisitorMissingProtocol> {
- self.error
+impl<'ctx, T: ?Sized + Any> Walker<'ctx> for RefWalker<'ctx, T> {
+ fn protocol(&mut self, id: ProtocolId) -> Option<crate::protocol::AnyHint<'_, 'ctx>> {
+ if id == ProtocolId::of::<reference::Reference<T>>() {
+ Some(AnyHint::new::<reference::Reference<T>>(self))
+ } else if id == ProtocolId::of::<reference::Reference<T>>() {
+ Some(AnyHint::new::<recoverable::Recoverable>(self))
+ } else {
+ None
+ }
}
}
-impl<'ctx:, T: ?Sized + Any> Walker<'ctx> for RefWalker<'ctx, T> {
- fn walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow {
+impl<'ctx, T: ?Sized + Any> Hint<'ctx, reference::Reference<T>> for RefWalker<'ctx, T> {
+ fn hint(&mut self, visitor: &mut dyn Visitor<'ctx>, _hint: reference::Hint) -> ControlFlow {
match lookup_visit::<reference::Reference<T>, _>(visitor) {
Ok(visit) => visit.visit(reference::Ref::Context(self.value)).to_done(),
Err(err) => {
self.error = Some(err);
ControlFlow::Error
- },
+ }
+ }
+ }
+
+ fn known(&mut self, _hint: &reference::Hint) -> reference::Known {
+ reference::Known {
+ kind: Some(reference::Kind::Context),
+ len: None,
+ }
+ }
+}
+
+impl<'ctx, T: ?Sized + Any> Hint<'ctx, recoverable::Recoverable> for RefWalker<'ctx, T> {
+ fn hint(&mut self, visitor: &mut dyn Visitor<'ctx>, _hint: ()) -> ControlFlow {
+ match lookup_visit::<recoverable::Recoverable, _>(visitor) {
+ Ok(visit) => visit.visit(self).to_done(),
+ Err(err) => {
+ self.error = Some(err);
+ ControlFlow::Error
+ }
}
}
+
+ fn known(&mut self, _hint: &()) {}
+}
+
+impl<'ctx, T: ?Sized + Any> recoverable::Accessor<'ctx> for RefWalker<'ctx, T> {
+ fn new_walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow {
+ todo!()
+ }
}
#[derive(thiserror::Error, Debug)]
@@ -81,7 +149,7 @@ pub enum Error {
ShortLifetime,
#[error(transparent)]
- MissingProtocol(#[from] WalkerMissingProtocol)
+ MissingProtocol(#[from] WalkerMissingProtocol),
}
pub struct RefBuilder<'ctx, T: ?Sized> {
@@ -115,19 +183,22 @@ impl<'ctx, T: ?Sized + Any> Builder<'ctx> for RefBuilder<'ctx, T> {
impl<'ctx, T: ?Sized + Any> Visitor<'ctx> for RefBuilder<'ctx, T> {
fn request_hint(
&mut self,
- hints: &mut dyn crate::WalkerHints<'ctx>,
+ hints: &mut dyn crate::Walker<'ctx>,
_need_hint: bool,
) -> ControlFlow {
match lookup_hint::<reference::Reference<T>, _>(hints) {
- Ok(hint) => hint.hint(self, reference::Hint {
- kind: Some(reference::Kind::Context),
- min_len: None,
- max_len: None,
- }),
+ Ok(hint) => hint.hint(
+ self,
+ reference::Hint {
+ kind: Some(reference::Kind::Context),
+ min_len: None,
+ max_len: None,
+ },
+ ),
Err(err) => {
self.value = Some(Err(err.into()));
ControlFlow::Error
- },
+ }
}
}
@@ -148,12 +219,11 @@ impl<'ctx, T: ?Sized + Any> Visit<'ctx, reference::Reference<T>> for RefBuilder<
reference::Ref::Walking(_) => {
self.value = Some(Err(Error::ShortLifetime));
ControlFlow::Error
- },
- reference::Ref::Context(value) |
- reference::Ref::Static(value) => {
+ }
+ reference::Ref::Context(value) | reference::Ref::Static(value) => {
self.value = Some(Ok(value));
ControlFlow::Done
- },
+ }
}
}
}
@@ -164,12 +234,11 @@ impl<'ctx, T: ?Sized + Any> Visit<'ctx, reference::ReferenceMut<T>> for RefBuild
reference::Mut::Walking(_) => {
self.value = Some(Err(Error::ShortLifetime));
ControlFlow::Error
- },
- reference::Mut::Context(value) |
- reference::Mut::Static(value) => {
+ }
+ reference::Mut::Context(value) | reference::Mut::Static(value) => {
self.value = Some(Ok(value));
ControlFlow::Done
- },
+ }
}
}
}
diff --git a/src/impls/core/reference_mut.rs b/src/impls/core/reference_mut.rs
index 5f0eff7..98427fe 100644
--- a/src/impls/core/reference_mut.rs
+++ b/src/impls/core/reference_mut.rs
@@ -1,15 +1,19 @@
use core::any::Any;
use crate::{
- protocol::{lookup_visit, VisitorMissingProtocol, WalkerMissingProtocol, lookup_hint, ProtocolId, AnyVisit, Visit},
+ build::{Build, Builder},
+ protocol::{
+ lookup_hint, lookup_visit, AnyVisit, ProtocolId, Visit, VisitorMissingProtocol,
+ WalkerMissingProtocol,
+ },
protocols::reference,
- walk::{WalkMut, WalkOnce, Walk},
- Visitor, Walker, ControlFlow, build::{Builder, Build},
+ walk::{Walk, WalkMut, WalkOnce},
+ ControlFlow, Visitor, Walker,
};
impl<'borrow, 'ctx, T> WalkOnce<'ctx> for &'borrow mut T
where
- T: WalkMut<'borrow, 'ctx>
+ T: WalkMut<'borrow, 'ctx>,
{
type Error = T::Error;
@@ -20,18 +24,21 @@ where
}
}
-impl<'borrow, 'ctx, T> WalkMut<'borrow, 'ctx> for &'borrow mut T
-where
- T: WalkMut<'borrow, 'ctx>
+impl<'borrow, 'ctx, T> WalkMut<'borrow, 'ctx> for &'borrow mut T
+where
+ T: WalkMut<'borrow, 'ctx>,
{
- fn walk_mut(&'borrow mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> {
+ fn walk_mut(
+ &'borrow mut self,
+ visitor: &mut dyn Visitor<'ctx>,
+ ) -> Result<Self::Value, Self::Error> {
T::walk_mut(self, visitor)
}
}
-impl<'borrow, 'ctx, T> Walk<'borrow, 'ctx> for &'borrow mut T
-where
- T: Walk<'borrow, 'ctx>
+impl<'borrow, 'ctx, T> Walk<'borrow, 'ctx> for &'borrow mut T
+where
+ T: Walk<'borrow, 'ctx>,
{
fn walk(&'borrow self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> {
T::walk(self, visitor)
@@ -44,35 +51,27 @@ impl<'ctx, T: ?Sized + Any> Build<'ctx> for &'ctx mut T {
pub struct MutWalker<'ctx, T: ?Sized> {
value: Option<&'ctx mut T>,
- error: Option<VisitorMissingProtocol>,
}
impl<'ctx, T: ?Sized> MutWalker<'ctx, T> {
pub fn new(value: &'ctx mut T) -> Self {
Self {
value: Some(value),
- error: None,
}
}
-
- pub fn into_error(self) -> Option<VisitorMissingProtocol> {
- self.error
- }
}
-impl<'ctx:, T: ?Sized + Any> Walker<'ctx> for MutWalker<'ctx, T> {
- fn walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow {
+impl<'ctx, T: ?Sized + Any> WalkOnce<'ctx> for MutWalker<'ctx, T> {
+ type Error = VisitorMissingProtocol;
+
+ type Value = ();
+
+ fn walk_once(mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> {
if let Some(value) = self.value.take() {
- match lookup_visit::<reference::ReferenceMut<T>, _>(visitor) {
- Ok(visit) => visit.visit(reference::Mut::Context(value)).to_done(),
- Err(err) => {
- self.error = Some(err);
- ControlFlow::Continue
- },
- }
- } else {
- ControlFlow::Done
+ let visit = lookup_visit::<reference::ReferenceMut<T>, _>(visitor)?;
+ visit.visit(reference::Mut::Context(value));
}
+ Ok(())
}
}
@@ -85,7 +84,7 @@ pub enum Error {
ShortLifetime,
#[error(transparent)]
- MissingProtocol(#[from] WalkerMissingProtocol)
+ MissingProtocol(#[from] WalkerMissingProtocol),
}
pub struct MutBuilder<'ctx, T: ?Sized> {
@@ -119,19 +118,22 @@ impl<'ctx, T: ?Sized + Any> Builder<'ctx> for MutBuilder<'ctx, T> {
impl<'ctx, T: ?Sized + Any> Visitor<'ctx> for MutBuilder<'ctx, T> {
fn request_hint(
&mut self,
- hints: &mut dyn crate::WalkerHints<'ctx>,
+ hints: &mut dyn crate::Walker<'ctx>,
_need_hint: bool,
) -> ControlFlow {
match lookup_hint::<reference::Reference<T>, _>(hints) {
- Ok(hint) => hint.hint(self, reference::Hint {
- kind: Some(reference::Kind::Context),
- min_len: None,
- max_len: None,
- }),
+ Ok(hint) => hint.hint(
+ self,
+ reference::Hint {
+ kind: Some(reference::Kind::Context),
+ min_len: None,
+ max_len: None,
+ },
+ ),
Err(err) => {
self.value = Some(Err(err.into()));
ControlFlow::Error
- },
+ }
}
}
@@ -150,13 +152,11 @@ impl<'ctx, T: ?Sized + Any> Visit<'ctx, reference::ReferenceMut<T>> for MutBuild
reference::Mut::Walking(_) => {
self.value = Some(Err(Error::ShortLifetime));
ControlFlow::Continue
- },
- reference::Mut::Context(value) |
- reference::Mut::Static(value) => {
+ }
+ reference::Mut::Context(value) | reference::Mut::Static(value) => {
self.value = Some(Ok(value));
ControlFlow::Done
- },
+ }
}
-
}
}
diff --git a/src/impls/core/str.rs b/src/impls/core/str.rs
index e09b219..0ff2de8 100644
--- a/src/impls/core/str.rs
+++ b/src/impls/core/str.rs
@@ -1,4 +1,8 @@
-use crate::{walk::{Walk, WalkOnce, WalkMut}, protocol::VisitorMissingProtocol, Walker, Visitor};
+use crate::{
+ protocol::VisitorMissingProtocol,
+ walk::{Walk, WalkMut, WalkOnce},
+ Visitor, Walker,
+};
use super::{reference::RefWalker, reference_mut::MutWalker};
@@ -15,7 +19,10 @@ impl<'ctx> WalkOnce<'ctx> for &'ctx str {
impl<'borrow, 'ctx> WalkMut<'borrow, 'ctx> for &'ctx str {
#[inline]
- fn walk_mut(&'borrow mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> {
+ fn walk_mut(
+ &'borrow mut self,
+ visitor: &mut dyn Visitor<'ctx>,
+ ) -> Result<Self::Value, Self::Error> {
self.walk(visitor)
}
}
@@ -23,12 +30,7 @@ impl<'borrow, 'ctx> WalkMut<'borrow, 'ctx> for &'ctx str {
impl<'borrow, 'ctx> Walk<'borrow, 'ctx> for &'ctx str {
#[inline]
fn walk(&'borrow self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> {
- let mut walker = RefWalker::new(*self);
- let _ = walker.walk(visitor);
- match walker.into_error() {
- Some(err) => Err(err),
- None => Ok(()),
- }
+ RefWalker::new(*self).walk_once(visitor)
}
}
@@ -39,36 +41,23 @@ impl<'ctx> WalkOnce<'ctx> for &'ctx mut str {
#[inline]
fn walk_once(self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> {
- let mut walker = MutWalker::new(self);
- let _ = walker.walk(visitor);
- match walker.into_error() {
- Some(err) => Err(err),
- None => Ok(()),
- }
+ MutWalker::new(self).walk_once(visitor)
}
}
impl<'ctx> WalkMut<'ctx, 'ctx> for &'ctx mut str {
#[inline]
- fn walk_mut(&'ctx mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> {
- let mut walker = MutWalker::new(*self);
- let _ = walker.walk(visitor);
- match walker.into_error() {
- Some(err) => Err(err),
- None => Ok(()),
- }
+ fn walk_mut(
+ &'ctx mut self,
+ visitor: &mut dyn Visitor<'ctx>,
+ ) -> Result<Self::Value, Self::Error> {
+ MutWalker::new(*self).walk_once(visitor)
}
}
impl<'ctx> Walk<'ctx, 'ctx> for &'ctx mut str {
#[inline]
fn walk(&'ctx self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> {
- let mut walker = RefWalker::new(*self);
- let _ = walker.walk(visitor);
- match walker.into_error() {
- Some(err) => Err(err),
- None => Ok(()),
- }
+ RefWalker::new(*self).walk_once(visitor)
}
}
-
diff --git a/src/lib.rs b/src/lib.rs
index 493b0ba..1a7aef4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,103 +1,17 @@
+//! # Design
+//!
+
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "alloc")]
extern crate alloc;
-pub mod build;
+mod build;
pub mod impls;
pub mod protocol;
pub mod protocols;
pub mod transform;
-pub mod walk;
-
-use protocol::{AnyHint, AnyVisit, Hint, ProtocolId, Visit};
-
-/// Signal to a walker or visitor that it should exit early or continue.
-///
-/// [`Walker`] and [`Visitor`] can't signal an error condition with a
-/// [`Result`] so instead they can use this.
-#[must_use]
-#[derive(Copy, Clone, Debug)]
-pub enum ControlFlow {
- /// Continue the walk as normal.
- Continue,
-
- Done,
-
- Error,
-}
-
-impl ControlFlow {
- pub fn to_done(self) -> Self {
- match self {
- ControlFlow::Continue => ControlFlow::Done,
- ControlFlow::Done => ControlFlow::Done,
- ControlFlow::Error => ControlFlow::Error,
- }
- }
-
- pub fn to_continue(self) -> Self {
- match self {
- ControlFlow::Continue => ControlFlow::Continue,
- ControlFlow::Done => ControlFlow::Continue,
- ControlFlow::Error => ControlFlow::Error,
- }
- }
-}
-
-/// Walker over a value.
-///
-/// The walker can give out borrows with a lifetime of `'ctx` to the visitor.
-pub trait Walker<'ctx> {
- /// Walk the value.
- ///
- /// The walker will call [`Visit::visit`] methods for one or more
- /// [`Protocol`][protocol::Protocol] on the given `visitor`.
- fn walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow;
-}
-
-/// Hint lookup for a walker.
-///
-/// Some walkers may need a hint for what the value it's walking actually is.
-/// To support this, a [`Walker`] will call the visitor's [`Visitor::request_hint`]
-/// method and the visitor can call a [`Hint::hint`] method for a
-/// [`Protocol`][protocol::Protocol] that the walker supports.
-pub trait WalkerHints<'ctx> {
- /// Query the walker for a given protocol.
- ///
- /// If the walker doesn't support the protocol then a `None` is returned.
- /// Note, a walker may return a `None` for a particular value but support
- /// the protocol for other values.
- ///
- /// Use [`lookup_hint`][protocol::lookup_hint], or manually call
- /// [`AnyHint::downcast`] on the returned value to access the [`Hint`].
- fn protocol(&mut self, id: ProtocolId) -> Option<AnyHint<'_, 'ctx>>;
-}
-
-/// Visitor over a value to be built.
-pub trait Visitor<'ctx> {
- /// Request the visitor provide a hint for what protocol to use.
- ///
- /// Some walkers may need a hint for what the value it's walking actually is.
- /// To support this, a [`Walker`] will call this method
- /// and the visitor can call a [`Hint::hint`] method for a
- /// [`Protocol`][protocol::Protocol] that the walker supports.
- ///
- /// Returning a `None` means the visitor gave no hint. The `need_hint` will
- /// be `true` if the walker needs a hint to not encounter an error.
- fn request_hint(
- &mut self,
- hints: &mut dyn WalkerHints<'ctx>,
- need_hint: bool,
- ) -> ControlFlow;
+mod walk;
- /// Query the visitor for a given protocol.
- ///
- /// If the visitor doesn't support the protocol then a `None` is returned.
- /// Note, a visitor may return a `None` if it doesn't support the protocol
- /// for it's current internal state but could otherwise.
- ///
- /// Use [`lookup_visit`][protocol::lookup_visit], or manually call
- /// [`AnyVisit::downcast`] on the returned value to access the [`Visit`].
- fn protocol(&mut self, id: ProtocolId) -> Option<AnyVisit<'_, 'ctx>>;
-}
+pub use build::*;
+pub use walk::*;
diff --git a/src/protocol.rs b/src/protocol.rs
index 617cc4d..2b48fc8 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -1,289 +1,93 @@
-use core::any::{type_name, Any};
+use core::any::{Any, TypeId};
-pub use any_hint::AnyHint;
-pub use any_visit::AnyVisit;
-pub use id::ProtocolId;
+pub use any_implementation::AnyImpl;
-use crate::{ControlFlow, Visitor, WalkerHints};
-
-/// A protocol between a walker and visitor.
-///
-/// On the walker side this takes the form of hints a visitor can give.
-/// On the visitor side this takes the form of visits a walker can inject values into.
-///
-/// When a visitor hints a walker should use a particular protocol, its expected
-/// that the walker visits using that protocol.
-///
-/// A protocol never needs to be a value, so it's recommended to use an uninhabited type
-/// like an empty enum to represent them.
pub trait Protocol: Any {
- /// Arbitrary hint metadata for the protocol.
- ///
- /// This allows a visitor to give extra information to a walker when hinting to
- /// use the protocol.
- type Hint<'ctx>;
-
- /// Data known about the protocol before hinting.
- ///
- /// This allows a walker to give extra information to a visitor to make a
- /// better decision when selecting a hint.
- type Known<'ctx>;
-
- /// The visit data the walker provides to the visitor.
- ///
- /// This may be actual data or another walker for a part of the bigger value.
- /// The '`walking` lifetime is only alive while the walker is walking.
- /// As such, a visitor cannot borrow from a `'walking` lifetime containing type
- /// for it's output.
- type Accessor<'walking, 'ctx: 'walking>;
-}
-
-/// Protocol specific hint for a walker.
-///
-/// A walker can implement any number of these for any protocols it supports.
-pub trait Hint<'ctx, P: Protocol> {
- /// Hint that protocol `P` should be used.
- ///
- /// After hinting a protocol, a walker should invoke only the same protocol on the visitor.
- /// This is not forced though.
- fn hint(&mut self, visitor: &mut dyn Visitor<'ctx>, hint: P::Hint<'ctx>) -> ControlFlow;
-
- /// Any information the walker has for the protocol.
- ///
- /// This information should be easy to get inside the walker, and should
- /// only be used when making a decision of what protocol to hint as a visitor.
- /// This can be helpful for doing things like preallocating space in the visitor.
- ///
- /// Most protocols will allow returning a value representing no knowledge is known by the
- /// walker.
- fn known(&mut self, hint: &P::Hint<'ctx>) -> P::Known<'ctx>;
-}
-
-/// Protocol specific visit for a visitor.
-///
-/// A visitor can implement any number of these for any protocols it supports.
-pub trait Visit<'ctx, P: Protocol> {
- /// Visit a value from the walker.
- ///
- /// The `accessor` will either be a concrete value or another walker.
- /// This is dependant on the protocol `P`. The visitor can do whatever it wants
- /// with the `accessor` during the function call.
- fn visit(&mut self, accessor: P::Accessor<'_, 'ctx>) -> ControlFlow;
-}
-
-#[derive(thiserror::Error, Debug)]
-#[error("Expected Hint to be for `{expected}` but got one for `{got}`.")]
-pub struct WalkerWrongProtocol {
- pub got: &'static str,
- pub expected: &'static str,
-}
-
-#[derive(thiserror::Error, Debug)]
-pub enum WalkerMissingProtocol {
- #[error("Walker doesn't support the protocol `{0}`.")]
- Missing(&'static str),
-
- #[error(transparent)]
- Wrong(#[from] WalkerWrongProtocol),
-}
-
-#[derive(thiserror::Error, Debug)]
-#[error("Expected Visit to be for `{expected}` but got one for `{got}`.")]
-pub struct VisitorWrongProtocol {
- pub got: &'static str,
- pub expected: &'static str,
-}
-
-#[derive(thiserror::Error, Debug)]
-pub enum VisitorMissingProtocol {
- #[error("Visitor doesn't support the protocol `{0}`.")]
- Missing(&'static str),
-
- #[error(transparent)]
- Wrong(#[from] VisitorWrongProtocol),
+ type Object<'a, 'ctx: 'a>;
}
-/// Try to lookup a [`Hint`] on a walker.
-pub fn try_lookup_hint<'ctx, P: Protocol, H: ?Sized + WalkerHints<'ctx>>(
- hints: &mut H,
-) -> Result<Option<&mut dyn Hint<'ctx, P>>, WalkerWrongProtocol> {
- match hints.protocol(ProtocolId::of::<P>()) {
- Some(protocol) => match protocol.downcast::<P>() {
- Ok(hint) => Ok(Some(hint)),
- Err(hint) => Err(WalkerWrongProtocol {
- got: hint.protocol_type_name(),
- expected: type_name::<P>(),
- }),
- },
- None => Ok(None),
- }
+pub trait Implementer<'ctx> {
+ fn interface(&mut self, id: TypeId) -> Option<AnyImpl<'_, 'ctx>>;
}
-pub fn lookup_hint<'ctx, P: Protocol, H: ?Sized + WalkerHints<'ctx>>(
- hints: &mut H,
-) -> Result<&mut dyn Hint<'ctx, P>, WalkerMissingProtocol> {
- try_lookup_hint(hints)?.ok_or(WalkerMissingProtocol::Missing(type_name::<P>()))
-}
-
-pub fn try_lookup_visit<'ctx, P: Protocol, V: ?Sized + Visitor<'ctx>>(
- visitor: &mut V,
-) -> Result<Option<&mut dyn Visit<'ctx, P>>, VisitorWrongProtocol> {
- match visitor.protocol(ProtocolId::of::<P>()) {
- Some(protocol) => match protocol.downcast::<P>() {
- Ok(visit) => Ok(Some(visit)),
- Err(visit) => Err(VisitorWrongProtocol {
- got: visit.protocol_type_name(),
- expected: type_name::<P>(),
- }),
- },
- None => Ok(None),
- }
+pub trait Implementation<'ctx, P: Protocol> {
+ fn as_object(&mut self) -> P::Object<'_, 'ctx>;
}
-pub fn lookup_visit<'ctx, P: Protocol, V: ?Sized + Visitor<'ctx>>(
- visitor: &mut V,
-) -> Result<&mut dyn Visit<'ctx, P>, VisitorMissingProtocol> {
- try_lookup_visit(visitor)?.ok_or(VisitorMissingProtocol::Missing(type_name::<P>()))
+pub trait ImplementerExt<'ctx>: Implementer<'ctx> {
+ fn interface_for<P: Protocol>(&mut self) -> Option<&mut dyn Implementation<'ctx, P>>;
}
-mod id {
- use super::Protocol;
- use core::any::TypeId;
-
- /// ID of a protocol.
- ///
- /// This can be used to query if a walker or visitor supports a protocol.
- #[derive(PartialEq, Eq, Hash, Ord, PartialOrd, Debug, Copy, Clone)]
- pub struct ProtocolId(TypeId);
-
- impl ProtocolId {
- /// Get the ID of a protocol.
- ///
- /// The ID is unique per protocol.
- pub fn of<P: Protocol>() -> Self {
- Self(TypeId::of::<P>())
+impl<'ctx, T: Implementer<'ctx> + ?Sized> ImplementerExt<'ctx> for T {
+ fn interface_for<P: Protocol>(&mut self) -> Option<&mut dyn Implementation<'ctx, P>> {
+ match self.interface(TypeId::of::<P>()) {
+ Some(interface) => match interface.downcast::<P>() {
+ Ok(implementation) => Some(implementation),
+ Err(interface) => panic!(
+ "unexpected type ID for protocol implementation: `{:?}`, expected: `{:?}`",
+ interface.id(),
+ TypeId::of::<P>()
+ ),
+ },
+ None => None,
}
}
}
-mod any_hint {
- use core::{
- any::{type_name, Any},
- marker::PhantomData,
- mem::MaybeUninit,
- };
-
- use crate::Hint;
-
- use super::{Protocol, ProtocolId};
-
- /// Form of `Hint` without `P`.
- trait ErasedHint<'ctx>: Any {}
-
- /// Get the size of pointers to trait objects for this target.
- const DYN_PTR_SIZE: usize = core::mem::size_of::<&mut dyn ErasedHint<'static>>();
-
- /// Type erased form of `&'walking mut dyn Hint<'value, P, Err>` where `P` is erased.
- pub struct AnyHint<'walking, 'ctx> {
- /// ID of `P`.
- id: ProtocolId,
- name: &'static str,
-
- /// This field stores a `&'walking mut dyn Hint<'value, P, Err>`.
- fat_ptr: MaybeUninit<[u8; DYN_PTR_SIZE]>,
-
- /// Mimick what we actually store with a trait without `P`.
- _marker: PhantomData<&'walking mut dyn ErasedHint<'ctx>>,
- }
-
- impl<'walking, 'ctx> AnyHint<'walking, 'ctx> {
- /// Erase the `P` in a hint.
- ///
- /// This allows returning a hint from a object safe method.
- pub fn new<P: Protocol>(visit: &'walking mut dyn Hint<'ctx, P>) -> Self {
- Self {
- id: ProtocolId::of::<P>(),
- name: type_name::<P>(),
- // SAFETY: A maybe uninit array of bytes can hold any pointer.
- // Additionally, transmute makes sure the size is correct.
- fat_ptr: unsafe { core::mem::transmute(visit) },
- _marker: PhantomData,
+#[doc(hidden)]
+#[macro_export]
+macro_rules! implementer {
+ {
+ impl[$ctx:lifetime $($generic:tt)*] $name:ty = [$($protocol:ty),* $(,)?];
+ } => {
+ impl<$ctx $($generic)*> $crate::protocol::Implementer<$ctx> for $name {
+ #[inline]
+ fn interface(&mut self, id: ::core::any::TypeId) -> ::core::option::Option<$crate::protocol::AnyImpl<'_, $ctx>> {
+ match id {
+ $(id if id == ::core::any::TypeId::of::<$protocol>() => Some($crate::protocol::AnyImpl::new::<$protocol>(self)),)*
+ _ => None
+ }
}
}
- /// Try to downcast the hint for the given protocol.
- ///
- /// If the hint is of the wrong type then `None` is returned.
- pub fn downcast<P: Protocol>(self) -> Result<&'walking mut dyn Hint<'ctx, P>, Self> {
- if self.id == ProtocolId::of::<P>() {
- // SAFETY: Only `new` can make a value of this type, and it stores the ID of `P`.
- // If the IDs are equal then we can act like any and downcast back to the real
- // type.
- //
- // An important note is this method takes ownership. Which allows it to return
- // the borrow with the `'walking` lifetime instead of a sub-borrow.
- Ok(unsafe { core::mem::transmute(self.fat_ptr) })
- } else {
- Err(self)
+ $(impl<$ctx> $crate::protocol::Implementation<$ctx, $protocol> for $name {
+ fn as_object(&mut self) -> <$protocol as $crate::protocol::Protocol>::Object<'_, $ctx> {
+ self
}
- }
-
- pub fn protocol_type_name(&self) -> &'static str {
- self.name
- }
+ })*
}
}
+#[doc(inline)]
+pub use implementer;
-mod any_visit {
- use core::{
- any::{type_name, Any},
- marker::PhantomData,
- mem::MaybeUninit,
- };
-
- use crate::Visit;
+mod any_implementation {
+ use core::{any::TypeId, marker::PhantomData, mem::MaybeUninit};
- use super::{Protocol, ProtocolId};
+ use super::{Implementation, Protocol};
- /// Form of `Visit` without `P`.
- trait ErasedVisit<'ctx>: Any {}
+ trait ErasedImplementation<'ctx> {}
- /// Get the size of pointers to trait objects for this target.
- const DYN_PTR_SIZE: usize = core::mem::size_of::<&mut dyn ErasedVisit<'static>>();
+ const DYN_PTR_SIZE: usize = core::mem::size_of::<&mut dyn ErasedImplementation<'static>>();
- /// Type erased form of `&'walking mut dyn Visit<'value, P, Err>` where `P` is erased.
- pub struct AnyVisit<'walking, 'ctx> {
- /// ID of `P`.
- id: ProtocolId,
- name: &'static str,
-
- /// This field stores a `&'walking mut dyn Visit<'value, P, Err>`.
+ pub struct AnyImpl<'a, 'ctx> {
+ id: TypeId,
fat_ptr: MaybeUninit<[u8; DYN_PTR_SIZE]>,
-
- /// Mimick what we actually store with a trait without `P`.
- _marker: PhantomData<&'walking mut dyn ErasedVisit<'ctx>>,
+ _marker: PhantomData<&'a mut dyn ErasedImplementation<'ctx>>,
}
- impl<'walking, 'ctx> AnyVisit<'walking, 'ctx> {
- /// Erase the `P` in a Visit.
- ///
- /// This allows returning a Visit from a object safe method.
- pub fn new<P: Protocol>(visit: &'walking mut dyn Visit<'ctx, P>) -> Self {
+ impl<'a, 'ctx> AnyImpl<'a, 'ctx> {
+ pub fn new<P: Protocol>(implementation: &'a mut dyn Implementation<'ctx, P>) -> Self {
Self {
- id: ProtocolId::of::<P>(),
- name: type_name::<P>(),
+ id: TypeId::of::<P>(),
// SAFETY: A maybe uninit array of bytes can hold any pointer.
// Additionally, transmute makes sure the size is correct.
- fat_ptr: unsafe { core::mem::transmute(visit) },
+ fat_ptr: unsafe { core::mem::transmute(implementation) },
_marker: PhantomData,
}
}
- /// Try to downcast the Visit for the given protocol.
- ///
- /// If the Visit is of the wrong type then `None` is returned.
- pub fn downcast<P: Protocol>(self) -> Result<&'walking mut dyn Visit<'ctx, P>, Self> {
- if self.id == ProtocolId::of::<P>() {
+ pub fn downcast<P: Protocol>(self) -> Result<&'a mut dyn Implementation<'ctx, P>, Self> {
+ if self.id == TypeId::of::<P>() {
// SAFETY: Only `new` can make a value of this type, and it stores the ID of `P`.
// If the IDs are equal then we can act like any and downcast back to the real
// type.
@@ -296,41 +100,8 @@ mod any_visit {
}
}
- pub fn protocol_type_name(&self) -> &'static str {
- self.name
- }
- }
-}
-
-/// The following shows a safe form of the generic types in this module.
-/// This shows how the lifetimes are correct.
-#[cfg(test)]
-#[allow(unused)]
-mod generic_example {
- use crate::Hint;
-
- use super::{Protocol, ProtocolId};
-
- pub struct Generic<'walking, 'ctx, P> {
- id: ProtocolId,
- fat_ptr: &'walking mut dyn Hint<'ctx, P>,
- }
-
- impl<'walking, 'ctx, P: Protocol> Generic<'walking, 'ctx, P> {
- pub fn new(visit: &'walking mut dyn Hint<'ctx, P>) -> Self {
- Self {
- id: ProtocolId::of::<P>(),
- fat_ptr: visit,
- }
- }
-
- pub fn downcast(self) -> Result<&'walking mut dyn Hint<'ctx, P>, Self> {
- if self.id == ProtocolId::of::<P>() {
- // Notice how this is valid.
- Ok(self.fat_ptr)
- } else {
- Err(self)
- }
+ pub fn id(&self) -> TypeId {
+ self.id
}
}
}
diff --git a/src/protocols.rs b/src/protocols.rs
index cd0164e..6e0ae5f 100644
--- a/src/protocols.rs
+++ b/src/protocols.rs
@@ -1,23 +1,120 @@
+pub enum ControlFlow {
+ Done,
+ Error,
+}
+
+pub mod hint {
+ use crate::protocol::{Implementer, Protocol};
+
+ pub enum ControlFlow {
+ HintGiven,
+ NoHint,
+ Error,
+ }
+
+ pub trait Object<'ctx> {
+ fn request_hint(&mut self, hints: &mut dyn Implementer<'ctx>) -> ControlFlow;
+ }
+
+ pub enum RequestHint {}
+
+ impl Protocol for RequestHint {
+ type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>;
+ }
+
+ pub trait HintObject<'ctx> {
+ fn hint(&mut self, visitor: &mut dyn Implementer<'ctx>) -> ControlFlow;
+ }
+}
+
pub mod recoverable {
- use crate::{protocol::Protocol, ControlFlow, Visitor};
+ use crate::protocol::{Implementer, Protocol};
+
+ use super::{hint::HintObject, ControlFlow};
pub trait Accessor<'ctx> {
- /// Each time this is called the walker resets.
- fn new_walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow;
+ fn new_walk(&mut self, visitor: &mut dyn Implementer<'ctx>) -> ControlFlow;
+ }
+
+ pub trait Object<'ctx> {
+ fn visit(&mut self, accessor: &mut dyn Accessor<'ctx>) -> ControlFlow;
}
pub enum Recoverable {}
impl Protocol for Recoverable {
- type Hint<'ctx> = ();
+ type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>;
+ }
- type Known<'ctx> = ();
+ pub enum Hint {}
- type Accessor<'walking, 'ctx: 'walking> = &'walking mut dyn Accessor<'ctx>;
+ impl Protocol for Hint {
+ type Object<'a, 'ctx: 'a> = &'a mut dyn HintObject<'ctx>;
}
}
pub mod sequence {
+ use crate::protocol::{Implementer, Protocol};
+
+ pub enum ControlFlow {
+ Done,
+ Continue,
+ Error,
+ }
+
+ pub trait Accessor<'ctx> {
+ fn next(&mut self, visitor: &mut dyn Implementer<'ctx>) -> ControlFlow;
+ }
+
+ pub trait Object<'ctx> {
+ fn visit(&mut self, accessor: &mut dyn Accessor<'ctx>) -> super::ControlFlow;
+ }
+
+ pub enum Sequence {}
+
+ impl Protocol for Sequence {
+ type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>;
+ }
+
+ pub trait HintObject<'ctx> {
+ fn hint(&mut self, visitor: &mut dyn Implementer<'ctx>) -> super::ControlFlow;
+
+ fn len(&mut self) -> (usize, Option<usize>) {
+ (0, None)
+ }
+ }
+
+ pub enum Hint {}
+
+ impl Protocol for Hint {
+ type Object<'a, 'ctx: 'a> = &'a mut dyn HintObject<'ctx>;
+ }
+}
+
+pub mod bool {
+ use crate::protocol::Protocol;
+
+ use super::{hint::HintObject, ControlFlow};
+
+ pub trait Object<'ctx> {
+ fn visit(&mut self, value: bool) -> ControlFlow;
+ }
+
+ pub enum Bool {}
+
+ impl Protocol for Bool {
+ type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>;
+ }
+
+ pub enum Hint {}
+
+ impl Protocol for Hint {
+ type Object<'a, 'ctx: 'a> = &'a mut dyn HintObject<'ctx>;
+ }
+}
+
+/*
+pub mod map {
use crate::{protocol::Protocol, ControlFlow, Visitor};
pub struct Hint {
@@ -30,15 +127,16 @@ pub mod sequence {
}
pub trait Accessor<'ctx> {
- fn next(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow;
+ fn next_key(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow;
+ fn value(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow;
}
- pub enum Sequence {}
+ pub enum Map {}
- impl Protocol for Sequence {
- type Hint<'ctx> = Hint;
+ impl Protocol for Map {
+ type Hint<'walking, 'ctx: 'walking> = Hint;
- type Known<'ctx> = Known;
+ type Known<'walking, 'ctx: 'walking> = Known;
type Accessor<'walking, 'ctx: 'walking> = &'walking mut dyn Accessor<'ctx>;
}
@@ -86,18 +184,501 @@ pub mod reference {
pub struct ReferenceMut<T: ?Sized + Any>(PhantomData<fn() -> T>);
impl<T: ?Sized + Any> Protocol for Reference<T> {
- type Hint<'ctx> = Hint;
+ type Hint<'walking, 'ctx: 'walking> = Hint;
- type Known<'ctx> = Known;
+ type Known<'walking, 'ctx: 'walking> = Known;
type Accessor<'walking, 'ctx: 'walking> = Ref<'walking, 'ctx, T>;
}
impl<T: ?Sized + Any> Protocol for ReferenceMut<T> {
- type Hint<'ctx> = Hint;
+ type Hint<'walking, 'ctx: 'walking> = Hint;
- type Known<'ctx> = Known;
+ type Known<'walking, 'ctx: 'walking> = Known;
type Accessor<'walking, 'ctx: 'walking> = Mut<'walking, 'ctx, T>;
}
}
+
+pub mod bool {
+ use crate::protocol::Protocol;
+
+ pub enum Bool {}
+
+ impl Protocol for Bool {
+ type Hint<'walking, 'ctx: 'walking> = ();
+
+ type Known<'walking, 'ctx: 'walking> = ();
+
+ type Accessor<'walking, 'ctx: 'walking> = bool;
+ }
+}
+
+pub mod int {
+ use core::num::TryFromIntError;
+
+ use crate::protocol::Protocol;
+
+ pub enum Kind {
+ I8,
+ I16,
+ I32,
+ I64,
+ I128,
+ Isize,
+ U8,
+ U16,
+ U32,
+ U64,
+ U128,
+ Usize,
+ }
+
+ pub enum Value {
+ I8(i8),
+ I16(i16),
+ I32(i32),
+ I64(i64),
+ I128(i128),
+ Isize(isize),
+ U8(u8),
+ U16(u16),
+ U32(u32),
+ U64(u64),
+ U128(u128),
+ Usize(usize),
+ }
+
+ pub enum Int {}
+
+ impl Protocol for Int {
+ type Hint<'walking, 'ctx: 'walking> = Option<Kind>;
+
+ type Known<'walking, 'ctx: 'walking> = Option<Kind>;
+
+ type Accessor<'walking, 'ctx: 'walking> = Value;
+ }
+
+ impl From<i8> for Value {
+ fn from(value: i8) -> Self {
+ Self::I8(value)
+ }
+ }
+
+ impl From<i16> for Value {
+ fn from(value: i16) -> Self {
+ Self::I16(value)
+ }
+ }
+
+ impl From<i32> for Value {
+ fn from(value: i32) -> Self {
+ Self::I32(value)
+ }
+ }
+
+ impl From<i64> for Value {
+ fn from(value: i64) -> Self {
+ Self::I64(value)
+ }
+ }
+
+ impl From<i128> for Value {
+ fn from(value: i128) -> Self {
+ Self::I128(value)
+ }
+ }
+
+ impl From<isize> for Value {
+ fn from(value: isize) -> Self {
+ Self::Isize(value)
+ }
+ }
+
+ impl From<u8> for Value {
+ fn from(value: u8) -> Self {
+ Self::U8(value)
+ }
+ }
+
+ impl From<u16> for Value {
+ fn from(value: u16) -> Self {
+ Self::U16(value)
+ }
+ }
+
+ impl From<u32> for Value {
+ fn from(value: u32) -> Self {
+ Self::U32(value)
+ }
+ }
+
+ impl From<u64> for Value {
+ fn from(value: u64) -> Self {
+ Self::U64(value)
+ }
+ }
+
+ impl From<u128> for Value {
+ fn from(value: u128) -> Self {
+ Self::U128(value)
+ }
+ }
+
+ impl From<usize> for Value {
+ fn from(value: usize) -> Self {
+ Self::Usize(value)
+ }
+ }
+
+ impl TryFrom<Value> for i8 {
+ type Error = TryFromIntError;
+
+ fn try_from(value: Value) -> Result<Self, Self::Error> {
+ match value {
+ Value::I8(value) => Ok(value),
+ Value::I16(value) => value.try_into(),
+ Value::I32(value) => value.try_into(),
+ Value::I64(value) => value.try_into(),
+ Value::I128(value) => value.try_into(),
+ Value::Isize(value) => value.try_into(),
+ Value::U8(value) => value.try_into(),
+ Value::U16(value) => value.try_into(),
+ Value::U32(value) => value.try_into(),
+ Value::U64(value) => value.try_into(),
+ Value::U128(value) => value.try_into(),
+ Value::Usize(value) => value.try_into(),
+ }
+ }
+ }
+
+ impl TryFrom<Value> for i16 {
+ type Error = TryFromIntError;
+
+ fn try_from(value: Value) -> Result<Self, Self::Error> {
+ match value {
+ Value::I8(value) => Ok(value.into()),
+ Value::I16(value) => Ok(value),
+ Value::I32(value) => value.try_into(),
+ Value::I64(value) => value.try_into(),
+ Value::I128(value) => value.try_into(),
+ Value::Isize(value) => value.try_into(),
+ Value::U8(value) => Ok(value.into()),
+ Value::U16(value) => value.try_into(),
+ Value::U32(value) => value.try_into(),
+ Value::U64(value) => value.try_into(),
+ Value::U128(value) => value.try_into(),
+ Value::Usize(value) => value.try_into(),
+ }
+ }
+ }
+
+ impl TryFrom<Value> for i32 {
+ type Error = TryFromIntError;
+
+ fn try_from(value: Value) -> Result<Self, Self::Error> {
+ match value {
+ Value::I8(value) => Ok(value.into()),
+ Value::I16(value) => Ok(value.into()),
+ Value::I32(value) => Ok(value),
+ Value::I64(value) => value.try_into(),
+ Value::I128(value) => value.try_into(),
+ Value::Isize(value) => value.try_into(),
+ Value::U8(value) => Ok(value.into()),
+ Value::U16(value) => Ok(value.into()),
+ Value::U32(value) => value.try_into(),
+ Value::U64(value) => value.try_into(),
+ Value::U128(value) => value.try_into(),
+ Value::Usize(value) => value.try_into(),
+ }
+ }
+ }
+
+ impl TryFrom<Value> for i64 {
+ type Error = TryFromIntError;
+
+ fn try_from(value: Value) -> Result<Self, Self::Error> {
+ match value {
+ Value::I8(value) => Ok(value.into()),
+ Value::I16(value) => Ok(value.into()),
+ Value::I32(value) => Ok(value.into()),
+ Value::I64(value) => Ok(value),
+ Value::I128(value) => value.try_into(),
+ Value::Isize(value) => value.try_into(),
+ Value::U8(value) => Ok(value.into()),
+ Value::U16(value) => Ok(value.into()),
+ Value::U32(value) => Ok(value.into()),
+ Value::U64(value) => value.try_into(),
+ Value::U128(value) => value.try_into(),
+ Value::Usize(value) => value.try_into(),
+ }
+ }
+ }
+
+ impl TryFrom<Value> for i128 {
+ type Error = TryFromIntError;
+
+ fn try_from(value: Value) -> Result<Self, Self::Error> {
+ match value {
+ Value::I8(value) => Ok(value.into()),
+ Value::I16(value) => Ok(value.into()),
+ Value::I32(value) => Ok(value.into()),
+ Value::I64(value) => Ok(value.into()),
+ Value::I128(value) => Ok(value),
+ Value::Isize(value) => value.try_into(),
+ Value::U8(value) => Ok(value.into()),
+ Value::U16(value) => Ok(value.into()),
+ Value::U32(value) => Ok(value.into()),
+ Value::U64(value) => Ok(value.into()),
+ Value::U128(value) => value.try_into(),
+ Value::Usize(value) => value.try_into(),
+ }
+ }
+ }
+
+ impl TryFrom<Value> for isize {
+ type Error = TryFromIntError;
+
+ fn try_from(value: Value) -> Result<Self, Self::Error> {
+ match value {
+ Value::I8(value) => Ok(value.into()),
+ Value::I16(value) => Ok(value.into()),
+ Value::I32(value) => value.try_into(),
+ Value::I64(value) => value.try_into(),
+ Value::I128(value) => value.try_into(),
+ Value::Isize(value) => Ok(value),
+ Value::U8(value) => Ok(value.into()),
+ Value::U16(value) => value.try_into(),
+ Value::U32(value) => value.try_into(),
+ Value::U64(value) => value.try_into(),
+ Value::U128(value) => value.try_into(),
+ Value::Usize(value) => value.try_into(),
+ }
+ }
+ }
+
+ impl TryFrom<Value> for u8 {
+ type Error = TryFromIntError;
+
+ fn try_from(value: Value) -> Result<Self, Self::Error> {
+ match value {
+ Value::U8(value) => Ok(value),
+ Value::U16(value) => value.try_into(),
+ Value::U32(value) => value.try_into(),
+ Value::U64(value) => value.try_into(),
+ Value::U128(value) => value.try_into(),
+ Value::Usize(value) => value.try_into(),
+ Value::I8(value) => value.try_into(),
+ Value::I16(value) => value.try_into(),
+ Value::I32(value) => value.try_into(),
+ Value::I64(value) => value.try_into(),
+ Value::I128(value) => value.try_into(),
+ Value::Isize(value) => value.try_into(),
+ }
+ }
+ }
+
+ impl TryFrom<Value> for u16 {
+ type Error = TryFromIntError;
+
+ fn try_from(value: Value) -> Result<Self, Self::Error> {
+ match value {
+ Value::U8(value) => Ok(value.into()),
+ Value::U16(value) => Ok(value),
+ Value::U32(value) => value.try_into(),
+ Value::U64(value) => value.try_into(),
+ Value::U128(value) => value.try_into(),
+ Value::Usize(value) => value.try_into(),
+ Value::I8(value) => value.try_into(),
+ Value::I16(value) => value.try_into(),
+ Value::I32(value) => value.try_into(),
+ Value::I64(value) => value.try_into(),
+ Value::I128(value) => value.try_into(),
+ Value::Isize(value) => value.try_into(),
+ }
+ }
+ }
+
+ impl TryFrom<Value> for u32 {
+ type Error = TryFromIntError;
+
+ fn try_from(value: Value) -> Result<Self, Self::Error> {
+ match value {
+ Value::U8(value) => Ok(value.into()),
+ Value::U16(value) => Ok(value.into()),
+ Value::U32(value) => Ok(value),
+ Value::U64(value) => value.try_into(),
+ Value::U128(value) => value.try_into(),
+ Value::Usize(value) => value.try_into(),
+ Value::I8(value) => value.try_into(),
+ Value::I16(value) => value.try_into(),
+ Value::I32(value) => value.try_into(),
+ Value::I64(value) => value.try_into(),
+ Value::I128(value) => value.try_into(),
+ Value::Isize(value) => value.try_into(),
+ }
+ }
+ }
+
+ impl TryFrom<Value> for u64 {
+ type Error = TryFromIntError;
+
+ fn try_from(value: Value) -> Result<Self, Self::Error> {
+ match value {
+ Value::U8(value) => Ok(value.into()),
+ Value::U16(value) => Ok(value.into()),
+ Value::U32(value) => Ok(value.into()),
+ Value::U64(value) => Ok(value),
+ Value::U128(value) => value.try_into(),
+ Value::Usize(value) => value.try_into(),
+ Value::I8(value) => value.try_into(),
+ Value::I16(value) => value.try_into(),
+ Value::I32(value) => value.try_into(),
+ Value::I64(value) => value.try_into(),
+ Value::I128(value) => value.try_into(),
+ Value::Isize(value) => value.try_into(),
+ }
+ }
+ }
+
+ impl TryFrom<Value> for u128 {
+ type Error = TryFromIntError;
+
+ fn try_from(value: Value) -> Result<Self, Self::Error> {
+ match value {
+ Value::U8(value) => Ok(value.into()),
+ Value::U16(value) => Ok(value.into()),
+ Value::U32(value) => Ok(value.into()),
+ Value::U64(value) => Ok(value.into()),
+ Value::U128(value) => Ok(value),
+ Value::Usize(value) => value.try_into(),
+ Value::I8(value) => value.try_into(),
+ Value::I16(value) => value.try_into(),
+ Value::I32(value) => value.try_into(),
+ Value::I64(value) => value.try_into(),
+ Value::I128(value) => value.try_into(),
+ Value::Isize(value) => value.try_into(),
+ }
+ }
+ }
+
+ impl TryFrom<Value> for usize {
+ type Error = TryFromIntError;
+
+ fn try_from(value: Value) -> Result<Self, Self::Error> {
+ match value {
+ Value::U8(value) => Ok(value.into()),
+ Value::U16(value) => Ok(value.into()),
+ Value::U32(value) => value.try_into(),
+ Value::U64(value) => value.try_into(),
+ Value::U128(value) => value.try_into(),
+ Value::Usize(value) => Ok(value),
+ Value::I8(value) => value.try_into(),
+ Value::I16(value) => value.try_into(),
+ Value::I32(value) => value.try_into(),
+ Value::I64(value) => value.try_into(),
+ Value::I128(value) => value.try_into(),
+ Value::Isize(value) => value.try_into(),
+ }
+ }
+ }
+}
+
+pub mod optional {
+ use crate::{protocol::Protocol, Walker};
+
+ pub enum Kind {
+ Some,
+ None,
+ }
+
+ pub enum Optional {}
+
+ impl Protocol for Optional {
+ type Hint<'walking, 'ctx: 'walking> = Option<Kind>;
+
+ type Known<'walking, 'ctx: 'walking> = Option<Kind>;
+
+ type Accessor<'walking, 'ctx: 'walking> = Option<&'walking mut dyn Walker<'ctx>>;
+ }
+}
+
+pub mod unit {
+ use crate::protocol::Protocol;
+
+ pub enum Unit {}
+
+ impl Protocol for Unit {
+ type Hint<'walking, 'ctx: 'walking> = ();
+
+ type Known<'walking, 'ctx: 'walking> = ();
+
+ type Accessor<'walking, 'ctx: 'walking> = ();
+ }
+}
+
+pub mod r#struct {
+ use core::any::TypeId;
+
+ use crate::protocol::Protocol;
+
+ pub struct Hint<'walking> {
+ pub name: Option<&'static str>,
+ pub type_name: Option<&'static str>,
+ pub id: Option<TypeId>,
+ pub fields: Option<&'walking [&'walking str]>,
+ }
+
+ pub struct Known<'walking> {
+ pub name: Option<&'static str>,
+ pub type_name: Option<&'static str>,
+ pub id: Option<TypeId>,
+ pub fields: Option<&'walking [&'walking str]>,
+ }
+
+ pub enum Struct {}
+
+ impl Protocol for Struct {
+ type Hint<'walking, 'ctx: 'walking> = Hint<'walking>;
+
+ type Known<'walking, 'ctx: 'walking> = Known<'walking>;
+
+ type Accessor<'walking, 'ctx: 'walking> = &'walking mut dyn super::map::Accessor<'ctx>;
+ }
+}
+
+pub mod r#enum {
+ use core::any::TypeId;
+
+ use crate::{protocol::Protocol, ControlFlow, Visitor};
+
+ pub struct Hint<'walking> {
+ pub name: Option<&'static str>,
+ pub type_name: Option<&'static str>,
+ pub id: Option<TypeId>,
+ pub variants: Option<&'walking [&'walking str]>,
+ }
+
+ pub struct Known<'walking> {
+ pub name: Option<&'static str>,
+ pub type_name: Option<&'static str>,
+ pub id: Option<TypeId>,
+ pub variant: Option<&'walking str>,
+ }
+
+ pub trait Accessor<'ctx> {
+ fn variant(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow;
+ fn walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow;
+ }
+
+ pub enum Enum {}
+
+ impl Protocol for Enum {
+ type Hint<'walking, 'ctx: 'walking> = Hint<'walking>;
+
+ type Known<'walking, 'ctx: 'walking> = Known<'walking>;
+
+ type Accessor<'walking, 'ctx: 'walking> = &'walking mut dyn Accessor<'ctx>;
+ }
+}
+*/
diff --git a/src/transform.rs b/src/transform.rs
index 2999ad7..325b9ec 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -1,6 +1,6 @@
use crate::{
build::{Build, Builder},
- walk::{WalkOnce, WalkMut, Walk},
+ walk::{Walk, WalkMut, WalkOnce},
};
#[derive(thiserror::Error, Debug)]
diff --git a/src/walk.rs b/src/walk.rs
index 7b2ddc1..9d218b1 100644
--- a/src/walk.rs
+++ b/src/walk.rs
@@ -1,16 +1,20 @@
-use crate::Visitor;
+use crate::protocol::Implementer;
pub trait WalkOnce<'ctx> {
type Error;
type Value;
- fn walk_once(self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error>;
+ fn walk_once(self, visitor: &mut dyn Implementer<'ctx>) -> Result<Self::Value, Self::Error>;
}
pub trait WalkMut<'borrow, 'ctx>: WalkOnce<'ctx> {
- fn walk_mut(&'borrow mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error>;
+ fn walk_mut(
+ &'borrow mut self,
+ visitor: &mut dyn Implementer<'ctx>,
+ ) -> Result<Self::Value, Self::Error>;
}
pub trait Walk<'borrow, 'ctx>: WalkMut<'borrow, 'ctx> {
- fn walk(&'borrow self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error>;
+ fn walk(&'borrow self, visitor: &mut dyn Implementer<'ctx>)
+ -> Result<Self::Value, Self::Error>;
}
diff --git a/tests/demo.rs b/tests/demo.rs
index 81b4875..65b1083 100644
--- a/tests/demo.rs
+++ b/tests/demo.rs
@@ -1,70 +1,63 @@
-use uniserde::{transform::from, build::{Builder, Build}, Visitor, ControlFlow, protocol::{ProtocolId, AnyVisit, Visit}, protocols::sequence, impls::core::iterator::IterWalker, Walker};
+use std::any::TypeId;
+
+use uniserde::{
+ Build, Builder,
+ impls::core::iterator::IterWalker,
+ protocol::{implementer, AnyImpl, Implementation, Implementer},
+ protocols::{sequence, ControlFlow},
+ transform,
+ WalkOnce,
+};
#[test]
fn demo() {
- let x = ["1", "2", "3"];
+ let a = vec![true, false, true];
- let mut builder = VecBuilder::default();
- IterWalker::new(x.iter()).walk(builder.as_visitor());
+ let mut builder = ArrayBuilder::default();
+ IterWalker::new(a).walk_once(builder.as_visitor());
dbg!(builder.build());
- todo!();
+ todo!()
}
#[no_mangle]
-pub fn example<'a>(x: &'a str) -> &'a str {
- from(x).unwrap()
+fn example(a: [bool; 3]) -> [bool; 3] {
+ let mut builder = ArrayBuilder::default();
+ let _ = IterWalker::new(a).walk_once(builder.as_visitor());
+ builder.build().unwrap()
}
#[derive(Default)]
-pub struct VecBuilder(Vec<&'static str>);
+struct ArrayBuilder([Option<bool>; 3]);
-impl Builder<'static> for VecBuilder {
+impl<'ctx> Builder<'ctx> for ArrayBuilder {
type Error = ();
- type Value = Vec<&'static str>;
+ type Value = [bool; 3];
- fn as_visitor(&mut self) -> &mut dyn uniserde::Visitor<'static> {
+ fn as_visitor(&mut self) -> &mut dyn uniserde::protocol::Implementer<'ctx> {
self
}
fn build(self) -> Result<Self::Value, Self::Error> {
- Ok(self.0)
+ Ok([self.0[0].unwrap(), self.0[1].unwrap(), self.0[2].unwrap()])
}
}
-impl Visitor<'static> for VecBuilder {
- fn request_hint(
- &mut self,
- _hints: &mut dyn uniserde::WalkerHints<'static>,
- _need_hint: bool,
- ) -> uniserde::ControlFlow {
- ControlFlow::Continue
- }
-
- fn protocol(&mut self, id: uniserde::protocol::ProtocolId) -> Option<uniserde::protocol::AnyVisit<'_, 'static>> {
- if id == ProtocolId::of::<sequence::Sequence>() {
- Some(AnyVisit::new(self))
- } else {
- None
- }
- }
+implementer! {
+ impl['ctx] ArrayBuilder = [sequence::Sequence];
}
-impl Visit<'static, sequence::Sequence> for VecBuilder {
- fn visit(&mut self, accessor: <sequence::Sequence as uniserde::protocol::Protocol>::Accessor<'_, 'static>) -> ControlFlow {
- loop {
- let mut builder = <&'static str as Build<'static>>::Builder::default();
- match accessor.next(builder.as_visitor()) {
- ControlFlow::Continue => {},
- ControlFlow::Done => {},
- ControlFlow::Error => break ControlFlow::Error,
- }
-
- match builder.build() {
- Ok(value) => self.0.push(value),
- Err(err) => break ControlFlow::Error,
- }
+impl<'ctx> sequence::Object<'ctx> for ArrayBuilder {
+ fn visit(
+ &mut self,
+ accessor: &mut dyn sequence::Accessor<'ctx>,
+ ) -> uniserde::protocols::ControlFlow {
+ for slot in &mut self.0 {
+ let mut builder = <bool as Build>::Builder::default();
+ accessor.next(builder.as_visitor());
+ *slot = Some(builder.build().unwrap());
}
+ ControlFlow::Done
}
}