Schema generation now never returns an error
This commit is contained in:
parent
8880fb3961
commit
5bf8b30753
18 changed files with 167 additions and 160 deletions
|
@ -1,4 +1,4 @@
|
|||
use schemars::{JsonSchema, schema_for};
|
||||
use schemars::{schema_for, JsonSchema};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize, JsonSchema)]
|
||||
|
@ -20,7 +20,7 @@ struct Nested {
|
|||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let schema = schema_for!(MyStruct)?;
|
||||
let schema = schema_for!(MyStruct);
|
||||
println!("{}", serde_json::to_string_pretty(&schema)?);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
use std::fmt;
|
||||
use std::error::Error;
|
||||
use crate::schema::Schema;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
pub type Result<T = Schema> = std::result::Result<T, JsonSchemaError>;
|
||||
pub type Result<T> = std::result::Result<T, JsonSchemaError>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct JsonSchemaError {
|
||||
msg: &'static str,
|
||||
schema: Schema
|
||||
schema: Schema,
|
||||
}
|
||||
|
||||
impl JsonSchemaError {
|
||||
pub fn new(msg: &'static str, schema: Schema) -> JsonSchemaError {
|
||||
JsonSchemaError { msg, schema }
|
||||
}
|
||||
|
||||
pub fn schema(&self) -> &Schema {
|
||||
&self.schema
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for JsonSchemaError {
|
||||
|
@ -22,5 +26,4 @@ impl fmt::Display for JsonSchemaError {
|
|||
}
|
||||
}
|
||||
|
||||
impl Error for JsonSchemaError {
|
||||
}
|
||||
impl Error for JsonSchemaError {}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
use crate::schema::*;
|
||||
use crate::{JsonSchemaError, Map, Result, Set};
|
||||
use crate::{Map, Set};
|
||||
|
||||
impl Schema {
|
||||
pub fn flatten(self, other: Self) -> Result {
|
||||
pub fn flatten(self, other: Self) -> Schema {
|
||||
if is_null_type(&self) {
|
||||
return Ok(other);
|
||||
return other;
|
||||
} else if is_null_type(&other) {
|
||||
return Ok(self);
|
||||
return self;
|
||||
}
|
||||
let s1 = ensure_object_type(self)?;
|
||||
let s2 = ensure_object_type(other)?;
|
||||
Ok(Schema::Object(s1.merge(s2)))
|
||||
let s1: SchemaObject = self.into();
|
||||
let s2: SchemaObject = other.into();
|
||||
Schema::Object(s1.merge(s2))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,30 +145,3 @@ fn is_null_type(schema: &Schema) -> bool {
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_object_type(schema: Schema) -> Result<SchemaObject> {
|
||||
let s = match schema {
|
||||
Schema::Object(s) => s,
|
||||
s => {
|
||||
return Err(JsonSchemaError::new(
|
||||
"Only schemas with type `object` or `null` can be flattened.",
|
||||
s,
|
||||
))
|
||||
}
|
||||
};
|
||||
match s.instance_type {
|
||||
Some(SingleOrVec::Single(ref t)) if **t != InstanceType::Object => {
|
||||
Err(JsonSchemaError::new(
|
||||
"Only schemas with type `object` or `null` can be flattened.",
|
||||
s.into(),
|
||||
))
|
||||
}
|
||||
Some(SingleOrVec::Vec(ref t)) if !t.contains(&InstanceType::Object) => {
|
||||
Err(JsonSchemaError::new(
|
||||
"Only schemas with type `object` or `null` can be flattened.",
|
||||
s.into(),
|
||||
))
|
||||
}
|
||||
_ => Ok(s),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ impl SchemaGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn subschema_for<T: ?Sized + JsonSchema>(&mut self) -> Result {
|
||||
pub fn subschema_for<T: ?Sized + JsonSchema>(&mut self) -> Schema {
|
||||
if !T::is_referenceable() {
|
||||
return T::json_schema(self);
|
||||
}
|
||||
|
@ -94,26 +94,17 @@ impl SchemaGenerator {
|
|||
let name = T::schema_name();
|
||||
let reference = format!("{}{}", self.settings().definitions_path, name);
|
||||
if !self.definitions.contains_key(&name) {
|
||||
self.insert_new_subschema_for::<T>(name)?;
|
||||
self.insert_new_subschema_for::<T>(name);
|
||||
}
|
||||
Ok(Schema::new_ref(reference))
|
||||
Schema::new_ref(reference)
|
||||
}
|
||||
|
||||
fn insert_new_subschema_for<T: ?Sized + JsonSchema>(&mut self, name: String) -> Result<()> {
|
||||
fn insert_new_subschema_for<T: ?Sized + JsonSchema>(&mut self, name: String) {
|
||||
let dummy = Schema::Bool(false);
|
||||
// insert into definitions BEFORE calling json_schema to avoid infinite recursion
|
||||
self.definitions.insert(name.clone(), dummy);
|
||||
|
||||
match T::json_schema(self) {
|
||||
Ok(schema) => {
|
||||
self.definitions.insert(name, schema);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
self.definitions.remove(&name);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
let schema = T::json_schema(self);
|
||||
self.definitions.insert(name, schema);
|
||||
}
|
||||
|
||||
pub fn definitions(&self) -> &Map<String, Schema> {
|
||||
|
@ -124,25 +115,25 @@ impl SchemaGenerator {
|
|||
self.definitions
|
||||
}
|
||||
|
||||
pub fn root_schema_for<T: ?Sized + JsonSchema>(&mut self) -> Result<SchemaObject> {
|
||||
let mut schema: SchemaObject = T::json_schema(self)?.into();
|
||||
pub fn root_schema_for<T: ?Sized + JsonSchema>(&mut self) -> SchemaObject {
|
||||
let mut schema: SchemaObject = T::json_schema(self).into();
|
||||
let metadata = schema.metadata();
|
||||
metadata.schema = Some("http://json-schema.org/draft-07/schema#".to_owned());
|
||||
metadata.title = Some(T::schema_name());
|
||||
metadata.definitions.extend(self.definitions().clone());
|
||||
Ok(schema)
|
||||
schema
|
||||
}
|
||||
|
||||
pub fn into_root_schema_for<T: ?Sized + JsonSchema>(mut self) -> Result<SchemaObject> {
|
||||
let mut schema: SchemaObject = T::json_schema(&mut self)?.into();
|
||||
pub fn into_root_schema_for<T: ?Sized + JsonSchema>(mut self) -> SchemaObject {
|
||||
let mut schema: SchemaObject = T::json_schema(&mut self).into();
|
||||
let metadata = schema.metadata();
|
||||
metadata.schema = Some("http://json-schema.org/draft-07/schema#".to_owned());
|
||||
metadata.title = Some(T::schema_name());
|
||||
metadata.definitions.extend(self.into_definitions());
|
||||
Ok(schema)
|
||||
schema
|
||||
}
|
||||
|
||||
pub fn dereference_once(&self, schema: Schema) -> Result<Schema> {
|
||||
pub fn dereference_once<'a>(&'a self, schema: &'a Schema) -> Result<&'a Schema> {
|
||||
match schema {
|
||||
Schema::Object(SchemaObject {
|
||||
reference: Some(ref schema_ref),
|
||||
|
@ -152,20 +143,20 @@ impl SchemaGenerator {
|
|||
if !schema_ref.starts_with(definitions_path) {
|
||||
return Err(JsonSchemaError::new(
|
||||
"Could not extract referenced schema name.",
|
||||
schema,
|
||||
schema.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
let name = &schema_ref[definitions_path.len()..];
|
||||
self.definitions.get(name).cloned().ok_or_else(|| {
|
||||
JsonSchemaError::new("Could not find referenced schema.", schema)
|
||||
self.definitions.get(name).ok_or_else(|| {
|
||||
JsonSchemaError::new("Could not find referenced schema.", schema.clone())
|
||||
})
|
||||
}
|
||||
s => Ok(s),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dereference(&self, mut schema: Schema) -> Result<Schema> {
|
||||
pub fn dereference<'a>(&'a self, mut schema: &'a Schema) -> Result<&'a Schema> {
|
||||
if !schema.is_ref() {
|
||||
return Ok(schema);
|
||||
}
|
||||
|
@ -177,7 +168,7 @@ impl SchemaGenerator {
|
|||
}
|
||||
Err(JsonSchemaError::new(
|
||||
"Failed to dereference schema after 100 iterations - references may be cyclic.",
|
||||
schema,
|
||||
schema.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::gen::SchemaGenerator;
|
||||
use crate::schema::*;
|
||||
use crate::{JsonSchema, Result};
|
||||
use crate::JsonSchema;
|
||||
|
||||
// Does not require T: JsonSchema.
|
||||
impl<T> JsonSchema for [T; 0] {
|
||||
|
@ -10,8 +10,8 @@ impl<T> JsonSchema for [T; 0] {
|
|||
"Empty_Array".to_owned()
|
||||
}
|
||||
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Result {
|
||||
Ok(SchemaObject {
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||
SchemaObject {
|
||||
instance_type: Some(InstanceType::Array.into()),
|
||||
array: Some(Box::new(ArrayValidation {
|
||||
max_items: Some(0),
|
||||
|
@ -19,7 +19,7 @@ impl<T> JsonSchema for [T; 0] {
|
|||
})),
|
||||
..Default::default()
|
||||
}
|
||||
.into())
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,17 +33,18 @@ macro_rules! array_impls {
|
|||
format!("Array_Size_{}_Of_{}", $len, T::schema_name())
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Result {
|
||||
Ok(SchemaObject {
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||
SchemaObject {
|
||||
instance_type: Some(InstanceType::Array.into()),
|
||||
array: Some(Box::new(ArrayValidation {
|
||||
items: Some(gen.subschema_for::<T>()?.into()),
|
||||
items: Some(gen.subschema_for::<T>().into()),
|
||||
max_items: Some($len),
|
||||
min_items: Some($len),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}.into())
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
)+
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::gen::SchemaGenerator;
|
||||
use crate::schema::*;
|
||||
use crate::{JsonSchema, Result};
|
||||
use crate::JsonSchema;
|
||||
use chrono::prelude::*;
|
||||
use serde_json::json;
|
||||
|
||||
|
@ -11,8 +11,8 @@ impl JsonSchema for Weekday {
|
|||
"Weekday".to_owned()
|
||||
}
|
||||
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Result {
|
||||
Ok(SchemaObject {
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||
SchemaObject {
|
||||
instance_type: Some(InstanceType::String.into()),
|
||||
enum_values: Some(vec![
|
||||
json!("Mon"),
|
||||
|
@ -25,7 +25,7 @@ impl JsonSchema for Weekday {
|
|||
]),
|
||||
..Default::default()
|
||||
}
|
||||
.into())
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,13 +41,13 @@ macro_rules! formatted_string_impl {
|
|||
stringify!($ty).to_owned()
|
||||
}
|
||||
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Result {
|
||||
Ok(SchemaObject {
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||
SchemaObject {
|
||||
instance_type: Some(InstanceType::String.into()),
|
||||
format: Some($format.to_owned()),
|
||||
..Default::default()
|
||||
}
|
||||
.into())
|
||||
.into()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::gen::SchemaGenerator;
|
||||
use crate::schema::*;
|
||||
use crate::{JsonSchema, Result};
|
||||
use crate::JsonSchema;
|
||||
use serde_json::json;
|
||||
|
||||
impl<T: JsonSchema> JsonSchema for Option<T> {
|
||||
|
@ -10,16 +10,16 @@ impl<T: JsonSchema> JsonSchema for Option<T> {
|
|||
format!("Nullable_{}", T::schema_name())
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Result {
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||
let mut schema = if gen.settings().option_nullable {
|
||||
T::json_schema(gen)?
|
||||
T::json_schema(gen)
|
||||
} else {
|
||||
gen.subschema_for::<T>()?
|
||||
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::Bool(false) => <()>::json_schema(gen),
|
||||
Schema::Object(
|
||||
obj @ SchemaObject {
|
||||
instance_type: Some(_),
|
||||
|
@ -28,7 +28,7 @@ impl<T: JsonSchema> JsonSchema for Option<T> {
|
|||
) => Schema::Object(with_null_type(obj)),
|
||||
schema => SchemaObject {
|
||||
subschemas: Some(Box::new(SubschemaValidation {
|
||||
any_of: Some(vec![schema, <()>::json_schema(gen)?]),
|
||||
any_of: Some(vec![schema, <()>::json_schema(gen)]),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
|
@ -37,14 +37,16 @@ impl<T: JsonSchema> JsonSchema for Option<T> {
|
|||
}
|
||||
}
|
||||
if gen.settings().option_nullable {
|
||||
let mut deref: SchemaObject = gen.dereference(schema)?.into();
|
||||
deref.extensions.insert("nullable".to_owned(), json!(true));
|
||||
schema = Schema::Object(deref);
|
||||
let mut schema_obj: SchemaObject = schema.into();
|
||||
schema_obj
|
||||
.extensions
|
||||
.insert("nullable".to_owned(), json!(true));
|
||||
schema = Schema::Object(schema_obj);
|
||||
};
|
||||
Ok(schema)
|
||||
schema
|
||||
}
|
||||
|
||||
fn json_schema_non_null(gen: &mut SchemaGenerator) -> Result {
|
||||
fn json_schema_non_null(gen: &mut SchemaGenerator) -> Schema {
|
||||
T::json_schema_non_null(gen)
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +72,7 @@ impl<T: ?Sized> JsonSchema for std::marker::PhantomData<T> {
|
|||
<()>::schema_name()
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Result {
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||
<()>::json_schema(gen)
|
||||
}
|
||||
}
|
||||
|
@ -82,8 +84,8 @@ impl JsonSchema for std::convert::Infallible {
|
|||
"Never".to_owned()
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Result {
|
||||
Ok(gen.schema_for_none())
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||
gen.schema_for_none()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::gen::SchemaGenerator;
|
||||
use crate::{JsonSchema, Result};
|
||||
use crate::schema::Schema;
|
||||
use crate::JsonSchema;
|
||||
|
||||
macro_rules! deref_impl {
|
||||
($($desc:tt)+) => {
|
||||
|
@ -15,7 +16,7 @@ macro_rules! deref_impl {
|
|||
T::schema_name()
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Result {
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||
T::json_schema(gen)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::gen::{BoolSchemas, SchemaGenerator};
|
||||
use crate::schema::*;
|
||||
use crate::{JsonSchema, Result};
|
||||
use crate::JsonSchema;
|
||||
|
||||
macro_rules! map_impl {
|
||||
($($desc:tt)+) => {
|
||||
|
@ -15,8 +15,8 @@ macro_rules! map_impl {
|
|||
format!("Map_Of_{}", V::schema_name())
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Result {
|
||||
let subschema = gen.subschema_for::<V>()?;
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||
let subschema = gen.subschema_for::<V>();
|
||||
let json_schema_bool = gen.settings().bool_schemas == BoolSchemas::AdditionalPropertiesOnly
|
||||
&& subschema == gen.schema_for_any();
|
||||
let additional_properties =
|
||||
|
@ -25,14 +25,15 @@ macro_rules! map_impl {
|
|||
} else {
|
||||
subschema.into()
|
||||
};
|
||||
Ok(SchemaObject {
|
||||
SchemaObject {
|
||||
instance_type: Some(InstanceType::Object.into()),
|
||||
object: Some(Box::new(ObjectValidation {
|
||||
additional_properties: Some(Box::new(additional_properties)),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}.into())
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -61,7 +62,8 @@ mod tests {
|
|||
schema.instance_type,
|
||||
Some(SingleOrVec::from(InstanceType::Object))
|
||||
);
|
||||
let additional_properties = schema.object
|
||||
let additional_properties = schema
|
||||
.object
|
||||
.unwrap()
|
||||
.additional_properties
|
||||
.expect("additionalProperties field present");
|
||||
|
@ -80,7 +82,8 @@ mod tests {
|
|||
schema.instance_type,
|
||||
Some(SingleOrVec::from(InstanceType::Object))
|
||||
);
|
||||
let additional_properties = schema.object
|
||||
let additional_properties = schema
|
||||
.object
|
||||
.unwrap()
|
||||
.additional_properties
|
||||
.expect("additionalProperties field present");
|
||||
|
@ -103,7 +106,8 @@ mod tests {
|
|||
schema.instance_type,
|
||||
Some(SingleOrVec::from(InstanceType::Object))
|
||||
);
|
||||
let additional_properties = schema.object
|
||||
let additional_properties = schema
|
||||
.object
|
||||
.unwrap()
|
||||
.additional_properties
|
||||
.expect("additionalProperties field present");
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::gen::SchemaGenerator;
|
||||
use crate::schema::*;
|
||||
use crate::{JsonSchema, Result};
|
||||
use crate::JsonSchema;
|
||||
|
||||
macro_rules! simple_impl {
|
||||
($type:tt => $instance_type:ident) => {
|
||||
|
@ -17,13 +17,13 @@ macro_rules! simple_impl {
|
|||
stringify!($instance_type).to_owned()
|
||||
}
|
||||
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Result {
|
||||
Ok(SchemaObject {
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||
SchemaObject {
|
||||
instance_type: Some(InstanceType::$instance_type.into()),
|
||||
format: $($format)+,
|
||||
..Default::default()
|
||||
}
|
||||
.into())
|
||||
.into()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -55,8 +55,8 @@ impl JsonSchema for char {
|
|||
"Character".to_owned()
|
||||
}
|
||||
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Result {
|
||||
Ok(SchemaObject {
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||
SchemaObject {
|
||||
instance_type: Some(InstanceType::String.into()),
|
||||
string: Some(Box::new(StringValidation {
|
||||
min_length: Some(1),
|
||||
|
@ -65,6 +65,6 @@ impl JsonSchema for char {
|
|||
})),
|
||||
..Default::default()
|
||||
}
|
||||
.into())
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::gen::SchemaGenerator;
|
||||
use crate::schema::*;
|
||||
use crate::{JsonSchema, Result};
|
||||
use crate::JsonSchema;
|
||||
|
||||
macro_rules! seq_impl {
|
||||
($($desc:tt)+) => {
|
||||
|
@ -14,15 +14,16 @@ macro_rules! seq_impl {
|
|||
format!("Array_Of_{}", T::schema_name())
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Result {
|
||||
Ok(SchemaObject {
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||
SchemaObject {
|
||||
instance_type: Some(InstanceType::Array.into()),
|
||||
array: Some(Box::new(ArrayValidation {
|
||||
items: Some(gen.subschema_for::<T>()?.into()),
|
||||
items: Some(gen.subschema_for::<T>().into()),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}.into())
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::gen::SchemaGenerator;
|
||||
use crate::schema::*;
|
||||
use crate::{JsonSchema, Result};
|
||||
use crate::JsonSchema;
|
||||
use serde_json::{Map, Number, Value};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
|
@ -11,8 +11,8 @@ impl JsonSchema for Value {
|
|||
"Any_Value".to_owned()
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Result {
|
||||
Ok(gen.schema_for_any())
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||
gen.schema_for_any()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ impl JsonSchema for Map<String, Value> {
|
|||
BTreeMap::<String, Value>::schema_name()
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Result {
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||
BTreeMap::<String, Value>::json_schema(gen)
|
||||
}
|
||||
}
|
||||
|
@ -35,11 +35,11 @@ impl JsonSchema for Number {
|
|||
"Number".to_owned()
|
||||
}
|
||||
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Result {
|
||||
Ok(SchemaObject {
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||
SchemaObject {
|
||||
instance_type: Some(InstanceType::Number.into()),
|
||||
..Default::default()
|
||||
}
|
||||
.into())
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::gen::SchemaGenerator;
|
||||
use crate::schema::*;
|
||||
use crate::{JsonSchema, Result};
|
||||
use crate::JsonSchema;
|
||||
|
||||
macro_rules! tuple_impls {
|
||||
($($len:expr => ($($name:ident)+))+) => {
|
||||
|
@ -12,11 +12,11 @@ macro_rules! tuple_impls {
|
|||
["Tuple_Of".to_owned()$(, $name::schema_name())+].join("_And_")
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Result {
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||
let items = vec![
|
||||
$(gen.subschema_for::<$name>()?),+
|
||||
$(gen.subschema_for::<$name>()),+
|
||||
];
|
||||
Ok(SchemaObject {
|
||||
SchemaObject {
|
||||
instance_type: Some(InstanceType::Array.into()),
|
||||
array: Some(Box::new(ArrayValidation {
|
||||
items: Some(items.into()),
|
||||
|
@ -25,7 +25,8 @@ macro_rules! tuple_impls {
|
|||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}.into())
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
)+
|
||||
|
|
|
@ -15,6 +15,8 @@ pub mod schema;
|
|||
pub use error::*;
|
||||
pub use schemars_derive::*;
|
||||
|
||||
use schema::Schema;
|
||||
|
||||
pub trait JsonSchema {
|
||||
fn is_referenceable() -> bool {
|
||||
true
|
||||
|
@ -22,9 +24,10 @@ pub trait JsonSchema {
|
|||
|
||||
fn schema_name() -> String;
|
||||
|
||||
fn json_schema(gen: &mut gen::SchemaGenerator) -> Result;
|
||||
fn json_schema(gen: &mut gen::SchemaGenerator) -> Schema;
|
||||
|
||||
fn json_schema_non_null(gen: &mut gen::SchemaGenerator) -> Result {
|
||||
#[doc(hidden)]
|
||||
fn json_schema_non_null(gen: &mut gen::SchemaGenerator) -> Schema {
|
||||
Self::json_schema(gen)
|
||||
}
|
||||
}
|
||||
|
@ -48,14 +51,7 @@ pub mod tests {
|
|||
}
|
||||
|
||||
pub fn custom_schema_for<T: JsonSchema>(settings: gen::SchemaSettings) -> schema::Schema {
|
||||
match T::json_schema(&mut gen::SchemaGenerator::new(settings)) {
|
||||
Ok(s) => s,
|
||||
Err(e) => panic!(
|
||||
"Couldn't generate schema object for {}: {}",
|
||||
T::schema_name(),
|
||||
e
|
||||
),
|
||||
}
|
||||
T::json_schema(&mut gen::SchemaGenerator::new(settings))
|
||||
}
|
||||
|
||||
pub fn schema_object(schema: schema::Schema) -> schema::SchemaObject {
|
||||
|
|
36
schemars/tests/dereference.rs
Normal file
36
schemars/tests/dereference.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
mod util;
|
||||
use schemars::{gen::SchemaGenerator, JsonSchema};
|
||||
use std::ptr;
|
||||
|
||||
#[test]
|
||||
fn dereference_i32() -> util::TestResult {
|
||||
let mut gen = SchemaGenerator::default();
|
||||
let i32_schema = gen.subschema_for::<i32>();
|
||||
|
||||
let dereferenced_once = gen.dereference_once(&i32_schema)?;
|
||||
assert!(ptr::eq(dereferenced_once, &i32_schema));
|
||||
|
||||
let dereferenced = gen.dereference(&i32_schema)?;
|
||||
assert!(ptr::eq(dereferenced, &i32_schema));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, JsonSchema)]
|
||||
pub struct Struct {
|
||||
foo: i32,
|
||||
bar: bool,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dereference_struct() -> util::TestResult {
|
||||
let mut gen = SchemaGenerator::default();
|
||||
let struct_ref_schema = gen.subschema_for::<Struct>();
|
||||
let struct_schema = gen.definitions().get(&<Struct>::schema_name()).unwrap();
|
||||
|
||||
let dereferenced_once = gen.dereference_once(&struct_ref_schema)?;
|
||||
assert!(ptr::eq(dereferenced_once, struct_schema));
|
||||
|
||||
let dereferenced = gen.dereference(&struct_ref_schema)?;
|
||||
assert!(ptr::eq(dereferenced, struct_schema));
|
||||
Ok(())
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
mod util;
|
||||
use pretty_assertions::assert_eq;
|
||||
use schemars::{schema_for, JsonSchema};
|
||||
use util::*;
|
||||
|
||||
#[derive(Debug, JsonSchema)]
|
||||
struct Flat {
|
||||
|
@ -33,9 +32,8 @@ struct Deep3 {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn flatten_schema() -> TestResult {
|
||||
let flat = schema_for!(Flat)?;
|
||||
let deep = schema_for!(Deep1)?;
|
||||
fn flatten_schema() {
|
||||
let flat = schema_for!(Flat);
|
||||
let deep = schema_for!(Deep1);
|
||||
assert_eq!(flat, deep);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -8,13 +8,13 @@ pub type TestResult = Result<(), Box<dyn Error>>;
|
|||
|
||||
#[allow(dead_code)] // https://github.com/rust-lang/rust/issues/46379
|
||||
pub fn test_generated_schema<T: JsonSchema>(file: &str, settings: SchemaSettings) -> TestResult {
|
||||
let actual = settings.into_generator().into_root_schema_for::<T>()?;
|
||||
let actual = settings.into_generator().into_root_schema_for::<T>();
|
||||
test_schema(&actual, file)
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // https://github.com/rust-lang/rust/issues/46379
|
||||
pub fn test_default_generated_schema<T: JsonSchema>(file: &str) -> TestResult {
|
||||
let actual = schema_for!(T)?;
|
||||
let actual = schema_for!(T);
|
||||
test_schema(&actual, file)
|
||||
}
|
||||
|
||||
|
|
|
@ -71,8 +71,8 @@ pub fn derive_json_schema(input: proc_macro::TokenStream) -> proc_macro::TokenSt
|
|||
#schema_name
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::Result {
|
||||
Ok(#schema)
|
||||
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||
#schema
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -199,14 +199,14 @@ fn schema_for_internal_tagged_enum<'a>(
|
|||
let field = &variant.fields[0];
|
||||
let ty = get_json_schema_type(field);
|
||||
quote_spanned! {field.original.span()=>
|
||||
<#ty>::json_schema(gen)?
|
||||
<#ty>::json_schema(gen)
|
||||
}
|
||||
}
|
||||
Style::Struct => schema_for_struct(&variant.fields, cattrs),
|
||||
Style::Tuple => unreachable!("Internal tagged enum tuple variants will have caused serde_derive_internals to output a compile error already."),
|
||||
};
|
||||
quote! {
|
||||
#tag_schema.flatten(#variant_schema)?
|
||||
#tag_schema.flatten(#variant_schema)
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -243,14 +243,14 @@ fn schema_for_untagged_enum_variant(variant: &Variant, cattrs: &attr::Container)
|
|||
|
||||
fn schema_for_unit_struct() -> TokenStream {
|
||||
quote! {
|
||||
gen.subschema_for::<()>()?
|
||||
gen.subschema_for::<()>()
|
||||
}
|
||||
}
|
||||
|
||||
fn schema_for_newtype_struct(field: &Field) -> TokenStream {
|
||||
let ty = get_json_schema_type(field);
|
||||
quote_spanned! {field.original.span()=>
|
||||
gen.subschema_for::<#ty>()?
|
||||
gen.subschema_for::<#ty>()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,7 +260,7 @@ fn schema_for_tuple_struct(fields: &[Field]) -> TokenStream {
|
|||
.filter(|f| !f.attrs.skip_deserializing())
|
||||
.map(get_json_schema_type);
|
||||
quote! {
|
||||
gen.subschema_for::<(#(#types),*)>()?
|
||||
gen.subschema_for::<(#(#types),*)>()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,19 +281,19 @@ fn schema_for_struct(fields: &[Field], cattrs: &attr::Container) -> TokenStream
|
|||
|
||||
if field.attrs.skip_deserializing() {
|
||||
quote_spanned! {field.original.span()=>
|
||||
let mut schema: schemars::schema::SchemaObject = gen.subschema_for::<#ty>()?.into();
|
||||
let mut schema: schemars::schema::SchemaObject = gen.subschema_for::<#ty>().into();
|
||||
schema.metadata().read_only = true;
|
||||
props.insert(#name.to_owned(), schema.into());
|
||||
}
|
||||
} else if field.attrs.skip_serializing() {
|
||||
quote_spanned! {field.original.span()=>
|
||||
let mut schema: schemars::schema::SchemaObject = gen.subschema_for::<#ty>()?.into();
|
||||
let mut schema: schemars::schema::SchemaObject = gen.subschema_for::<#ty>().into();
|
||||
schema.metadata().write_only = true;
|
||||
props.insert(#name.to_owned(), schema.into());
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {field.original.span()=>
|
||||
props.insert(#name.to_owned(), gen.subschema_for::<#ty>()?);
|
||||
props.insert(#name.to_owned(), gen.subschema_for::<#ty>());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -318,7 +318,7 @@ fn schema_for_struct(fields: &[Field], cattrs: &attr::Container) -> TokenStream
|
|||
let flattens = flat.iter().map(|field| {
|
||||
let ty = get_json_schema_type(field);
|
||||
quote_spanned! {field.original.span()=>
|
||||
.flatten(<#ty>::json_schema_non_null(gen)?)?
|
||||
.flatten(<#ty>::json_schema_non_null(gen))
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue