1use crate::wit_type::WitType;
2use crate::{IntoValueAndType, Value, ValueAndType};
3use std::borrow::Cow;
4use std::collections::HashSet;
5use wasm_wave::wasm::{WasmType, WasmTypeKind, WasmValue, WasmValueError};
6use wasm_wave::{from_str, to_string};
7
8pub fn parse_value_and_type(analysed_type: &WitType, input: &str) -> Result<ValueAndType, String> {
9 let parsed: ValueAndType = from_str(analysed_type, input).map_err(|err| err.to_string())?;
10 Ok(parsed)
11}
12
13pub fn print_value_and_type(value: &ValueAndType) -> Result<String, String> {
14 if value.typ.contains_handle() {
15 Err("Cannot print handle type".to_string())
16 } else {
17 to_string(value).map_err(|err| err.to_string())
18 }
19}
20
21impl WasmValue for ValueAndType {
22 type Type = WitType;
23
24 fn kind(&self) -> WasmTypeKind {
25 self.typ.kind()
26 }
27
28 fn make_bool(val: bool) -> Self {
29 val.into_value_and_type()
30 }
31
32 fn make_s8(val: i8) -> Self {
33 val.into_value_and_type()
34 }
35
36 fn make_s16(val: i16) -> Self {
37 val.into_value_and_type()
38 }
39
40 fn make_s32(val: i32) -> Self {
41 val.into_value_and_type()
42 }
43
44 fn make_s64(val: i64) -> Self {
45 val.into_value_and_type()
46 }
47
48 fn make_u8(val: u8) -> Self {
49 val.into_value_and_type()
50 }
51
52 fn make_u16(val: u16) -> Self {
53 val.into_value_and_type()
54 }
55
56 fn make_u32(val: u32) -> Self {
57 val.into_value_and_type()
58 }
59
60 fn make_u64(val: u64) -> Self {
61 val.into_value_and_type()
62 }
63
64 fn make_f32(val: f32) -> Self {
65 val.into_value_and_type()
66 }
67
68 fn make_f64(val: f64) -> Self {
69 val.into_value_and_type()
70 }
71
72 fn make_char(val: char) -> Self {
73 val.into_value_and_type()
74 }
75
76 fn make_string(val: Cow<str>) -> Self {
77 val.to_string().into_value_and_type()
78 }
79
80 fn make_list(
81 ty: &Self::Type,
82 vals: impl IntoIterator<Item = Self>,
83 ) -> Result<Self, WasmValueError> {
84 Ok(ValueAndType {
85 value: Value::List(vals.into_iter().map(|vnt| vnt.value).collect()),
86 typ: ty.clone(),
87 })
88 }
89
90 fn make_record<'a>(
91 ty: &Self::Type,
92 fields: impl IntoIterator<Item = (&'a str, Self)>,
93 ) -> Result<Self, WasmValueError> {
94 Ok(ValueAndType {
95 value: Value::Record(fields.into_iter().map(|(_, vnt)| vnt.value).collect()),
96 typ: ty.clone(),
97 })
98 }
99
100 fn make_tuple(
101 ty: &Self::Type,
102 vals: impl IntoIterator<Item = Self>,
103 ) -> Result<Self, WasmValueError> {
104 Ok(ValueAndType {
105 value: Value::Tuple(vals.into_iter().map(|vnt| vnt.value).collect()),
106 typ: ty.clone(),
107 })
108 }
109
110 fn make_variant(
111 ty: &Self::Type,
112 case: &str,
113 val: Option<Self>,
114 ) -> Result<Self, WasmValueError> {
115 if let WitType::Variant(typ) = ty {
116 let case_idx = typ
117 .cases
118 .iter()
119 .position(|pair| pair.name == case)
120 .ok_or_else(|| WasmValueError::UnknownCase(case.to_string()))?
121 as u32;
122 Ok(ValueAndType {
123 value: Value::Variant {
124 case_idx,
125 case_value: val.map(|vnt| Box::new(vnt.value)),
126 },
127 typ: ty.clone(),
128 })
129 } else {
130 Err(WasmValueError::WrongTypeKind {
131 kind: WasmTypeKind::Variant,
132 ty: ty.kind().to_string(),
133 })
134 }
135 }
136
137 fn make_enum(ty: &Self::Type, case: &str) -> Result<Self, WasmValueError> {
138 if let WitType::Enum(typ) = ty {
139 let case_idx = typ
140 .cases
141 .iter()
142 .position(|c| c == case)
143 .ok_or_else(|| WasmValueError::UnknownCase(case.to_string()))?
144 as u32;
145 Ok(ValueAndType {
146 value: Value::Enum(case_idx),
147 typ: ty.clone(),
148 })
149 } else {
150 Err(WasmValueError::WrongTypeKind {
151 kind: WasmTypeKind::Enum,
152 ty: ty.kind().to_string(),
153 })
154 }
155 }
156
157 fn make_option(ty: &Self::Type, val: Option<Self>) -> Result<Self, WasmValueError> {
158 Ok(ValueAndType {
159 value: Value::Option(val.map(|vnt| Box::new(vnt.value))),
160 typ: ty.clone(),
161 })
162 }
163
164 fn make_result(
165 ty: &Self::Type,
166 val: Result<Option<Self>, Option<Self>>,
167 ) -> Result<Self, WasmValueError> {
168 Ok(ValueAndType {
169 value: Value::Result(
170 val.map(|maybe_ok| maybe_ok.map(|vnt| Box::new(vnt.value)))
171 .map_err(|maybe_err| maybe_err.map(|vnt| Box::new(vnt.value))),
172 ),
173 typ: ty.clone(),
174 })
175 }
176
177 fn make_flags<'a>(
178 ty: &Self::Type,
179 names: impl IntoIterator<Item = &'a str>,
180 ) -> Result<Self, WasmValueError> {
181 if let WitType::Flags(typ) = ty {
182 let mut bitmap = Vec::new();
183 let names: HashSet<&'a str> = HashSet::from_iter(names);
184 for name in &typ.names {
185 bitmap.push(names.contains(name.as_str()));
186 }
187 Ok(ValueAndType {
188 value: Value::Flags(bitmap),
189 typ: ty.clone(),
190 })
191 } else {
192 Err(WasmValueError::WrongTypeKind {
193 kind: WasmTypeKind::Flags,
194 ty: ty.kind().to_string(),
195 })
196 }
197 }
198
199 fn unwrap_bool(&self) -> bool {
200 match self.value {
201 Value::Bool(val) => val,
202 _ => panic!("Expected bool, found {self:?}"),
203 }
204 }
205
206 fn unwrap_s8(&self) -> i8 {
207 match self.value {
208 Value::S8(val) => val,
209 _ => panic!("Expected s8, found {self:?}"),
210 }
211 }
212
213 fn unwrap_s16(&self) -> i16 {
214 match self.value {
215 Value::S16(val) => val,
216 _ => panic!("Expected s16, found {self:?}"),
217 }
218 }
219
220 fn unwrap_s32(&self) -> i32 {
221 match self.value {
222 Value::S32(val) => val,
223 _ => panic!("Expected s32, found {self:?}"),
224 }
225 }
226
227 fn unwrap_s64(&self) -> i64 {
228 match self.value {
229 Value::S64(val) => val,
230 _ => panic!("Expected s64, found {self:?}"),
231 }
232 }
233
234 fn unwrap_u8(&self) -> u8 {
235 match self.value {
236 Value::U8(val) => val,
237 _ => panic!("Expected u8, found {self:?}"),
238 }
239 }
240
241 fn unwrap_u16(&self) -> u16 {
242 match self.value {
243 Value::U16(val) => val,
244 _ => panic!("Expected u16, found {self:?}"),
245 }
246 }
247
248 fn unwrap_u32(&self) -> u32 {
249 match self.value {
250 Value::U32(val) => val,
251 _ => panic!("Expected u32, found {self:?}"),
252 }
253 }
254
255 fn unwrap_u64(&self) -> u64 {
256 match self.value {
257 Value::U64(val) => val,
258 _ => panic!("Expected u64, found {self:?}"),
259 }
260 }
261
262 fn unwrap_f32(&self) -> f32 {
263 match self.value {
264 Value::F32(val) => val,
265 _ => panic!("Expected f32, found {self:?}"),
266 }
267 }
268
269 fn unwrap_f64(&self) -> f64 {
270 match self.value {
271 Value::F64(val) => val,
272 _ => panic!("Expected f64, found {self:?}"),
273 }
274 }
275
276 fn unwrap_char(&self) -> char {
277 match self.value {
278 Value::Char(val) => val,
279 _ => panic!("Expected char, found {self:?}"),
280 }
281 }
282
283 fn unwrap_string(&self) -> Cow<'_, str> {
284 match &self.value {
285 Value::String(val) => Cow::Borrowed(val),
286 _ => panic!("Expected string, found {self:?}"),
287 }
288 }
289
290 fn unwrap_list(&self) -> Box<dyn Iterator<Item = Cow<'_, Self>> + '_> {
291 match (&self.value, &self.typ) {
292 (Value::List(vals), WitType::List(typ)) => Box::new(vals.iter().map(|val| {
293 Cow::Owned(ValueAndType {
294 value: val.clone(),
295 typ: (*typ.inner).clone(),
296 })
297 })),
298 _ => panic!("Expected list, found {self:?}"),
299 }
300 }
301
302 fn unwrap_record(&self) -> Box<dyn Iterator<Item = (Cow<'_, str>, Cow<'_, Self>)> + '_> {
303 match (&self.value, &self.typ) {
304 (Value::Record(vals), WitType::Record(typ)) => {
305 Box::new(vals.iter().zip(typ.fields.iter()).map(|(val, field)| {
306 (
307 Cow::Borrowed(field.name.as_str()),
308 Cow::Owned(ValueAndType {
309 value: val.clone(),
310 typ: field.typ.clone(),
311 }),
312 )
313 }))
314 }
315 _ => panic!("Expected record, found {self:?}"),
316 }
317 }
318
319 fn unwrap_tuple(&self) -> Box<dyn Iterator<Item = Cow<'_, Self>> + '_> {
320 match (&self.value, &self.typ) {
321 (Value::Tuple(vals), WitType::Tuple(typ)) => {
322 Box::new(vals.iter().zip(typ.items.iter()).map(|(val, ty)| {
323 Cow::Owned(ValueAndType {
324 value: val.clone(),
325 typ: ty.clone(),
326 })
327 }))
328 }
329 _ => panic!("Expected tuple, found {self:?}"),
330 }
331 }
332
333 fn unwrap_variant(&self) -> (Cow<'_, str>, Option<Cow<'_, Self>>) {
334 match (&self.value, &self.typ) {
335 (
336 Value::Variant {
337 case_idx,
338 case_value,
339 },
340 WitType::Variant(typ),
341 ) => {
342 let case = &typ.cases[*case_idx as usize];
343 (
344 Cow::Borrowed(case.name.as_str()),
345 case_value.as_ref().map(|val| {
346 Cow::Owned(ValueAndType {
347 value: *val.clone(),
348 typ: case.typ.clone().unwrap(),
349 })
350 }),
351 )
352 }
353 _ => panic!("Expected variant, found {self:?}"),
354 }
355 }
356
357 fn unwrap_enum(&self) -> Cow<'_, str> {
358 match (&self.value, &self.typ) {
359 (Value::Enum(case_idx), WitType::Enum(typ)) => {
360 Cow::Borrowed(&typ.cases[*case_idx as usize])
361 }
362 _ => panic!("Expected enum, found {self:?}"),
363 }
364 }
365
366 fn unwrap_option(&self) -> Option<Cow<'_, Self>> {
367 match (&self.value, &self.typ) {
368 (Value::Option(Some(val)), WitType::Option(typ)) => Some(Cow::Owned(ValueAndType {
369 value: *val.clone(),
370 typ: (*typ.inner).clone(),
371 })),
372 (Value::Option(None), WitType::Option(_)) => None,
373 _ => panic!("Expected option, found {self:?}"),
374 }
375 }
376
377 fn unwrap_result(&self) -> Result<Option<Cow<'_, Self>>, Option<Cow<'_, Self>>> {
378 match (&self.value, &self.typ) {
379 (Value::Result(Ok(Some(val))), WitType::Result(typ)) => {
380 Ok(Some(Cow::Owned(ValueAndType {
381 value: *val.clone(),
382 typ: *typ
383 .ok
384 .as_ref()
385 .expect("No type information for non-unit ok value")
386 .clone(),
387 })))
388 }
389 (Value::Result(Ok(None)), WitType::Result(_)) => Ok(None),
390 (Value::Result(Err(Some(val))), WitType::Result(typ)) => {
391 Err(Some(Cow::Owned(ValueAndType {
392 value: *val.clone(),
393 typ: *typ
394 .err
395 .as_ref()
396 .expect("No type information for non-unit error value")
397 .clone(),
398 })))
399 }
400 (Value::Result(Err(None)), WitType::Result(_)) => Err(None),
401 _ => panic!("Expected result, found {self:?}"),
402 }
403 }
404
405 fn unwrap_flags(&self) -> Box<dyn Iterator<Item = Cow<'_, str>> + '_> {
406 match (&self.value, &self.typ) {
407 (Value::Flags(bitmap), WitType::Flags(typ)) => Box::new(
408 bitmap
409 .iter()
410 .zip(typ.names.iter())
411 .filter_map(|(is_set, name)| {
412 if *is_set {
413 Some(Cow::Borrowed(name.as_str()))
414 } else {
415 None
416 }
417 }),
418 ),
419 _ => panic!("Expected flags, found {self:?}"),
420 }
421 }
422}