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 if s.is_export {
349 quote! { &#vr }
350 } else {
351 quote! { ::hyperlight_common::resource::BorrowedResourceGuard<#vr> }
352 }
353 }
354 }
355 },
356 Value::Var(Some(tv), _) => emit_var_ref(s, tv),
357 Value::Var(None, _) => panic!("value type with recorded but unknown var"),
358 }
359}
360
361fn emit_value_toplevel(s: &mut State, v: Option<u32>, id: Ident, vt: &Value) -> TokenStream {
365 let is_wasmtime_guest = s.is_wasmtime_guest;
366 match vt {
367 Value::Record(rfs) => {
368 let (vs, toks) = gather_needed_vars(s, v, |s| {
369 let rfs = rfs
370 .iter()
371 .map(|rf| {
372 let orig_name = rf.name.name;
373 let id = kebab_to_var(orig_name);
374 let derives = if s.is_wasmtime_guest {
375 quote! { #[component(name = #orig_name)] }
376 } else {
377 TokenStream::new()
378 };
379 let ty = emit_value(s, &rf.ty);
380 quote! { #derives pub #id: #ty }
381 })
382 .collect::<Vec<_>>();
383 quote! { #(#rfs),* }
384 });
385 let vs = emit_type_defn_var_list(s, vs);
386 let derives = if s.is_wasmtime_guest {
387 quote! {
388 #[derive(::wasmtime::component::ComponentType)]
389 #[derive(::wasmtime::component::Lift)]
390 #[derive(::wasmtime::component::Lower)]
391 #[component(record)]
392 }
393 } else {
394 TokenStream::new()
395 };
396 quote! {
397 #derives
398 #[derive(Debug)]
399 pub struct #id #vs { #toks }
400 }
401 }
402 Value::Flags(ns) => {
403 let (vs, toks) = gather_needed_vars(s, v, |_| {
404 let ns = ns
405 .iter()
406 .map(|n| {
407 let orig_name = n.name;
408 let id = kebab_to_var(orig_name);
409 quote! { pub #id: bool }
410 })
411 .collect::<Vec<_>>();
412 quote! { #(#ns),* }
413 });
414 let vs = emit_type_defn_var_list(s, vs);
415 quote! {
416 #[derive(Debug, Clone, PartialEq)]
417 pub struct #id #vs { #toks }
418 }
419 }
420 Value::Variant(vcs) => {
421 let (vs, toks) = gather_needed_vars(s, v, |s| {
422 let vcs = vcs
423 .iter()
424 .map(|vc| {
425 let orig_name = vc.name.name;
426 let id = kebab_to_cons(orig_name);
427 let derives = if s.is_wasmtime_guest {
428 quote! { #[component(name = #orig_name)] }
429 } else {
430 TokenStream::new()
431 };
432 match &vc.ty {
433 Some(ty) => {
434 let ty = emit_value(s, ty);
435 quote! { #derives #id(#ty) }
436 }
437 None => quote! { #derives #id },
438 }
439 })
440 .collect::<Vec<_>>();
441 quote! { #(#vcs),* }
442 });
443 let vs = emit_type_defn_var_list(s, vs);
444 let derives = if s.is_wasmtime_guest {
445 quote! {
446 #[derive(::wasmtime::component::ComponentType)]
447 #[derive(::wasmtime::component::Lift)]
448 #[derive(::wasmtime::component::Lower)]
449 #[component(variant)]
450 }
451 } else {
452 TokenStream::new()
453 };
454 quote! {
455 #derives
456 #[derive(Debug)]
457 pub enum #id #vs { #toks }
458 }
459 }
460 Value::Enum(ns) => {
461 let (vs, toks) = gather_needed_vars(s, v, |_| {
462 let ns = ns
463 .iter()
464 .map(|n| {
465 let orig_name = n.name;
466 let id = kebab_to_cons(orig_name);
467 let derives = if is_wasmtime_guest {
468 quote! { #[component(name = #orig_name)] }
469 } else {
470 TokenStream::new()
471 };
472 quote! { #derives #id }
473 })
474 .collect::<Vec<_>>();
475 quote! { #(#ns),* }
476 });
477 let vs = emit_type_defn_var_list(s, vs);
478 let derives = if s.is_wasmtime_guest {
479 quote! {
480 #[derive(::wasmtime::component::ComponentType)]
481 #[derive(::wasmtime::component::Lift)]
482 #[derive(::wasmtime::component::Lower)]
483 #[component(enum)]
484 #[repr(u8)] }
486 } else {
487 TokenStream::new()
488 };
489 quote! {
490 #derives
491 #[derive(Debug, Copy, Clone, PartialEq)]
492 pub enum #id #vs { #toks }
493 }
494 }
495 _ => emit_type_alias(s, v, id, |s| emit_value(s, vt)),
496 }
497}
498
499fn emit_defined(s: &mut State, v: Option<u32>, id: Ident, dt: &Defined) -> TokenStream {
506 match dt {
507 Defined::Instance(_) | Defined::Component(_) => TokenStream::new(),
510 Defined::Handleable(Handleable::Resource(_)) => panic!("bare resource in type"),
512 Defined::Handleable(Handleable::Var(tv)) => {
513 emit_type_alias(s, v, id, |s| emit_var_ref(s, tv))
514 }
515 Defined::Value(vt) => emit_value_toplevel(s, v, id, vt),
516 Defined::Func(ft) => emit_type_alias(s, v, id, |s| emit_func(s, ft)),
517 }
518}
519
520pub fn emit_func_param(s: &mut State, p: &Param) -> TokenStream {
524 let name = kebab_to_var(p.name.name);
525 let ty = emit_value(s, &p.ty);
526 quote! { #name: #ty }
527}
528
529pub fn emit_func_result(s: &mut State, r: &etypes::Result<'_>) -> TokenStream {
534 match r {
535 Some(vt) => emit_value(s, vt),
536 None => quote! { () },
537 }
538}
539
540fn emit_func(s: &mut State, ft: &Func) -> TokenStream {
545 let params = ft
546 .params
547 .iter()
548 .map(|p| emit_func_param(s, p))
549 .collect::<Vec<_>>();
550 let result = emit_func_result(s, &ft.result);
551 quote! { fn(#(#params),*) -> #result }
552}
553
554fn gather_needed_vars<F: Fn(&mut State) -> TokenStream>(
558 s: &mut State,
559 v: Option<u32>,
560 f: F,
561) -> (BTreeSet<u32>, TokenStream) {
562 let mut needs_vars = BTreeSet::new();
563 let mut sv = s.with_needs_vars(&mut needs_vars);
564 let toks = f(&mut sv);
565 if let Some(vn) = v {
566 sv.record_needs_vars(vn);
567 }
568 drop(sv);
569 (needs_vars, toks)
570}
571fn emit_type_defn_var_list(s: &mut State, vs: BTreeSet<u32>) -> TokenStream {
575 if vs.is_empty() {
576 TokenStream::new()
577 } else {
578 let vs = vs
579 .iter()
580 .map(|n| {
581 if s.is_guest {
582 let t = s.noff_var_id(*n);
583 quote! { #t: 'static }
584 } else {
585 let t = s.noff_var_id(*n);
586 quote! { #t }
587 }
588 })
589 .collect::<Vec<_>>();
590 quote! { <#(#vs),*> }
591 }
592}
593fn emit_type_alias<F: Fn(&mut State) -> TokenStream>(
602 s: &mut State,
603 v: Option<u32>,
604 id: Ident,
605 f: F,
606) -> TokenStream {
607 let (vs, toks) = gather_needed_vars(s, v, f);
608 let vs = emit_type_defn_var_list(s, vs);
609 quote! { pub type #id #vs = #toks; }
610}
611
612fn emit_extern_decl<'a, 'b, 'c>(
618 origin_was_export: bool,
619 s: &'c mut State<'a, 'b>,
620 ed: &'c ExternDecl<'b>,
621) -> TokenStream {
622 log::debug!(" emitting decl {:?}", ed.kebab_name);
623 match &ed.desc {
624 ExternDesc::CoreModule(_) => panic!("core module (im/ex)ports are not supported"),
625 ExternDesc::Func(ft) => {
626 let mut s = s.push_origin(origin_was_export, ed.kebab_name);
627 match kebab_to_fn(ed.kebab_name) {
628 FnName::Plain(n) => {
629 let params = ft
630 .params
631 .iter()
632 .map(|p| emit_func_param(&mut s, p))
633 .collect::<Vec<_>>();
634 let result = emit_func_result(&mut s, &ft.result);
635 quote! {
636 fn #n(&mut self, #(#params),*) -> #result;
637 }
638 }
639 FnName::Associated(r, n) => {
640 let mut s = s.helper();
641 s.cur_trait = Some(r.clone());
642 let mut needs_vars = BTreeSet::new();
643 let mut sv = s.with_needs_vars(&mut needs_vars);
644 let params = ft
645 .params
646 .iter()
647 .map(|p| emit_func_param(&mut sv, p))
648 .collect::<Vec<_>>();
649 match n {
650 ResourceItemName::Constructor => {
651 sv.cur_trait().items.extend(quote! {
652 fn new(&mut self, #(#params),*) -> Self::T;
653 });
654 }
655 ResourceItemName::Method(n) => {
656 let result = emit_func_result(&mut sv, &ft.result);
657 sv.cur_trait().items.extend(quote! {
658 fn #n(&mut self, #(#params),*) -> #result;
659 });
660 }
661 ResourceItemName::Static(n) => {
662 let result = emit_func_result(&mut sv, &ft.result);
663 sv.cur_trait().items.extend(quote! {
664 fn #n(&mut self, #(#params),*) -> #result;
665 });
666 }
667 }
668 for v in needs_vars {
669 let id = s.noff_var_id(v);
670 s.cur_trait().tvs.insert(id, (Some(v), TokenStream::new()));
671 }
672 quote! {}
673 }
674 }
675 }
676 ExternDesc::Type(t) => {
677 fn go_defined<'a, 'b, 'c>(
678 s: &'c mut State<'a, 'b>,
679 ed: &'c ExternDecl<'b>,
680 t: &'c Defined<'b>,
681 v: Option<u32>,
682 ) -> TokenStream {
683 let id = kebab_to_type(ed.kebab_name);
684 let mut s = s.helper();
685
686 let t = emit_defined(&mut s, v, id, t);
687 s.cur_mod().items.extend(t);
688 TokenStream::new()
689 }
690 let edn: &'b str = ed.kebab_name;
691 let mut s: State<'_, 'b> = s.push_origin(origin_was_export, edn);
692 if let Some((n, bound)) = s.is_var_defn(t) {
693 match bound {
694 TypeBound::Eq(t) => {
695 let noff = s.var_offset as u32 + n;
699 s.var_offset += n as usize + 1;
700 go_defined(&mut s, ed, &t, Some(noff))
701 }
702 TypeBound::SubResource => {
703 let rn = kebab_to_type(ed.kebab_name);
704 s.add_helper_supertrait(rn.clone());
705 let mut s = s.helper();
706 s.cur_trait = Some(rn.clone());
707 s.cur_trait().items.extend(quote! {
708 type T: ::core::marker::Send;
709 });
710 quote! {}
711 }
712 }
713 } else {
714 go_defined(&mut s, ed, t, None)
715 }
716 }
717 ExternDesc::Instance(it) => {
718 let mut s = s.push_origin(origin_was_export, ed.kebab_name);
719 let wn = split_wit_name(ed.kebab_name);
720 emit_instance(&mut s, wn.clone(), it);
721
722 let nsids = wn.namespace_idents();
723 let repr = s.r#trait(&nsids, kebab_to_type(wn.name));
724 let vs = if !repr.tvs.is_empty() {
725 let vs = repr.tvs.clone();
726 let tvs = vs
727 .iter()
728 .map(|(_, (tv, _))| emit_var_ref(&mut s, &Tyvar::Bound(tv.unwrap())));
729 quote! { <#(#tvs),*> }
730 } else {
731 TokenStream::new()
732 };
733
734 let getter = kebab_to_getter(wn.name);
735 let rp = s.root_path();
736 let tns = wn.namespace_path();
737 let tn = kebab_to_type(wn.name);
738 quote! {
739 type #tn: #rp #tns::#tn #vs;
740 fn #getter(&mut self) -> impl ::core::borrow::BorrowMut<Self::#tn>;
741 }
742 }
743 ExternDesc::Component(_) => {
744 panic!("nested components not yet supported in rust bindings");
745 }
746 }
747}
748
749fn emit_instance<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, it: &'c Instance<'b>) {
752 log::debug!("emitting instance {:?}", wn);
753 let mut s = s.with_cursor(wn.namespace_idents());
754
755 let name = kebab_to_type(wn.name);
756
757 s.cur_helper_mod = Some(kebab_to_namespace(wn.name));
758 s.cur_trait = Some(name.clone());
759 if !s.cur_trait().items.is_empty() {
760 return;
772 }
773
774 let mut needs_vars = BTreeSet::new();
775 let mut sv = s.with_needs_vars(&mut needs_vars);
776
777 let exports = it
778 .exports
779 .iter()
780 .map(|ed| emit_extern_decl(true, &mut sv, ed))
781 .collect::<Vec<_>>();
782
783 let mut stvs = BTreeMap::new();
786 let _ = sv.cur_trait(); let t = sv.cur_trait_immut();
788 for (ti, _) in t.supertraits.iter() {
789 let t = sv.resolve_trait_immut(false, ti);
790 stvs.insert(ti.clone(), t.tv_idxs());
791 }
792 sv.origin.push(ImportExport::Export("self"));
795 let mut stis = BTreeMap::new();
796 for (id, tvs) in stvs.into_iter() {
797 stis.insert(id, emit_tvis(&mut sv, tvs));
798 }
799 for (id, ts) in stis.into_iter() {
800 sv.cur_trait().supertraits.get_mut(&id).unwrap().extend(ts);
801 }
802
803 drop(sv);
804 log::debug!("after exports, ncur_needs_vars is {:?}", needs_vars);
805 for v in needs_vars {
806 let id = s.noff_var_id(v);
807 s.cur_trait().tvs.insert(id, (Some(v), TokenStream::new()));
808 }
809
810 s.cur_trait().items.extend(quote! { #(#exports)* });
811}
812
813fn emit_component<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, ct: &'c Component<'b>) {
819 let mut s = s.with_cursor(wn.namespace_idents());
820
821 let base_name = kebab_to_type(wn.name);
822
823 s.cur_helper_mod = Some(kebab_to_namespace(wn.name));
824
825 let import_name = kebab_to_imports_name(wn.name);
826 *s.bound_vars = ct
827 .uvars
828 .iter()
829 .rev()
830 .map(Clone::clone)
831 .collect::<VecDeque<_>>();
832 s.cur_trait = Some(import_name.clone());
833 let imports = ct
834 .imports
835 .iter()
836 .map(|ed| emit_extern_decl(false, &mut s, ed))
837 .collect::<Vec<TokenStream>>();
838 s.cur_trait().items.extend(quote! { #(#imports)* });
839
840 s.adjust_vars(ct.instance.evars.len() as u32);
841 s.import_param_var = Some(format_ident!("I"));
842 s.is_export = true;
843
844 let export_name = kebab_to_exports_name(wn.name);
845 *s.bound_vars = ct
846 .instance
847 .evars
848 .iter()
849 .rev()
850 .chain(ct.uvars.iter().rev())
851 .map(Clone::clone)
852 .collect::<VecDeque<_>>();
853 s.cur_trait = Some(export_name.clone());
854 let exports = ct
855 .instance
856 .unqualified
857 .exports
858 .iter()
859 .map(|ed| emit_extern_decl(true, &mut s, ed))
860 .collect::<Vec<_>>();
861 s.cur_trait().tvs.insert(
862 format_ident!("I"),
863 (None, quote! { #import_name + ::core::marker::Send }),
864 );
865 s.cur_trait().items.extend(quote! { #(#exports)* });
866
867 s.cur_helper_mod = None;
868 s.cur_trait = None;
869
870 s.cur_mod().items.extend(quote! {
871 pub trait #base_name {
872 type Exports<I: #import_name + ::core::marker::Send>: #export_name<I>;
873 fn instantiate<I: #import_name + ::core::marker::Send + 'static>(self, imports: I) -> Self::Exports<I>;
876 }
877 });
878}
879
880pub fn emit_toplevel<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, n: &str, ct: &'c Component<'b>) {
882 let wn = split_wit_name(n);
883 emit_component(s, wn, ct);
884}