Skip to main content

dodo_bindgen_codegen/
class.rs

1use std::collections::BTreeMap;
2
3use crate::util::*;
4use crate::{FfiFunction, FfiType, TsMethod, TsModule};
5use dodo_bindgen_rust_ir::ItemImpl;
6use proc_macro2::TokenStream;
7use syn::Ident;
8
9use super::fn_::ItemFnExt as _;
10
11#[derive(Clone, Debug)]
12pub struct TsClass {
13    pub methods: Vec<TsMethod>,
14}
15
16#[derive(Clone, Debug, Default)]
17pub struct ClassDefs {
18    pub store: BTreeMap<Ident, TsClass>,
19}
20
21pub trait ItemImplExt {
22    fn unwrap(self, module: &mut TsModule);
23}
24
25impl ItemImplExt for ItemImpl {
26    fn unwrap(self, module: &mut TsModule) {
27        let mut methods = Vec::new();
28        for item in self.items {
29            let method = item.unwrap(module);
30            methods.push(method);
31        }
32
33        if let Some(ts_class) = module.class_defs.store.get_mut(&self.self_ty) {
34            ts_class.methods.append(&mut methods);
35        } else {
36            module.ffi_lib.interface.push_fn(FfiFunction {
37                ident: format_ident!("__{}__drop", &self.self_ty.to_string()),
38                inputs: vec![FfiType::Pointer],
39                output: FfiType::Void,
40                non_blocking: false,
41            });
42            module
43                .class_defs
44                .store
45                .insert(self.self_ty, TsClass { methods });
46        }
47    }
48}
49
50impl ToTokens for ClassDefs {
51    fn to_tokens(&self, tokens: &mut TokenStream) {
52        for (ident, TsClass { methods }) in &self.store {
53            let mut _methods = Vec::new();
54            for method in methods {
55                let method = method.print();
56                _methods.push(method);
57            }
58
59            tokens.extend(quote! {
60                export class #ident extends RustPrototype<#ident> {
61                    #(#_methods)*
62                }
63            });
64        }
65    }
66}
67
68/* -------------------------------------------------------------------------- */
69
70// MARK: tests
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75    use crate::{TsFormat, TsModule};
76    use dodo_bindgen_rust_ir::{parse_quote, prettify};
77
78    macro_rules! test_transform {
79        ($($tt:tt)*) => {
80            println!("[rust source]\n{}", prettify!(stringify!($($tt)*)));
81
82            let source = parse_quote!(ItemImpl, $($tt)*);
83
84            let mut export = source.clone();
85            export.transform();
86            println!("[rust wrapper]\n{}", prettify!(export.to_token_stream().to_string().as_str()));
87
88            let mut module = TsModule::default();
89            source.unwrap(&mut module);
90
91            let ffi_lib = TsFormat::format(module.ffi_lib.to_token_stream().to_string());
92            println!("[ts ffi]\n{}", ffi_lib);
93
94            let class_defs = TsFormat::format(module.class_defs.to_token_stream().to_string());
95            println!("[ts mod]\n{}", class_defs);
96        };
97    }
98
99    #[test]
100    fn test_print() {
101        test_transform!(
102            impl CustomType {
103                fn test_fn(&self) {}
104            }
105        );
106    }
107}