diff --git a/Cargo.lock b/Cargo.lock index f39bca27..ed586729 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -85,6 +85,15 @@ dependencies = [ "syn", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "diff" version = "0.1.13" @@ -212,6 +221,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.45" @@ -243,6 +258,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "pretty_assertions" version = "1.4.0" @@ -328,6 +349,7 @@ dependencies = [ "serde_json", "smallvec", "smol_str", + "time", "trybuild", "url", "uuid", @@ -426,6 +448,24 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + [[package]] name = "tinyvec" version = "1.6.0" diff --git a/schemars/Cargo.toml b/schemars/Cargo.toml index 42457472..cee7c81d 100644 --- a/schemars/Cargo.toml +++ b/schemars/Cargo.toml @@ -33,6 +33,7 @@ smallvec1 = { version = "1.0", default-features = false, optional = true, packag smol_str02 = { version = "0.2.1", default-features = false, optional = true, package = "smol_str" } url2 = { version = "2.0", default-features = false, optional = true, package = "url" } uuid1 = { version = "1.0", default-features = false, optional = true, package = "uuid" } +time = { version = "0.3", default-features = false, optional = true } [dev-dependencies] pretty_assertions = "1.2.1" @@ -120,6 +121,10 @@ required-features = ["semver1"] name = "decimal" required-features = ["rust_decimal1", "bigdecimal04"] +[[test]] +name = "time" +required-features = ["time"] + [package.metadata.docs.rs] all-features = true rustdoc-args = ["--extend-css", "docs-rs-custom.css"] diff --git a/schemars/src/json_schema_impls/mod.rs b/schemars/src/json_schema_impls/mod.rs index 1921a6ae..3b73364c 100644 --- a/schemars/src/json_schema_impls/mod.rs +++ b/schemars/src/json_schema_impls/mod.rs @@ -48,6 +48,8 @@ mod primitives; mod sequences; mod serdejson; mod std_time; +#[cfg(feature = "time")] +mod time; mod tuple; mod wrapper; diff --git a/schemars/src/json_schema_impls/time.rs b/schemars/src/json_schema_impls/time.rs new file mode 100644 index 00000000..ef28b58f --- /dev/null +++ b/schemars/src/json_schema_impls/time.rs @@ -0,0 +1,35 @@ +use crate::SchemaGenerator; +use crate::{json_schema, JsonSchema, Schema}; +use alloc::borrow::Cow; +use time::{Date, OffsetDateTime, PrimitiveDateTime, Time}; + +macro_rules! formatted_string_impl { + ($ty:ident, $format:literal) => { + formatted_string_impl!($ty, $format, JsonSchema for $ty); + }; + ($ty:ident, $format:literal, $($desc:tt)+) => { + impl $($desc)+ { + always_inline!(); + + fn schema_name() -> Cow<'static, str> { + stringify!($ty).into() + } + + fn schema_id() -> Cow<'static, str> { + stringify!(time::$ty).into() + } + + fn json_schema(_: &mut SchemaGenerator) -> Schema { + json_schema!({ + "type": "string", + "format": $format + }) + } + } + }; +} + +formatted_string_impl!(Date, "date"); +formatted_string_impl!(PrimitiveDateTime, "partial-date-time"); +formatted_string_impl!(Time, "time"); +formatted_string_impl!(OffsetDateTime, "date-time"); diff --git a/schemars/tests/expected/time-types.json b/schemars/tests/expected/time-types.json new file mode 100644 index 00000000..994a00ad --- /dev/null +++ b/schemars/tests/expected/time-types.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "TimeTypes", + "type": "object", + "properties": { + "date": { + "type": "string", + "format": "date" + }, + "offset_date_time": { + "type": "string", + "format": "date-time" + }, + "primitive_date_time": { + "type": "string", + "format": "partial-date-time" + }, + "time": { + "type": "string", + "format": "time" + } + }, + "required": [ + "date", + "offset_date_time", + "primitive_date_time", + "time" + ] +} \ No newline at end of file diff --git a/schemars/tests/time.rs b/schemars/tests/time.rs new file mode 100644 index 00000000..9c717f3e --- /dev/null +++ b/schemars/tests/time.rs @@ -0,0 +1,18 @@ +mod util; +use schemars::JsonSchema; +use time::{Date, OffsetDateTime, PrimitiveDateTime, Time}; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct TimeTypes { + date: Date, + offset_date_time: OffsetDateTime, + primitive_date_time: PrimitiveDateTime, + time: Time, +} + +#[test] +fn time_types() -> TestResult { + test_default_generated_schema::("time-types") +}