From e04f6bf53235406d366adcc2e313c6ed75478756 Mon Sep 17 00:00:00 2001 From: Techcable Date: Sun, 29 Jun 2025 11:38:37 -0700 Subject: [PATCH 1/4] Implement sval2 support Supports serialization without nesting --- Cargo.toml | 5 +- src/lib.rs | 2 + src/sval2.rs | 36 +++++++++++++++ test-sval2/Cargo.toml | 13 ++++++ test-sval2/src/lib.rs | 104 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 src/sval2.rs create mode 100644 test-sval2/Cargo.toml create mode 100644 test-sval2/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index f7fa6c5e..ae6e829b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ arbitrary = { version = "1.0", optional = true, default-features = false } quickcheck = { version = "1.0", optional = true, default-features = false } serde = { version = "1.0", optional = true, default-features = false } rayon = { version = "1.9", optional = true } +sval2 = { package = "sval", version = "2", optional = true, default-features = false } # deprecated: use borsh's "indexmap" feature instead. borsh = { version = "1.2", optional = true, default-features = false } @@ -51,11 +52,11 @@ sign-tag = true tag-name = "{{version}}" [package.metadata.docs.rs] -features = ["arbitrary", "quickcheck", "serde", "borsh", "rayon"] +features = ["arbitrary", "quickcheck", "serde", "borsh", "rayon", "sval2"] rustdoc-args = ["--cfg", "docsrs"] [workspace] -members = ["test-nostd", "test-serde"] +members = ["test-nostd", "test-serde", "test-sval2"] [lints.clippy] style = "allow" diff --git a/src/lib.rs b/src/lib.rs index 04995a27..211ac4af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,6 +115,8 @@ mod macros; mod borsh; #[cfg(feature = "serde")] mod serde; +#[cfg(feature = "sval2")] +mod sval2; mod util; pub mod map; diff --git a/src/sval2.rs b/src/sval2.rs new file mode 100644 index 00000000..23ac6fc5 --- /dev/null +++ b/src/sval2.rs @@ -0,0 +1,36 @@ +#![cfg_attr(docsrs, doc(cfg(feature = "serde")))] + +use crate::{IndexMap, IndexSet}; +use sval2::{Stream, Value}; + +impl Value for IndexMap { + fn stream<'sval, ST: Stream<'sval> + ?Sized>(&'sval self, stream: &mut ST) -> sval2::Result { + stream.map_begin(Some(self.len()))?; + + for (k, v) in self { + stream.map_key_begin()?; + stream.value(k)?; + stream.map_key_end()?; + + stream.map_value_begin()?; + stream.value(v)?; + stream.map_value_end()?; + } + + stream.map_end() + } +} + +impl Value for IndexSet { + fn stream<'sval, ST: Stream<'sval> + ?Sized>(&'sval self, stream: &mut ST) -> sval2::Result { + stream.seq_begin(Some(self.len()))?; + + for value in self { + stream.seq_value_begin()?; + stream.value(value)?; + stream.seq_value_end()?; + } + + stream.seq_end() + } +} diff --git a/test-sval2/Cargo.toml b/test-sval2/Cargo.toml new file mode 100644 index 00000000..c5e1db53 --- /dev/null +++ b/test-sval2/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "test-sval2" +version = "0.1.0" +publish = false +edition = "2021" + +[dependencies] + +[dev-dependencies] +fnv = "1.0" +indexmap = { path = "..", features = ["sval2"] } +sval2 = { package = "sval", version = "2", features = ["derive"] } +sval2_test = { package = "sval_test", version = "2" } diff --git a/test-sval2/src/lib.rs b/test-sval2/src/lib.rs new file mode 100644 index 00000000..447ca51a --- /dev/null +++ b/test-sval2/src/lib.rs @@ -0,0 +1,104 @@ +#![cfg(test)] + +use fnv::FnvBuildHasher; +use indexmap::{indexmap, indexset, IndexMap, IndexSet}; +use sval2_test::{assert_tokens, Token}; + +#[test] +fn test_sval2_map() { + let map = indexmap! { 1 => 2, 3 => 4 }; + assert_tokens( + &map, + &[ + Token::MapBegin(Some(2)), + Token::MapKeyBegin, + Token::I32(1), + Token::MapKeyEnd, + Token::MapValueBegin, + Token::I32(2), + Token::MapValueEnd, + Token::MapKeyBegin, + Token::I32(3), + Token::MapKeyEnd, + Token::MapValueBegin, + Token::I32(4), + Token::MapValueEnd, + Token::MapEnd, + ], + ); +} + +#[test] +fn test_sval2_set() { + let set = indexset! { 1, 2, 3, 4 }; + assert_tokens( + &set, + &[ + Token::SeqBegin(Some(4)), + Token::SeqValueBegin, + Token::I32(1), + Token::SeqValueEnd, + Token::SeqValueBegin, + Token::I32(2), + Token::SeqValueEnd, + Token::SeqValueBegin, + Token::I32(3), + Token::SeqValueEnd, + Token::SeqValueBegin, + Token::I32(4), + Token::SeqValueEnd, + Token::SeqEnd, + ], + ); +} + +#[test] +fn test_sval2_map_fnv_hasher() { + let mut map: IndexMap = Default::default(); + map.insert(1, 2); + map.insert(3, 4); + assert_tokens( + &map, + &[ + Token::MapBegin(Some(2)), + Token::MapKeyBegin, + Token::I32(1), + Token::MapKeyEnd, + Token::MapValueBegin, + Token::I32(2), + Token::MapValueEnd, + Token::MapKeyBegin, + Token::I32(3), + Token::MapKeyEnd, + Token::MapValueBegin, + Token::I32(4), + Token::MapValueEnd, + Token::MapEnd, + ], + ); +} + +#[test] +fn test_sval2_set_fnv_hasher() { + let mut set: IndexSet = Default::default(); + set.extend(1..5); + assert_tokens( + &set, + &[ + Token::SeqBegin(Some(4)), + Token::SeqValueBegin, + Token::I32(1), + Token::SeqValueEnd, + Token::SeqValueBegin, + Token::I32(2), + Token::SeqValueEnd, + Token::SeqValueBegin, + Token::I32(3), + Token::SeqValueEnd, + Token::SeqValueBegin, + Token::I32(4), + Token::SeqValueEnd, + Token::SeqEnd, + ], + ); +} From 6586821f3d49890505b0f21c35c4f7bdd91240ba Mon Sep 17 00:00:00 2001 From: Techcable Date: Fri, 11 Jul 2025 22:24:23 -0700 Subject: [PATCH 2/4] Use feature name sval instead of sval2 --- Cargo.toml | 6 +++--- src/lib.rs | 4 ++-- src/{sval2.rs => sval.rs} | 6 +++--- test-sval/Cargo.toml | 13 +++++++++++++ {test-sval2 => test-sval}/src/lib.rs | 10 +++++----- test-sval2/Cargo.toml | 13 ------------- 6 files changed, 26 insertions(+), 26 deletions(-) rename src/{sval2.rs => sval.rs} (90%) create mode 100644 test-sval/Cargo.toml rename {test-sval2 => test-sval}/src/lib.rs (94%) delete mode 100644 test-sval2/Cargo.toml diff --git a/Cargo.toml b/Cargo.toml index ae6e829b..c00e1a21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ arbitrary = { version = "1.0", optional = true, default-features = false } quickcheck = { version = "1.0", optional = true, default-features = false } serde = { version = "1.0", optional = true, default-features = false } rayon = { version = "1.9", optional = true } -sval2 = { package = "sval", version = "2", optional = true, default-features = false } +sval = { version = "2", optional = true, default-features = false } # deprecated: use borsh's "indexmap" feature instead. borsh = { version = "1.2", optional = true, default-features = false } @@ -52,11 +52,11 @@ sign-tag = true tag-name = "{{version}}" [package.metadata.docs.rs] -features = ["arbitrary", "quickcheck", "serde", "borsh", "rayon", "sval2"] +features = ["arbitrary", "quickcheck", "serde", "borsh", "rayon", "sval"] rustdoc-args = ["--cfg", "docsrs"] [workspace] -members = ["test-nostd", "test-serde", "test-sval2"] +members = ["test-nostd", "test-serde", "test-sval"] [lints.clippy] style = "allow" diff --git a/src/lib.rs b/src/lib.rs index 211ac4af..1aa7cbab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,8 +115,8 @@ mod macros; mod borsh; #[cfg(feature = "serde")] mod serde; -#[cfg(feature = "sval2")] -mod sval2; +#[cfg(feature = "sval")] +mod sval; mod util; pub mod map; diff --git a/src/sval2.rs b/src/sval.rs similarity index 90% rename from src/sval2.rs rename to src/sval.rs index 23ac6fc5..9fad382c 100644 --- a/src/sval2.rs +++ b/src/sval.rs @@ -1,10 +1,10 @@ #![cfg_attr(docsrs, doc(cfg(feature = "serde")))] use crate::{IndexMap, IndexSet}; -use sval2::{Stream, Value}; +use sval::{Stream, Value}; impl Value for IndexMap { - fn stream<'sval, ST: Stream<'sval> + ?Sized>(&'sval self, stream: &mut ST) -> sval2::Result { + fn stream<'sval, ST: Stream<'sval> + ?Sized>(&'sval self, stream: &mut ST) -> sval::Result { stream.map_begin(Some(self.len()))?; for (k, v) in self { @@ -22,7 +22,7 @@ impl Value for IndexMap { } impl Value for IndexSet { - fn stream<'sval, ST: Stream<'sval> + ?Sized>(&'sval self, stream: &mut ST) -> sval2::Result { + fn stream<'sval, ST: Stream<'sval> + ?Sized>(&'sval self, stream: &mut ST) -> sval::Result { stream.seq_begin(Some(self.len()))?; for value in self { diff --git a/test-sval/Cargo.toml b/test-sval/Cargo.toml new file mode 100644 index 00000000..a363f984 --- /dev/null +++ b/test-sval/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "test-sval" +version = "0.1.0" +publish = false +edition = "2021" + +[dependencies] + +[dev-dependencies] +fnv = "1.0" +indexmap = { path = "..", features = ["sval"] } +sval = { version = "2", features = ["derive"] } +sval_test = "2" diff --git a/test-sval2/src/lib.rs b/test-sval/src/lib.rs similarity index 94% rename from test-sval2/src/lib.rs rename to test-sval/src/lib.rs index 447ca51a..41531aad 100644 --- a/test-sval2/src/lib.rs +++ b/test-sval/src/lib.rs @@ -2,10 +2,10 @@ use fnv::FnvBuildHasher; use indexmap::{indexmap, indexset, IndexMap, IndexSet}; -use sval2_test::{assert_tokens, Token}; +use sval_test::{assert_tokens, Token}; #[test] -fn test_sval2_map() { +fn test_sval_map() { let map = indexmap! { 1 => 2, 3 => 4 }; assert_tokens( &map, @@ -29,7 +29,7 @@ fn test_sval2_map() { } #[test] -fn test_sval2_set() { +fn test_sval_set() { let set = indexset! { 1, 2, 3, 4 }; assert_tokens( &set, @@ -53,7 +53,7 @@ fn test_sval2_set() { } #[test] -fn test_sval2_map_fnv_hasher() { +fn test_sval_map_fnv_hasher() { let mut map: IndexMap = Default::default(); map.insert(1, 2); map.insert(3, 4); @@ -79,7 +79,7 @@ fn test_sval2_map_fnv_hasher() { } #[test] -fn test_sval2_set_fnv_hasher() { +fn test_sval_set_fnv_hasher() { let mut set: IndexSet = Default::default(); set.extend(1..5); assert_tokens( diff --git a/test-sval2/Cargo.toml b/test-sval2/Cargo.toml deleted file mode 100644 index c5e1db53..00000000 --- a/test-sval2/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "test-sval2" -version = "0.1.0" -publish = false -edition = "2021" - -[dependencies] - -[dev-dependencies] -fnv = "1.0" -indexmap = { path = "..", features = ["sval2"] } -sval2 = { package = "sval", version = "2", features = ["derive"] } -sval2_test = { package = "sval_test", version = "2" } From 30f27ba64cdbb1550061daaed936fd794f6b19bb Mon Sep 17 00:00:00 2001 From: Techcable Date: Fri, 18 Jul 2025 12:33:53 -0700 Subject: [PATCH 3/4] Correct doc(cfg(...)) for sval module Co-authored-by: Josh Stone --- src/sval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sval.rs b/src/sval.rs index 9fad382c..73f096cf 100644 --- a/src/sval.rs +++ b/src/sval.rs @@ -1,4 +1,4 @@ -#![cfg_attr(docsrs, doc(cfg(feature = "serde")))] +#![cfg_attr(docsrs, doc(cfg(feature = "sval")))] use crate::{IndexMap, IndexSet}; use sval::{Stream, Value}; From 44cbb0331dc7eeab2a65c606d948756a36bc8b71 Mon Sep 17 00:00:00 2001 From: Techcable Date: Fri, 18 Jul 2025 12:38:42 -0700 Subject: [PATCH 4/4] Add serde to CI test matrix Mirrors the testing of serde. --- .github/workflows/ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 87ca19b4..e166236f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,8 @@ jobs: features: rayon - rust: stable features: serde + - rust: stable + features: sval - rust: stable features: borsh - rust: stable @@ -62,6 +64,10 @@ jobs: if: matrix.features == 'serde' run: | cargo test --verbose -p test-serde + - name: Tests (sval) + if: matrix.features == 'sval' + run: | + cargo test --verbose -p test-sval - name: Test run benchmarks if: matrix.bench != '' run: cargo test -v --benches @@ -141,7 +147,7 @@ jobs: - name: Build (nightly) run: cargo +nightly build --verbose --all-features - name: Build (MSRV) - run: cargo build --verbose --features arbitrary,quickcheck,serde,rayon + run: cargo build --verbose --features arbitrary,quickcheck,serde,sval,rayon # One job that "summarizes" the success state of this pipeline. This can then be added to branch # protection, rather than having to add each job separately.