added effects and tagged protocol
Konnor Andrews 2024-02-12
parent 06eb47f · commit 02572de
-rw-r--r--Cargo.lock297
-rw-r--r--Cargo.toml3
-rw-r--r--src/any.rs2
-rw-r--r--src/build.rs41
-rw-r--r--src/protocol.rs28
-rw-r--r--src/protocol/visitor.rs4
-rw-r--r--src/protocol/visitor/request_hint.rs18
-rw-r--r--src/protocol/visitor/sequence.rs30
-rw-r--r--src/protocol/visitor/tagged.rs38
-rw-r--r--src/protocol/visitor/value.rs49
-rw-r--r--src/protocol/walker/hint.rs62
-rw-r--r--src/walk.rs15
-rw-r--r--tests/async.rs148
-rw-r--r--tests/demo.rs40
14 files changed, 666 insertions, 109 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 6fea945..113b721 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,12 +3,42 @@
version = 3
[[package]]
+name = "addr2line"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
+name = "backtrace"
+version = "0.3.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+]
+
+[[package]]
name = "bit-set"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -36,6 +66,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
[[package]]
+name = "bytes"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
+
+[[package]]
+name = "cc"
+version = "1.0.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -48,7 +93,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
dependencies = [
"libc",
- "windows-sys",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -75,6 +120,18 @@ dependencies = [
]
[[package]]
+name = "gimli"
+version = "0.28.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3"
+
+[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -99,6 +156,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
[[package]]
+name = "lock_api"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
name = "macro_rules_attribute"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -115,6 +182,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8dd856d451cc0da70e2ef2ce95a18e39a93b7558bedf10201ad28503f918568"
[[package]]
+name = "memchr"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "mio"
+version = "0.8.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
name = "num-traits"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -125,12 +218,60 @@ dependencies = [
]
[[package]]
+name = "num_cpus"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "object"
+version = "0.32.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets 0.48.5",
+]
+
+[[package]]
name = "paste"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
+name = "pin-project-lite"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
+
+[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -235,6 +376,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
+name = "rustc-demangle"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+
+[[package]]
name = "rustix"
version = "0.38.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -244,7 +391,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -260,6 +407,12 @@ dependencies = [
]
[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
name = "serde"
version = "1.0.195"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -280,6 +433,31 @@ dependencies = [
]
[[package]]
+name = "signal-hook-registry"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
+
+[[package]]
+name = "socket2"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
+dependencies = [
+ "libc",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
name = "syn"
version = "2.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -300,7 +478,37 @@ dependencies = [
"fastrand",
"redox_syscall",
"rustix",
- "windows-sys",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "tokio"
+version = "1.36.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "libc",
+ "mio",
+ "num_cpus",
+ "parking_lot",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2",
+ "tokio-macros",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
]
[[package]]
@@ -310,6 +518,7 @@ dependencies = [
"macro_rules_attribute",
"proptest",
"serde",
+ "tokio",
]
[[package]]
@@ -341,11 +550,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
- "windows-targets",
+ "windows-targets 0.52.0",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
]
[[package]]
@@ -354,53 +587,95 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_aarch64_gnullvm 0.52.0",
+ "windows_aarch64_msvc 0.52.0",
+ "windows_i686_gnu 0.52.0",
+ "windows_i686_msvc 0.52.0",
+ "windows_x86_64_gnu 0.52.0",
+ "windows_x86_64_gnullvm 0.52.0",
+ "windows_x86_64_msvc 0.52.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]]
name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]]
name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]]
name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]]
name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]]
name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]]
name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
diff --git a/Cargo.toml b/Cargo.toml
index 0c99fe4..7930439 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
serde = { version = "1.0", default-features = false, optional = true }
[features]
-default = []
+default = ["alloc"]
std = ["alloc", "serde?/std"]
alloc = ["serde?/alloc"]
serde = ["dep:serde"]
@@ -15,6 +15,7 @@ serde = ["dep:serde"]
[dev-dependencies]
macro_rules_attribute = "0.2.0"
proptest = "1.4.0"
+tokio = { version = "1.36.0", features = ["full"] }
[profile.test.package.proptest]
opt-level = 3
diff --git a/src/any.rs b/src/any.rs
index 54cbee1..453d0a4 100644
--- a/src/any.rs
+++ b/src/any.rs
@@ -110,7 +110,7 @@ macro_rules! nameable {
::core::marker::PhantomData<fn() -> ($( $(*const $generic,)* )?)>
);
- impl<$a, $lt $(, $($generic)*)?>
+ impl<$a, $lt $(, $($generic),*)?>
$crate::any::TypeNameable<$a, $lt> for $type
where
$($nameable_bound)*
diff --git a/src/build.rs b/src/build.rs
index efadc25..0d103ce 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -1,7 +1,10 @@
// pub mod builders;
// pub mod protocols;
-use crate::protocol::Visitor;
+use crate::{
+ protocol::{SyncEffect, Visitor},
+ Walker,
+};
/// A buildable type.
pub trait Build<'ctx>: Sized {
@@ -32,7 +35,7 @@ pub trait Builder<'ctx>: Default {
/// Get the builder as a visitor that a walker can use.
///
/// This is expected to just be `self`.
- fn as_visitor(&mut self) -> Visitor<'_, 'ctx>;
+ fn as_visitor(&mut self) -> &mut Visitor<'ctx>;
/// Finish the value.
///
@@ -40,3 +43,37 @@ pub trait Builder<'ctx>: Default {
/// it will be reported here.
fn build(self) -> Result<Self::Value, Self::Error>;
}
+
+#[derive(Debug)]
+pub enum BuildError<B, W> {
+ Builder(B),
+ Walker(W),
+}
+
+pub fn build_with<'ctx, B: Builder<'ctx>, W: Walker<'ctx, Effect = SyncEffect>>(
+ walker: W,
+) -> Result<B::Value, BuildError<B::Error, W::Error>> {
+ let mut builder = B::default();
+
+ if let core::ops::ControlFlow::Break(err) = walker.walk(builder.as_visitor()) {
+ return Err(BuildError::Walker(err));
+ }
+
+ builder.build().map_err(BuildError::Builder)
+}
+
+#[cfg(feature = "alloc")]
+use crate::protocol::AsyncEffect;
+
+#[cfg(feature = "alloc")]
+pub async fn async_build_with<'ctx, B: Builder<'ctx>, W: Walker<'ctx, Effect = AsyncEffect>>(
+ walker: W,
+) -> Result<B::Value, BuildError<B::Error, W::Error>> {
+ let mut builder = B::default();
+
+ if let core::ops::ControlFlow::Break(err) = walker.walk(builder.as_visitor()).await {
+ return Err(BuildError::Walker(err));
+ }
+
+ builder.build().map_err(BuildError::Builder)
+}
diff --git a/src/protocol.rs b/src/protocol.rs
index f06f095..26ec664 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -38,6 +38,28 @@ use crate::any::AnyTrait;
pub mod visitor;
pub mod walker;
-pub type Visitor<'a, 'ctx> = &'a mut dyn AnyTrait<'ctx>;
-pub type Walker<'a, 'ctx> = &'a mut dyn AnyTrait<'ctx>;
-pub type ControlFlow<B = (), C = ()> = core::ops::ControlFlow<B, C>;
+#[cfg(not(feature = "std"))]
+use alloc::boxed::Box;
+
+pub type Visitor<'ctx> = dyn AnyTrait<'ctx>;
+pub type Walker<'ctx> = dyn AnyTrait<'ctx>;
+
+pub trait Effect {
+ type ControlFlow<'a, C, B>;
+}
+pub type ControlFlowFor<'a, E = SyncEffect, C = (), B = ()> = <E as Effect>::ControlFlow<'a, C, B>;
+
+pub enum SyncEffect {}
+
+impl Effect for SyncEffect {
+ type ControlFlow<'a, C, B> = core::ops::ControlFlow<B, C>;
+}
+
+#[cfg(feature = "alloc")]
+pub enum AsyncEffect {}
+
+#[cfg(feature = "alloc")]
+impl Effect for AsyncEffect {
+ type ControlFlow<'a, C, B> =
+ core::pin::Pin<Box<dyn core::future::Future<Output = core::ops::ControlFlow<B, C>> + 'a>>;
+}
diff --git a/src/protocol/visitor.rs b/src/protocol/visitor.rs
index cee7dd4..7b91c7a 100644
--- a/src/protocol/visitor.rs
+++ b/src/protocol/visitor.rs
@@ -1,9 +1,9 @@
mod request_hint;
mod sequence;
-// pub mod tagged;
+mod tagged;
mod value;
-// pub mod borrow;
pub use request_hint::*;
pub use sequence::*;
+pub use tagged::*;
pub use value::*;
diff --git a/src/protocol/visitor/request_hint.rs b/src/protocol/visitor/request_hint.rs
index 179a68a..87c073d 100644
--- a/src/protocol/visitor/request_hint.rs
+++ b/src/protocol/visitor/request_hint.rs
@@ -1,17 +1,21 @@
-use core::ops::ControlFlow;
-
-use crate::{nameable, protocol::Walker};
+use crate::{
+ nameable,
+ protocol::{ControlFlowFor, Effect, SyncEffect, Walker},
+};
/// Protocol for requesting a hint from a visitor.
-pub trait RequestHint<'ctx> {
+pub trait RequestHint<'ctx, E: Effect = SyncEffect> {
/// Call this to request a hint.
///
/// `walker` is what the visitor (`self`) will call to give a hint using the
/// [`Hint`][crate::builtins::walker::Hint] protocol.
- fn request_hint(&mut self, walker: Walker<'_, 'ctx>) -> ControlFlow<()>;
+ fn request_hint<'a>(&'a mut self, walker: &'a mut Walker<'ctx>) -> ControlFlowFor<'a, E>;
}
nameable! {
- pub struct Name['a, 'ctx];
- impl for dyn RequestHint<'ctx> + 'a where {'ctx: 'a}
+ pub struct Name['a, 'ctx, E];
+ impl [E] for dyn RequestHint<'ctx, E> + 'a where {
+ E: Effect + 'static,
+ 'ctx: 'a
+ }
}
diff --git a/src/protocol/visitor/sequence.rs b/src/protocol/visitor/sequence.rs
index 3cb8897..9b24377 100644
--- a/src/protocol/visitor/sequence.rs
+++ b/src/protocol/visitor/sequence.rs
@@ -1,20 +1,28 @@
use crate::{
nameable,
- protocol::{walker::HintMeta, ControlFlow, Visitor},
+ protocol::{walker::HintMeta, ControlFlowFor, Effect, SyncEffect, Visitor},
};
-pub trait Sequence<'ctx> {
- fn visit(&mut self, scope: &mut dyn SequenceScope<'ctx>) -> ControlFlow;
+pub trait Sequence<'ctx, E: Effect = SyncEffect> {
+ fn visit<'a>(&'a mut self, scope: &'a mut dyn SequenceScope<'ctx, E>) -> ControlFlowFor<'a, E>;
}
nameable! {
- pub struct Name['a, 'ctx];
- impl for dyn Sequence<'ctx> + 'a where { 'ctx: 'a }
- impl where dyn Sequence<'ctx> + 'a { 'ctx: 'a }
+ pub struct Name['a, 'ctx, E];
+
+ impl [E] for dyn Sequence<'ctx, E> + 'a where {
+ E: Effect + 'static,
+ 'ctx: 'a
+ }
+
+ impl [E] where dyn Sequence<'ctx, E> + 'a {
+ E: Effect + 'static,
+ 'ctx: 'a
+ }
}
-pub trait SequenceScope<'ctx> {
- fn next(&mut self, visitor: Visitor<'_, 'ctx>) -> ControlFlow<(), Status>;
+pub trait SequenceScope<'ctx, E: Effect = SyncEffect> {
+ fn next<'a>(&'a mut self, visitor: &'a mut Visitor<'ctx>) -> ControlFlowFor<'a, E, Status>;
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)]
@@ -32,10 +40,12 @@ pub struct Hint {
pub len: (usize, Option<usize>),
}
-impl<'ctx> HintMeta<'ctx> for dyn Sequence<'ctx> + '_ {
+impl<'ctx, E: Effect> HintMeta<'ctx> for dyn Sequence<'ctx, E> + '_ {
type Known<'a> = Known
where
'ctx: 'a;
- type Hint = Hint;
+ type Hint<'a> = Hint
+ where
+ 'ctx: 'a;
}
diff --git a/src/protocol/visitor/tagged.rs b/src/protocol/visitor/tagged.rs
index c447a5f..4cf3912 100644
--- a/src/protocol/visitor/tagged.rs
+++ b/src/protocol/visitor/tagged.rs
@@ -1,25 +1,33 @@
use crate::{
- builtins::walker::hint::Meta,
- protocol::{Implementer, Protocol},
+ nameable,
+ protocol::{walker::HintMeta, ControlFlowFor, Effect, SyncEffect, Visitor},
symbol::Symbol,
};
-pub enum Tagged {}
+pub trait Tagged<'ctx, E: Effect = SyncEffect> {
+ fn visit<'a>(&'a mut self, scope: &'a mut dyn TaggedScope<'ctx, E>) -> ControlFlowFor<'a, E>;
+}
-pub trait TaggedWalker<'ctx> {
- fn kind(&mut self) -> Symbol;
+nameable! {
+ pub struct Name['a, 'ctx, E];
- fn walk_tag(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<(), ()>;
+ impl [E] for dyn Tagged<'ctx, E> + 'a where {
+ E: Effect + 'static,
+ 'ctx: 'a
+ }
- fn walk_value(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<(), ()>;
+ impl [E] where dyn Tagged<'ctx, E> + 'a {
+ E: Effect + 'static,
+ 'ctx: 'a
+ }
}
-pub trait Object<'ctx> {
- fn visit(&mut self, walker: &mut dyn TaggedWalker<'ctx>) -> Result<(), ()>;
-}
+pub trait TaggedScope<'ctx, E: Effect = SyncEffect> {
+ fn kind(&mut self) -> Symbol;
+
+ fn tag<'a>(&'a mut self, visitor: &'a mut Visitor<'ctx>) -> ControlFlowFor<'a, E>;
-impl Protocol for Tagged {
- type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>;
+ fn value<'a>(&'a mut self, visitor: &'a mut Visitor<'ctx>) -> ControlFlowFor<'a, E>;
}
pub struct Known {
@@ -30,8 +38,8 @@ pub struct Hint {
pub kind: Option<Symbol>,
}
-impl Meta for Tagged {
- type Known<'a, 'ctx: 'a> = Known;
+impl<'ctx, Return> HintMeta<'ctx> for dyn Tagged<'ctx, Return> + '_ {
+ type Known<'a> = Known where 'ctx: 'a;
- type Hint<'a, 'ctx: 'a> = Hint;
+ type Hint<'a> = Hint where 'ctx: 'a;
}
diff --git a/src/protocol/visitor/value.rs b/src/protocol/visitor/value.rs
index 3cb8908..ed8a8ec 100644
--- a/src/protocol/visitor/value.rs
+++ b/src/protocol/visitor/value.rs
@@ -5,13 +5,13 @@
use crate::{
any::{TypeName, TypeNameable},
nameable,
- protocol::{walker::HintMeta, ControlFlow},
+ protocol::{walker::HintMeta, ControlFlowFor, Effect, SyncEffect},
};
/// Trait object for the [`Value`] protocol.
///
/// Types implementing the [`Value`] protocol will implement this trait.
-pub trait Value<T> {
+pub trait Value<'a, T, E: Effect = SyncEffect> {
/// Visit a value of type `T`.
///
/// Use this to give a value to a visitor. Its expected that a walker
@@ -21,30 +21,41 @@ pub trait Value<T> {
/// If a [`ControlFlow::Break`] is returned then the walker
/// should stop walking as soon as possible as there has likely been
/// and error.
- fn visit(&mut self, value: T) -> ControlFlow;
+ fn visit(&'a mut self, value: T) -> ControlFlowFor<'a, E>;
}
nameable! {
- pub struct Name['a, 'ctx, T];
- impl [T::Name] for dyn Value<T> + 'a where { T: TypeNameable<'a, 'ctx> + ?Sized }
- impl [T] where dyn Value<T::Nameable> + 'a { T: TypeName<'a, 'ctx> + ?Sized }
+ pub struct Name['a, 'ctx, T, E];
+
+ impl [T::Name, E] for dyn Value<'a, T, E> + 'a where {
+ T: TypeNameable<'a, 'ctx> + ?Sized,
+ E: Effect + 'static,
+ }
+
+ impl [T, E] where dyn Value<'a, T::Nameable, E> + 'a {
+ T: TypeName<'a, 'ctx> + ?Sized,
+ E: Effect + 'static,
+ }
}
// This enrolls the Value protocol into the walker hint system.
-impl<'ctx, T> HintMeta<'ctx> for dyn Value<T> + '_ {
+impl<'ctx, T, E: Effect> HintMeta<'ctx> for dyn Value<'_, T, E> + '_ {
type Known<'a> = () where 'ctx: 'a;
- type Hint = ();
+ type Hint<'a> = () where 'ctx: 'a;
}
#[cfg(test)]
mod test {
+ use core::ops::ControlFlow;
+
use crate::{
any::{
static_wrapper::{BorrowedMutStatic, BorrowedStatic, OwnedStatic},
AnyTrait,
},
any_trait,
+ protocol::SyncControlFlow,
};
use super::*;
@@ -53,15 +64,21 @@ mod test {
fn visit() {
struct Visitor(Option<i32>);
- impl Value<OwnedStatic<i32>> for Visitor {
- fn visit(&mut self, OwnedStatic(value): OwnedStatic<i32>) -> ControlFlow<()> {
+ impl Value<'_, OwnedStatic<i32>, SyncControlFlow> for Visitor {
+ fn visit(
+ &mut self,
+ OwnedStatic(value): OwnedStatic<i32>,
+ ) -> core::ops::ControlFlow<()> {
self.0 = Some(value);
ControlFlow::Continue(())
}
}
- impl Value<BorrowedStatic<'_, i32>> for Visitor {
- fn visit(&mut self, BorrowedStatic(value): BorrowedStatic<'_, i32>) -> ControlFlow<()> {
+ impl Value<'_, BorrowedStatic<'_, i32>, SyncControlFlow> for Visitor {
+ fn visit(
+ &mut self,
+ BorrowedStatic(value): BorrowedStatic<'_, i32>,
+ ) -> core::ops::ControlFlow<()> {
self.0 = Some(*value);
ControlFlow::Continue(())
}
@@ -69,15 +86,15 @@ mod test {
any_trait! {
impl['a, 'ctx] Visitor = [
- dyn Value<OwnedStatic<i32>>,
- dyn Value<BorrowedStatic<'ctx, i32>>,
+ dyn Value<'a, OwnedStatic<i32>, SyncControlFlow> + 'a,
+ dyn Value<'a, BorrowedStatic<'ctx, i32, SyncControlFlow>> + 'a,
];
}
let mut v = Visitor(None);
let object: &mut dyn AnyTrait<'_> = &mut v;
object
- .upcast_mut::<dyn Value<OwnedStatic<i32>>>()
+ .upcast_mut::<dyn Value<'_, OwnedStatic<i32, SyncControlFlow>>>()
.unwrap()
.visit(OwnedStatic(42));
@@ -85,7 +102,7 @@ mod test {
let object: &mut dyn AnyTrait<'_> = &mut v;
object
- .upcast_mut::<dyn Value<BorrowedStatic<'_, i32>>>()
+ .upcast_mut::<dyn Value<'_, BorrowedStatic<'_, i32, SyncControlFlow>>>()
.unwrap()
.visit(BorrowedStatic(&101));
diff --git a/src/protocol/walker/hint.rs b/src/protocol/walker/hint.rs
index c7d85d1..abdb136 100644
--- a/src/protocol/walker/hint.rs
+++ b/src/protocol/walker/hint.rs
@@ -7,7 +7,7 @@
use crate::{
any::{TypeName, TypeNameable},
nameable,
- protocol::{ControlFlow, Visitor},
+ protocol::{ControlFlowFor, Effect, SyncEffect, Visitor},
};
/// Meta information for the hint.
@@ -17,38 +17,57 @@ pub trait HintMeta<'ctx> {
/// Information known by the walker.
///
/// This should be information easy to get without changing the state of the walker
- /// in an irreversable way.
+ /// in an irreversible way.
type Known<'a>
where
'ctx: 'a;
/// Extra information the visitor can give to the walker about what it is expecting.
- type Hint;
+ type Hint<'a>
+ where
+ 'ctx: 'a;
}
/// Object implementing the [`Hint`] protocol.
-pub trait Hint<'ctx, Protocol: HintMeta<'ctx>> {
+pub trait Hint<'ctx, Protocol: HintMeta<'ctx>, E: Effect = SyncEffect> {
/// Hint to the walker to use the `P` protocol.
///
/// This should only be called once per [`RequestHint`].
- fn hint(&mut self, visitor: Visitor<'_, 'ctx>, hint: Protocol::Hint) -> ControlFlow;
+ fn hint<'a>(
+ &'a mut self,
+ visitor: &'a mut Visitor<'ctx>,
+ hint: Protocol::Hint<'a>,
+ ) -> ControlFlowFor<'a, E>;
/// Ask the walker for information about it's support of the protocol.
- fn known(&mut self, hint: &Protocol::Hint) -> ControlFlow<(), Protocol::Known<'_>>;
+ fn known<'a>(
+ &'a mut self,
+ hint: &'a Protocol::Hint<'a>,
+ ) -> ControlFlowFor<'a, E, Protocol::Known<'_>>
+ where
+ 'ctx: 'a;
}
nameable! {
- pub struct Name['a, 'ctx, Protocol];
- impl [Protocol::Name] for dyn Hint<'ctx, Protocol> + 'a where {
- Protocol: TypeNameable<'a, 'ctx> + ?Sized, 'ctx: 'a
+ pub struct Name['a, 'ctx, Protocol, E];
+
+ impl [Protocol::Name, E] for dyn Hint<'ctx, Protocol, E> + 'a where {
+ Protocol: TypeNameable<'a, 'ctx> + ?Sized,
+ E: Effect + 'static,
+ 'ctx: 'a,
}
- impl [Protocol] where dyn Hint<'ctx, Protocol::Nameable> + 'a {
- Protocol: TypeName<'a, 'ctx> + ?Sized, 'ctx: 'a
+
+ impl [Protocol, E] where dyn Hint<'ctx, Protocol::Nameable, E> + 'a {
+ Protocol: TypeName<'a, 'ctx> + ?Sized,
+ E: Effect + 'static,
+ 'ctx: 'a,
}
}
#[cfg(test)]
mod test {
+ use core::ops::ControlFlow;
+
use crate::any::{LtTypeId, TypeNameable};
use super::*;
@@ -64,18 +83,21 @@ mod test {
}
impl<'ctx, X> Hint<'ctx, Y> for X {
- fn hint(
- &mut self,
- visitor: Visitor<'_, 'ctx>,
- hint: <Y as HintMeta<'_>>::Hint,
+ fn hint<'a>(
+ &'a mut self,
+ visitor: &'a mut Visitor<'ctx>,
+ hint: <Y as HintMeta<'ctx>>::Hint<'a>,
) -> ControlFlow<()> {
todo!()
}
- fn known(
- &mut self,
- hint: &<Y as HintMeta<'_>>::Hint,
- ) -> ControlFlow<(), <Y as HintMeta<'_>>::Known<'_>> {
+ fn known<'a>(
+ &'a mut self,
+ hint: &'a <Y as HintMeta<'ctx>>::Hint<'a>,
+ ) -> ControlFlow<(), <Y as HintMeta<'ctx>>::Known<'a>>
+ where
+ 'ctx: 'a,
+ {
todo!()
}
}
@@ -83,7 +105,7 @@ mod test {
impl<'ctx> HintMeta<'ctx> for Y {
type Known<'a> = () where 'ctx: 'a;
- type Hint = ();
+ type Hint<'a> = () where 'ctx: 'a;
}
let x = X;
diff --git a/src/walk.rs b/src/walk.rs
index 9eda9d8..88f3287 100644
--- a/src/walk.rs
+++ b/src/walk.rs
@@ -1,7 +1,7 @@
// pub mod protocols;
// pub mod walkers;
-use crate::protocol::Visitor;
+use crate::protocol::{ControlFlowFor, Effect, Visitor};
/// A type that can be walked.
pub trait Walk<'ctx>: Sized {
@@ -9,6 +9,10 @@ pub trait Walk<'ctx>: Sized {
type Walker: Walker<'ctx> + From<Self>;
}
+pub fn into_walker<'ctx, T: Walk<'ctx>>(value: T) -> T::Walker {
+ <T as Walk<'ctx>>::Walker::from(value)
+}
+
/// Walker for a type.
///
/// The `'ctx` lifetime is some lifetime that is longer than `Self`.
@@ -19,7 +23,8 @@ pub trait Walk<'ctx>: Sized {
/// - Call [Self::walk()] to walk the value. Data will be sent to the provided
/// visitor.
pub trait Walker<'ctx> {
- /// Error that can happen while walking the value.
+ type Effect: Effect;
+
type Error;
/// An arbitrary type the walker is left with after walking.
@@ -30,5 +35,9 @@ pub trait Walker<'ctx> {
/// Walk the value.
///
/// The walker should send data to the `visitor` as it walks the value.
- fn walk(self, visitor: Visitor<'_, 'ctx>) -> Result<Self::Output, Self::Error>;
+ #[must_use]
+ fn walk<'a>(
+ self,
+ visitor: &'a mut Visitor<'ctx>,
+ ) -> ControlFlowFor<'a, Self::Effect, Self::Output, Self::Error>;
}
diff --git a/tests/async.rs b/tests/async.rs
new file mode 100644
index 0000000..2c446a1
--- /dev/null
+++ b/tests/async.rs
@@ -0,0 +1,148 @@
+use std::{collections::VecDeque, future::Future, ops::ControlFlow, pin::Pin};
+use treaty::{
+ any::{any_trait, static_wrapper::OwnedStatic},
+ async_build_with, build_with, into_walker,
+ protocol::{
+ visitor::{Sequence, SequenceScope, Status, Value},
+ AsyncEffect, ControlFlowFor, Visitor,
+ },
+ Builder, Walk, Walker,
+};
+
+#[tokio::test]
+async fn demo() {
+ let a = Data::Sequence(vec![
+ Data::Bool(true),
+ Data::Sequence(vec![Data::Bool(false), Data::Bool(true)]),
+ Data::Bool(false),
+ ]);
+
+ let s = async_build_with::<JsonLike, _>(into_walker(a))
+ .await
+ .unwrap();
+
+ assert_eq!(s, "[true,[false,true,],false,]");
+}
+
+#[derive(Debug)]
+enum Data {
+ Bool(bool),
+ Sequence(Vec<Data>),
+}
+
+const _: () = {
+ struct Impl(Data);
+
+ impl From<Data> for Impl {
+ fn from(value: Data) -> Self {
+ Self(value)
+ }
+ }
+
+ impl<'ctx> Walk<'ctx> for Data {
+ type Walker = Impl;
+ }
+
+ impl<'ctx> Walker<'ctx> for Impl {
+ type Effect = AsyncEffect;
+
+ type Error = ();
+
+ type Output = ();
+
+ fn walk<'a>(self, visitor: &'a mut Visitor<'ctx>) -> ControlFlowFor<'a, AsyncEffect> {
+ Box::pin(async {
+ match self.0 {
+ Data::Bool(value) => walk_bool(value, visitor),
+ Data::Sequence(value) => walk_vec(value, visitor).await,
+ }
+ core::ops::ControlFlow::Continue(())
+ })
+ }
+ }
+};
+
+fn walk_bool(value: bool, visitor: &mut Visitor<'_>) {
+ visitor
+ .upcast_mut::<dyn Value<OwnedStatic<bool>>>()
+ .unwrap()
+ .visit(OwnedStatic(value));
+}
+
+async fn walk_vec(value: Vec<Data>, visitor: &mut Visitor<'_>) {
+ struct Scope(VecDeque<Data>);
+
+ impl<'ctx> SequenceScope<'ctx, AsyncEffect> for Scope {
+ fn next<'a>(
+ &'a mut self,
+ visitor: &'a mut Visitor<'ctx>,
+ ) -> ControlFlowFor<'a, AsyncEffect, Status> {
+ Box::pin(async {
+ if let Some(value) = self.0.pop_front() {
+ into_walker(value).walk(visitor).await;
+
+ ControlFlow::Continue(Status::Continue)
+ } else {
+ ControlFlow::Continue(Status::Done)
+ }
+ })
+ }
+ }
+
+ let mut scope = Scope(value.into());
+
+ visitor
+ .upcast_mut::<dyn Sequence<'_, AsyncEffect>>()
+ .unwrap()
+ .visit(&mut scope)
+ .await;
+}
+
+#[derive(Default)]
+struct JsonLike(String);
+
+impl<'ctx> Builder<'ctx> for JsonLike {
+ type Error = ();
+
+ type Value = String;
+
+ fn as_visitor(&mut self) -> &mut Visitor<'ctx> {
+ self
+ }
+
+ fn build(self) -> Result<Self::Value, Self::Error> {
+ Ok(self.0)
+ }
+}
+
+any_trait! {
+ impl['a, 'ctx] JsonLike = [
+ dyn Value<'a, OwnedStatic<bool>> + 'a,
+ dyn Sequence<'ctx, AsyncEffect> + 'a,
+ ];
+}
+
+impl Value<'_, OwnedStatic<bool>> for JsonLike {
+ fn visit(&mut self, value: OwnedStatic<bool>) -> core::ops::ControlFlow<()> {
+ self.0.push_str(&format!("{}", value.0));
+ std::ops::ControlFlow::Continue(())
+ }
+}
+
+impl<'ctx> Sequence<'ctx, AsyncEffect> for JsonLike {
+ fn visit<'a>(
+ &'a mut self,
+ scope: &'a mut dyn SequenceScope<'ctx, AsyncEffect>,
+ ) -> ControlFlowFor<'a, AsyncEffect> {
+ Box::pin(async {
+ self.0.push_str("[");
+ while let std::ops::ControlFlow::Continue(treaty::protocol::visitor::Status::Continue) =
+ scope.next(self).await
+ {
+ self.0.push_str(",");
+ }
+ self.0.push_str("]");
+ std::ops::ControlFlow::Continue(())
+ })
+ }
+}
diff --git a/tests/demo.rs b/tests/demo.rs
index 6f3565b..9baf602 100644
--- a/tests/demo.rs
+++ b/tests/demo.rs
@@ -1,9 +1,10 @@
-use std::{any::TypeId, collections::VecDeque, ops::ControlFlow};
+use std::{collections::VecDeque, ops::ControlFlow};
use treaty::{
any::{any_trait, static_wrapper::OwnedStatic},
+ build_with, into_walker,
protocol::{
visitor::{Sequence, SequenceScope, Value},
- Visitor,
+ SyncEffect, Visitor,
},
Builder, Walk, Walker,
};
@@ -16,11 +17,9 @@ fn demo() {
Data::Bool(false),
]);
- let mut builder = JsonLike::default();
- <Data as Walk>::Walker::from(a).walk(builder.as_visitor()).unwrap();
- dbg!(builder.build().unwrap());
+ let s = build_with::<JsonLike, _>(into_walker(a)).unwrap();
- todo!()
+ assert_eq!(s, "[true,[false,true,],false,]");
}
#[derive(Debug)]
@@ -43,37 +42,42 @@ const _: () = {
}
impl<'ctx> Walker<'ctx> for Impl {
+ type Effect = SyncEffect;
+
type Error = ();
type Output = ();
- fn walk(self, visitor: Visitor<'_, 'ctx>) -> Result<Self::Output, Self::Error> {
+ fn walk(
+ self,
+ visitor: &mut Visitor<'ctx>,
+ ) -> core::ops::ControlFlow<Self::Error, Self::Output> {
match self.0 {
Data::Bool(value) => walk_bool(value, visitor),
Data::Sequence(value) => walk_vec(value, visitor),
}
- Ok(())
+ core::ops::ControlFlow::Continue(())
}
}
};
-fn walk_bool(value: bool, visitor: Visitor<'_, '_>) {
+fn walk_bool(value: bool, visitor: &mut Visitor<'_>) {
visitor
.upcast_mut::<dyn Value<OwnedStatic<bool>>>()
.unwrap()
.visit(OwnedStatic(value));
}
-fn walk_vec(value: Vec<Data>, visitor: Visitor<'_, '_>) {
+fn walk_vec(value: Vec<Data>, visitor: &mut Visitor<'_>) {
struct Scope(VecDeque<Data>);
impl<'ctx> SequenceScope<'ctx> for Scope {
fn next(
&mut self,
- visitor: Visitor<'_, 'ctx>,
- ) -> treaty::protocol::ControlFlow<(), treaty::protocol::visitor::Status> {
+ visitor: &mut Visitor<'ctx>,
+ ) -> core::ops::ControlFlow<(), treaty::protocol::visitor::Status> {
if let Some(value) = self.0.pop_front() {
- <<Data as Walk>::Walker>::from(value).walk(visitor).unwrap();
+ into_walker(value).walk(visitor);
ControlFlow::Continue(treaty::protocol::visitor::Status::Continue)
} else {
@@ -98,7 +102,7 @@ impl<'ctx> Builder<'ctx> for JsonLike {
type Value = String;
- fn as_visitor(&mut self) -> Visitor<'_, 'ctx> {
+ fn as_visitor(&mut self) -> &mut Visitor<'ctx> {
self
}
@@ -109,20 +113,20 @@ impl<'ctx> Builder<'ctx> for JsonLike {
any_trait! {
impl['a, 'ctx] JsonLike = [
- dyn Value<OwnedStatic<bool>> + 'a,
+ dyn Value<'a, OwnedStatic<bool>> + 'a,
dyn Sequence<'ctx> + 'a,
];
}
-impl Value<OwnedStatic<bool>> for JsonLike {
- fn visit(&mut self, value: OwnedStatic<bool>) -> treaty::protocol::ControlFlow {
+impl Value<'_, OwnedStatic<bool>> for JsonLike {
+ fn visit(&mut self, value: OwnedStatic<bool>) -> core::ops::ControlFlow<()> {
self.0.push_str(&format!("{}", value.0));
ControlFlow::Continue(())
}
}
impl<'ctx> Sequence<'ctx> for JsonLike {
- fn visit(&mut self, scope: &mut dyn SequenceScope<'ctx>) -> treaty::protocol::ControlFlow {
+ fn visit(&mut self, scope: &mut dyn SequenceScope<'ctx>) -> core::ops::ControlFlow<()> {
self.0.push_str("[");
while let ControlFlow::Continue(treaty::protocol::visitor::Status::Continue) =
scope.next(self)