hyperlight_component_util/resource.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
17use proc_macro2::{Ident, TokenStream};
18use quote::{format_ident, quote};
19
20use crate::emit::State;
21use crate::etypes::{TypeBound, Tyvar};
22use crate::rtypes::emit_var_ref;
23
24/// Emit a structure definition for a resource table that keeps track
25/// of resources lent/borrowed/given/taken to/from the other side of
26/// the Hyperlight boundary.
27/// - `rtsid`: The name of the struct to create
28/// - `bound`: a bound to be used for a phantom type variable that
29/// records the fact that these resource tables are only valid for a
30/// component that has been instantiated with a particular
31/// implementation of its imports
32/// - `sv`: optionally a bound to be used for a phantom type variable
33/// that records the fact that these resource tables are only valid
34/// for a particular implementation of a component
35pub fn emit_tables<'a, 'b, 'c>(
36 s: &'c mut State<'a, 'b>,
37 rtsid: Ident,
38 bound: TokenStream,
39 sv: Option<TokenStream>,
40 is_guest: bool,
41) {
42 let vs = s.bound_vars.clone();
43 let (fields, inits) = vs
44 .iter()
45 .enumerate()
46 .map(|(i, v)| {
47 let field_name = format_ident!("resource{}", i);
48 let alloc_ns = if s.is_guest {
49 quote! { ::alloc }
50 } else {
51 quote! { ::std }
52 };
53 match v.bound {
54 TypeBound::Eq(_) => (quote! { #field_name: () }, quote! { #field_name: () }),
55 TypeBound::SubResource => {
56 if v.origin.is_imported() ^ is_guest {
57 let t = emit_var_ref(s, &Tyvar::Bound(i as u32));
58 (
59 quote! {
60 #field_name: #alloc_ns::collections::VecDeque<
61 ::hyperlight_common::resource::ResourceEntry<#t>
62 >
63 },
64 quote! { #field_name: #alloc_ns::collections::VecDeque::new() },
65 )
66 } else {
67 // we don't need to keep track of anything for
68 // resources owned by the other side
69 (
70 quote! {
71 #field_name: ()
72 },
73 quote! { #field_name: () },
74 )
75 }
76 }
77 }
78 })
79 .unzip::<_, _, Vec<_>, Vec<_>>();
80 let (sv, svs, sphantom, sphantominit) = if let Some(sv) = sv {
81 (
82 quote! { , S: #sv },
83 quote! { , S },
84 quote! { _phantomS: ::core::marker::PhantomData<S>, },
85 quote! { _phantomS: ::core::marker::PhantomData, },
86 )
87 } else {
88 (
89 TokenStream::new(),
90 TokenStream::new(),
91 TokenStream::new(),
92 TokenStream::new(),
93 )
94 };
95 s.root_mod.items.extend(quote! {
96 pub(crate) struct #rtsid<I: #bound #sv> {
97 #(#fields,)*
98 _phantomI: ::core::marker::PhantomData<I>,
99 #sphantom
100 }
101 impl<I: #bound #sv> #rtsid<I #svs> {
102 fn new() -> Self {
103 #rtsid {
104 #(#inits,)*
105 _phantomI: ::core::marker::PhantomData,
106 #sphantominit
107 }
108 }
109 }
110 });
111}