From af6810933e46b350b5c8c359ce2a3e9b11fd8a44 Mon Sep 17 00:00:00 2001 From: Wojciech Graj Date: Mon, 9 Mar 2026 13:17:51 +0100 Subject: [PATCH] Add schemars support The implementation is based on https://docs.rs/schemars/latest/src/schemars/json_schema_impls/arrayvec07.rs.html --- Cargo.toml | 8 ++++++-- src/arrayvec.rs | 37 ++++++++++++++++++++++++++++++++----- src/lib.rs | 2 ++ src/slicevec.rs | 4 ++-- src/tinyvec.rs | 31 +++++++++++++++++++++++++++++-- tests/arrayvec.rs | 6 +++--- tests/tinyvec.rs | 2 +- 7 files changed, 75 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 02c610f..bcfc028 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ generic-array = { version = "1.1.1", optional = true, default-features = false } bin-proto = { version = "0.12.5", optional = true, default-features = false } # Provides `Format` implementations defmt = { version = "1.0", optional = true } +# Provides `JsonSchema` implementations +schemars = { version = "1.0", optional = true, default-features = false } [features] @@ -82,12 +84,14 @@ experimental_write_impl = [] # and thus a nightly compiler, but is only used in benchmarks. real_blackbox = ["criterion/real_blackbox"] +schemars = ["dep:schemars", "alloc"] + [package.metadata.docs.rs] -features = ["alloc", "std", "grab_spare_slice", "latest_stable_rust", "serde", "borsh", "defmt", "bin-proto"] +features = ["alloc", "std", "grab_spare_slice", "latest_stable_rust", "serde", "borsh", "defmt", "bin-proto", "schemars"] rustdoc-args = ["--cfg","docs_rs"] [package.metadata.playground] -features = ["alloc", "std", "grab_spare_slice", "latest_stable_rust", "serde", "borsh"] +features = ["alloc", "std", "grab_spare_slice", "latest_stable_rust", "serde", "borsh", "schemars"] [profile.dev] lto = "thin" diff --git a/src/arrayvec.rs b/src/arrayvec.rs index 04d6dac..8e69342 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -362,6 +362,33 @@ where } } +#[cfg(feature = "schemars")] +#[cfg_attr(docs_rs, doc(cfg(feature = "schemars")))] +impl schemars::JsonSchema for ArrayVec +where + A: Array, + ::Item: schemars::JsonSchema, +{ + fn schema_name() -> alloc::borrow::Cow<'static, str> { + alloc::format!( + "Array_up_to_size_{}_of_{}", + A::CAPACITY, + ::Item::schema_name() + ) + .into() + } + + fn json_schema( + generator: &mut schemars::SchemaGenerator, + ) -> schemars::Schema { + schemars::json_schema!({ + "type": "array", + "items": generator.subschema_for::<::Item>(), + "maxItems": A::CAPACITY + }) + } +} + impl ArrayVec { /// Move all values from `other` into this vec. /// @@ -493,7 +520,7 @@ impl ArrayVec { /// assert_eq!(av2.as_slice(), &[2, 3][..]); /// /// av.drain(..); - /// assert_eq!(av.as_slice(), &[]); + /// assert_eq!(av.as_slice(), &[] as &[i32]); /// ``` #[inline] pub fn drain(&mut self, range: R) -> ArrayVecDrain<'_, A::Item> @@ -758,7 +785,7 @@ impl ArrayVec { /// ```rust /// # use tinyvec::*; /// let mut av = array_vec!([i32; 2]); - /// assert_eq!(&av[..], []); + /// assert_eq!(&av[..], [] as [i32; 0]); /// av.push(1); /// assert_eq!(&av[..], [1]); /// av.push(2); @@ -777,7 +804,7 @@ impl ArrayVec { /// ```rust /// # use tinyvec::*; /// let mut av = array_vec!([i32; 2]); - /// assert_eq!(av.as_slice(), []); + /// assert_eq!(av.as_slice(), [] as [i32; 0]); /// assert_eq!(av.try_push(1), None); /// assert_eq!(&av[..], [1]); /// assert_eq!(av.try_push(2), None); @@ -1090,7 +1117,7 @@ impl ArrayVec { /// assert_eq!(av2.as_slice(), &[2, 3][..]); /// /// av.splice(.., None); - /// assert_eq!(av.as_slice(), &[]); + /// assert_eq!(av.as_slice(), &[] as &[i32]); /// ``` #[inline] pub fn splice( @@ -1246,7 +1273,7 @@ impl ArrayVec { /// ```rust /// # use tinyvec::ArrayVec; /// let mut data = ArrayVec::from_array_empty([1, 2, 3, 4]); - /// assert_eq!(&data[..], &[]); + /// assert_eq!(&data[..], &[] as &[i32]); /// data.push(42); /// assert_eq!(&data[..], &[42]); /// ``` diff --git a/src/lib.rs b/src/lib.rs index b8110cf..2d27927 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,6 +57,8 @@ //! implementation. //! * `defmt` provides a `Format` implementation for all types, provided the //! inner item also has an implementation. +//! * `schemars` provides a `JsonSchema` implementation for [`TinyVec`] and +//! [`ArrayVec`] types, provided the inner item also has an implementation. //! //! ## API //! The general goal of the crate is that, as much as possible, the vecs here diff --git a/src/slicevec.rs b/src/slicevec.rs index 3a35d3a..e03efea 100644 --- a/src/slicevec.rs +++ b/src/slicevec.rs @@ -143,7 +143,7 @@ impl<'s, T> SliceVec<'s, T> { /// assert_eq!(drained_values.as_slice(), &[7, 8][..]); /// /// sv.drain(..); - /// assert_eq!(sv.as_slice(), &[]); + /// assert_eq!(sv.as_slice(), &[] as &[i32]); /// ``` #[inline] pub fn drain<'p, R: RangeBounds>( @@ -345,7 +345,7 @@ impl<'s, T> SliceVec<'s, T> { /// # use tinyvec::*; /// let mut arr = [0, 0]; /// let mut sv = SliceVec::from_slice_len(&mut arr, 0); - /// assert_eq!(&sv[..], []); + /// assert_eq!(&sv[..], [] as [i32; 0]); /// sv.push(1); /// assert_eq!(&sv[..], [1]); /// sv.push(2); diff --git a/src/tinyvec.rs b/src/tinyvec.rs index 28e4102..cd92795 100644 --- a/src/tinyvec.rs +++ b/src/tinyvec.rs @@ -339,6 +339,33 @@ where } } +#[cfg(feature = "schemars")] +#[cfg_attr(docs_rs, doc(cfg(feature = "schemars")))] +impl schemars::JsonSchema for TinyVec +where + A: Array, + ::Item: schemars::JsonSchema, +{ + fn schema_name() -> alloc::borrow::Cow<'static, str> { + alloc::format!( + "Array_up_to_size_{}_of_{}", + A::CAPACITY, + ::Item::schema_name() + ) + .into() + } + + fn json_schema( + generator: &mut schemars::SchemaGenerator, + ) -> schemars::Schema { + schemars::json_schema!({ + "type": "array", + "items": generator.subschema_for::<::Item>(), + "maxItems": A::CAPACITY + }) + } +} + impl TinyVec { /// Returns whether elements are on heap #[inline(always)] @@ -912,7 +939,7 @@ impl TinyVec { /// assert_eq!(tv2.as_slice(), &[2, 3][..]); /// /// tv.drain(..); - /// assert_eq!(tv.as_slice(), &[]); + /// assert_eq!(tv.as_slice(), &[] as &[i32]); /// ``` #[inline] pub fn drain>( @@ -1167,7 +1194,7 @@ impl TinyVec { /// assert_eq!(tv2.as_slice(), &[2, 3][..]); /// /// tv.splice(.., None); - /// assert_eq!(tv.as_slice(), &[]); + /// assert_eq!(tv.as_slice(), &[] as &[i32]); /// ``` #[inline] pub fn splice( diff --git a/tests/arrayvec.rs b/tests/arrayvec.rs index f74d7e2..b280186 100644 --- a/tests/arrayvec.rs +++ b/tests/arrayvec.rs @@ -132,7 +132,7 @@ fn ArrayVec_append() { // av.append(&mut av2); assert_eq!(av.as_slice(), &[1_i32, 2, 3, 4, 5, 6]); - assert_eq!(av2.as_slice(), &[]); + assert_eq!(av2.as_slice(), &[] as &[i32]); } #[test] @@ -167,7 +167,7 @@ fn ArrayVec_swap_remove() { assert_eq!(av.swap_remove(0), 3); assert_eq!(&av[..], &[2][..]); assert_eq!(av.swap_remove(0), 2); - assert_eq!(&av[..], &[][..]); + assert_eq!(&av[..], &[][..] as &[i32]); } #[test] @@ -552,7 +552,7 @@ fn ArrayVec_try_from_slice() { let empty: Result, _> = ArrayVec::try_from(&nums[..0]); assert!(empty.is_ok()); - assert_eq!(empty.unwrap().as_slice(), &[]); + assert_eq!(empty.unwrap().as_slice(), &[] as &[i32]); let fits: Result, _> = ArrayVec::try_from(&nums[..2]); assert!(fits.is_ok()); diff --git a/tests/tinyvec.rs b/tests/tinyvec.rs index 12311ef..2f21aad 100644 --- a/tests/tinyvec.rs +++ b/tests/tinyvec.rs @@ -23,7 +23,7 @@ fn TinyVec_swap_remove() { assert_eq!(tv.swap_remove(0), 3); assert_eq!(&tv[..], &[2][..]); assert_eq!(tv.swap_remove(0), 2); - assert_eq!(&tv[..], &[][..]); + assert_eq!(&tv[..], &[][..] as &[i32]); } #[test]