1use crate::ast::types as ast;
10use derive_more::{AsRef, From};
11use std::{borrow::Cow, fmt::Display};
12use typed_builder::TypedBuilder;
13
14#[derive(Debug, Clone, PartialEq)]
16pub enum Node<'a> {
17 Namespace(Namespace<'a>),
18 Table(Table<'a>),
19 Struct(Struct<'a>),
20 Enum(Enum<'a>),
21 Union(Union<'a>),
22 Rpc(Rpc<'a>),
23}
24
25impl<'a> Node<'a> {
26 pub fn ident(&self) -> &QualifiedIdent<'a> {
27 match self {
28 Node::Namespace(ns) => &ns.ident,
29 Node::Table(t) => &t.ident,
30 Node::Struct(s) => &s.ident,
31 Node::Enum(e) => &e.ident,
32 Node::Union(u) => &u.ident,
33 Node::Rpc(r) => &r.ident,
34 }
35 }
36
37 pub fn namespace(&self) -> Option<QualifiedIdent<'a>> {
38 self.ident().namespace()
39 }
40
41 pub fn is_namespace(&self) -> bool {
42 self.as_namespace().is_some()
43 }
44
45 pub fn as_namespace(&self) -> Option<&Namespace<'a>> {
46 match self {
47 Node::Namespace(ns) => Some(ns),
48 _ => None,
49 }
50 }
51
52 pub fn as_namespace_mut(&mut self) -> Option<&mut Namespace<'a>> {
53 match self {
54 Node::Namespace(ns) => Some(ns),
55 _ => None,
56 }
57 }
58
59 pub fn into_namespace(self) -> Option<Namespace<'a>> {
60 match self {
61 Node::Namespace(ns) => Some(ns),
62 _ => None,
63 }
64 }
65}
66
67#[derive(Debug, Clone, PartialEq, TypedBuilder)]
71pub struct Root<'a> {
72 pub nodes: Vec<Node<'a>>,
74}
75
76#[derive(Debug, Clone, PartialEq, TypedBuilder)]
77pub struct Namespace<'a> {
78 pub ident: QualifiedIdent<'a>,
80
81 #[builder(default)]
83 pub nodes: Vec<Node<'a>>,
84}
85
86impl Namespace<'_> {
87 pub fn depth(&self) -> usize {
88 self.nodes.len()
89 }
90}
91
92#[derive(Debug, Clone, PartialEq, TypedBuilder)]
93pub struct Table<'a> {
94 pub ident: QualifiedIdent<'a>,
96 #[builder(default)]
97 pub fields: Vec<Field<'a>>,
98 #[builder(default)]
99 pub root_type: bool,
100 #[builder(default)]
101 pub doc: ast::Comment<'a>,
102}
103
104#[derive(Debug, Clone, PartialEq, TypedBuilder)]
105pub struct Struct<'a> {
106 pub ident: QualifiedIdent<'a>,
108 #[builder(default)]
109 pub fields: Vec<Field<'a>>,
110
111 #[builder(default)]
112 pub doc: ast::Comment<'a>,
113}
114
115#[derive(Debug, Clone, PartialEq, TypedBuilder)]
116pub struct Field<'a> {
117 pub ident: Ident<'a>,
119 pub ty: Type<'a>,
120 #[builder(default)]
121 pub default_value: Option<ast::DefaultValue<'a>>,
122 #[builder(default)]
123 pub metadata: FieldMetadata,
124
125 #[builder(default)]
126 pub doc: ast::Comment<'a>,
127}
128
129#[derive(Clone, Copy, Debug, Default, PartialEq, TypedBuilder)]
130pub struct FieldMetadata {
131 #[builder(default)]
132 pub required: bool,
133}
134
135#[derive(Debug, Clone, PartialEq)]
136pub enum Type<'a> {
137 Bool,
138 Byte,
139 UByte,
140 Short,
141 UShort,
142 Int,
143 UInt,
144 Float,
145 Long,
146 ULong,
147 Double,
148 Int8,
149 UInt8,
150 Int16,
151 UInt16,
152 Int32,
153 UInt32,
154 Int64,
155 UInt64,
156 Float32,
157 Float64,
158 String,
159 Array(Box<Type<'a>>),
160 Custom(CustomTypeRef<'a>),
161}
162
163impl<'a> Type<'a> {
164 pub fn is_scalar(&self) -> bool {
165 match self {
166 Type::String | Type::Array(..) => false,
172 Type::Custom(CustomTypeRef { ty, .. }) => match ty {
173 CustomType::Table | CustomType::Union { .. } => false,
176 CustomType::Struct { .. } | CustomType::Enum { .. } => true,
177 },
178 _ => true,
179 }
180 }
181
182 pub fn is_union(&self) -> bool {
183 match self {
184 Type::Custom(CustomTypeRef { ty, .. }) => match ty {
185 CustomType::Union { .. } => true,
186 _ => false,
187 },
188 _ => false,
189 }
190 }
191
192 pub fn is_enum(&self) -> bool {
193 match self {
194 Type::Custom(CustomTypeRef { ty, .. }) => match ty {
195 CustomType::Enum { .. } => true,
196 _ => false,
197 },
198 _ => false,
199 }
200 }
201
202 pub fn is_array(&self) -> bool {
203 match self {
204 Type::Array(..) => true,
205 _ => false,
206 }
207 }
208
209 pub fn is_complex(&self) -> bool {
211 self.is_array()
212 }
213
214 pub fn make_union_enum_type_companion(&self) -> Option<&QualifiedIdent<'a>> {
219 match self {
220 Type::Custom(CustomTypeRef { ty, .. }) => match ty {
221 CustomType::Union { ref enum_ident, .. } => Some(enum_ident),
222 _ => None,
223 },
224 _ => None,
225 }
226 }
227}
228
229impl Display for Type<'_> {
230 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
231 match self {
232 Type::Bool => write!(f, "bool"),
233 Type::Byte => write!(f, "i8"),
234 Type::UByte => write!(f, "u8"),
235 Type::Short => write!(f, "i16"),
236 Type::UShort => write!(f, "u16"),
237 Type::Int => write!(f, "i32"),
238 Type::UInt => write!(f, "u32"),
239 Type::Float => write!(f, "f32"),
240 Type::Long => write!(f, "i64"),
241 Type::ULong => write!(f, "u64"),
242 Type::Double => write!(f, "f64"),
243 Type::Int8 => write!(f, "i8"),
244 Type::UInt8 => write!(f, "u8"),
245 Type::Int16 => write!(f, "i16"),
246 Type::UInt16 => write!(f, "u16"),
247 Type::Int32 => write!(f, "i32"),
248 Type::UInt32 => write!(f, "u32"),
249 Type::Int64 => write!(f, "i64"),
250 Type::UInt64 => write!(f, "u64"),
251 Type::Float32 => write!(f, "f32"),
252 Type::Float64 => write!(f, "f64"),
253 Type::String => write!(f, "&str"),
254 Type::Array(component) => write!(f, "[{}]", component),
255 Type::Custom(CustomTypeRef { ident, .. }) => write!(f, "{}", ident),
256 }
257 }
258}
259
260#[derive(Debug, Clone, PartialEq, TypedBuilder)]
261pub struct CustomTypeRef<'a> {
262 pub ident: QualifiedIdent<'a>,
263 pub ty: CustomType<'a>,
264}
265
266#[derive(Debug, Clone, PartialEq)]
267pub enum CustomType<'a> {
268 Table,
269 Struct {
270 fields: Vec<Field<'a>>,
271 },
272 Enum {
273 variants: Vec<EnumVariant<'a>>,
274 base_type: EnumBaseType,
275 },
276 Union {
277 enum_ident: QualifiedIdent<'a>,
278 variants: Vec<UnionVariant<'a>>,
279 },
280}
281
282impl<'a> CustomType<'a> {
283 pub fn is_scalar(&self) -> bool {
284 match self {
285 CustomType::Struct { .. } | CustomType::Enum { .. } => true,
286 _ => false,
287 }
288 }
289}
290
291#[derive(Debug, Clone, PartialEq, TypedBuilder)]
292pub struct Enum<'a> {
293 pub ident: QualifiedIdent<'a>,
294 pub variants: Vec<EnumVariant<'a>>,
295 pub base_type: EnumBaseType,
296
297 #[builder(default)]
298 pub doc: ast::Comment<'a>,
299}
300
301#[derive(Debug, Copy, Clone, PartialEq, Eq)]
302pub enum EnumBaseType {
303 Byte,
304 UByte,
305 Short,
306 UShort,
307 Int,
308 UInt,
309 Long,
310 ULong,
311 Int8,
312 UInt8,
313 Int16,
314 UInt16,
315 Int32,
316 UInt32,
317 Int64,
318 UInt64,
319}
320
321impl<'a> std::convert::TryFrom<&ast::Type<'a>> for EnumBaseType {
322 type Error = ();
323 fn try_from(ty: &ast::Type<'a>) -> Result<Self, Self::Error> {
324 Ok(match ty {
325 ast::Type::Byte => EnumBaseType::Byte,
326 ast::Type::UByte => EnumBaseType::UByte,
327 ast::Type::Short => EnumBaseType::Short,
328 ast::Type::UShort => EnumBaseType::UShort,
329 ast::Type::Int => EnumBaseType::Int,
330 ast::Type::UInt => EnumBaseType::UInt,
331 ast::Type::Long => EnumBaseType::Long,
332 ast::Type::ULong => EnumBaseType::ULong,
333 ast::Type::Int8 => EnumBaseType::Int8,
334 ast::Type::UInt8 => EnumBaseType::UInt8,
335 ast::Type::Int16 => EnumBaseType::Int16,
336 ast::Type::UInt16 => EnumBaseType::UInt16,
337 ast::Type::Int32 => EnumBaseType::Int32,
338 ast::Type::UInt32 => EnumBaseType::UInt32,
339 ast::Type::Int64 => EnumBaseType::Int64,
340 ast::Type::UInt64 => EnumBaseType::UInt64,
341 _ => return Err(()),
342 })
343 }
344}
345
346#[derive(Debug, Clone, PartialEq, TypedBuilder)]
347pub struct Union<'a> {
348 pub ident: QualifiedIdent<'a>,
349 pub enum_ident: QualifiedIdent<'a>,
351 pub variants: Vec<UnionVariant<'a>>,
352
353 #[builder(default)]
354 pub doc: ast::Comment<'a>,
355}
356
357#[derive(Debug, Clone, PartialEq, TypedBuilder)]
359pub struct Rpc<'a> {
360 pub ident: QualifiedIdent<'a>,
361 pub methods: Vec<RpcMethod<'a>>,
362
363 #[builder(default)]
364 pub doc: ast::Comment<'a>,
365}
366
367#[derive(Debug, Clone, PartialEq, TypedBuilder)]
369pub struct RpcMethod<'a> {
370 pub ident: Ident<'a>,
372
373 pub snake_ident: Ident<'a>,
375
376 pub request_type: QualifiedIdent<'a>,
378
379 pub response_type: QualifiedIdent<'a>,
381
382 #[builder(default)]
384 pub metadata: RpcMethodMetadata,
385
386 #[builder(default)]
387 pub doc: ast::Comment<'a>,
388}
389
390#[derive(Clone, Copy, Debug, Default, PartialEq, TypedBuilder)]
391pub struct RpcMethodMetadata {
392 pub streaming: RpcStreaming,
393}
394
395#[derive(Clone, Copy, Debug, PartialEq)]
396pub enum RpcStreaming {
397 None,
398 Client,
399 Server,
400 Bidi,
401}
402
403impl Default for RpcStreaming {
404 fn default() -> Self {
405 Self::None
406 }
407}
408
409#[derive(Debug, Clone, PartialEq, Eq)]
410pub struct RootType<'a> {
411 _phantom: &'a (),
412}
413
414#[derive(Debug, Clone, PartialEq, Hash, Eq, From, TypedBuilder)]
416pub struct EnumVariant<'a> {
417 pub ident: Ident<'a>,
419
420 #[builder(default)]
422 pub value: Option<ast::IntegerConstant>,
423
424 #[builder(default)]
425 pub doc: ast::Comment<'a>,
426}
427
428#[derive(Debug, Clone, PartialEq, From, TypedBuilder)]
430pub struct UnionVariant<'a> {
431 pub ty: Type<'a>,
433 pub ident: Ident<'a>,
435
436 #[builder(default)]
437 pub doc: ast::Comment<'a>,
438}
439
440#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord, AsRef)]
445pub struct Ident<'a> {
446 pub raw: Cow<'a, str>,
447}
448
449impl<'a> Ident<'a> {
450 pub fn fix_identifier(ident: Cow<'_, str>) -> Cow<'_, str> {
453 if let Some(substitute) = super::keywords::substitute_keyword(ident.as_ref()) {
454 Cow::Borrowed(substitute)
455 } else {
456 ident
457 }
458 }
459
460 fn keyword(keyword: &str) -> Ident<'_> {
463 Ident {
464 raw: Cow::Borrowed(keyword),
465 }
466 }
467}
468
469impl<'a> From<ast::Ident<'a>> for Ident<'a> {
470 fn from(ident: ast::Ident<'a>) -> Self {
471 Ident::from(Cow::Borrowed(ident.raw))
472 }
473}
474
475impl<'a> From<&ast::Ident<'a>> for Ident<'a> {
476 fn from(ident: &ast::Ident<'a>) -> Self {
477 Ident::from(Cow::Borrowed(ident.raw))
478 }
479}
480impl<'a> From<&'a str> for Ident<'a> {
481 fn from(s: &'a str) -> Self {
482 Ident::from(Cow::Borrowed(s))
483 }
484}
485
486impl<'a> From<String> for Ident<'a> {
487 fn from(s: String) -> Self {
488 Ident::from(Cow::Owned(s))
489 }
490}
491
492impl<'a> From<Cow<'a, str>> for Ident<'a> {
493 fn from(raw: Cow<'a, str>) -> Self {
494 let raw = Ident::fix_identifier(raw);
495 Self { raw }
496 }
497}
498
499impl<'a> Display for Ident<'a> {
500 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
501 write!(f, "{}", self.raw.as_ref())
502 }
503}
504
505#[derive(Default, Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord, From)]
507pub struct QualifiedIdent<'a> {
508 pub parts: Vec<Ident<'a>>,
509}
510
511#[allow(clippy::len_without_is_empty)]
514impl<'a> QualifiedIdent<'a> {
515 pub fn len(&self) -> usize {
516 self.parts.len()
517 }
518
519 pub fn namespace(&self) -> Option<QualifiedIdent<'a>> {
520 if self.parts.len() > 1 {
521 Some(Self {
522 parts: self.parts[..self.parts.len() - 1].to_vec(),
523 })
524 } else {
525 None
526 }
527 }
528
529 pub fn relative(&self, namespace: Option<&QualifiedIdent<'a>>) -> QualifiedIdent<'a> {
530 if let Some(ns) = namespace {
531 let common_prefix_len = self
532 .parts
533 .iter()
534 .zip(ns.parts.iter())
535 .take_while(|(a, b)| a == b)
536 .count();
537
538 let parts = std::iter::repeat(Ident::keyword("super"))
539 .take(ns.len() - common_prefix_len)
540 .chain(self.parts[common_prefix_len..].to_vec())
541 .collect();
542 QualifiedIdent { parts }
543 } else {
544 self.clone()
545 }
546 }
547
548 pub fn simple(&self) -> &Ident<'a> {
549 &self.parts[self.parts.len() - 1]
550 }
551
552 #[cfg(test)]
556 pub fn parse_str(s: &'a str) -> Self {
557 QualifiedIdent {
558 parts: s
559 .split('.')
560 .map(|p| Ident {
561 raw: Cow::Borrowed(p),
562 })
563 .collect(),
564 }
565 }
566}
567
568impl<'a> From<&'a str> for QualifiedIdent<'a> {
569 fn from(s: &'a str) -> Self {
570 Self {
571 parts: vec![s.into()],
572 }
573 }
574}
575
576impl<'a> From<ast::QualifiedIdent<'a>> for QualifiedIdent<'a> {
577 fn from(ident: ast::QualifiedIdent<'a>) -> Self {
578 Self {
579 parts: ident.parts.into_iter().map(Into::into).collect(),
580 }
581 }
582}
583
584impl<'a> From<&ast::QualifiedIdent<'a>> for QualifiedIdent<'a> {
585 fn from(ident: &ast::QualifiedIdent<'a>) -> Self {
586 Self {
587 parts: ident.parts.iter().map(Into::into).collect(),
588 }
589 }
590}
591
592impl<'a> Display for QualifiedIdent<'a> {
593 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
594 use itertools::Itertools;
595 write!(f, "{}", self.parts.iter().join("."))
596 }
597}
598
599#[cfg(test)]
600mod tests {
601 use super::*;
602
603 #[test]
604 pub fn test_relative_ident_from_same_namespace() {
605 let id = QualifiedIdent::parse_str("foo.bar.Baz");
606 let ns = id.namespace(); let expected = QualifiedIdent::parse_str("Baz");
608 let actual = id.relative(ns.as_ref());
609
610 assert_eq!(expected, actual);
611 }
612
613 #[test]
614 pub fn test_relative_ident_from_root_namespace() {
615 let id = QualifiedIdent::parse_str("foo.bar.Baz");
616 let ns = None; let expected = id.clone(); let actual = id.relative(ns.as_ref());
619
620 assert_eq!(expected, actual);
621 }
622
623 #[test]
624 pub fn test_relative_ident_from_parent_namespace() {
625 let id = QualifiedIdent::parse_str("foo.bar.Baz");
626 let ns = Some(QualifiedIdent::parse_str("foo"));
627 let expected = QualifiedIdent::parse_str("bar.Baz");
628 let actual = id.relative(ns.as_ref());
629
630 assert_eq!(expected, actual);
631 }
632
633 #[test]
634 pub fn test_relative_ident_from_child_namespace() {
635 let id = QualifiedIdent::parse_str("foo.bar.Baz");
636 let ns = Some(QualifiedIdent::parse_str("foo.bar.bim"));
637 let expected = QualifiedIdent::parse_str("super.Baz");
638 let actual = id.relative(ns.as_ref());
639
640 assert_eq!(expected, actual);
641 }
642
643 #[test]
644 pub fn test_relative_ident_from_sibling_namespace() {
645 let id = QualifiedIdent::parse_str("foo.bar.bam.Baz");
646 let ns = Some(QualifiedIdent::parse_str("foo.bar.bim"));
647 let expected = QualifiedIdent::parse_str("super.bam.Baz");
648 let actual = id.relative(ns.as_ref());
649
650 assert_eq!(expected, actual);
651 }
652}