gruel_builtins/lib.rs
1//! Built-in type definitions for the Gruel compiler.
2//!
3//! This crate provides the registry of built-in types like `String`. These are
4//! types that behave like user-defined structs but have runtime implementations
5//! for their methods rather than generated code.
6//!
7//! # Architecture
8//!
9//! Built-in types are represented as "synthetic structs" — the compiler injects
10//! them as `StructDef` entries before processing user code. This allows them to
11//! flow through the same code paths as user-defined types, eliminating scattered
12//! special-case handling throughout the compiler.
13//!
14//! The injection happens in `Sema::inject_builtin_types()` during the declaration
15//! gathering phase. After injection:
16//!
17//! - The type is accessible by name (e.g., `String`)
18//! - Methods are registered and callable (e.g., `s.len()`)
19//! - Associated functions work (e.g., `String::new()`)
20//! - Operators are supported (e.g., `s1 == s2`)
21//! - Drop glue is automatically generated if `drop_fn` is set
22//!
23//! # Adding a New Built-in Type
24//!
25//! To add a new built-in type (e.g., `Vec<T>` when generics are available):
26//!
27//! ## Step 1: Define the Type
28//!
29//! Create a `BuiltinTypeDef` constant describing the type's structure:
30//!
31//! ```rust,ignore
32//! pub static VEC_TYPE: BuiltinTypeDef = BuiltinTypeDef {
33//! name: "Vec", // How users refer to it in source code
34//! fields: &[
35//! BuiltinField { name: "ptr", ty: BuiltinFieldType::U64 },
36//! BuiltinField { name: "len", ty: BuiltinFieldType::U64 },
37//! BuiltinField { name: "cap", ty: BuiltinFieldType::U64 },
38//! ],
39//! is_copy: false, // Vec owns heap memory, so it's a move type
40//! drop_fn: Some("__gruel_drop_Vec"), // Runtime destructor
41//! operators: &[
42//! // Vec might support equality if elements do
43//! ],
44//! associated_fns: &[
45//! BuiltinAssociatedFn {
46//! name: "new",
47//! params: &[],
48//! return_ty: BuiltinReturnType::SelfType,
49//! runtime_fn: "Vec__new",
50//! },
51//! BuiltinAssociatedFn {
52//! name: "with_capacity",
53//! params: &[BuiltinParam { name: "capacity", ty: BuiltinParamType::U64 }],
54//! return_ty: BuiltinReturnType::SelfType,
55//! runtime_fn: "Vec__with_capacity",
56//! },
57//! ],
58//! methods: &[
59//! BuiltinMethod {
60//! name: "len",
61//! receiver_mode: ReceiverMode::ByRef,
62//! params: &[],
63//! return_ty: BuiltinReturnType::U64,
64//! runtime_fn: "Vec__len",
65//! },
66//! BuiltinMethod {
67//! name: "push",
68//! receiver_mode: ReceiverMode::ByMutRef,
69//! params: &[BuiltinParam { name: "value", ty: BuiltinParamType::U64 }],
70//! return_ty: BuiltinReturnType::SelfType,
71//! runtime_fn: "Vec__push",
72//! },
73//! // ... more methods
74//! ],
75//! };
76//! ```
77//!
78//! ## Step 2: Register the Type
79//!
80//! Add it to the `BUILTIN_TYPES` slice:
81//!
82//! ```rust,ignore
83//! pub static BUILTIN_TYPES: &[&BuiltinTypeDef] = &[
84//! &STRING_TYPE,
85//! &VEC_TYPE, // Add new types here
86//! ];
87//! ```
88//!
89//! ## Step 3: Implement Runtime Functions
90//!
91//! In `gruel-runtime`, implement the functions referenced in the type definition:
92//!
93//! ```rust,ignore
94//! // In gruel-runtime/src/lib.rs or a new module
95//!
96//! #[unsafe(no_mangle)]
97//! pub extern "C" fn Vec__new(out: *mut u64) {
98//! // Initialize empty Vec at `out` pointer
99//! unsafe {
100//! *out = 0; // ptr = null
101//! *out.add(1) = 0; // len = 0
102//! *out.add(2) = 0; // cap = 0
103//! }
104//! }
105//!
106//! #[unsafe(no_mangle)]
107//! pub extern "C" fn __gruel_drop_Vec(ptr: *mut u64) {
108//! // Free the Vec's heap allocation if any
109//! unsafe {
110//! let data_ptr = *ptr as *mut u8;
111//! let cap = *ptr.add(2);
112//! if cap > 0 {
113//! __gruel_free(data_ptr, cap as usize);
114//! }
115//! }
116//! }
117//! ```
118//!
119//! ## Naming Conventions
120//!
121//! - **Associated functions**: `TypeName__function_name` (e.g., `String__new`)
122//! - **Methods**: `TypeName__method_name` (e.g., `String__len`)
123//! - **Drop functions**: `__gruel_drop_TypeName` (e.g., `__gruel_drop_String`)
124//! - **Operators**: `__gruel_typename_op` (e.g., `__gruel_str_eq`)
125//!
126//! ## Key Types
127//!
128//! - [`BuiltinTypeDef`]: Complete definition of a built-in type
129//! - [`BuiltinField`]: A field in the struct layout
130//! - [`BuiltinMethod`]: An instance method (takes `self`)
131//! - [`BuiltinAssociatedFn`]: A static function (e.g., `Type::new()`)
132//! - [`BuiltinOperator`]: Operator overload (e.g., `==`, `!=`)
133//! - [`ReceiverMode`]: How `self` is passed to methods
134//!
135//! See [`STRING_TYPE`] for a complete working example.
136
137/// Binary operators that can be overloaded for built-in types.
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139pub enum BinOp {
140 /// Equality: `==`
141 Eq,
142 /// Inequality: `!=`
143 Ne,
144 /// Less than: `<`
145 Lt,
146 /// Less than or equal: `<=`
147 Le,
148 /// Greater than: `>`
149 Gt,
150 /// Greater than or equal: `>=`
151 Ge,
152}
153
154/// Field type for built-in struct fields.
155///
156/// This is a simplified type representation for defining builtin struct layouts.
157/// It maps to actual `Type` variants during struct injection.
158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
159pub enum BuiltinFieldType {
160 /// 64-bit unsigned integer (used for pointers, lengths, capacities)
161 U64,
162 /// 8-bit unsigned integer
163 U8,
164 /// Boolean
165 Bool,
166}
167
168/// A field in a built-in struct.
169#[derive(Debug, Clone, Copy)]
170pub struct BuiltinField {
171 /// Field name
172 pub name: &'static str,
173 /// Field type
174 pub ty: BuiltinFieldType,
175}
176
177/// How the receiver is passed to a method.
178#[derive(Debug, Clone, Copy, PartialEq, Eq)]
179pub enum ReceiverMode {
180 /// Method takes ownership: `fn method(self)`
181 ByValue,
182 /// Method borrows: `fn method(&self)`
183 ByRef,
184 /// Method mutably borrows: `fn method(&mut self)`
185 ByMutRef,
186}
187
188/// A parameter to a built-in method or associated function.
189#[derive(Debug, Clone, Copy)]
190pub struct BuiltinParam {
191 /// Parameter name
192 pub name: &'static str,
193 /// Parameter type (simplified)
194 pub ty: BuiltinParamType,
195}
196
197/// Type of a parameter to a built-in function.
198#[derive(Debug, Clone, Copy, PartialEq, Eq)]
199pub enum BuiltinParamType {
200 /// 64-bit unsigned integer
201 U64,
202 /// 8-bit unsigned integer
203 U8,
204 /// Boolean
205 Bool,
206 /// The built-in type itself (e.g., String for String methods)
207 SelfType,
208}
209
210/// Return type of a built-in method.
211#[derive(Debug, Clone, Copy, PartialEq, Eq)]
212pub enum BuiltinReturnType {
213 /// No return value (unit type)
214 Unit,
215 /// 64-bit unsigned integer
216 U64,
217 /// 8-bit unsigned integer
218 U8,
219 /// Boolean (returned as u8: 0 or 1)
220 Bool,
221 /// Returns the built-in type itself
222 SelfType,
223}
224
225/// An operator overload for a built-in type.
226#[derive(Debug, Clone, Copy)]
227pub struct BuiltinOperator {
228 /// The operator being overloaded
229 pub op: BinOp,
230 /// Runtime function to call (e.g., `__gruel_str_eq`)
231 pub runtime_fn: &'static str,
232 /// Whether to invert the result (for `!=` using `==` implementation)
233 pub invert_result: bool,
234}
235
236/// An associated function on a built-in type (e.g., `String::new`).
237#[derive(Debug, Clone, Copy)]
238pub struct BuiltinAssociatedFn {
239 /// Function name (e.g., "new")
240 pub name: &'static str,
241 /// Parameters (excluding any implicit out pointer)
242 pub params: &'static [BuiltinParam],
243 /// Return type
244 pub return_ty: BuiltinReturnType,
245 /// Runtime function name (e.g., "String__new")
246 pub runtime_fn: &'static str,
247}
248
249/// An instance method on a built-in type (e.g., `s.len()`).
250#[derive(Debug, Clone, Copy)]
251pub struct BuiltinMethod {
252 /// Method name (e.g., "len")
253 pub name: &'static str,
254 /// How the receiver is passed
255 pub receiver_mode: ReceiverMode,
256 /// Additional parameters after self
257 pub params: &'static [BuiltinParam],
258 /// Return type
259 pub return_ty: BuiltinReturnType,
260 /// Runtime function name (e.g., "String__len")
261 pub runtime_fn: &'static str,
262}
263
264/// Definition of a built-in type.
265///
266/// This describes everything the compiler needs to know about a built-in type:
267/// its layout (fields), behavior (operators), and available operations (methods).
268#[derive(Debug, Clone)]
269pub struct BuiltinTypeDef {
270 /// Type name as it appears in source code (e.g., "String")
271 pub name: &'static str,
272 /// Fields that make up the struct layout
273 pub fields: &'static [BuiltinField],
274 /// Whether this type is Copy (can be implicitly duplicated)
275 pub is_copy: bool,
276 /// Runtime function to call for drop, if any
277 pub drop_fn: Option<&'static str>,
278 /// Supported operators and their implementations
279 pub operators: &'static [BuiltinOperator],
280 /// Associated functions (e.g., `String::new`)
281 pub associated_fns: &'static [BuiltinAssociatedFn],
282 /// Instance methods (e.g., `s.len()`)
283 pub methods: &'static [BuiltinMethod],
284}
285
286// ============================================================================
287// String Type Definition
288// ============================================================================
289
290/// The built-in String type.
291///
292/// Layout: `{ ptr: u64, len: u64, cap: u64 }` (24 bytes)
293///
294/// - `ptr`: Pointer to heap-allocated byte buffer (or .rodata for literals)
295/// - `len`: Current length in bytes
296/// - `cap`: Capacity of allocated buffer (0 for .rodata literals)
297///
298/// String is a move type (not Copy) because it owns heap-allocated memory.
299/// The drop function checks `cap > 0` before freeing, allowing .rodata
300/// literals (with `cap = 0`) to be safely dropped without freeing.
301pub static STRING_TYPE: BuiltinTypeDef = BuiltinTypeDef {
302 name: "String",
303 fields: &[
304 BuiltinField {
305 name: "ptr",
306 ty: BuiltinFieldType::U64,
307 },
308 BuiltinField {
309 name: "len",
310 ty: BuiltinFieldType::U64,
311 },
312 BuiltinField {
313 name: "cap",
314 ty: BuiltinFieldType::U64,
315 },
316 ],
317 is_copy: false,
318 drop_fn: Some("__gruel_drop_String"),
319 operators: &[
320 BuiltinOperator {
321 op: BinOp::Eq,
322 runtime_fn: "__gruel_str_eq",
323 invert_result: false,
324 },
325 BuiltinOperator {
326 op: BinOp::Ne,
327 runtime_fn: "__gruel_str_eq",
328 invert_result: true,
329 },
330 BuiltinOperator {
331 op: BinOp::Lt,
332 runtime_fn: "__gruel_str_cmp",
333 invert_result: false,
334 },
335 BuiltinOperator {
336 op: BinOp::Le,
337 runtime_fn: "__gruel_str_cmp",
338 invert_result: false,
339 },
340 BuiltinOperator {
341 op: BinOp::Gt,
342 runtime_fn: "__gruel_str_cmp",
343 invert_result: false,
344 },
345 BuiltinOperator {
346 op: BinOp::Ge,
347 runtime_fn: "__gruel_str_cmp",
348 invert_result: false,
349 },
350 ],
351 associated_fns: &[
352 BuiltinAssociatedFn {
353 name: "new",
354 params: &[],
355 return_ty: BuiltinReturnType::SelfType,
356 runtime_fn: "String__new",
357 },
358 BuiltinAssociatedFn {
359 name: "with_capacity",
360 params: &[BuiltinParam {
361 name: "capacity",
362 ty: BuiltinParamType::U64,
363 }],
364 return_ty: BuiltinReturnType::SelfType,
365 runtime_fn: "String__with_capacity",
366 },
367 ],
368 methods: &[
369 // Query methods (take &self)
370 BuiltinMethod {
371 name: "len",
372 receiver_mode: ReceiverMode::ByRef,
373 params: &[],
374 return_ty: BuiltinReturnType::U64,
375 runtime_fn: "String__len",
376 },
377 BuiltinMethod {
378 name: "capacity",
379 receiver_mode: ReceiverMode::ByRef,
380 params: &[],
381 return_ty: BuiltinReturnType::U64,
382 runtime_fn: "String__capacity",
383 },
384 BuiltinMethod {
385 name: "is_empty",
386 receiver_mode: ReceiverMode::ByRef,
387 params: &[],
388 return_ty: BuiltinReturnType::Bool,
389 runtime_fn: "String__is_empty",
390 },
391 BuiltinMethod {
392 name: "clone",
393 receiver_mode: ReceiverMode::ByRef,
394 params: &[],
395 return_ty: BuiltinReturnType::SelfType,
396 runtime_fn: "String__clone",
397 },
398 BuiltinMethod {
399 name: "contains",
400 receiver_mode: ReceiverMode::ByRef,
401 params: &[BuiltinParam {
402 name: "needle",
403 ty: BuiltinParamType::SelfType,
404 }],
405 return_ty: BuiltinReturnType::Bool,
406 runtime_fn: "String__contains",
407 },
408 BuiltinMethod {
409 name: "starts_with",
410 receiver_mode: ReceiverMode::ByRef,
411 params: &[BuiltinParam {
412 name: "prefix",
413 ty: BuiltinParamType::SelfType,
414 }],
415 return_ty: BuiltinReturnType::Bool,
416 runtime_fn: "String__starts_with",
417 },
418 BuiltinMethod {
419 name: "ends_with",
420 receiver_mode: ReceiverMode::ByRef,
421 params: &[BuiltinParam {
422 name: "suffix",
423 ty: BuiltinParamType::SelfType,
424 }],
425 return_ty: BuiltinReturnType::Bool,
426 runtime_fn: "String__ends_with",
427 },
428 BuiltinMethod {
429 name: "concat",
430 receiver_mode: ReceiverMode::ByRef,
431 params: &[BuiltinParam {
432 name: "other",
433 ty: BuiltinParamType::SelfType,
434 }],
435 return_ty: BuiltinReturnType::SelfType,
436 runtime_fn: "String__concat",
437 },
438 // Mutation methods (take &mut self, return modified String)
439 BuiltinMethod {
440 name: "push_str",
441 receiver_mode: ReceiverMode::ByMutRef,
442 params: &[BuiltinParam {
443 name: "other",
444 ty: BuiltinParamType::SelfType,
445 }],
446 return_ty: BuiltinReturnType::SelfType,
447 runtime_fn: "String__push_str",
448 },
449 BuiltinMethod {
450 name: "push",
451 receiver_mode: ReceiverMode::ByMutRef,
452 params: &[BuiltinParam {
453 name: "byte",
454 ty: BuiltinParamType::U8,
455 }],
456 return_ty: BuiltinReturnType::SelfType,
457 runtime_fn: "String__push",
458 },
459 BuiltinMethod {
460 name: "clear",
461 receiver_mode: ReceiverMode::ByMutRef,
462 params: &[],
463 return_ty: BuiltinReturnType::SelfType,
464 runtime_fn: "String__clear",
465 },
466 BuiltinMethod {
467 name: "reserve",
468 receiver_mode: ReceiverMode::ByMutRef,
469 params: &[BuiltinParam {
470 name: "additional",
471 ty: BuiltinParamType::U64,
472 }],
473 return_ty: BuiltinReturnType::SelfType,
474 runtime_fn: "String__reserve",
475 },
476 ],
477};
478
479// ============================================================================
480// Registry
481// ============================================================================
482
483/// All built-in types.
484///
485/// The compiler iterates over this to inject synthetic structs before
486/// processing user code.
487pub static BUILTIN_TYPES: &[&BuiltinTypeDef] = &[&STRING_TYPE];
488
489// ============================================================================
490// Built-in Enums (Target Platform)
491// ============================================================================
492
493/// Definition of a built-in enum type.
494///
495/// These are synthetic enums injected by the compiler before processing user code.
496/// They are used for compile-time platform detection via intrinsics like
497/// `@target_arch()` and `@target_os()`.
498#[derive(Debug, Clone)]
499pub struct BuiltinEnumDef {
500 /// Enum name as it appears in source code (e.g., "Arch")
501 pub name: &'static str,
502 /// Variant names in order (index matches variant_index in EnumVariant)
503 pub variants: &'static [&'static str],
504}
505
506/// The built-in Arch enum for CPU architecture detection.
507///
508/// Variants:
509/// - `X86_64` (index 0): x86-64 / AMD64
510/// - `Aarch64` (index 1): ARM64 / AArch64
511///
512/// Used with `@target_arch()` intrinsic for platform-specific code.
513pub static ARCH_ENUM: BuiltinEnumDef = BuiltinEnumDef {
514 name: "Arch",
515 variants: &["X86_64", "Aarch64"],
516};
517
518/// The built-in Os enum for operating system detection.
519///
520/// Variants:
521/// - `Linux` (index 0): Linux
522/// - `Macos` (index 1): macOS / Darwin
523///
524/// Used with `@target_os()` intrinsic for platform-specific code.
525pub static OS_ENUM: BuiltinEnumDef = BuiltinEnumDef {
526 name: "Os",
527 variants: &["Linux", "Macos"],
528};
529
530/// The built-in TypeKind enum for compile-time type reflection.
531///
532/// Variants represent different type classifications, used by `@typeInfo`.
533///
534/// Variants:
535/// - `Struct` (index 0): Struct types
536/// - `Enum` (index 1): Enum types
537/// - `Int` (index 2): Integer types (i8..i64, u8..u64)
538/// - `Bool` (index 3): Boolean type
539/// - `Unit` (index 4): Unit type
540/// - `Never` (index 5): Never type
541/// - `Array` (index 6): Fixed-size array types
542pub static TYPEKIND_ENUM: BuiltinEnumDef = BuiltinEnumDef {
543 name: "TypeKind",
544 variants: &["Struct", "Enum", "Int", "Bool", "Unit", "Never", "Array"],
545};
546
547/// All built-in enums.
548///
549/// The compiler iterates over this to inject synthetic enums before
550/// processing user code.
551pub static BUILTIN_ENUMS: &[&BuiltinEnumDef] = &[&ARCH_ENUM, &OS_ENUM, &TYPEKIND_ENUM];
552
553/// Look up a built-in enum by name.
554pub fn get_builtin_enum(name: &str) -> Option<&'static BuiltinEnumDef> {
555 BUILTIN_ENUMS.iter().find(|e| e.name == name).copied()
556}
557
558/// Check if a name is reserved for a built-in enum.
559pub fn is_reserved_enum_name(name: &str) -> bool {
560 BUILTIN_ENUMS.iter().any(|e| e.name == name)
561}
562
563/// Look up a built-in type by name.
564pub fn get_builtin_type(name: &str) -> Option<&'static BuiltinTypeDef> {
565 BUILTIN_TYPES.iter().find(|t| t.name == name).copied()
566}
567
568/// Check if a name is reserved for a built-in type.
569pub fn is_reserved_type_name(name: &str) -> bool {
570 BUILTIN_TYPES.iter().any(|t| t.name == name)
571}
572
573// ============================================================================
574// Helper methods
575// ============================================================================
576
577impl BuiltinTypeDef {
578 /// Get the number of slots this type uses in the ABI.
579 ///
580 /// Each field uses one slot (all fields are currently scalar types).
581 pub fn slot_count(&self) -> u32 {
582 self.fields.len() as u32
583 }
584
585 /// Find an associated function by name.
586 pub fn find_associated_fn(&self, name: &str) -> Option<&BuiltinAssociatedFn> {
587 self.associated_fns.iter().find(|f| f.name == name)
588 }
589
590 /// Find a method by name.
591 pub fn find_method(&self, name: &str) -> Option<&BuiltinMethod> {
592 self.methods.iter().find(|m| m.name == name)
593 }
594
595 /// Find an operator implementation.
596 pub fn find_operator(&self, op: BinOp) -> Option<&BuiltinOperator> {
597 self.operators.iter().find(|o| o.op == op)
598 }
599
600 /// Check if this type supports a given operator.
601 pub fn supports_operator(&self, op: BinOp) -> bool {
602 self.operators.iter().any(|o| o.op == op)
603 }
604}
605
606#[cfg(test)]
607mod tests {
608 use super::*;
609
610 #[test]
611 fn test_string_type_exists() {
612 assert_eq!(STRING_TYPE.name, "String");
613 assert_eq!(STRING_TYPE.fields.len(), 3);
614 assert!(!STRING_TYPE.is_copy);
615 assert_eq!(STRING_TYPE.drop_fn, Some("__gruel_drop_String"));
616 }
617
618 #[test]
619 fn test_string_slot_count() {
620 assert_eq!(STRING_TYPE.slot_count(), 3);
621 }
622
623 #[test]
624 fn test_string_associated_fns() {
625 let new_fn = STRING_TYPE.find_associated_fn("new").unwrap();
626 assert_eq!(new_fn.runtime_fn, "String__new");
627 assert!(new_fn.params.is_empty());
628
629 let with_cap = STRING_TYPE.find_associated_fn("with_capacity").unwrap();
630 assert_eq!(with_cap.runtime_fn, "String__with_capacity");
631 assert_eq!(with_cap.params.len(), 1);
632 }
633
634 #[test]
635 fn test_string_methods() {
636 let len = STRING_TYPE.find_method("len").unwrap();
637 assert_eq!(len.runtime_fn, "String__len");
638 assert_eq!(len.receiver_mode, ReceiverMode::ByRef);
639
640 let push_str = STRING_TYPE.find_method("push_str").unwrap();
641 assert_eq!(push_str.runtime_fn, "String__push_str");
642 assert_eq!(push_str.receiver_mode, ReceiverMode::ByMutRef);
643 }
644
645 #[test]
646 fn test_string_operators() {
647 assert!(STRING_TYPE.supports_operator(BinOp::Eq));
648 assert!(STRING_TYPE.supports_operator(BinOp::Ne));
649 assert!(STRING_TYPE.supports_operator(BinOp::Lt));
650 assert!(STRING_TYPE.supports_operator(BinOp::Gt));
651
652 let eq = STRING_TYPE.find_operator(BinOp::Eq).unwrap();
653 assert_eq!(eq.runtime_fn, "__gruel_str_eq");
654 assert!(!eq.invert_result);
655
656 let ne = STRING_TYPE.find_operator(BinOp::Ne).unwrap();
657 assert_eq!(ne.runtime_fn, "__gruel_str_eq");
658 assert!(ne.invert_result);
659 }
660
661 #[test]
662 fn test_get_builtin_type() {
663 assert!(get_builtin_type("String").is_some());
664 assert!(get_builtin_type("Vec").is_none());
665 }
666
667 #[test]
668 fn test_is_reserved_type_name() {
669 assert!(is_reserved_type_name("String"));
670 assert!(!is_reserved_type_name("MyStruct"));
671 }
672
673 #[test]
674 fn test_all_string_methods_present() {
675 // Verify all expected methods are defined
676 let expected_methods = [
677 "len",
678 "capacity",
679 "is_empty",
680 "clone",
681 "contains",
682 "starts_with",
683 "ends_with",
684 "concat",
685 "push_str",
686 "push",
687 "clear",
688 "reserve",
689 ];
690 for name in expected_methods {
691 assert!(
692 STRING_TYPE.find_method(name).is_some(),
693 "missing method: {}",
694 name
695 );
696 }
697 }
698
699 // ========================================================================
700 // Built-in Enum Tests
701 // ========================================================================
702
703 #[test]
704 fn test_arch_enum() {
705 assert_eq!(ARCH_ENUM.name, "Arch");
706 assert_eq!(ARCH_ENUM.variants.len(), 2);
707 assert_eq!(ARCH_ENUM.variants[0], "X86_64");
708 assert_eq!(ARCH_ENUM.variants[1], "Aarch64");
709 }
710
711 #[test]
712 fn test_os_enum() {
713 assert_eq!(OS_ENUM.name, "Os");
714 assert_eq!(OS_ENUM.variants.len(), 2);
715 assert_eq!(OS_ENUM.variants[0], "Linux");
716 assert_eq!(OS_ENUM.variants[1], "Macos");
717 }
718
719 #[test]
720 fn test_get_builtin_enum() {
721 assert!(get_builtin_enum("Arch").is_some());
722 assert!(get_builtin_enum("Os").is_some());
723 assert!(get_builtin_enum("Target").is_none());
724 }
725
726 #[test]
727 fn test_is_reserved_enum_name() {
728 assert!(is_reserved_enum_name("Arch"));
729 assert!(is_reserved_enum_name("Os"));
730 assert!(is_reserved_enum_name("TypeKind"));
731 assert!(!is_reserved_enum_name("MyEnum"));
732 }
733
734 #[test]
735 fn test_builtin_enums_count() {
736 assert_eq!(BUILTIN_ENUMS.len(), 3);
737 }
738}