1use crate::analysis::analysed_type::{
16 bool, case, chr, f32, f64, field, flags, list, option, r#enum, record, s16, s32, s64, s8, str,
17 tuple, u16, u32, u64, u8, unit_case, variant,
18};
19use crate::analysis::{AnalysedType, TypeResult};
20use crate::{Uri, Value};
21use async_recursion::async_recursion;
22use async_trait::async_trait;
23use std::fmt;
24use std::fmt::{Display, Formatter};
25use wasmtime::component::{types, ResourceAny, Type, Val};
26
27#[derive(Debug)]
28pub enum EncodingError {
29 ParamTypeMismatch { details: String },
30 ValueMismatch { details: String },
31 Unknown { details: String },
32}
33
34impl Display for EncodingError {
35 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
36 match self {
37 EncodingError::ParamTypeMismatch { details } => {
38 write!(f, "Parameter type mismatch: {details}")
39 }
40 EncodingError::ValueMismatch { details } => write!(f, "Value mismatch: {details}"),
41 EncodingError::Unknown { details } => write!(f, "Unknown error: {details}"),
42 }
43 }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq, Hash)]
47#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
48pub struct ResourceTypeId {
49 pub name: String,
51 pub owner: String,
53}
54
55#[async_trait]
56pub trait ResourceStore {
57 fn self_uri(&self) -> Uri;
58 async fn add(&mut self, resource: ResourceAny, name: ResourceTypeId) -> u64;
59 async fn get(&mut self, resource_id: u64) -> Option<(ResourceTypeId, ResourceAny)>;
60 async fn borrow(&self, resource_id: u64) -> Option<(ResourceTypeId, ResourceAny)>;
61}
62
63pub struct DecodeParamResult {
64 pub val: Val,
65 pub resources_to_drop: Vec<ResourceAny>,
66}
67
68impl DecodeParamResult {
69 pub fn simple(val: Val) -> Self {
70 Self {
71 val,
72 resources_to_drop: Vec::new(),
73 }
74 }
75}
76
77pub async fn decode_param(
79 param: &Value,
80 param_type: &Type,
81 resource_store: &mut (impl ResourceStore + Send),
82) -> Result<DecodeParamResult, EncodingError> {
83 decode_param_impl(param, param_type, resource_store, "$").await
84}
85
86#[async_recursion]
87async fn decode_param_impl(
88 param: &Value,
89 param_type: &Type,
90 resource_store: &mut (impl ResourceStore + Send),
91 context: &str,
92) -> Result<DecodeParamResult, EncodingError> {
93 match param_type {
94 Type::Bool => match param {
95 Value::Bool(bool) => Ok(DecodeParamResult::simple(Val::Bool(*bool))),
96 _ => Err(EncodingError::ParamTypeMismatch {
97 details: format!("in {context} expected bool, got {}", param.type_case_name()),
98 }),
99 },
100 Type::S8 => match param {
101 Value::S8(s8) => Ok(DecodeParamResult::simple(Val::S8(*s8))),
102 _ => Err(EncodingError::ParamTypeMismatch {
103 details: format!("in {context} expected s8, got {}", param.type_case_name()),
104 }),
105 },
106 Type::U8 => match param {
107 Value::U8(u8) => Ok(DecodeParamResult::simple(Val::U8(*u8))),
108 _ => Err(EncodingError::ParamTypeMismatch {
109 details: format!("in {context} expected u8, got {}", param.type_case_name()),
110 }),
111 },
112 Type::S16 => match param {
113 Value::S16(s16) => Ok(DecodeParamResult::simple(Val::S16(*s16))),
114 _ => Err(EncodingError::ParamTypeMismatch {
115 details: format!("in {context} expected s16, got {}", param.type_case_name()),
116 }),
117 },
118 Type::U16 => match param {
119 Value::U16(u16) => Ok(DecodeParamResult::simple(Val::U16(*u16))),
120 _ => Err(EncodingError::ParamTypeMismatch {
121 details: format!("in {context} expected u16, got {}", param.type_case_name()),
122 }),
123 },
124 Type::S32 => match param {
125 Value::S32(s32) => Ok(DecodeParamResult::simple(Val::S32(*s32))),
126 _ => Err(EncodingError::ParamTypeMismatch {
127 details: format!("in {context} expected s32, got {}", param.type_case_name()),
128 }),
129 },
130 Type::U32 => match param {
131 Value::U32(u32) => Ok(DecodeParamResult::simple(Val::U32(*u32))),
132 _ => Err(EncodingError::ParamTypeMismatch {
133 details: format!("in {context} expected u32, got {}", param.type_case_name()),
134 }),
135 },
136 Type::S64 => match param {
137 Value::S64(s64) => Ok(DecodeParamResult::simple(Val::S64(*s64))),
138 _ => Err(EncodingError::ParamTypeMismatch {
139 details: format!("in {context} expected s64, got {}", param.type_case_name()),
140 }),
141 },
142 Type::U64 => match param {
143 Value::U64(u64) => Ok(DecodeParamResult::simple(Val::U64(*u64))),
144 _ => Err(EncodingError::ParamTypeMismatch {
145 details: format!("in {context} expected u64, got {}", param.type_case_name()),
146 }),
147 },
148 Type::Float32 => match param {
149 Value::F32(f32) => Ok(DecodeParamResult::simple(Val::Float32(*f32))),
150 _ => Err(EncodingError::ParamTypeMismatch {
151 details: format!("in {context} expected f32, got {}", param.type_case_name()),
152 }),
153 },
154 Type::Float64 => match param {
155 Value::F64(f64) => Ok(DecodeParamResult::simple(Val::Float64(*f64))),
156 _ => Err(EncodingError::ParamTypeMismatch {
157 details: format!("in {context} expected f64, got {}", param.type_case_name()),
158 }),
159 },
160 Type::Char => match param {
161 Value::Char(char) => Ok(DecodeParamResult::simple(Val::Char(*char))),
162 _ => Err(EncodingError::ParamTypeMismatch {
163 details: format!("in {context} expected char, got {}", param.type_case_name()),
164 }),
165 },
166 Type::String => match param {
167 Value::String(string) => Ok(DecodeParamResult::simple(Val::String(string.clone()))),
168 _ => Err(EncodingError::ParamTypeMismatch {
169 details: format!(
170 "in {context} expected string, got {}",
171 param.type_case_name()
172 ),
173 }),
174 },
175 Type::List(ty) => match param {
176 Value::List(values) => {
177 let mut decoded_values = Vec::new();
178 let mut resource_ids_to_drop = Vec::new();
179 for (idx, value) in values.iter().enumerate() {
180 let decoded_param = decode_param_impl(
181 value,
182 &ty.ty(),
183 resource_store,
184 &format!("{context}.[{idx}]"),
185 )
186 .await?;
187 decoded_values.push(decoded_param.val);
188 resource_ids_to_drop.extend(decoded_param.resources_to_drop);
189 }
190 Ok(DecodeParamResult {
191 val: Val::List(decoded_values),
192 resources_to_drop: resource_ids_to_drop,
193 })
194 }
195 _ => Err(EncodingError::ParamTypeMismatch {
196 details: format!("in {context} expected list, got {}", param.type_case_name()),
197 }),
198 },
199 Type::Record(ty) => match param {
200 Value::Record(values) => {
201 let mut record_values = Vec::new();
202 let mut resource_ids_to_drop = Vec::new();
203
204 for (value, field) in values.iter().zip(ty.fields()) {
205 let decoded_param = decode_param_impl(
206 value,
207 &field.ty,
208 resource_store,
209 &format!("{context}.{}", field.name),
210 )
211 .await?;
212 record_values.push((field.name.to_string(), decoded_param.val));
213 resource_ids_to_drop.extend(decoded_param.resources_to_drop);
214 }
215
216 Ok(DecodeParamResult {
217 val: Val::Record(record_values),
218 resources_to_drop: resource_ids_to_drop,
219 })
220 }
221 _ => Err(EncodingError::ParamTypeMismatch {
222 details: format!(
223 "in {context} expected record, got {}",
224 param.type_case_name()
225 ),
226 }),
227 },
228 Type::Tuple(ty) => match param {
229 Value::Tuple(values) => {
230 let mut tuple_values = Vec::new();
231 let mut resource_ids_to_drop = Vec::new();
232
233 for (idx, (value, ty)) in values.iter().zip(ty.types()).enumerate() {
234 let decoded_param =
235 decode_param_impl(value, &ty, resource_store, &format!("{context}.{idx}"))
236 .await?;
237 tuple_values.push(decoded_param.val);
238 resource_ids_to_drop.extend(decoded_param.resources_to_drop);
239 }
240
241 Ok(DecodeParamResult {
242 val: Val::Tuple(tuple_values),
243 resources_to_drop: resource_ids_to_drop,
244 })
245 }
246 _ => Err(EncodingError::ParamTypeMismatch {
247 details: format!(
248 "in {context} expected tuple, got {}",
249 param.type_case_name()
250 ),
251 }),
252 },
253 Type::Variant(ty) => match param {
254 Value::Variant {
255 case_idx,
256 case_value,
257 } => {
258 let cases: Vec<types::Case> = ty.cases().collect();
259 let case = cases
260 .get(*case_idx as usize)
261 .ok_or(EncodingError::ValueMismatch {
262 details: format!(
263 "in {context} could not get case for discriminant {case_idx}"
264 ),
265 })?;
266 let name = case.name;
267 match case.ty {
268 Some(ref case_ty) => {
269 let decoded_value = match case_value {
270 Some(v) => Some(
271 decode_param_impl(
272 v,
273 case_ty,
274 resource_store,
275 &format!("{context}.{name}"),
276 )
277 .await?,
278 ),
279 None => None,
280 };
281 match decoded_value {
282 Some(decoded_value) => Ok(DecodeParamResult {
283 val: Val::Variant(
284 name.to_string(),
285 Some(Box::new(decoded_value.val)),
286 ),
287 resources_to_drop: decoded_value.resources_to_drop,
288 }),
289 None => Ok(DecodeParamResult::simple(Val::Variant(
290 name.to_string(),
291 None,
292 ))),
293 }
294 }
295 None => match case_value {
296 Some(_) => Err(EncodingError::ValueMismatch {
297 details: format!("in {context} expected no value for unit variant"),
298 }),
299 None => Ok(DecodeParamResult::simple(Val::Variant(
300 name.to_string(),
301 None,
302 ))),
303 },
304 }
305 }
306 _ => Err(EncodingError::ParamTypeMismatch {
307 details: format!(
308 "in {context} expected variant, got {}",
309 param.type_case_name()
310 ),
311 }),
312 },
313 Type::Enum(ty) => match param {
314 Value::Enum(discriminant) => {
315 let names: Vec<&str> = ty.names().collect();
316 let name: &str =
317 names
318 .get(*discriminant as usize)
319 .ok_or(EncodingError::ValueMismatch {
320 details: format!(
321 "in {context} could not get name for discriminant {discriminant}"
322 ),
323 })?;
324
325 Ok(DecodeParamResult::simple(Val::Enum(name.to_string())))
326 }
327 _ => Err(EncodingError::ParamTypeMismatch {
328 details: format!("in {context} expected enum, got {}", param.type_case_name()),
329 }),
330 },
331 Type::Option(ty) => match param {
332 Value::Option(value) => match value {
333 Some(value) => {
334 let decoded_value = decode_param_impl(
335 value,
336 &ty.ty(),
337 resource_store,
338 &format!("{context}.some"),
339 )
340 .await?;
341 Ok(DecodeParamResult {
342 val: Val::Option(Some(Box::new(decoded_value.val))),
343 resources_to_drop: decoded_value.resources_to_drop,
344 })
345 }
346 None => Ok(DecodeParamResult::simple(Val::Option(None))),
347 },
348 _ => Err(EncodingError::ParamTypeMismatch {
349 details: format!(
350 "in {context} expected option, got {}",
351 param.type_case_name()
352 ),
353 }),
354 },
355 Type::Result(ty) => match param {
356 Value::Result(result) => match result {
357 Ok(value) => {
358 let decoded_value = match value {
359 Some(v) => {
360 let ok_ty = ty.ok().ok_or(EncodingError::ValueMismatch {
361 details: format!("in {context} could not get ok type"),
362 })?;
363 Some(
364 decode_param_impl(
365 v,
366 &ok_ty,
367 resource_store,
368 &format!("{context}.ok"),
369 )
370 .await?,
371 )
372 }
373 None => None,
374 };
375 match decoded_value {
376 Some(decoded_value) => Ok(DecodeParamResult {
377 val: Val::Result(Ok(Some(Box::new(decoded_value.val)))),
378 resources_to_drop: decoded_value.resources_to_drop,
379 }),
380 None => Ok(DecodeParamResult::simple(Val::Result(Ok(None)))),
381 }
382 }
383 Err(value) => {
384 let decoded_value = match value {
385 Some(v) => {
386 let err_ty = ty.err().ok_or(EncodingError::ValueMismatch {
387 details: format!("in {context} could not get err type"),
388 })?;
389 Some(
390 decode_param_impl(
391 v,
392 &err_ty,
393 resource_store,
394 &format!("{context}.err"),
395 )
396 .await?,
397 )
398 }
399 None => None,
400 };
401
402 match decoded_value {
403 Some(decoded_value) => Ok(DecodeParamResult {
404 val: Val::Result(Err(Some(Box::new(decoded_value.val)))),
405 resources_to_drop: decoded_value.resources_to_drop,
406 }),
407 None => Ok(DecodeParamResult::simple(Val::Result(Err(None)))),
408 }
409 }
410 },
411 _ => Err(EncodingError::ParamTypeMismatch {
412 details: format!(
413 "in {context} expected result, got {}",
414 param.type_case_name()
415 ),
416 }),
417 },
418 Type::Flags(ty) => match param {
419 Value::Flags(flags) => {
420 let flag_names = ty.names().collect::<Vec<&str>>();
421 let active_flags: Vec<String> = flag_names
422 .iter()
423 .zip(flags)
424 .filter_map(|(name, enabled)| {
425 if *enabled {
426 Some(name.to_string())
427 } else {
428 None
429 }
430 })
431 .collect();
432
433 Ok(DecodeParamResult::simple(Val::Flags(active_flags)))
434 }
435 _ => Err(EncodingError::ParamTypeMismatch {
436 details: format!(
437 "in {context} expected flags, got {}",
438 param.type_case_name()
439 ),
440 }),
441 },
442 Type::Own(_) => {
443 match param {
444 Value::Handle { uri, resource_id } => {
445 let uri = Uri { value: uri.clone() };
446 if resource_store.self_uri() == uri {
447 match resource_store.get(*resource_id).await {
448 Some((_, resource)) => Ok(DecodeParamResult {
449 val: Val::Resource(resource),
450 resources_to_drop: vec![resource],
451 }),
452 None => Err(EncodingError::ValueMismatch {
453 details: format!("in {context} resource not found"),
454 }),
455 }
456 } else {
457 Err(EncodingError::ValueMismatch {
458 details: format!("in {context} cannot resolve handle belonging to a different worker"),
459 })
460 }
461 }
462 _ => Err(EncodingError::ParamTypeMismatch {
463 details: format!(
464 "in {context} expected handle, got {}",
465 param.type_case_name()
466 ),
467 }),
468 }
469 }
470 Type::Borrow(_) => match param {
471 Value::Handle { uri, resource_id } => {
472 let uri = Uri { value: uri.clone() };
473 if resource_store.self_uri() == uri {
474 match resource_store.borrow(*resource_id).await {
475 Some((_, resource)) => {
476 Ok(DecodeParamResult::simple(Val::Resource(resource)))
477 }
478 None => Err(EncodingError::ValueMismatch {
479 details: format!("in {context} resource not found"),
480 }),
481 }
482 } else {
483 Err(EncodingError::ValueMismatch {
484 details: format!(
485 "in {context} cannot resolve handle belonging to a different worker"
486 ),
487 })
488 }
489 }
490 _ => Err(EncodingError::ParamTypeMismatch {
491 details: format!(
492 "in {context} expected handle, got {}",
493 param.type_case_name()
494 ),
495 }),
496 },
497 }
498}
499
500#[async_recursion]
502pub async fn encode_output(
503 value: &Val,
504 typ: &Type,
505 analysed_typ: &AnalysedType,
506 resource_store: &mut (impl ResourceStore + Send),
507) -> Result<Value, EncodingError> {
508 match value {
509 Val::Bool(bool) => Ok(Value::Bool(*bool)),
510 Val::S8(i8) => Ok(Value::S8(*i8)),
511 Val::U8(u8) => Ok(Value::U8(*u8)),
512 Val::S16(i16) => Ok(Value::S16(*i16)),
513 Val::U16(u16) => Ok(Value::U16(*u16)),
514 Val::S32(i32) => Ok(Value::S32(*i32)),
515 Val::U32(u32) => Ok(Value::U32(*u32)),
516 Val::S64(i64) => Ok(Value::S64(*i64)),
517 Val::U64(u64) => Ok(Value::U64(*u64)),
518 Val::Float32(f32) => Ok(Value::F32(*f32)),
519 Val::Float64(f64) => Ok(Value::F64(*f64)),
520 Val::Char(char) => Ok(Value::Char(*char)),
521 Val::String(string) => Ok(Value::String(string.to_string())),
522 Val::List(list) => {
523 if let Type::List(list_type) = typ {
524 let mut encoded_values = Vec::new();
525 let inner_analysed_typ = if let AnalysedType::List(inner) = analysed_typ {
526 Ok(&*inner.inner)
527 } else {
528 Err(EncodingError::ValueMismatch {
529 details: "Expected a List type for list value".to_string(),
530 })
531 }?;
532
533 for value in (*list).iter() {
534 encoded_values.push(
535 encode_output(value, &list_type.ty(), inner_analysed_typ, resource_store)
536 .await?,
537 );
538 }
539 Ok(Value::List(encoded_values))
540 } else {
541 Err(EncodingError::ValueMismatch {
542 details: "Got a List value for non-list result type".to_string(),
543 })
544 }
545 }
546 Val::Record(record) => {
547 if let Type::Record(record_type) = typ {
548 let mut encoded_values = Vec::new();
549 for (idx, ((_name, value), field)) in
550 record.iter().zip(record_type.fields()).enumerate()
551 {
552 let field_analysed_type = if let AnalysedType::Record(inner) = analysed_typ {
553 Ok(&inner.fields[idx].typ)
554 } else {
555 Err(EncodingError::ValueMismatch {
556 details: "Expected a Record type for record value".to_string(),
557 })
558 }?;
559
560 let field =
561 encode_output(value, &field.ty, field_analysed_type, resource_store)
562 .await?;
563 encoded_values.push(field);
564 }
565 Ok(Value::Record(encoded_values))
566 } else {
567 Err(EncodingError::ValueMismatch {
568 details: "Got a Record value for non-record result type".to_string(),
569 })
570 }
571 }
572 Val::Tuple(tuple) => {
573 if let Type::Tuple(tuple_type) = typ {
574 let mut encoded_values = Vec::new();
575 for (idx, (v, t)) in tuple.iter().zip(tuple_type.types()).enumerate() {
576 let item_analysed_type = if let AnalysedType::Tuple(inner) = analysed_typ {
577 Ok(&inner.items[idx])
578 } else {
579 Err(EncodingError::ValueMismatch {
580 details: "Expected a Tuple type for tuple value".to_string(),
581 })
582 }?;
583
584 let value = encode_output(v, &t, item_analysed_type, resource_store).await?;
585 encoded_values.push(value);
586 }
587 Ok(Value::Tuple(encoded_values))
588 } else {
589 Err(EncodingError::ValueMismatch {
590 details: "Got a Tuple value for non-tuple result type".to_string(),
591 })
592 }
593 }
594 Val::Variant(name, value) => {
595 if let Type::Variant(variant_type) = typ {
596 let (discriminant, case, analysed_case_type) = variant_type
597 .cases()
598 .enumerate()
599 .find(|(_idx, case)| case.name == *name)
600 .map(|(idx, case)| {
601 if let AnalysedType::Variant(inner) = analysed_typ {
602 Ok((idx, case, &inner.cases[idx].typ))
603 } else {
604 Err(EncodingError::ValueMismatch {
605 details: "Expected a Variant type for variant value".to_string(),
606 })
607 }
608 })
609 .transpose()?
610 .ok_or(EncodingError::ValueMismatch {
611 details: format!("Could not find case for variant {name}"),
612 })?;
613
614 let encoded_output = match value {
615 Some(v) => Some(
616 encode_output(
617 v,
618 &case.ty.ok_or(EncodingError::ValueMismatch {
619 details: "Could not get type information for case".to_string(),
620 })?,
621 analysed_case_type
622 .as_ref()
623 .ok_or(EncodingError::ValueMismatch {
624 details: "Could not get type information for case".to_string(),
625 })?,
626 resource_store,
627 )
628 .await?,
629 ),
630 None => None,
631 };
632
633 Ok(Value::Variant {
634 case_idx: discriminant as u32,
635 case_value: encoded_output.map(Box::new),
636 })
637 } else {
638 Err(EncodingError::ValueMismatch {
639 details: "Got a Variant value for non-variant result type".to_string(),
640 })
641 }
642 }
643 Val::Enum(name) => {
644 if let Type::Enum(enum_type) = typ {
645 let (discriminant, _name) = enum_type
646 .names()
647 .enumerate()
648 .find(|(_idx, n)| n == name)
649 .ok_or(EncodingError::ValueMismatch {
650 details: format!("Could not find discriminant for enum {name}"),
651 })?;
652 Ok(Value::Enum(discriminant as u32))
653 } else {
654 Err(EncodingError::ValueMismatch {
655 details: "Got an Enum value for non-enum result type".to_string(),
656 })
657 }
658 }
659 Val::Option(option) => match option {
660 Some(value) => {
661 if let Type::Option(option_type) = typ {
662 let analysed_inner_type = if let AnalysedType::Option(inner) = analysed_typ {
663 Ok(&*inner.inner)
664 } else {
665 Err(EncodingError::ValueMismatch {
666 details: "Expected an Option type for option value".to_string(),
667 })
668 }?;
669
670 let encoded_output = encode_output(
671 value,
672 &option_type.ty(),
673 analysed_inner_type,
674 resource_store,
675 )
676 .await?;
677 Ok(Value::Option(Some(Box::new(encoded_output))))
678 } else {
679 Err(EncodingError::ValueMismatch {
680 details: "Got an Option value for non-option result type".to_string(),
681 })
682 }
683 }
684 None => Ok(Value::Option(None)),
685 },
686 Val::Result(result) => {
687 if let Type::Result(result_type) = typ {
688 match result {
689 Ok(value) => {
690 let encoded_output = match value {
691 Some(v) => {
692 let t = result_type.ok().ok_or(EncodingError::ValueMismatch {
693 details: "Could not get ok type for result".to_string(),
694 })?;
695
696 let analysed_ok_type =
697 if let AnalysedType::Result(inner) = analysed_typ {
698 Ok(inner.ok.as_ref().ok_or_else(|| {
699 EncodingError::ValueMismatch {
700 details: "Expected a Result type for result value"
701 .to_string(),
702 }
703 })?)
704 } else {
705 Err(EncodingError::ValueMismatch {
706 details: "Expected a Result type for result value"
707 .to_string(),
708 })
709 }?;
710
711 Some(encode_output(v, &t, analysed_ok_type, resource_store).await?)
712 }
713 None => None,
714 };
715 Ok(Value::Result(Ok(encoded_output.map(Box::new))))
716 }
717 Err(value) => {
718 let encoded_output = match value {
719 Some(v) => {
720 let t = result_type.err().ok_or(EncodingError::ValueMismatch {
721 details: "Could not get error type for result".to_string(),
722 })?;
723
724 let analysed_err_type =
725 if let AnalysedType::Result(inner) = analysed_typ {
726 Ok(inner.err.as_ref().ok_or_else(|| {
727 EncodingError::ValueMismatch {
728 details: "Expected a Result type for result value"
729 .to_string(),
730 }
731 })?)
732 } else {
733 Err(EncodingError::ValueMismatch {
734 details: "Expected a Result type for result value"
735 .to_string(),
736 })
737 }?;
738
739 Some(encode_output(v, &t, analysed_err_type, resource_store).await?)
740 }
741 None => None,
742 };
743 Ok(Value::Result(Err(encoded_output.map(Box::new))))
744 }
745 }
746 } else {
747 Err(EncodingError::ValueMismatch {
748 details: "Got a Result value for non-result result type".to_string(),
749 })
750 }
751 }
752 Val::Flags(flags) => {
753 if let Type::Flags(flags_type) = typ {
754 let mut encoded_value = vec![false; flags_type.names().count()];
755
756 for (idx, name) in flags_type.names().enumerate() {
757 if flags.contains(&name.to_string()) {
758 encoded_value[idx] = true;
759 }
760 }
761
762 Ok(Value::Flags(encoded_value))
763 } else {
764 Err(EncodingError::ValueMismatch {
765 details: "Got a Flags value for non-flags result type".to_string(),
766 })
767 }
768 }
769 Val::Resource(resource) => {
770 let type_id = analysed_typ
771 .name()
772 .and_then(|name| {
773 analysed_typ.owner().map(|owner| ResourceTypeId {
774 name: name.to_string(),
775 owner: owner.to_string(),
776 })
777 })
778 .ok_or_else(|| EncodingError::ValueMismatch {
779 details: "Resource type information is missing for resource value".to_string(),
780 })?;
781
782 let id = resource_store.add(*resource, type_id).await;
783 Ok(Value::Handle {
784 uri: resource_store.self_uri().value,
785 resource_id: id,
786 })
787 }
788 }
789}
790
791pub fn type_to_analysed_type(typ: &Type) -> Result<AnalysedType, String> {
792 match typ {
793 Type::Bool => Ok(bool()),
794 Type::S8 => Ok(s8()),
795 Type::U8 => Ok(u8()),
796 Type::S16 => Ok(s16()),
797 Type::U16 => Ok(u16()),
798 Type::S32 => Ok(s32()),
799 Type::U32 => Ok(u32()),
800 Type::S64 => Ok(s64()),
801 Type::U64 => Ok(u64()),
802 Type::Float32 => Ok(f32()),
803 Type::Float64 => Ok(f64()),
804 Type::Char => Ok(chr()),
805 Type::String => Ok(str()),
806 Type::List(wlist) => {
807 let inner = type_to_analysed_type(&wlist.ty())?;
808 Ok(list(inner))
809 }
810 Type::Record(wrecord) => {
811 let fields = wrecord
812 .fields()
813 .map(|wfield| type_to_analysed_type(&wfield.ty).map(|t| field(wfield.name, t)))
814 .collect::<Result<Vec<_>, _>>()?;
815 Ok(record(fields))
816 }
817 Type::Tuple(wtuple) => {
818 let items = wtuple
819 .types()
820 .map(|ty| type_to_analysed_type(&ty))
821 .collect::<Result<Vec<_>, _>>()?;
822 Ok(tuple(items))
823 }
824 Type::Variant(wvariant) => {
825 let cases = wvariant
826 .cases()
827 .map(|wcase| match wcase.ty {
828 Some(ty) => type_to_analysed_type(&ty).map(|t| case(wcase.name, t)),
829 None => Ok(unit_case(wcase.name)),
830 })
831 .collect::<Result<Vec<_>, _>>()?;
832 Ok(variant(cases))
833 }
834 Type::Enum(wenum) => Ok(r#enum(&wenum.names().collect::<Vec<_>>())),
835 Type::Option(woption) => {
836 let inner = type_to_analysed_type(&woption.ty())?;
837 Ok(option(inner))
838 }
839 Type::Result(result) => {
840 let ok = match result.ok() {
841 Some(ty) => Some(Box::new(type_to_analysed_type(&ty)?)),
842 None => None,
843 };
844 let err = match result.err() {
845 Some(ty) => Some(Box::new(type_to_analysed_type(&ty)?)),
846 None => None,
847 };
848 Ok(AnalysedType::Result(TypeResult {
849 ok,
850 err,
851 name: None,
852 owner: None,
853 }))
854 }
855 Type::Flags(wflags) => Ok(flags(&wflags.names().collect::<Vec<_>>())),
856 Type::Own(_) => Err("Cannot extract information about owned resource type".to_string()),
857 Type::Borrow(_) => {
858 Err("Cannot extract information about borrowed resource type".to_string())
859 }
860 }
861}