Add no_std support via disabling the new default feature std (#319)

This commit is contained in:
Graham Esau 2024-08-17 19:46:11 +01:00 committed by GitHub
parent 3c9e49d161
commit 89a34e7a63
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
40 changed files with 343 additions and 164 deletions

View file

@ -1,5 +1,11 @@
# Changelog
## [1.0.0-alpha.5] - _in-dev_
### Added
- Schemars can now be used in `no_std` environments by disabling the new `std` feature flag (which is enabled by default). Schemars still requires an allocator to be available.
## [1.0.0-alpha.4] - 2024-08-17
### Fixed

23
Cargo.lock generated
View file

@ -175,9 +175,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.0.2"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
dependencies = [
"equivalent",
"hashbrown",
@ -195,6 +195,12 @@ version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "num-bigint"
version = "0.4.4"
@ -346,18 +352,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
[[package]]
name = "serde"
version = "1.0.189"
version = "1.0.208"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537"
checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.189"
version = "1.0.208"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5"
checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
dependencies = [
"proc-macro2",
"quote",
@ -377,12 +383,13 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.107"
version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed"
dependencies = [
"indexmap",
"itoa",
"memchr",
"ryu",
"serde",
]

View file

@ -14,8 +14,8 @@ rust-version = "1.60"
[dependencies]
schemars_derive = { version = "=1.0.0-alpha.4", optional = true, path = "../schemars_derive" }
serde = "1.0"
serde_json = "1.0.25"
serde = { version = "1.0", default-features = false, features = ["alloc"]}
serde_json = { version = "1.0.122", default-features = false, features = ["alloc"] }
dyn-clone = "1.0"
ref-cast = "1.0.22"
@ -40,18 +40,37 @@ trybuild = "1.0"
serde = { version = "1.0", features = ["derive"] }
[features]
default = ["derive"]
default = ["derive", "std"]
# Provide impls for common standard library types like `HashMap<K, V>`.
# Requires a dependency on the Rust standard library.
std = []
# Provide `derive(JsonSchema)` macro.
derive = ["schemars_derive"]
# Preserves order of properties inserted into a `Schema`.
# When deriving `JsonSchema`, this ensures that the `properties` entires match
# the order of the fields in the struct definition.
preserve_order = ["serde_json/preserve_order"]
# Implements `JsonSchema` on `serde_json::value::RawValue`
raw_value = ["serde_json/raw_value"]
ui_test = []
# For internal/CI use only
_ui_test = []
[[test]]
name = "std_time"
required-features = ["std"]
[[test]]
name = "ffi"
required-features = ["std"]
[[test]]
name = "ui"
required-features = ["ui_test"]
required-features = ["_ui_test"]
[[test]]
name = "chrono"
@ -103,4 +122,4 @@ required-features = ["rust_decimal1", "bigdecimal04"]
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--extend-css", "docs-rs-custom.css "]
rustdoc-args = ["--extend-css", "docs-rs-custom.css"]

View file

@ -1,3 +1,4 @@
use crate::_alloc_prelude::*;
use crate::{JsonSchema, Schema, SchemaGenerator};
use serde::Serialize;
use serde_json::{json, map::Entry, Map, Value};

View file

@ -8,14 +8,15 @@ There are two main types in this module:
*/
use crate::Schema;
use crate::_alloc_prelude::*;
use crate::{transform::*, JsonSchema};
use alloc::collections::{BTreeMap, BTreeSet};
use core::{any::Any, fmt::Debug};
use dyn_clone::DynClone;
use serde::Serialize;
use serde_json::{Map, Value};
use std::collections::{HashMap, HashSet};
use std::{any::Any, fmt::Debug};
use serde_json::{Map as JsonMap, Value};
type CowStr = std::borrow::Cow<'static, str>;
type CowStr = alloc::borrow::Cow<'static, str>;
/// Settings to customize how Schemas are generated.
///
@ -168,10 +169,10 @@ impl SchemaSettings {
#[derive(Debug, Default)]
pub struct SchemaGenerator {
settings: SchemaSettings,
definitions: Map<String, Value>,
pending_schema_ids: HashSet<CowStr>,
schema_id_to_name: HashMap<CowStr, CowStr>,
used_schema_names: HashSet<CowStr>,
definitions: JsonMap<String, Value>,
pending_schema_ids: BTreeSet<CowStr>,
schema_id_to_name: BTreeMap<CowStr, CowStr>,
used_schema_names: BTreeSet<CowStr>,
}
impl Clone for SchemaGenerator {
@ -179,9 +180,9 @@ impl Clone for SchemaGenerator {
Self {
settings: self.settings.clone(),
definitions: self.definitions.clone(),
pending_schema_ids: HashSet::new(),
schema_id_to_name: HashMap::new(),
used_schema_names: HashSet::new(),
pending_schema_ids: BTreeSet::new(),
schema_id_to_name: BTreeMap::new(),
used_schema_names: BTreeSet::new(),
}
}
}
@ -276,7 +277,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 definitions(&self) -> &Map<String, Value> {
pub fn definitions(&self) -> &JsonMap<String, Value> {
&self.definitions
}
@ -284,7 +285,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 definitions_mut(&mut self) -> &mut Map<String, Value> {
pub fn definitions_mut(&mut self) -> &mut JsonMap<String, Value> {
&mut self.definitions
}
@ -293,8 +294,8 @@ 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, Value> {
std::mem::take(&mut self.definitions)
pub fn take_definitions(&mut self) -> JsonMap<String, Value> {
core::mem::take(&mut self.definitions)
}
/// Returns an iterator over the [transforms](SchemaSettings::transforms) being used by this `SchemaGenerator`.
@ -338,7 +339,7 @@ impl SchemaGenerator {
.entry("title")
.or_insert_with(|| T::schema_name().into());
if let Some(meta_schema) = std::mem::take(&mut self.settings.meta_schema) {
if let Some(meta_schema) = core::mem::take(&mut self.settings.meta_schema) {
object.insert("$schema".into(), meta_schema.into());
}
@ -401,7 +402,7 @@ impl SchemaGenerator {
object.insert("examples".into(), vec![example].into());
}
if let Some(meta_schema) = std::mem::take(&mut self.settings.meta_schema) {
if let Some(meta_schema) = core::mem::take(&mut self.settings.meta_schema) {
object.insert("$schema".into(), meta_schema.into());
}
@ -440,8 +441,8 @@ impl SchemaGenerator {
fn add_definitions(
&mut self,
schema_object: &mut Map<String, Value>,
mut definitions: Map<String, Value>,
schema_object: &mut JsonMap<String, Value>,
mut definitions: JsonMap<String, Value>,
) {
if definitions.is_empty() {
return;
@ -472,10 +473,10 @@ impl SchemaGenerator {
}
fn json_pointer_mut<'a>(
mut object: &'a mut Map<String, Value>,
mut object: &'a mut JsonMap<String, Value>,
pointer: &str,
create_if_missing: bool,
) -> Option<&'a mut Map<String, Value>> {
) -> Option<&'a mut JsonMap<String, Value>> {
let pointer = pointer.strip_prefix('/')?;
if pointer.is_empty() {
return Some(object);
@ -491,7 +492,7 @@ fn json_pointer_mut<'a>(
use serde_json::map::Entry;
let next_value = match object.entry(segment) {
Entry::Occupied(o) => o.into_mut(),
Entry::Vacant(v) if create_if_missing => v.insert(Value::Object(Map::default())),
Entry::Vacant(v) if create_if_missing => v.insert(Value::Object(JsonMap::default())),
Entry::Vacant(_) => return None,
};
@ -580,7 +581,7 @@ where
}
impl Debug for Box<dyn GenTransform> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self._debug_type_name(f)
}
}

View file

@ -1,6 +1,7 @@
use crate::_alloc_prelude::*;
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use std::borrow::Cow;
use alloc::borrow::Cow;
// Does not require T: JsonSchema.
impl<T> JsonSchema for [T; 0] {

View file

@ -1,3 +1,4 @@
use crate::_alloc_prelude::*;
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use arrayvec07::{ArrayString, ArrayVec};
@ -12,7 +13,7 @@ where
{
always_inline!();
fn schema_name() -> std::borrow::Cow<'static, str> {
fn schema_name() -> alloc::borrow::Cow<'static, str> {
format!("Array_up_to_size_{}_of_{}", CAP, T::schema_name()).into()
}

View file

@ -1,4 +1,4 @@
use std::sync::atomic::*;
use core::sync::atomic::*;
#[cfg(target_has_atomic = "8")]
forward_impl!(AtomicBool => bool);

View file

@ -1,7 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use chrono04::prelude::*;
use std::borrow::Cow;
use alloc::borrow::Cow;
impl JsonSchema for Weekday {
always_inline!();

View file

@ -1,8 +1,9 @@
use crate::_alloc_prelude::*;
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use alloc::borrow::Cow;
use core::ops::{Bound, Range, RangeInclusive};
use serde_json::Value;
use std::borrow::Cow;
use std::ops::{Bound, Range, RangeInclusive};
impl<T: JsonSchema> JsonSchema for Option<T> {
always_inline!();
@ -32,8 +33,10 @@ impl<T: JsonSchema> JsonSchema for Option<T> {
}
Some(Value::String(string)) => {
if string != "null" {
*instance_type.unwrap() =
Value::Array(vec![std::mem::take(string).into(), "null".into()])
*instance_type.unwrap() = Value::Array(vec![
core::mem::take(string).into(),
"null".into(),
])
}
obj.into()
}
@ -158,6 +161,6 @@ impl<T: JsonSchema> JsonSchema for Range<T> {
forward_impl!((<T: JsonSchema> JsonSchema for RangeInclusive<T>) => Range<T>);
forward_impl!((<T: ?Sized> JsonSchema for std::marker::PhantomData<T>) => ());
forward_impl!((<T: ?Sized> JsonSchema for core::marker::PhantomData<T>) => ());
forward_impl!((<'a> JsonSchema for std::fmt::Arguments<'a>) => String);
forward_impl!((<'a> JsonSchema for core::fmt::Arguments<'a>) => String);

View file

@ -1,6 +1,6 @@
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use std::borrow::Cow;
use alloc::borrow::Cow;
macro_rules! decimal_impl {
($type:ty) => {

View file

@ -1,7 +1,8 @@
use crate::_alloc_prelude::*;
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use alloc::borrow::Cow;
use either1::Either;
use std::borrow::Cow;
impl<L: JsonSchema, R: JsonSchema> JsonSchema for Either<L, R> {
always_inline!();

View file

@ -1,6 +1,7 @@
use crate::_alloc_prelude::*;
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use std::borrow::Cow;
use alloc::borrow::Cow;
use std::ffi::{CStr, CString, OsStr, OsString};
impl JsonSchema for OsString {

View file

@ -1,6 +1,6 @@
use crate::JsonSchema;
use alloc::collections::{BTreeMap, BTreeSet};
use indexmap2::{IndexMap, IndexSet};
use std::collections::{HashMap, HashSet};
forward_impl!((<K, V: JsonSchema, H> JsonSchema for IndexMap<K, V, H>) => HashMap<K, V, H>);
forward_impl!((<T: JsonSchema, H> JsonSchema for IndexSet<T, H>) => HashSet<T, H>);
forward_impl!((<K, V: JsonSchema, H> JsonSchema for IndexMap<K, V, H>) => BTreeMap<K, V>);
forward_impl!((<T: JsonSchema, H> JsonSchema for IndexSet<T, H>) => BTreeSet<T>);

View file

@ -1,6 +1,7 @@
use crate::_alloc_prelude::*;
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use std::borrow::Cow;
use alloc::borrow::Cow;
macro_rules! map_impl {
($($desc:tt)+) => {
@ -28,5 +29,7 @@ macro_rules! map_impl {
};
}
map_impl!(<K, V> JsonSchema for std::collections::BTreeMap<K, V>);
map_impl!(<K, V> JsonSchema for alloc::collections::BTreeMap<K, V>);
#[cfg(feature = "std")]
map_impl!(<K, V, H> JsonSchema for std::collections::HashMap<K, V, H>);

View file

@ -13,11 +13,11 @@ macro_rules! forward_impl {
<$target>::always_inline_schema()
}
fn schema_name() -> std::borrow::Cow<'static, str> {
fn schema_name() -> alloc::borrow::Cow<'static, str> {
<$target>::schema_name()
}
fn schema_id() -> std::borrow::Cow<'static, str> {
fn schema_id() -> alloc::borrow::Cow<'static, str> {
<$target>::schema_id()
}
@ -41,27 +41,29 @@ macro_rules! forward_impl {
mod array;
mod core;
mod ffi;
mod maps;
mod nonzero_signed;
mod nonzero_unsigned;
mod primitives;
mod sequences;
mod serdejson;
mod time;
mod std_time;
mod tuple;
mod wrapper;
#[cfg(target_has_atomic)]
mod atomic;
#[cfg(feature = "std")]
mod ffi;
#[cfg(feature = "arrayvec07")]
mod arrayvec07;
#[cfg(feature = "bytes1")]
mod bytes1 {
forward_impl!(bytes1::Bytes => Vec<u8>);
forward_impl!(bytes1::BytesMut => Vec<u8>);
forward_impl!(bytes1::Bytes => alloc::vec::Vec<u8>);
forward_impl!(bytes1::BytesMut => alloc::vec::Vec<u8>);
}
#[cfg(feature = "chrono04")]
@ -74,7 +76,7 @@ mod decimal;
mod either1;
#[cfg(feature = "enumset1")]
forward_impl!((<T: enumset1::EnumSetType + crate::JsonSchema> crate::JsonSchema for enumset1::EnumSet<T>) => std::collections::BTreeSet<T>);
forward_impl!((<T: enumset1::EnumSetType + crate::JsonSchema> crate::JsonSchema for enumset1::EnumSet<T>) => alloc::collections::BTreeSet<T>);
#[cfg(feature = "indexmap2")]
mod indexmap2;
@ -83,10 +85,10 @@ mod indexmap2;
mod semver1;
#[cfg(feature = "smallvec1")]
forward_impl!((<A: smallvec1::Array> crate::JsonSchema for smallvec1::SmallVec<A> where A::Item: crate::JsonSchema) => Vec<A::Item>);
forward_impl!((<A: smallvec1::Array> crate::JsonSchema for smallvec1::SmallVec<A> where A::Item: crate::JsonSchema) => alloc::vec::Vec<A::Item>);
#[cfg(feature = "smol_str02")]
forward_impl!(smol_str02::SmolStr => String);
forward_impl!(smol_str02::SmolStr => alloc::string::String);
#[cfg(feature = "url2")]
mod url2;

View file

@ -1,7 +1,8 @@
use crate::_alloc_prelude::*;
use crate::gen::SchemaGenerator;
use crate::{JsonSchema, Schema};
use std::borrow::Cow;
use std::num::*;
use alloc::borrow::Cow;
use core::num::*;
macro_rules! nonzero_unsigned_impl {
($type:ty => $primitive:ty) => {

View file

@ -1,8 +1,9 @@
use crate::_alloc_prelude::*;
use crate::gen::SchemaGenerator;
use crate::JsonSchema;
use crate::Schema;
use std::borrow::Cow;
use std::num::*;
use alloc::borrow::Cow;
use core::num::*;
macro_rules! nonzero_unsigned_impl {
($type:ty => $primitive:ty) => {

View file

@ -1,8 +1,7 @@
use crate::_alloc_prelude::*;
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use std::borrow::Cow;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::path::{Path, PathBuf};
use alloc::borrow::Cow;
macro_rules! simple_impl {
($type:ty => $instance_type:literal) => {
@ -51,16 +50,23 @@ simple_impl!(i128 => "integer", "int128");
simple_impl!(isize => "integer", "int");
simple_impl!(() => "null");
simple_impl!(Path => "string");
simple_impl!(PathBuf => "string");
#[cfg(feature = "std")]
mod std_types {
use super::*;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::path::{Path, PathBuf};
simple_impl!(Ipv4Addr => "string", "ipv4");
simple_impl!(Ipv6Addr => "string", "ipv6");
simple_impl!(IpAddr => "string", "ip");
simple_impl!(Path => "string");
simple_impl!(PathBuf => "string");
simple_impl!(SocketAddr => "string");
simple_impl!(SocketAddrV4 => "string");
simple_impl!(SocketAddrV6 => "string");
simple_impl!(Ipv4Addr => "string", "ipv4");
simple_impl!(Ipv6Addr => "string", "ipv6");
simple_impl!(IpAddr => "string", "ip");
simple_impl!(SocketAddr => "string");
simple_impl!(SocketAddrV4 => "string");
simple_impl!(SocketAddrV6 => "string");
}
macro_rules! unsigned_impl {
($type:ty => $instance_type:literal, $format:literal) => {

View file

@ -1,7 +1,7 @@
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use semver1::Version;
use std::borrow::Cow;
use alloc::borrow::Cow;
impl JsonSchema for Version {
always_inline!();

View file

@ -1,6 +1,7 @@
use crate::_alloc_prelude::*;
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use std::borrow::Cow;
use alloc::borrow::Cow;
macro_rules! seq_impl {
($($desc:tt)+) => {
@ -55,11 +56,13 @@ macro_rules! set_impl {
};
}
seq_impl!(<T> JsonSchema for std::collections::BinaryHeap<T>);
seq_impl!(<T> JsonSchema for std::collections::LinkedList<T>);
seq_impl!(<T> JsonSchema for alloc::collections::BinaryHeap<T>);
seq_impl!(<T> JsonSchema for alloc::collections::LinkedList<T>);
seq_impl!(<T> JsonSchema for [T]);
seq_impl!(<T> JsonSchema for Vec<T>);
seq_impl!(<T> JsonSchema for std::collections::VecDeque<T>);
seq_impl!(<T> JsonSchema for alloc::vec::Vec<T>);
seq_impl!(<T> JsonSchema for alloc::collections::VecDeque<T>);
set_impl!(<T> JsonSchema for std::collections::BTreeSet<T>);
set_impl!(<T> JsonSchema for alloc::collections::BTreeSet<T>);
#[cfg(feature = "std")]
set_impl!(<T, H> JsonSchema for std::collections::HashSet<T, H>);

View file

@ -1,8 +1,9 @@
use crate::_alloc_prelude::*;
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use alloc::borrow::Cow;
use alloc::collections::BTreeMap;
use serde_json::{Map, Number, Value};
use std::borrow::Cow;
use std::collections::BTreeMap;
impl JsonSchema for Value {
always_inline!();

View file

@ -1,9 +1,8 @@
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use std::borrow::Cow;
use std::time::{Duration, SystemTime};
use alloc::borrow::Cow;
impl JsonSchema for Duration {
impl JsonSchema for core::time::Duration {
fn schema_name() -> Cow<'static, str> {
"Duration".into()
}
@ -24,7 +23,8 @@ impl JsonSchema for Duration {
}
}
impl JsonSchema for SystemTime {
#[cfg(feature = "std")]
impl JsonSchema for std::time::SystemTime {
fn schema_name() -> Cow<'static, str> {
"SystemTime".into()
}

View file

@ -1,6 +1,7 @@
use crate::_alloc_prelude::*;
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use std::borrow::Cow;
use alloc::borrow::Cow;
macro_rules! tuple_impls {
($($len:expr => ($($name:ident)+))+) => {

View file

@ -1,6 +1,6 @@
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use std::borrow::Cow;
use alloc::borrow::Cow;
use url2::Url;
impl JsonSchema for Url {

View file

@ -1,6 +1,6 @@
use crate::gen::SchemaGenerator;
use crate::{json_schema, JsonSchema, Schema};
use std::borrow::Cow;
use alloc::borrow::Cow;
use uuid1::Uuid;
impl JsonSchema for Uuid {

View file

@ -1,4 +1,5 @@
use crate::JsonSchema;
use crate::_alloc_prelude::*;
macro_rules! wrapper_impl {
($($desc:tt)+) => {
@ -9,14 +10,16 @@ macro_rules! wrapper_impl {
wrapper_impl!(<'a, T: ?Sized> JsonSchema for &'a T);
wrapper_impl!(<'a, T: ?Sized> JsonSchema for &'a mut T);
wrapper_impl!(<T: ?Sized> JsonSchema for Box<T>);
wrapper_impl!(<T: ?Sized> JsonSchema for std::rc::Rc<T>);
wrapper_impl!(<T: ?Sized> JsonSchema for std::rc::Weak<T>);
wrapper_impl!(<T: ?Sized> JsonSchema for std::sync::Arc<T>);
wrapper_impl!(<T: ?Sized> JsonSchema for std::sync::Weak<T>);
wrapper_impl!(<T: ?Sized> JsonSchema for alloc::rc::Rc<T>);
wrapper_impl!(<T: ?Sized> JsonSchema for alloc::rc::Weak<T>);
wrapper_impl!(<T: ?Sized> JsonSchema for alloc::sync::Arc<T>);
wrapper_impl!(<T: ?Sized> JsonSchema for alloc::sync::Weak<T>);
#[cfg(feature = "std")]
wrapper_impl!(<T: ?Sized> JsonSchema for std::sync::Mutex<T>);
#[cfg(feature = "std")]
wrapper_impl!(<T: ?Sized> JsonSchema for std::sync::RwLock<T>);
wrapper_impl!(<T: ?Sized> JsonSchema for std::cell::Cell<T>);
wrapper_impl!(<T: ?Sized> JsonSchema for std::cell::RefCell<T>);
wrapper_impl!(<'a, T: ?Sized + ToOwned> JsonSchema for std::borrow::Cow<'a, T>);
wrapper_impl!(<T> JsonSchema for std::num::Wrapping<T>);
wrapper_impl!(<T> JsonSchema for std::cmp::Reverse<T>);
wrapper_impl!(<T: ?Sized> JsonSchema for core::cell::Cell<T>);
wrapper_impl!(<T: ?Sized> JsonSchema for core::cell::RefCell<T>);
wrapper_impl!(<'a, T: ?Sized + ToOwned> JsonSchema for alloc::borrow::Cow<'a, T>);
wrapper_impl!(<T> JsonSchema for core::num::Wrapping<T>);
wrapper_impl!(<T> JsonSchema for core::cmp::Reverse<T>);

View file

@ -1,5 +1,10 @@
#![deny(unsafe_code)]
#![doc = include_str!("../README.md")]
#![no_std]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
mod json_schema_impls;
mod schema;
@ -16,18 +21,29 @@ pub mod transform;
#[cfg(feature = "schemars_derive")]
extern crate schemars_derive;
use std::borrow::Cow;
use alloc::borrow::Cow;
#[cfg(feature = "schemars_derive")]
pub use schemars_derive::*;
// Export serde_json so schemars_derive can use it
// Export crates so schemars_derive can use them
#[doc(hidden)]
pub use serde_json as _serde_json;
pub extern crate alloc as _alloc;
#[doc(hidden)]
pub extern crate serde_json as _serde_json;
pub use gen::SchemaGenerator;
pub use schema::Schema;
mod _alloc_prelude {
pub use alloc::borrow::ToOwned;
pub use alloc::boxed::Box;
pub use alloc::format;
pub use alloc::string::{String, ToString};
pub use alloc::vec;
pub use alloc::vec::Vec;
}
/// A type which can be described as a JSON Schema document.
///
/// This is implemented for many Rust primitive and standard library types.

View file

@ -2,6 +2,7 @@
JSON Schema types.
*/
use crate::_alloc_prelude::*;
use ref_cast::{ref_cast_custom, RefCastCustom};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
@ -186,7 +187,7 @@ impl From<Schema> for Value {
}
}
impl std::convert::TryFrom<Value> for Schema {
impl core::convert::TryFrom<Value> for Schema {
type Error = serde_json::Error;
fn try_from(value: Value) -> serde_json::Result<Schema> {
@ -195,7 +196,7 @@ impl std::convert::TryFrom<Value> for Schema {
}
}
impl<'a> std::convert::TryFrom<&'a Value> for &'a Schema {
impl<'a> core::convert::TryFrom<&'a Value> for &'a Schema {
type Error = serde_json::Error;
fn try_from(value: &Value) -> serde_json::Result<&Schema> {
@ -204,7 +205,7 @@ impl<'a> std::convert::TryFrom<&'a Value> for &'a Schema {
}
}
impl<'a> std::convert::TryFrom<&'a mut Value> for &'a mut Schema {
impl<'a> core::convert::TryFrom<&'a mut Value> for &'a mut Schema {
type Error = serde_json::Error;
fn try_from(value: &mut Value) -> serde_json::Result<&mut Schema> {
@ -232,11 +233,11 @@ impl From<bool> for Schema {
}
impl crate::JsonSchema for Schema {
fn schema_name() -> std::borrow::Cow<'static, str> {
fn schema_name() -> alloc::borrow::Cow<'static, str> {
"Schema".into()
}
fn schema_id() -> std::borrow::Cow<'static, str> {
fn schema_id() -> alloc::borrow::Cow<'static, str> {
"schemars::Schema".into()
}

View file

@ -1,6 +1,7 @@
use crate::_alloc_prelude::*;
use crate::{json_schema, JsonSchema, Schema, SchemaGenerator};
use core::fmt::Display;
use serde_json::{Error, Map, Value};
use std::fmt::Display;
pub(crate) struct Serializer<'a> {
pub(crate) gen: &'a mut SchemaGenerator,
@ -142,8 +143,10 @@ impl<'a> serde::Serializer for Serializer<'a> {
}
Some(Value::String(string)) => {
if string != "null" {
*value.unwrap() =
Value::Array(vec![std::mem::take(string).into(), "null".into()])
*value.unwrap() = Value::Array(vec![
core::mem::take(string).into(),
"null".into(),
])
}
obj.into()
}

View file

@ -112,9 +112,9 @@ assert_eq!(
```
*/
use serde_json::{json, Value};
use crate::Schema;
use crate::_alloc_prelude::*;
use serde_json::{json, Value};
/// Trait used to modify a constructed schema and optionally its subschemas.
///
@ -128,8 +128,8 @@ pub trait Transform {
// Not public API
// Hack to enable implementing Debug on Box<dyn GenTransform> even though closures don't implement Debug
#[doc(hidden)]
fn _debug_type_name(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(std::any::type_name::<Self>())
fn _debug_type_name(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(core::any::type_name::<Self>())
}
}

View file

@ -0,0 +1,70 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "MyStruct",
"type": "object",
"properties": {
"my_int": {
"type": "integer",
"format": "int32"
},
"my_bool": {
"type": "boolean"
},
"my_nullable_enum": {
"anyOf": [
{
"$ref": "#/$defs/MyEnum"
},
{
"type": "null"
}
]
}
},
"required": [
"my_int",
"my_bool"
],
"$defs": {
"MyEnum": {
"oneOf": [
{
"type": "object",
"properties": {
"StringNewType": {
"type": "string"
}
},
"required": [
"StringNewType"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"StructVariant": {
"type": "object",
"properties": {
"floats": {
"type": "array",
"items": {
"type": "number",
"format": "float"
}
}
},
"required": [
"floats"
]
}
},
"required": [
"StructVariant"
],
"additionalProperties": false
}
]
}
}
}

25
schemars/tests/no_std.rs Normal file
View file

@ -0,0 +1,25 @@
#![no_std]
mod util;
use schemars::JsonSchema;
use util::*;
extern crate alloc as test_alloc;
#[derive(JsonSchema)]
pub struct MyStruct {
pub my_int: i32,
pub my_bool: bool,
pub my_nullable_enum: Option<MyEnum>,
}
#[derive(JsonSchema)]
pub enum MyEnum {
StringNewType(test_alloc::string::String),
StructVariant { floats: test_alloc::vec::Vec<f32> },
}
#[test]
fn no_std() -> TestResult {
test_default_generated_schema::<MyStruct>("no_std")
}

View file

@ -2,7 +2,7 @@ mod util;
use schemars::JsonSchema;
use serde::Serialize;
use std::collections::{HashMap, HashSet};
use std::collections::{BTreeMap, BTreeSet};
use util::*;
#[allow(dead_code)]
@ -39,7 +39,7 @@ struct MyStruct<'a, T: Serialize> {
s: Str<'a>,
// #[schemars(with = "HashMap::<_, HashSet<_>>")]
// map: BTreeMap<String, BTreeSet<String>>,
#[schemars(with = "HashMap::<String, HashSet<String>>")]
#[schemars(with = "BTreeMap::<String, BTreeSet<String>>")]
fake_map: (),
}

View file

@ -1,7 +1,11 @@
use pretty_assertions::assert_eq;
use schemars::{gen::SchemaSettings, schema_for, JsonSchema, Schema};
use std::error::Error;
use std::format;
use std::fs;
use std::prelude::rust_2021::*;
extern crate std;
pub type TestResult = Result<(), Box<dyn Error>>;

View file

@ -1,6 +1,6 @@
mod util;
use schemars::JsonSchema;
use std::collections::HashMap;
use std::collections::BTreeMap;
use util::*;
// In real code, this would typically be a Regex, potentially created in a `lazy_static!`.
@ -39,7 +39,7 @@ pub struct Struct {
#[validate(length(equal = 2))]
pair: Vec<i32>,
#[validate(contains = "map_key")]
map_contains: HashMap<String, ()>,
map_contains: BTreeMap<String, ()>,
#[validate(required)]
required_option: Option<bool>,
#[validate(required)]
@ -91,7 +91,7 @@ pub struct Struct2 {
#[schemars(length(equal = 2))]
pair: Vec<i32>,
#[schemars(contains = "map_key")]
map_contains: HashMap<String, ()>,
map_contains: BTreeMap<String, ()>,
#[schemars(required)]
required_option: Option<bool>,
#[schemars(required)]

View file

@ -155,7 +155,7 @@ impl ValidationAttrs {
if !ignore_errors {
errors.error_spanned_by(
meta,
"unknown item in schemars length attribute".to_string(),
"unknown item in schemars length attribute",
);
}
}
@ -184,7 +184,7 @@ impl ValidationAttrs {
if !ignore_errors {
errors.error_spanned_by(
meta,
"unknown item in schemars range attribute".to_string(),
"unknown item in schemars range attribute",
);
}
}
@ -252,8 +252,7 @@ impl ValidationAttrs {
if !ignore_errors {
errors.error_spanned_by(
meta,
"unknown item in schemars regex attribute"
.to_string(),
"unknown item in schemars regex attribute",
);
}
}
@ -294,8 +293,7 @@ impl ValidationAttrs {
if !ignore_errors {
errors.error_spanned_by(
meta,
"unknown item in schemars contains attribute"
.to_string(),
"unknown item in schemars contains attribute",
);
}
}
@ -390,7 +388,7 @@ impl ValidationAttrs {
if let Some(format) = &self.format {
let f = format.schema_str();
result.push(quote! {
schema.ensure_object().insert("format".to_owned(), #f.into());
schema.ensure_object().insert("format".into(), #f.into());
})
};

View file

@ -60,11 +60,11 @@ fn derive_json_schema(mut input: syn::DeriveInput, repr: bool) -> syn::Result<To
<#ty as schemars::JsonSchema>::always_inline_schema()
}
fn schema_name() -> std::borrow::Cow<'static, str> {
fn schema_name() -> schemars::_alloc::borrow::Cow<'static, str> {
<#ty as schemars::JsonSchema>::schema_name()
}
fn schema_id() -> std::borrow::Cow<'static, str> {
fn schema_id() -> schemars::_alloc::borrow::Cow<'static, str> {
<#ty as schemars::JsonSchema>::schema_id()
}
@ -104,11 +104,11 @@ fn derive_json_schema(mut input: syn::DeriveInput, repr: bool) -> syn::Result<To
{
(
quote! {
std::borrow::Cow::Borrowed(#schema_base_name)
schemars::_alloc::borrow::Cow::Borrowed(#schema_base_name)
},
quote! {
std::borrow::Cow::Borrowed(std::concat!(
std::module_path!(),
schemars::_alloc::borrow::Cow::Borrowed(::core::concat!(
::core::module_path!(),
"::",
#schema_base_name
))
@ -121,15 +121,15 @@ fn derive_json_schema(mut input: syn::DeriveInput, repr: bool) -> syn::Result<To
}
(
quote! {
std::borrow::Cow::Owned(
format!(#schema_name_fmt #(,#type_params=#type_params::schema_name())* #(,#const_params=#const_params)*)
schemars::_alloc::borrow::Cow::Owned(
schemars::_alloc::format!(#schema_name_fmt #(,#type_params=#type_params::schema_name())* #(,#const_params=#const_params)*)
)
},
quote! {
std::borrow::Cow::Owned(
format!(
std::concat!(
std::module_path!(),
schemars::_alloc::borrow::Cow::Owned(
schemars::_alloc::format!(
::core::concat!(
::core::module_path!(),
"::",
#schema_name_fmt
)
@ -145,15 +145,15 @@ fn derive_json_schema(mut input: syn::DeriveInput, repr: bool) -> syn::Result<To
schema_name_fmt.push_str(&"_and_{}".repeat(params.len() - 1));
(
quote! {
std::borrow::Cow::Owned(
format!(#schema_name_fmt #(,#type_params::schema_name())* #(,#const_params)*)
schemars::_alloc::borrow::Cow::Owned(
schemars::_alloc::format!(#schema_name_fmt #(,#type_params::schema_name())* #(,#const_params)*)
)
},
quote! {
std::borrow::Cow::Owned(
format!(
std::concat!(
std::module_path!(),
schemars::_alloc::borrow::Cow::Owned(
schemars::_alloc::format!(
::core::concat!(
::core::module_path!(),
"::",
#schema_name_fmt
)
@ -178,11 +178,11 @@ fn derive_json_schema(mut input: syn::DeriveInput, repr: bool) -> syn::Result<To
#[automatically_derived]
#[allow(unused_braces)]
impl #impl_generics schemars::JsonSchema for #type_name #ty_generics #where_clause {
fn schema_name() -> std::borrow::Cow<'static, str> {
fn schema_name() -> schemars::_alloc::borrow::Cow<'static, str> {
#schema_name
}
fn schema_id() -> std::borrow::Cow<'static, str> {
fn schema_id() -> schemars::_alloc::borrow::Cow<'static, str> {
#schema_id
}

View file

@ -51,11 +51,11 @@ pub fn expr_for_repr(cont: &Container) -> Result<TokenStream, syn::Error> {
let mut schema_expr = quote!({
let mut map = schemars::_serde_json::Map::new();
map.insert("type".to_owned(), "integer".into());
map.insert("type".into(), "integer".into());
map.insert(
"enum".to_owned(),
"enum".into(),
schemars::_serde_json::Value::Array({
let mut enum_values = Vec::new();
let mut enum_values = schemars::_alloc::vec::Vec::new();
#(enum_values.push((#enum_ident::#variant_idents as #repr_type).into());)*
enum_values
}),
@ -114,14 +114,14 @@ fn type_for_schema(with_attr: &WithAttr) -> (syn::Type, Option<TokenStream>) {
true
}
fn schema_name() -> std::borrow::Cow<'static, str> {
std::borrow::Cow::Borrowed(#fn_name)
fn schema_name() -> schemars::_alloc::borrow::Cow<'static, str> {
schemars::_alloc::borrow::Cow::Borrowed(#fn_name)
}
fn schema_id() -> std::borrow::Cow<'static, str> {
std::borrow::Cow::Borrowed(std::concat!(
fn schema_id() -> schemars::_alloc::borrow::Cow<'static, str> {
schemars::_alloc::borrow::Cow::Borrowed(::core::concat!(
"_SchemarsSchemaWithFunction/",
std::module_path!(),
::core::module_path!(),
"/",
#fn_name
))
@ -171,11 +171,11 @@ fn expr_for_external_tagged_enum<'a>(
let unit_names = unit_variants.iter().map(|v| v.name());
let unit_schema = quote!({
let mut map = schemars::_serde_json::Map::new();
map.insert("type".to_owned(), "string".into());
map.insert("type".into(), "string".into());
map.insert(
"enum".to_owned(),
"enum".into(),
schemars::_serde_json::Value::Array({
let mut enum_values = Vec::new();
let mut enum_values = schemars::_alloc::vec::Vec::new();
#(enum_values.push((#unit_names).into());)*
enum_values
}),
@ -347,9 +347,9 @@ fn variant_subschemas(unique: bool, schemas: Vec<TokenStream>) -> TokenStream {
quote!({
let mut map = schemars::_serde_json::Map::new();
map.insert(
#keyword.to_owned(),
#keyword.into(),
schemars::_serde_json::Value::Array({
let mut enum_values = Vec::new();
let mut enum_values = schemars::_alloc::vec::Vec::new();
#(enum_values.push(#schemas.to_value());)*
enum_values
}),
@ -556,7 +556,7 @@ fn field_default_expr(field: &Field, container_has_default: bool) -> Option<Toke
impl serde::Serialize for _SchemarsDefaultSerialize<#ty>
{
fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
fn serialize<S>(&self, serializer: S) -> ::core::result::Result<S::Ok, S::Error>
where
S: serde::Serializer
{