schemars/json_schema_impls/
core.rs
1use crate::gen::SchemaGenerator;
2use crate::schema::*;
3use crate::JsonSchema;
4use serde_json::json;
5use std::ops::{Bound, Range, RangeInclusive};
6
7impl<T: JsonSchema> JsonSchema for Option<T> {
8 no_ref_schema!();
9
10 fn schema_name() -> String {
11 format!("Nullable_{}", T::schema_name())
12 }
13
14 fn json_schema(gen: &mut SchemaGenerator) -> Schema {
15 let mut schema = gen.subschema_for::<T>();
16 if gen.settings().option_add_null_type {
17 schema = match schema {
18 Schema::Bool(true) => Schema::Bool(true),
19 Schema::Bool(false) => <()>::json_schema(gen),
20 Schema::Object(SchemaObject {
21 instance_type: Some(ref mut instance_type),
22 ..
23 }) => {
24 add_null_type(instance_type);
25 schema
26 }
27 schema => SchemaObject {
28 subschemas: Some(Box::new(SubschemaValidation {
30 any_of: Some(vec![schema, <()>::json_schema(gen)]),
31 ..Default::default()
32 })),
33 ..Default::default()
34 }
35 .into(),
36 }
37 }
38 if gen.settings().option_nullable {
39 let mut schema_obj = schema.into_object();
40 schema_obj
41 .extensions
42 .insert("nullable".to_owned(), json!(true));
43 schema = Schema::Object(schema_obj);
44 };
45 schema
46 }
47
48 fn _schemars_private_non_optional_json_schema(gen: &mut SchemaGenerator) -> Schema {
49 T::_schemars_private_non_optional_json_schema(gen)
50 }
51
52 fn _schemars_private_is_option() -> bool {
53 true
54 }
55}
56
57fn add_null_type(instance_type: &mut SingleOrVec<InstanceType>) {
58 match instance_type {
59 SingleOrVec::Single(ty) if **ty != InstanceType::Null => {
60 *instance_type = vec![**ty, InstanceType::Null].into()
61 }
62 SingleOrVec::Vec(ty) if !ty.contains(&InstanceType::Null) => ty.push(InstanceType::Null),
63 _ => {}
64 };
65}
66
67impl<T: JsonSchema, E: JsonSchema> JsonSchema for Result<T, E> {
68 fn schema_name() -> String {
69 format!("Result_of_{}_or_{}", T::schema_name(), E::schema_name())
70 }
71
72 fn json_schema(gen: &mut SchemaGenerator) -> Schema {
73 let mut ok_schema = SchemaObject {
74 instance_type: Some(InstanceType::Object.into()),
75 ..Default::default()
76 };
77 let obj = ok_schema.object();
78 obj.required.insert("Ok".to_owned());
79 obj.properties
80 .insert("Ok".to_owned(), gen.subschema_for::<T>());
81
82 let mut err_schema = SchemaObject {
83 instance_type: Some(InstanceType::Object.into()),
84 ..Default::default()
85 };
86 let obj = err_schema.object();
87 obj.required.insert("Err".to_owned());
88 obj.properties
89 .insert("Err".to_owned(), gen.subschema_for::<E>());
90
91 let mut schema = SchemaObject::default();
92 schema.subschemas().one_of = Some(vec![ok_schema.into(), err_schema.into()]);
93 schema.into()
94 }
95}
96
97impl<T: JsonSchema> JsonSchema for Bound<T> {
98 fn schema_name() -> String {
99 format!("Bound_of_{}", T::schema_name())
100 }
101
102 fn json_schema(gen: &mut SchemaGenerator) -> Schema {
103 let mut included_schema = SchemaObject {
104 instance_type: Some(InstanceType::Object.into()),
105 ..Default::default()
106 };
107 let obj = included_schema.object();
108 obj.required.insert("Included".to_owned());
109 obj.properties
110 .insert("Included".to_owned(), gen.subschema_for::<T>());
111
112 let mut excluded_schema = SchemaObject {
113 instance_type: Some(InstanceType::Object.into()),
114 ..Default::default()
115 };
116 let obj = excluded_schema.object();
117 obj.required.insert("Excluded".to_owned());
118 obj.properties
119 .insert("Excluded".to_owned(), gen.subschema_for::<T>());
120
121 let unbounded_schema = SchemaObject {
122 instance_type: Some(InstanceType::String.into()),
123 const_value: Some(json!("Unbounded")),
124 ..Default::default()
125 };
126
127 let mut schema = SchemaObject::default();
128 schema.subschemas().one_of = Some(vec![
129 included_schema.into(),
130 excluded_schema.into(),
131 unbounded_schema.into(),
132 ]);
133 schema.into()
134 }
135}
136
137impl<T: JsonSchema> JsonSchema for Range<T> {
138 fn schema_name() -> String {
139 format!("Range_of_{}", T::schema_name())
140 }
141
142 fn json_schema(gen: &mut SchemaGenerator) -> Schema {
143 let mut schema = SchemaObject {
144 instance_type: Some(InstanceType::Object.into()),
145 ..Default::default()
146 };
147 let obj = schema.object();
148 obj.required.insert("start".to_owned());
149 obj.required.insert("end".to_owned());
150 obj.properties
151 .insert("start".to_owned(), gen.subschema_for::<T>());
152 obj.properties
153 .insert("end".to_owned(), gen.subschema_for::<T>());
154 schema.into()
155 }
156}
157
158forward_impl!((<T: JsonSchema> JsonSchema for RangeInclusive<T>) => Range<T>);
159
160forward_impl!((<T: ?Sized> JsonSchema for std::marker::PhantomData<T>) => ());
161
162forward_impl!((<'a> JsonSchema for std::fmt::Arguments<'a>) => String);
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167 use crate::tests::{schema_for, schema_object_for};
168 use pretty_assertions::assert_eq;
169
170 #[test]
171 fn schema_for_option() {
172 let schema = schema_object_for::<Option<i32>>();
173 assert_eq!(
174 schema.instance_type,
175 Some(vec![InstanceType::Integer, InstanceType::Null].into())
176 );
177 assert_eq!(schema.extensions.get("nullable"), None);
178 assert_eq!(schema.subschemas.is_none(), true);
179 }
180
181 #[test]
182 fn schema_for_option_with_ref() {
183 use crate as schemars;
184 #[derive(JsonSchema)]
185 struct Foo;
186
187 let schema = schema_object_for::<Option<Foo>>();
188 assert_eq!(schema.instance_type, None);
189 assert_eq!(schema.extensions.get("nullable"), None);
190 assert_eq!(schema.subschemas.is_some(), true);
191 let any_of = schema.subschemas.unwrap().any_of.unwrap();
192 assert_eq!(any_of.len(), 2);
193 assert_eq!(any_of[0], Schema::new_ref("#/definitions/Foo".to_string()));
194 assert_eq!(any_of[1], schema_for::<()>());
195 }
196
197 #[test]
198 fn schema_for_result() {
199 let schema = schema_object_for::<Result<bool, String>>();
200 let one_of = schema.subschemas.unwrap().one_of.unwrap();
201 assert_eq!(one_of.len(), 2);
202
203 let ok_schema: SchemaObject = one_of[0].clone().into();
204 let obj = ok_schema.object.unwrap();
205 assert!(obj.required.contains("Ok"));
206 assert_eq!(obj.properties["Ok"], schema_for::<bool>());
207
208 let err_schema: SchemaObject = one_of[1].clone().into();
209 let obj = err_schema.object.unwrap();
210 assert!(obj.required.contains("Err"));
211 assert_eq!(obj.properties["Err"], schema_for::<String>());
212 }
213}