hyperlight_component_util/
util.rs1use crate::etypes;
6
7#[derive(Debug)]
9pub enum WitSource {
10 Wasm(std::path::PathBuf),
11 Wat(std::path::PathBuf),
12 Wit(std::path::PathBuf),
13 Inline(String),
14}
15
16impl WitSource {
17 fn encode(self) -> Vec<u8> {
18 match self {
19 Self::Wasm(path) => {
20 let path = manifest_path(&path);
21 let bytes = std::fs::read(&path).unwrap_or_else(|err| {
22 panic!(
23 "failed to read wasm-encoded WIT input '{}': {err}",
24 path.display()
25 )
26 });
27 if !wasmparser::Parser::is_component(&bytes) {
28 panic!(
29 "wasm-encoded WIT input '{}' is not a wasm component",
30 path.display()
31 );
32 }
33 bytes
34 }
35 Self::Wat(path) => {
36 let path = manifest_path(&path);
37 let bytes = wat::parse_file(&path).unwrap_or_else(|err| {
38 panic!("failed to read wat input '{}': {err:#}", path.display());
39 });
40 if !wasmparser::Parser::is_component(&bytes) {
41 panic!("wat input '{}' is not a wasm component", path.display());
42 }
43 bytes
44 }
45 Self::Wit(path) => {
46 let path = manifest_path(&path);
47 let mut resolve = wit_parser::Resolve::default();
48 let (package, _) = resolve.push_path(&path).unwrap_or_else(|err| {
49 panic!("failed to parse WIT input '{}': {err:#}", path.display())
50 });
51
52 wit_component::encode(&resolve, package).unwrap_or_else(|err| {
53 panic!(
54 "failed to encode WIT input '{}' as a wasm component type: {err:#}",
55 path.display()
56 )
57 })
58 }
59 Self::Inline(contents) => {
60 match wat::Detect::from_bytes(&contents) {
61 wat::Detect::WasmBinary => {
62 panic!("inline component type looks like a binary!")
63 }
64 wat::Detect::WasmText => {
65 let bytes = wat::parse_str(&contents).unwrap_or_else(|err| {
66 panic!("failed to read inline wat input: {err:#}")
67 });
68 if !wasmparser::Parser::is_component(&bytes) {
69 panic!("inline wat input is not a wasm component");
70 }
71 bytes
72 }
73 wat::Detect::Unknown => {
74 let mut resolve = wit_parser::Resolve::default();
76 let package =
77 resolve
78 .push_str("inline.wit", &contents)
79 .unwrap_or_else(|err| {
80 panic!("failed to parse inline WIT input: {err:#}")
81 });
82 wit_component::encode(&resolve, package).unwrap_or_else(|err| {
83 panic!("failed to encode inline WIT input as a wasm component type: {err:#}")
84 })
85 }
86 }
87 }
88 }
89 }
90}
91
92fn manifest_path(path: &std::path::Path) -> std::path::PathBuf {
93 let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
94 std::path::Path::new(&manifest_dir).join(path)
95}
96
97pub fn read_wit_type<R, F: FnMut(String, &etypes::Component) -> R>(
99 source: WitSource,
100 world_name: Option<String>,
101 mut cb: F,
102) -> R {
103 let bytes = source.encode();
104 let i = wasmparser::Parser::new(0).parse_all(&bytes);
105 let ct = crate::component::read_component_single_exported_type(i, world_name);
106
107 if !ct.uvars.is_empty()
110 || !ct.imports.is_empty()
111 || !ct.instance.evars.is_empty()
112 || ct.instance.unqualified.exports.len() != 1
113 {
114 panic!("malformed component type container for wit type");
115 };
116 let export = &ct.instance.unqualified.exports[0];
117 use etypes::ExternDesc;
118 let ExternDesc::Component(ct) = &export.desc else {
119 panic!("malformed component type container: does not contain component type");
120 };
121 tracing::debug!("hcm: considering component type {:?}", ct);
122 cb(export.kebab_name.to_string(), ct)
123}
124
125pub fn read_wit_type_from_file<R, F: FnMut(String, &etypes::Component) -> R>(
128 filename: impl AsRef<std::ffi::OsStr>,
129 world_name: Option<String>,
130 cb: F,
131) -> R {
132 let src = WitSource::Wasm(std::path::PathBuf::from(filename.as_ref()));
133 read_wit_type(src, world_name, cb)
134}
135
136pub fn emit_decls(decls: proc_macro2::TokenStream, for_kebab: &str) -> proc_macro2::TokenStream {
140 if let Ok(dbg_out) = std::env::var("HYPERLIGHT_COMPONENT_MACRO_DEBUG") {
141 let fs_safe = for_kebab.replace("/", "_");
142 #[cfg(windows)]
143 let fs_safe = fs_safe.replace(":", "+");
144 let dbg_out = dbg_out.replace("#", &fs_safe);
145 if let Ok(file) = syn::parse2(decls.clone()) {
146 std::fs::write(&dbg_out, prettyplease::unparse(&file)).unwrap();
147 } else {
148 let decls = format!("{}", &decls);
149 std::fs::write(&dbg_out, &decls).unwrap();
150 }
151 quote::quote! { include!(#dbg_out); }
152 } else {
153 decls
154 }
155}