1use pest::{iterators::Pairs, Parser};
2use pest_derive::Parser;
3use serde::{Deserialize, Serialize};
4use std::{collections::HashMap, hash::Hash};
5
6#[derive(Parser)]
7#[grammar = "schema.grammar.pest"]
8struct SchemaIdParser;
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
11pub enum SchemaIdTree {
12 Tuple(Vec<Self>),
13 Path { path: Vec<String>, args: Vec<Self> },
14}
15
16impl SchemaIdTree {
17 pub fn new<T>() -> Self {
18 let id = SchemaId::new::<T>();
19 id.tree()
20 .unwrap_or_else(|| panic!("Cannot produce schema id tree from: {}", id.id()))
21 }
22
23 pub fn as_tuple(&self) -> Option<&[Self]> {
24 match self {
25 Self::Tuple(list) => Some(list),
26 _ => None,
27 }
28 }
29
30 pub fn as_path(&self) -> Option<&[String]> {
31 match self {
32 Self::Path { path, .. } => Some(path),
33 _ => None,
34 }
35 }
36
37 pub fn as_path_name(&self) -> Option<&str> {
38 self.as_path()
39 .and_then(|list| list.last())
40 .map(|segment| segment.as_str())
41 }
42
43 pub fn as_path_args(&self) -> Option<&[Self]> {
44 match self {
45 Self::Path { args, .. } => Some(args),
46 _ => None,
47 }
48 }
49}
50
51impl std::fmt::Display for SchemaIdTree {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 match self {
54 Self::Tuple(list) => {
55 write!(f, "(")?;
56 for (i, item) in list.iter().enumerate() {
57 if i > 0 {
58 write!(f, ", ")?;
59 }
60 item.fmt(f)?;
61 }
62 write!(f, ")")?;
63 }
64 Self::Path { path, args } => {
65 for (i, segment) in path.iter().enumerate() {
66 if i > 0 {
67 write!(f, "::")?;
68 }
69 segment.fmt(f)?;
70 }
71 if !args.is_empty() {
72 write!(f, "<")?;
73 for (i, arg) in args.iter().enumerate() {
74 if i > 0 {
75 write!(f, ", ")?;
76 }
77 arg.fmt(f)?;
78 }
79 write!(f, ">")?;
80 }
81 }
82 }
83 Ok(())
84 }
85}
86
87impl TryFrom<SchemaId> for SchemaIdTree {
88 type Error = ();
89
90 fn try_from(id: SchemaId) -> Result<Self, Self::Error> {
91 id.tree().ok_or(())
92 }
93}
94
95#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
96pub struct SchemaId(String);
97
98impl SchemaId {
99 pub fn new<T>() -> Self {
100 Self(std::any::type_name::<T>().to_string())
101 }
102
103 pub fn id(&self) -> &str {
104 &self.0
105 }
106
107 pub fn tree(&self) -> Option<SchemaIdTree> {
108 let pairs = SchemaIdParser::parse(Rule::main, &self.0)
109 .ok()?
110 .next()?
111 .into_inner();
112 Some(Self::parse_tree(pairs))
113 }
114
115 fn parse_tree(mut pairs: Pairs<Rule>) -> SchemaIdTree {
116 let pair = pairs.next().unwrap();
117 match pair.as_rule() {
118 Rule::tuple_element => SchemaIdTree::Tuple(Self::parse_list(pair.into_inner())),
119 Rule::path_element => {
120 let mut pairs = pair.into_inner();
121 let path = Self::parse_path(pairs.next().unwrap().into_inner());
122 let args = pairs
123 .next()
124 .map(|pair| Self::parse_list(pair.into_inner()))
125 .unwrap_or_default();
126 SchemaIdTree::Path { path, args }
127 }
128 _ => unreachable!(),
129 }
130 }
131
132 fn parse_path(pairs: Pairs<Rule>) -> Vec<String> {
133 pairs.map(|pair| pair.as_str().to_owned()).collect()
134 }
135
136 fn parse_list(pairs: Pairs<Rule>) -> Vec<SchemaIdTree> {
137 pairs
138 .map(|pair| Self::parse_tree(pair.into_inner()))
139 .collect()
140 }
141}
142
143impl std::fmt::Display for SchemaId {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 write!(f, "{}", self.0)
146 }
147}
148
149impl From<SchemaIdTree> for SchemaId {
150 fn from(tree: SchemaIdTree) -> Self {
151 Self(tree.to_string())
152 }
153}
154
155#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
156pub enum SchemaIdContainer {
157 Id(SchemaId),
158 Tree(SchemaIdTree),
159}
160
161impl SchemaIdContainer {
162 pub fn new<T>(prefer_tree: bool) -> Self {
163 let id = SchemaId::new::<T>();
164 if prefer_tree {
165 id.tree()
166 .map(|tree| tree.into())
167 .unwrap_or_else(|| id.into())
168 } else {
169 id.into()
170 }
171 }
172
173 pub fn new_id(id: impl Into<SchemaId>) -> Self {
174 Self::Id(id.into())
175 }
176
177 pub fn new_tree(tree: impl Into<SchemaIdTree>) -> Self {
178 Self::Tree(tree.into())
179 }
180
181 pub fn as_id(&self) -> Option<&SchemaId> {
182 match self {
183 Self::Id(id) => Some(id),
184 _ => None,
185 }
186 }
187
188 pub fn as_tree(&self) -> Option<&SchemaIdTree> {
189 match self {
190 Self::Tree(tree) => Some(tree),
191 _ => None,
192 }
193 }
194
195 pub fn into_id(self) -> SchemaId {
196 match self {
197 Self::Id(id) => id,
198 Self::Tree(tree) => tree.into(),
199 }
200 }
201
202 pub fn try_into_tree(self) -> Option<SchemaIdTree> {
203 match self {
204 Self::Id(id) => id.tree(),
205 Self::Tree(tree) => Some(tree),
206 }
207 }
208}
209
210impl std::fmt::Display for SchemaIdContainer {
211 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212 match self {
213 Self::Id(id) => id.fmt(f),
214 Self::Tree(tree) => tree.fmt(f),
215 }
216 }
217}
218
219impl From<SchemaId> for SchemaIdContainer {
220 fn from(id: SchemaId) -> Self {
221 Self::Id(id)
222 }
223}
224
225impl From<SchemaIdTree> for SchemaIdContainer {
226 fn from(tree: SchemaIdTree) -> Self {
227 Self::Tree(tree)
228 }
229}
230
231#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
232pub struct SchemaTypeInstance {
233 pub id: SchemaIdContainer,
234 #[serde(default)]
235 pub description: String,
236}
237
238impl SchemaTypeInstance {
239 pub fn new(id: impl Into<SchemaIdContainer>) -> Self {
240 Self {
241 id: id.into(),
242 description: Default::default(),
243 }
244 }
245
246 pub fn description(mut self, content: impl ToString) -> Self {
247 self.description = content.to_string();
248 self
249 }
250}
251
252impl<ID> From<ID> for SchemaTypeInstance
253where
254 ID: Into<SchemaIdContainer>,
255{
256 fn from(id: ID) -> Self {
257 Self::new(id)
258 }
259}
260
261#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
262pub struct SchemaTypeTuple(pub Vec<SchemaTypeInstance>);
263
264impl SchemaTypeTuple {
265 pub fn item(mut self, type_instance: impl Into<SchemaTypeInstance>) -> Self {
266 self.0.push(type_instance.into());
267 self
268 }
269}
270
271impl<TI> FromIterator<TI> for SchemaTypeTuple
272where
273 TI: Into<SchemaTypeInstance>,
274{
275 fn from_iter<I>(iter: I) -> Self
276 where
277 I: IntoIterator<Item = TI>,
278 {
279 Self(
280 iter.into_iter()
281 .map(|type_instance| type_instance.into())
282 .collect(),
283 )
284 }
285}
286
287#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
288pub struct SchemaTypeStruct(pub HashMap<String, SchemaTypeInstance>);
289
290impl SchemaTypeStruct {
291 pub fn field(
292 mut self,
293 name: impl ToString,
294 type_instance: impl Into<SchemaTypeInstance>,
295 ) -> Self {
296 self.0.insert(name.to_string(), type_instance.into());
297 self
298 }
299}
300
301impl<N, TI> FromIterator<(N, TI)> for SchemaTypeStruct
302where
303 N: ToString,
304 TI: Into<SchemaTypeInstance>,
305{
306 fn from_iter<I>(iter: I) -> Self
307 where
308 I: IntoIterator<Item = (N, TI)>,
309 {
310 Self(
311 iter.into_iter()
312 .map(|(name, type_instance)| (name.to_string(), type_instance.into()))
313 .collect(),
314 )
315 }
316}
317
318#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
319pub struct SchemaTypeArrayOrSlice {
320 pub type_instance: SchemaTypeInstance,
321 pub count: usize,
322}
323
324impl SchemaTypeArrayOrSlice {
325 pub fn new(type_instance: impl Into<SchemaTypeInstance>, count: usize) -> Self {
326 Self {
327 type_instance: type_instance.into(),
328 count,
329 }
330 }
331}
332
333impl<TI> From<(TI, usize)> for SchemaTypeArrayOrSlice
334where
335 TI: Into<SchemaTypeInstance>,
336{
337 fn from((type_instance, count): (TI, usize)) -> Self {
338 Self::new(type_instance, count)
339 }
340}
341
342#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
343pub enum SchemaTypeEnumVariant {
344 #[default]
345 Empty,
346 Tuple(SchemaTypeTuple),
347 Struct(SchemaTypeStruct),
348}
349
350impl SchemaTypeEnumVariant {
351 pub fn new_tuple(content: impl Into<SchemaTypeTuple>) -> Self {
352 Self::Tuple(content.into())
353 }
354
355 pub fn new_struct(content: impl Into<SchemaTypeStruct>) -> Self {
356 Self::Struct(content.into())
357 }
358}
359
360#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
361pub struct SchemaTypeEnum(pub HashMap<String, SchemaTypeEnumVariant>);
362
363impl SchemaTypeEnum {
364 pub fn variant(
365 mut self,
366 name: impl ToString,
367 content: impl Into<SchemaTypeEnumVariant>,
368 ) -> Self {
369 self.0.insert(name.to_string(), content.into());
370 self
371 }
372}
373
374impl<N, V> FromIterator<(N, V)> for SchemaTypeEnum
375where
376 N: ToString,
377 V: Into<SchemaTypeEnumVariant>,
378{
379 fn from_iter<I>(iter: I) -> Self
380 where
381 I: IntoIterator<Item = (N, V)>,
382 {
383 Self(
384 iter.into_iter()
385 .map(|(name, variant)| (name.to_string(), variant.into()))
386 .collect(),
387 )
388 }
389}
390
391#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
392pub enum SchemaType {
393 Tuple(SchemaTypeTuple),
394 Array(SchemaTypeArrayOrSlice),
395 Slice(SchemaTypeArrayOrSlice),
396 TupleStruct(SchemaTypeTuple),
397 Struct(SchemaTypeStruct),
398 Enum(SchemaTypeEnum),
399}
400
401impl SchemaType {
402 pub fn new_tuple(content: impl Into<SchemaTypeTuple>) -> Self {
403 Self::Tuple(content.into())
404 }
405
406 pub fn new_array(content: impl Into<SchemaTypeArrayOrSlice>) -> Self {
407 Self::Array(content.into())
408 }
409
410 pub fn new_slice(content: impl Into<SchemaTypeArrayOrSlice>) -> Self {
411 Self::Slice(content.into())
412 }
413
414 pub fn new_tuple_struct(content: impl Into<SchemaTypeTuple>) -> Self {
415 Self::TupleStruct(content.into())
416 }
417
418 pub fn new_struct(content: impl Into<SchemaTypeStruct>) -> Self {
419 Self::Struct(content.into())
420 }
421
422 pub fn new_enum(content: impl Into<SchemaTypeEnum>) -> Self {
423 Self::Enum(content.into())
424 }
425}
426
427#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
428pub struct Schema {
429 pub data_type: SchemaType,
430 #[serde(default)]
431 pub description: String,
432}
433
434impl Schema {
435 pub fn new(data_type: impl Into<SchemaType>) -> Self {
436 Self {
437 description: Default::default(),
438 data_type: data_type.into(),
439 }
440 }
441
442 pub fn description(mut self, content: impl ToString) -> Self {
443 self.description = content.to_string();
444 self
445 }
446}
447
448impl<T> From<T> for Schema
449where
450 T: Into<SchemaType>,
451{
452 fn from(data_type: T) -> Self {
453 Self::new(data_type)
454 }
455}
456
457#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
458pub struct SchemaPackage {
459 #[serde(default)]
460 pub prefer_tree_id: bool,
461 pub schemas: HashMap<SchemaIdContainer, Schema>,
462}
463
464impl SchemaPackage {
465 pub fn with_capacity(capacity: usize) -> Self {
466 Self {
467 prefer_tree_id: false,
468 schemas: HashMap::with_capacity(capacity),
469 }
470 }
471
472 pub fn prefer_tree_id(mut self, value: bool) -> Self {
473 self.prefer_tree_id = value;
474 self
475 }
476
477 pub fn with(
478 &mut self,
479 id: impl Into<SchemaIdContainer>,
480 schema: impl Into<Schema>,
481 ) -> &mut Self {
482 self.schemas.insert(id.into(), schema.into());
483 self
484 }
485}
486
487pub trait SchemaIntermediate: Sized {
488 fn schema(package: &mut SchemaPackage) -> SchemaIdContainer;
489}