use openapiv3::{
ArrayType, NumberType, ReferenceOr, Schema, SchemaData, SchemaKind, StringType, Type,
};
use crate::*;
macro_rules! primitive_def {
($($t:ident)+) => {
$(DataType::Primitive(PrimitiveType::$t))|+
}
}
pub fn to_openapi(typ: &DataType) -> ReferenceOr<Schema> {
let mut schema_data = SchemaData {
nullable: false,
deprecated: false, example: None, title: None, description: None, default: None, ..Default::default()
};
match &typ {
DataType::Any => ReferenceOr::Item(Schema {
schema_data,
schema_kind: SchemaKind::Type(Type::Object(openapiv3::ObjectType::default())), }),
primitive_def!(i8 i16 i32 isize u8 u16 u32 usize f32 f64) => ReferenceOr::Item(Schema {
schema_data,
schema_kind: SchemaKind::Type(Type::Number(NumberType::default())), }),
primitive_def!(i64 u64 i128 u128) => ReferenceOr::Item(Schema {
schema_data,
schema_kind: SchemaKind::Type(Type::Number(NumberType::default())), }),
primitive_def!(String char) => ReferenceOr::Item(Schema {
schema_data,
schema_kind: SchemaKind::Type(Type::String(StringType::default())), }),
primitive_def!(bool) => ReferenceOr::Item(Schema {
schema_data,
schema_kind: SchemaKind::Type(Type::Boolean {}),
}),
DataType::Nullable(def) => {
let schema = to_openapi(def);
schema
}
DataType::List(def) => ReferenceOr::Item(Schema {
schema_data,
schema_kind: SchemaKind::Type(Type::Array(ArrayType {
items: Some(match to_openapi(def) {
ReferenceOr::Item(schema) => ReferenceOr::Item(Box::new(schema)),
ReferenceOr::Reference { reference } => ReferenceOr::Reference { reference },
}),
min_items: None,
max_items: None,
unique_items: false,
})),
}),
DataType::Tuple(TupleType { fields, .. }) => match &fields[..] {
[] => {
schema_data.nullable = true;
ReferenceOr::Item(Schema {
schema_data,
schema_kind: SchemaKind::Type(Type::Object(openapiv3::ObjectType::default())), })
}
[ty] => to_openapi(ty),
tys => todo!(),
},
DataType::Struct(StructType {
fields, tag, name, ..
}) => match &fields[..] {
[] => todo!(), fields => {
ReferenceOr::Item(Schema {
schema_data,
schema_kind: SchemaKind::Type(Type::Object(openapiv3::ObjectType {
properties: fields
.iter()
.map(
|ObjectField {
name, ty, optional, ..
}| {
(
name.clone(),
match to_openapi(ty) {
ReferenceOr::Item(v) => ReferenceOr::Item(Box::new(v)),
ReferenceOr::Reference { reference } => {
ReferenceOr::Reference { reference }
}
},
)
},
)
.collect(),
..Default::default()
})),
})
}
},
DataType::Enum(EnumType { variants, repr, .. }) => match &variants[..] {
[] => todo!(), variants => {
ReferenceOr::Item(Schema {
schema_data,
schema_kind: SchemaKind::AnyOf {
any_of: variants
.iter()
.map(|variant| match variant {
EnumVariant::Unit(_) => ReferenceOr::Item(Schema {
schema_data: Default::default(),
schema_kind: SchemaKind::Type(Type::Object(
openapiv3::ObjectType::default(), )),
}),
EnumVariant::Unnamed(tuple) => {
to_openapi(&DataType::Tuple(tuple.clone()))
}
EnumVariant::Named(obj) => {
to_openapi(&DataType::Struct(obj.clone()))
}
})
.collect(),
},
})
}
},
DataType::Reference { name, generics, .. } => match &generics[..] {
[] => ReferenceOr::Item(Schema {
schema_data,
schema_kind: SchemaKind::OneOf {
one_of: vec![ReferenceOr::Reference {
reference: format!("#/components/schemas/{}", name),
}],
},
}),
generics => {
todo!();
}
},
x => {
println!("{:?} {:?}", x, typ);
todo!();
}
}
}