wasm_wave/wasm/
fmt.rs

1use std::fmt::Display;
2
3use crate::{
4    WasmValue,
5    wasm::{WasmFunc, WasmType, WasmTypeKind},
6    writer::Writer,
7};
8
9/// Implements a WAVE-formatted [`Display`] for a [`WasmType`].
10pub struct DisplayType<'a, T: WasmType>(pub &'a T);
11
12impl<T: WasmType> Display for DisplayType<'_, T> {
13    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14        let ty = self.0;
15        match ty.kind() {
16            WasmTypeKind::List => {
17                write!(f, "list<{}>", DisplayType(&ty.list_element_type().unwrap()))
18            }
19            WasmTypeKind::Record => {
20                f.write_str("record { ")?;
21                for (idx, (name, field_type)) in ty.record_fields().enumerate() {
22                    if idx != 0 {
23                        f.write_str(", ")?;
24                    }
25                    write!(f, "{name}: {}", DisplayType(&field_type))?;
26                }
27                f.write_str(" }")
28            }
29            WasmTypeKind::Tuple => {
30                f.write_str("tuple<")?;
31                for (idx, ty) in ty.tuple_element_types().enumerate() {
32                    if idx != 0 {
33                        f.write_str(", ")?;
34                    }
35                    write!(f, "{}", DisplayType(&ty))?;
36                }
37                f.write_str(">")
38            }
39            WasmTypeKind::Variant => {
40                f.write_str("variant { ")?;
41                for (idx, (name, payload)) in ty.variant_cases().enumerate() {
42                    if idx != 0 {
43                        f.write_str(", ")?;
44                    }
45                    f.write_str(name.as_ref())?;
46                    if let Some(ty) = payload {
47                        write!(f, "({})", DisplayType(&ty))?;
48                    }
49                }
50                f.write_str(" }")
51            }
52            WasmTypeKind::Enum => {
53                f.write_str("enum { ")?;
54                for (idx, name) in ty.enum_cases().enumerate() {
55                    if idx != 0 {
56                        f.write_str(", ")?;
57                    }
58                    f.write_str(name.as_ref())?;
59                }
60                f.write_str(" }")
61            }
62            WasmTypeKind::Option => {
63                write!(
64                    f,
65                    "option<{}>",
66                    DisplayType(&ty.option_some_type().unwrap())
67                )
68            }
69            WasmTypeKind::Result => {
70                f.write_str("result")?;
71                match ty.result_types().unwrap() {
72                    (None, None) => Ok(()),
73                    (None, Some(err)) => write!(f, "<_, {}>", DisplayType(&err)),
74                    (Some(ok), None) => write!(f, "<{}>", DisplayType(&ok)),
75                    (Some(ok), Some(err)) => {
76                        write!(f, "<{}, {}>", DisplayType(&ok), DisplayType(&err))
77                    }
78                }
79            }
80            WasmTypeKind::Flags => {
81                f.write_str("flags { ")?;
82                for (idx, name) in ty.flags_names().enumerate() {
83                    if idx != 0 {
84                        f.write_str(", ")?;
85                    }
86                    f.write_str(name.as_ref())?;
87                }
88                f.write_str(" }")
89            }
90            simple => Display::fmt(&simple, f),
91        }
92    }
93}
94
95/// Implements a WAVE-formatted [`Display`] for a [`WasmValue`].
96pub struct DisplayValue<'a, T: WasmValue>(pub &'a T);
97
98impl<T: WasmValue> Display for DisplayValue<'_, T> {
99    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100        let mut buf = vec![];
101        Writer::new(&mut buf)
102            .write_value(self.0)
103            .map_err(|_| std::fmt::Error)?;
104        f.write_str(String::from_utf8_lossy(&buf).as_ref())
105    }
106}
107
108/// Implements a WAVE-formatted [`Display`] for a [`WasmFunc`].
109pub struct DisplayFunc<T: WasmFunc>(pub T);
110
111impl<T: WasmFunc> Display for DisplayFunc<T> {
112    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113        f.write_str("func(")?;
114        let mut param_names = self.0.param_names();
115        for (idx, ty) in self.0.params().enumerate() {
116            if idx != 0 {
117                f.write_str(", ")?;
118            }
119            if let Some(name) = param_names.next() {
120                write!(f, "{name}: ")?;
121            }
122            DisplayType(&ty).fmt(f)?
123        }
124        f.write_str(")")?;
125
126        let results = self.0.results().collect::<Vec<_>>();
127        if results.is_empty() {
128            return Ok(());
129        }
130
131        let mut result_names = self.0.result_names();
132        if results.len() == 1 {
133            let ty = DisplayType(&results.into_iter().next().unwrap()).to_string();
134            if let Some(name) = result_names.next() {
135                write!(f, " -> ({name}: {ty})")
136            } else {
137                write!(f, " -> {ty}")
138            }
139        } else {
140            f.write_str(" -> (")?;
141            for (idx, ty) in results.into_iter().enumerate() {
142                if idx != 0 {
143                    f.write_str(", ")?;
144                }
145                if let Some(name) = result_names.next() {
146                    write!(f, "{name}: ")?;
147                }
148                DisplayType(&ty).fmt(f)?;
149            }
150            f.write_str(")")
151        }
152    }
153}
154
155/// Implements a WAVE-formatted [`Display`] for [`WasmValue`] func arguments.
156pub struct DisplayFuncArgs<'a, T: WasmValue>(pub &'a [T]);
157
158impl<T: WasmValue> Display for DisplayFuncArgs<'_, T> {
159    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160        f.write_str("(")?;
161        for (idx, v) in self.0.iter().enumerate() {
162            if idx != 0 {
163                f.write_str(", ")?;
164            }
165            DisplayValue(v).fmt(f)?;
166        }
167        f.write_str(")")
168    }
169}
170
171/// Implements a WAVE-formatted [`Display`] for [`WasmValue`] func results.
172pub struct DisplayFuncResults<'a, T: WasmValue>(pub &'a [T]);
173
174impl<T: WasmValue> Display for DisplayFuncResults<'_, T> {
175    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176        if self.0.len() == 1 {
177            DisplayValue(&self.0[0]).fmt(f)
178        } else {
179            DisplayFuncArgs(self.0).fmt(f)
180        }
181    }
182}
183
184#[cfg(test)]
185mod tests {
186    use crate::value::Type;
187
188    #[test]
189    fn test_type_display() {
190        for (ty, expected) in [
191            (Type::U8, "u8"),
192            (Type::list(Type::U8), "list<u8>"),
193            (
194                Type::record([("a", Type::U8), ("b", Type::STRING)]).unwrap(),
195                "record { a: u8, b: string }",
196            ),
197            (
198                Type::tuple([Type::U8, Type::BOOL]).unwrap(),
199                "tuple<u8, bool>",
200            ),
201            (
202                Type::variant([("off", None), ("on", Some(Type::U8))]).unwrap(),
203                "variant { off, on(u8) }",
204            ),
205            (
206                Type::enum_ty(["east", "west"]).unwrap(),
207                "enum { east, west }",
208            ),
209            (Type::option(Type::U8), "option<u8>"),
210            (Type::result(None, None), "result"),
211            (Type::result(Some(Type::U8), None), "result<u8>"),
212            (Type::result(None, Some(Type::STRING)), "result<_, string>"),
213            (
214                Type::result(Some(Type::U8), Some(Type::STRING)),
215                "result<u8, string>",
216            ),
217            (
218                Type::flags(["read", "write"]).unwrap(),
219                "flags { read, write }",
220            ),
221        ] {
222            assert_eq!(ty.to_string(), expected);
223        }
224    }
225}