1use std::collections::{BTreeMap, BTreeSet, VecDeque};
20use std::vec::Vec;
21
22use proc_macro2::TokenStream;
23use quote::{format_ident, quote};
24use syn::Ident;
25
26use crate::emit::{
27 FnName, ResourceItemName, State, WitName, kebab_to_cons, kebab_to_exports_name, kebab_to_fn,
28 kebab_to_getter, kebab_to_imports_name, kebab_to_namespace, kebab_to_type, kebab_to_var,
29 split_wit_name,
30};
31use crate::etypes::{
32 Component, Defined, ExternDecl, ExternDesc, Func, Handleable, ImportExport, Instance, Param,
33 Result, TypeBound, Tyvar, Value,
34};
35
36fn emit_tvis(s: &mut State, tvs: Vec<u32>) -> TokenStream {
40 let tvs = tvs
41 .iter()
42 .map(|tv| emit_var_ref(s, &Tyvar::Bound(*tv)))
43 .collect::<Vec<_>>();
44 if !tvs.is_empty() {
45 quote! { <#(#tvs),*> }
46 } else {
47 TokenStream::new()
48 }
49}
50
51fn emit_resource_ref(s: &mut State, n: u32, path: Vec<ImportExport>) -> TokenStream {
59 if s.is_guest && s.is_impl {
63 let id = format_ident!("HostResource{}", n);
69 return quote! { #id };
70 }
71 let rtrait = kebab_to_type(path[path.len() - 1].name());
74
75 if path.len() == 1 {
79 let helper = s.cur_helper_mod.clone().unwrap();
80 let rtrait = kebab_to_type(path[0].name());
81 let t = s.resolve_trait_immut(false, &[helper.clone(), rtrait.clone()]);
82 let tvis = emit_tvis(s, t.tv_idxs());
83 let mut sv = quote! { Self };
84 if let Some(s) = &s.self_param_var {
85 sv = quote! { #s };
86 };
87 return quote! { <#sv as #helper::#rtrait #tvis>::T };
88 };
89
90 let instance = path[path.len() - 2].name();
96 let iwn = split_wit_name(instance);
97 let extras = path[0..path.len() - 2]
98 .iter()
99 .map(|p| {
100 let wn = split_wit_name(p.name());
101 kebab_to_type(wn.name)
102 })
103 .collect::<Vec<_>>();
104 let extras = quote! { #(#extras::)* };
105 let rp = s.root_path();
106 let tns = iwn.namespace_path();
107 let instance_mod = kebab_to_namespace(iwn.name);
108 let instance_type = kebab_to_type(iwn.name);
109 let mut sv = quote! { Self };
110 if path[path.len() - 2].imported() {
111 if let Some(iv) = &s.import_param_var {
112 sv = quote! { #iv }
113 };
114 } else if let Some(s) = &s.self_param_var {
115 sv = quote! { #s }
116 };
117 let mut trait_path = Vec::new();
118 trait_path.extend(iwn.namespace_idents());
119 trait_path.push(instance_mod.clone());
120 trait_path.push(rtrait.clone());
121 let t = s.resolve_trait_immut(true, &trait_path);
122 let tvis = emit_tvis(s, t.tv_idxs());
123 quote! { <#sv::#extras #instance_type as #rp #tns::#instance_mod::#rtrait #tvis>::T }
124}
125
126fn try_find_local_var_id(
133 s: &mut State,
134 n: u32,
136) -> Option<TokenStream> {
137 if let Some((path, bound)) = s.is_noff_var_local(n) {
138 let var_is_helper = match bound {
139 TypeBound::Eq(_) => true,
140 TypeBound::SubResource => false,
141 };
142 if !var_is_helper {
143 if s.is_helper {
145 if path.len() == 1 && s.cur_trait == Some(kebab_to_type(path[0].name())) {
147 return Some(quote! { Self::T });
148 }
149 return None;
151 } else {
152 let mut path_strs = vec!["".to_string(); path.len()];
153 for (i, p) in path.iter().enumerate() {
154 path_strs[i] = p.name().to_string();
155 }
156 let path = path
157 .into_iter()
158 .enumerate()
159 .map(|(i, p)| match p {
160 ImportExport::Import(_) => ImportExport::Import(&path_strs[i]),
161 ImportExport::Export(_) => ImportExport::Export(&path_strs[i]),
162 })
163 .collect::<Vec<_>>();
164 return Some(emit_resource_ref(s, n, path));
165 }
166 }
167 log::debug!("path is {:?}\n", path);
168 let mut path = path.iter().rev();
169 let name = kebab_to_type(path.next().unwrap().name());
170 let owner = path.next();
171 if let Some(owner) = owner {
172 let wn = split_wit_name(owner.name());
174 let rp = s.root_path();
175 let tns = wn.namespace_path();
176 let helper = kebab_to_namespace(wn.name);
177 Some(quote! { #rp #tns::#helper::#name })
178 } else {
179 let hp = s.helper_path();
180 Some(quote! { #hp #name })
181 }
182 } else {
183 None
184 }
185}
186
187pub fn emit_var_ref(s: &mut State, tv: &Tyvar) -> TokenStream {
194 let Tyvar::Bound(n) = tv else {
195 panic!("free tyvar in rust emit")
196 };
197 emit_var_ref_noff(s, n + s.var_offset as u32, false)
198}
199pub fn emit_var_ref_value(s: &mut State, tv: &Tyvar) -> TokenStream {
207 let Tyvar::Bound(n) = tv else {
208 panic!("free tyvar in rust emit")
209 };
210 emit_var_ref_noff(s, n + s.var_offset as u32, true)
211}
212pub fn emit_var_ref_noff(s: &mut State, n: u32, is_value: bool) -> TokenStream {
219 log::debug!("var_ref {:?} {:?}", &s.bound_vars[n as usize], s.origin);
220 let id = try_find_local_var_id(s, n);
222 let id = match id {
223 Some(id) => {
224 let vs = s.get_noff_var_refs(n);
227 let vs = vs
228 .iter()
229 .map(|n| emit_var_ref_noff(s, *n, false))
230 .collect::<Vec<_>>();
231 let vs_toks = if !vs.is_empty() {
232 if is_value {
233 quote! { ::<#(#vs),*> }
234 } else {
235 quote! { <#(#vs),*> }
236 }
237 } else {
238 TokenStream::new()
239 };
240
241 quote! { #id #vs_toks }
242 }
243 None => {
244 s.need_noff_var(n);
247 let id = s.noff_var_id(n);
248 quote! { #id }
249 }
250 };
251 quote! { #id }
252}
253
254pub fn numeric_rtype(vt: &Value) -> (Ident, u8) {
259 match vt {
260 Value::S(w) => (format_ident!("i{}", w.width()), w.width()),
261 Value::U(w) => (format_ident!("u{}", w.width()), w.width()),
262 Value::F(w) => (format_ident!("f{}", w.width()), w.width()),
263 _ => panic!("numeric_rtype: internal invariant violation"),
264 }
265}
266
267pub fn emit_value(s: &mut State, vt: &Value) -> TokenStream {
272 match vt {
273 Value::Bool => quote! { bool },
274 Value::S(_) | Value::U(_) | Value::F(_) => {
275 let (id, _) = numeric_rtype(vt);
276 quote! { #id }
277 }
278 Value::Char => quote! { char },
279 Value::String => quote! { alloc::string::String },
280 Value::List(vt) => {
281 let vt = emit_value(s, vt);
282 quote! { alloc::vec::Vec<#vt> }
283 }
284 Value::Record(_) => panic!("record not at top level of valtype"),
285 Value::Tuple(vts) => {
286 let vts = vts.iter().map(|vt| emit_value(s, vt)).collect::<Vec<_>>();
287 quote! { (#(#vts),*) }
288 }
289 Value::Flags(_) => panic!("flags not at top level of valtype"),
290 Value::Variant(_) => panic!("flags not at top level of valtype"),
291 Value::Enum(_) => panic!("enum not at top level of valtype"),
292 Value::Option(vt) => {
293 let vt = emit_value(s, vt);
294 quote! { ::core::option::Option<#vt> }
295 }
296 Value::Result(vt1, vt2) => {
297 let unit = Value::Tuple(Vec::new());
298 let vt1 = emit_value(s, vt1.as_ref().as_ref().unwrap_or(&unit));
299 let vt2 = emit_value(s, vt2.as_ref().as_ref().unwrap_or(&unit));
300 quote! { ::core::result::Result<#vt1, #vt2> }
301 }
302 Value::Own(ht) => match ht {
303 Handleable::Resource(_) => panic!("bare resource in type"),
304 Handleable::Var(tv) => {
305 if s.is_guest {
306 let wrap = if s.is_wasmtime_guest {
307 |toks| quote! { ::wasmtime::component::Resource<#toks> }
308 } else {
309 |toks| toks
310 };
311 if !s.is_impl {
312 wrap(emit_var_ref(s, tv))
313 } else {
314 let n = crate::hl::resolve_handleable_to_resource(s, ht);
315 log::debug!("resolved ht to r (4) {:?} {:?}", ht, n);
316 let id = format_ident!("HostResource{}", n);
317 wrap(quote! { #id })
318 }
319 } else {
320 emit_var_ref(s, tv)
321 }
322 }
323 },
324 Value::Borrow(ht) => match ht {
325 Handleable::Resource(_) => panic!("bare resource in type"),
326 Handleable::Var(tv) => {
327 if s.is_guest {
328 let wrap = if s.is_wasmtime_guest {
329 |toks| quote! { ::wasmtime::component::Resource<#toks> }
330 } else {
331 |toks| quote! { &#toks }
332 };
333 if !s.is_impl {
334 wrap(emit_var_ref(s, tv))
335 } else {
336 let n = crate::hl::resolve_handleable_to_resource(s, ht);
337 log::debug!("resolved ht to r (5) {:?} {:?}", ht, n);
338 let id = format_ident!("HostResource{}", n);
339 wrap(quote! { #id })
340 }
341 } else {
342 let vr = emit_var_ref(s, tv);
343 quote! { ::hyperlight_common::resource::BorrowedResourceGuard<#vr> }
344 }
345 }
346 },
347 Value::Var(Some(tv), _) => emit_var_ref(s, tv),
348 Value::Var(None, _) => panic!("value type with recorded but unknown var"),
349 }
350}
351
352fn emit_value_toplevel(s: &mut State, v: Option<u32>, id: Ident, vt: &Value) -> TokenStream {
356 let is_wasmtime_guest = s.is_wasmtime_guest;
357 match vt {
358 Value::Record(rfs) => {
359 let (vs, toks) = gather_needed_vars(s, v, |s| {
360 let rfs = rfs
361 .iter()
362 .map(|rf| {
363 let orig_name = rf.name.name;
364 let id = kebab_to_var(orig_name);
365 let derives = if s.is_wasmtime_guest {
366 quote! { #[component(name = #orig_name)] }
367 } else {
368 TokenStream::new()
369 };
370 let ty = emit_value(s, &rf.ty);
371 quote! { #derives pub #id: #ty }
372 })
373 .collect::<Vec<_>>();
374 quote! { #(#rfs),* }
375 });
376 let vs = emit_type_defn_var_list(s, vs);
377 let derives = if s.is_wasmtime_guest {
378 quote! {
379 #[derive(::wasmtime::component::ComponentType)]
380 #[derive(::wasmtime::component::Lift)]
381 #[derive(::wasmtime::component::Lower)]
382 #[component(record)]
383 }
384 } else {
385 TokenStream::new()
386 };
387 quote! {
388 #derives
389 #[derive(Debug)]
390 pub struct #id #vs { #toks }
391 }
392 }
393 Value::Flags(ns) => {
394 let (vs, toks) = gather_needed_vars(s, v, |_| {
395 let ns = ns
396 .iter()
397 .map(|n| {
398 let orig_name = n.name;
399 let id = kebab_to_var(orig_name);
400 quote! { pub #id: bool }
401 })
402 .collect::<Vec<_>>();
403 quote! { #(#ns),* }
404 });
405 let vs = emit_type_defn_var_list(s, vs);
406 quote! {
407 #[derive(Debug, Clone, PartialEq)]
408 pub struct #id #vs { #toks }
409 }
410 }
411 Value::Variant(vcs) => {
412 let (vs, toks) = gather_needed_vars(s, v, |s| {
413 let vcs = vcs
414 .iter()
415 .map(|vc| {
416 let orig_name = vc.name.name;
417 let id = kebab_to_cons(orig_name);
418 let derives = if s.is_wasmtime_guest {
419 quote! { #[component(name = #orig_name)] }
420 } else {
421 TokenStream::new()
422 };
423 match &vc.ty {
424 Some(ty) => {
425 let ty = emit_value(s, ty);
426 quote! { #derives #id(#ty) }
427 }
428 None => quote! { #derives #id },
429 }
430 })
431 .collect::<Vec<_>>();
432 quote! { #(#vcs),* }
433 });
434 let vs = emit_type_defn_var_list(s, vs);
435 let derives = if s.is_wasmtime_guest {
436 quote! {
437 #[derive(::wasmtime::component::ComponentType)]
438 #[derive(::wasmtime::component::Lift)]
439 #[derive(::wasmtime::component::Lower)]
440 #[component(variant)]
441 }
442 } else {
443 TokenStream::new()
444 };
445 quote! {
446 #derives
447 #[derive(Debug)]
448 pub enum #id #vs { #toks }
449 }
450 }
451 Value::Enum(ns) => {
452 let (vs, toks) = gather_needed_vars(s, v, |_| {
453 let ns = ns
454 .iter()
455 .map(|n| {
456 let orig_name = n.name;
457 let id = kebab_to_cons(orig_name);
458 let derives = if is_wasmtime_guest {
459 quote! { #[component(name = #orig_name)] }
460 } else {
461 TokenStream::new()
462 };
463 quote! { #derives #id }
464 })
465 .collect::<Vec<_>>();
466 quote! { #(#ns),* }
467 });
468 let vs = emit_type_defn_var_list(s, vs);
469 let derives = if s.is_wasmtime_guest {
470 quote! {
471 #[derive(::wasmtime::component::ComponentType)]
472 #[derive(::wasmtime::component::Lift)]
473 #[derive(::wasmtime::component::Lower)]
474 #[component(enum)]
475 #[repr(u8)] }
477 } else {
478 TokenStream::new()
479 };
480 quote! {
481 #derives
482 #[derive(Debug, Copy, Clone, PartialEq)]
483 pub enum #id #vs { #toks }
484 }
485 }
486 _ => emit_type_alias(s, v, id, |s| emit_value(s, vt)),
487 }
488}
489
490fn emit_defined(s: &mut State, v: Option<u32>, id: Ident, dt: &Defined) -> TokenStream {
497 match dt {
498 Defined::Instance(_) | Defined::Component(_) => TokenStream::new(),
501 Defined::Handleable(Handleable::Resource(_)) => panic!("bare resource in type"),
503 Defined::Handleable(Handleable::Var(tv)) => {
504 emit_type_alias(s, v, id, |s| emit_var_ref(s, tv))
505 }
506 Defined::Value(vt) => emit_value_toplevel(s, v, id, vt),
507 Defined::Func(ft) => emit_type_alias(s, v, id, |s| emit_func(s, ft)),
508 }
509}
510
511pub fn emit_func_param(s: &mut State, p: &Param) -> TokenStream {
515 let name = kebab_to_var(p.name.name);
516 let ty = emit_value(s, &p.ty);
517 quote! { #name: #ty }
518}
519
520pub fn emit_func_result(s: &mut State, r: &Result) -> TokenStream {
525 match r {
526 Result::Unnamed(vt) => emit_value(s, vt),
527 Result::Named(rs) if rs.is_empty() => quote! { () },
528 _ => panic!("multiple named function results are not currently supported"),
529 }
530}
531
532fn emit_func(s: &mut State, ft: &Func) -> TokenStream {
537 let params = ft
538 .params
539 .iter()
540 .map(|p| emit_func_param(s, p))
541 .collect::<Vec<_>>();
542 let result = emit_func_result(s, &ft.result);
543 quote! { fn(#(#params),*) -> #result }
544}
545
546fn gather_needed_vars<F: Fn(&mut State) -> TokenStream>(
550 s: &mut State,
551 v: Option<u32>,
552 f: F,
553) -> (BTreeSet<u32>, TokenStream) {
554 let mut needs_vars = BTreeSet::new();
555 let mut sv = s.with_needs_vars(&mut needs_vars);
556 let toks = f(&mut sv);
557 if let Some(vn) = v {
558 sv.record_needs_vars(vn);
559 }
560 drop(sv);
561 (needs_vars, toks)
562}
563fn emit_type_defn_var_list(s: &mut State, vs: BTreeSet<u32>) -> TokenStream {
567 if vs.is_empty() {
568 TokenStream::new()
569 } else {
570 let vs = vs
571 .iter()
572 .map(|n| {
573 if s.is_guest {
574 let t = s.noff_var_id(*n);
575 quote! { #t: 'static }
576 } else {
577 let t = s.noff_var_id(*n);
578 quote! { #t }
579 }
580 })
581 .collect::<Vec<_>>();
582 quote! { <#(#vs),*> }
583 }
584}
585fn emit_type_alias<F: Fn(&mut State) -> TokenStream>(
594 s: &mut State,
595 v: Option<u32>,
596 id: Ident,
597 f: F,
598) -> TokenStream {
599 let (vs, toks) = gather_needed_vars(s, v, f);
600 let vs = emit_type_defn_var_list(s, vs);
601 quote! { pub type #id #vs = #toks; }
602}
603
604fn emit_extern_decl<'a, 'b, 'c>(
607 is_export: bool,
608 s: &'c mut State<'a, 'b>,
609 ed: &'c ExternDecl<'b>,
610) -> TokenStream {
611 log::debug!(" emitting decl {:?}", ed.kebab_name);
612 match &ed.desc {
613 ExternDesc::CoreModule(_) => panic!("core module (im/ex)ports are not supported"),
614 ExternDesc::Func(ft) => {
615 let mut s = s.push_origin(is_export, ed.kebab_name);
616 match kebab_to_fn(ed.kebab_name) {
617 FnName::Plain(n) => {
618 let params = ft
619 .params
620 .iter()
621 .map(|p| emit_func_param(&mut s, p))
622 .collect::<Vec<_>>();
623 let result = emit_func_result(&mut s, &ft.result);
624 quote! {
625 fn #n(&mut self, #(#params),*) -> #result;
626 }
627 }
628 FnName::Associated(r, n) => {
629 let mut s = s.helper();
630 s.cur_trait = Some(r.clone());
631 let mut needs_vars = BTreeSet::new();
632 let mut sv = s.with_needs_vars(&mut needs_vars);
633 let params = ft
634 .params
635 .iter()
636 .map(|p| emit_func_param(&mut sv, p))
637 .collect::<Vec<_>>();
638 match n {
639 ResourceItemName::Constructor => {
640 sv.cur_trait().items.extend(quote! {
641 fn new(&mut self, #(#params),*) -> Self::T;
642 });
643 }
644 ResourceItemName::Method(n) => {
645 let result = emit_func_result(&mut sv, &ft.result);
646 sv.cur_trait().items.extend(quote! {
647 fn #n(&mut self, #(#params),*) -> #result;
648 });
649 }
650 ResourceItemName::Static(n) => {
651 let result = emit_func_result(&mut sv, &ft.result);
652 sv.cur_trait().items.extend(quote! {
653 fn #n(&mut self, #(#params),*) -> #result;
654 });
655 }
656 }
657 for v in needs_vars {
658 let id = s.noff_var_id(v);
659 s.cur_trait().tvs.insert(id, (Some(v), TokenStream::new()));
660 }
661 quote! {}
662 }
663 }
664 }
665 ExternDesc::Type(t) => {
666 fn go_defined<'a, 'b, 'c>(
667 s: &'c mut State<'a, 'b>,
668 ed: &'c ExternDecl<'b>,
669 t: &'c Defined<'b>,
670 v: Option<u32>,
671 ) -> TokenStream {
672 let id = kebab_to_type(ed.kebab_name);
673 let mut s = s.helper();
674
675 let t = emit_defined(&mut s, v, id, t);
676 s.cur_mod().items.extend(t);
677 TokenStream::new()
678 }
679 let edn: &'b str = ed.kebab_name;
680 let mut s: State<'_, 'b> = s.push_origin(is_export, edn);
681 if let Some((n, bound)) = s.is_var_defn(t) {
682 match bound {
683 TypeBound::Eq(t) => {
684 let noff = s.var_offset as u32 + n;
688 s.var_offset += n as usize + 1;
689 go_defined(&mut s, ed, &t, Some(noff))
690 }
691 TypeBound::SubResource => {
692 let rn = kebab_to_type(ed.kebab_name);
693 s.add_helper_supertrait(rn.clone());
694 let mut s = s.helper();
695 s.cur_trait = Some(rn.clone());
696 s.cur_trait().items.extend(quote! {
697 type T: ::core::marker::Send;
698 });
699 quote! {}
700 }
701 }
702 } else {
703 go_defined(&mut s, ed, t, None)
704 }
705 }
706 ExternDesc::Instance(it) => {
707 let mut s = s.push_origin(is_export, ed.kebab_name);
708 let wn = split_wit_name(ed.kebab_name);
709 emit_instance(&mut s, wn.clone(), it);
710
711 let nsids = wn.namespace_idents();
712 let repr = s.r#trait(&nsids, kebab_to_type(wn.name));
713 let vs = if !repr.tvs.is_empty() {
714 let vs = repr.tvs.clone();
715 let tvs = vs
716 .iter()
717 .map(|(_, (tv, _))| emit_var_ref(&mut s, &Tyvar::Bound(tv.unwrap())));
718 quote! { <#(#tvs),*> }
719 } else {
720 TokenStream::new()
721 };
722
723 let getter = kebab_to_getter(wn.name);
724 let rp = s.root_path();
725 let tns = wn.namespace_path();
726 let tn = kebab_to_type(wn.name);
727 quote! {
728 type #tn: #rp #tns::#tn #vs;
729 fn #getter(&mut self) -> impl ::core::borrow::BorrowMut<Self::#tn>;
730 }
731 }
732 ExternDesc::Component(_) => {
733 panic!("nested components not yet supported in rust bindings");
734 }
735 }
736}
737
738fn emit_instance<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, it: &'c Instance<'b>) {
741 log::debug!("emitting instance {:?}", wn);
742 let mut s = s.with_cursor(wn.namespace_idents());
743
744 let name = kebab_to_type(wn.name);
745
746 s.cur_helper_mod = Some(kebab_to_namespace(wn.name));
747 s.cur_trait = Some(name.clone());
748 if !s.cur_trait().items.is_empty() {
749 return;
761 }
762
763 let mut needs_vars = BTreeSet::new();
764 let mut sv = s.with_needs_vars(&mut needs_vars);
765
766 let exports = it
767 .exports
768 .iter()
769 .map(|ed| emit_extern_decl(true, &mut sv, ed))
770 .collect::<Vec<_>>();
771
772 let mut stvs = BTreeMap::new();
775 let _ = sv.cur_trait(); let t = sv.cur_trait_immut();
777 for (ti, _) in t.supertraits.iter() {
778 let t = sv.resolve_trait_immut(false, ti);
779 stvs.insert(ti.clone(), t.tv_idxs());
780 }
781 sv.origin.push(ImportExport::Export("self"));
784 let mut stis = BTreeMap::new();
785 for (id, tvs) in stvs.into_iter() {
786 stis.insert(id, emit_tvis(&mut sv, tvs));
787 }
788 for (id, ts) in stis.into_iter() {
789 sv.cur_trait().supertraits.get_mut(&id).unwrap().extend(ts);
790 }
791
792 drop(sv);
793 log::debug!("after exports, ncur_needs_vars is {:?}", needs_vars);
794 for v in needs_vars {
795 let id = s.noff_var_id(v);
796 s.cur_trait().tvs.insert(id, (Some(v), TokenStream::new()));
797 }
798
799 s.cur_trait().items.extend(quote! { #(#exports)* });
800}
801
802fn emit_component<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, ct: &'c Component<'b>) {
808 let mut s = s.with_cursor(wn.namespace_idents());
809
810 let base_name = kebab_to_type(wn.name);
811
812 s.cur_helper_mod = Some(kebab_to_namespace(wn.name));
813
814 let import_name = kebab_to_imports_name(wn.name);
815 *s.bound_vars = ct
816 .uvars
817 .iter()
818 .rev()
819 .map(Clone::clone)
820 .collect::<VecDeque<_>>();
821 s.cur_trait = Some(import_name.clone());
822 let imports = ct
823 .imports
824 .iter()
825 .map(|ed| emit_extern_decl(false, &mut s, ed))
826 .collect::<Vec<TokenStream>>();
827 s.cur_trait().items.extend(quote! { #(#imports)* });
828
829 s.adjust_vars(ct.instance.evars.len() as u32);
830
831 s.import_param_var = Some(format_ident!("I"));
832
833 let export_name = kebab_to_exports_name(wn.name);
834 *s.bound_vars = ct
835 .instance
836 .evars
837 .iter()
838 .rev()
839 .chain(ct.uvars.iter().rev())
840 .map(Clone::clone)
841 .collect::<VecDeque<_>>();
842 s.cur_trait = Some(export_name.clone());
843 let exports = ct
844 .instance
845 .unqualified
846 .exports
847 .iter()
848 .map(|ed| emit_extern_decl(true, &mut s, ed))
849 .collect::<Vec<_>>();
850 s.cur_trait().tvs.insert(
851 format_ident!("I"),
852 (None, quote! { #import_name + ::core::marker::Send }),
853 );
854 s.cur_trait().items.extend(quote! { #(#exports)* });
855
856 s.cur_helper_mod = None;
857 s.cur_trait = None;
858
859 s.cur_mod().items.extend(quote! {
860 pub trait #base_name {
861 type Exports<I: #import_name + ::core::marker::Send>: #export_name<I>;
862 fn instantiate<I: #import_name + ::core::marker::Send + 'static>(self, imports: I) -> Self::Exports<I>;
865 }
866 });
867}
868
869pub fn emit_toplevel<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, n: &str, ct: &'c Component<'b>) {
871 let wn = split_wit_name(n);
872 emit_component(s, wn, ct);
873}