Repository: GREsau/schemars
Pull request #192 (2022-12-03 00:09:45)

Set a reasonable min version for serde_json
The goal is use be able to compile a project using schemars with `cargo +nightly build -Zminimal-versions` to ensure the min versions are all set correctly. 

Here serde_json was set to ^1.0.0 but this is not the actual min version we need. serde_json 1.0.25 brings in the `json!` macro that is used here (https://github.com/serde-rs/json/releases/tag/v1.0.25).


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 382c922..8ed3bff 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,7 +16,7 @@ jobs:
           - beta
           - nightly
         include:
-          - rust: 1.45.0          
+          - rust: 1.45.0
             test_features: "--features impl_json_schema"
             allow_failure: false
           - rust: stable
@@ -35,10 +35,10 @@ jobs:
         with:
           profile: minimal
           toolchain: ${{ matrix.rust }}
-          override: true          
+          override: true
       - if: matrix.rust == '1.45.0'
         # work-around https://github.com/serde-rs/serde/issues/2255 and similar crate/rustc compatibility issues
-        run: cargo update -p serde --precise 1.0.142 && cargo update -p once_cell --precise 1.10.0 && cargo update -p pretty_assertions --precise 1.2.1
+        run: cargo update -p serde --precise 1.0.142 && cargo update -p once_cell --precise 1.10.0 && cargo update -p pretty_assertions --precise 1.2.1 && cargo update -p trybuild --precise 1.0.64
       - name: Check with no feature flags
         run: cargo check --verbose --no-default-features
         continue-on-error: ${{ matrix.allow_failure }}
diff --git a/README.md b/README.md
index a94bf7f..c9fe0d8 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Schemars
 
-[![CI Build](https://img.shields.io/github/workflow/status/GREsau/schemars/CI?logo=GitHub)](https://github.com/GREsau/schemars/actions)
+[![CI Build](https://img.shields.io/github/actions/workflow/status/GREsau/schemars/ci.yml?branch=master&logo=GitHub)](https://github.com/GREsau/schemars/actions)
 [![Crates.io](https://img.shields.io/crates/v/schemars)](https://crates.io/crates/schemars)
 [![Docs](https://docs.rs/schemars/badge.svg)](https://docs.rs/schemars)
 [![rustc 1.45+](https://img.shields.io/badge/schemars-rustc_1.45+-lightgray.svg)](https://blog.rust-lang.org/2020/07/16/Rust-1.45.0.html)
diff --git a/docs/1.1-attributes.md b/docs/1.1-attributes.md
index 2904968..251a6a1 100644
--- a/docs/1.1-attributes.md
+++ b/docs/1.1-attributes.md
@@ -208,7 +208,7 @@ Validator docs: [range](https://github.com/Keats/validator#range)
 
 <h3 id="regex">
 
-`#[validate(regex = "path::to::regex")]` / `#[schemars(regex = "path::to::regex")]`
+`#[validate(regex = "path::to::regex")]` / `#[schemars(regex = "path::to::regex")]`<br />
 `#[schemars(regex(pattern = r"^\d+$"))]`
 </h3>
 
diff --git a/schemars/Cargo.toml b/schemars/Cargo.toml
index 51fd64c..9f3fedd 100644
--- a/schemars/Cargo.toml
+++ b/schemars/Cargo.toml
@@ -15,7 +15,7 @@ build = "build.rs"
 [dependencies]
 schemars_derive = { version = "=0.8.11", optional = true, path = "../schemars_derive" }
 serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
+serde_json = "1.0.25"
 dyn-clone = "1.0"
 
 chrono = { version = "0.4", default-features = false, optional = true }
@@ -31,6 +31,7 @@ bytes = { version = "1.0", optional = true }
 rust_decimal = { version = "1", default-features = false, optional = true }
 bigdecimal = { version = "0.3", default-features = false, optional = true }
 enumset = { version = "1.0", optional = true }
+smol_str = { version = "0.1.17", optional = true }
 
 [dev-dependencies]
 pretty_assertions = "1.2.1"
@@ -102,5 +103,9 @@ required-features = ["url"]
 name = "enumset"
 required-features = ["enumset"]
 
+[[test]]
+name = "smol_str"
+required-features = ["smol_str"]
+
 [package.metadata.docs.rs]
 all-features = true
diff --git a/schemars/src/gen.rs b/schemars/src/gen.rs
index 8ae1740..58eaa61 100644
--- a/schemars/src/gen.rs
+++ b/schemars/src/gen.rs
@@ -263,7 +263,7 @@ impl SchemaGenerator {
     /// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the values are the schemas
     /// themselves.
     pub fn take_definitions(&mut self) -> Map<String, Schema> {
-        std::mem::replace(&mut self.definitions, Map::default())
+        std::mem::take(&mut self.definitions)
     }
 
     /// Returns an iterator over the [visitors](SchemaSettings::visitors) being used by this `SchemaGenerator`.
diff --git a/schemars/src/json_schema_impls/decimal.rs b/schemars/src/json_schema_impls/decimal.rs
index 6058a7f..d7fc8a1 100644
--- a/schemars/src/json_schema_impls/decimal.rs
+++ b/schemars/src/json_schema_impls/decimal.rs
@@ -25,7 +25,7 @@ macro_rules! decimal_impl {
     };
 }
 
-#[cfg(feature="rust_decimal")]
+#[cfg(feature = "rust_decimal")]
 decimal_impl!(rust_decimal::Decimal);
-#[cfg(feature="bigdecimal")]
+#[cfg(feature = "bigdecimal")]
 decimal_impl!(bigdecimal::BigDecimal);
diff --git a/schemars/src/json_schema_impls/mod.rs b/schemars/src/json_schema_impls/mod.rs
index 9925442..490a544 100644
--- a/schemars/src/json_schema_impls/mod.rs
+++ b/schemars/src/json_schema_impls/mod.rs
@@ -64,6 +64,8 @@ mod sequences;
 mod serdejson;
 #[cfg(feature = "smallvec")]
 mod smallvec;
+#[cfg(feature = "smol_str")]
+mod smol_str;
 mod time;
 mod tuple;
 #[cfg(feature = "url")]
diff --git a/schemars/src/json_schema_impls/smol_str.rs b/schemars/src/json_schema_impls/smol_str.rs
new file mode 100644
index 0000000..cbca4a1
--- /dev/null
+++ b/schemars/src/json_schema_impls/smol_str.rs
@@ -0,0 +1,6 @@
+use crate::gen::SchemaGenerator;
+use crate::schema::*;
+use crate::JsonSchema;
+use smol_str::SmolStr;
+
+forward_impl!(SmolStr => String);
diff --git a/schemars/src/ser.rs b/schemars/src/ser.rs
index fc2bba0..3f69bef 100644
--- a/schemars/src/ser.rs
+++ b/schemars/src/ser.rs
@@ -128,7 +128,7 @@ impl<'a> serde::Serializer for Serializer<'a> {
         self.serialize_none()
     }
 
-    fn serialize_some<T: ?Sized>(mut self, value: &T) -> Result<Self::Ok, Self::Error>
+    fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
     where
         T: serde::Serialize,
     {
@@ -153,7 +153,7 @@ impl<'a> serde::Serializer for Serializer<'a> {
         if self.gen.settings().option_add_null_type {
             schema = match schema {
                 Schema::Bool(true) => Schema::Bool(true),
-                Schema::Bool(false) => <()>::json_schema(&mut self.gen),
+                Schema::Bool(false) => <()>::json_schema(self.gen),
                 Schema::Object(SchemaObject {
                     instance_type: Some(ref mut instance_type),
                     ..
@@ -163,7 +163,7 @@ impl<'a> serde::Serializer for Serializer<'a> {
                 }
                 schema => SchemaObject {
                     subschemas: Some(Box::new(SubschemaValidation {
-                        any_of: Some(vec![schema, <()>::json_schema(&mut self.gen)]),
+                        any_of: Some(vec![schema, <()>::json_schema(self.gen)]),
                         ..Default::default()
                     })),
                     ..Default::default()
diff --git a/schemars_derive/src/attr/mod.rs b/schemars_derive/src/attr/mod.rs
index 26c1f3e..f790694 100644
--- a/schemars_derive/src/attr/mod.rs
+++ b/schemars_derive/src/attr/mod.rs
@@ -27,7 +27,7 @@ pub struct Attrs {
     pub examples: Vec<syn::Path>,
     pub repr: Option<syn::Type>,
     pub crate_name: Option<syn::Path>,
-    pub is_renamed: bool
+    pub is_renamed: bool,
 }
 
 #[derive(Debug)]
@@ -153,9 +153,7 @@ impl Attrs {
                     }
                 }
 
-                Meta(NameValue(m)) if m.path.is_ident("rename") => {
-                    self.is_renamed = true
-                }
+                Meta(NameValue(m)) if m.path.is_ident("rename") => self.is_renamed = true,
 
                 Meta(NameValue(m)) if m.path.is_ident("crate") && attr_type == "schemars" => {
                     if let Ok(p) = parse_lit_into_path(errors, attr_type, "crate", &m.lit) {
diff --git a/schemars_derive/src/attr/schemars_to_serde.rs b/schemars_derive/src/attr/schemars_to_serde.rs
index 781f5da..7878a2c 100644
--- a/schemars_derive/src/attr/schemars_to_serde.rs
+++ b/schemars_derive/src/attr/schemars_to_serde.rs
@@ -46,14 +46,14 @@ pub fn process_serde_attrs(input: &mut syn::DeriveInput) -> Result<(), Vec<syn::
 
 fn process_serde_variant_attrs<'a>(ctxt: &Ctxt, variants: impl Iterator<Item = &'a mut Variant>) {
     for v in variants {
-        process_attrs(&ctxt, &mut v.attrs);
-        process_serde_field_attrs(&ctxt, v.fields.iter_mut());
+        process_attrs(ctxt, &mut v.attrs);
+        process_serde_field_attrs(ctxt, v.fields.iter_mut());
     }
 }
 
 fn process_serde_field_attrs<'a>(ctxt: &Ctxt, fields: impl Iterator<Item = &'a mut Field>) {
     for f in fields {
-        process_attrs(&ctxt, &mut f.attrs);
+        process_attrs(ctxt, &mut f.attrs);
     }
 }
 
@@ -71,10 +71,10 @@ fn process_attrs(ctxt: &Ctxt, attrs: &mut Vec<Attribute>) {
     // Copy appropriate #[schemars(...)] attributes to #[serde(...)] attributes
     let (mut serde_meta, mut schemars_meta_names): (Vec<_>, HashSet<_>) = schemars_attrs
         .iter()
-        .flat_map(|at| get_meta_items(&ctxt, at))
+        .flat_map(|at| get_meta_items(ctxt, at))
         .flatten()
         .filter_map(|meta| {
-            let keyword = get_meta_ident(&ctxt, &meta).ok()?;
+            let keyword = get_meta_ident(ctxt, &meta).ok()?;
             if keyword.ends_with("with") || !SERDE_KEYWORDS.contains(&keyword.as_ref()) {
                 None
             } else {
@@ -91,10 +91,10 @@ fn process_attrs(ctxt: &Ctxt, attrs: &mut Vec<Attribute>) {
     // Re-add #[serde(...)] attributes that weren't overridden by #[schemars(...)] attributes
     for meta in serde_attrs
         .into_iter()
-        .flat_map(|at| get_meta_items(&ctxt, &at))
+        .flat_map(|at| get_meta_items(ctxt, &at))
         .flatten()
     {
-        if let Ok(i) = get_meta_ident(&ctxt, &meta) {
+        if let Ok(i) = get_meta_ident(ctxt, &meta) {
             if !schemars_meta_names.contains(&i)
                 && SERDE_KEYWORDS.contains(&i.as_ref())
                 && i != "bound"
diff --git a/schemars_derive/src/attr/validation.rs b/schemars_derive/src/attr/validation.rs
index 1a93a2a..a089a1d 100644
--- a/schemars_derive/src/attr/validation.rs
+++ b/schemars_derive/src/attr/validation.rs
@@ -112,7 +112,7 @@ impl ValidationAttrs {
                                 } else if self.length_equal.is_some() {
                                     mutual_exclusive_error(&nv.path, "equal")
                                 } else {
-                                    self.length_min = str_or_num_to_expr(&errors, "min", &nv.lit);
+                                    self.length_min = str_or_num_to_expr(errors, "min", &nv.lit);
                                 }
                             }
                             NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("max") => {
@@ -121,7 +121,7 @@ impl ValidationAttrs {
                                 } else if self.length_equal.is_some() {
                                     mutual_exclusive_error(&nv.path, "equal")
                                 } else {
-                                    self.length_max = str_or_num_to_expr(&errors, "max", &nv.lit);
+                                    self.length_max = str_or_num_to_expr(errors, "max", &nv.lit);
                                 }
                             }
                             NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("equal") => {
@@ -133,14 +133,14 @@ impl ValidationAttrs {
                                     mutual_exclusive_error(&nv.path, "max")
                                 } else {
                                     self.length_equal =
-                                        str_or_num_to_expr(&errors, "equal", &nv.lit);
+                                        str_or_num_to_expr(errors, "equal", &nv.lit);
                                 }
                             }
                             meta => {
                                 if !ignore_errors {
                                     errors.error_spanned_by(
                                         meta,
-                                        format!("unknown item in schemars length attribute"),
+                                        "unknown item in schemars length attribute".to_string(),
                                     );
                                 }
                             }
@@ -155,21 +155,21 @@ impl ValidationAttrs {
                                 if self.range_min.is_some() {
                                     duplicate_error(&nv.path)
                                 } else {
-                                    self.range_min = str_or_num_to_expr(&errors, "min", &nv.lit);
+                                    self.range_min = str_or_num_to_expr(errors, "min", &nv.lit);
                                 }
                             }
                             NestedMeta::Meta(Meta::NameValue(nv)) if nv.path.is_ident("max") => {
                                 if self.range_max.is_some() {
                                     duplicate_error(&nv.path)
                                 } else {
-                                    self.range_max = str_or_num_to_expr(&errors, "max", &nv.lit);
+                                    self.range_max = str_or_num_to_expr(errors, "max", &nv.lit);
                                 }
                             }
                             meta => {
                                 if !ignore_errors {
                                     errors.error_spanned_by(
                                         meta,
-                                        format!("unknown item in schemars range attribute"),
+                                        "unknown item in schemars range attribute".to_string(),
                                     );
                                 }
                             }
@@ -247,7 +247,7 @@ impl ValidationAttrs {
                                         if !ignore_errors {
                                             errors.error_spanned_by(
                                                 meta,
-                                                format!("unknown item in schemars regex attribute"),
+                                                "unknown item in schemars regex attribute".to_string(),
                                             );
                                         }
                                     }
@@ -261,8 +261,8 @@ impl ValidationAttrs {
                     if path.is_ident("contains") =>
                 {
                     match (&self.contains, &self.regex) {
-                        (Some(_), _) => duplicate_error(&path),
-                        (None, Some(_)) => mutual_exclusive_error(&path, "regex"),
+                        (Some(_), _) => duplicate_error(path),
+                        (None, Some(_)) => mutual_exclusive_error(path, "regex"),
                         (None, None) => {
                             self.contains = get_lit_str(errors, attr_type, "contains", lit)
                                 .map(|litstr| litstr.value())
@@ -292,9 +292,7 @@ impl ValidationAttrs {
                                         if !ignore_errors {
                                             errors.error_spanned_by(
                                                 meta,
-                                                format!(
-                                                    "unknown item in schemars contains attribute"
-                                                ),
+                                                "unknown item in schemars contains attribute".to_string(),
                                             );
                                         }
                                     }
@@ -319,7 +317,7 @@ impl ValidationAttrs {
         if let Some(length_min) = self
             .length_min
             .as_ref()
-            .or_else(|| self.length_equal.as_ref())
+            .or(self.length_equal.as_ref())
         {
             string_validation.push(quote! {
                 validation.min_length = Some(#length_min as u32);
@@ -332,7 +330,7 @@ impl ValidationAttrs {
         if let Some(length_max) = self
             .length_max
             .as_ref()
-            .or_else(|| self.length_equal.as_ref())
+            .or(self.length_equal.as_ref())
         {
             string_validation.push(quote! {
                 validation.max_length = Some(#length_max as u32);
diff --git a/schemars_derive/src/lib.rs b/schemars_derive/src/lib.rs
index 7e7060e..f8173f4 100644
--- a/schemars_derive/src/lib.rs
+++ b/schemars_derive/src/lib.rs
@@ -95,26 +95,27 @@ fn derive_json_schema(
 
     // FIXME improve handling of generic type params which may not implement JsonSchema
     let type_params: Vec<_> = cont.generics.type_params().map(|ty| &ty.ident).collect();
-    let schema_name = if type_params.is_empty() || (cont.attrs.is_renamed && !schema_base_name.contains('{')) {
-        quote! {
-            #schema_base_name.to_owned()
-        }
-    } else if cont.attrs.is_renamed {
-        let mut schema_name_fmt = schema_base_name;
-        for tp in &type_params {
-            schema_name_fmt.push_str(&format!("{{{}:.0}}", tp));
-        }
-        quote! {
-            format!(#schema_name_fmt #(,#type_params=#type_params::schema_name())*)
-        }
-    } else {
-        let mut schema_name_fmt = schema_base_name;
-        schema_name_fmt.push_str("_for_{}");
-        schema_name_fmt.push_str(&"_and_{}".repeat(type_params.len() - 1));
-        quote! {
-            format!(#schema_name_fmt #(,#type_params::schema_name())*)
-        }
-    };
+    let schema_name =
+        if type_params.is_empty() || (cont.attrs.is_renamed && !schema_base_name.contains('{')) {
+            quote! {
+                #schema_base_name.to_owned()
+            }
+        } else if cont.attrs.is_renamed {
+            let mut schema_name_fmt = schema_base_name;
+            for tp in &type_params {
+                schema_name_fmt.push_str(&format!("{{{}:.0}}", tp));
+            }
+            quote! {
+                format!(#schema_name_fmt #(,#type_params=#type_params::schema_name())*)
+            }
+        } else {
+            let mut schema_name_fmt = schema_base_name;
+            schema_name_fmt.push_str("_for_{}");
+            schema_name_fmt.push_str(&"_and_{}".repeat(type_params.len() - 1));
+            quote! {
+                format!(#schema_name_fmt #(,#type_params::schema_name())*)
+            }
+        };
 
     let schema_expr = if repr {
         schema_exprs::expr_for_repr(&cont).map_err(|e| vec![e])?


Test patch:
diff --git a/schemars/tests/bound.rs b/schemars/tests/bound.rs
index 8df3e91..cb545dd 100644
--- a/schemars/tests/bound.rs
+++ b/schemars/tests/bound.rs
@@ -18,7 +18,10 @@ impl Iterator for MyIterator {
 // which MyIterator does not.
 #[derive(JsonSchema)]
 #[schemars(bound = "T::Item: JsonSchema", rename = "MyContainer")]
-pub struct MyContainer<T> where T: Iterator {
+pub struct MyContainer<T>
+where
+    T: Iterator,
+{
     pub associated: T::Item,
     pub generic: PhantomData<T>,
 }
diff --git a/schemars/tests/examples.rs b/schemars/tests/examples.rs
index 2557e1c..bbe9af5 100644
--- a/schemars/tests/examples.rs
+++ b/schemars/tests/examples.rs
@@ -17,7 +17,7 @@ fn eight() -> i32 {
     8
 }
 
-fn null() -> () {}
+fn null() {}
 
 #[test]
 fn examples() -> TestResult {
diff --git a/schemars/tests/expected/smol_str.json b/schemars/tests/expected/smol_str.json
new file mode 100644
index 0000000..42f099a
--- /dev/null
+++ b/schemars/tests/expected/smol_str.json
@@ -0,0 +1,5 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "String",
+  "type": "string"
+}
\ No newline at end of file
diff --git a/schemars/tests/smol_str.rs b/schemars/tests/smol_str.rs
new file mode 100644
index 0000000..1e48196
--- /dev/null
+++ b/schemars/tests/smol_str.rs
@@ -0,0 +1,8 @@
+mod util;
+use smol_str::SmolStr;
+use util::*;
+
+#[test]
+fn smol_str() -> TestResult {
+    test_default_generated_schema::<SmolStr>("smol_str")
+}
diff --git a/schemars/tests/validate.rs b/schemars/tests/validate.rs
index 58ef080..e381734 100644
--- a/schemars/tests/validate.rs
+++ b/schemars/tests/validate.rs
@@ -4,7 +4,7 @@ use std::collections::HashMap;
 use util::*;
 
 // In real code, this would typically be a Regex, potentially created in a `lazy_static!`.
-static STARTS_WITH_HELLO: &'static str = r"^[Hh]ello\b";
+static STARTS_WITH_HELLO: &str = r"^[Hh]ello\b";
 
 const MIN: u32 = 1;
 const MAX: u32 = 1000;