webwire_cli/schema/
enum.rs1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::rc::Rc;
4
5use crate::common::FilePosition;
6use crate::idl;
7
8use super::errors::ValidationError;
9use super::fqtn::FQTN;
10use super::namespace::Namespace;
11use super::r#type::Type;
12use super::typemap::TypeMap;
13use super::TypeRef;
14
15#[derive(Clone)]
16pub struct Enum {
17 pub fqtn: FQTN,
18 pub generics: Vec<String>,
19 pub extends: Option<TypeRef>,
20 pub variants: Vec<EnumVariant>,
21 pub all_variants: Vec<EnumVariant>,
22}
23
24#[derive(Clone)]
25pub struct EnumVariant {
26 pub name: String,
27 pub value_type: Option<Type>,
28}
29
30impl Enum {
31 pub(crate) fn from_idl(
32 ienum: &idl::Enum,
33 ns: &Namespace,
34 builtin_types: &HashMap<String, String>,
35 ) -> Self {
36 let variants = ienum
37 .variants
38 .iter()
39 .map(|ivariant| EnumVariant {
40 name: ivariant.name.clone(),
41 value_type: ivariant
42 .value_type
43 .as_ref()
44 .map(|itype| Type::from_idl(itype, &ns, &builtin_types)),
45 })
46 .collect();
47 let extends = ienum
48 .extends
49 .as_ref()
50 .map(|itype| TypeRef::from_idl(itype, &ns, &builtin_types));
51 Self {
52 fqtn: FQTN::new(&ienum.name, ns),
53 generics: ienum.generics.clone(),
54 extends,
55 variants,
56 all_variants: Vec::new(),
57 }
58 }
59 pub(crate) fn resolve(&mut self, type_map: &TypeMap) -> Result<(), ValidationError> {
60 for variant in self.variants.iter_mut() {
61 if let Some(typeref) = &mut variant.value_type {
62 typeref.resolve(type_map)?;
63 }
64 }
65 if let Some(extends) = &mut self.extends {
66 extends.resolve(type_map)?;
67 }
68 self.all_variants.extend(self.resolve_extends()?);
69 Ok(())
70 }
71 fn resolve_extends(&self) -> Result<Vec<EnumVariant>, ValidationError> {
72 let mut variants = self.variants.clone();
73 if let Some(extends) = &self.extends {
74 if let TypeRef::Enum(extends_enum) = extends {
75 variants.extend(
76 extends_enum
77 .enum_
78 .upgrade()
79 .unwrap()
80 .borrow()
81 .resolve_extends()?,
82 );
83 } else {
84 return Err(ValidationError::EnumExtendsNonEnum {
85 position: FilePosition { line: 0, column: 0 },
86 r#enum: self.fqtn.clone(),
87 extends: extends.fqtn(),
88 });
89 }
90 }
91 Ok(variants)
92 }
93 pub fn extends_enum(&self) -> Option<Rc<RefCell<Enum>>> {
94 if let Some(extends) = &self.extends {
95 if let TypeRef::Enum(extends) = extends {
96 Some(extends.enum_.upgrade().unwrap())
97 } else {
98 None
99 }
100 } else {
101 None
102 }
103 }
104}
105
106#[test]
107fn test_schema_enum_extends() {
108 let idl = r"
109 enum Foo { Foo }
110 enum Bar extends Foo { Bar }
111 ";
112 let idoc = crate::idl::parse_document(idl).unwrap();
113 let idocs = vec![idoc];
114 let builtin_types = HashMap::default();
115 let doc = crate::schema::Document::from_idl(idocs.iter(), &builtin_types).unwrap();
116 let foo = doc.ns.types.get("Bar").unwrap();
117 match foo {
118 crate::schema::UserDefinedType::Enum(enum_) => {
119 assert!(enum_.borrow().extends.is_some());
120 }
121 _ => unreachable!(),
122 }
123}
124
125#[test]
126fn test_schema_enum_extends_different_namespace() {
127 let idl = r"
128 enum Foo { Foo }
129 namespace bar {
130 enum Bar extends ::Foo { Bar }
131 }
132 namespace baz {
133 enum Baz extends ::bar::Bar { Baz }
134 }
135 ";
136 let idoc = crate::idl::parse_document(idl).unwrap();
137 let idocs = vec![idoc];
138 let builtin_types = HashMap::default();
139 let doc = crate::schema::Document::from_idl(idocs.iter(), &builtin_types).unwrap();
140 let bar_ns = doc.ns.namespaces.get("bar").unwrap();
141 let bar_type = bar_ns.types.get("Bar").unwrap();
142 match bar_type {
143 crate::schema::UserDefinedType::Enum(enum_) => {
144 assert!(enum_.borrow().extends.is_some());
145 }
146 _ => unreachable!(),
147 }
148 let baz_ns = doc.ns.namespaces.get("baz").unwrap();
149 let baz_type = baz_ns.types.get("Baz").unwrap();
150 match baz_type {
151 crate::schema::UserDefinedType::Enum(enum_) => {
152 assert!(enum_.borrow().extends.is_some());
153 }
154 _ => unreachable!(),
155 }
156}