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, Clone, PartialEq)]
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, Clone, PartialEq)]
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 #[derive(::core::clone::Clone)]
475 #[derive(::core::marker::Copy)]
476 #[component(enum)]
477 #[repr(u8)] }
479 } else {
480 TokenStream::new()
481 };
482 quote! {
483 #derives
484 #[derive(Debug, Clone, PartialEq)]
485 pub enum #id #vs { #toks }
486 }
487 }
488 _ => emit_type_alias(s, v, id, |s| emit_value(s, vt)),
489 }
490}
491
492fn emit_defined(s: &mut State, v: Option<u32>, id: Ident, dt: &Defined) -> TokenStream {
499 match dt {
500 Defined::Instance(_) | Defined::Component(_) => TokenStream::new(),
503 Defined::Handleable(Handleable::Resource(_)) => panic!("bare resource in type"),
505 Defined::Handleable(Handleable::Var(tv)) => {
506 emit_type_alias(s, v, id, |s| emit_var_ref(s, tv))
507 }
508 Defined::Value(vt) => emit_value_toplevel(s, v, id, vt),
509 Defined::Func(ft) => emit_type_alias(s, v, id, |s| emit_func(s, ft)),
510 }
511}
512
513pub fn emit_func_param(s: &mut State, p: &Param) -> TokenStream {
517 let name = kebab_to_var(p.name.name);
518 let ty = emit_value(s, &p.ty);
519 quote! { #name: #ty }
520}
521
522pub fn emit_func_result(s: &mut State, r: &Result) -> TokenStream {
527 match r {
528 Result::Unnamed(vt) => emit_value(s, vt),
529 Result::Named(rs) if rs.is_empty() => quote! { () },
530 _ => panic!("multiple named function results are not currently supported"),
531 }
532}
533
534fn emit_func(s: &mut State, ft: &Func) -> TokenStream {
539 let params = ft
540 .params
541 .iter()
542 .map(|p| emit_func_param(s, p))
543 .collect::<Vec<_>>();
544 let result = emit_func_result(s, &ft.result);
545 quote! { fn(#(#params),*) -> #result }
546}
547
548fn gather_needed_vars<F: Fn(&mut State) -> TokenStream>(
552 s: &mut State,
553 v: Option<u32>,
554 f: F,
555) -> (BTreeSet<u32>, TokenStream) {
556 let mut needs_vars = BTreeSet::new();
557 let mut sv = s.with_needs_vars(&mut needs_vars);
558 let toks = f(&mut sv);
559 if let Some(vn) = v {
560 sv.record_needs_vars(vn);
561 }
562 drop(sv);
563 (needs_vars, toks)
564}
565fn emit_type_defn_var_list(s: &mut State, vs: BTreeSet<u32>) -> TokenStream {
569 if vs.is_empty() {
570 TokenStream::new()
571 } else {
572 let vs = vs
573 .iter()
574 .map(|n| {
575 if s.is_guest {
576 let t = s.noff_var_id(*n);
577 quote! { #t: 'static }
578 } else {
579 let t = s.noff_var_id(*n);
580 quote! { #t }
581 }
582 })
583 .collect::<Vec<_>>();
584 quote! { <#(#vs),*> }
585 }
586}
587fn emit_type_alias<F: Fn(&mut State) -> TokenStream>(
596 s: &mut State,
597 v: Option<u32>,
598 id: Ident,
599 f: F,
600) -> TokenStream {
601 let (vs, toks) = gather_needed_vars(s, v, f);
602 let vs = emit_type_defn_var_list(s, vs);
603 quote! { pub type #id #vs = #toks; }
604}
605
606fn emit_extern_decl<'a, 'b, 'c>(
609 is_export: bool,
610 s: &'c mut State<'a, 'b>,
611 ed: &'c ExternDecl<'b>,
612) -> TokenStream {
613 log::debug!(" emitting decl {:?}", ed.kebab_name);
614 match &ed.desc {
615 ExternDesc::CoreModule(_) => panic!("core module (im/ex)ports are not supported"),
616 ExternDesc::Func(ft) => {
617 let mut s = s.push_origin(is_export, ed.kebab_name);
618 match kebab_to_fn(ed.kebab_name) {
619 FnName::Plain(n) => {
620 let params = ft
621 .params
622 .iter()
623 .map(|p| emit_func_param(&mut s, p))
624 .collect::<Vec<_>>();
625 let result = emit_func_result(&mut s, &ft.result);
626 quote! {
627 fn #n(&mut self, #(#params),*) -> #result;
628 }
629 }
630 FnName::Associated(r, n) => {
631 let mut s = s.helper();
632 s.cur_trait = Some(r.clone());
633 let mut needs_vars = BTreeSet::new();
634 let mut sv = s.with_needs_vars(&mut needs_vars);
635 let params = ft
636 .params
637 .iter()
638 .map(|p| emit_func_param(&mut sv, p))
639 .collect::<Vec<_>>();
640 match n {
641 ResourceItemName::Constructor => {
642 sv.cur_trait().items.extend(quote! {
643 fn new(&mut self, #(#params),*) -> Self::T;
644 });
645 }
646 ResourceItemName::Method(n) => {
647 let result = emit_func_result(&mut sv, &ft.result);
648 sv.cur_trait().items.extend(quote! {
649 fn #n(&mut self, #(#params),*) -> #result;
650 });
651 }
652 ResourceItemName::Static(n) => {
653 let result = emit_func_result(&mut sv, &ft.result);
654 sv.cur_trait().items.extend(quote! {
655 fn #n(&mut self, #(#params),*) -> #result;
656 });
657 }
658 }
659 for v in needs_vars {
660 let id = s.noff_var_id(v);
661 s.cur_trait().tvs.insert(id, (Some(v), TokenStream::new()));
662 }
663 quote! {}
664 }
665 }
666 }
667 ExternDesc::Type(t) => {
668 fn go_defined<'a, 'b, 'c>(
669 s: &'c mut State<'a, 'b>,
670 ed: &'c ExternDecl<'b>,
671 t: &'c Defined<'b>,
672 v: Option<u32>,
673 ) -> TokenStream {
674 let id = kebab_to_type(ed.kebab_name);
675 let mut s = s.helper();
676
677 let t = emit_defined(&mut s, v, id, t);
678 s.cur_mod().items.extend(t);
679 TokenStream::new()
680 }
681 let edn: &'b str = ed.kebab_name;
682 let mut s: State<'_, 'b> = s.push_origin(is_export, edn);
683 if let Some((n, bound)) = s.is_var_defn(t) {
684 match bound {
685 TypeBound::Eq(t) => {
686 let noff = s.var_offset as u32 + n;
690 s.var_offset += n as usize + 1;
691 go_defined(&mut s, ed, &t, Some(noff))
692 }
693 TypeBound::SubResource => {
694 let rn = kebab_to_type(ed.kebab_name);
695 s.add_helper_supertrait(rn.clone());
696 let mut s = s.helper();
697 s.cur_trait = Some(rn.clone());
698 s.cur_trait().items.extend(quote! {
699 type T: ::core::marker::Send;
700 });
701 quote! {}
702 }
703 }
704 } else {
705 go_defined(&mut s, ed, t, None)
706 }
707 }
708 ExternDesc::Instance(it) => {
709 let mut s = s.push_origin(is_export, ed.kebab_name);
710 let wn = split_wit_name(ed.kebab_name);
711 emit_instance(&mut s, wn.clone(), it);
712
713 let nsids = wn.namespace_idents();
714 let repr = s.r#trait(&nsids, kebab_to_type(wn.name));
715 let vs = if !repr.tvs.is_empty() {
716 let vs = repr.tvs.clone();
717 let tvs = vs
718 .iter()
719 .map(|(_, (tv, _))| emit_var_ref(&mut s, &Tyvar::Bound(tv.unwrap())));
720 quote! { <#(#tvs),*> }
721 } else {
722 TokenStream::new()
723 };
724
725 let getter = kebab_to_getter(wn.name);
726 let rp = s.root_path();
727 let tns = wn.namespace_path();
728 let tn = kebab_to_type(wn.name);
729 quote! {
730 type #tn: #rp #tns::#tn #vs;
731 fn #getter(&mut self) -> impl ::core::borrow::BorrowMut<Self::#tn>;
732 }
733 }
734 ExternDesc::Component(_) => {
735 panic!("nested components not yet supported in rust bindings");
736 }
737 }
738}
739
740fn emit_instance<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, it: &'c Instance<'b>) {
743 log::debug!("emitting instance {:?}", wn);
744 let mut s = s.with_cursor(wn.namespace_idents());
745
746 let name = kebab_to_type(wn.name);
747
748 s.cur_helper_mod = Some(kebab_to_namespace(wn.name));
749 s.cur_trait = Some(name.clone());
750 if !s.cur_trait().items.is_empty() {
751 return;
763 }
764
765 let mut needs_vars = BTreeSet::new();
766 let mut sv = s.with_needs_vars(&mut needs_vars);
767
768 let exports = it
769 .exports
770 .iter()
771 .map(|ed| emit_extern_decl(true, &mut sv, ed))
772 .collect::<Vec<_>>();
773
774 let mut stvs = BTreeMap::new();
777 let _ = sv.cur_trait(); let t = sv.cur_trait_immut();
779 for (ti, _) in t.supertraits.iter() {
780 let t = sv.resolve_trait_immut(false, ti);
781 stvs.insert(ti.clone(), t.tv_idxs());
782 }
783 sv.origin.push(ImportExport::Export("self"));
786 let mut stis = BTreeMap::new();
787 for (id, tvs) in stvs.into_iter() {
788 stis.insert(id, emit_tvis(&mut sv, tvs));
789 }
790 for (id, ts) in stis.into_iter() {
791 sv.cur_trait().supertraits.get_mut(&id).unwrap().extend(ts);
792 }
793
794 drop(sv);
795 log::debug!("after exports, ncur_needs_vars is {:?}", needs_vars);
796 for v in needs_vars {
797 let id = s.noff_var_id(v);
798 s.cur_trait().tvs.insert(id, (Some(v), TokenStream::new()));
799 }
800
801 s.cur_trait().items.extend(quote! { #(#exports)* });
802}
803
804fn emit_component<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, ct: &'c Component<'b>) {
810 let mut s = s.with_cursor(wn.namespace_idents());
811
812 let base_name = kebab_to_type(wn.name);
813
814 s.cur_helper_mod = Some(kebab_to_namespace(wn.name));
815
816 let import_name = kebab_to_imports_name(wn.name);
817 *s.bound_vars = ct
818 .uvars
819 .iter()
820 .rev()
821 .map(Clone::clone)
822 .collect::<VecDeque<_>>();
823 s.cur_trait = Some(import_name.clone());
824 let imports = ct
825 .imports
826 .iter()
827 .map(|ed| emit_extern_decl(false, &mut s, ed))
828 .collect::<Vec<TokenStream>>();
829 s.cur_trait().items.extend(quote! { #(#imports)* });
830
831 s.adjust_vars(ct.instance.evars.len() as u32);
832
833 s.import_param_var = Some(format_ident!("I"));
834
835 let export_name = kebab_to_exports_name(wn.name);
836 *s.bound_vars = ct
837 .instance
838 .evars
839 .iter()
840 .rev()
841 .chain(ct.uvars.iter().rev())
842 .map(Clone::clone)
843 .collect::<VecDeque<_>>();
844 s.cur_trait = Some(export_name.clone());
845 let exports = ct
846 .instance
847 .unqualified
848 .exports
849 .iter()
850 .map(|ed| emit_extern_decl(true, &mut s, ed))
851 .collect::<Vec<_>>();
852 s.cur_trait().tvs.insert(
853 format_ident!("I"),
854 (None, quote! { #import_name + ::core::marker::Send }),
855 );
856 s.cur_trait().items.extend(quote! { #(#exports)* });
857
858 s.cur_helper_mod = None;
859 s.cur_trait = None;
860
861 s.cur_mod().items.extend(quote! {
862 pub trait #base_name {
863 type Exports<I: #import_name + ::core::marker::Send>: #export_name<I>;
864 fn instantiate<I: #import_name + ::core::marker::Send + 'static>(self, imports: I) -> Self::Exports<I>;
867 }
868 });
869}
870
871pub fn emit_toplevel<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, n: &str, ct: &'c Component<'b>) {
873 let wn = split_wit_name(n);
874 emit_component(s, wn, ct);
875}