fbs_build/ast/
types.rs

1//! Types representing the parts of a flatbuffer schema
2use derive_more::{AsRef, From};
3use std::{collections::HashMap, convert::TryFrom, iter::FromIterator, path::Path};
4use typed_builder::TypedBuilder;
5
6/// A Flatbuffer schema.
7#[derive(Debug, Clone, PartialEq, From, TypedBuilder)]
8pub struct Schema<'a> {
9    /// A collection of included flatbuffer files.
10    #[builder(default)]
11    pub includes: Vec<Include<'a>>,
12
13    /// A collection of `Element`s that make up the body of the schema.
14    #[builder(default)]
15    pub elements: Vec<Element<'a>>,
16}
17
18/// A single include.
19#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, From, TypedBuilder)]
20pub struct Include<'a> {
21    /// The path to the included file.
22    pub path: &'a Path,
23
24    /// The file stem of `path`.
25    pub stem: &'a str,
26
27    #[builder(default)]
28    pub doc: Comment<'a>,
29}
30
31/// A single schema element.
32#[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    /// Check whether an element is a namespace.
49    pub fn is_namespace(&self) -> bool {
50        self.namespace().is_some()
51    }
52
53    /// Return the underlying `Namespace` object from the element if `self` is a `Namespace`.
54    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/// The root type of the schema file.
87#[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/// The extension to use when creating flatbuffers binary files.
96#[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/// A magic number for using flatbuffers as a file format.
105#[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/// A namespace in which one or more schema elements resides.
114#[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/// Declares an attribute to be used as metadata wherever metadata is valid.
123#[derive(Debug, Clone, PartialEq, Hash, Eq, From, TypedBuilder)]
124pub struct Attribute<'a> {
125    pub attr: Ident<'a>,
126}
127
128/// Struct type. Structs are product types where fields are always required.
129#[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/// Table type. Tables are product types where fields are optional unless indicated otherwise.
142#[derive(Debug, Clone, PartialEq, TypedBuilder)]
143pub struct Table<'a> {
144    pub id: Ident<'a>,
145    pub fields: Vec<Field<'a>>, // one or more
146
147    #[builder(default)]
148    pub metadata: Option<Metadata<'a>>,
149
150    #[builder(default)]
151    pub doc: Comment<'a>,
152}
153
154/// Enum type.
155#[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/// Union type.
169#[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/// A field of a `Struct` or `Table`.
182#[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/// An RPC service.
198#[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/// A method in an RPC service.
208#[derive(Debug, Clone, PartialEq, TypedBuilder)]
209pub struct RpcMethod<'a> {
210    /// The name of the method.
211    pub id: Ident<'a>,
212
213    /// The request type of the method.
214    pub request_type: QualifiedIdent<'a>,
215
216    /// The response type of the method.
217    pub response_type: QualifiedIdent<'a>,
218
219    /// Method metadata.
220    #[builder(default)]
221    pub metadata: Option<Metadata<'a>>,
222
223    #[builder(default)]
224    pub doc: Comment<'a>,
225}
226
227/// Scalar, array, and user-defined types.
228#[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    /// Check whether a `Type` is scalar.
258    pub fn is_scalar(&self) -> bool {
259        // If it's a string or array type it's not a scalar.
260        //
261        // TODO: enums are scalars, tables are not -- what about structs?
262        // we might need more context to determine if the type is a scalar
263        // to catch errors early
264        match self {
265            Type::String | Type::Array(_) => false,
266            _ => true,
267        }
268    }
269}
270
271impl<'a> From<[Type<'a>; 1]> for Type<'a> {
272    /// Convert an array of size 1 to a `Type::Array`.
273    fn from(array: [Type<'a>; 1]) -> Self {
274        Self::Array(Box::new(array[0].clone()))
275    }
276}
277
278pub type IntegerConstant = i128;
279
280/// Floating point constant type.
281pub type FloatingConstant = f64;
282
283/// Boolean constant type.
284pub type BooleanConstant = bool;
285
286/// Type for `Enum`/`Union` values.
287#[derive(Debug, Clone, PartialEq, Hash, Eq, From, TypedBuilder)]
288pub struct EnumVariant<'a> {
289    /// The name of the enum value.
290    pub id: Ident<'a>,
291
292    /// An optional enum value.
293    #[builder(default)]
294    pub value: Option<IntegerConstant>,
295
296    #[builder(default)]
297    pub doc: Comment<'a>,
298}
299
300/// Key-value pair metadata.
301#[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    /// Convert a `Vec` of `Ident`/`Value` pairs to a `Value`.
309    fn from(values: Vec<(Ident<'a>, Option<Single<'a>>)>) -> Self {
310        Self::builder().values(HashMap::from_iter(values)).build()
311    }
312}
313
314/// Integer, float, or boolean constants.
315#[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/// JSON-like values.
335#[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    /// Convert a `Vec` of `Ident`/`Value` pairs to a `Value`.
346    fn from(values: Vec<(Ident<'a>, Value<'a>)>) -> Self {
347        Self::builder().values(HashMap::from_iter(values)).build()
348    }
349}
350
351/// Default field value: A `Scalar` or an `Ident` referring to an enum variant
352/// on the current field enum type
353#[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/// A `Scalar` or string literal
410#[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/// Strings, integers, bools, objects, and lists thereof.
447#[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/// An identifier
461#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq, From, AsRef, TypedBuilder)]
462pub struct Ident<'a> {
463    pub raw: &'a str,
464}
465
466/// An identifier composed of `Ident`s separated by dots.
467#[derive(Debug, Clone, PartialEq, Hash, Eq, From, TypedBuilder)]
468pub struct QualifiedIdent<'a> {
469    pub parts: Vec<Ident<'a>>,
470}
471
472/// A documentation comment.
473#[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/// The root type of the file. This type is different from the [`Root`](crate::types::Root) type resulting from a parse.
480/// This type is an enum that contains the actual type object.
481#[derive(Debug, Clone, PartialEq, From)]
482pub enum RootType<'a> {
483    Table(Table<'a>),
484    Struct(Struct<'a>),
485}
486
487/// A file containing a flatbuffer schema.
488#[derive(Debug, Clone, PartialEq, From, TypedBuilder)]
489pub struct File<'a> {
490    /// The flatbuffer schema.
491    pub schema: Schema<'a>,
492
493    /// The path to the file.
494    pub path: &'a Path,
495
496    /// A list of root types declared in the file.
497    #[builder(default)]
498    pub root_type: Vec<RootType<'a>>,
499
500    /// An optional file identifier. See [`FileIdentifier`](crate::types::Identifier).
501    #[builder(default)]
502    pub file_identifier: Option<FileIdentifier<'a>>,
503
504    /// An optional file extension. See [`FileExtension`](crate::types::FileExtension).
505    #[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}