mod internal;
mod rename;
#[cfg(feature = "glob")]
pub use self::rename::Glob;
#[cfg(feature = "glob")]
pub use glob::PatternError;
pub use self::rename::*;
use std::{collections::HashMap, ops::Index};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Schema {
pub name: String,
#[serde(skip_serializing_if = "String::is_empty", default)]
pub description: String,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub functions: Vec<Function>,
#[serde(skip_serializing_if = "Typespace::is_empty", default)]
pub input_types: Typespace,
#[serde(skip_serializing_if = "Typespace::is_empty", default)]
pub output_types: Typespace,
}
impl Default for Schema {
fn default() -> Self {
Self::new()
}
}
impl Schema {
pub fn new() -> Self {
Schema {
name: String::new(),
description: String::new(),
functions: Vec::new(),
input_types: Typespace::new(),
output_types: Typespace::new(),
}
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn description(&self) -> &str {
self.description.as_str()
}
pub fn functions(&self) -> std::slice::Iter<Function> {
self.functions.iter()
}
pub fn input_types(&self) -> &Typespace {
&self.input_types
}
pub fn is_input_type(&self, name: &str) -> bool {
self.input_types.has_type(name)
}
pub fn output_types(&self) -> &Typespace {
&self.output_types
}
pub fn is_output_type(&self, name: &str) -> bool {
self.output_types.has_type(name)
}
pub fn extend(&mut self, other: Self) {
let Self {
functions,
input_types,
output_types,
..
} = other;
self.functions.extend(functions);
self.input_types.extend(input_types);
self.output_types.extend(output_types);
}
pub fn prepend_path(&mut self, path: &str) {
if path.is_empty() {
return;
}
for function in self.functions.iter_mut() {
function.path = format!("{}{}", path, function.path);
}
}
pub fn consolidate_types(&mut self) -> Vec<String> {
loop {
let mut all_types = std::collections::HashSet::new();
let mut colliding_types = std::collections::HashSet::new();
let mut colliging_non_equal_types = std::collections::HashSet::new();
for input_type in self.input_types.types() {
all_types.insert(input_type.name().to_string());
if let Some(output_type) = self.output_types.get_type(input_type.name()) {
colliding_types.insert(input_type.name().to_string());
if input_type != output_type {
colliging_non_equal_types.insert(input_type.name().to_string());
}
}
}
for output_type in self.output_types.types() {
all_types.insert(output_type.name().to_string());
if let Some(input_type) = self.input_types.get_type(output_type.name()) {
colliding_types.insert(output_type.name().to_string());
if input_type != output_type {
colliging_non_equal_types.insert(output_type.name().to_string());
}
}
}
if colliging_non_equal_types.is_empty() {
let mut r: Vec<_> = all_types.into_iter().collect();
r.sort();
return r;
}
for type_name in colliging_non_equal_types.iter() {
let mut type_name_parts = type_name.split("::").collect::<Vec<_>>();
type_name_parts.insert(type_name_parts.len() - 1, "input");
self.rename_input_types(type_name.as_str(), &type_name_parts.join("::"));
let mut type_name_parts = type_name.split("::").collect::<Vec<_>>();
type_name_parts.insert(type_name_parts.len() - 1, "output");
self.rename_output_types(type_name.as_str(), &type_name_parts.join("::"));
}
}
}
pub fn get_type(&self, name: &str) -> Option<&Type> {
if let Some(t) = self.input_types.get_type(name) {
return Some(t);
}
if let Some(t) = self.output_types.get_type(name) {
return Some(t);
}
None
}
#[cfg(feature = "glob")]
pub fn glob_rename_types(
&mut self,
glob: &str,
replacer: &str,
) -> Result<(), glob::PatternError> {
let matcher = glob.parse::<Glob>()?;
self.rename_types(&matcher, replacer);
Ok(())
}
pub fn rename_types(&mut self, matcher: impl Pattern, replacer: &str) -> usize {
self.rename_input_types(matcher, replacer) + self.rename_output_types(matcher, replacer)
}
pub fn rename_input_types(&mut self, matcher: impl Pattern, replacer: &str) -> usize {
self.input_types.rename_types(matcher, replacer)
+ self
.functions
.iter_mut()
.map(|f| f.rename_input_types(matcher, replacer))
.sum::<usize>()
}
pub fn rename_output_types(&mut self, matcher: impl Pattern, replacer: &str) -> usize {
self.output_types.rename_types(matcher, replacer)
+ self
.functions
.iter_mut()
.map(|f| f.rename_output_types(matcher, replacer))
.sum::<usize>()
}
pub fn fold_transparent_types(&mut self) {
let transparent_types = self
.input_types()
.types()
.filter_map(|t| {
t.as_struct()
.filter(|i| i.transparent && i.fields.len() == 1)
.map(|s| (s.name.clone(), s.fields[0].type_ref.name.clone()))
})
.collect::<Vec<_>>();
for (from, to) in transparent_types {
self.input_types.remove_type(&from);
self.rename_input_types(from.as_str(), &to);
}
let transparent_types = self
.output_types()
.types()
.filter_map(|t| {
t.as_struct()
.filter(|i| i.transparent && i.fields.len() == 1)
.map(|s| (s.name.clone(), s.fields[0].type_ref.name.clone()))
})
.collect::<Vec<_>>();
for (from, to) in transparent_types {
self.output_types.remove_type(&from);
self.rename_output_types(from.as_str(), &to);
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
pub struct Typespace {
#[serde(skip_serializing_if = "Vec::is_empty", default)]
types: Vec<Type>,
#[serde(skip_serializing, default)]
types_map: std::cell::RefCell<HashMap<String, usize>>,
}
impl Typespace {
pub fn new() -> Self {
Typespace {
types: Vec::new(),
types_map: std::cell::RefCell::new(HashMap::new()),
}
}
pub fn is_empty(&self) -> bool {
self.types.is_empty()
}
pub fn types(&self) -> std::slice::Iter<Type> {
self.types.iter()
}
pub fn get_type(&self, name: &str) -> Option<&Type> {
self.ensure_types_map();
let index = {
let b = self.types_map.borrow();
b.get(name).copied().unwrap_or(usize::MAX)
};
if index == usize::MAX {
return None;
}
self.types.get(index)
}
pub fn reserve_type(&mut self, name: &str) -> bool {
self.ensure_types_map();
if self.types_map.borrow().contains_key(name) {
return false;
}
self.types_map.borrow_mut().insert(name.into(), usize::MAX);
true
}
pub fn insert_type(&mut self, ty: Type) {
self.ensure_types_map();
if let Some(index) = self.types_map.borrow().get(ty.name()) {
if index != &usize::MAX {
return;
}
}
self.types_map
.borrow_mut()
.insert(ty.name().into(), self.types.len());
self.types.push(ty);
}
pub fn remove_type(&mut self, ty: &str) -> Option<Type> {
self.ensure_types_map();
let index = self
.types_map
.borrow()
.get(ty)
.copied()
.unwrap_or(usize::MAX);
if index == usize::MAX {
return None;
}
self.types_map.borrow_mut().remove(ty);
Some(self.types.remove(index))
}
fn rename_types(&mut self, pattern: impl Pattern, replacer: &str) -> usize {
self.invalidate_types_map();
self.types
.iter_mut()
.map(|ty| ty.rename(pattern, replacer))
.sum()
}
pub fn sort_types(&mut self) {
self.types.sort_by(|a, b| a.name().cmp(b.name()));
self.build_types_map();
}
pub fn has_type(&self, name: &str) -> bool {
self.ensure_types_map();
self.types_map.borrow().contains_key(name)
}
pub fn extend(&mut self, other: Self) {
self.ensure_types_map();
for ty in other.types {
if self.has_type(ty.name()) {
continue;
}
self.insert_type(ty);
}
}
fn invalidate_types_map(&self) {
*(self.types_map.borrow_mut()) = HashMap::new();
}
fn ensure_types_map(&self) {
if self.types_map.borrow().is_empty() && !self.types.is_empty() {
self.build_types_map();
}
}
fn build_types_map(&self) {
let mut types_map = HashMap::new();
for (i, ty) in self.types.iter().enumerate() {
types_map.insert(ty.name().into(), i);
}
*(self.types_map.borrow_mut()) = types_map;
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Function {
pub name: String,
pub path: String,
#[serde(skip_serializing_if = "String::is_empty", default)]
pub description: String,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub input_type: Option<TypeReference>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub input_headers: Option<TypeReference>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub output_type: Option<TypeReference>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub error_type: Option<TypeReference>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub serialization: Vec<SerializationMode>,
#[serde(skip_serializing_if = "is_false", default)]
pub readonly: bool,
}
impl Function {
pub fn new(name: String) -> Self {
Function {
name,
path: String::new(),
description: String::new(),
input_type: None,
input_headers: None,
output_type: None,
error_type: None,
serialization: Vec::new(),
readonly: false,
}
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn path(&self) -> &str {
self.path.as_str()
}
pub fn description(&self) -> &str {
self.description.as_str()
}
pub fn input_type(&self) -> Option<&TypeReference> {
self.input_type.as_ref()
}
pub fn input_headers(&self) -> Option<&TypeReference> {
self.input_headers.as_ref()
}
pub fn output_type(&self) -> Option<&TypeReference> {
self.output_type.as_ref()
}
pub fn error_type(&self) -> Option<&TypeReference> {
self.error_type.as_ref()
}
pub fn serialization(&self) -> std::slice::Iter<SerializationMode> {
self.serialization.iter()
}
pub fn readonly(&self) -> bool {
self.readonly
}
fn rename_input_types(&mut self, matcher: impl Pattern, replacer: &str) -> usize {
let mut count = 0;
if let Some(input_type) = &mut self.input_type {
count += input_type.rename(matcher, replacer);
}
if let Some(input_headers) = &mut self.input_headers {
count += input_headers.rename(matcher, replacer);
}
count
}
fn rename_output_types(&mut self, matcher: impl Pattern, replacer: &str) -> usize {
let mut count = 0;
if let Some(output_type) = &mut self.output_type {
count += output_type.rename(matcher, replacer);
}
if let Some(error_type) = &mut self.error_type {
count += error_type.rename(matcher, replacer);
}
count
}
}
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SerializationMode {
#[default]
Json,
Msgpack,
}
#[derive(
Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord,
)]
pub struct TypeReference {
pub name: String,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub arguments: Vec<TypeReference>,
}
impl TypeReference {
pub fn new(name: String, arguments: Vec<TypeReference>) -> Self {
TypeReference { name, arguments }
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn arguments(&self) -> std::slice::Iter<TypeReference> {
self.arguments.iter()
}
pub fn fallback_recursively(&mut self, schema: &Typespace) {
loop {
let Some(type_def) = schema.get_type(self.name()) else {
return;
};
let Some(fallback_type_ref) = type_def.fallback_internal(self) else {
return;
};
*self = fallback_type_ref;
}
}
pub fn fallback_once(&self, schema: &Typespace) -> Option<TypeReference> {
let type_def = schema.get_type(self.name())?;
type_def.fallback_internal(self)
}
fn rename(&mut self, pattern: impl Pattern, replacer: &str) -> usize {
pattern.rename(&self.name, replacer).map_or(0, |new_name| {
self.name = new_name;
1
}) + self
.arguments
.iter_mut()
.map(|arg| arg.rename(pattern, replacer))
.sum::<usize>()
}
}
impl From<&str> for TypeReference {
fn from(name: &str) -> Self {
TypeReference::new(name.into(), Vec::new())
}
}
impl From<String> for TypeReference {
fn from(name: String) -> Self {
TypeReference::new(name, Vec::new())
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TypeParameter {
pub name: String,
#[serde(skip_serializing_if = "String::is_empty", default)]
pub description: String,
}
impl TypeParameter {
pub fn new(name: String, description: String) -> Self {
TypeParameter { name, description }
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn description(&self) -> &str {
self.description.as_str()
}
}
impl From<&str> for TypeParameter {
fn from(name: &str) -> Self {
TypeParameter {
name: name.into(),
description: String::new(),
}
}
}
impl From<String> for TypeParameter {
fn from(name: String) -> Self {
TypeParameter {
name,
description: String::new(),
}
}
}
impl PartialEq for TypeParameter {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl Eq for TypeParameter {}
impl std::hash::Hash for TypeParameter {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
#[serde(rename_all = "snake_case", tag = "kind")]
pub enum Type {
Primitive(Primitive),
Struct(Struct),
Enum(Enum),
}
impl Type {
pub fn name(&self) -> &str {
match self {
Type::Primitive(p) => &p.name,
Type::Struct(s) => &s.name,
Type::Enum(e) => &e.name,
}
}
pub fn serde_name(&self) -> &str {
match self {
Type::Primitive(_) => self.name(),
Type::Struct(s) => s.serde_name(),
Type::Enum(e) => e.serde_name(),
}
}
pub fn description(&self) -> &str {
match self {
Type::Primitive(p) => &p.description,
Type::Struct(s) => &s.description,
Type::Enum(e) => &e.description,
}
}
pub fn parameters(&self) -> std::slice::Iter<TypeParameter> {
match self {
Type::Primitive(p) => p.parameters(),
Type::Struct(s) => s.parameters(),
Type::Enum(e) => e.parameters(),
}
}
pub fn as_struct(&self) -> Option<&Struct> {
match self {
Type::Struct(s) => Some(s),
_ => None,
}
}
pub fn is_struct(&self) -> bool {
matches!(self, Type::Struct(_))
}
pub fn as_enum(&self) -> Option<&Enum> {
match self {
Type::Enum(e) => Some(e),
_ => None,
}
}
pub fn is_enum(&self) -> bool {
matches!(self, Type::Enum(_))
}
pub fn as_primitive(&self) -> Option<&Primitive> {
match self {
Type::Primitive(p) => Some(p),
_ => None,
}
}
pub fn is_primitive(&self) -> bool {
matches!(self, Type::Primitive(_))
}
fn fallback_internal(&self, origin: &TypeReference) -> Option<TypeReference> {
match self {
Type::Primitive(p) => p.fallback_internal(origin),
Type::Struct(_) => None,
Type::Enum(_) => None,
}
}
fn rename(&mut self, matcher: impl Pattern, replacer: &str) -> usize {
match self {
Type::Primitive(p) => p.rename(matcher, replacer),
Type::Struct(s) => s.rename(matcher, replacer),
Type::Enum(e) => e.rename(matcher, replacer),
}
}
pub fn __internal_rename_current(&mut self, new_name: String) {
match self {
Type::Primitive(p) => p.name = new_name,
Type::Struct(s) => s.name = new_name,
Type::Enum(e) => e.name = new_name,
}
}
pub fn __internal_rebind_generic_parameters(
&mut self,
unresolved_to_resolved_map: &std::collections::HashMap<TypeReference, TypeReference>,
schema: &Typespace,
) {
internal::replace_type_references_for_type(self, unresolved_to_resolved_map, schema)
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
pub struct Primitive {
pub name: String,
#[serde(skip_serializing_if = "String::is_empty", default)]
pub description: String,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub parameters: Vec<TypeParameter>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub fallback: Option<TypeReference>,
}
impl Primitive {
pub fn new(
name: String,
description: String,
parameters: Vec<TypeParameter>,
fallback: Option<TypeReference>,
) -> Self {
Primitive {
name,
description,
parameters,
fallback,
}
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn description(&self) -> &str {
self.description.as_str()
}
pub fn parameters(&self) -> std::slice::Iter<TypeParameter> {
self.parameters.iter()
}
pub fn fallback(&self) -> Option<&TypeReference> {
self.fallback.as_ref()
}
fn fallback_internal(&self, origin: &TypeReference) -> Option<TypeReference> {
let fallback = self.fallback.as_ref()?;
if let Some((type_def_param_index, _)) = self
.parameters()
.enumerate()
.find(|(_, type_def_param)| type_def_param.name() == fallback.name())
{
let Some(origin_type_ref_param) = origin.arguments.get(type_def_param_index) else {
return None;
};
return Some(TypeReference {
name: origin_type_ref_param.name.clone(),
arguments: origin_type_ref_param.arguments.clone(),
});
}
let mut new_arguments_for_origin = Vec::new();
for fallback_type_ref_param in fallback.arguments() {
let Some((type_def_param_index, _)) =
self.parameters().enumerate().find(|(_, type_def_param)| {
type_def_param.name() == fallback_type_ref_param.name()
})
else {
continue;
};
let Some(origin_type_ref_param) = origin.arguments.get(type_def_param_index) else {
return None;
};
new_arguments_for_origin.push(origin_type_ref_param.clone());
}
Some(TypeReference {
name: fallback.name.clone(),
arguments: new_arguments_for_origin,
})
}
fn rename(&mut self, pattern: impl Pattern, replacer: &str) -> usize {
pattern.rename(&self.name, replacer).map_or(0, |new_name| {
self.name = new_name;
1
})
}
}
impl From<Primitive> for Type {
fn from(val: Primitive) -> Self {
Type::Primitive(val)
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
pub struct Struct {
pub name: String,
#[serde(skip_serializing_if = "String::is_empty", default)]
pub serde_name: String,
#[serde(skip_serializing_if = "String::is_empty", default)]
pub description: String,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub parameters: Vec<TypeParameter>,
pub fields: Fields,
#[serde(skip_serializing_if = "is_false", default)]
pub transparent: bool,
}
impl Struct {
pub fn new(name: String) -> Self {
Struct {
name,
serde_name: String::new(),
description: String::new(),
parameters: Vec::new(),
fields: Fields::None,
transparent: false,
}
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn serde_name(&self) -> &str {
if self.serde_name.is_empty() {
self.name.as_str()
} else {
self.serde_name.as_str()
}
}
pub fn description(&self) -> &str {
self.description.as_str()
}
pub fn parameters(&self) -> std::slice::Iter<TypeParameter> {
self.parameters.iter()
}
pub fn fields(&self) -> std::slice::Iter<Field> {
self.fields.iter()
}
pub fn transparent(&self) -> bool {
self.transparent
}
pub fn is_alias(&self) -> bool {
self.fields.len() == 1 && (self.fields[0].name() == "0" || self.transparent)
}
pub fn is_unit(&self) -> bool {
let Some(first_field) = self.fields.iter().next() else {
return false;
};
self.fields.len() == 1
&& first_field.name() == "0"
&& first_field.type_ref.name == "std::tuple::Tuple0"
&& !first_field.required
}
pub fn is_tuple(&self) -> bool {
!self.fields.is_empty()
&& self
.fields
.iter()
.all(|f| f.name().parse::<usize>().is_ok())
}
fn rename(&mut self, pattern: impl Pattern, replacer: &str) -> usize {
pattern.rename(&self.name, replacer).map_or(0, |new_name| {
self.name = new_name;
1
}) + self
.fields
.iter_mut()
.map(|f| f.rename(pattern, replacer))
.sum::<usize>()
}
}
impl From<Struct> for Type {
fn from(val: Struct) -> Self {
Type::Struct(val)
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum Fields {
Named(Vec<Field>),
Unnamed(Vec<Field>),
None,
}
impl Fields {
pub fn is_empty(&self) -> bool {
match self {
Fields::Named(fields) | Fields::Unnamed(fields) => fields.is_empty(),
Fields::None => true,
}
}
pub fn len(&self) -> usize {
match self {
Fields::Named(fields) | Fields::Unnamed(fields) => fields.len(),
Fields::None => 0,
}
}
pub fn iter(&self) -> std::slice::Iter<Field> {
match self {
Fields::Named(fields) | Fields::Unnamed(fields) => fields.iter(),
Fields::None => [].iter(),
}
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<Field> {
match self {
Fields::Named(fields) | Fields::Unnamed(fields) => fields.iter_mut(),
Fields::None => [].iter_mut(),
}
}
}
impl Index<usize> for Fields {
type Output = Field;
fn index(&self, index: usize) -> &Self::Output {
match self {
Fields::Named(fields) | Fields::Unnamed(fields) => &fields[index],
Fields::None => panic!("index out of bounds"),
}
}
}
impl IntoIterator for Fields {
type Item = Field;
type IntoIter = std::vec::IntoIter<Field>;
fn into_iter(self) -> Self::IntoIter {
match self {
Fields::Named(fields) => fields.into_iter(),
Fields::Unnamed(fields) => fields.into_iter(),
Fields::None => vec![].into_iter(),
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
pub struct Field {
pub name: String,
#[serde(skip_serializing_if = "String::is_empty", default)]
pub serde_name: String,
#[serde(skip_serializing_if = "String::is_empty", default)]
pub description: String,
#[serde(rename = "type")]
pub type_ref: TypeReference,
#[serde(skip_serializing_if = "is_false", default)]
pub required: bool,
#[serde(skip_serializing_if = "is_false", default)]
pub flattened: bool,
#[serde(skip, default)]
pub transform_callback: String,
#[serde(skip, default)]
pub transform_callback_fn: Option<fn(&mut TypeReference, &Typespace) -> ()>,
}
impl Field {
pub fn new(name: String, ty: TypeReference) -> Self {
Field {
name,
serde_name: String::new(),
description: String::new(),
type_ref: ty,
required: false,
flattened: false,
transform_callback: String::new(),
transform_callback_fn: None,
}
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn is_named(&self) -> bool {
!self.is_unnamed()
}
pub fn is_unnamed(&self) -> bool {
self.name.parse::<u64>().is_ok()
}
pub fn serde_name(&self) -> &str {
if self.serde_name.is_empty() {
self.name.as_str()
} else {
self.serde_name.as_str()
}
}
pub fn description(&self) -> &str {
self.description.as_str()
}
pub fn type_ref(&self) -> &TypeReference {
&self.type_ref
}
pub fn required(&self) -> bool {
self.required
}
pub fn flattened(&self) -> bool {
self.flattened
}
pub fn transform_callback(&self) -> &str {
self.transform_callback.as_str()
}
pub fn transform_callback_fn(&self) -> Option<fn(&mut TypeReference, &Typespace)> {
self.transform_callback_fn
}
fn rename(&mut self, pattern: impl Pattern, replacer: &str) -> usize {
self.type_ref.rename(pattern, replacer)
}
}
fn is_false(b: &bool) -> bool {
!*b
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
pub struct Enum {
pub name: String,
#[serde(skip_serializing_if = "String::is_empty", default)]
pub serde_name: String,
#[serde(skip_serializing_if = "String::is_empty", default)]
pub description: String,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub parameters: Vec<TypeParameter>,
#[serde(skip_serializing_if = "Representation::is_default", default)]
pub representation: Representation,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub variants: Vec<Variant>,
}
impl Enum {
pub fn new(name: String) -> Self {
Enum {
name,
serde_name: String::new(),
description: String::new(),
parameters: Vec::new(),
representation: Default::default(),
variants: Vec::new(),
}
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn serde_name(&self) -> &str {
if self.serde_name.is_empty() {
self.name.as_str()
} else {
self.serde_name.as_str()
}
}
pub fn description(&self) -> &str {
self.description.as_str()
}
pub fn parameters(&self) -> std::slice::Iter<TypeParameter> {
self.parameters.iter()
}
pub fn representation(&self) -> &Representation {
&self.representation
}
pub fn variants(&self) -> std::slice::Iter<Variant> {
self.variants.iter()
}
fn rename(&mut self, pattern: impl Pattern, replacer: &str) -> usize {
pattern.rename(&self.name, replacer).map_or(0, |new_name| {
self.name = new_name;
1
}) + self
.variants
.iter_mut()
.map(|v| v.rename(pattern, replacer))
.sum::<usize>()
}
}
impl From<Enum> for Type {
fn from(val: Enum) -> Self {
Type::Enum(val)
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
pub struct Variant {
pub name: String,
#[serde(skip_serializing_if = "String::is_empty", default)]
pub serde_name: String,
#[serde(skip_serializing_if = "String::is_empty", default)]
pub description: String,
pub fields: Fields,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub discriminant: Option<isize>,
#[serde(skip_serializing_if = "is_false", default)]
pub untagged: bool,
}
impl Variant {
pub fn new(name: String) -> Self {
Variant {
name,
serde_name: String::new(),
description: String::new(),
fields: Fields::None,
discriminant: None,
untagged: false,
}
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn serde_name(&self) -> &str {
if self.serde_name.is_empty() {
self.name.as_str()
} else {
self.serde_name.as_str()
}
}
pub fn description(&self) -> &str {
self.description.as_str()
}
pub fn fields(&self) -> std::slice::Iter<Field> {
self.fields.iter()
}
pub fn discriminant(&self) -> Option<isize> {
self.discriminant
}
pub fn untagged(&self) -> bool {
self.untagged
}
fn rename(&mut self, pattern: impl Pattern, replacer: &str) -> usize {
self.fields
.iter_mut()
.map(|f| f.rename(pattern, replacer))
.sum::<usize>()
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash, Default)]
#[serde(rename_all = "snake_case")]
pub enum Representation {
#[default]
External,
Internal { tag: String },
Adjacent { tag: String, content: String },
None,
}
impl Representation {
pub fn new() -> Self {
Default::default()
}
pub fn is_default(&self) -> bool {
matches!(self, Representation::External)
}
pub fn is_external(&self) -> bool {
matches!(self, Representation::External)
}
pub fn is_internal(&self) -> bool {
matches!(self, Representation::Internal { .. })
}
pub fn is_adjacent(&self) -> bool {
matches!(self, Representation::Adjacent { .. })
}
pub fn is_none(&self) -> bool {
matches!(self, Representation::None)
}
}