cosmian_wit_bindgen_rust_impl/
lib.rs1use cosmian_wit_bindgen_gen_core::{cosmian_wit_parser::Interface, Direction, Files, Generator};
2use proc_macro::TokenStream;
3use syn::parse::{Error, Parse, ParseStream, Result};
4use syn::punctuated::Punctuated;
5use syn::{token, Token};
6
7#[proc_macro]
8pub fn import(input: TokenStream) -> TokenStream {
9 run(input, Direction::Import)
10}
11
12#[proc_macro]
13pub fn export(input: TokenStream) -> TokenStream {
14 run(input, Direction::Export)
15}
16
17fn run(input: TokenStream, dir: Direction) -> TokenStream {
18 let input = syn::parse_macro_input!(input as Opts);
19 let mut gen = input.opts.build();
20 let mut files = Files::default();
21 let (imports, exports) = match dir {
22 Direction::Import => (input.interfaces, vec![]),
23 Direction::Export => (vec![], input.interfaces),
24 };
25 gen.generate_all(&imports, &exports, &mut files);
26 let (_, contents) = files.iter().next().unwrap();
27 let mut contents = std::str::from_utf8(contents).unwrap().to_string();
28
29 let cwd = std::env::current_dir().unwrap();
32 for file in input.files.iter() {
33 contents.push_str(&format!(
34 "const _: &str = include_str!(r#\"{}\"#);\n",
35 cwd.join(file).display()
36 ));
37 }
38
39 contents.parse().unwrap()
40}
41
42struct Opts {
43 opts: cosmian_wit_bindgen_gen_rust_wasm::Opts,
44 interfaces: Vec<Interface>,
45 files: Vec<String>,
46}
47
48mod kw {
49 syn::custom_keyword!(src);
50 syn::custom_keyword!(paths);
51 syn::custom_keyword!(unchecked);
52 syn::custom_keyword!(multi_module);
53}
54
55impl Parse for Opts {
56 fn parse(input: ParseStream<'_>) -> Result<Opts> {
57 let mut opts = cosmian_wit_bindgen_gen_rust_wasm::Opts::default();
58 let call_site = proc_macro2::Span::call_site();
59 let mut files = Vec::new();
60 let interfaces = if input.peek(token::Brace) {
61 let content;
62 syn::braced!(content in input);
63 let mut interfaces = Vec::new();
64 let fields = Punctuated::<ConfigField, Token![,]>::parse_terminated(&content)?;
65 for field in fields.into_pairs() {
66 match field.into_value() {
67 ConfigField::Unchecked => opts.unchecked = true,
68 ConfigField::MultiModule => opts.multi_module = true,
69 ConfigField::Interfaces(v) => interfaces = v,
70 }
71 }
72 if interfaces.is_empty() {
73 return Err(Error::new(
74 call_site,
75 "must either specify `src` or `paths` keys",
76 ));
77 }
78 interfaces
79 } else {
80 while !input.is_empty() {
81 let s = input.parse::<syn::LitStr>()?;
82 files.push(s.value());
83 }
84 let mut interfaces = Vec::new();
85 for path in files.iter() {
86 let iface = Interface::parse_file(path).map_err(|e| Error::new(call_site, e))?;
87 interfaces.push(iface);
88 }
89 interfaces
90 };
91 Ok(Opts {
92 files,
93 opts,
94 interfaces,
95 })
96 }
97}
98
99enum ConfigField {
100 Interfaces(Vec<Interface>),
101 Unchecked,
102 MultiModule,
103}
104
105impl Parse for ConfigField {
106 fn parse(input: ParseStream<'_>) -> Result<Self> {
107 let l = input.lookahead1();
108 if l.peek(kw::src) {
109 input.parse::<kw::src>()?;
110 let name;
111 syn::bracketed!(name in input);
112 let name = name.parse::<syn::LitStr>()?;
113 input.parse::<Token![:]>()?;
114 let s = input.parse::<syn::LitStr>()?;
115 let interface =
116 Interface::parse(&name.value(), &s.value()).map_err(|e| Error::new(s.span(), e))?;
117 Ok(ConfigField::Interfaces(vec![interface]))
118 } else if l.peek(kw::paths) {
119 input.parse::<kw::paths>()?;
120 input.parse::<Token![:]>()?;
121 let paths;
122 let bracket = syn::bracketed!(paths in input);
123 let paths = Punctuated::<syn::LitStr, Token![,]>::parse_terminated(&paths)?;
124 let values = paths.iter().map(|s| s.value()).collect::<Vec<_>>();
125 let mut interfaces = Vec::new();
126 for value in &values {
127 let interface =
128 Interface::parse_file(value).map_err(|e| Error::new(bracket.span, e))?;
129 interfaces.push(interface);
130 }
131 Ok(ConfigField::Interfaces(interfaces))
132 } else if l.peek(kw::unchecked) {
133 input.parse::<kw::unchecked>()?;
134 Ok(ConfigField::Unchecked)
135 } else if l.peek(kw::multi_module) {
136 input.parse::<kw::multi_module>()?;
137 Ok(ConfigField::MultiModule)
138 } else {
139 Err(l.error())
140 }
141 }
142}