hyperlight_component_util/
emit.rs

1/*
2Copyright 2025 The Hyperlight Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15 */
16
17//! A bunch of utilities used by the actual code emit functions
18use std::collections::{BTreeMap, BTreeSet, VecDeque};
19use std::vec::Vec;
20
21use proc_macro2::TokenStream;
22use quote::{format_ident, quote};
23use syn::Ident;
24
25use crate::etypes::{BoundedTyvar, Defined, Handleable, ImportExport, TypeBound, Tyvar};
26
27/// A representation of a trait definition that we will eventually
28/// emit. This is used to allow easily adding onto the trait each time
29/// we see an extern decl.
30#[derive(Debug, Default)]
31pub struct Trait {
32    /// A set of supertrait constraints, each associated with a
33    /// bindings module path
34    pub supertraits: BTreeMap<Vec<Ident>, TokenStream>,
35    /// Keep track for each type variable of:
36    /// - The identifier that we use for it in the generated source
37    /// - Whether it comes from a component type variable, and if so,
38    ///   which one. (Most do; the I: Imports on the main component
39    ///   trait is the main one that doesn't).
40    /// - Whether there are any bounds on it
41    pub tvs: BTreeMap<Ident, (Option<u32>, TokenStream)>,
42    /// Raw tokens of the contents of the trait
43    pub items: TokenStream,
44}
45impl Trait {
46    pub fn new() -> Self {
47        Self {
48            supertraits: BTreeMap::new(),
49            tvs: BTreeMap::new(),
50            items: TokenStream::new(),
51        }
52    }
53    /// Collect the component tyvar indices that correspond to the
54    /// type variables on this trait.
55    ///
56    /// Precondition: all of the type
57    /// variables on this trait do correspond to component variables.
58    pub fn tv_idxs(&self) -> Vec<u32> {
59        self.tvs.iter().map(|(_, (n, _))| n.unwrap()).collect()
60    }
61    /// See [`State::adjust_vars`].
62    pub fn adjust_vars(&mut self, n: u32) {
63        for (_, (v, _)) in self.tvs.iter_mut() {
64            if let Some(v) = v.as_mut() {
65                *v += n;
66            }
67        }
68    }
69    /// Build a token stream of all type variables and trait bounds on
70    /// them, e.g. what you would put "inside" the <> in trait T<...>.
71    pub fn tv_toks_inner(&mut self) -> TokenStream {
72        let tvs = self
73            .tvs
74            .iter()
75            .map(|(k, (_, v))| {
76                let colon = if v.is_empty() {
77                    quote! {}
78                } else {
79                    quote! { : }
80                };
81                quote! { #k #colon #v }
82            })
83            .collect::<Vec<_>>();
84        quote! { #(#tvs),* }
85    }
86    /// Build a token stream for the type variable part of the trait
87    /// declaration
88    pub fn tv_toks(&mut self) -> TokenStream {
89        if !self.tvs.is_empty() {
90            let toks = self.tv_toks_inner();
91            quote! { <#toks> }
92        } else {
93            quote! {}
94        }
95    }
96    /// Build a token stream for this entire trait definition
97    pub fn into_tokens(&mut self, n: Ident) -> TokenStream {
98        let trait_colon = if !self.supertraits.is_empty() {
99            quote! { : }
100        } else {
101            quote! {}
102        };
103        let supertraits = self
104            .supertraits
105            .iter()
106            .map(|(is, ts)| {
107                quote! { #(#is)::*#ts }
108            })
109            .collect::<Vec<_>>();
110        let tvs = self.tv_toks();
111        let items = &self.items;
112        quote! {
113            pub trait #n #tvs #trait_colon #(#supertraits)+* { #items }
114        }
115    }
116}
117
118/// A representation of a module definition that we will eventually
119/// emit. This is used to allow easily adding onto the module each time
120/// we see a relevant decl.
121#[derive(Debug, Default)]
122pub struct Mod {
123    pub submods: BTreeMap<Ident, Mod>,
124    pub items: TokenStream,
125    pub traits: BTreeMap<Ident, Trait>,
126    pub impls: BTreeMap<(Vec<Ident>, Ident), TokenStream>,
127}
128impl Mod {
129    pub fn empty() -> Self {
130        Self {
131            submods: BTreeMap::new(),
132            items: TokenStream::new(),
133            traits: BTreeMap::new(),
134            impls: BTreeMap::new(),
135        }
136    }
137    /// Get a reference to a sub-module, creating it if necessary
138    pub fn submod<'a>(&'a mut self, i: Ident) -> &'a mut Self {
139        self.submods.entry(i).or_insert(Self::empty())
140    }
141    /// Get an immutable reference to a sub-module
142    ///
143    /// Precondition: the named submodule must already exist
144    pub fn submod_immut<'a>(&'a self, i: Ident) -> &'a Self {
145        &self.submods[&i]
146    }
147    /// Get a reference to a trait definition in this module, creating
148    /// it if necessary
149    pub fn r#trait<'a>(&'a mut self, i: Ident) -> &'a mut Trait {
150        self.traits.entry(i).or_default()
151    }
152    /// Get an immutable reference to a trait definition in this module
153    ///
154    /// Precondition: the named trait must already exist
155    pub fn trait_immut<'a>(&'a self, i: Ident) -> &'a Trait {
156        &self.traits[&i]
157    }
158    /// Get a reference to an impl block that is in this module,
159    /// creating it if necessary.
160    ///
161    /// Currently, we don't track much information about these, so
162    /// it's just a mutable token stream.
163    pub fn r#impl<'a>(&'a mut self, t: Vec<Ident>, i: Ident) -> &'a mut TokenStream {
164        self.impls.entry((t, i)).or_default()
165    }
166    /// See [`State::adjust_vars`].
167    pub fn adjust_vars(&mut self, n: u32) {
168        self.submods
169            .iter_mut()
170            .map(|(_, m)| m.adjust_vars(n))
171            .for_each(drop);
172        self.traits
173            .iter_mut()
174            .map(|(_, t)| t.adjust_vars(n))
175            .for_each(drop);
176    }
177    /// Build a token stream for this entire module
178    pub fn into_tokens(self) -> TokenStream {
179        let mut tt = TokenStream::new();
180        for (k, v) in self.submods {
181            let vt = v.into_tokens();
182            tt.extend(quote! {
183                pub mod #k { #vt }
184            });
185        }
186        for (n, mut t) in self.traits {
187            tt.extend(t.into_tokens(n));
188        }
189        tt.extend(self.items);
190        for ((ns, i), t) in self.impls {
191            tt.extend(quote! {
192                impl #(#ns)::* for #i { #t }
193            })
194        }
195        tt
196    }
197}
198
199/// Unlike [`tv::ResolvedTyvar`], which is mostly concerned with free
200/// variables and leaves bound variables alone, this tells us the most
201/// information that we have at codegen time for a top level bound
202/// variable.
203pub enum ResolvedBoundVar<'a> {
204    Definite {
205        /// The final variable offset (relative to s.var_offset) that
206        /// we followed to get to this definite type, used
207        /// occasionally to name things.
208        final_bound_var: u32,
209        /// The actual definite type that this resolved to
210        ty: Defined<'a>,
211    },
212    Resource {
213        /// A resource-type index. Currently a resource-type index is
214        /// the same as the de Bruijn index of the tyvar that
215        /// introduced the resource type, but is never affected by
216        /// e.g. s.var_offset.
217        rtidx: u32,
218    },
219}
220
221/// A whole grab-bag of useful state to have while emitting Rust
222#[derive(Debug)]
223pub struct State<'a, 'b> {
224    /// A pointer to a [`Mod`] that everything we emit will end up in
225    pub root_mod: &'a mut Mod,
226    /// A cursor to the current submodule (under [`State::root_mod`]),
227    /// where decls that we are looking at right now should end up
228    pub mod_cursor: Vec<Ident>,
229    /// If we are currently processing decls that should end up inside
230    /// a trait (representing an instance or a resource), this names
231    /// the trait where they should end up.
232    pub cur_trait: Option<Ident>,
233    /// We use a "helper module" for auxiliary definitions: for
234    /// example, an instance represented by `InstanceTrait` would end
235    /// up with nominal definitions for its nontrivial types in
236    /// `instance_trait::Type`.  This keeps track of the name of that
237    /// module, if it presently exists.
238    pub cur_helper_mod: Option<Ident>,
239    /// Whether the trait/type definition that we are currently
240    /// emitting is in the helper module or the main module
241    /// corresponding directly to the wit package. This is important
242    /// to get references to other types correct.
243    pub is_helper: bool,
244    /// All the bound variables in the component type that we are
245    /// currently processing
246    pub bound_vars: &'a mut VecDeque<BoundedTyvar<'b>>,
247    /// An offset into bound_vars from which any variable indices we
248    /// see in the source component type will be resolved; used to
249    /// deal with the fact that when we recurse down into a type in
250    /// the Eq bound of a type variable, its variables are offset from
251    /// ours (since we use de Bruijn indices).
252    pub var_offset: usize,
253    /// A path through instance import/export names from the root
254    /// component type to the type we are currently processing. This
255    /// is used with [`crate::etypes::TyvarOrigin`] to decide whether
256    /// a type variable we encounter is "locally defined", i.e. should
257    /// have a type definition emitted for it in this module.
258    pub origin: Vec<ImportExport<'b>>,
259    /// A set of type variables that we encountered while emitting the
260    /// type bound for a type variable.
261    pub cur_needs_vars: Option<&'a mut BTreeSet<u32>>,
262    /// A map from type variables to the type variables used in their
263    /// bounds, used to ensure that we are parametrized over the
264    /// things we need to be
265    pub vars_needs_vars: &'a mut VecDeque<BTreeSet<u32>>,
266    /// The Rust type parameter used to represent the type that
267    /// implements the imports of a component
268    pub import_param_var: Option<Ident>,
269    /// The Rust type parameter used to represent the current Rust
270    /// state type
271    pub self_param_var: Option<Ident>,
272    /// Whether we are emitting an implementation of the component
273    /// interfaces, or just the types of the interface
274    pub is_impl: bool,
275    /// A namespace path and a name representing the Rust trait
276    /// generated for the root component that we started codegen from
277    pub root_component_name: Option<(TokenStream, &'a str)>,
278    /// Whether we are generating code for the Hyperlight host or the
279    /// Hyperlight guest
280    pub is_guest: bool,
281    /// A temporary hack to enable some special cases used by the
282    /// wasmtime guest emit. When that is refactored to use the host
283    /// guest emit, this can go away.
284    pub is_wasmtime_guest: bool,
285    /// Are we working on an export or an import of the component type?
286    pub is_export: bool,
287}
288
289/// Create a State with all of its &mut references pointing to
290/// sensible things, run a function that emits code into the state,
291/// and then generate a token stream representing everything emitted
292pub fn run_state<'b, F: for<'a> FnMut(&mut State<'a, 'b>)>(
293    is_guest: bool,
294    is_wasmtime_guest: bool,
295    mut f: F,
296) -> TokenStream {
297    let mut root_mod = Mod::empty();
298    let mut bound_vars = std::collections::VecDeque::new();
299    let mut vars_needs_vars = std::collections::VecDeque::new();
300    {
301        let mut state = State::new(
302            &mut root_mod,
303            &mut bound_vars,
304            &mut vars_needs_vars,
305            is_guest,
306            is_wasmtime_guest,
307        );
308        f(&mut state);
309    }
310    root_mod.into_tokens()
311}
312
313impl<'a, 'b> State<'a, 'b> {
314    pub fn new(
315        root_mod: &'a mut Mod,
316        bound_vars: &'a mut VecDeque<BoundedTyvar<'b>>,
317        vars_needs_vars: &'a mut VecDeque<BTreeSet<u32>>,
318        is_guest: bool,
319        is_wasmtime_guest: bool,
320    ) -> Self {
321        Self {
322            root_mod,
323            mod_cursor: Vec::new(),
324            cur_trait: None,
325            cur_helper_mod: None,
326            is_helper: false,
327            bound_vars,
328            var_offset: 0,
329            origin: Vec::new(),
330            cur_needs_vars: None,
331            vars_needs_vars,
332            import_param_var: None,
333            self_param_var: None,
334            is_impl: false,
335            root_component_name: None,
336            is_guest,
337            is_wasmtime_guest,
338            is_export: false,
339        }
340    }
341    pub fn clone<'c>(&'c mut self) -> State<'c, 'b> {
342        State {
343            root_mod: self.root_mod,
344            mod_cursor: self.mod_cursor.clone(),
345            cur_trait: self.cur_trait.clone(),
346            cur_helper_mod: self.cur_helper_mod.clone(),
347            is_helper: self.is_helper,
348            bound_vars: self.bound_vars,
349            var_offset: self.var_offset,
350            origin: self.origin.clone(),
351            cur_needs_vars: self.cur_needs_vars.as_deref_mut(),
352            vars_needs_vars: self.vars_needs_vars,
353            import_param_var: self.import_param_var.clone(),
354            self_param_var: self.self_param_var.clone(),
355            is_impl: self.is_impl,
356            root_component_name: self.root_component_name.clone(),
357            is_guest: self.is_guest,
358            is_wasmtime_guest: self.is_wasmtime_guest,
359            is_export: self.is_export,
360        }
361    }
362    /// Obtain a reference to the [`Mod`] that we are currently
363    /// generating code in, creating it if necessary
364    pub fn cur_mod<'c>(&'c mut self) -> &'c mut Mod {
365        let mut m: &'c mut Mod = self.root_mod;
366        for i in &self.mod_cursor {
367            m = m.submod(i.clone());
368        }
369        if self.is_helper {
370            m = m.submod(self.cur_helper_mod.clone().unwrap());
371        }
372        m
373    }
374    /// Obtain an immutable reference to the [`Mod`] that we are
375    /// currently generating code in.
376    ///
377    /// Precondition: the module must already exist
378    pub fn cur_mod_immut<'c>(&'c self) -> &'c Mod {
379        let mut m: &'c Mod = self.root_mod;
380        for i in &self.mod_cursor {
381            m = m.submod_immut(i.clone());
382        }
383        if self.is_helper {
384            m = m.submod_immut(self.cur_helper_mod.clone().unwrap());
385        }
386        m
387    }
388    /// Copy the state, changing its module cursor to emit code into a
389    /// different module
390    pub fn with_cursor<'c>(&'c mut self, cursor: Vec<Ident>) -> State<'c, 'b> {
391        let mut s = self.clone();
392        s.mod_cursor = cursor;
393        s
394    }
395    /// Copy the state, replacing its [`State::cur_needs_vars`] reference,
396    /// allowing a caller to capture the vars referenced by any emit
397    /// run with the resultant state
398    pub fn with_needs_vars<'c>(&'c mut self, needs_vars: &'c mut BTreeSet<u32>) -> State<'c, 'b> {
399        let mut s = self.clone();
400        s.cur_needs_vars = Some(needs_vars);
401        s
402    }
403    /// Record that an emit sequence needed a var, given an absolute
404    /// index for the var (i.e. ignoring [`State::var_offset`])
405    pub fn need_noff_var(&mut self, n: u32) {
406        self.cur_needs_vars.as_mut().map(|vs| vs.insert(n));
407    }
408    /// Use the [`State::cur_needs_vars`] map to populate
409    /// [`State::vars_needs_vars`] for a var that we presumably just
410    /// finished emitting a bound for
411    pub fn record_needs_vars(&mut self, n: u32) {
412        let un = n as usize;
413        if self.vars_needs_vars.len() < un + 1 {
414            self.vars_needs_vars.resize(un + 1, BTreeSet::new());
415        }
416        let Some(ref mut cnvs) = self.cur_needs_vars else {
417            return;
418        };
419        log::debug!("debug varref: recording {:?} for var {:?}", cnvs.iter(), un);
420        self.vars_needs_vars[un].extend(cnvs.iter());
421    }
422    /// Get a list of all the variables needed by a var, given its absolute
423    /// index (i.e. ignoring [`State::var_offset`])
424    pub fn get_noff_var_refs(&mut self, n: u32) -> BTreeSet<u32> {
425        let un = n as usize;
426        if self.vars_needs_vars.len() < un + 1 {
427            return BTreeSet::new();
428        };
429        log::debug!(
430            "debug varref: looking up {:?} for var {:?}",
431            self.vars_needs_vars[un].iter(),
432            un
433        );
434        self.vars_needs_vars[un].clone()
435    }
436    /// Find the exported name which gave rise to a component type
437    /// variable, given its absolute index (i.e. ignoring
438    /// [`State::var_offset`])
439    pub fn noff_var_id(&self, n: u32) -> Ident {
440        let Some(n) = self.bound_vars[n as usize].origin.last_name() else {
441            panic!("missing origin on tyvar in rust emit")
442        };
443        kebab_to_type(n)
444    }
445    /// Copy the state, changing it to emit into the helper module of
446    /// the current trait
447    pub fn helper<'c>(&'c mut self) -> State<'c, 'b> {
448        let mut s = self.clone();
449        s.is_helper = true;
450        s
451    }
452    /// Construct a namespace token stream that can be emitted in the
453    /// current module to refer to a name in the root module
454    pub fn root_path(&self) -> TokenStream {
455        if self.is_impl {
456            return TokenStream::new();
457        }
458        let mut s = self
459            .mod_cursor
460            .iter()
461            .map(|_| quote! { super })
462            .collect::<Vec<_>>();
463        if self.is_helper {
464            s.push(quote! { super });
465        }
466        quote! { #(#s::)* }
467    }
468    /// Construct a namespace token stream that can be emitted in the
469    /// current module to refer to a name in the helper module
470    pub fn helper_path(&self) -> TokenStream {
471        if self.is_impl {
472            let c = &self.mod_cursor;
473            let helper = self.cur_helper_mod.clone().unwrap();
474            let h = if !self.is_helper {
475                quote! { #helper:: }
476            } else {
477                TokenStream::new()
478            };
479            quote! { #(#c::)*#h }
480        } else if self.is_helper {
481            quote! { self:: }
482        } else {
483            let helper = self.cur_helper_mod.clone().unwrap();
484            quote! { #helper:: }
485        }
486    }
487    /// Emit a namespace token stream that can be emitted in the root
488    /// module to refer to the current trait
489    pub fn cur_trait_path(&self) -> TokenStream {
490        let tns = &self.mod_cursor;
491        let tid = self.cur_trait.clone().unwrap();
492        quote! { #(#tns::)* #tid }
493    }
494    /// Add a supertrait constraint referring to a trait in the helper
495    /// module; primarily used to add a constraint for the trait
496    /// representing a resource type.
497    pub fn add_helper_supertrait(&mut self, r: Ident) {
498        let (Some(t), Some(hm)) = (self.cur_trait.clone(), &self.cur_helper_mod.clone()) else {
499            panic!("invariant violation")
500        };
501        self.cur_mod()
502            .r#trait(t)
503            .supertraits
504            .insert(vec![hm.clone(), r], TokenStream::new());
505    }
506    /// Obtain a reference to the [`Trait`] that we are currently
507    /// generating code in, creating it if necessary.
508    ///
509    /// Precondition: we are currently generating code in a trait
510    /// (i.e. [`State::cur_trait`] is not [`None`])
511    pub fn cur_trait<'c>(&'c mut self) -> &'c mut Trait {
512        let n = self.cur_trait.as_ref().unwrap().clone();
513        self.cur_mod().r#trait(n)
514    }
515    /// Obtain an immutable reference to the [`Trait`] that we are
516    /// currently generating code in.
517    ///
518    /// Precondition: we are currently generating code in a trait
519    /// (i.e. [`State::cur_trait`] is not [`None`]), and that trait has
520    /// already been created
521    pub fn cur_trait_immut<'c>(&'c self) -> &'c Trait {
522        let n = self.cur_trait.as_ref().unwrap().clone();
523        self.cur_mod_immut().trait_immut(n)
524    }
525    /// Obtain a reference to the trait at the given module path and
526    /// name from the root module, creating it and any named modules
527    /// if necessary
528    pub fn r#trait<'c>(&'c mut self, namespace: &'c [Ident], name: Ident) -> &'c mut Trait {
529        let mut m: &'c mut Mod = self.root_mod;
530        for i in namespace {
531            m = m.submod(i.clone());
532        }
533        m.r#trait(name)
534    }
535    /// Add an import/export to [`State::origin`], reflecting that we are now
536    /// looking at code underneath it
537    ///
538    /// origin_was_export differs from s.is_export in that s.is_export
539    /// keeps track of whether the item overall was imported or exported
540    /// from the root component (taking into account positivity), whereas
541    /// origin_was_export just checks if this particular extern_decl was
542    /// imported or exported from its parent instance (and so e.g. an
543    /// export of an instance that is imported by the root component has
544    /// !s.is_export && origin_was_export)
545    pub fn push_origin<'c>(&'c mut self, origin_was_export: bool, name: &'b str) -> State<'c, 'b> {
546        let mut s = self.clone();
547        s.origin.push(if origin_was_export {
548            ImportExport::Export(name)
549        } else {
550            ImportExport::Import(name)
551        });
552        s
553    }
554    /// Find out if a [`Defined`] type is actually a reference to a
555    /// locally defined type variable, returning its index and bound
556    /// if it is
557    pub fn is_var_defn(&self, t: &Defined<'b>) -> Option<(u32, TypeBound<'b>)> {
558        match t {
559            Defined::Handleable(Handleable::Var(tv)) => match tv {
560                Tyvar::Bound(n) => {
561                    let bv = &self.bound_vars[self.var_offset + (*n as usize)];
562                    log::debug!("checking an origin {:?} {:?}", bv.origin, self.origin);
563                    if bv.origin.matches(self.origin.iter()) {
564                        Some((*n, bv.bound.clone()))
565                    } else {
566                        None
567                    }
568                }
569                Tyvar::Free(_) => panic!("free tyvar in finished type"),
570            },
571            _ => None,
572        }
573    }
574    /// Find out if a variable is locally-defined given its absolute
575    /// index, returning its origin and bound if it is
576    pub fn is_noff_var_local<'c>(
577        &'c self,
578        n: u32,
579    ) -> Option<(Vec<ImportExport<'c>>, TypeBound<'a>)> {
580        let bv = &self.bound_vars[n as usize];
581        bv.origin
582            .is_local(self.origin.iter())
583            .map(|path| (path, bv.bound.clone()))
584    }
585    /// Obtain an immutable reference to the trait at the specified
586    /// namespace path, either from the root module (if `absolute`)
587    /// is true, or from the current module
588    ///
589    /// Precondition: all named traits/modules must exist
590    pub fn resolve_trait_immut(&self, absolute: bool, path: &[Ident]) -> &Trait {
591        log::debug!("resolving trait {:?} {:?}", absolute, path);
592        let mut m = if absolute {
593            &*self.root_mod
594        } else {
595            self.cur_mod_immut()
596        };
597        for x in &path[0..path.len() - 1] {
598            m = &m.submods[x];
599        }
600        &m.traits[&path[path.len() - 1]]
601    }
602    /// Shift all of the type variable indices over, because we have
603    /// gone under some binders.  Used when we switch from looking at
604    /// a component's import types (where type idxs are de Bruijn into
605    /// the component's uvar list) to a component's export types
606    /// (where type idx are de Bruijn first into the evar list and
607    /// then the uvar list, as we go under the existential binders).
608    pub fn adjust_vars(&mut self, n: u32) {
609        self.vars_needs_vars
610            .iter_mut()
611            .enumerate()
612            .for_each(|(i, vs)| {
613                *vs = vs.iter().map(|v| v + n).collect();
614                log::debug!("updated {:?} to {:?}", i, *vs);
615            });
616        for _ in 0..n {
617            self.vars_needs_vars.push_front(BTreeSet::new());
618        }
619        self.root_mod.adjust_vars(n);
620    }
621    /// Resolve a type variable as far as possible: either this ends
622    /// up with a definition, in which case, let's get that, or it
623    /// ends up with a resource type, in which case we return the
624    /// resource index
625    ///
626    /// Distinct from [`Ctx::resolve_tv`], which is mostly concerned
627    /// with free variables, because this is concerned entirely with
628    /// bound variables.
629    pub fn resolve_bound_var(&self, n: u32) -> ResolvedBoundVar<'b> {
630        let noff = self.var_offset as u32 + n;
631        match &self.bound_vars[noff as usize].bound {
632            TypeBound::Eq(Defined::Handleable(Handleable::Var(Tyvar::Bound(nn)))) => {
633                self.resolve_bound_var(n + 1 + nn)
634            }
635            TypeBound::Eq(t) => ResolvedBoundVar::Definite {
636                final_bound_var: n,
637                ty: t.clone(),
638            },
639            TypeBound::SubResource => ResolvedBoundVar::Resource { rtidx: noff },
640        }
641    }
642
643    /// Construct a namespace path referring to the resource trait for
644    /// a resource with the given name
645    pub fn resource_trait_path(&self, r: Ident) -> Vec<Ident> {
646        let mut path = self.mod_cursor.clone();
647        let helper = self
648            .cur_helper_mod
649            .as_ref()
650            .expect("There should always be a helper mod to hold a resource trait")
651            .clone();
652        path.push(helper);
653        path.push(r);
654        path
655    }
656}
657
658/// A parsed representation of a WIT name, containing package
659/// namespaces, an actual name, and possibly a SemVer version
660#[derive(Debug, Clone)]
661pub struct WitName<'a> {
662    pub namespaces: Vec<&'a str>,
663    pub name: &'a str,
664    pub _version: Vec<&'a str>,
665}
666impl<'a> WitName<'a> {
667    /// Extract a list of Rust module names corresponding to the WIT
668    /// namespace/package
669    pub fn namespace_idents(&self) -> Vec<Ident> {
670        self.namespaces
671            .iter()
672            .map(|x| kebab_to_namespace(x))
673            .collect::<Vec<_>>()
674    }
675    /// Extract a token stream representing the Rust namespace path
676    /// corresponding to the WIT namespace/package
677    pub fn namespace_path(&self) -> TokenStream {
678        let ns = self.namespace_idents();
679        quote! { #(#ns)::* }
680    }
681}
682/// Parse a kebab-name as a WIT name
683pub fn split_wit_name(n: &str) -> WitName<'_> {
684    let mut namespaces = Vec::new();
685    let mut colon_components = n.split(':').rev();
686    let last = colon_components.next().unwrap();
687    namespaces.extend(colon_components.rev());
688    let mut slash_components = last.split('/').rev();
689    let mut versioned_name = slash_components.next().unwrap().split('@');
690    let name = versioned_name.next().unwrap();
691    namespaces.extend(slash_components.rev());
692    WitName {
693        namespaces,
694        name,
695        _version: versioned_name.collect(),
696    }
697}
698
699fn kebab_to_snake(n: &str) -> Ident {
700    if n == "self" {
701        return format_ident!("self_");
702    }
703    let mut ret = String::new();
704    for c in n.chars() {
705        if c == '-' {
706            ret.push('_');
707            continue;
708        }
709        ret.push(c);
710    }
711    format_ident!("r#{}", ret)
712}
713
714fn kebab_to_camel(n: &str) -> Ident {
715    let mut word_start = true;
716    let mut ret = String::new();
717    for c in n.chars() {
718        if c == '-' {
719            word_start = true;
720            continue;
721        }
722        if word_start {
723            ret.extend(c.to_uppercase())
724        } else {
725            ret.push(c)
726        };
727        word_start = false;
728    }
729    format_ident!("{}", ret)
730}
731
732/// Convert a kebab name to something suitable for use as a
733/// (value-level) variable
734pub fn kebab_to_var(n: &str) -> Ident {
735    kebab_to_snake(n)
736}
737/// Convert a kebab name to something suitable for use as a
738/// type constructor
739pub fn kebab_to_cons(n: &str) -> Ident {
740    kebab_to_camel(n)
741}
742/// Convert a kebab name to something suitable for use as a getter
743/// function name
744pub fn kebab_to_getter(n: &str) -> Ident {
745    kebab_to_snake(n)
746}
747/// Convert a kebab name to something suitable for use as a type name
748pub fn kebab_to_type(n: &str) -> Ident {
749    kebab_to_camel(n)
750}
751/// Convert a kebab name to something suitable for use as a module
752/// name/namespace path entry
753pub fn kebab_to_namespace(n: &str) -> Ident {
754    kebab_to_snake(n)
755}
756/// From a kebab name for a Component, derive something suitable for
757/// use as the name of the imports trait for that component
758pub fn kebab_to_imports_name(trait_name: &str) -> Ident {
759    format_ident!("{}Imports", kebab_to_type(trait_name))
760}
761/// From a kebab name for a Component, derive something suitable for
762/// use as the name of the imports trait for that component
763pub fn kebab_to_exports_name(trait_name: &str) -> Ident {
764    format_ident!("{}Exports", kebab_to_type(trait_name))
765}
766
767/// The kinds of names that a function associated with a resource in
768/// WIT can have
769pub enum ResourceItemName {
770    Constructor,
771    Method(Ident),
772    Static(Ident),
773}
774
775/// The kinds of names that a function in WIT can have
776pub enum FnName {
777    Associated(Ident, ResourceItemName),
778    Plain(Ident),
779}
780/// Parse a kebab-name as a WIT function name, figuring out if it is
781/// associated with a resource
782pub fn kebab_to_fn(n: &str) -> FnName {
783    if let Some(n) = n.strip_prefix("[constructor]") {
784        return FnName::Associated(kebab_to_type(n), ResourceItemName::Constructor);
785    }
786    if let Some(n) = n.strip_prefix("[method]") {
787        let mut i = n.split('.');
788        let r = i.next().unwrap();
789        let n = i.next().unwrap();
790        return FnName::Associated(
791            kebab_to_type(r),
792            ResourceItemName::Method(kebab_to_snake(n)),
793        );
794    }
795    if let Some(n) = n.strip_prefix("[static]") {
796        let mut i = n.split('.');
797        let r = i.next().unwrap();
798        let n = i.next().unwrap();
799        return FnName::Associated(
800            kebab_to_type(r),
801            ResourceItemName::Static(kebab_to_snake(n)),
802        );
803    }
804    FnName::Plain(kebab_to_snake(n))
805}