1use std::collections::HashMap;
2use std::sync::Arc;
3
4use anyhow::{bail, ensure, Context as _};
5use tracing::{error, instrument, trace, warn};
6
7#[derive(Clone, Debug, Hash, PartialEq, Eq)]
9#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
10pub struct DynamicResource {
11 pub instance: String,
12 pub name: String,
13}
14
15#[derive(Clone, Debug, Hash, PartialEq, Eq)]
17#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
18pub enum Resource {
19 Pollable,
20 InputStream,
21 OutputStream,
22 Dynamic(Arc<DynamicResource>),
23}
24
25#[derive(Clone, Debug, Hash, PartialEq, Eq)]
27#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
28pub enum Type {
29 Bool,
30 U8,
31 U16,
32 U32,
33 U64,
34 S8,
35 S16,
36 S32,
37 S64,
38 F32,
39 F64,
40 Char,
41 String,
42 List(Arc<Type>),
43 Record(Arc<[Type]>),
44 Tuple(Arc<[Type]>),
45 Variant(Arc<[Option<Type>]>),
46 Enum,
47 Option(Arc<Type>),
48 Result {
49 ok: Option<Arc<Type>>,
50 err: Option<Arc<Type>>,
51 },
52 Flags,
53 Future(Option<Arc<Type>>),
54 Stream(Option<Arc<Type>>),
55 Resource(Resource),
56}
57
58fn resolve_iter<'a, C: FromIterator<Type>>(
59 resolve: &wit_parser::Resolve,
60 types: impl IntoIterator<Item = &'a wit_parser::Type>,
61) -> anyhow::Result<C> {
62 types
63 .into_iter()
64 .map(|ty| Type::resolve(resolve, ty))
65 .collect()
66}
67
68fn resolve_optional(
69 resolve: &wit_parser::Resolve,
70 ty: &Option<wit_parser::Type>,
71) -> anyhow::Result<Option<Type>> {
72 ty.as_ref().map(|ty| Type::resolve(resolve, ty)).transpose()
73}
74
75impl Type {
76 #[instrument(level = "trace", skip(resolve), ret)]
77 pub fn resolve_def(
78 resolve: &wit_parser::Resolve,
79 ty: &wit_parser::TypeDef,
80 ) -> anyhow::Result<Self> {
81 use wit_parser::{
82 Case, Field, Handle, Record, Result_, Stream, Tuple, TypeDef, TypeDefKind, TypeOwner,
83 Variant,
84 };
85
86 match ty {
87 TypeDef {
88 kind: TypeDefKind::Record(Record { fields, .. }),
89 ..
90 } => resolve_iter(resolve, fields.iter().map(|Field { ty, .. }| ty)).map(Type::Record),
91 TypeDef {
92 name,
93 kind: TypeDefKind::Resource,
94 owner,
95 ..
96 } => {
97 let name = name.as_ref().context("resource is missing a name")?;
98 match owner {
99 TypeOwner::Interface(interface) => {
100 let interface = resolve
101 .interfaces
102 .get(*interface)
103 .context("resource belongs to a non-existent interface")?;
104 let interface_name = interface
105 .name
106 .as_ref()
107 .context("interface is missing a name")?;
108 let pkg = interface
109 .package
110 .context("interface is missing a package")?;
111 let instance = resolve.id_of_name(pkg, interface_name);
112 match (instance.as_str(), name.as_str()) {
113 ("wasi:io/poll@0.2.0", "pollable") => {
114 Ok(Self::Resource(Resource::Pollable))
115 }
116 ("wasi:io/streams@0.2.0", "input-stream") => {
117 Ok(Self::Resource(Resource::InputStream))
118 }
119 ("wasi:io/streams@0.2.0", "output-stream") => {
120 Ok(Self::Resource(Resource::OutputStream))
121 }
122 _ => Ok(Self::Resource(Resource::Dynamic(Arc::new(
123 DynamicResource {
124 instance,
125 name: name.to_string(),
126 },
127 )))),
128 }
129 }
130 _ => bail!("only resources owned by an interface are currently supported"),
131 }
132 }
133 TypeDef {
134 kind: TypeDefKind::Handle(Handle::Own(ty) | Handle::Borrow(ty)),
135 ..
136 } => {
137 let ty = resolve
138 .types
139 .get(*ty)
140 .context("unknown handle inner type")?;
141 Self::resolve_def(resolve, ty)
142 }
143 TypeDef {
144 kind: TypeDefKind::Flags(..),
145 ..
146 } => Ok(Self::Flags),
147 TypeDef {
148 kind: TypeDefKind::Tuple(Tuple { types }),
149 ..
150 } => resolve_iter(resolve, types).map(Type::Tuple),
151 TypeDef {
152 kind: TypeDefKind::Variant(Variant { cases }),
153 ..
154 } => cases
155 .iter()
156 .map(|Case { ty, .. }| resolve_optional(resolve, ty))
157 .collect::<anyhow::Result<_>>()
158 .map(Type::Variant),
159 TypeDef {
160 kind: TypeDefKind::Enum(..),
161 ..
162 } => Ok(Type::Enum),
163 TypeDef {
164 kind: TypeDefKind::Option(ty),
165 ..
166 } => {
167 let ty =
168 Self::resolve(resolve, ty).context("failed to resolve inner option type")?;
169 Ok(Type::Option(Arc::new(ty)))
170 }
171 TypeDef {
172 kind: TypeDefKind::Result(Result_ { ok, err }),
173 ..
174 } => {
175 let ok = resolve_optional(resolve, ok)
176 .context("failed to resolve inner result `ok` variant type")?
177 .map(Arc::new);
178 let err = resolve_optional(resolve, err)
179 .context("failed to resolve inner result `err` variant type")?
180 .map(Arc::new);
181 Ok(Type::Result { ok, err })
182 }
183 TypeDef {
184 kind: TypeDefKind::List(ty),
185 ..
186 } => Self::resolve(resolve, ty)
187 .context("failed to resolve inner list type")
188 .map(Arc::new)
189 .map(Self::List),
190 TypeDef {
191 kind: TypeDefKind::Future(ty),
192 ..
193 } => {
194 let ty = resolve_optional(resolve, ty)
195 .context("failed to resolve inner future type")?
196 .map(Arc::new);
197 Ok(Type::Future(ty))
198 }
199 TypeDef {
200 kind: TypeDefKind::Stream(Stream { element, end }),
201 ..
202 } => {
203 ensure!(
204 end.is_none(),
205 "stream end elements are deprecated and will be removed in preview 3"
206 );
207 let element = resolve_optional(resolve, element)
208 .context("failed to resolve inner stream `element` type")?
209 .map(Arc::new);
210 Ok(Type::Stream(element))
211 }
212 TypeDef {
213 kind: TypeDefKind::Type(ty),
214 ..
215 } => Self::resolve(resolve, ty).context("failed to resolve inner handle type"),
216 TypeDef {
217 kind: TypeDefKind::Unknown,
218 ..
219 } => bail!("invalid type definition"),
220 }
221 }
222
223 #[instrument(level = "trace", skip(resolve), ret)]
224 pub fn resolve(resolve: &wit_parser::Resolve, ty: &wit_parser::Type) -> anyhow::Result<Self> {
225 use wit_parser::Type;
226
227 match ty {
228 Type::Bool => Ok(Self::Bool),
229 Type::U8 => Ok(Self::U8),
230 Type::U16 => Ok(Self::U16),
231 Type::U32 => Ok(Self::U32),
232 Type::U64 => Ok(Self::U64),
233 Type::S8 => Ok(Self::S8),
234 Type::S16 => Ok(Self::S16),
235 Type::S32 => Ok(Self::S32),
236 Type::S64 => Ok(Self::S64),
237 Type::F32 => Ok(Self::F32),
238 Type::F64 => Ok(Self::F64),
239 Type::Char => Ok(Self::Char),
240 Type::String => Ok(Self::String),
241 Type::Id(ty) => {
242 let ty = resolve.types.get(*ty).context("unknown type")?;
243 Self::resolve_def(resolve, ty)
244 }
245 }
246 }
247}
248
249#[derive(Debug)]
251#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
252pub enum DynamicFunction {
253 Method {
254 receiver: Arc<DynamicResource>,
255 params: Arc<[Type]>,
256 results: Arc<[Type]>,
257 },
258 Static {
259 params: Arc<[Type]>,
260 results: Arc<[Type]>,
261 },
262}
263
264impl DynamicFunction {
265 pub fn resolve(
266 resolve: &wit_parser::Resolve,
267 wit_parser::Function {
268 params,
269 results,
270 kind,
271 ..
272 }: &wit_parser::Function,
273 ) -> anyhow::Result<Self> {
274 let mut params = params
275 .iter()
276 .map(|(_, ty)| Type::resolve(resolve, ty))
277 .collect::<anyhow::Result<Vec<_>>>()
278 .context("failed to resolve parameter types")?;
279 let results = results
280 .iter_types()
281 .map(|ty| Type::resolve(resolve, ty))
282 .collect::<anyhow::Result<Vec<_>>>()
283 .context("failed to resolve result types")?;
284 let results = results.into();
285 match kind {
286 wit_parser::FunctionKind::Method(_) => {
287 if params.is_empty() {
288 bail!("method takes no parameters");
289 }
290 let Type::Resource(Resource::Dynamic(receiver)) = params.remove(0) else {
291 bail!("first method parameter is not a guest resource");
292 };
293 let params = params.into();
294 Ok(DynamicFunction::Method {
295 receiver,
296 params,
297 results,
298 })
299 }
300 _ => Ok(DynamicFunction::Static {
301 params: params.into(),
302 results,
303 }),
304 }
305 }
306}
307
308pub fn function_exports<'a>(
309 resolve: &wit_parser::Resolve,
310 exports: impl IntoIterator<Item = (&'a wit_parser::WorldKey, &'a wit_parser::WorldItem)>,
311) -> HashMap<String, HashMap<String, DynamicFunction>> {
312 use wit_parser::WorldItem;
313
314 exports
315 .into_iter()
316 .filter_map(|(wk, wi)| {
317 let name = resolve.name_world_key(wk);
318 match wi {
319 WorldItem::Type(_ty) => {
320 trace!(name, "type export, skip");
321 None
322 }
323 WorldItem::Function(ty) => match DynamicFunction::resolve(resolve, ty) {
324 Ok(ty) => Some((String::new(), HashMap::from([(name, ty)]))),
325 Err(err) => {
326 warn!(?err, "failed to resolve function export, skip");
327 None
328 }
329 },
330 WorldItem::Interface(interface_id) => {
331 let Some(wit_parser::Interface { functions, .. }) =
332 resolve.interfaces.get(*interface_id)
333 else {
334 warn!("component exports a non-existent interface, skip");
335 return None;
336 };
337 let functions = functions
338 .into_iter()
339 .filter_map(|(func_name, ty)| {
340 let ty = match DynamicFunction::resolve(resolve, ty) {
341 Ok(ty) => ty,
342 Err(err) => {
343 warn!(?err, "failed to resolve function export, skip");
344 return None;
345 }
346 };
347 let func_name = if let DynamicFunction::Method { .. } = ty {
348 let Some(func_name) = func_name.strip_prefix("[method]") else {
349 error!("`[method]` prefix missing in method name, skip");
350 return None;
351 };
352 func_name
353 } else {
354 func_name
355 };
356 Some((func_name.to_string(), ty))
357 })
358 .collect();
359 Some((name, functions))
360 }
361 }
362 })
363 .collect()
364}
365
366#[cfg(test)]
367mod tests {
368 #[cfg(feature = "serde")]
369 #[test]
370 fn serde() {
371 use super::*;
372
373 let buf = serde_json::to_vec(&Type::U8).unwrap();
374 let ty: Type = serde_json::from_slice(&buf).unwrap();
375 assert_eq!(ty, Type::U8)
376 }
377}