use core::fmt;
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "derive", derive(ron2_derive::FromRon, ron2_derive::ToRon))]
pub struct Schema {
#[cfg_attr(
feature = "derive",
ron(default, skip_serializing_if = "Option::is_none")
)]
pub doc: Option<String>,
pub kind: TypeKind,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "derive", derive(ron2_derive::FromRon, ron2_derive::ToRon))]
pub enum TypeKind {
Bool,
I8,
I16,
I32,
I64,
I128,
U8,
U16,
U32,
U64,
U128,
F32,
F64,
Char,
String,
Unit,
Option(Box<TypeKind>),
List(Box<TypeKind>),
Map {
key: Box<TypeKind>,
value: Box<TypeKind>,
},
Tuple(Vec<TypeKind>),
Struct {
fields: Vec<Field>,
},
Enum {
variants: Vec<Variant>,
},
TypeRef(String),
}
impl TypeKind {
#[must_use]
pub fn inner_type(&self) -> Option<&TypeKind> {
match self {
TypeKind::Option(inner) | TypeKind::List(inner) => Some(inner),
_ => None,
}
}
#[must_use]
pub fn map_types(&self) -> Option<(&TypeKind, &TypeKind)> {
match self {
TypeKind::Map { key, value } => Some((key, value)),
_ => None,
}
}
#[must_use]
pub fn tuple_types(&self) -> Option<&[TypeKind]> {
match self {
TypeKind::Tuple(types) => Some(types),
_ => None,
}
}
#[must_use]
pub fn struct_fields(&self) -> Option<&[Field]> {
match self {
TypeKind::Struct { fields } => Some(fields),
_ => None,
}
}
#[must_use]
pub fn enum_variants(&self) -> Option<&[Variant]> {
match self {
TypeKind::Enum { variants } => Some(variants),
_ => None,
}
}
#[must_use]
pub fn type_ref_path(&self) -> Option<&str> {
match self {
TypeKind::TypeRef(path) => Some(path),
_ => None,
}
}
#[must_use]
pub fn is_primitive(&self) -> bool {
matches!(
self,
TypeKind::Bool
| TypeKind::I8
| TypeKind::I16
| TypeKind::I32
| TypeKind::I64
| TypeKind::I128
| TypeKind::U8
| TypeKind::U16
| TypeKind::U32
| TypeKind::U64
| TypeKind::U128
| TypeKind::F32
| TypeKind::F64
| TypeKind::Char
| TypeKind::String
| TypeKind::Unit
)
}
}
impl fmt::Display for TypeKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TypeKind::Bool => write!(f, "bool"),
TypeKind::I8 => write!(f, "i8"),
TypeKind::I16 => write!(f, "i16"),
TypeKind::I32 => write!(f, "i32"),
TypeKind::I64 => write!(f, "i64"),
TypeKind::I128 => write!(f, "i128"),
TypeKind::U8 => write!(f, "u8"),
TypeKind::U16 => write!(f, "u16"),
TypeKind::U32 => write!(f, "u32"),
TypeKind::U64 => write!(f, "u64"),
TypeKind::U128 => write!(f, "u128"),
TypeKind::F32 => write!(f, "f32"),
TypeKind::F64 => write!(f, "f64"),
TypeKind::Char => write!(f, "char"),
TypeKind::String => write!(f, "String"),
TypeKind::Unit => write!(f, "()"),
TypeKind::Option(inner) => write!(f, "Option<{inner}>"),
TypeKind::List(inner) => write!(f, "List<{inner}>"),
TypeKind::Map { key, value } => write!(f, "Map<{key}, {value}>"),
TypeKind::Tuple(types) => {
write!(f, "(")?;
for (i, ty) in types.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{ty}")?;
}
write!(f, ")")
}
TypeKind::Struct { .. } => write!(f, "Struct"),
TypeKind::Enum { .. } => write!(f, "Enum"),
TypeKind::TypeRef(path) => write!(f, "{path}"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "derive", derive(ron2_derive::FromRon, ron2_derive::ToRon))]
pub struct Field {
pub name: String,
pub ty: TypeKind,
#[cfg_attr(
feature = "derive",
ron(default, skip_serializing_if = "Option::is_none")
)]
pub doc: Option<String>,
#[cfg_attr(
feature = "derive",
ron(default, skip_serializing_if = "std::ops::Not::not")
)]
pub optional: bool,
#[cfg_attr(
feature = "derive",
ron(default, skip_serializing_if = "std::ops::Not::not")
)]
pub flattened: bool,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "derive", derive(ron2_derive::FromRon, ron2_derive::ToRon))]
pub struct Variant {
pub name: String,
#[cfg_attr(
feature = "derive",
ron(default, skip_serializing_if = "Option::is_none")
)]
pub doc: Option<String>,
pub kind: VariantKind,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "derive", derive(ron2_derive::FromRon, ron2_derive::ToRon))]
pub enum VariantKind {
Unit,
Tuple(Vec<TypeKind>),
Struct(Vec<Field>),
}
impl Schema {
#[must_use]
pub fn new(kind: TypeKind) -> Self {
Self { doc: None, kind }
}
#[must_use]
pub fn with_doc(doc: impl Into<String>, kind: TypeKind) -> Self {
Self {
doc: Some(doc.into()),
kind,
}
}
}
impl Field {
#[must_use]
pub fn new(name: impl Into<String>, ty: TypeKind) -> Self {
Self {
name: name.into(),
ty,
doc: None,
optional: false,
flattened: false,
}
}
#[must_use]
pub fn optional(name: impl Into<String>, ty: TypeKind) -> Self {
Self {
name: name.into(),
ty,
doc: None,
optional: true,
flattened: false,
}
}
#[must_use]
pub fn flattened(name: impl Into<String>, ty: TypeKind) -> Self {
Self {
name: name.into(),
ty,
doc: None,
optional: false,
flattened: true,
}
}
#[must_use]
pub fn with_doc(mut self, doc: impl Into<String>) -> Self {
self.doc = Some(doc.into());
self
}
#[must_use]
pub fn with_flatten(mut self) -> Self {
self.flattened = true;
self
}
}
impl Variant {
#[must_use]
pub fn unit(name: impl Into<String>) -> Self {
Self {
name: name.into(),
doc: None,
kind: VariantKind::Unit,
}
}
#[must_use]
pub fn tuple(name: impl Into<String>, fields: Vec<TypeKind>) -> Self {
Self {
name: name.into(),
doc: None,
kind: VariantKind::Tuple(fields),
}
}
#[must_use]
pub fn struct_variant(name: impl Into<String>, fields: Vec<Field>) -> Self {
Self {
name: name.into(),
doc: None,
kind: VariantKind::Struct(fields),
}
}
#[must_use]
pub fn with_doc(mut self, doc: impl Into<String>) -> Self {
self.doc = Some(doc.into());
self
}
}