1use serde::{Deserialize, Serialize};
17use std::hash::Hash;
18
19#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
28pub struct Arena {
29 pub name: String,
31 pub types: Vec<TypeDef>,
33 pub functions: Vec<Function>,
35 pub children: Vec<Arena>,
37}
38
39impl Arena {
40 pub fn new(name: impl Into<String>) -> Self {
42 Self {
43 name: name.into(),
44 types: Vec::new(),
45 functions: Vec::new(),
46 children: Vec::new(),
47 }
48 }
49
50 pub fn add_type(&mut self, typedef: TypeDef) {
52 self.types.push(typedef);
53 }
54
55 pub fn add_function(&mut self, func: Function) {
57 self.functions.push(func);
58 }
59
60 pub fn add_child(&mut self, child: Arena) {
62 self.children.push(child);
63 }
64
65 pub fn find_type(&self, name: &str) -> Option<&TypeDef> {
67 self.types.iter().find(|t| t.name() == name)
68 }
69
70 pub fn find_function(&self, name: &str) -> Option<&Function> {
72 self.functions.iter().find(|f| f.name == name)
73 }
74
75 pub fn imports(&self) -> Vec<Function> {
80 self.children
81 .iter()
82 .find(|c| c.name == "imports")
83 .map(|imports_arena| {
84 imports_arena
85 .children
86 .iter()
87 .flat_map(|interface| {
88 interface.functions.iter().map(|f| {
89 let mut func = f.clone();
90 func.interface = interface.name.clone();
91 func
92 })
93 })
94 .collect()
95 })
96 .unwrap_or_default()
97 }
98
99 pub fn exports(&self) -> Vec<Function> {
104 self.children
105 .iter()
106 .find(|c| c.name == "exports")
107 .map(|exports_arena| {
108 exports_arena
109 .children
110 .iter()
111 .flat_map(|interface| {
112 interface.functions.iter().map(|f| {
113 let mut func = f.clone();
114 func.interface = interface.name.clone();
115 func
116 })
117 })
118 .collect()
119 })
120 .unwrap_or_default()
121 }
122
123 pub fn imported_function_names(&self, interface_name: &str) -> Vec<String> {
128 self.imports()
129 .into_iter()
130 .filter(|f| f.interface == interface_name)
131 .map(|f| f.name)
132 .collect()
133 }
134
135 pub fn exported_function_names(&self, interface_name: &str) -> Vec<String> {
137 self.exports()
138 .into_iter()
139 .filter(|f| f.interface == interface_name)
140 .map(|f| f.name)
141 .collect()
142 }
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
151pub struct Function {
152 pub name: String,
154 #[serde(default)]
156 pub interface: String,
157 pub types: Vec<TypeDef>,
159 pub params: Vec<Param>,
161 pub results: Vec<Type>,
163}
164
165impl Function {
166 pub fn new(name: impl Into<String>) -> Self {
168 Self {
169 name: name.into(),
170 interface: String::new(),
171 types: Vec::new(),
172 params: Vec::new(),
173 results: Vec::new(),
174 }
175 }
176
177 pub fn with_signature(name: impl Into<String>, params: Vec<Param>, results: Vec<Type>) -> Self {
179 Self {
180 name: name.into(),
181 interface: String::new(),
182 types: Vec::new(),
183 params,
184 results,
185 }
186 }
187
188 pub fn with_interface(
190 name: impl Into<String>,
191 interface: impl Into<String>,
192 params: Vec<Param>,
193 results: Vec<Type>,
194 ) -> Self {
195 Self {
196 name: name.into(),
197 interface: interface.into(),
198 types: Vec::new(),
199 params,
200 results,
201 }
202 }
203}
204
205#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
207pub struct Param {
208 pub name: String,
210 pub ty: Type,
212}
213
214impl Param {
215 pub fn new(name: impl Into<String>, ty: Type) -> Self {
217 Self {
218 name: name.into(),
219 ty,
220 }
221 }
222}
223
224#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
230pub enum TypeDef {
231 Alias { name: String, ty: Type },
233
234 Record { name: String, fields: Vec<Field> },
236
237 Variant { name: String, cases: Vec<Case> },
239
240 Enum { name: String, cases: Vec<String> },
242
243 Flags { name: String, flags: Vec<String> },
245}
246
247impl TypeDef {
248 pub fn name(&self) -> &str {
250 match self {
251 TypeDef::Alias { name, .. } => name,
252 TypeDef::Record { name, .. } => name,
253 TypeDef::Variant { name, .. } => name,
254 TypeDef::Enum { name, .. } => name,
255 TypeDef::Flags { name, .. } => name,
256 }
257 }
258
259 pub fn alias(name: impl Into<String>, ty: Type) -> Self {
261 TypeDef::Alias {
262 name: name.into(),
263 ty,
264 }
265 }
266
267 pub fn record(name: impl Into<String>, fields: Vec<Field>) -> Self {
269 TypeDef::Record {
270 name: name.into(),
271 fields,
272 }
273 }
274
275 pub fn variant(name: impl Into<String>, cases: Vec<Case>) -> Self {
277 TypeDef::Variant {
278 name: name.into(),
279 cases,
280 }
281 }
282
283 pub fn enumeration(name: impl Into<String>, cases: Vec<String>) -> Self {
285 TypeDef::Enum {
286 name: name.into(),
287 cases,
288 }
289 }
290
291 pub fn flags(name: impl Into<String>, flags: Vec<String>) -> Self {
293 TypeDef::Flags {
294 name: name.into(),
295 flags,
296 }
297 }
298}
299
300#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
302pub struct Field {
303 pub name: String,
305 pub ty: Type,
307}
308
309impl Field {
310 pub fn new(name: impl Into<String>, ty: Type) -> Self {
312 Self {
313 name: name.into(),
314 ty,
315 }
316 }
317}
318
319#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
321pub struct Case {
322 pub name: String,
324 pub payload: Type,
326}
327
328impl Case {
329 pub fn new(name: impl Into<String>, payload: Type) -> Self {
331 Self {
332 name: name.into(),
333 payload,
334 }
335 }
336
337 pub fn unit(name: impl Into<String>) -> Self {
339 Self {
340 name: name.into(),
341 payload: Type::Unit,
342 }
343 }
344}
345
346#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
355pub enum Type {
356 Unit,
358
359 Bool,
361 U8,
362 U16,
363 U32,
364 U64,
365 S8,
366 S16,
367 S32,
368 S64,
369 F32,
370 F64,
371 Char,
372 String,
373
374 List(Box<Type>),
376 Option(Box<Type>),
377 Result { ok: Box<Type>, err: Box<Type> },
378 Tuple(Vec<Type>),
379
380 Ref(TypePath),
382
383 Value,
385}
386
387impl Type {
388 pub fn list(inner: Type) -> Self {
390 Type::List(Box::new(inner))
391 }
392
393 pub fn option(inner: Type) -> Self {
395 Type::Option(Box::new(inner))
396 }
397
398 pub fn result(ok: Type, err: Type) -> Self {
400 Type::Result {
401 ok: Box::new(ok),
402 err: Box::new(err),
403 }
404 }
405
406 pub fn tuple(types: Vec<Type>) -> Self {
408 Type::Tuple(types)
409 }
410
411 pub fn named(name: impl Into<String>) -> Self {
413 Type::Ref(TypePath::simple(name))
414 }
415
416 pub fn self_ref() -> Self {
419 Type::Ref(TypePath::self_ref())
420 }
421
422 pub fn is_unit(&self) -> bool {
424 matches!(self, Type::Unit)
425 }
426
427 pub fn is_self_ref(&self) -> bool {
429 matches!(self, Type::Ref(path) if path.is_self_ref())
430 }
431
432 pub fn contains_recursion(&self) -> bool {
434 match self {
435 Type::Ref(path) if path.is_self_ref() => true,
436 Type::List(inner) | Type::Option(inner) => inner.contains_recursion(),
437 Type::Result { ok, err } => ok.contains_recursion() || err.contains_recursion(),
438 Type::Tuple(types) => types.iter().any(|t| t.contains_recursion()),
439 _ => false,
440 }
441 }
442}
443
444#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
455pub struct TypePath {
456 pub segments: Vec<String>,
458 pub absolute: bool,
460}
461
462impl TypePath {
463 pub fn simple(name: impl Into<String>) -> Self {
465 Self {
466 segments: vec![name.into()],
467 absolute: false,
468 }
469 }
470
471 pub fn absolute(segments: Vec<String>) -> Self {
473 Self {
474 segments,
475 absolute: true,
476 }
477 }
478
479 pub fn relative(segments: Vec<String>) -> Self {
481 Self {
482 segments,
483 absolute: false,
484 }
485 }
486
487 pub fn self_ref() -> Self {
489 Self {
490 segments: Vec::new(),
491 absolute: false,
492 }
493 }
494
495 pub fn is_self_ref(&self) -> bool {
497 self.segments.is_empty() && !self.absolute
498 }
499
500 pub fn is_simple(&self) -> bool {
502 self.segments.len() == 1 && !self.absolute
503 }
504
505 pub fn as_simple(&self) -> Option<&str> {
507 if self.is_simple() {
508 self.segments.first().map(|s| s.as_str())
509 } else {
510 None
511 }
512 }
513
514 pub fn name(&self) -> Option<&str> {
516 self.segments.last().map(|s| s.as_str())
517 }
518}
519
520impl std::fmt::Display for TypePath {
521 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
522 if self.is_self_ref() {
523 write!(f, "self")
524 } else if self.absolute {
525 write!(f, "::{}", self.segments.join("::"))
526 } else {
527 write!(f, "{}", self.segments.join("::"))
528 }
529 }
530}
531
532pub fn sexpr_type() -> TypeDef {
538 TypeDef::Variant {
539 name: "sexpr".to_string(),
540 cases: vec![
541 Case::new("sym", Type::String),
542 Case::new("num", Type::S64),
543 Case::new("flt", Type::F64),
544 Case::new("str", Type::String),
545 Case::new("lst", Type::list(Type::self_ref())),
546 ],
547 }
548}
549
550#[cfg(test)]
564mod tests {
565 use super::*;
566 use std::collections::HashSet;
567
568 #[test]
569 fn test_arena_creation() {
570 let mut arena = Arena::new("test");
571 arena.add_type(TypeDef::alias("count", Type::U32));
572 arena.add_function(Function::with_signature(
573 "add",
574 vec![Param::new("a", Type::S32), Param::new("b", Type::S32)],
575 vec![Type::S32],
576 ));
577
578 assert_eq!(arena.name, "test");
579 assert_eq!(arena.types.len(), 1);
580 assert_eq!(arena.functions.len(), 1);
581 assert!(arena.find_type("count").is_some());
582 assert!(arena.find_function("add").is_some());
583 }
584
585 #[test]
586 fn test_type_path() {
587 let simple = TypePath::simple("expr");
588 assert!(simple.is_simple());
589 assert_eq!(simple.as_simple(), Some("expr"));
590 assert!(!simple.is_self_ref());
591
592 let self_ref = TypePath::self_ref();
593 assert!(self_ref.is_self_ref());
594 assert!(!self_ref.is_simple());
595
596 let absolute = TypePath::absolute(vec!["wasi".into(), "cli".into(), "stdout".into()]);
597 assert!(absolute.absolute);
598 assert_eq!(absolute.name(), Some("stdout"));
599 }
600
601 #[test]
602 fn test_sexpr_type() {
603 let sexpr = sexpr_type();
604 assert_eq!(sexpr.name(), "sexpr");
605 if let TypeDef::Variant { cases, .. } = &sexpr {
606 assert_eq!(cases.len(), 5);
607 assert_eq!(cases[0].name, "sym");
608 assert_eq!(cases[4].name, "lst");
609 if let Type::List(inner) = &cases[4].payload {
611 assert!(inner.is_self_ref());
612 } else {
613 panic!("Expected list type");
614 }
615 } else {
616 panic!("Expected variant");
617 }
618 }
619
620 #[test]
621 fn test_contains_recursion() {
622 assert!(Type::self_ref().contains_recursion());
623 assert!(Type::list(Type::self_ref()).contains_recursion());
624 assert!(!Type::list(Type::S32).contains_recursion());
625 assert!(!Type::String.contains_recursion());
626 assert!(Type::result(Type::self_ref(), Type::String).contains_recursion());
627 }
628
629 #[test]
630 fn test_type_hashing() {
631 let mut set = HashSet::new();
632
633 set.insert(Type::S32);
635 assert!(!set.insert(Type::S32)); assert!(set.insert(Type::S64));
639 assert!(set.insert(Type::String));
640 assert!(set.insert(Type::list(Type::S32)));
641 }
642
643 #[test]
644 fn test_arena_hashing() {
645 let mut set = HashSet::new();
646
647 let arena1 = Arena::new("test");
648 let arena2 = Arena::new("test");
649 let arena3 = Arena::new("other");
650
651 set.insert(arena1.clone());
652 assert!(!set.insert(arena2)); assert!(set.insert(arena3)); }
655
656 #[test]
657 fn test_typedef_name() {
658 assert_eq!(TypeDef::alias("foo", Type::S32).name(), "foo");
659 assert_eq!(TypeDef::record("bar", vec![]).name(), "bar");
660 assert_eq!(TypeDef::variant("baz", vec![]).name(), "baz");
661 assert_eq!(TypeDef::enumeration("qux", vec![]).name(), "qux");
662 assert_eq!(TypeDef::flags("quux", vec![]).name(), "quux");
663 }
664
665 #[test]
666 fn test_case_constructors() {
667 let with_payload = Case::new("data", Type::String);
668 assert_eq!(with_payload.name, "data");
669 assert_eq!(with_payload.payload, Type::String);
670
671 let without_payload = Case::unit("empty");
672 assert_eq!(without_payload.name, "empty");
673 assert_eq!(without_payload.payload, Type::Unit);
674 }
675
676 #[test]
677 fn test_unit_type() {
678 assert!(Type::Unit.is_unit());
679 assert!(!Type::S32.is_unit());
680 assert!(!Type::String.is_unit());
681 }
682
683 #[test]
684 fn test_type_display() {
685 assert_eq!(TypePath::self_ref().to_string(), "self");
686 assert_eq!(TypePath::simple("expr").to_string(), "expr");
687 assert_eq!(
688 TypePath::absolute(vec!["wasi".into(), "cli".into()]).to_string(),
689 "::wasi::cli"
690 );
691 }
692}