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