1use derive_more::{AsRef, From};
3use std::{collections::HashMap, convert::TryFrom, iter::FromIterator, path::Path};
4use typed_builder::TypedBuilder;
5
6#[derive(Debug, Clone, PartialEq, From, TypedBuilder)]
8pub struct Schema<'a> {
9 #[builder(default)]
11 pub includes: Vec<Include<'a>>,
12
13 #[builder(default)]
15 pub elements: Vec<Element<'a>>,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, From, TypedBuilder)]
20pub struct Include<'a> {
21 pub path: &'a Path,
23
24 pub stem: &'a str,
26
27 #[builder(default)]
28 pub doc: Comment<'a>,
29}
30
31#[derive(Debug, Clone, PartialEq, From)]
33pub enum Element<'a> {
34 Namespace(Namespace<'a>),
35 Table(Table<'a>),
36 Struct(Struct<'a>),
37 Enum(Enum<'a>),
38 Union(Union<'a>),
39 Root(Root<'a>),
40 FileExtension(FileExtension<'a>),
41 FileIdentifier(FileIdentifier<'a>),
42 Attribute(Attribute<'a>),
43 Rpc(Rpc<'a>),
44 Object(Object<'a>),
45}
46
47impl Element<'_> {
48 pub fn is_namespace(&self) -> bool {
50 self.namespace().is_some()
51 }
52
53 pub fn namespace(&self) -> Option<&Namespace<'_>> {
55 match self {
56 Element::Namespace(ns) => Some(ns),
57 _ => None,
58 }
59 }
60}
61
62#[cfg(test)]
63mod element_impl_tests {
64 use super::*;
65 use crate::namespace;
66
67 #[test]
68 fn test_is_namespace_with_namespace() {
69 let ns = Element::from(namespace!(a::b::c));
70 assert!(ns.is_namespace());
71 }
72
73 #[test]
74 fn test_namespace_with_namespace() {
75 let ns = Element::from(namespace!(foo::bar));
76 assert_eq!(
77 ns.namespace(),
78 Some(&Namespace::from((
79 vec!["foo".into(), "bar".into()].into(),
80 Comment::builder().build(),
81 )))
82 );
83 }
84}
85
86#[derive(Debug, Clone, PartialEq, From, TypedBuilder)]
88pub struct Root<'a> {
89 pub typename: Ident<'a>,
90
91 #[builder(default)]
92 pub doc: Comment<'a>,
93}
94
95#[derive(Debug, Clone, PartialEq, Hash, Eq, From, TypedBuilder)]
97pub struct FileExtension<'a> {
98 pub ext: &'a str,
99
100 #[builder(default)]
101 pub doc: Comment<'a>,
102}
103
104#[derive(Debug, Clone, PartialEq, Hash, Eq, From, TypedBuilder)]
106pub struct FileIdentifier<'a> {
107 pub id: [u8; 4],
108
109 #[builder(default)]
110 pub doc: Comment<'a>,
111}
112
113#[derive(Debug, Clone, PartialEq, Eq, Hash, From, TypedBuilder)]
115pub struct Namespace<'a> {
116 pub ident: QualifiedIdent<'a>,
117
118 #[builder(default)]
119 pub doc: Comment<'a>,
120}
121
122#[derive(Debug, Clone, PartialEq, Hash, Eq, From, TypedBuilder)]
124pub struct Attribute<'a> {
125 pub attr: Ident<'a>,
126}
127
128#[derive(Debug, Clone, PartialEq, TypedBuilder)]
130pub struct Struct<'a> {
131 pub id: Ident<'a>,
132 pub fields: Vec<Field<'a>>,
133
134 #[builder(default)]
135 pub metadata: Option<Metadata<'a>>,
136
137 #[builder(default)]
138 pub doc: Comment<'a>,
139}
140
141#[derive(Debug, Clone, PartialEq, TypedBuilder)]
143pub struct Table<'a> {
144 pub id: Ident<'a>,
145 pub fields: Vec<Field<'a>>, #[builder(default)]
148 pub metadata: Option<Metadata<'a>>,
149
150 #[builder(default)]
151 pub doc: Comment<'a>,
152}
153
154#[derive(Debug, Clone, PartialEq, TypedBuilder)]
156pub struct Enum<'a> {
157 pub id: Ident<'a>,
158 pub variants: Vec<EnumVariant<'a>>,
159 pub base_type: Type<'a>,
160
161 #[builder(default)]
162 pub metadata: Option<Metadata<'a>>,
163
164 #[builder(default)]
165 pub doc: Comment<'a>,
166}
167
168#[derive(Debug, Clone, PartialEq, TypedBuilder)]
170pub struct Union<'a> {
171 pub id: Ident<'a>,
172 pub variants: Vec<EnumVariant<'a>>,
173
174 #[builder(default)]
175 pub metadata: Option<Metadata<'a>>,
176
177 #[builder(default)]
178 pub doc: Comment<'a>,
179}
180
181#[derive(Debug, Clone, PartialEq, TypedBuilder)]
183pub struct Field<'a> {
184 pub id: Ident<'a>,
185 pub ty: Type<'a>,
186
187 #[builder(default)]
188 pub default_value: Option<DefaultValue<'a>>,
189
190 #[builder(default)]
191 pub metadata: Option<Metadata<'a>>,
192
193 #[builder(default)]
194 pub doc: Comment<'a>,
195}
196
197#[derive(Debug, Clone, PartialEq, TypedBuilder)]
199pub struct Rpc<'a> {
200 pub id: Ident<'a>,
201 pub methods: Vec<RpcMethod<'a>>,
202
203 #[builder(default)]
204 pub doc: Comment<'a>,
205}
206
207#[derive(Debug, Clone, PartialEq, TypedBuilder)]
209pub struct RpcMethod<'a> {
210 pub id: Ident<'a>,
212
213 pub request_type: QualifiedIdent<'a>,
215
216 pub response_type: QualifiedIdent<'a>,
218
219 #[builder(default)]
221 pub metadata: Option<Metadata<'a>>,
222
223 #[builder(default)]
224 pub doc: Comment<'a>,
225}
226
227#[derive(Debug, Clone, PartialEq, Hash, Eq)]
229pub enum Type<'a> {
230 Bool,
231 Byte,
232 UByte,
233 Short,
234 UShort,
235 Int,
236 UInt,
237 Float,
238 Long,
239 ULong,
240 Double,
241 Int8,
242 UInt8,
243 Int16,
244 UInt16,
245 Int32,
246 UInt32,
247 Int64,
248 UInt64,
249 Float32,
250 Float64,
251 String,
252 Array(Box<Type<'a>>),
253 Ident(QualifiedIdent<'a>),
254}
255
256impl Type<'_> {
257 pub fn is_scalar(&self) -> bool {
259 match self {
265 Type::String | Type::Array(_) => false,
266 _ => true,
267 }
268 }
269}
270
271impl<'a> From<[Type<'a>; 1]> for Type<'a> {
272 fn from(array: [Type<'a>; 1]) -> Self {
274 Self::Array(Box::new(array[0].clone()))
275 }
276}
277
278pub type IntegerConstant = i128;
279
280pub type FloatingConstant = f64;
282
283pub type BooleanConstant = bool;
285
286#[derive(Debug, Clone, PartialEq, Hash, Eq, From, TypedBuilder)]
288pub struct EnumVariant<'a> {
289 pub id: Ident<'a>,
291
292 #[builder(default)]
294 pub value: Option<IntegerConstant>,
295
296 #[builder(default)]
297 pub doc: Comment<'a>,
298}
299
300#[derive(Debug, Clone, PartialEq, From, TypedBuilder)]
302pub struct Metadata<'a> {
303 #[builder(default)]
304 pub values: HashMap<Ident<'a>, Option<Single<'a>>>,
305}
306
307impl<'a> From<Vec<(Ident<'a>, Option<Single<'a>>)>> for Metadata<'a> {
308 fn from(values: Vec<(Ident<'a>, Option<Single<'a>>)>) -> Self {
310 Self::builder().values(HashMap::from_iter(values)).build()
311 }
312}
313
314#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, From)]
316pub enum Scalar {
317 Integer(IntegerConstant),
318 Float(FloatingConstant),
319 Boolean(BooleanConstant),
320}
321
322impl From<u64> for Scalar {
323 fn from(value: u64) -> Self {
324 Self::from(IntegerConstant::from(value))
325 }
326}
327
328impl From<i32> for Scalar {
329 fn from(value: i32) -> Self {
330 Self::from(IntegerConstant::from(value))
331 }
332}
333
334#[derive(Debug, Clone, PartialEq, From, TypedBuilder)]
336pub struct Object<'a> {
337 #[builder(default)]
338 pub values: HashMap<Ident<'a>, Value<'a>>,
339
340 #[builder(default)]
341 pub doc: Comment<'a>,
342}
343
344impl<'a> From<Vec<(Ident<'a>, Value<'a>)>> for Object<'a> {
345 fn from(values: Vec<(Ident<'a>, Value<'a>)>) -> Self {
347 Self::builder().values(HashMap::from_iter(values)).build()
348 }
349}
350
351#[derive(Debug, Clone, PartialEq, From)]
354pub enum DefaultValue<'a> {
355 Scalar(Scalar),
356 Ident(Ident<'a>),
357}
358
359impl From<IntegerConstant> for DefaultValue<'_> {
360 fn from(value: IntegerConstant) -> Self {
361 Scalar::from(value).into()
362 }
363}
364
365impl From<u64> for DefaultValue<'_> {
366 fn from(value: u64) -> Self {
367 Scalar::from(IntegerConstant::from(value)).into()
368 }
369}
370
371impl From<i32> for DefaultValue<'_> {
372 fn from(value: i32) -> Self {
373 Scalar::from(IntegerConstant::from(value)).into()
374 }
375}
376
377impl From<FloatingConstant> for DefaultValue<'_> {
378 fn from(value: FloatingConstant) -> Self {
379 Scalar::from(value).into()
380 }
381}
382
383impl From<BooleanConstant> for DefaultValue<'_> {
384 fn from(value: BooleanConstant) -> Self {
385 Scalar::from(value).into()
386 }
387}
388
389impl<'a> From<&'a str> for DefaultValue<'a> {
390 fn from(value: &'a str) -> Self {
391 Ident::from(value).into()
392 }
393}
394
395impl<'a> TryFrom<&Type<'a>> for DefaultValue<'a> {
396 type Error = fbs::Error;
397
398 fn try_from(ty: &Type<'a>) -> Result<Self, Self::Error> {
399 match ty {
400 Type::Array(..) | Type::Ident(..) | Type::String => None,
401 Type::Bool => Some(false.into()),
402 Type::Double | Type::Float | Type::Float32 | Type::Float64 => Some((0.0).into()),
403 _ => Some(0.into()),
404 }
405 .ok_or(fbs::Error::NoTypeDefaultValue)
406 }
407}
408
409#[derive(Debug, Clone, PartialEq, PartialOrd, From)]
411pub enum Single<'a> {
412 Scalar(Scalar),
413 String(&'a str),
414}
415
416impl From<IntegerConstant> for Single<'_> {
417 fn from(value: IntegerConstant) -> Self {
418 Scalar::from(value).into()
419 }
420}
421
422impl From<u64> for Single<'_> {
423 fn from(value: u64) -> Self {
424 Scalar::from(IntegerConstant::from(value)).into()
425 }
426}
427
428impl From<i32> for Single<'_> {
429 fn from(value: i32) -> Self {
430 Scalar::from(IntegerConstant::from(value)).into()
431 }
432}
433
434impl From<FloatingConstant> for Single<'_> {
435 fn from(value: FloatingConstant) -> Self {
436 Scalar::from(value).into()
437 }
438}
439
440impl From<BooleanConstant> for Single<'_> {
441 fn from(value: BooleanConstant) -> Self {
442 Scalar::from(value).into()
443 }
444}
445
446#[derive(Debug, Clone, PartialEq, From)]
448pub enum Value<'a> {
449 Single(Single<'a>),
450 Object(Object<'a>),
451 List(Vec<Value<'a>>),
452}
453
454impl<'a> From<Vec<(Ident<'a>, Value<'a>)>> for Value<'a> {
455 fn from(values: Vec<(Ident<'a>, Value<'a>)>) -> Self {
456 Object::from(values).into()
457 }
458}
459
460#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq, From, AsRef, TypedBuilder)]
462pub struct Ident<'a> {
463 pub raw: &'a str,
464}
465
466#[derive(Debug, Clone, PartialEq, Hash, Eq, From, TypedBuilder)]
468pub struct QualifiedIdent<'a> {
469 pub parts: Vec<Ident<'a>>,
470}
471
472#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default, From, TypedBuilder)]
474pub struct Comment<'a> {
475 #[builder(default)]
476 pub lines: Vec<&'a str>,
477}
478
479#[derive(Debug, Clone, PartialEq, From)]
482pub enum RootType<'a> {
483 Table(Table<'a>),
484 Struct(Struct<'a>),
485}
486
487#[derive(Debug, Clone, PartialEq, From, TypedBuilder)]
489pub struct File<'a> {
490 pub schema: Schema<'a>,
492
493 pub path: &'a Path,
495
496 #[builder(default)]
498 pub root_type: Vec<RootType<'a>>,
499
500 #[builder(default)]
502 pub file_identifier: Option<FileIdentifier<'a>>,
503
504 #[builder(default)]
506 pub file_extension: Option<FileExtension<'a>>,
507}
508
509#[cfg(test)]
510mod type_tests {
511 use super::*;
512
513 #[test]
514 fn test_is_scalar() {
515 assert!(Type::Float32.is_scalar());
516 assert!(Type::UInt16.is_scalar());
517 assert!(!Type::String.is_scalar());
518 assert!(!Type::Array(Box::new(Type::Byte)).is_scalar());
519 }
520}