use serde::{Deserialize, Serialize};
use std::{
collections::{HashMap, HashSet},
hash::{Hash, Hasher},
};
fn is_false(value: &bool) -> bool {
!value
}
#[derive(Debug, Serialize, Deserialize)]
pub struct IgniteTypeDefinition {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub namespace: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub generic_args: Vec<String>,
pub variant: IgniteTypeVariant,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub meta: HashMap<String, IgniteAttribMeta>,
#[serde(default, skip_serializing_if = "is_false")]
pub is_proxy: bool,
}
impl IgniteTypeDefinition {
pub fn name(&self) -> String {
self.variant.name()
}
pub fn referenced(&self) -> HashSet<String> {
self.variant.referenced()
}
}
impl Hash for IgniteTypeDefinition {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.namespace.hash(state);
self.generic_args.hash(state);
self.variant.hash(state);
}
}
#[derive(Debug, Serialize, Deserialize, Hash)]
pub enum IgniteTypeVariant {
StructUnit(String),
StructNamed(IgniteNamed),
StructUnnamed(IgniteUnnamed),
Enum(IgniteEnum),
}
impl IgniteTypeVariant {
pub fn name(&self) -> String {
match self {
Self::StructUnit(name) => name.clone(),
Self::StructNamed(value) => value.name.clone(),
Self::StructUnnamed(value) => value.name.clone(),
Self::Enum(value) => value.name.clone(),
}
}
pub fn referenced(&self) -> HashSet<String> {
match self {
Self::StructUnit(_) => HashSet::new(),
Self::StructNamed(value) => value.referenced(),
Self::StructUnnamed(value) => value.referenced(),
Self::Enum(value) => value.referenced(),
}
}
}
#[derive(Debug, Serialize, Deserialize, Hash)]
pub struct IgniteNamed {
pub name: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub fields: Vec<IgniteNamedField>,
}
impl IgniteNamed {
pub fn referenced(&self) -> HashSet<String> {
self.fields
.iter()
.flat_map(|field| field.referenced())
.collect()
}
}
#[derive(Debug, Serialize, Deserialize, Hash)]
pub struct IgniteUnnamed {
pub name: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub fields: Vec<IgniteUnnamedField>,
}
impl IgniteUnnamed {
pub fn referenced(&self) -> HashSet<String> {
self.fields
.iter()
.flat_map(|field| field.referenced())
.collect()
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct IgniteNamedField {
pub name: String,
pub typename: IgniteType,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mapping: Option<String>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub meta: HashMap<String, IgniteAttribMeta>,
}
impl IgniteNamedField {
pub fn referenced(&self) -> HashSet<String> {
if let Some(mapping) = &self.mapping {
let mut result = HashSet::new();
if let Some(mapping) = mapping.split('.').last() {
result.insert(mapping.to_owned());
}
result
} else {
self.typename.referenced()
}
}
}
impl Hash for IgniteNamedField {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.name.hash(state);
self.typename.hash(state);
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct IgniteUnnamedField {
pub typename: IgniteType,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mapping: Option<String>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub meta: HashMap<String, IgniteAttribMeta>,
}
impl IgniteUnnamedField {
pub fn referenced(&self) -> HashSet<String> {
if let Some(mapping) = &self.mapping {
let mut result = HashSet::new();
if let Some(mapping) = mapping.split('.').last() {
result.insert(mapping.to_owned());
}
result
} else {
self.typename.referenced()
}
}
}
impl Hash for IgniteUnnamedField {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.typename.hash(state);
}
}
#[derive(Debug, Serialize, Deserialize, Hash)]
pub struct IgniteEnum {
pub name: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub variants: Vec<IgniteVariant>,
}
impl IgniteEnum {
pub fn referenced(&self) -> HashSet<String> {
self.variants
.iter()
.flat_map(|variant| variant.referenced())
.collect()
}
}
#[derive(Debug, Serialize, Deserialize, Hash)]
pub enum IgniteVariant {
Unit(String),
Named(IgniteNamed),
Unnamed(IgniteUnnamed),
}
impl IgniteVariant {
pub fn referenced(&self) -> HashSet<String> {
match self {
Self::Unit(_) => HashSet::new(),
Self::Named(value) => value.referenced(),
Self::Unnamed(value) => value.referenced(),
}
}
}
#[derive(Debug, Serialize, Deserialize, Hash)]
pub enum IgniteType {
Unit,
Atom(String),
Tuple(Vec<IgniteType>),
Array(IgniteTypeArray),
Generic(IgniteTypeGeneric),
}
impl IgniteType {
pub fn referenced(&self) -> HashSet<String> {
match self {
Self::Unit => HashSet::new(),
Self::Atom(name) => {
let mut result = HashSet::new();
result.insert(name.clone());
result
}
Self::Tuple(value) => value.iter().flat_map(|item| item.referenced()).collect(),
Self::Array(value) => value.referenced(),
Self::Generic(value) => value.referenced(),
}
}
}
#[derive(Debug, Serialize, Deserialize, Hash)]
pub struct IgniteTypeArray {
pub typename: Box<IgniteType>,
pub size: usize,
}
impl IgniteTypeArray {
pub fn referenced(&self) -> HashSet<String> {
self.typename.referenced()
}
}
#[derive(Debug, Serialize, Deserialize, Hash)]
pub struct IgniteTypeGeneric {
pub name: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub arguments: Vec<IgniteType>,
}
impl IgniteTypeGeneric {
pub fn referenced(&self) -> HashSet<String> {
std::iter::once(self.name.clone())
.chain(self.arguments.iter().flat_map(|arg| arg.referenced()))
.collect()
}
}
#[derive(Debug, Serialize, Deserialize)]
pub enum IgniteAttribMeta {
None,
Bool(bool),
String(String),
Integer(i64),
Float(f64),
}
impl Default for IgniteAttribMeta {
fn default() -> Self {
Self::None
}
}
pub trait Ignite {
fn generate_type_definition() -> IgniteTypeDefinition;
}