golem_wasm/
wasmtime.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Golem Source License v1.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://license.golem.cloud/LICENSE
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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    /// Name of the WIT resource
50    pub name: String,
51    /// Owner of the resource, either an interface in a WIT package or a name of a world
52    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
77/// Converts a Value to a wasmtime Val based on the available type information.
78pub 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/// Converts a wasmtime Val to a wasm-rpc Value
501#[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}