Implement JsonSchema for Range/RangeInclusive

This commit is contained in:
Graham Esau 2019-10-27 22:30:01 +00:00
parent b334bef91a
commit fe861ac3a1
10 changed files with 203 additions and 50 deletions

View file

@ -2,6 +2,7 @@ use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use serde_json::json;
use std::ops::{Range, RangeInclusive};
impl<T: JsonSchema> JsonSchema for Option<T> {
no_ref_schema!();
@ -74,8 +75,6 @@ fn with_null_type(mut obj: SchemaObject) -> SchemaObject {
}
impl<T: JsonSchema, E: JsonSchema> JsonSchema for Result<T, E> {
no_ref_schema!();
fn schema_name() -> String {
format!("Result_Of_{}_Or_{}", T::schema_name(), E::schema_name())
}
@ -83,18 +82,16 @@ impl<T: JsonSchema, E: JsonSchema> JsonSchema for Result<T, E> {
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut ok_schema = SchemaObject::default();
ok_schema.instance_type = Some(InstanceType::Object.into());
ok_schema.object().required.insert("Ok".to_owned());
ok_schema
.object()
.properties
let obj = ok_schema.object();
obj.required.insert("Ok".to_owned());
obj.properties
.insert("Ok".to_owned(), gen.subschema_for::<T>());
let mut err_schema = SchemaObject::default();
err_schema.instance_type = Some(InstanceType::Object.into());
err_schema.object().required.insert("Err".to_owned());
err_schema
.object()
.properties
let obj = err_schema.object();
obj.required.insert("Err".to_owned());
obj.properties
.insert("Err".to_owned(), gen.subschema_for::<E>());
let mut schema = SchemaObject::default();
@ -103,6 +100,35 @@ impl<T: JsonSchema, E: JsonSchema> JsonSchema for Result<T, E> {
}
}
impl<T: JsonSchema> JsonSchema for Range<T> {
fn schema_name() -> String {
format!("Range_Of_{}", T::schema_name())
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut schema = SchemaObject::default();
schema.instance_type = Some(InstanceType::Object.into());
let obj = schema.object();
obj.required.insert("start".to_owned());
obj.required.insert("end".to_owned());
obj.properties
.insert("start".to_owned(), gen.subschema_for::<T>());
obj.properties
.insert("end".to_owned(), gen.subschema_for::<T>());
schema.into()
}
}
impl<T: JsonSchema> JsonSchema for RangeInclusive<T> {
fn schema_name() -> String {
<Range<T>>::schema_name()
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
<Range<T>>::json_schema(gen)
}
}
impl<T: ?Sized> JsonSchema for std::marker::PhantomData<T> {
no_ref_schema!();

View file

@ -5,13 +5,13 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV
use std::path::{Path, PathBuf};
macro_rules! simple_impl {
($type:tt => $instance_type:ident) => {
($type:ty => $instance_type:ident) => {
simple_impl!($type => $instance_type, None);
};
($type:tt => $instance_type:ident, $format: literal) => {
($type:ty => $instance_type:ident, $format: literal) => {
simple_impl!($type => $instance_type, Some($format.to_owned()));
};
($type:tt => $instance_type:ident, $($format:tt)+) => {
($type:ty => $instance_type:ident, $($format:tt)+) => {
impl JsonSchema for $type {
no_ref_schema!();

View file

@ -11,9 +11,11 @@ impl JsonSchema for Duration {
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut schema = SchemaObject::default();
schema.instance_type = Some(InstanceType::Object.into());
let properties = &mut schema.object().properties;
properties.insert("secs".to_owned(), <u64>::json_schema(gen));
properties.insert("nanos".to_owned(), <u32>::json_schema(gen));
let obj = schema.object();
obj.required.insert("secs".to_owned());
obj.required.insert("nanos".to_owned());
obj.properties.insert("secs".to_owned(), <u64>::json_schema(gen));
obj.properties.insert("nanos".to_owned(), <u32>::json_schema(gen));
schema.into()
}
}
@ -26,9 +28,11 @@ impl JsonSchema for SystemTime {
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut schema = SchemaObject::default();
schema.instance_type = Some(InstanceType::Object.into());
let properties = &mut schema.object().properties;
properties.insert("secs_since_epoch".to_owned(), <u64>::json_schema(gen));
properties.insert("nanos_since_epoch".to_owned(), <u32>::json_schema(gen));
let obj = schema.object();
obj.required.insert("secs_since_epoch".to_owned());
obj.required.insert("nanos_since_epoch".to_owned());
obj.properties.insert("secs_since_epoch".to_owned(), <u64>::json_schema(gen));
obj.properties.insert("nanos_since_epoch".to_owned(), <u32>::json_schema(gen));
schema.into()
}
}

View file

@ -15,7 +15,7 @@
/// ```
#[macro_export]
macro_rules! schema_for {
($type:path) => {
($type:ty) => {
$crate::gen::SchemaGenerator::default().into_root_schema_for::<$type>()
};
}

View file

@ -144,14 +144,14 @@ where
}
macro_rules! get_or_insert_default_fn {
($name:ident, $ret:path) => {
($name:ident, $ret:ty) => {
get_or_insert_default_fn!(
concat!("Returns a mutable reference to this schema's [`", stringify!($ret), "`](#structfield.", stringify!($name), "), creating it if it was `None`."),
$name,
$ret
);
};
($doc:expr, $name:ident, $ret:path) => {
($doc:expr, $name:ident, $ret:ty) => {
#[doc = $doc]
pub fn $name(&mut self) -> &mut $ret {
self.$name.get_or_insert_with(Default::default)

View file

@ -17,6 +17,10 @@
"definitions": {
"Duration": {
"type": "object",
"required": [
"nanos",
"secs"
],
"properties": {
"nanos": {
"type": "integer",
@ -30,6 +34,10 @@
},
"SystemTime": {
"type": "object",
"required": [
"nanos_since_epoch",
"secs_since_epoch"
],
"properties": {
"nanos_since_epoch": {
"type": "integer",

View file

@ -0,0 +1,53 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MyStruct",
"type": "object",
"required": [
"inclusive",
"range"
],
"properties": {
"inclusive": {
"$ref": "#/definitions/Range_Of_Number"
},
"range": {
"$ref": "#/definitions/Range_Of_Integer"
}
},
"definitions": {
"Range_Of_Integer": {
"type": "object",
"required": [
"end",
"start"
],
"properties": {
"end": {
"type": "integer",
"format": "uint"
},
"start": {
"type": "integer",
"format": "uint"
}
}
},
"Range_Of_Number": {
"type": "object",
"required": [
"end",
"start"
],
"properties": {
"end": {
"type": "number",
"format": "double"
},
"start": {
"type": "number",
"format": "double"
}
}
}
}
}

View file

@ -1,6 +1,59 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Result_Of_MyStruct_Or_Array_Of_String",
"title": "Container",
"type": "object",
"required": [
"result1",
"result2"
],
"properties": {
"result1": {
"$ref": "#/definitions/Result_Of_MyStruct_Or_Array_Of_String"
},
"result2": {
"$ref": "#/definitions/Result_Of_Boolean_Or_Null"
}
},
"definitions": {
"MyStruct": {
"type": "object",
"required": [
"foo"
],
"properties": {
"foo": {
"type": "integer",
"format": "int32"
}
}
},
"Result_Of_Boolean_Or_Null": {
"oneOf": [
{
"type": "object",
"required": [
"Ok"
],
"properties": {
"Ok": {
"type": "boolean"
}
}
},
{
"type": "object",
"required": [
"Err"
],
"properties": {
"Err": {
"type": "null"
}
}
}
]
},
"Result_Of_MyStruct_Or_Array_Of_String": {
"oneOf": [
{
"type": "object",
@ -27,19 +80,7 @@
}
}
}
],
"definitions": {
"MyStruct": {
"type": "object",
"required": [
"foo"
],
"properties": {
"foo": {
"type": "integer",
"format": "int32"
}
}
]
}
}
}

15
schemars/tests/range.rs Normal file
View file

@ -0,0 +1,15 @@
mod util;
use schemars::JsonSchema;
use util::*;
use std::ops::{Range, RangeInclusive};
#[derive(Debug, JsonSchema)]
struct MyStruct {
range: Range<usize>,
inclusive: RangeInclusive<f64>,
}
#[test]
fn result() -> TestResult {
test_default_generated_schema::<MyStruct>("range")
}

View file

@ -7,7 +7,13 @@ struct MyStruct {
foo: i32,
}
#[derive(Debug, JsonSchema)]
struct Container {
result1: Result<MyStruct, Vec<String>>,
result2: Result<bool, ()>,
}
#[test]
fn result() -> TestResult {
test_default_generated_schema::<Result<MyStruct, Vec<String>>>("result")
test_default_generated_schema::<Container>("result")
}