oxygengine_ignite_types/
lib.rs

1use serde::{Deserialize, Serialize};
2use std::{
3    collections::{HashMap, HashSet},
4    hash::{Hash, Hasher},
5};
6
7fn is_false(value: &bool) -> bool {
8    !value
9}
10
11#[derive(Debug, Serialize, Deserialize)]
12pub struct IgniteTypeDefinition {
13    #[serde(default, skip_serializing_if = "String::is_empty")]
14    pub namespace: String,
15    #[serde(default, skip_serializing_if = "Vec::is_empty")]
16    pub generic_args: Vec<String>,
17    pub variant: IgniteTypeVariant,
18    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
19    pub meta: HashMap<String, IgniteAttribMeta>,
20    #[serde(default, skip_serializing_if = "is_false")]
21    pub is_proxy: bool,
22}
23
24impl IgniteTypeDefinition {
25    pub fn name(&self) -> String {
26        self.variant.name()
27    }
28
29    pub fn referenced(&self) -> HashSet<String> {
30        self.variant.referenced()
31    }
32}
33
34impl Hash for IgniteTypeDefinition {
35    fn hash<H>(&self, state: &mut H)
36    where
37        H: Hasher,
38    {
39        self.namespace.hash(state);
40        self.generic_args.hash(state);
41        self.variant.hash(state);
42    }
43}
44
45#[derive(Debug, Serialize, Deserialize, Hash)]
46pub enum IgniteTypeVariant {
47    StructUnit(String),
48    StructNamed(IgniteNamed),
49    StructUnnamed(IgniteUnnamed),
50    Enum(IgniteEnum),
51}
52
53impl IgniteTypeVariant {
54    pub fn name(&self) -> String {
55        match self {
56            Self::StructUnit(name) => name.clone(),
57            Self::StructNamed(value) => value.name.clone(),
58            Self::StructUnnamed(value) => value.name.clone(),
59            Self::Enum(value) => value.name.clone(),
60        }
61    }
62
63    pub fn referenced(&self) -> HashSet<String> {
64        match self {
65            Self::StructUnit(_) => HashSet::new(),
66            Self::StructNamed(value) => value.referenced(),
67            Self::StructUnnamed(value) => value.referenced(),
68            Self::Enum(value) => value.referenced(),
69        }
70    }
71}
72
73#[derive(Debug, Serialize, Deserialize, Hash)]
74pub struct IgniteNamed {
75    pub name: String,
76    #[serde(default, skip_serializing_if = "Vec::is_empty")]
77    pub fields: Vec<IgniteNamedField>,
78}
79
80impl IgniteNamed {
81    pub fn referenced(&self) -> HashSet<String> {
82        self.fields
83            .iter()
84            .flat_map(|field| field.referenced())
85            .collect()
86    }
87}
88
89#[derive(Debug, Serialize, Deserialize, Hash)]
90pub struct IgniteUnnamed {
91    pub name: String,
92    #[serde(default, skip_serializing_if = "Vec::is_empty")]
93    pub fields: Vec<IgniteUnnamedField>,
94}
95
96impl IgniteUnnamed {
97    pub fn referenced(&self) -> HashSet<String> {
98        self.fields
99            .iter()
100            .flat_map(|field| field.referenced())
101            .collect()
102    }
103}
104
105#[derive(Debug, Serialize, Deserialize)]
106pub struct IgniteNamedField {
107    pub name: String,
108    pub typename: IgniteType,
109    #[serde(default, skip_serializing_if = "Option::is_none")]
110    pub mapping: Option<String>,
111    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
112    pub meta: HashMap<String, IgniteAttribMeta>,
113}
114
115impl IgniteNamedField {
116    pub fn referenced(&self) -> HashSet<String> {
117        if let Some(mapping) = &self.mapping {
118            let mut result = HashSet::new();
119            if let Some(mapping) = mapping.split('.').last() {
120                result.insert(mapping.to_owned());
121            }
122            result
123        } else {
124            self.typename.referenced()
125        }
126    }
127}
128
129impl Hash for IgniteNamedField {
130    fn hash<H>(&self, state: &mut H)
131    where
132        H: Hasher,
133    {
134        self.name.hash(state);
135        self.typename.hash(state);
136    }
137}
138
139#[derive(Debug, Serialize, Deserialize)]
140pub struct IgniteUnnamedField {
141    pub typename: IgniteType,
142    #[serde(default, skip_serializing_if = "Option::is_none")]
143    pub mapping: Option<String>,
144    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
145    pub meta: HashMap<String, IgniteAttribMeta>,
146}
147
148impl IgniteUnnamedField {
149    pub fn referenced(&self) -> HashSet<String> {
150        if let Some(mapping) = &self.mapping {
151            let mut result = HashSet::new();
152            if let Some(mapping) = mapping.split('.').last() {
153                result.insert(mapping.to_owned());
154            }
155            result
156        } else {
157            self.typename.referenced()
158        }
159    }
160}
161
162impl Hash for IgniteUnnamedField {
163    fn hash<H>(&self, state: &mut H)
164    where
165        H: Hasher,
166    {
167        self.typename.hash(state);
168    }
169}
170
171#[derive(Debug, Serialize, Deserialize, Hash)]
172pub struct IgniteEnum {
173    pub name: String,
174    #[serde(default, skip_serializing_if = "Vec::is_empty")]
175    pub variants: Vec<IgniteVariant>,
176}
177
178impl IgniteEnum {
179    pub fn referenced(&self) -> HashSet<String> {
180        self.variants
181            .iter()
182            .flat_map(|variant| variant.referenced())
183            .collect()
184    }
185}
186
187#[derive(Debug, Serialize, Deserialize, Hash)]
188pub enum IgniteVariant {
189    Unit(String),
190    Named(IgniteNamed),
191    Unnamed(IgniteUnnamed),
192}
193
194impl IgniteVariant {
195    pub fn referenced(&self) -> HashSet<String> {
196        match self {
197            Self::Unit(_) => HashSet::new(),
198            Self::Named(value) => value.referenced(),
199            Self::Unnamed(value) => value.referenced(),
200        }
201    }
202}
203
204#[derive(Debug, Serialize, Deserialize, Hash)]
205pub enum IgniteType {
206    Unit,
207    Atom(String),
208    Tuple(Vec<IgniteType>),
209    Array(IgniteTypeArray),
210    Generic(IgniteTypeGeneric),
211}
212
213impl IgniteType {
214    pub fn referenced(&self) -> HashSet<String> {
215        match self {
216            Self::Unit => HashSet::new(),
217            Self::Atom(name) => {
218                let mut result = HashSet::new();
219                result.insert(name.clone());
220                result
221            }
222            Self::Tuple(value) => value.iter().flat_map(|item| item.referenced()).collect(),
223            Self::Array(value) => value.referenced(),
224            Self::Generic(value) => value.referenced(),
225        }
226    }
227}
228
229#[derive(Debug, Serialize, Deserialize, Hash)]
230pub struct IgniteTypeArray {
231    pub typename: Box<IgniteType>,
232    pub size: usize,
233}
234
235impl IgniteTypeArray {
236    pub fn referenced(&self) -> HashSet<String> {
237        self.typename.referenced()
238    }
239}
240
241#[derive(Debug, Serialize, Deserialize, Hash)]
242pub struct IgniteTypeGeneric {
243    pub name: String,
244    #[serde(default, skip_serializing_if = "Vec::is_empty")]
245    pub arguments: Vec<IgniteType>,
246}
247
248impl IgniteTypeGeneric {
249    pub fn referenced(&self) -> HashSet<String> {
250        std::iter::once(self.name.clone())
251            .chain(self.arguments.iter().flat_map(|arg| arg.referenced()))
252            .collect()
253    }
254}
255
256#[derive(Debug, Serialize, Deserialize)]
257pub enum IgniteAttribMeta {
258    None,
259    Bool(bool),
260    String(String),
261    Integer(i64),
262    Float(f64),
263}
264
265impl Default for IgniteAttribMeta {
266    fn default() -> Self {
267        Self::None
268    }
269}
270
271pub trait Ignite {
272    fn generate_type_definition() -> IgniteTypeDefinition;
273}