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 self, Component, Defined, ExternDecl, ExternDesc, Func, Handleable, ImportExport, Instance,
33 Param, 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::FixList(vt, size) => {
285 let vt = emit_value(s, vt);
286 let size = *size as usize;
287 quote! { [#vt; #size] }
288 }
289 Value::Record(_) => panic!("record not at top level of valtype"),
290 Value::Tuple(vts) => {
291 let vts = vts.iter().map(|vt| emit_value(s, vt)).collect::<Vec<_>>();
292 quote! { (#(#vts),*) }
293 }
294 Value::Flags(_) => panic!("flags not at top level of valtype"),
295 Value::Variant(_) => panic!("flags not at top level of valtype"),
296 Value::Enum(_) => panic!("enum not at top level of valtype"),
297 Value::Option(vt) => {
298 let vt = emit_value(s, vt);
299 quote! { ::core::option::Option<#vt> }
300 }
301 Value::Result(vt1, vt2) => {
302 let unit = Value::Tuple(Vec::new());
303 let vt1 = emit_value(s, vt1.as_ref().as_ref().unwrap_or(&unit));
304 let vt2 = emit_value(s, vt2.as_ref().as_ref().unwrap_or(&unit));
305 quote! { ::core::result::Result<#vt1, #vt2> }
306 }
307 Value::Own(ht) => match ht {
308 Handleable::Resource(_) => panic!("bare resource in type"),
309 Handleable::Var(tv) => {
310 if s.is_guest {
311 let wrap = if s.is_wasmtime_guest {
312 |toks| quote! { ::wasmtime::component::Resource<#toks> }
313 } else {
314 |toks| toks
315 };
316 if !s.is_impl {
317 wrap(emit_var_ref(s, tv))
318 } else {
319 let n = crate::hl::resolve_handleable_to_resource(s, ht);
320 log::debug!("resolved ht to r (4) {:?} {:?}", ht, n);
321 let id = format_ident!("HostResource{}", n);
322 wrap(quote! { #id })
323 }
324 } else {
325 emit_var_ref(s, tv)
326 }
327 }
328 },
329 Value::Borrow(ht) => match ht {
330 Handleable::Resource(_) => panic!("bare resource in type"),
331 Handleable::Var(tv) => {
332 if s.is_guest {
333 let wrap = if s.is_wasmtime_guest {
334 |toks| quote! { ::wasmtime::component::Resource<#toks> }
335 } else {
336 |toks| quote! { &#toks }
337 };
338 if !s.is_impl {
339 wrap(emit_var_ref(s, tv))
340 } else {
341 let n = crate::hl::resolve_handleable_to_resource(s, ht);
342 log::debug!("resolved ht to r (5) {:?} {:?}", ht, n);
343 let id = format_ident!("HostResource{}", n);
344 wrap(quote! { #id })
345 }
346 } else {
347 let vr = emit_var_ref(s, tv);
348 quote! { ::hyperlight_common::resource::BorrowedResourceGuard<#vr> }
349 }
350 }
351 },
352 Value::Var(Some(tv), _) => emit_var_ref(s, tv),
353 Value::Var(None, _) => panic!("value type with recorded but unknown var"),
354 }
355}
356
357fn emit_value_toplevel(s: &mut State, v: Option<u32>, id: Ident, vt: &Value) -> TokenStream {
361 let is_wasmtime_guest = s.is_wasmtime_guest;
362 match vt {
363 Value::Record(rfs) => {
364 let (vs, toks) = gather_needed_vars(s, v, |s| {
365 let rfs = rfs
366 .iter()
367 .map(|rf| {
368 let orig_name = rf.name.name;
369 let id = kebab_to_var(orig_name);
370 let derives = if s.is_wasmtime_guest {
371 quote! { #[component(name = #orig_name)] }
372 } else {
373 TokenStream::new()
374 };
375 let ty = emit_value(s, &rf.ty);
376 quote! { #derives pub #id: #ty }
377 })
378 .collect::<Vec<_>>();
379 quote! { #(#rfs),* }
380 });
381 let vs = emit_type_defn_var_list(s, vs);
382 let derives = if s.is_wasmtime_guest {
383 quote! {
384 #[derive(::wasmtime::component::ComponentType)]
385 #[derive(::wasmtime::component::Lift)]
386 #[derive(::wasmtime::component::Lower)]
387 #[component(record)]
388 }
389 } else {
390 TokenStream::new()
391 };
392 quote! {
393 #derives
394 #[derive(Debug)]
395 pub struct #id #vs { #toks }
396 }
397 }
398 Value::Flags(ns) => {
399 let (vs, toks) = gather_needed_vars(s, v, |_| {
400 let ns = ns
401 .iter()
402 .map(|n| {
403 let orig_name = n.name;
404 let id = kebab_to_var(orig_name);
405 quote! { pub #id: bool }
406 })
407 .collect::<Vec<_>>();
408 quote! { #(#ns),* }
409 });
410 let vs = emit_type_defn_var_list(s, vs);
411 quote! {
412 #[derive(Debug, Clone, PartialEq)]
413 pub struct #id #vs { #toks }
414 }
415 }
416 Value::Variant(vcs) => {
417 let (vs, toks) = gather_needed_vars(s, v, |s| {
418 let vcs = vcs
419 .iter()
420 .map(|vc| {
421 let orig_name = vc.name.name;
422 let id = kebab_to_cons(orig_name);
423 let derives = if s.is_wasmtime_guest {
424 quote! { #[component(name = #orig_name)] }
425 } else {
426 TokenStream::new()
427 };
428 match &vc.ty {
429 Some(ty) => {
430 let ty = emit_value(s, ty);
431 quote! { #derives #id(#ty) }
432 }
433 None => quote! { #derives #id },
434 }
435 })
436 .collect::<Vec<_>>();
437 quote! { #(#vcs),* }
438 });
439 let vs = emit_type_defn_var_list(s, vs);
440 let derives = if s.is_wasmtime_guest {
441 quote! {
442 #[derive(::wasmtime::component::ComponentType)]
443 #[derive(::wasmtime::component::Lift)]
444 #[derive(::wasmtime::component::Lower)]
445 #[component(variant)]
446 }
447 } else {
448 TokenStream::new()
449 };
450 quote! {
451 #derives
452 #[derive(Debug)]
453 pub enum #id #vs { #toks }
454 }
455 }
456 Value::Enum(ns) => {
457 let (vs, toks) = gather_needed_vars(s, v, |_| {
458 let ns = ns
459 .iter()
460 .map(|n| {
461 let orig_name = n.name;
462 let id = kebab_to_cons(orig_name);
463 let derives = if is_wasmtime_guest {
464 quote! { #[component(name = #orig_name)] }
465 } else {
466 TokenStream::new()
467 };
468 quote! { #derives #id }
469 })
470 .collect::<Vec<_>>();
471 quote! { #(#ns),* }
472 });
473 let vs = emit_type_defn_var_list(s, vs);
474 let derives = if s.is_wasmtime_guest {
475 quote! {
476 #[derive(::wasmtime::component::ComponentType)]
477 #[derive(::wasmtime::component::Lift)]
478 #[derive(::wasmtime::component::Lower)]
479 #[component(enum)]
480 #[repr(u8)] }
482 } else {
483 TokenStream::new()
484 };
485 quote! {
486 #derives
487 #[derive(Debug, Copy, Clone, PartialEq)]
488 pub enum #id #vs { #toks }
489 }
490 }
491 _ => emit_type_alias(s, v, id, |s| emit_value(s, vt)),
492 }
493}
494
495fn emit_defined(s: &mut State, v: Option<u32>, id: Ident, dt: &Defined) -> TokenStream {
502 match dt {
503 Defined::Instance(_) | Defined::Component(_) => TokenStream::new(),
506 Defined::Handleable(Handleable::Resource(_)) => panic!("bare resource in type"),
508 Defined::Handleable(Handleable::Var(tv)) => {
509 emit_type_alias(s, v, id, |s| emit_var_ref(s, tv))
510 }
511 Defined::Value(vt) => emit_value_toplevel(s, v, id, vt),
512 Defined::Func(ft) => emit_type_alias(s, v, id, |s| emit_func(s, ft)),
513 }
514}
515
516pub fn emit_func_param(s: &mut State, p: &Param) -> TokenStream {
520 let name = kebab_to_var(p.name.name);
521 let ty = emit_value(s, &p.ty);
522 quote! { #name: #ty }
523}
524
525pub fn emit_func_result(s: &mut State, r: &etypes::Result<'_>) -> TokenStream {
530 match r {
531 Some(vt) => emit_value(s, vt),
532 None => quote! { () },
533 }
534}
535
536fn emit_func(s: &mut State, ft: &Func) -> TokenStream {
541 let params = ft
542 .params
543 .iter()
544 .map(|p| emit_func_param(s, p))
545 .collect::<Vec<_>>();
546 let result = emit_func_result(s, &ft.result);
547 quote! { fn(#(#params),*) -> #result }
548}
549
550fn gather_needed_vars<F: Fn(&mut State) -> TokenStream>(
554 s: &mut State,
555 v: Option<u32>,
556 f: F,
557) -> (BTreeSet<u32>, TokenStream) {
558 let mut needs_vars = BTreeSet::new();
559 let mut sv = s.with_needs_vars(&mut needs_vars);
560 let toks = f(&mut sv);
561 if let Some(vn) = v {
562 sv.record_needs_vars(vn);
563 }
564 drop(sv);
565 (needs_vars, toks)
566}
567fn emit_type_defn_var_list(s: &mut State, vs: BTreeSet<u32>) -> TokenStream {
571 if vs.is_empty() {
572 TokenStream::new()
573 } else {
574 let vs = vs
575 .iter()
576 .map(|n| {
577 if s.is_guest {
578 let t = s.noff_var_id(*n);
579 quote! { #t: 'static }
580 } else {
581 let t = s.noff_var_id(*n);
582 quote! { #t }
583 }
584 })
585 .collect::<Vec<_>>();
586 quote! { <#(#vs),*> }
587 }
588}
589fn emit_type_alias<F: Fn(&mut State) -> TokenStream>(
598 s: &mut State,
599 v: Option<u32>,
600 id: Ident,
601 f: F,
602) -> TokenStream {
603 let (vs, toks) = gather_needed_vars(s, v, f);
604 let vs = emit_type_defn_var_list(s, vs);
605 quote! { pub type #id #vs = #toks; }
606}
607
608fn emit_extern_decl<'a, 'b, 'c>(
611 is_export: bool,
612 s: &'c mut State<'a, 'b>,
613 ed: &'c ExternDecl<'b>,
614) -> TokenStream {
615 log::debug!(" emitting decl {:?}", ed.kebab_name);
616 match &ed.desc {
617 ExternDesc::CoreModule(_) => panic!("core module (im/ex)ports are not supported"),
618 ExternDesc::Func(ft) => {
619 let mut s = s.push_origin(is_export, ed.kebab_name);
620 match kebab_to_fn(ed.kebab_name) {
621 FnName::Plain(n) => {
622 let params = ft
623 .params
624 .iter()
625 .map(|p| emit_func_param(&mut s, p))
626 .collect::<Vec<_>>();
627 let result = emit_func_result(&mut s, &ft.result);
628 quote! {
629 fn #n(&mut self, #(#params),*) -> #result;
630 }
631 }
632 FnName::Associated(r, n) => {
633 let mut s = s.helper();
634 s.cur_trait = Some(r.clone());
635 let mut needs_vars = BTreeSet::new();
636 let mut sv = s.with_needs_vars(&mut needs_vars);
637 let params = ft
638 .params
639 .iter()
640 .map(|p| emit_func_param(&mut sv, p))
641 .collect::<Vec<_>>();
642 match n {
643 ResourceItemName::Constructor => {
644 sv.cur_trait().items.extend(quote! {
645 fn new(&mut self, #(#params),*) -> Self::T;
646 });
647 }
648 ResourceItemName::Method(n) => {
649 let result = emit_func_result(&mut sv, &ft.result);
650 sv.cur_trait().items.extend(quote! {
651 fn #n(&mut self, #(#params),*) -> #result;
652 });
653 }
654 ResourceItemName::Static(n) => {
655 let result = emit_func_result(&mut sv, &ft.result);
656 sv.cur_trait().items.extend(quote! {
657 fn #n(&mut self, #(#params),*) -> #result;
658 });
659 }
660 }
661 for v in needs_vars {
662 let id = s.noff_var_id(v);
663 s.cur_trait().tvs.insert(id, (Some(v), TokenStream::new()));
664 }
665 quote! {}
666 }
667 }
668 }
669 ExternDesc::Type(t) => {
670 fn go_defined<'a, 'b, 'c>(
671 s: &'c mut State<'a, 'b>,
672 ed: &'c ExternDecl<'b>,
673 t: &'c Defined<'b>,
674 v: Option<u32>,
675 ) -> TokenStream {
676 let id = kebab_to_type(ed.kebab_name);
677 let mut s = s.helper();
678
679 let t = emit_defined(&mut s, v, id, t);
680 s.cur_mod().items.extend(t);
681 TokenStream::new()
682 }
683 let edn: &'b str = ed.kebab_name;
684 let mut s: State<'_, 'b> = s.push_origin(is_export, edn);
685 if let Some((n, bound)) = s.is_var_defn(t) {
686 match bound {
687 TypeBound::Eq(t) => {
688 let noff = s.var_offset as u32 + n;
692 s.var_offset += n as usize + 1;
693 go_defined(&mut s, ed, &t, Some(noff))
694 }
695 TypeBound::SubResource => {
696 let rn = kebab_to_type(ed.kebab_name);
697 s.add_helper_supertrait(rn.clone());
698 let mut s = s.helper();
699 s.cur_trait = Some(rn.clone());
700 s.cur_trait().items.extend(quote! {
701 type T: ::core::marker::Send;
702 });
703 quote! {}
704 }
705 }
706 } else {
707 go_defined(&mut s, ed, t, None)
708 }
709 }
710 ExternDesc::Instance(it) => {
711 let mut s = s.push_origin(is_export, ed.kebab_name);
712 let wn = split_wit_name(ed.kebab_name);
713 emit_instance(&mut s, wn.clone(), it);
714
715 let nsids = wn.namespace_idents();
716 let repr = s.r#trait(&nsids, kebab_to_type(wn.name));
717 let vs = if !repr.tvs.is_empty() {
718 let vs = repr.tvs.clone();
719 let tvs = vs
720 .iter()
721 .map(|(_, (tv, _))| emit_var_ref(&mut s, &Tyvar::Bound(tv.unwrap())));
722 quote! { <#(#tvs),*> }
723 } else {
724 TokenStream::new()
725 };
726
727 let getter = kebab_to_getter(wn.name);
728 let rp = s.root_path();
729 let tns = wn.namespace_path();
730 let tn = kebab_to_type(wn.name);
731 quote! {
732 type #tn: #rp #tns::#tn #vs;
733 fn #getter(&mut self) -> impl ::core::borrow::BorrowMut<Self::#tn>;
734 }
735 }
736 ExternDesc::Component(_) => {
737 panic!("nested components not yet supported in rust bindings");
738 }
739 }
740}
741
742fn emit_instance<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, it: &'c Instance<'b>) {
745 log::debug!("emitting instance {:?}", wn);
746 let mut s = s.with_cursor(wn.namespace_idents());
747
748 let name = kebab_to_type(wn.name);
749
750 s.cur_helper_mod = Some(kebab_to_namespace(wn.name));
751 s.cur_trait = Some(name.clone());
752 if !s.cur_trait().items.is_empty() {
753 return;
765 }
766
767 let mut needs_vars = BTreeSet::new();
768 let mut sv = s.with_needs_vars(&mut needs_vars);
769
770 let exports = it
771 .exports
772 .iter()
773 .map(|ed| emit_extern_decl(true, &mut sv, ed))
774 .collect::<Vec<_>>();
775
776 let mut stvs = BTreeMap::new();
779 let _ = sv.cur_trait(); let t = sv.cur_trait_immut();
781 for (ti, _) in t.supertraits.iter() {
782 let t = sv.resolve_trait_immut(false, ti);
783 stvs.insert(ti.clone(), t.tv_idxs());
784 }
785 sv.origin.push(ImportExport::Export("self"));
788 let mut stis = BTreeMap::new();
789 for (id, tvs) in stvs.into_iter() {
790 stis.insert(id, emit_tvis(&mut sv, tvs));
791 }
792 for (id, ts) in stis.into_iter() {
793 sv.cur_trait().supertraits.get_mut(&id).unwrap().extend(ts);
794 }
795
796 drop(sv);
797 log::debug!("after exports, ncur_needs_vars is {:?}", needs_vars);
798 for v in needs_vars {
799 let id = s.noff_var_id(v);
800 s.cur_trait().tvs.insert(id, (Some(v), TokenStream::new()));
801 }
802
803 s.cur_trait().items.extend(quote! { #(#exports)* });
804}
805
806fn emit_component<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, ct: &'c Component<'b>) {
812 let mut s = s.with_cursor(wn.namespace_idents());
813
814 let base_name = kebab_to_type(wn.name);
815
816 s.cur_helper_mod = Some(kebab_to_namespace(wn.name));
817
818 let import_name = kebab_to_imports_name(wn.name);
819 *s.bound_vars = ct
820 .uvars
821 .iter()
822 .rev()
823 .map(Clone::clone)
824 .collect::<VecDeque<_>>();
825 s.cur_trait = Some(import_name.clone());
826 let imports = ct
827 .imports
828 .iter()
829 .map(|ed| emit_extern_decl(false, &mut s, ed))
830 .collect::<Vec<TokenStream>>();
831 s.cur_trait().items.extend(quote! { #(#imports)* });
832
833 s.adjust_vars(ct.instance.evars.len() as u32);
834
835 s.import_param_var = Some(format_ident!("I"));
836
837 let export_name = kebab_to_exports_name(wn.name);
838 *s.bound_vars = ct
839 .instance
840 .evars
841 .iter()
842 .rev()
843 .chain(ct.uvars.iter().rev())
844 .map(Clone::clone)
845 .collect::<VecDeque<_>>();
846 s.cur_trait = Some(export_name.clone());
847 let exports = ct
848 .instance
849 .unqualified
850 .exports
851 .iter()
852 .map(|ed| emit_extern_decl(true, &mut s, ed))
853 .collect::<Vec<_>>();
854 s.cur_trait().tvs.insert(
855 format_ident!("I"),
856 (None, quote! { #import_name + ::core::marker::Send }),
857 );
858 s.cur_trait().items.extend(quote! { #(#exports)* });
859
860 s.cur_helper_mod = None;
861 s.cur_trait = None;
862
863 s.cur_mod().items.extend(quote! {
864 pub trait #base_name {
865 type Exports<I: #import_name + ::core::marker::Send>: #export_name<I>;
866 fn instantiate<I: #import_name + ::core::marker::Send + 'static>(self, imports: I) -> Self::Exports<I>;
869 }
870 });
871}
872
873pub fn emit_toplevel<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, n: &str, ct: &'c Component<'b>) {
875 let wn = split_wit_name(n);
876 emit_component(s, wn, ct);
877}