From cc896739d3d2c969f88ad05e0569ef80aacbcb2e Mon Sep 17 00:00:00 2001 From: Graham Esau Date: Mon, 28 Oct 2019 22:46:51 +0000 Subject: [PATCH] Implement JsonSchema for atomics --- .travis.yml | 6 +- schemars/Cargo.toml | 1 + schemars/build.rs | 67 +++++++++++++++++++++ schemars/src/json_schema_impls/atomic.rs | 47 +++++++++++++++ schemars/src/json_schema_impls/core.rs | 34 +---------- schemars/src/json_schema_impls/ffi.rs | 35 +---------- schemars/src/json_schema_impls/mod.rs | 27 +++++++++ schemars/src/json_schema_impls/serdejson.rs | 12 +--- schemars/src/json_schema_impls/wrapper.rs | 51 +++++----------- 9 files changed, 168 insertions(+), 112 deletions(-) create mode 100644 schemars/build.rs create mode 100644 schemars/src/json_schema_impls/atomic.rs diff --git a/.travis.yml b/.travis.yml index 907673d..c5b9ed4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,6 @@ jobs: fast_finish: true script: - cd "${TRAVIS_BUILD_DIR}/schemars" - - cargo check --verbose --all --no-default-features - - cargo build --verbose --all --all-features - - cargo test --verbose --all --all-features --no-fail-fast + - cargo check --verbose --no-default-features + - cargo build --verbose --all-features + - cargo test --verbose --all-features --no-fail-fast diff --git a/schemars/Cargo.toml b/schemars/Cargo.toml index 1bfbda1..a594fc3 100644 --- a/schemars/Cargo.toml +++ b/schemars/Cargo.toml @@ -9,6 +9,7 @@ license = "MIT" readme = "README.md" keywords = ["rust", "json-schema", "serde"] categories = ["encoding"] +build = "build.rs" [dependencies] schemars_derive = { version = "0.4.0", path = "../schemars_derive" } diff --git a/schemars/build.rs b/schemars/build.rs new file mode 100644 index 0000000..e432deb --- /dev/null +++ b/schemars/build.rs @@ -0,0 +1,67 @@ +use std::env; +use std::process::Command; +use std::str::{self, FromStr}; + +// Based on https://github.com/serde-rs/serde/blob/master/serde/build.rs + +fn main() { + let minor = match rustc_minor_version() { + Some(minor) => minor, + None => return, + }; + + let target = env::var("TARGET").unwrap(); + let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten"; + + // Atomic types, and non-zero signed integers stabilized in Rust 1.34: + // https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#library-stabilizations + if minor >= 34 { + println!("cargo:rustc-cfg=num_nonzero_signed"); + + // Whitelist of archs that support std::sync::atomic module. Ideally we + // would use #[cfg(target_has_atomic = "...")] but it is not stable yet. + // Instead this is based on rustc's src/librustc_target/spec/*.rs. + let has_atomic64 = target.starts_with("x86_64") + || target.starts_with("i686") + || target.starts_with("aarch64") + || target.starts_with("powerpc64") + || target.starts_with("sparc64") + || target.starts_with("mips64el"); + let has_atomic32 = has_atomic64 || emscripten; + if has_atomic64 { + println!("cargo:rustc-cfg=std_atomic64"); + } + if has_atomic32 { + println!("cargo:rustc-cfg=std_atomic"); + } + } +} + +fn rustc_minor_version() -> Option { + let rustc = match env::var_os("RUSTC") { + Some(rustc) => rustc, + None => return None, + }; + + let output = match Command::new(rustc).arg("--version").output() { + Ok(output) => output, + Err(_) => return None, + }; + + let version = match str::from_utf8(&output.stdout) { + Ok(version) => version, + Err(_) => return None, + }; + + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + + let next = match pieces.next() { + Some(next) => next, + None => return None, + }; + + u32::from_str(next).ok() +} diff --git a/schemars/src/json_schema_impls/atomic.rs b/schemars/src/json_schema_impls/atomic.rs new file mode 100644 index 0000000..5d8f6d9 --- /dev/null +++ b/schemars/src/json_schema_impls/atomic.rs @@ -0,0 +1,47 @@ +use crate::gen::SchemaGenerator; +use crate::schema::*; +use crate::JsonSchema; +use std::sync::atomic::*; + +forward_impl!(AtomicBool => bool); + +forward_impl!(AtomicI8 => i8); +forward_impl!(AtomicI16 => i16); +forward_impl!(AtomicI32 => i32); +#[cfg(std_atomic64)] +forward_impl!(AtomicI64 => i64); +forward_impl!(AtomicIsize => isize); + +forward_impl!(AtomicU8 => u8); +forward_impl!(AtomicU16 => u16); +forward_impl!(AtomicU32 => u32); +#[cfg(std_atomic64)] +forward_impl!(AtomicU64 => u64); +forward_impl!(AtomicUsize => usize); + +#[cfg(test)] +mod tests { + use super::*; + use crate::tests::schema_object_for; + use pretty_assertions::assert_eq; + + #[test] + fn schema_for_atomics() { + let atomic_schema = schema_object_for::<( + AtomicBool, + AtomicI8, + AtomicI16, + AtomicI32, + AtomicI64, + AtomicIsize, + AtomicU8, + AtomicU16, + AtomicU32, + AtomicU64, + AtomicUsize, + )>(); + let basic_schema = + schema_object_for::<(bool, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize)>(); + assert_eq!(atomic_schema, basic_schema); + } +} diff --git a/schemars/src/json_schema_impls/core.rs b/schemars/src/json_schema_impls/core.rs index 9ae9313..28d08b6 100644 --- a/schemars/src/json_schema_impls/core.rs +++ b/schemars/src/json_schema_impls/core.rs @@ -119,39 +119,11 @@ impl JsonSchema for Range { } } -impl JsonSchema for RangeInclusive { - fn schema_name() -> String { - >::schema_name() - } +forward_impl!(( JsonSchema for RangeInclusive) => Range); - fn json_schema(gen: &mut SchemaGenerator) -> Schema { - >::json_schema(gen) - } -} +forward_impl!(( JsonSchema for std::marker::PhantomData) => ()); -impl JsonSchema for std::marker::PhantomData { - no_ref_schema!(); - - fn schema_name() -> String { - <()>::schema_name() - } - - fn json_schema(gen: &mut SchemaGenerator) -> Schema { - <()>::json_schema(gen) - } -} - -impl<'a> JsonSchema for std::fmt::Arguments<'a> { - no_ref_schema!(); - - fn schema_name() -> String { - ::schema_name() - } - - fn json_schema(gen: &mut SchemaGenerator) -> Schema { - ::json_schema(gen) - } -} +forward_impl!((<'a> JsonSchema for std::fmt::Arguments<'a>) => String); #[cfg(test)] mod tests { diff --git a/schemars/src/json_schema_impls/ffi.rs b/schemars/src/json_schema_impls/ffi.rs index 8da586a..b5b6118 100644 --- a/schemars/src/json_schema_impls/ffi.rs +++ b/schemars/src/json_schema_impls/ffi.rs @@ -31,36 +31,7 @@ impl JsonSchema for OsString { } } -impl JsonSchema for OsStr { - fn schema_name() -> String { - ::schema_name() - } +forward_impl!(OsStr => OsString); - fn json_schema(gen: &mut SchemaGenerator) -> Schema { - ::json_schema(gen) - } -} - -impl JsonSchema for CString { - no_ref_schema!(); - - fn schema_name() -> String { - >::schema_name() - } - - fn json_schema(gen: &mut SchemaGenerator) -> Schema { - >::json_schema(gen) - } -} - -impl JsonSchema for CStr { - no_ref_schema!(); - - fn schema_name() -> String { - >::schema_name() - } - - fn json_schema(gen: &mut SchemaGenerator) -> Schema { - >::json_schema(gen) - } -} +forward_impl!(CString => Vec); +forward_impl!(CStr => Vec); diff --git a/schemars/src/json_schema_impls/mod.rs b/schemars/src/json_schema_impls/mod.rs index 432cbb8..58b27c2 100644 --- a/schemars/src/json_schema_impls/mod.rs +++ b/schemars/src/json_schema_impls/mod.rs @@ -6,6 +6,31 @@ macro_rules! no_ref_schema { }; } +macro_rules! forward_impl { + (($($impl:tt)+) => $target:ty) => { + impl $($impl)+ { + fn is_referenceable() -> bool { + <$target>::is_referenceable() + } + + fn schema_name() -> String { + <$target>::schema_name() + } + + fn json_schema(gen: &mut SchemaGenerator) -> Schema { + <$target>::json_schema(gen) + } + + fn json_schema_optional(gen: &mut SchemaGenerator) -> Schema { + <$target>::json_schema_optional(gen) + } + } + }; + ($ty:ty => $target:ty) => { + forward_impl!((JsonSchema for $ty) => $target); + }; +} + mod array; #[cfg(feature = "chrono")] mod chrono; @@ -18,3 +43,5 @@ mod serdejson; mod time; mod tuple; mod wrapper; +#[cfg(std_atomic)] +mod atomic; \ No newline at end of file diff --git a/schemars/src/json_schema_impls/serdejson.rs b/schemars/src/json_schema_impls/serdejson.rs index f911b8e..e07ee83 100644 --- a/schemars/src/json_schema_impls/serdejson.rs +++ b/schemars/src/json_schema_impls/serdejson.rs @@ -16,17 +16,7 @@ impl JsonSchema for Value { } } -impl JsonSchema for Map { - no_ref_schema!(); - - fn schema_name() -> String { - BTreeMap::::schema_name() - } - - fn json_schema(gen: &mut SchemaGenerator) -> Schema { - BTreeMap::::json_schema(gen) - } -} +forward_impl!(Map => BTreeMap::); impl JsonSchema for Number { no_ref_schema!(); diff --git a/schemars/src/json_schema_impls/wrapper.rs b/schemars/src/json_schema_impls/wrapper.rs index 5d7164b..243a06b 100644 --- a/schemars/src/json_schema_impls/wrapper.rs +++ b/schemars/src/json_schema_impls/wrapper.rs @@ -2,42 +2,23 @@ use crate::gen::SchemaGenerator; use crate::schema::Schema; use crate::JsonSchema; -macro_rules! deref_impl { +macro_rules! wrapper_impl { ($($desc:tt)+) => { - impl $($desc)+ - where - T: JsonSchema, - { - fn is_referenceable() -> bool { - T::is_referenceable() - } - - fn schema_name() -> String { - T::schema_name() - } - - fn json_schema(gen: &mut SchemaGenerator) -> Schema { - T::json_schema(gen) - } - - fn json_schema_optional(gen: &mut SchemaGenerator) -> Schema { - T::json_schema_optional(gen) - } - } + forward_impl!(($($desc)+ where T: JsonSchema) => T); }; } -deref_impl!(<'a, T: ?Sized> JsonSchema for &'a T); -deref_impl!(<'a, T: ?Sized> JsonSchema for &'a mut T); -deref_impl!( JsonSchema for Box); -deref_impl!( JsonSchema for std::rc::Rc); -deref_impl!( JsonSchema for std::rc::Weak); -deref_impl!( JsonSchema for std::sync::Arc); -deref_impl!( JsonSchema for std::sync::Weak); -deref_impl!( JsonSchema for std::sync::Mutex); -deref_impl!( JsonSchema for std::sync::RwLock); -deref_impl!( JsonSchema for std::cell::Cell); -deref_impl!( JsonSchema for std::cell::RefCell); -deref_impl!(<'a, T: ?Sized + ToOwned> JsonSchema for std::borrow::Cow<'a, T>); -deref_impl!( JsonSchema for std::num::Wrapping); -deref_impl!( JsonSchema for std::cmp::Reverse); +wrapper_impl!(<'a, T: ?Sized> JsonSchema for &'a T); +wrapper_impl!(<'a, T: ?Sized> JsonSchema for &'a mut T); +wrapper_impl!( JsonSchema for Box); +wrapper_impl!( JsonSchema for std::rc::Rc); +wrapper_impl!( JsonSchema for std::rc::Weak); +wrapper_impl!( JsonSchema for std::sync::Arc); +wrapper_impl!( JsonSchema for std::sync::Weak); +wrapper_impl!( JsonSchema for std::sync::Mutex); +wrapper_impl!( JsonSchema for std::sync::RwLock); +wrapper_impl!( JsonSchema for std::cell::Cell); +wrapper_impl!( JsonSchema for std::cell::RefCell); +wrapper_impl!(<'a, T: ?Sized + ToOwned> JsonSchema for std::borrow::Cow<'a, T>); +wrapper_impl!( JsonSchema for std::num::Wrapping); +wrapper_impl!( JsonSchema for std::cmp::Reverse);