wasmtime_wit_bindgen/
types.rs

1use std::collections::HashMap;
2use wit_parser::*;
3
4#[derive(Default)]
5pub struct Types {
6    type_info: HashMap<TypeId, TypeInfo>,
7}
8
9#[derive(Default, Clone, Copy, Debug, PartialEq)]
10pub struct TypeInfo {
11    /// Whether or not this type is ever used (transitively) within a borrowed
12    /// context, or a parameter to an export function.
13    pub borrowed: bool,
14
15    /// Whether or not this type is ever used (transitively) within an owned
16    /// context, such as the result of an exported function or in the params or
17    /// results of an imported function.
18    pub owned: bool,
19
20    /// Whether or not this type is ever used (transitively) within the
21    /// error case in the result of a function.
22    pub error: bool,
23
24    /// Whether or not this type (transitively) has a list.
25    pub has_list: bool,
26
27    /// Whether or not this type (transitively) has a handle.
28    pub has_handle: bool,
29}
30
31impl std::ops::BitOrAssign for TypeInfo {
32    fn bitor_assign(&mut self, rhs: Self) {
33        self.borrowed |= rhs.borrowed;
34        self.owned |= rhs.owned;
35        self.error |= rhs.error;
36        self.has_list |= rhs.has_list;
37        self.has_handle |= rhs.has_handle;
38    }
39}
40
41impl Types {
42    pub fn analyze(&mut self, resolve: &Resolve, world: WorldId) {
43        // Build up all type information first which is inherited through types,
44        // such as properties of borrows/lists/etc.
45        for (t, _) in resolve.types.iter() {
46            self.type_id_info(resolve, t);
47        }
48
49        // ... next handle borrowed/owned flags which aren't inherited through
50        // types.
51        let world = &resolve.worlds[world];
52        for (import, (_, item)) in world
53            .imports
54            .iter()
55            .map(|i| (true, i))
56            .chain(world.exports.iter().map(|i| (false, i)))
57        {
58            match item {
59                WorldItem::Function(f) => self.type_info_func(resolve, f, import),
60                WorldItem::Interface { id, .. } => {
61                    let iface = &resolve.interfaces[*id];
62
63                    for (_, t) in iface.types.iter() {
64                        self.type_id_info(resolve, *t);
65                    }
66                    for (_, f) in iface.functions.iter() {
67                        self.type_info_func(resolve, f, import);
68                    }
69                }
70                WorldItem::Type(id) => {
71                    self.type_id_info(resolve, *id);
72                }
73            }
74        }
75    }
76
77    fn type_info_func(&mut self, resolve: &Resolve, func: &Function, import: bool) {
78        let mut live = LiveTypes::default();
79        for (_, ty) in func.params.iter() {
80            self.type_info(resolve, ty);
81            live.add_type(resolve, ty);
82        }
83        for id in live.iter() {
84            if resolve.types[id].name.is_some() {
85                let info = self.type_info.get_mut(&id).unwrap();
86                if import {
87                    info.owned = true;
88                } else {
89                    info.borrowed = true;
90                }
91            }
92        }
93        let mut live = LiveTypes::default();
94        if let Some(ty) = &func.result {
95            self.type_info(resolve, ty);
96            live.add_type(resolve, ty);
97        }
98        for id in live.iter() {
99            if resolve.types[id].name.is_some() {
100                self.type_info.get_mut(&id).unwrap().owned = true;
101            }
102        }
103
104        if let Some(Type::Id(id)) = func.result {
105            if let TypeDefKind::Result(Result_ {
106                err: Some(Type::Id(id)),
107                ..
108            }) = &resolve.types[id].kind
109            {
110                let id = super::resolve_type_definition_id(resolve, *id);
111                self.type_info.get_mut(&id).unwrap().error = true;
112            }
113        }
114    }
115
116    pub fn get(&self, id: TypeId) -> TypeInfo {
117        self.type_info[&id]
118    }
119
120    fn type_id_info(&mut self, resolve: &Resolve, ty: TypeId) -> TypeInfo {
121        if let Some(info) = self.type_info.get(&ty) {
122            return *info;
123        }
124        let mut info = TypeInfo::default();
125        match &resolve.types[ty].kind {
126            TypeDefKind::Record(r) => {
127                for field in r.fields.iter() {
128                    info |= self.type_info(resolve, &field.ty);
129                }
130            }
131            TypeDefKind::Tuple(t) => {
132                for ty in t.types.iter() {
133                    info |= self.type_info(resolve, ty);
134                }
135            }
136            TypeDefKind::Flags(_) => {}
137            TypeDefKind::Enum(_) => {}
138            TypeDefKind::Variant(v) => {
139                for case in v.cases.iter() {
140                    info |= self.optional_type_info(resolve, case.ty.as_ref());
141                }
142            }
143            TypeDefKind::List(ty) => {
144                info = self.type_info(resolve, ty);
145                info.has_list = true;
146            }
147            TypeDefKind::Type(ty) | TypeDefKind::Option(ty) => {
148                info = self.type_info(resolve, ty);
149            }
150            TypeDefKind::Result(r) => {
151                info = self.optional_type_info(resolve, r.ok.as_ref());
152                info |= self.optional_type_info(resolve, r.err.as_ref());
153            }
154            TypeDefKind::Future(ty) | TypeDefKind::Stream(ty) => {
155                info = self.optional_type_info(resolve, ty.as_ref());
156            }
157            TypeDefKind::Handle(_) => info.has_handle = true,
158            TypeDefKind::Resource => {}
159            TypeDefKind::Unknown => unreachable!(),
160        }
161        self.type_info.insert(ty, info);
162        info
163    }
164
165    fn type_info(&mut self, resolve: &Resolve, ty: &Type) -> TypeInfo {
166        let mut info = TypeInfo::default();
167        match ty {
168            Type::String => info.has_list = true,
169            Type::Id(id) => return self.type_id_info(resolve, *id),
170            _ => {}
171        }
172        info
173    }
174
175    fn optional_type_info(&mut self, resolve: &Resolve, ty: Option<&Type>) -> TypeInfo {
176        match ty {
177            Some(ty) => self.type_info(resolve, ty),
178            None => TypeInfo::default(),
179        }
180    }
181}
182
183impl TypeInfo {
184    pub fn is_copy(&self) -> bool {
185        !self.has_list && !self.has_handle
186    }
187
188    pub fn is_clone(&self) -> bool {
189        !self.has_handle
190    }
191}