1use std::fmt::Display;
2
3use crate::{
4 WasmValue,
5 wasm::{WasmFunc, WasmType, WasmTypeKind},
6 writer::Writer,
7};
8
9pub 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
95pub 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
108pub 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
155pub 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
171pub 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}