use crate::*;
use std::cell::RefCell;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
#[derive(Clone, Debug, Default)]
pub struct SchemaBuilder {
deprecated: Option<String>,
description: Option<String>,
name: Option<String>,
name_stack: Rc<RefCell<Vec<String>>>,
ty: SchemaType,
nullable: bool,
}
impl SchemaBuilder {
pub fn generate<T: Schematic>() -> Schema {
Self::build_root::<T>()
}
pub fn build_root<T: Schematic>() -> Schema {
let mut builder = SchemaBuilder::default();
if let Some(name) = T::schema_name() {
builder.set_name(name);
}
T::build_schema(builder)
}
pub fn build(&mut self) -> Schema {
Schema {
deprecated: self.deprecated.take(),
description: self.description.take(),
name: self.name.take(),
nullable: self.nullable,
ty: mem::take(&mut self.ty),
}
}
pub fn set_deprecated(&mut self, value: impl AsRef<str>) {
self.deprecated = Some(value.as_ref().to_owned());
}
pub fn set_description(&mut self, value: impl AsRef<str>) {
self.description = Some(value.as_ref().to_owned());
}
pub fn set_name(&mut self, value: impl AsRef<str>) {
let name = value.as_ref();
self.name = Some(name.to_owned());
self.name_stack.borrow_mut().push(name.to_owned());
}
pub fn set_type(&mut self, value: SchemaType) {
self.ty = value;
}
pub fn set_type_and_build(&mut self, value: SchemaType) -> Schema {
self.set_type(value);
self.build()
}
pub fn array(&mut self, value: ArrayType) -> Schema {
self.set_type_and_build(SchemaType::Array(Box::new(value)))
}
pub fn boolean(&mut self, value: BooleanType) -> Schema {
self.set_type_and_build(SchemaType::Boolean(Box::new(value)))
}
pub fn boolean_default(&mut self) -> Schema {
self.boolean(BooleanType::default())
}
pub fn enumerable(&mut self, value: EnumType) -> Schema {
self.set_type_and_build(SchemaType::Enum(Box::new(value)))
}
pub fn float(&mut self, value: FloatType) -> Schema {
self.set_type_and_build(SchemaType::Float(Box::new(value)))
}
pub fn float32_default(&mut self) -> Schema {
self.float(FloatType::new_kind(FloatKind::F32))
}
pub fn float64_default(&mut self) -> Schema {
self.float(FloatType::new_kind(FloatKind::F64))
}
pub fn integer(&mut self, value: IntegerType) -> Schema {
self.set_type_and_build(SchemaType::Integer(Box::new(value)))
}
pub fn literal(&mut self, value: LiteralType) -> Schema {
self.set_type_and_build(SchemaType::Literal(Box::new(value)))
}
pub fn literal_value(&mut self, value: LiteralValue) -> Schema {
self.literal(LiteralType::new(value))
}
pub fn nest(&self) -> SchemaBuilder {
SchemaBuilder {
deprecated: None,
description: None,
name: None,
name_stack: Rc::clone(&self.name_stack),
ty: SchemaType::Unknown,
nullable: false,
}
}
pub fn nullable(&mut self, value: impl Into<Schema>) -> Schema {
self.union(UnionType::new_any([value.into(), Schema::null()]))
}
pub fn object(&mut self, value: ObjectType) -> Schema {
self.set_type_and_build(SchemaType::Object(Box::new(value)))
}
pub fn string(&mut self, value: StringType) -> Schema {
self.set_type_and_build(SchemaType::String(Box::new(value)))
}
pub fn string_default(&mut self) -> Schema {
self.string(StringType::default())
}
pub fn structure(&mut self, value: StructType) -> Schema {
self.set_type_and_build(SchemaType::Struct(Box::new(value)))
}
pub fn tuple(&mut self, value: TupleType) -> Schema {
self.set_type_and_build(SchemaType::Tuple(Box::new(value)))
}
pub fn union(&mut self, value: UnionType) -> Schema {
self.set_type_and_build(SchemaType::Union(Box::new(value)))
}
pub fn infer<T: Schematic>(&self) -> Schema {
let mut builder = self.nest();
let Some(name) = T::schema_name() else {
return T::build_schema(builder);
};
if self.name_stack.borrow().contains(&name) {
return builder.set_type_and_build(SchemaType::Reference(name));
}
builder.set_name(&name);
let schema = T::build_schema(builder);
self.name_stack.borrow_mut().pop();
schema
}
pub fn infer_as_nested<T: Schematic>(&self) -> Schema {
let mut schema = self.infer::<T>();
schema.partialize();
schema
}
pub fn infer_with_default<T: Schematic>(&self, default: LiteralValue) -> Schema {
let mut schema = self.infer::<T>();
schema.set_default(default);
schema
}
}
impl Deref for SchemaBuilder {
type Target = SchemaType;
fn deref(&self) -> &Self::Target {
&self.ty
}
}
impl DerefMut for SchemaBuilder {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.ty
}
}
impl From<SchemaBuilder> for Schema {
fn from(mut builder: SchemaBuilder) -> Self {
builder.build()
}
}