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