added bigger example
Konnor Andrews 2024-01-21
parent 8bbab64 · commit 5fba976
-rw-r--r--src/build.rs4
-rw-r--r--src/impls/core/bool.rs8
-rw-r--r--src/protocol.rs18
-rw-r--r--src/protocols.rs1
-rw-r--r--tests/demo.rs173
5 files changed, 179 insertions, 25 deletions
diff --git a/src/build.rs b/src/build.rs
index 1c28354..b5dfc75 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -1,3 +1,5 @@
+use core::any::TypeId;
+
use crate::protocol::Implementer;
/// A type buildable from a walker.
@@ -18,4 +20,6 @@ pub trait Builder<'ctx>: Default {
/// Finish the value.
fn build(self) -> Result<Self::Value, Self::Error>;
+
+ fn accepts(id: TypeId) -> bool;
}
diff --git a/src/impls/core/bool.rs b/src/impls/core/bool.rs
index 2e3aba9..cdc1337 100644
--- a/src/impls/core/bool.rs
+++ b/src/impls/core/bool.rs
@@ -1,7 +1,9 @@
+use core::any::TypeId;
+
use crate::{
build::{Build, Builder},
implementer,
- protocol::{ImplementerExt, Implementer},
+ protocol::{Implementer, ImplementerExt},
protocols::{bool, ControlFlow},
walk::WalkOnce,
};
@@ -32,6 +34,10 @@ impl<'ctx> Builder<'ctx> for BoolBuilder {
None => Err(IncompleteValue),
}
}
+
+ fn accepts(id: core::any::TypeId) -> bool {
+ id == TypeId::of::<bool::Bool>()
+ }
}
implementer! {
diff --git a/src/protocol.rs b/src/protocol.rs
index 2b48fc8..2535449 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -50,12 +50,26 @@ macro_rules! implementer {
}
}
- $(impl<$ctx> $crate::protocol::Implementation<$ctx, $protocol> for $name {
+ $crate::implementer! {
+ $ctx $name [$($protocol),*] [$($generic)*]
+ }
+ };
+ {
+ $ctx:lifetime $name:ty [$protocol:ty] [$($generic:tt)*]
+ } => {
+ impl<$ctx $($generic)*> $crate::protocol::Implementation<$ctx, $protocol> for $name {
fn as_object(&mut self) -> <$protocol as $crate::protocol::Protocol>::Object<'_, $ctx> {
self
}
+ }
+ };
+ {
+ $ctx:lifetime $name:ty [$($protocol:ty),*] $generic:tt
+ } => {
+ $($crate::implementer! {
+ $ctx $name [$protocol] $generic
})*
- }
+ };
}
#[doc(inline)]
pub use implementer;
diff --git a/src/protocols.rs b/src/protocols.rs
index 6e0ae5f..3f1d597 100644
--- a/src/protocols.rs
+++ b/src/protocols.rs
@@ -56,6 +56,7 @@ pub mod recoverable {
pub mod sequence {
use crate::protocol::{Implementer, Protocol};
+ #[derive(PartialEq)]
pub enum ControlFlow {
Done,
Continue,
diff --git a/tests/demo.rs b/tests/demo.rs
index 65b1083..900ba42 100644
--- a/tests/demo.rs
+++ b/tests/demo.rs
@@ -1,62 +1,191 @@
use std::any::TypeId;
use uniserde::{
- Build, Builder,
impls::core::iterator::IterWalker,
- protocol::{implementer, AnyImpl, Implementation, Implementer},
+ protocol::{implementer, AnyImpl, Implementation, Implementer, ImplementerExt},
protocols::{sequence, ControlFlow},
- transform,
- WalkOnce,
+ transform, Build, Builder, WalkOnce,
};
#[test]
fn demo() {
- let a = vec![true, false, true];
+ let a = Data::Sequence(vec![
+ Data::Bool(true),
+ Data::Sequence(vec![Data::Bool(false), Data::Bool(true)]),
+ Data::Bool(false),
+ ]);
- let mut builder = ArrayBuilder::default();
- IterWalker::new(a).walk_once(builder.as_visitor());
+ // let mut builder = <Data as Build>::Builder::default();
+ let mut builder = StringBuilder::default();
+ a.walk_once(builder.as_visitor());
dbg!(builder.build());
todo!()
}
-#[no_mangle]
-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(Debug)]
+enum Data {
+ Bool(bool),
+ Sequence(Vec<Data>),
+}
+
+impl<'ctx> WalkOnce<'ctx> for Data {
+ type Error = ();
+
+ type Value = ();
+
+ fn walk_once(self, visitor: &mut dyn Implementer<'ctx>) -> Result<Self::Value, Self::Error> {
+ match self {
+ Data::Bool(value) => value.walk_once(visitor),
+ Data::Sequence(list) => IterWalker::new(list).walk_once(visitor),
+ }
+ }
+}
+
+#[derive(Default)]
+struct StringBuilder(String);
+
+impl<'ctx> Builder<'ctx> for StringBuilder {
+ type Error = ();
+
+ type Value = String;
+
+ fn as_visitor(&mut self) -> &mut dyn Implementer<'ctx> {
+ self
+ }
+
+ fn build(self) -> Result<Self::Value, Self::Error> {
+ Ok(self.0)
+ }
+
+ fn accepts(id: TypeId) -> bool {
+ id == TypeId::of::<uniserde::protocols::sequence::Sequence>() ||
+ id == TypeId::of::<uniserde::protocols::bool::Bool>()
+ }
+}
+
+implementer! {
+ impl['ctx] StringBuilder = [sequence::Sequence, uniserde::protocols::bool::Bool];
+}
+
+impl<'ctx> uniserde::protocols::sequence::Object<'ctx> for StringBuilder {
+ fn visit(&mut self, accessor: &mut dyn sequence::Accessor<'ctx>) -> uniserde::protocols::ControlFlow {
+ self.0.push('[');
+ loop {
+ if accessor.next(self) != uniserde::protocols::sequence::ControlFlow::Continue {
+ break
+ }
+ self.0.push_str(", ");
+ }
+ self.0.push(']');
+ uniserde::protocols::ControlFlow::Done
+ }
+}
+
+impl<'ctx> uniserde::protocols::bool::Object<'ctx> for StringBuilder {
+ fn visit(&mut self, value: bool) -> ControlFlow {
+ self.0.push_str(&value.to_string());
+ ControlFlow::Done
+ }
}
#[derive(Default)]
-struct ArrayBuilder([Option<bool>; 3]);
+enum DataBuilder {
+ #[default]
+ Empty,
+ Bool(<bool as Build<'static>>::Builder),
+ Sequence(VecBuilder<Data>),
+}
+
+impl<'ctx> Build<'ctx> for Data {
+ type Builder = DataBuilder;
+}
+
+impl<'ctx> Builder<'ctx> for DataBuilder {
+ type Error = ();
+
+ type Value = Data;
+
+ fn as_visitor(&mut self) -> &mut dyn Implementer<'ctx> {
+ self
+ }
+
+ fn build(self) -> Result<Self::Value, Self::Error> {
+ match self {
+ DataBuilder::Empty => Err(()),
+ DataBuilder::Bool(value) => Ok(Data::Bool(value.build().unwrap())),
+ DataBuilder::Sequence(list) => Ok(Data::Sequence(list.build().unwrap())),
+ }
+ }
-impl<'ctx> Builder<'ctx> for ArrayBuilder {
+ fn accepts(id: TypeId) -> bool {
+ <<bool as Build>::Builder as Builder>::accepts(id)
+ || <VecBuilder<Data> as Builder>::accepts(id)
+ }
+}
+
+impl<'ctx> Implementer<'ctx> for DataBuilder {
+ fn interface(&mut self, id: TypeId) -> Option<AnyImpl<'_, 'ctx>> {
+ if <<bool as Build>::Builder as Builder>::accepts(id) {
+ let builder = <<bool as Build>::Builder as Default>::default();
+ *self = Self::Bool(builder);
+ } else if VecBuilder::<Data>::accepts(id) {
+ let builder = VecBuilder::<Data>::default();
+ *self = Self::Sequence(builder);
+ }
+
+ match self {
+ DataBuilder::Empty => panic!(),
+ DataBuilder::Bool(builder) => builder.interface(id),
+ DataBuilder::Sequence(builder) => builder.interface(id),
+ }
+ }
+}
+
+struct VecBuilder<T>(Vec<T>);
+
+impl<T> Default for VecBuilder<T> {
+ fn default() -> Self {
+ Self(Vec::new())
+ }
+}
+
+impl<'ctx, T: Build<'ctx>> Builder<'ctx> for VecBuilder<T> {
type Error = ();
- type Value = [bool; 3];
+ type Value = Vec<T>;
fn as_visitor(&mut self) -> &mut dyn uniserde::protocol::Implementer<'ctx> {
self
}
fn build(self) -> Result<Self::Value, Self::Error> {
- Ok([self.0[0].unwrap(), self.0[1].unwrap(), self.0[2].unwrap()])
+ Ok(self.0)
+ }
+
+ fn accepts(id: TypeId) -> bool {
+ id == TypeId::of::<uniserde::protocols::sequence::Sequence>()
}
}
implementer! {
- impl['ctx] ArrayBuilder = [sequence::Sequence];
+ impl['ctx, T: Build<'ctx>] VecBuilder<T> = [sequence::Sequence];
}
-impl<'ctx> sequence::Object<'ctx> for ArrayBuilder {
+impl<'ctx, T: Build<'ctx>> sequence::Object<'ctx> for VecBuilder<T> {
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());
+ loop {
+ let mut builder = <T as Build>::Builder::default();
+ let flow = accessor.next(builder.as_visitor());
+ if flow == uniserde::protocols::sequence::ControlFlow::Done {
+ break;
+ } else {
+ let Ok(value) = builder.build() else { panic!() };
+ self.0.push(value);
+ }
}
ControlFlow::Done
}