1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
use crate::gen::SchemaGenerator; use crate::schema::*; use crate::JsonSchema; use serde_json::json; impl<T: JsonSchema> JsonSchema for Option<T> { no_ref_schema!(); fn schema_name() -> String { format!("Nullable_{}", T::schema_name()) } fn json_schema(gen: &mut SchemaGenerator) -> Schema { let mut schema = if gen.settings().option_nullable { T::json_schema(gen) } else { gen.subschema_for::<T>() }; if gen.settings().option_add_null_type { schema = match schema { Schema::Bool(true) => Schema::Bool(true), Schema::Bool(false) => <()>::json_schema(gen), Schema::Object( obj @ SchemaObject { instance_type: Some(_), .. }, ) => Schema::Object(with_null_type(obj)), schema => SchemaObject { subschemas: Some(Box::new(SubschemaValidation { any_of: Some(vec![schema, <()>::json_schema(gen)]), ..Default::default() })), ..Default::default() } .into(), } } if gen.settings().option_nullable { let mut schema_obj: SchemaObject = schema.into(); schema_obj .extensions .insert("nullable".to_owned(), json!(true)); schema = Schema::Object(schema_obj); }; schema } fn json_schema_optional(gen: &mut SchemaGenerator) -> Schema { let mut schema = T::json_schema_optional(gen); if let Schema::Object(SchemaObject { object: Some(ref mut object_validation), .. }) = schema { object_validation.required.clear(); } schema } } fn with_null_type(mut obj: SchemaObject) -> SchemaObject { match obj .instance_type .as_mut() .expect("checked in calling function") { SingleOrVec::Single(ty) if **ty == InstanceType::Null => {} SingleOrVec::Vec(ty) if ty.contains(&InstanceType::Null) => {} SingleOrVec::Single(ty) => obj.instance_type = Some(vec![**ty, InstanceType::Null].into()), SingleOrVec::Vec(ref mut ty) => ty.push(InstanceType::Null), }; obj } impl<T: ?Sized> JsonSchema for std::marker::PhantomData<T> { no_ref_schema!(); fn schema_name() -> String { <()>::schema_name() } fn json_schema(gen: &mut SchemaGenerator) -> Schema { <()>::json_schema(gen) } } #[cfg(test)] mod tests { use super::*; use crate::gen::*; use crate::tests::{custom_schema_object_for, schema_for, schema_object_for}; use pretty_assertions::assert_eq; #[test] fn schema_for_option() { let schema = schema_object_for::<Option<i32>>(); assert_eq!( schema.instance_type, Some(vec![InstanceType::Integer, InstanceType::Null].into()) ); assert_eq!(schema.extensions.get("nullable"), None); assert_eq!(schema.subschemas.is_none(), true); } #[test] fn schema_for_option_with_ref() { use crate as schemars; #[derive(JsonSchema)] struct Foo; let schema = schema_object_for::<Option<Foo>>(); assert_eq!(schema.instance_type, None); assert_eq!(schema.extensions.get("nullable"), None); assert_eq!(schema.subschemas.is_some(), true); let any_of = schema.subschemas.unwrap().any_of.unwrap(); assert_eq!(any_of.len(), 2); assert_eq!(any_of[0], Schema::new_ref("#/definitions/Foo".to_string())); assert_eq!(any_of[1], schema_for::<()>()); } #[test] fn schema_for_option_with_nullable() { let settings = SchemaSettings { option_nullable: true, option_add_null_type: false, ..Default::default() }; let schema = custom_schema_object_for::<Option<i32>>(settings); assert_eq!( schema.instance_type, Some(SingleOrVec::from(InstanceType::Integer)) ); assert_eq!(schema.extensions.get("nullable"), Some(&json!(true))); assert_eq!(schema.subschemas.is_none(), true); } }