wit_bindgen_wrpc_rust/
lib.rs

1use crate::interface::InterfaceGenerator;
2use anyhow::{bail, Result};
3use heck::{ToSnakeCase, ToUpperCamelCase};
4use std::collections::{BTreeMap, HashMap, HashSet};
5use std::fmt::{self, Write as _};
6use std::mem;
7use wit_bindgen_core::wit_parser::{
8    Flags, FlagsRepr, Function, Int, InterfaceId, Resolve, SizeAlign, TypeId, World, WorldId,
9    WorldItem, WorldKey,
10};
11use wit_bindgen_core::{
12    name_package_module, uwrite, uwriteln, Files, InterfaceGenerator as _, Source, Types,
13    WorldGenerator,
14};
15
16mod interface;
17
18struct InterfaceName {
19    /// True when this interface name has been remapped through the use of `with` in the `bindgen!`
20    /// macro invocation.
21    remapped: bool,
22
23    /// The string name for this interface.
24    path: String,
25}
26
27#[derive(Default)]
28struct RustWrpc {
29    types: Types,
30    src: Source,
31    opts: Opts,
32    import_modules: Vec<(String, Vec<String>)>,
33    export_modules: Vec<(String, Vec<String>)>,
34    skip: HashSet<String>,
35    interface_names: HashMap<InterfaceId, InterfaceName>,
36    import_funcs_called: bool,
37    with_name_counter: usize,
38    // Track which interfaces were generated. Remapped interfaces provided via `with`
39    // are required to be used.
40    generated_interfaces: HashSet<String>,
41    world: Option<WorldId>,
42
43    export_paths: Vec<String>,
44    /// Interface names to how they should be generated
45    with: GenerationConfiguration,
46}
47
48#[derive(Default)]
49struct GenerationConfiguration {
50    map: HashMap<String, InterfaceGeneration>,
51    generate_by_default: bool,
52}
53
54impl GenerationConfiguration {
55    fn get(&self, key: &str) -> Option<&InterfaceGeneration> {
56        self.map.get(key).or_else(|| {
57            self.generate_by_default
58                .then_some(&InterfaceGeneration::Generate)
59        })
60    }
61
62    fn insert(&mut self, name: String, generate: InterfaceGeneration) {
63        self.map.insert(name, generate);
64    }
65
66    fn iter(&self) -> impl Iterator<Item = (&String, &InterfaceGeneration)> {
67        self.map.iter()
68    }
69}
70
71/// How an interface should be generated.
72enum InterfaceGeneration {
73    /// Remapped to some other type
74    Remap(String),
75    /// Generate the interface
76    Generate,
77}
78
79#[cfg(feature = "clap")]
80fn parse_with(s: &str) -> Result<(String, WithOption), String> {
81    let (k, v) = s.split_once('=').ok_or_else(|| {
82        format!("expected string of form `<key>=<value>[,<key>=<value>...]`; got `{s}`")
83    })?;
84    let v = match v {
85        "generate" => WithOption::Generate,
86        other => WithOption::Path(other.to_string()),
87    };
88    Ok((k.to_string(), v))
89}
90
91#[derive(Default, Debug, Clone)]
92#[cfg_attr(feature = "clap", derive(clap::Args))]
93pub struct Opts {
94    /// Whether or not a formatter is executed to format generated code.
95    #[cfg_attr(feature = "clap", arg(long))]
96    pub format: bool,
97
98    /// Names of functions to skip generating bindings for.
99    #[cfg_attr(feature = "clap", arg(long))]
100    pub skip: Vec<String>,
101
102    /// The optional path to the bitflags crate to use.
103    ///
104    /// This defaults to `wit_bindgen_wrpc::bitflags`.
105    #[cfg_attr(feature = "clap", arg(long))]
106    pub bitflags_path: Option<String>,
107
108    /// Additional derive attributes to add to generated types. If using in a CLI, this flag can be
109    /// specified multiple times to add multiple attributes.
110    ///
111    /// These derive attributes will be added to any generated structs or enums
112    #[cfg_attr(feature = "clap", arg(long = "additional_derive_attribute", short = 'd', default_values_t = Vec::<String>::new()))]
113    pub additional_derive_attributes: Vec<String>,
114
115    /// Remapping of interface names to rust module names.
116    ///
117    /// Argument must be of the form `k=v` and this option can be passed
118    /// multiple times or one option can be comma separated, for example
119    /// `k1=v1,k2=v2`.
120    #[cfg_attr(feature = "clap", arg(long, value_parser = parse_with, value_delimiter = ','))]
121    pub with: Vec<(String, WithOption)>,
122
123    /// Indicates that all interfaces not specified in `with` should be
124    /// generated.
125    #[cfg_attr(feature = "clap", arg(long))]
126    pub generate_all: bool,
127
128    /// Whether to generate unused structures, not generated by default (false)
129    #[cfg_attr(feature = "clap", arg(long))]
130    pub generate_unused_types: bool,
131
132    /// The optional path to the `anyhow` crate to use.
133    ///
134    /// This defaults to `wit_bindgen_wrpc::anyhow`.
135    #[cfg_attr(feature = "clap", arg(long))]
136    pub anyhow_path: Option<String>,
137
138    /// The optional path to the `bytes` crate to use.
139    ///
140    /// This defaults to `wit_bindgen_wrpc::bytes`.
141    #[cfg_attr(feature = "clap", arg(long))]
142    pub bytes_path: Option<String>,
143
144    /// The optional path to the `futures` crate to use.
145    ///
146    /// This defaults to `wit_bindgen_wrpc::futures`.
147    #[cfg_attr(feature = "clap", arg(long))]
148    pub futures_path: Option<String>,
149
150    /// The optional path to the `tokio` crate to use.
151    ///
152    /// This defaults to `wit_bindgen_wrpc::tokio`.
153    #[cfg_attr(feature = "clap", arg(long))]
154    pub tokio_path: Option<String>,
155
156    /// The optional path to the `tokio-util` crate to use.
157    ///
158    /// This defaults to `wit_bindgen_wrpc::tokio_util`.
159    #[cfg_attr(feature = "clap", arg(long))]
160    pub tokio_util_path: Option<String>,
161
162    /// The optional path to the `tracing` crate to use.
163    ///
164    /// This defaults to `wit_bindgen_wrpc::tracing`.
165    #[cfg_attr(feature = "clap", arg(long))]
166    pub tracing_path: Option<String>,
167
168    /// The optional path to the `wasm-tokio` crate to use.
169    ///
170    /// This defaults to `wit_bindgen_wrpc::wasm_tokio`.
171    #[cfg_attr(feature = "clap", arg(long))]
172    pub wasm_tokio_path: Option<String>,
173
174    /// The optional path to the `wrpc-transport` crate to use.
175    ///
176    /// This defaults to `wit_bindgen_wrpc::wrpc_transport`.
177    #[cfg_attr(feature = "clap", arg(long))]
178    pub wrpc_transport_path: Option<String>,
179}
180
181impl Opts {
182    #[must_use]
183    pub fn build(self) -> Box<dyn WorldGenerator> {
184        let mut r = RustWrpc::new();
185        r.skip = self.skip.iter().cloned().collect();
186        r.opts = self;
187        Box::new(r)
188    }
189}
190
191impl RustWrpc {
192    fn new() -> RustWrpc {
193        RustWrpc::default()
194    }
195
196    fn interface<'a>(
197        &'a mut self,
198        identifier: Identifier<'a>,
199        resolve: &'a Resolve,
200        in_import: bool,
201    ) -> InterfaceGenerator<'a> {
202        let mut sizes = SizeAlign::default();
203        sizes.fill(resolve);
204
205        InterfaceGenerator {
206            identifier,
207            src: Source::default(),
208            in_import,
209            gen: self,
210            resolve,
211        }
212    }
213
214    fn emit_modules(&mut self, modules: Vec<(String, Vec<String>)>) {
215        #[derive(Default)]
216        struct Module {
217            submodules: BTreeMap<String, Module>,
218            contents: Vec<String>,
219        }
220        let mut map = Module::default();
221        for (module, path) in modules {
222            let mut cur = &mut map;
223            for name in &path[..path.len() - 1] {
224                cur = cur
225                    .submodules
226                    .entry(name.clone())
227                    .or_insert(Module::default());
228            }
229            cur.contents.push(module);
230        }
231        emit(&mut self.src, map);
232        fn emit(me: &mut Source, module: Module) {
233            for (name, submodule) in module.submodules {
234                // Ignore dead-code warnings. If the bindings are only used
235                // within a crate, and not exported to a different crate, some
236                // parts may be unused, and that's ok.
237                uwriteln!(me, "#[allow(dead_code)]");
238
239                uwriteln!(me, "pub mod {name} {{");
240                emit(me, submodule);
241                uwriteln!(me, "}}");
242            }
243            for submodule in module.contents {
244                uwriteln!(me, "{submodule}");
245            }
246        }
247    }
248
249    fn anyhow_path(&self) -> &str {
250        self.opts
251            .anyhow_path
252            .as_deref()
253            .unwrap_or("::wit_bindgen_wrpc::anyhow")
254    }
255
256    fn bitflags_path(&self) -> &str {
257        self.opts
258            .bitflags_path
259            .as_deref()
260            .unwrap_or("::wit_bindgen_wrpc::bitflags")
261    }
262
263    fn bytes_path(&self) -> &str {
264        self.opts
265            .bytes_path
266            .as_deref()
267            .unwrap_or("::wit_bindgen_wrpc::bytes")
268    }
269
270    fn futures_path(&self) -> &str {
271        self.opts
272            .futures_path
273            .as_deref()
274            .unwrap_or("::wit_bindgen_wrpc::futures")
275    }
276
277    fn tokio_path(&self) -> &str {
278        self.opts
279            .tokio_path
280            .as_deref()
281            .unwrap_or("::wit_bindgen_wrpc::tokio")
282    }
283
284    fn tokio_util_path(&self) -> &str {
285        self.opts
286            .tokio_util_path
287            .as_deref()
288            .unwrap_or("::wit_bindgen_wrpc::tokio_util")
289    }
290
291    fn tracing_path(&self) -> &str {
292        self.opts
293            .tracing_path
294            .as_deref()
295            .unwrap_or("::wit_bindgen_wrpc::tracing")
296    }
297
298    fn wasm_tokio_path(&self) -> &str {
299        self.opts
300            .wasm_tokio_path
301            .as_deref()
302            .unwrap_or("::wit_bindgen_wrpc::wasm_tokio")
303    }
304
305    fn wrpc_transport_path(&self) -> &str {
306        self.opts
307            .wrpc_transport_path
308            .as_deref()
309            .unwrap_or("::wit_bindgen_wrpc::wrpc_transport")
310    }
311
312    fn name_interface(
313        &mut self,
314        resolve: &Resolve,
315        id: InterfaceId,
316        name: &WorldKey,
317        is_export: bool,
318    ) -> Result<bool> {
319        let with_name = resolve.name_world_key(name);
320        let Some(remapping) = self.with.get(&with_name) else {
321            bail!("no remapping found for {with_name:?} - use the `generate!` macro's `with` option to force the interface to be generated or specify where it is already defined:
322```
323with: {{\n\t{with_name:?}: generate\n}}
324```")
325        };
326        self.generated_interfaces.insert(with_name);
327        let entry = match remapping {
328            InterfaceGeneration::Remap(remapped_path) => {
329                let name = format!("__with_name{}", self.with_name_counter);
330                self.with_name_counter += 1;
331                uwriteln!(self.src, "use {remapped_path} as {name};");
332                InterfaceName {
333                    remapped: true,
334                    path: name,
335                }
336            }
337            InterfaceGeneration::Generate => {
338                let path = compute_module_path(name, resolve, is_export).join("::");
339
340                InterfaceName {
341                    remapped: false,
342                    path,
343                }
344            }
345        };
346
347        let remapped = entry.remapped;
348        self.interface_names.insert(id, entry);
349
350        Ok(remapped)
351    }
352
353    /// Generates a `serve` function for the `world_id` specified.
354    ///
355    /// This will generate a macro which will then itself invoke all the
356    /// other macros collected in `self.export_paths` prior. All these macros
357    /// are woven together in this single invocation.
358    fn finish_serve_function(&mut self) {
359        const ROOT: &str = "Handler<T::Context>";
360        let mut traits: Vec<String> = self
361            .export_paths
362            .iter()
363            .map(|path| {
364                if path.is_empty() {
365                    ROOT.to_string()
366                } else {
367                    format!("{path}::{ROOT}")
368                }
369            })
370            .collect();
371        let bound = match traits.len() {
372            0 => return,
373            1 => traits.pop().unwrap(),
374            _ => traits.join(" + "),
375        };
376        let anyhow = self.anyhow_path().to_string();
377        let futures = self.futures_path().to_string();
378        let tokio = self.tokio_path().to_string();
379        let wrpc_transport = self.wrpc_transport_path().to_string();
380        uwriteln!(
381            self.src,
382            r#"
383#[allow(clippy::manual_async_fn)]
384pub fn serve<'a, T: {wrpc_transport}::Serve>(
385    wrpc: &'a T,
386    handler: impl {bound} + ::core::marker::Send + ::core::marker::Sync + ::core::clone::Clone + 'static,
387) -> impl ::core::future::Future<
388        Output = {anyhow}::Result<
389            ::std::vec::Vec<
390                (
391                    &'static str,
392                    &'static str,
393                    ::core::pin::Pin<
394                        ::std::boxed::Box<
395                            dyn {futures}::Stream<
396                                Item = {anyhow}::Result<
397                                    ::core::pin::Pin<
398                                        ::std::boxed::Box<
399                                            dyn ::core::future::Future<
400                                                Output = {anyhow}::Result<()>
401                                            > + ::core::marker::Send + 'static
402                                        >
403                                    >
404                                >
405                            > + ::core::marker::Send + 'static
406                        >
407                    >
408                )
409            >
410        >
411    > + ::core::marker::Send + {wrpc_transport}::Captures<'a> {{
412    async move {{
413        let interfaces = {tokio}::try_join!("#
414        );
415        for path in &self.export_paths {
416            if !path.is_empty() {
417                self.src.push_str(path);
418                self.src.push_str("::");
419            }
420            self.src.push_str("serve_interface(wrpc, handler.clone()),");
421        }
422        uwriteln!(
423            self.src,
424            r#"
425        )?;
426        let mut streams = Vec::new();"#
427        );
428        for i in 0..self.export_paths.len() {
429            uwrite!(
430                self.src,
431                r"
432        for s in interfaces.{i} {{
433            streams.push(s);
434        }}"
435            );
436        }
437        uwriteln!(
438            self.src,
439            r#"
440        Ok(streams)
441    }}
442}}"#
443        );
444    }
445}
446
447impl WorldGenerator for RustWrpc {
448    fn preprocess(&mut self, resolve: &Resolve, world: WorldId) {
449        wit_bindgen_core::generated_preamble(&mut self.src, env!("CARGO_PKG_VERSION"));
450
451        // Render some generator options to assist with debugging and/or to help
452        // recreate it if the original generation command is lost.
453        uwriteln!(self.src, "// Options used:");
454        if !self.opts.skip.is_empty() {
455            uwriteln!(self.src, "//   * skip: {:?}", self.opts.skip);
456        }
457        if !self.opts.additional_derive_attributes.is_empty() {
458            uwriteln!(
459                self.src,
460                "//   * additional derives {:?}",
461                self.opts.additional_derive_attributes
462            );
463        }
464        for (k, v) in &self.opts.with {
465            uwriteln!(self.src, "//   * with {k:?} = {v:?}");
466        }
467        self.types.analyze(resolve);
468        self.world = Some(world);
469
470        let world = &resolve.worlds[world];
471        // Specify that all imports local to the world's package should be generated
472        for (key, item) in world.imports.iter().chain(world.exports.iter()) {
473            if let WorldItem::Interface { id, .. } = item {
474                if resolve.interfaces[*id].package == world.package {
475                    let name = resolve.name_world_key(key);
476                    if self.with.get(&name).is_none() {
477                        self.with.insert(name, InterfaceGeneration::Generate);
478                    }
479                }
480            }
481        }
482        for (k, v) in &self.opts.with {
483            self.with.insert(k.clone(), v.clone().into());
484        }
485        self.with.generate_by_default = self.opts.generate_all;
486    }
487
488    fn import_interface(
489        &mut self,
490        resolve: &Resolve,
491        name: &WorldKey,
492        id: InterfaceId,
493        _files: &mut Files,
494    ) -> Result<()> {
495        let mut gen = self.interface(Identifier::Interface(id, name), resolve, true);
496        let (snake, module_path) = gen.start_append_submodule(name);
497        if gen.gen.name_interface(resolve, id, name, false)? {
498            return Ok(());
499        }
500        gen.types(id);
501
502        let interface = &resolve.interfaces[id];
503        let name = match name {
504            WorldKey::Name(s) => s.to_string(),
505            WorldKey::Interface(..) => interface
506                .name
507                .as_ref()
508                .expect("interface name missing")
509                .to_string(),
510        };
511        let instance = if let Some(package) = interface.package {
512            resolve.id_of_name(package, &name)
513        } else {
514            name
515        };
516        gen.generate_imports(&instance, resolve.interfaces[id].functions.values());
517
518        gen.finish_append_submodule(&snake, module_path);
519
520        Ok(())
521    }
522
523    fn import_funcs(
524        &mut self,
525        resolve: &Resolve,
526        world: WorldId,
527        funcs: &[(&str, &Function)],
528        _files: &mut Files,
529    ) {
530        self.import_funcs_called = true;
531
532        let mut gen = self.interface(Identifier::World(world), resolve, true);
533        let World {
534            ref name, package, ..
535        } = resolve.worlds[world];
536        let instance = if let Some(package) = package {
537            resolve.id_of_name(package, name)
538        } else {
539            name.to_string()
540        };
541        gen.generate_imports(&instance, funcs.iter().map(|(_, func)| *func));
542
543        let src = gen.finish();
544        self.src.push_str(&src);
545    }
546
547    fn export_interface(
548        &mut self,
549        resolve: &Resolve,
550        name: &WorldKey,
551        id: InterfaceId,
552        _files: &mut Files,
553    ) -> Result<()> {
554        let mut gen = self.interface(Identifier::Interface(id, name), resolve, false);
555        let (snake, module_path) = gen.start_append_submodule(name);
556        if gen.gen.name_interface(resolve, id, name, true)? {
557            return Ok(());
558        }
559        gen.types(id);
560        let exports = gen.generate_exports(
561            Identifier::Interface(id, name),
562            resolve.interfaces[id].functions.values(),
563        );
564        gen.finish_append_submodule(&snake, module_path);
565        if exports {
566            self.export_paths
567                .push(self.interface_names[&id].path.clone());
568        }
569        Ok(())
570    }
571
572    fn export_funcs(
573        &mut self,
574        resolve: &Resolve,
575        world: WorldId,
576        funcs: &[(&str, &Function)],
577        _files: &mut Files,
578    ) -> Result<()> {
579        let mut gen = self.interface(Identifier::World(world), resolve, false);
580        let exports = gen.generate_exports(Identifier::World(world), funcs.iter().map(|f| f.1));
581        let src = gen.finish();
582        self.src.push_str(&src);
583        if exports {
584            self.export_paths.push(String::new());
585        }
586        Ok(())
587    }
588
589    fn import_types(
590        &mut self,
591        resolve: &Resolve,
592        world: WorldId,
593        types: &[(&str, TypeId)],
594        _files: &mut Files,
595    ) {
596        let mut gen = self.interface(Identifier::World(world), resolve, true);
597        for (name, ty) in types {
598            gen.define_type(name, *ty);
599        }
600        let src = gen.finish();
601        self.src.push_str(&src);
602    }
603
604    fn finish_imports(&mut self, resolve: &Resolve, world: WorldId, files: &mut Files) {
605        if !self.import_funcs_called {
606            // We call `import_funcs` even if the world doesn't import any
607            // functions since one of the side effects of that method is to
608            // generate `struct`s for any imported resources.
609            self.import_funcs(resolve, world, &[], files);
610        }
611    }
612
613    fn finish(&mut self, resolve: &Resolve, world: WorldId, files: &mut Files) -> Result<()> {
614        let name = &resolve.worlds[world].name;
615
616        let imports = mem::take(&mut self.import_modules);
617        self.emit_modules(imports);
618        let exports = mem::take(&mut self.export_modules);
619        self.emit_modules(exports);
620
621        self.finish_serve_function();
622
623        let mut src = mem::take(&mut self.src);
624        if self.opts.format {
625            let syntax_tree = syn::parse_file(src.as_str()).unwrap();
626            *src.as_mut_string() = prettyplease::unparse(&syntax_tree);
627        }
628
629        let module_name = name.to_snake_case();
630        files.push(&format!("{module_name}.rs"), src.as_bytes());
631
632        let remapped_keys = self
633            .with
634            .iter()
635            .map(|(k, _)| k)
636            .cloned()
637            .collect::<HashSet<String>>();
638
639        let mut unused_keys = remapped_keys
640            .difference(&self.generated_interfaces)
641            .collect::<Vec<&String>>();
642
643        unused_keys.sort();
644
645        if !unused_keys.is_empty() {
646            bail!("unused remappings provided via `with`: {unused_keys:?}");
647        }
648
649        Ok(())
650    }
651}
652
653fn compute_module_path(name: &WorldKey, resolve: &Resolve, is_export: bool) -> Vec<String> {
654    let mut path = Vec::new();
655    if is_export {
656        path.push("exports".to_string());
657    }
658    match name {
659        WorldKey::Name(name) => {
660            path.push(to_rust_ident(name));
661        }
662        WorldKey::Interface(id) => {
663            let iface = &resolve.interfaces[*id];
664            let pkg = iface.package.unwrap();
665            let pkgname = resolve.packages[pkg].name.clone();
666            path.push(to_rust_ident(&pkgname.namespace));
667            path.push(to_rust_ident(&name_package_module(resolve, pkg)));
668            path.push(to_rust_ident(iface.name.as_ref().unwrap()));
669        }
670    }
671    path
672}
673
674enum Identifier<'a> {
675    World(WorldId),
676    Interface(InterfaceId, &'a WorldKey),
677}
678
679/// Options for with "with" remappings.
680#[derive(Debug, Clone)]
681pub enum WithOption {
682    Path(String),
683    Generate,
684}
685
686impl std::fmt::Display for WithOption {
687    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
688        match self {
689            WithOption::Path(p) => f.write_fmt(format_args!("\"{p}\"")),
690            WithOption::Generate => f.write_str("generate"),
691        }
692    }
693}
694
695impl From<WithOption> for InterfaceGeneration {
696    fn from(opt: WithOption) -> Self {
697        match opt {
698            WithOption::Path(p) => InterfaceGeneration::Remap(p),
699            WithOption::Generate => InterfaceGeneration::Generate,
700        }
701    }
702}
703
704#[derive(Default)]
705struct FnSig {
706    private: bool,
707    use_item_name: bool,
708    self_arg: Option<String>,
709    self_is_first_param: bool,
710}
711
712#[must_use]
713pub fn to_rust_ident(name: &str) -> String {
714    match name {
715        // Escape Rust keywords.
716        // Source: https://doc.rust-lang.org/reference/keywords.html
717        "as" => "as_".into(),
718        "break" => "break_".into(),
719        "const" => "const_".into(),
720        "continue" => "continue_".into(),
721        "crate" => "crate_".into(),
722        "else" => "else_".into(),
723        "enum" => "enum_".into(),
724        "extern" => "extern_".into(),
725        "false" => "false_".into(),
726        "fn" => "fn_".into(),
727        "for" => "for_".into(),
728        "if" => "if_".into(),
729        "impl" => "impl_".into(),
730        "in" => "in_".into(),
731        "let" => "let_".into(),
732        "loop" => "loop_".into(),
733        "match" => "match_".into(),
734        "mod" => "mod_".into(),
735        "move" => "move_".into(),
736        "mut" => "mut_".into(),
737        "pub" => "pub_".into(),
738        "ref" => "ref_".into(),
739        "return" => "return_".into(),
740        "self" => "self_".into(),
741        "static" => "static_".into(),
742        "struct" => "struct_".into(),
743        "super" => "super_".into(),
744        "trait" => "trait_".into(),
745        "true" => "true_".into(),
746        "type" => "type_".into(),
747        "unsafe" => "unsafe_".into(),
748        "use" => "use_".into(),
749        "where" => "where_".into(),
750        "while" => "while_".into(),
751        "async" => "async_".into(),
752        "await" => "await_".into(),
753        "dyn" => "dyn_".into(),
754        "abstract" => "abstract_".into(),
755        "become" => "become_".into(),
756        "box" => "box_".into(),
757        "do" => "do_".into(),
758        "final" => "final_".into(),
759        "macro" => "macro_".into(),
760        "override" => "override_".into(),
761        "priv" => "priv_".into(),
762        "typeof" => "typeof_".into(),
763        "unsized" => "unsized_".into(),
764        "virtual" => "virtual_".into(),
765        "yield" => "yield_".into(),
766        "try" => "try_".into(),
767        s => s.to_snake_case(),
768    }
769}
770
771fn to_upper_camel_case(name: &str) -> String {
772    match name {
773        // The name "Handler" is reserved for traits generated by exported
774        // interfaces, so remap types defined in wit to something else.
775        "handler" => "Handler_".to_string(),
776        s => s.to_upper_camel_case(),
777    }
778}
779
780fn int_repr(repr: Int) -> &'static str {
781    match repr {
782        Int::U8 => "u8",
783        Int::U16 => "u16",
784        Int::U32 => "u32",
785        Int::U64 => "u64",
786    }
787}
788
789enum RustFlagsRepr {
790    U8,
791    U16,
792    U32,
793    U64,
794    U128,
795}
796
797impl RustFlagsRepr {
798    fn new(f: &Flags) -> RustFlagsRepr {
799        match f.repr() {
800            FlagsRepr::U8 => RustFlagsRepr::U8,
801            FlagsRepr::U16 => RustFlagsRepr::U16,
802            FlagsRepr::U32(1) => RustFlagsRepr::U32,
803            FlagsRepr::U32(2) => RustFlagsRepr::U64,
804            FlagsRepr::U32(3 | 4) => RustFlagsRepr::U128,
805            FlagsRepr::U32(n) => panic!("unsupported number of flags: {}", n * 32),
806        }
807    }
808}
809
810impl fmt::Display for RustFlagsRepr {
811    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
812        match self {
813            RustFlagsRepr::U8 => "u8".fmt(f),
814            RustFlagsRepr::U16 => "u16".fmt(f),
815            RustFlagsRepr::U32 => "u32".fmt(f),
816            RustFlagsRepr::U64 => "u64".fmt(f),
817            RustFlagsRepr::U128 => "u128".fmt(f),
818        }
819    }
820}
821
822#[derive(Debug, Clone)]
823pub struct MissingWith(pub String);
824
825impl fmt::Display for MissingWith {
826    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
827        write!(f, "missing `with` mapping for the key `{}`", self.0)
828    }
829}
830
831impl std::error::Error for MissingWith {}
832
833// bail!("no remapping found for {with_name:?} - use the `generate!` macro's `with` option to force the interface to be generated or specify where it is already defined:
834// ```
835// with: {{\n\t{with_name:?}: generate\n}}
836// ```")