planus_types/
ast.rs

1use std::collections::HashMap;
2
3use codespan::{FileId, Span};
4use indexmap::IndexMap;
5
6pub type RawIdentifier = string_interner::DefaultSymbol;
7pub type Interner = string_interner::StringInterner<string_interner::DefaultBackend>;
8
9#[derive(Copy, Clone, Debug)]
10pub struct Identifier {
11    pub span: Span,
12    pub value: RawIdentifier,
13}
14
15pub struct Schema {
16    pub file_id: FileId,
17    pub docstrings: Docstrings,
18
19    // the spans are where the include definitions were
20    pub native_includes: Vec<StringLiteral>,
21    pub includes: Vec<StringLiteral>,
22
23    pub namespace: Option<(Span, NamespacePath)>,
24    pub root_type: Option<(Span, Type)>,
25    pub file_extension: Option<(Span, StringLiteral)>,
26    pub file_identifier: Option<(Span, StringLiteral)>,
27
28    pub attributes: Vec<Attribute>,
29    pub type_declarations: IndexMap<RawIdentifier, Declaration>,
30}
31
32impl Schema {
33    pub fn new(file_id: FileId, location: String) -> Self {
34        Self {
35            file_id,
36            docstrings: Docstrings::new(Some(location)),
37            namespace: Default::default(),
38            native_includes: Default::default(),
39            includes: Default::default(),
40            root_type: Default::default(),
41            file_extension: Default::default(),
42            file_identifier: Default::default(),
43            attributes: Default::default(),
44            type_declarations: Default::default(),
45        }
46    }
47}
48
49pub struct Attribute {
50    pub span: Span,
51    pub kind: AttributeKind,
52}
53
54pub enum AttributeKind {
55    // Potentially add more as we begin caring about them
56    Identifier(RawIdentifier),
57    String(String),
58}
59
60#[derive(Clone)]
61pub struct Declaration {
62    pub file_id: FileId,
63    pub full_span: Span,
64    pub definition_span: Span,
65    pub identifier: Identifier,
66    pub kind: TypeDeclarationKind,
67    pub docstrings: Docstrings,
68}
69
70#[derive(Clone)]
71pub enum TypeDeclarationKind {
72    Table(Struct),
73    Struct(Struct),
74    Enum(Enum),
75    Union(Union),
76    RpcService(RpcService),
77}
78
79#[derive(Clone, Debug, Default)]
80pub struct MetadataMap {
81    pub seen: HashMap<MetadataValueKindKey, Span>,
82    pub values: Vec<MetadataValue>,
83}
84
85#[derive(Clone)]
86pub struct Struct {
87    pub metadata: MetadataMap,
88    pub fields: IndexMap<RawIdentifier, StructField>,
89}
90
91#[derive(Clone, Debug)]
92pub struct StructField {
93    pub span: Span,
94    pub ident: Identifier,
95    pub type_: Type,
96    pub assignment: Option<Literal>,
97    pub metadata: MetadataMap,
98    pub docstrings: Docstrings,
99}
100
101#[derive(Clone)]
102pub struct Enum {
103    pub metadata: MetadataMap,
104    pub type_: IntegerType,
105    pub type_span: Span,
106    pub variants: IndexMap<RawIdentifier, EnumVariant>,
107}
108
109#[derive(Clone)]
110pub struct EnumVariant {
111    pub span: Span,
112    pub ident: Identifier,
113    pub value: Option<IntegerLiteral>,
114    pub docstrings: Docstrings,
115}
116
117#[derive(Clone)]
118pub struct Union {
119    pub metadata: MetadataMap,
120    pub variants: IndexMap<UnionKey, UnionVariant>,
121}
122
123#[derive(Clone, Debug)]
124pub enum UnionKey {
125    Identifier(RawIdentifier),
126    Type(Type),
127}
128
129impl PartialEq for UnionKey {
130    fn eq(&self, other: &Self) -> bool {
131        match (self, other) {
132            (UnionKey::Identifier(i0), UnionKey::Identifier(i1)) => i0 == i1,
133            (UnionKey::Type(t0), UnionKey::Type(t1)) => t0.eq_unspanned(t1),
134            _ => false,
135        }
136    }
137}
138
139impl Eq for UnionKey {}
140impl std::hash::Hash for UnionKey {
141    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
142        std::hash::Hash::hash(&std::mem::discriminant(self), state);
143        match self {
144            UnionKey::Identifier(i) => i.hash(state),
145            UnionKey::Type(t) => t.hash_unspanned(state),
146        }
147    }
148}
149
150#[derive(Clone)]
151pub struct UnionVariant {
152    pub span: Span,
153    pub ident: Option<Identifier>,
154    pub type_: Type,
155    pub docstrings: Docstrings,
156}
157
158#[derive(Clone)]
159pub struct RpcService {
160    pub methods: IndexMap<RawIdentifier, RpcMethod>,
161}
162
163#[derive(Clone)]
164pub struct RpcMethod {
165    pub span: Span,
166    pub ident: Identifier,
167    pub argument_type: Type,
168    pub return_type: Type,
169    pub metadata: MetadataMap,
170    pub docstrings: Docstrings,
171}
172
173#[derive(Clone, Debug)]
174pub struct MetadataValue {
175    pub span: Span,
176    pub kind: MetadataValueKind,
177}
178
179#[derive(Clone, Debug)]
180pub enum MetadataValueKind {
181    ForceAlign(IntegerLiteral),
182    BitFlags,
183    CsharpPartial,
184    Private,
185    NativeType(StringLiteral),
186    NativeTypePackName(StringLiteral),
187    OriginalOrder,
188
189    Required,
190    Deprecated,
191    Key,
192    Shared,
193    NestedFlatbuffer(StringLiteral),
194    Id(IntegerLiteral),
195    Hash(StringLiteral),
196    CppType(StringLiteral),
197    CppPtrType(StringLiteral),
198    CppPtrTypeGet(StringLiteral),
199    CppStrType(StringLiteral),
200    CppStrFlexCtor,
201    NativeInline,
202    NativeDefault(StringLiteral),
203    Flexbuffer,
204
205    Streaming(StringLiteral),
206    Idempotent,
207}
208
209#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
210pub enum MetadataValueKindKey {
211    ForceAlign,
212    BitFlags,
213    CsharpPartial,
214    Private,
215    NativeType,
216    NativeTypePackName,
217    OriginalOrder,
218
219    Required,
220    Deprecated,
221    Key,
222    Shared,
223    NestedFlatbuffer,
224    Id,
225    Hash,
226    CppType,
227    CppPtrType,
228    CppPtrTypeGet,
229    CppStrType,
230    CppStrFlexCtor,
231    NativeInline,
232    NativeDefault,
233    Flexbuffer,
234
235    Streaming,
236    Idempotent,
237}
238
239impl MetadataValueKindKey {
240    pub fn parse(s: &str) -> Option<MetadataValueKindKey> {
241        match s {
242            "force_align" => Some(Self::ForceAlign),
243            "bit_flags" => Some(Self::BitFlags),
244            "csharp_partial" => Some(Self::CsharpPartial),
245            "private" => Some(Self::Private),
246            "native_type" => Some(Self::NativeType),
247            "native_type_pack_name" => Some(Self::NativeTypePackName),
248            "original_order" => Some(Self::OriginalOrder),
249            "required" => Some(Self::Required),
250            "deprecated" => Some(Self::Deprecated),
251            "key" => Some(Self::Key),
252            "shared" => Some(Self::Shared),
253            "nested_flatbuffer" => Some(Self::NestedFlatbuffer),
254            "id" => Some(Self::Id),
255            "hash" => Some(Self::Hash),
256            "cpp_type" => Some(Self::CppType),
257            "cpp_ptr_type" => Some(Self::CppPtrType),
258            "cpp_ptr_type_get" => Some(Self::CppPtrTypeGet),
259            "cpp_str_type" => Some(Self::CppStrType),
260            "cpp_str_flex_ctor" => Some(Self::CppStrFlexCtor),
261            "native_inline" => Some(Self::NativeInline),
262            "native_default" => Some(Self::NativeDefault),
263            "flexbuffer" => Some(Self::Flexbuffer),
264            "streaming" => Some(Self::Streaming),
265            "idempotent" => Some(Self::Idempotent),
266            _ => None,
267        }
268    }
269
270    pub fn requirement(&self) -> &'static str {
271        match self {
272            Self::BitFlags
273            | Self::CsharpPartial
274            | Self::Private
275            | Self::OriginalOrder
276            | Self::Required
277            | Self::Deprecated
278            | Self::Key
279            | Self::Shared
280            | Self::CppStrFlexCtor
281            | Self::NativeInline
282            | Self::Flexbuffer
283            | Self::Idempotent => "should not have an argument",
284            Self::ForceAlign | Self::Id => "should have an integer argument",
285            Self::NativeType
286            | Self::NativeTypePackName
287            | Self::NestedFlatbuffer
288            | Self::Hash
289            | Self::CppType
290            | Self::CppPtrType
291            | Self::CppPtrTypeGet
292            | Self::CppStrType
293            | Self::NativeDefault
294            | Self::Streaming => "should have a string argument",
295        }
296    }
297}
298
299impl MetadataValueKind {
300    // Does the attribute have at least partial support?
301    pub fn is_supported(&self) -> bool {
302        matches!(
303            self,
304            Self::ForceAlign(_) | Self::Required | Self::Deprecated | Self::Id(_)
305        )
306    }
307
308    pub fn accepted_on_enums(&self) -> bool {
309        matches!(self, Self::BitFlags | Self::CsharpPartial | Self::Private)
310    }
311
312    pub fn accepted_on_structs(&self) -> bool {
313        matches!(
314            self,
315            Self::ForceAlign(_)
316                | Self::CsharpPartial
317                | Self::Private
318                | Self::NativeType(_)
319                | Self::NativeTypePackName(_)
320        )
321    }
322
323    pub fn accepted_on_tables(&self) -> bool {
324        matches!(
325            self,
326            Self::CsharpPartial
327                | Self::Private
328                | Self::NativeType(_)
329                | Self::NativeTypePackName(_)
330                | Self::OriginalOrder
331        )
332    }
333
334    pub fn accepted_on_unions(&self) -> bool {
335        matches!(
336            self,
337            Self::CsharpPartial | Self::Private | Self::NativeType(_) | Self::NativeTypePackName(_)
338        )
339    }
340
341    pub fn accepted_on_rpc_services(&self) -> bool {
342        matches!(self, Self::Private)
343    }
344
345    pub fn accepted_on_struct_fields(&self) -> bool {
346        matches!(
347            self,
348            Self::Key
349                | Self::Hash(_)
350                | Self::CppType(_)
351                | Self::CppPtrType(_)
352                | Self::CppPtrTypeGet(_)
353                | Self::NativeInline
354                | Self::NativeDefault(_)
355        )
356    }
357
358    pub fn accepted_on_table_fields(&self) -> bool {
359        matches!(
360            self,
361            Self::ForceAlign(_)
362                | Self::Required
363                | Self::Deprecated
364                | Self::Key
365                | Self::Shared
366                | Self::NestedFlatbuffer(_)
367                | Self::Id(_)
368                | Self::Hash(_)
369                | Self::CppType(_)
370                | Self::CppPtrType(_)
371                | Self::CppPtrTypeGet(_)
372                | Self::CppStrType(_)
373                | Self::CppStrFlexCtor
374                | Self::NativeInline
375                | Self::NativeDefault(_)
376                | Self::Flexbuffer
377        )
378    }
379
380    pub fn accepted_on_rpc_methods(&self) -> bool {
381        matches!(self, Self::Streaming(_) | Self::Idempotent)
382    }
383}
384
385#[derive(Clone, Debug)]
386pub struct NamespacePath {
387    pub span: Span,
388    pub parts: Vec<RawIdentifier>,
389}
390
391#[derive(Clone, Debug)]
392pub struct Type {
393    pub span: Span,
394    pub kind: TypeKind,
395}
396
397impl Type {
398    pub fn hash_unspanned<H>(&self, state: &mut H)
399    where
400        H: std::hash::Hasher,
401    {
402        self.kind.hash_unspanned(state);
403    }
404
405    pub fn eq_unspanned(&self, other: &Self) -> bool {
406        self.kind.eq_unspanned(&other.kind)
407    }
408}
409
410#[derive(Clone, Debug)]
411pub enum TypeKind {
412    Builtin(BuiltinType),
413    Vector { inner_type: Box<Type> },
414    Array { inner_type: Box<Type>, size: u32 },
415    Path(NamespacePath),
416    Invalid,
417}
418
419impl TypeKind {
420    pub fn hash_unspanned<H>(&self, state: &mut H)
421    where
422        H: std::hash::Hasher,
423    {
424        std::hash::Hash::hash(&std::mem::discriminant(self), state);
425        match self {
426            TypeKind::Builtin(t) => std::hash::Hash::hash(t, state),
427            TypeKind::Vector { inner_type } => inner_type.hash_unspanned(state),
428            TypeKind::Array { inner_type, size } => {
429                inner_type.hash_unspanned(state);
430                std::hash::Hash::hash(size, state);
431            }
432            TypeKind::Path(path) => {
433                std::hash::Hash::hash(&path.parts, state);
434            }
435            TypeKind::Invalid => (),
436        }
437    }
438
439    pub fn eq_unspanned(&self, other: &Self) -> bool {
440        match (self, other) {
441            (TypeKind::Builtin(t0), TypeKind::Builtin(t1)) => t0 == t1,
442            (TypeKind::Vector { inner_type: t0 }, TypeKind::Vector { inner_type: t1 }) => {
443                t0.eq_unspanned(t1)
444            }
445            (
446                TypeKind::Array {
447                    inner_type: t0,
448                    size: s0,
449                },
450                TypeKind::Array {
451                    inner_type: t1,
452                    size: s1,
453                },
454            ) => s0 == s1 && t0.eq_unspanned(t1),
455            (TypeKind::Path(p0), TypeKind::Path(p1)) => p0.parts == p1.parts,
456            (TypeKind::Invalid, TypeKind::Invalid) => true,
457            _ => false,
458        }
459    }
460}
461
462#[derive(Clone, Debug, PartialEq, Eq, Hash)]
463pub enum BuiltinType {
464    Bool,
465    Integer(IntegerType),
466    Float(FloatType),
467    String,
468}
469
470#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
471pub enum IntegerType {
472    U8,
473    U16,
474    U32,
475    U64,
476    I8,
477    I16,
478    I32,
479    I64,
480}
481
482impl IntegerType {
483    pub fn byte_size(&self) -> u32 {
484        match self {
485            IntegerType::U8 => 1,
486            IntegerType::I8 => 1,
487            IntegerType::U16 => 2,
488            IntegerType::I16 => 2,
489            IntegerType::U32 => 4,
490            IntegerType::I32 => 4,
491            IntegerType::U64 => 8,
492            IntegerType::I64 => 8,
493        }
494    }
495
496    pub fn flatbuffer_name(&self) -> &'static str {
497        match self {
498            IntegerType::U8 => "uint8",
499            IntegerType::U16 => "uint16",
500            IntegerType::U32 => "uint32",
501            IntegerType::U64 => "uint64",
502            IntegerType::I8 => "int8",
503            IntegerType::I16 => "int16",
504            IntegerType::I32 => "int32",
505            IntegerType::I64 => "int64",
506        }
507    }
508}
509
510#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
511pub enum FloatType {
512    F32,
513    F64,
514}
515
516impl FloatType {
517    pub fn byte_size(&self) -> u32 {
518        match self {
519            FloatType::F32 => 4,
520            FloatType::F64 => 8,
521        }
522    }
523
524    pub fn flatbuffer_name(&self) -> &'static str {
525        match self {
526            FloatType::F32 => "float32",
527            FloatType::F64 => "float64",
528        }
529    }
530}
531#[derive(Clone, Debug)]
532pub struct Literal {
533    pub span: Span,
534    pub kind: LiteralKind,
535}
536
537#[derive(Clone, Debug)]
538pub enum LiteralKind {
539    Bool(bool),
540    Integer { is_negative: bool, value: String },
541    Float { is_negative: bool, value: String },
542    String(String),
543    List(Vec<Literal>),
544    Null,
545    Constant(String),
546}
547
548#[derive(Clone, Debug)]
549pub struct IntegerLiteral {
550    pub span: Span,
551    pub is_negative: bool,
552    pub value: String,
553}
554
555#[derive(Clone, Debug)]
556pub struct StringLiteral {
557    pub span: Span,
558    pub value: String,
559}
560
561#[derive(Clone, Debug)]
562pub struct Docstrings {
563    pub docstrings: Vec<Docstring>,
564    pub default_docstring: String,
565    pub locations: Vec<String>,
566}
567
568#[derive(Clone, Debug)]
569pub struct Docstring {
570    pub span: Span,
571    pub value: String,
572}
573
574impl Docstrings {
575    pub fn new(location: Option<String>) -> Self {
576        Self {
577            docstrings: Default::default(),
578            default_docstring: Default::default(),
579            locations: location.into_iter().collect(),
580        }
581    }
582
583    pub fn iter_strings(&self) -> impl Iterator<Item = &str> {
584        // TODO: Make this mess part of the template logic instead
585        self.docstrings
586            .iter()
587            .map(|docstring| docstring.value.as_str())
588            .chain(
589                (self.docstrings.is_empty() && !self.default_docstring.is_empty())
590                    .then_some(self.default_docstring.as_str()),
591            )
592            .chain(
593                (!self.locations.is_empty())
594                    .then_some(
595                        ["", "Generated from these locations:"]
596                            .into_iter()
597                            .chain(self.locations.iter().map(|s| s.as_str())),
598                    )
599                    .into_iter()
600                    .flatten(),
601            )
602    }
603}