1use core::fmt;
4
5use super::{CustomEnum, CustomObject};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum CustomType<'a> {
13 Object(CustomObject<'a>),
15 Enum(CustomEnum<'a>),
17}
18
19impl<'a> CustomType<'a> {
20 pub fn name(&self) -> &'a str {
22 match self {
23 CustomType::Object(obj) => obj.name(),
24 CustomType::Enum(enm) => enm.name(),
25 }
26 }
27
28 pub fn is_object(&self) -> bool {
30 matches!(self, CustomType::Object(_))
31 }
32
33 pub fn is_enum(&self) -> bool {
35 matches!(self, CustomType::Enum(_))
36 }
37
38 pub const fn as_object(&self) -> Option<&CustomObject<'a>> {
40 match self {
41 CustomType::Object(obj) => Some(obj),
42 CustomType::Enum(_) => None,
43 }
44 }
45
46 pub fn as_enum(&self) -> Option<&CustomEnum<'a>> {
48 match self {
49 CustomType::Object(_) => None,
50 CustomType::Enum(enm) => Some(enm),
51 }
52 }
53}
54
55impl<'a> From<CustomObject<'a>> for CustomType<'a> {
56 fn from(obj: CustomObject<'a>) -> Self {
57 CustomType::Object(obj)
58 }
59}
60
61impl<'a> From<CustomEnum<'a>> for CustomType<'a> {
62 fn from(enm: CustomEnum<'a>) -> Self {
63 CustomType::Enum(enm)
64 }
65}
66
67impl<'a> fmt::Display for CustomType<'a> {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 match self {
70 CustomType::Object(obj) => write!(f, "{obj}"),
71 CustomType::Enum(enm) => write!(f, "{enm}"),
72 }
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use alloc::vec;
79
80 use super::*;
81 use crate::{EnumVariant, Field, Type};
82
83 #[test]
84 fn object_creation() {
85 let field_x = Field::new("x", &Type::Float, &[]);
86 let field_y = Field::new("y", &Type::Float, &[]);
87 let fields = [&field_x, &field_y];
88
89 let custom_obj = CustomObject::new("Point", &fields, &[]);
90 assert_eq!(custom_obj.name(), "Point");
91 assert_eq!(custom_obj.fields().count(), 2);
92
93 let fields = custom_obj.fields().collect::<Vec<_>>();
95 assert_eq!(fields[0].name(), "x");
96 assert_eq!(fields[0].ty(), &Type::Float);
97 assert_eq!(fields[1].name(), "y");
98 assert_eq!(fields[1].ty(), &Type::Float);
99 }
100
101 #[test]
102 fn enum_creation() {
103 let red = EnumVariant::new_owned("red", vec![]);
104 let green = EnumVariant::new_owned("green", vec![]);
105 let blue = EnumVariant::new_owned("blue", vec![]);
106 let custom_enum = CustomEnum::new_owned("Color", vec![red, green, blue], vec![]);
107
108 assert_eq!(custom_enum.name(), "Color");
109 assert_eq!(custom_enum.variants().count(), 3);
110
111 let variants = custom_enum.variants().collect::<Vec<_>>();
113 assert_eq!(variants[0].name(), "red");
114 assert_eq!(variants[1].name(), "green");
115 assert_eq!(variants[2].name(), "blue");
116 }
117
118 #[test]
119 fn type_from_object() {
120 let field_x = Field::new("x", &Type::Float, &[]);
121 let field_y = Field::new("y", &Type::Float, &[]);
122 let fields = [&field_x, &field_y];
123
124 let custom_obj = CustomObject::new("Point", &fields, &[]);
125 let custom_type = CustomType::from(custom_obj);
126
127 assert_eq!(custom_type.name(), "Point");
128 assert!(custom_type.is_object());
129 assert!(!custom_type.is_enum());
130 assert!(custom_type.as_object().is_some());
131 assert!(custom_type.as_enum().is_none());
132 }
133
134 #[test]
135 fn type_from_enum() {
136 let red = EnumVariant::new_owned("red", vec![]);
137 let green = EnumVariant::new_owned("green", vec![]);
138 let blue = EnumVariant::new_owned("blue", vec![]);
139 let custom_enum = CustomEnum::new_owned("Color", vec![red, green, blue], vec![]);
140 let custom_type = CustomType::from(custom_enum);
141
142 assert_eq!(custom_type.name(), "Color");
143 assert!(!custom_type.is_object());
144 assert!(custom_type.is_enum());
145 assert!(custom_type.as_object().is_none());
146 assert!(custom_type.as_enum().is_some());
147 }
148
149 #[test]
150 fn type_display_object() {
151 let field_x = Field::new("x", &Type::Int, &[]);
153 let field_y = Field::new("y", &Type::Int, &[]);
154 let fields = [&field_x, &field_y];
155 let custom_obj = CustomObject::new("Point", &fields, &[]);
156 let custom_type = CustomType::from(custom_obj);
157 use core::fmt::Write;
158 let mut buf = String::new();
159 write!(buf, "{}", custom_type).unwrap();
160 assert_eq!(buf.as_str(), "type Point (x: int, y: int)");
161 }
162
163 #[test]
164 fn type_display_enum() {
165 const DIRECTION_VARIANTS: &[&EnumVariant<'static>] = &[
167 &EnumVariant::new("north", &[]),
168 &EnumVariant::new("south", &[]),
169 &EnumVariant::new("east", &[]),
170 &EnumVariant::new("west", &[]),
171 ];
172 let custom_enum = CustomEnum::new("Direction", DIRECTION_VARIANTS, &[]);
173 let custom_type = CustomType::from(custom_enum);
174 use core::fmt::Write;
175 let mut buf = String::new();
176 write!(buf, "{}", custom_type).unwrap();
177 assert_eq!(buf.as_str(), "type Direction (north, south, east, west)");
178 }
179
180 #[test]
181 fn owned_types() {
182 let fields = vec![
184 Field::new("name", &Type::String, &[]),
185 Field::new("age", &Type::Int, &[]),
186 ];
187 let custom_obj = CustomObject::new_owned("Person", fields, vec![]);
188 assert_eq!(custom_obj.name(), "Person");
189 use core::fmt::Write;
190 let mut buf = String::new();
191 write!(buf, "{}", custom_obj).unwrap();
192 assert_eq!(buf.as_str(), "type Person (name: string, age: int)");
193
194 let custom_enum = CustomEnum::new_owned(
196 "Size",
197 vec![
198 EnumVariant::new_owned("small", vec![]),
199 EnumVariant::new_owned("medium", vec![]),
200 EnumVariant::new_owned("large", vec![]),
201 ],
202 vec![],
203 );
204 assert_eq!(custom_enum.name(), "Size");
205 let mut buf = String::new();
206 write!(buf, "{}", custom_enum).unwrap();
207 assert_eq!(buf.as_str(), "type Size (small, medium, large)");
208 }
209}