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 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 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 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 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}