linera_wit_bindgen_core/
lib.rs

1use anyhow::Result;
2use std::collections::{btree_map::Entry, BTreeMap, HashMap};
3use std::fmt::{self, Write};
4use std::ops::Deref;
5use std::path::Path;
6use wit_parser::*;
7
8pub use wit_parser;
9mod ns;
10
11pub use ns::Ns;
12
13/// This is the direction from the user's perspective. Are we importing
14/// functions to call, or defining functions and exporting them to be called?
15///
16/// This is only used outside of `Generator` implementations. Inside of
17/// `Generator` implementations, the `Direction` is translated to an
18/// `AbiVariant` instead. The ABI variant is usually the same as the
19/// `Direction`, but it's different in the case of the Wasmtime host bindings:
20///
21/// In a wasm-calling-wasm use case, one wasm module would use the `Import`
22/// ABI, the other would use the `Export` ABI, and there would be an adapter
23/// layer between the two that translates from one ABI to the other.
24///
25/// But with wasm-calling-host, we don't go through a separate adapter layer;
26/// the binding code we generate on the host side just does everything itself.
27/// So when the host is conceptually "exporting" a function to wasm, it uses
28/// the `Import` ABI so that wasm can also use the `Import` ABI and import it
29/// directly from the host.
30///
31/// These are all implementation details; from the user perspective, and
32/// from the perspective of everything outside of `Generator` implementations,
33/// `export` means I'm exporting functions to be called, and `import` means I'm
34/// importing functions that I'm going to call, in both wasm modules and host
35/// code. The enum here represents this user perspective.
36#[derive(Copy, Clone, Eq, PartialEq)]
37pub enum Direction {
38    Import,
39    Export,
40}
41
42pub trait Generator {
43    fn preprocess_all(&mut self, imports: &[Interface], exports: &[Interface]) {
44        drop((imports, exports));
45    }
46
47    fn preprocess_one(&mut self, iface: &Interface, dir: Direction) {
48        drop((iface, dir));
49    }
50
51    fn type_record(
52        &mut self,
53        iface: &Interface,
54        id: TypeId,
55        name: &str,
56        record: &Record,
57        docs: &Docs,
58    );
59    fn type_flags(&mut self, iface: &Interface, id: TypeId, name: &str, flags: &Flags, docs: &Docs);
60    fn type_tuple(&mut self, iface: &Interface, id: TypeId, name: &str, flags: &Tuple, docs: &Docs);
61    fn type_variant(
62        &mut self,
63        iface: &Interface,
64        id: TypeId,
65        name: &str,
66        variant: &Variant,
67        docs: &Docs,
68    );
69    fn type_option(
70        &mut self,
71        iface: &Interface,
72        id: TypeId,
73        name: &str,
74        payload: &Type,
75        docs: &Docs,
76    );
77    fn type_result(
78        &mut self,
79        iface: &Interface,
80        id: TypeId,
81        name: &str,
82        result: &Result_,
83        docs: &Docs,
84    );
85    fn type_union(&mut self, iface: &Interface, id: TypeId, name: &str, union: &Union, docs: &Docs);
86    fn type_enum(&mut self, iface: &Interface, id: TypeId, name: &str, enum_: &Enum, docs: &Docs);
87    fn type_resource(&mut self, iface: &Interface, ty: ResourceId);
88    fn type_alias(&mut self, iface: &Interface, id: TypeId, name: &str, ty: &Type, docs: &Docs);
89    fn type_list(&mut self, iface: &Interface, id: TypeId, name: &str, ty: &Type, docs: &Docs);
90    fn type_builtin(&mut self, iface: &Interface, id: TypeId, name: &str, ty: &Type, docs: &Docs);
91
92    fn preprocess_resources(&mut self, iface: &Interface, dir: Direction) {
93        drop((iface, dir));
94    }
95
96    fn preprocess_functions(&mut self, iface: &Interface, dir: Direction) {
97        drop((iface, dir));
98    }
99    fn import(&mut self, iface: &Interface, func: &Function);
100    fn export(&mut self, iface: &Interface, func: &Function);
101    fn finish_functions(&mut self, iface: &Interface, dir: Direction) {
102        drop((iface, dir));
103    }
104
105    fn finish_one(&mut self, iface: &Interface, files: &mut Files);
106
107    fn finish_all(&mut self, files: &mut Files) {
108        drop(files);
109    }
110
111    fn generate_one(&mut self, iface: &Interface, dir: Direction, files: &mut Files) {
112        self.preprocess_one(iface, dir);
113
114        for (id, ty) in iface.types.iter() {
115            // assert!(ty.foreign_module.is_none()); // TODO
116            let name = match &ty.name {
117                Some(name) => name,
118                None => continue,
119            };
120            match &ty.kind {
121                TypeDefKind::Record(record) => self.type_record(iface, id, name, record, &ty.docs),
122                TypeDefKind::Flags(flags) => self.type_flags(iface, id, name, flags, &ty.docs),
123                TypeDefKind::Tuple(tuple) => self.type_tuple(iface, id, name, tuple, &ty.docs),
124                TypeDefKind::Enum(enum_) => self.type_enum(iface, id, name, enum_, &ty.docs),
125                TypeDefKind::Variant(variant) => {
126                    self.type_variant(iface, id, name, variant, &ty.docs)
127                }
128                TypeDefKind::Option(t) => self.type_option(iface, id, name, t, &ty.docs),
129                TypeDefKind::Result(r) => self.type_result(iface, id, name, r, &ty.docs),
130                TypeDefKind::Union(u) => self.type_union(iface, id, name, u, &ty.docs),
131                TypeDefKind::List(t) => self.type_list(iface, id, name, t, &ty.docs),
132                TypeDefKind::Type(t) => self.type_alias(iface, id, name, t, &ty.docs),
133                TypeDefKind::Future(_) => todo!("generate for future"),
134                TypeDefKind::Stream(_) => todo!("generate for stream"),
135            }
136        }
137
138        self.preprocess_resources(iface, dir);
139
140        for (id, _resource) in iface.resources.iter() {
141            self.type_resource(iface, id);
142        }
143
144        self.preprocess_functions(iface, dir);
145
146        for f in iface.functions.iter() {
147            match dir {
148                Direction::Import => self.import(iface, &f),
149                Direction::Export => self.export(iface, &f),
150            }
151        }
152
153        self.finish_functions(iface, dir);
154
155        self.finish_one(iface, files)
156    }
157
158    fn generate_all(&mut self, imports: &[Interface], exports: &[Interface], files: &mut Files) {
159        self.preprocess_all(imports, exports);
160
161        for imp in imports {
162            self.generate_one(imp, Direction::Import, files);
163        }
164
165        for exp in exports {
166            self.generate_one(exp, Direction::Export, files);
167        }
168
169        self.finish_all(files);
170    }
171}
172
173#[derive(Default)]
174pub struct Types {
175    type_info: HashMap<TypeId, TypeInfo>,
176}
177
178#[derive(Default, Clone, Copy)]
179pub struct TypeInfo {
180    /// Whether or not this type is ever used (transitively) within the
181    /// parameter of a function.
182    pub param: bool,
183
184    /// Whether or not this type is ever used (transitively) within the
185    /// result of a function.
186    pub result: bool,
187
188    /// Whether or not this type (transitively) has a list.
189    pub has_list: bool,
190
191    /// Whether or not this type (transitively) has a handle.
192    pub has_handle: bool,
193}
194
195impl std::ops::BitOrAssign for TypeInfo {
196    fn bitor_assign(&mut self, rhs: Self) {
197        self.param |= rhs.param;
198        self.result |= rhs.result;
199        self.has_list |= rhs.has_list;
200        self.has_handle |= rhs.has_handle;
201    }
202}
203
204impl Types {
205    pub fn analyze(&mut self, iface: &Interface) {
206        for (t, _) in iface.types.iter() {
207            self.type_id_info(iface, t);
208        }
209        for f in iface.functions.iter() {
210            for (_, ty) in f.params.iter() {
211                self.set_param_result_ty(iface, ty, true, false);
212            }
213            self.set_param_result_ty(iface, &f.result, false, true);
214        }
215    }
216
217    pub fn get(&self, id: TypeId) -> TypeInfo {
218        self.type_info[&id]
219    }
220
221    pub fn type_id_info(&mut self, iface: &Interface, ty: TypeId) -> TypeInfo {
222        if let Some(info) = self.type_info.get(&ty) {
223            return *info;
224        }
225        let mut info = TypeInfo::default();
226        match &iface.types[ty].kind {
227            TypeDefKind::Record(r) => {
228                for field in r.fields.iter() {
229                    info |= self.type_info(iface, &field.ty);
230                }
231            }
232            TypeDefKind::Tuple(t) => {
233                for ty in t.types.iter() {
234                    info |= self.type_info(iface, ty);
235                }
236            }
237            TypeDefKind::Flags(_) => {}
238            TypeDefKind::Enum(_) => {}
239            TypeDefKind::Variant(v) => {
240                for case in v.cases.iter() {
241                    info |= self.type_info(iface, &case.ty);
242                }
243            }
244            TypeDefKind::List(ty) => {
245                info = self.type_info(iface, ty);
246                info.has_list = true;
247            }
248            TypeDefKind::Type(ty) => {
249                info = self.type_info(iface, ty);
250            }
251            TypeDefKind::Option(ty) => {
252                info = self.type_info(iface, ty);
253            }
254            TypeDefKind::Result(r) => {
255                info = self.type_info(iface, &r.ok);
256                info |= self.type_info(iface, &r.err);
257            }
258            TypeDefKind::Union(u) => {
259                for case in u.cases.iter() {
260                    info |= self.type_info(iface, &case.ty);
261                }
262            }
263            TypeDefKind::Future(ty) => {
264                info = self.type_info(iface, ty);
265            }
266            TypeDefKind::Stream(stream) => {
267                info = self.type_info(iface, &stream.element);
268                info |= self.type_info(iface, &stream.end);
269            }
270        }
271        self.type_info.insert(ty, info);
272        return info;
273    }
274
275    pub fn type_info(&mut self, iface: &Interface, ty: &Type) -> TypeInfo {
276        let mut info = TypeInfo::default();
277        match ty {
278            Type::Handle(_) => info.has_handle = true,
279            Type::String => info.has_list = true,
280            Type::Id(id) => return self.type_id_info(iface, *id),
281            _ => {}
282        }
283        info
284    }
285
286    fn set_param_result_id(&mut self, iface: &Interface, ty: TypeId, param: bool, result: bool) {
287        match &iface.types[ty].kind {
288            TypeDefKind::Record(r) => {
289                for field in r.fields.iter() {
290                    self.set_param_result_ty(iface, &field.ty, param, result)
291                }
292            }
293            TypeDefKind::Tuple(t) => {
294                for ty in t.types.iter() {
295                    self.set_param_result_ty(iface, ty, param, result)
296                }
297            }
298            TypeDefKind::Flags(_) => {}
299            TypeDefKind::Enum(_) => {}
300            TypeDefKind::Variant(v) => {
301                for case in v.cases.iter() {
302                    self.set_param_result_ty(iface, &case.ty, param, result)
303                }
304            }
305            TypeDefKind::List(ty) | TypeDefKind::Type(ty) | TypeDefKind::Option(ty) => {
306                self.set_param_result_ty(iface, ty, param, result)
307            }
308            TypeDefKind::Result(r) => {
309                self.set_param_result_ty(iface, &r.ok, param, result);
310                self.set_param_result_ty(iface, &r.err, param, result);
311            }
312            TypeDefKind::Union(u) => {
313                for case in u.cases.iter() {
314                    self.set_param_result_ty(iface, &case.ty, param, result)
315                }
316            }
317            TypeDefKind::Future(ty) => self.set_param_result_ty(iface, ty, param, result),
318            TypeDefKind::Stream(stream) => {
319                self.set_param_result_ty(iface, &stream.element, param, result);
320                self.set_param_result_ty(iface, &stream.end, param, result);
321            }
322        }
323    }
324
325    fn set_param_result_ty(&mut self, iface: &Interface, ty: &Type, param: bool, result: bool) {
326        match ty {
327            Type::Id(id) => {
328                self.type_id_info(iface, *id);
329                let info = self.type_info.get_mut(id).unwrap();
330                if (param && !info.param) || (result && !info.result) {
331                    info.param = info.param || param;
332                    info.result = info.result || result;
333                    self.set_param_result_id(iface, *id, param, result);
334                }
335            }
336            _ => {}
337        }
338    }
339}
340
341#[derive(Default)]
342pub struct Files {
343    files: BTreeMap<String, Vec<u8>>,
344}
345
346impl Files {
347    pub fn push(&mut self, name: &str, contents: &[u8]) {
348        match self.files.entry(name.to_owned()) {
349            Entry::Vacant(entry) => {
350                entry.insert(contents.to_owned());
351            }
352            Entry::Occupied(ref mut entry) => {
353                entry.get_mut().extend_from_slice(contents);
354            }
355        }
356    }
357
358    pub fn iter(&self) -> impl Iterator<Item = (&'_ str, &'_ [u8])> {
359        self.files.iter().map(|p| (p.0.as_str(), p.1.as_slice()))
360    }
361}
362
363pub fn load(path: impl AsRef<Path>) -> Result<Interface> {
364    Interface::parse_file(path)
365}
366
367#[derive(Default)]
368pub struct Source {
369    s: String,
370    indent: usize,
371}
372
373impl Source {
374    pub fn push_str(&mut self, src: &str) {
375        let lines = src.lines().collect::<Vec<_>>();
376        for (i, line) in lines.iter().enumerate() {
377            let trimmed = line.trim();
378            if trimmed.starts_with("}") && self.s.ends_with("  ") {
379                self.s.pop();
380                self.s.pop();
381            }
382            self.s.push_str(if lines.len() == 1 {
383                line
384            } else {
385                line.trim_start()
386            });
387            if trimmed.ends_with('{') {
388                self.indent += 1;
389            }
390            if trimmed.starts_with('}') {
391                self.indent -= 1;
392            }
393            if i != lines.len() - 1 || src.ends_with("\n") {
394                self.newline();
395            }
396        }
397    }
398
399    pub fn indent(&mut self, amt: usize) {
400        self.indent += amt;
401    }
402
403    pub fn deindent(&mut self, amt: usize) {
404        self.indent -= amt;
405    }
406
407    fn newline(&mut self) {
408        self.s.push_str("\n");
409        for _ in 0..self.indent {
410            self.s.push_str("  ");
411        }
412    }
413
414    pub fn as_mut_string(&mut self) -> &mut String {
415        &mut self.s
416    }
417}
418
419impl Write for Source {
420    fn write_str(&mut self, s: &str) -> fmt::Result {
421        self.push_str(s);
422        Ok(())
423    }
424}
425
426impl Deref for Source {
427    type Target = str;
428    fn deref(&self) -> &str {
429        &self.s
430    }
431}
432
433impl From<Source> for String {
434    fn from(s: Source) -> String {
435        s.s
436    }
437}
438
439/// Calls [`write!`] with the passed arguments and unwraps the result.
440///
441/// Useful for writing to things with infallible `Write` implementations like
442/// `Source` and `String`.
443///
444/// [`write!`]: std::write
445#[macro_export]
446macro_rules! uwrite {
447    ($dst:expr, $($arg:tt)*) => {
448        write!($dst, $($arg)*).unwrap()
449    };
450}
451
452/// Calls [`writeln!`] with the passed arguments and unwraps the result.
453///
454/// Useful for writing to things with infallible `Write` implementations like
455/// `Source` and `String`.
456///
457/// [`writeln!`]: std::writeln
458#[macro_export]
459macro_rules! uwriteln {
460    ($dst:expr, $($arg:tt)*) => {
461        writeln!($dst, $($arg)*).unwrap()
462    };
463}
464
465#[cfg(test)]
466mod tests {
467    use super::{Generator, Source};
468
469    #[test]
470    fn simple_append() {
471        let mut s = Source::default();
472        s.push_str("x");
473        assert_eq!(s.s, "x");
474        s.push_str("y");
475        assert_eq!(s.s, "xy");
476        s.push_str("z ");
477        assert_eq!(s.s, "xyz ");
478        s.push_str(" a ");
479        assert_eq!(s.s, "xyz  a ");
480        s.push_str("\na");
481        assert_eq!(s.s, "xyz  a \na");
482    }
483
484    #[test]
485    fn newline_remap() {
486        let mut s = Source::default();
487        s.push_str("function() {\n");
488        s.push_str("y\n");
489        s.push_str("}\n");
490        assert_eq!(s.s, "function() {\n  y\n}\n");
491    }
492
493    #[test]
494    fn if_else() {
495        let mut s = Source::default();
496        s.push_str("if() {\n");
497        s.push_str("y\n");
498        s.push_str("} else if () {\n");
499        s.push_str("z\n");
500        s.push_str("}\n");
501        assert_eq!(s.s, "if() {\n  y\n} else if () {\n  z\n}\n");
502    }
503
504    #[test]
505    fn trim_ws() {
506        let mut s = Source::default();
507        s.push_str(
508            "function() {
509                x
510        }",
511        );
512        assert_eq!(s.s, "function() {\n  x\n}");
513    }
514
515    #[test]
516    fn generator_is_object_safe() {
517        fn _assert(_: &dyn Generator) {}
518    }
519}