1use std::collections::BTreeSet;
2#[cfg(not(feature = "js"))]
3use wasmer::vm::VMSharedMemory;
4use wasmer::{AsStoreMut, Imports, Memory, Module};
5use wasmer_wasi_types::wasi::Errno;
6
7#[allow(dead_code)]
8pub fn is_wasi_module(module: &Module) -> bool {
11 get_wasi_version(module, false).is_some()
12}
13
14#[allow(dead_code)]
15#[cfg(feature = "wasix")]
16pub fn is_wasix_module(module: &Module) -> bool {
18 match get_wasi_versions(module, false).ok_or(false) {
19 Ok(wasi_versions) => {
20 wasi_versions.contains(&WasiVersion::Wasix32v1)
21 || wasi_versions.contains(&WasiVersion::Wasix64v1)
22 }
23 Err(_) => false,
24 }
25}
26
27pub fn map_io_err(err: std::io::Error) -> Errno {
28 use std::io::ErrorKind;
29 match err.kind() {
30 ErrorKind::NotFound => Errno::Noent,
31 ErrorKind::PermissionDenied => Errno::Perm,
32 ErrorKind::ConnectionRefused => Errno::Connrefused,
33 ErrorKind::ConnectionReset => Errno::Connreset,
34 ErrorKind::ConnectionAborted => Errno::Connaborted,
35 ErrorKind::NotConnected => Errno::Notconn,
36 ErrorKind::AddrInUse => Errno::Addrinuse,
37 ErrorKind::AddrNotAvailable => Errno::Addrnotavail,
38 ErrorKind::BrokenPipe => Errno::Pipe,
39 ErrorKind::AlreadyExists => Errno::Exist,
40 ErrorKind::WouldBlock => Errno::Again,
41 ErrorKind::InvalidInput => Errno::Io,
42 ErrorKind::InvalidData => Errno::Io,
43 ErrorKind::TimedOut => Errno::Timedout,
44 ErrorKind::WriteZero => Errno::Io,
45 ErrorKind::Interrupted => Errno::Intr,
46 ErrorKind::Other => Errno::Io,
47 ErrorKind::UnexpectedEof => Errno::Io,
48 ErrorKind::Unsupported => Errno::Notsup,
49 _ => Errno::Io,
50 }
51}
52
53#[cfg(not(feature = "js"))]
56pub fn wasi_import_shared_memory(
57 imports: &mut Imports,
58 module: &Module,
59 store: &mut impl AsStoreMut,
60) {
61 let shared_memory = module
63 .imports()
64 .memories()
65 .next()
66 .map(|a| *a.ty())
67 .map(|ty| {
68 let style = store.as_store_ref().tunables().memory_style(&ty);
69 VMSharedMemory::new(&ty, &style).unwrap()
70 });
71
72 if let Some(memory) = shared_memory {
73 if !imports.exists("env", "memory") {
75 imports.define(
76 "env",
77 "memory",
78 Memory::new_from_existing(store, memory.into()),
79 );
80 }
81 };
82}
83#[cfg(feature = "js")]
84pub fn wasi_import_shared_memory(
85 _imports: &mut Imports,
86 _module: &Module,
87 _store: &mut impl AsStoreMut,
88) {
89}
90
91#[derive(Debug, Clone, Copy, Eq)]
94pub enum WasiVersion {
95 Snapshot0,
97
98 Snapshot1,
100
101 Wasix32v1,
103
104 Wasix64v1,
106
107 Latest,
118}
119
120impl WasiVersion {
121 pub const fn get_namespace_str(&self) -> &'static str {
123 match *self {
124 WasiVersion::Snapshot0 => SNAPSHOT0_NAMESPACE,
125 WasiVersion::Snapshot1 => SNAPSHOT1_NAMESPACE,
126 WasiVersion::Wasix32v1 => WASIX_32V1_NAMESPACE,
127 WasiVersion::Wasix64v1 => WASIX_64V1_NAMESPACE,
128 WasiVersion::Latest => SNAPSHOT1_NAMESPACE,
129 }
130 }
131}
132
133impl PartialEq<WasiVersion> for WasiVersion {
134 fn eq(&self, other: &Self) -> bool {
135 matches!(
136 (*self, *other),
137 (Self::Snapshot1, Self::Latest)
138 | (Self::Latest, Self::Snapshot1)
139 | (Self::Latest, Self::Latest)
140 | (Self::Snapshot0, Self::Snapshot0)
141 | (Self::Snapshot1, Self::Snapshot1)
142 | (Self::Wasix32v1, Self::Wasix32v1)
143 | (Self::Wasix64v1, Self::Wasix64v1)
144 )
145 }
146}
147
148impl PartialOrd for WasiVersion {
149 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
150 Some(self.cmp(other))
151 }
152}
153
154impl Ord for WasiVersion {
155 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
156 if self == other {
157 return std::cmp::Ordering::Equal;
158 }
159 match (*self, *other) {
160 (Self::Snapshot1, Self::Snapshot0) => std::cmp::Ordering::Greater,
161 (Self::Wasix32v1, Self::Snapshot1) | (Self::Wasix32v1, Self::Snapshot0) => {
162 std::cmp::Ordering::Greater
163 }
164 (Self::Wasix64v1, Self::Wasix32v1)
165 | (Self::Wasix64v1, Self::Snapshot1)
166 | (Self::Wasix64v1, Self::Snapshot0) => std::cmp::Ordering::Greater,
167 (Self::Latest, Self::Wasix64v1)
168 | (Self::Latest, Self::Wasix32v1)
169 | (Self::Latest, Self::Snapshot1)
170 | (Self::Latest, Self::Snapshot0) => std::cmp::Ordering::Greater,
171 (_, _) => std::cmp::Ordering::Less,
173 }
174 }
175}
176
177const SNAPSHOT0_NAMESPACE: &str = "wasi_unstable";
179
180const SNAPSHOT1_NAMESPACE: &str = "wasi_snapshot_preview1";
182
183const WASIX_32V1_NAMESPACE: &str = "wasix_32v1";
185
186const WASIX_64V1_NAMESPACE: &str = "wasix_64v1";
188
189pub fn get_wasi_version(module: &Module, strict: bool) -> Option<WasiVersion> {
197 let mut imports = module.imports().functions().map(|f| f.module().to_owned());
198
199 if strict {
200 let first_module = imports.next()?;
201 if imports.all(|module| module == first_module) {
202 match first_module.as_str() {
203 SNAPSHOT0_NAMESPACE => Some(WasiVersion::Snapshot0),
204 SNAPSHOT1_NAMESPACE => Some(WasiVersion::Snapshot1),
205 WASIX_32V1_NAMESPACE => Some(WasiVersion::Wasix32v1),
206 WASIX_64V1_NAMESPACE => Some(WasiVersion::Wasix64v1),
207 _ => None,
208 }
209 } else {
210 None
211 }
212 } else {
213 imports.find_map(|module| match module.as_str() {
216 SNAPSHOT0_NAMESPACE => Some(WasiVersion::Snapshot0),
217 SNAPSHOT1_NAMESPACE => Some(WasiVersion::Snapshot1),
218 WASIX_32V1_NAMESPACE => Some(WasiVersion::Wasix32v1),
219 WASIX_64V1_NAMESPACE => Some(WasiVersion::Wasix64v1),
220 _ => None,
221 })
222 }
223}
224
225pub fn get_wasi_versions(module: &Module, strict: bool) -> Option<BTreeSet<WasiVersion>> {
230 let mut out = BTreeSet::new();
231 let imports = module.imports().functions().map(|f| f.module().to_owned());
232
233 let mut non_wasi_seen = false;
234 for ns in imports {
235 match ns.as_str() {
236 SNAPSHOT0_NAMESPACE => {
237 out.insert(WasiVersion::Snapshot0);
238 }
239 SNAPSHOT1_NAMESPACE => {
240 out.insert(WasiVersion::Snapshot1);
241 }
242 WASIX_32V1_NAMESPACE => {
243 out.insert(WasiVersion::Wasix32v1);
244 }
245 WASIX_64V1_NAMESPACE => {
246 out.insert(WasiVersion::Wasix64v1);
247 }
248 _ => {
249 non_wasi_seen = true;
250 }
251 }
252 }
253 if strict && non_wasi_seen {
254 None
255 } else {
256 Some(out)
257 }
258}
259
260#[cfg(test)]
261mod test {
262 use super::*;
263
264 #[test]
265 fn wasi_version_equality() {
266 assert_eq!(WasiVersion::Snapshot0, WasiVersion::Snapshot0);
267 assert_eq!(WasiVersion::Wasix64v1, WasiVersion::Wasix64v1);
268 assert_eq!(WasiVersion::Wasix32v1, WasiVersion::Wasix32v1);
269 assert_eq!(WasiVersion::Snapshot1, WasiVersion::Snapshot1);
270 assert_eq!(WasiVersion::Snapshot1, WasiVersion::Latest);
271 assert_eq!(WasiVersion::Latest, WasiVersion::Snapshot1);
272 assert_eq!(WasiVersion::Latest, WasiVersion::Latest);
273 assert!(WasiVersion::Wasix32v1 != WasiVersion::Wasix64v1);
274 assert!(WasiVersion::Wasix64v1 != WasiVersion::Wasix32v1);
275 assert!(WasiVersion::Snapshot1 != WasiVersion::Wasix64v1);
276 assert!(WasiVersion::Wasix64v1 != WasiVersion::Snapshot1);
277 assert!(WasiVersion::Snapshot1 != WasiVersion::Wasix32v1);
278 assert!(WasiVersion::Wasix32v1 != WasiVersion::Snapshot1);
279 assert!(WasiVersion::Snapshot0 != WasiVersion::Snapshot1);
280 assert!(WasiVersion::Snapshot1 != WasiVersion::Snapshot0);
281 assert!(WasiVersion::Snapshot0 != WasiVersion::Latest);
282 assert!(WasiVersion::Latest != WasiVersion::Snapshot0);
283 assert!(WasiVersion::Snapshot0 != WasiVersion::Latest);
284 assert!(WasiVersion::Latest != WasiVersion::Snapshot0);
285 assert!(WasiVersion::Wasix32v1 != WasiVersion::Latest);
286 assert!(WasiVersion::Wasix64v1 != WasiVersion::Latest);
287 }
288
289 #[test]
290 fn wasi_version_ordering() {
291 assert!(WasiVersion::Snapshot0 <= WasiVersion::Snapshot0);
292 assert!(WasiVersion::Snapshot1 <= WasiVersion::Snapshot1);
293 assert!(WasiVersion::Wasix32v1 <= WasiVersion::Wasix32v1);
294 assert!(WasiVersion::Wasix64v1 <= WasiVersion::Wasix64v1);
295 assert!(WasiVersion::Latest <= WasiVersion::Latest);
296 assert!(WasiVersion::Snapshot0 >= WasiVersion::Snapshot0);
297 assert!(WasiVersion::Snapshot1 >= WasiVersion::Snapshot1);
298 assert!(WasiVersion::Wasix32v1 >= WasiVersion::Wasix32v1);
299 assert!(WasiVersion::Wasix64v1 >= WasiVersion::Wasix64v1);
300 assert!(WasiVersion::Latest >= WasiVersion::Latest);
301
302 assert!(WasiVersion::Snapshot0 < WasiVersion::Latest);
303 assert!(WasiVersion::Snapshot0 < WasiVersion::Wasix32v1);
304 assert!(WasiVersion::Snapshot0 < WasiVersion::Wasix64v1);
305 assert!(WasiVersion::Snapshot0 < WasiVersion::Snapshot1);
306 assert!(WasiVersion::Latest > WasiVersion::Snapshot0);
307 assert!(WasiVersion::Wasix32v1 > WasiVersion::Snapshot0);
308 assert!(WasiVersion::Wasix64v1 > WasiVersion::Snapshot0);
309 assert!(WasiVersion::Snapshot1 > WasiVersion::Snapshot0);
310
311 assert!(WasiVersion::Snapshot1 < WasiVersion::Wasix32v1);
312 assert!(WasiVersion::Snapshot1 < WasiVersion::Wasix64v1);
313 assert!(WasiVersion::Wasix32v1 > WasiVersion::Snapshot1);
314 assert!(WasiVersion::Wasix64v1 > WasiVersion::Snapshot1);
315
316 assert!(WasiVersion::Wasix32v1 < WasiVersion::Latest);
317 assert!(WasiVersion::Wasix32v1 > WasiVersion::Snapshot1);
318 assert!(WasiVersion::Wasix64v1 < WasiVersion::Latest);
319 assert!(WasiVersion::Wasix64v1 > WasiVersion::Snapshot1);
320 assert!(WasiVersion::Latest > WasiVersion::Wasix32v1);
321 assert!(WasiVersion::Snapshot1 < WasiVersion::Wasix32v1);
322 assert!(WasiVersion::Latest > WasiVersion::Wasix64v1);
323 assert!(WasiVersion::Snapshot1 < WasiVersion::Wasix32v1);
324
325 assert!(WasiVersion::Wasix32v1 < WasiVersion::Wasix64v1);
326 assert!(WasiVersion::Wasix64v1 > WasiVersion::Wasix32v1);
327 }
328}