wasmtime_wasi/
preview0.rs

1//! Bindings for WASIp0 aka Preview 0 aka `wasi_unstable`.
2//!
3//! This module is purely here for backwards compatibility in the Wasmtime CLI.
4//! You probably want to use [`preview1`](crate::preview1) instead.
5
6use crate::preview0::types::Error;
7use crate::preview1::types as snapshot1_types;
8use crate::preview1::wasi_snapshot_preview1::WasiSnapshotPreview1 as Snapshot1;
9use crate::preview1::WasiP1Ctx;
10use wiggle::{GuestError, GuestMemory, GuestPtr};
11
12pub fn add_to_linker_async<T: Send>(
13    linker: &mut wasmtime::Linker<T>,
14    f: impl Fn(&mut T) -> &mut WasiP1Ctx + Copy + Send + Sync + 'static,
15) -> anyhow::Result<()> {
16    wasi_unstable::add_to_linker(linker, f)
17}
18
19pub fn add_to_linker_sync<T: Send>(
20    linker: &mut wasmtime::Linker<T>,
21    f: impl Fn(&mut T) -> &mut WasiP1Ctx + Copy + Send + Sync + 'static,
22) -> anyhow::Result<()> {
23    sync::add_wasi_unstable_to_linker(linker, f)
24}
25
26wiggle::from_witx!({
27    witx: ["$CARGO_MANIFEST_DIR/witx/preview0/wasi_unstable.witx"],
28    async: {
29        wasi_unstable::{
30            fd_advise, fd_close, fd_datasync, fd_fdstat_get, fd_filestat_get, fd_filestat_set_size,
31            fd_filestat_set_times, fd_read, fd_pread, fd_seek, fd_sync, fd_readdir, fd_write,
32            fd_pwrite, poll_oneoff, path_create_directory, path_filestat_get,
33            path_filestat_set_times, path_link, path_open, path_readlink, path_remove_directory,
34            path_rename, path_symlink, path_unlink_file
35        }
36    },
37    errors: { errno => trappable Error },
38});
39
40mod sync {
41    use anyhow::Result;
42    use std::future::Future;
43
44    wiggle::wasmtime_integration!({
45        witx: ["$CARGO_MANIFEST_DIR/witx/preview0/wasi_unstable.witx"],
46        target: super,
47        block_on[in_tokio]: {
48            wasi_unstable::{
49                fd_advise, fd_close, fd_datasync, fd_fdstat_get, fd_filestat_get, fd_filestat_set_size,
50                fd_filestat_set_times, fd_read, fd_pread, fd_seek, fd_sync, fd_readdir, fd_write,
51                fd_pwrite, poll_oneoff, path_create_directory, path_filestat_get,
52                path_filestat_set_times, path_link, path_open, path_readlink, path_remove_directory,
53                path_rename, path_symlink, path_unlink_file
54            }
55        },
56        errors: { errno => trappable Error },
57    });
58
59    // Small wrapper around `in_tokio` to add a `Result` layer which is always
60    // `Ok`
61    fn in_tokio<F: Future>(future: F) -> Result<F::Output> {
62        Ok(crate::runtime::in_tokio(future))
63    }
64}
65
66impl wiggle::GuestErrorType for types::Errno {
67    fn success() -> Self {
68        Self::Success
69    }
70}
71
72#[wiggle::async_trait]
73impl<T: Snapshot1 + Send> wasi_unstable::WasiUnstable for T {
74    fn args_get(
75        &mut self,
76        memory: &mut GuestMemory<'_>,
77        argv: GuestPtr<GuestPtr<u8>>,
78        argv_buf: GuestPtr<u8>,
79    ) -> Result<(), Error> {
80        Snapshot1::args_get(self, memory, argv, argv_buf)?;
81        Ok(())
82    }
83
84    fn args_sizes_get(
85        &mut self,
86        memory: &mut GuestMemory<'_>,
87    ) -> Result<(types::Size, types::Size), Error> {
88        let s = Snapshot1::args_sizes_get(self, memory)?;
89        Ok(s)
90    }
91
92    fn environ_get(
93        &mut self,
94        memory: &mut GuestMemory<'_>,
95        environ: GuestPtr<GuestPtr<u8>>,
96        environ_buf: GuestPtr<u8>,
97    ) -> Result<(), Error> {
98        Snapshot1::environ_get(self, memory, environ, environ_buf)?;
99        Ok(())
100    }
101
102    fn environ_sizes_get(
103        &mut self,
104        memory: &mut GuestMemory<'_>,
105    ) -> Result<(types::Size, types::Size), Error> {
106        let s = Snapshot1::environ_sizes_get(self, memory)?;
107        Ok(s)
108    }
109
110    fn clock_res_get(
111        &mut self,
112        memory: &mut GuestMemory<'_>,
113        id: types::Clockid,
114    ) -> Result<types::Timestamp, Error> {
115        let t = Snapshot1::clock_res_get(self, memory, id.into())?;
116        Ok(t)
117    }
118
119    fn clock_time_get(
120        &mut self,
121        memory: &mut GuestMemory<'_>,
122        id: types::Clockid,
123        precision: types::Timestamp,
124    ) -> Result<types::Timestamp, Error> {
125        let t = Snapshot1::clock_time_get(self, memory, id.into(), precision)?;
126        Ok(t)
127    }
128
129    async fn fd_advise(
130        &mut self,
131        memory: &mut GuestMemory<'_>,
132        fd: types::Fd,
133        offset: types::Filesize,
134        len: types::Filesize,
135        advice: types::Advice,
136    ) -> Result<(), Error> {
137        Snapshot1::fd_advise(self, memory, fd.into(), offset, len, advice.into()).await?;
138        Ok(())
139    }
140
141    fn fd_allocate(
142        &mut self,
143        memory: &mut GuestMemory<'_>,
144        fd: types::Fd,
145        offset: types::Filesize,
146        len: types::Filesize,
147    ) -> Result<(), Error> {
148        Snapshot1::fd_allocate(self, memory, fd.into(), offset, len)?;
149        Ok(())
150    }
151
152    async fn fd_close(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {
153        Snapshot1::fd_close(self, memory, fd.into()).await?;
154        Ok(())
155    }
156
157    async fn fd_datasync(
158        &mut self,
159        memory: &mut GuestMemory<'_>,
160        fd: types::Fd,
161    ) -> Result<(), Error> {
162        Snapshot1::fd_datasync(self, memory, fd.into()).await?;
163        Ok(())
164    }
165
166    async fn fd_fdstat_get(
167        &mut self,
168        memory: &mut GuestMemory<'_>,
169        fd: types::Fd,
170    ) -> Result<types::Fdstat, Error> {
171        Ok(Snapshot1::fd_fdstat_get(self, memory, fd.into())
172            .await?
173            .into())
174    }
175
176    fn fd_fdstat_set_flags(
177        &mut self,
178        memory: &mut GuestMemory<'_>,
179        fd: types::Fd,
180        flags: types::Fdflags,
181    ) -> Result<(), Error> {
182        Snapshot1::fd_fdstat_set_flags(self, memory, fd.into(), flags.into())?;
183        Ok(())
184    }
185
186    fn fd_fdstat_set_rights(
187        &mut self,
188        memory: &mut GuestMemory<'_>,
189        fd: types::Fd,
190        fs_rights_base: types::Rights,
191        fs_rights_inheriting: types::Rights,
192    ) -> Result<(), Error> {
193        Snapshot1::fd_fdstat_set_rights(
194            self,
195            memory,
196            fd.into(),
197            fs_rights_base.into(),
198            fs_rights_inheriting.into(),
199        )?;
200        Ok(())
201    }
202
203    async fn fd_filestat_get(
204        &mut self,
205        memory: &mut GuestMemory<'_>,
206        fd: types::Fd,
207    ) -> Result<types::Filestat, Error> {
208        Ok(Snapshot1::fd_filestat_get(self, memory, fd.into())
209            .await?
210            .into())
211    }
212
213    async fn fd_filestat_set_size(
214        &mut self,
215        memory: &mut GuestMemory<'_>,
216        fd: types::Fd,
217        size: types::Filesize,
218    ) -> Result<(), Error> {
219        Snapshot1::fd_filestat_set_size(self, memory, fd.into(), size).await?;
220        Ok(())
221    }
222
223    async fn fd_filestat_set_times(
224        &mut self,
225        memory: &mut GuestMemory<'_>,
226        fd: types::Fd,
227        atim: types::Timestamp,
228        mtim: types::Timestamp,
229        fst_flags: types::Fstflags,
230    ) -> Result<(), Error> {
231        Snapshot1::fd_filestat_set_times(self, memory, fd.into(), atim, mtim, fst_flags.into())
232            .await?;
233        Ok(())
234    }
235
236    async fn fd_read(
237        &mut self,
238        memory: &mut GuestMemory<'_>,
239        fd: types::Fd,
240        iovs: types::IovecArray,
241    ) -> Result<types::Size, Error> {
242        assert_iovec_array_same();
243        let result = Snapshot1::fd_read(self, memory, fd.into(), iovs.cast()).await?;
244        Ok(result)
245    }
246
247    async fn fd_pread(
248        &mut self,
249        memory: &mut GuestMemory<'_>,
250        fd: types::Fd,
251        iovs: types::IovecArray,
252        offset: types::Filesize,
253    ) -> Result<types::Size, Error> {
254        assert_iovec_array_same();
255        let result = Snapshot1::fd_pread(self, memory, fd.into(), iovs.cast(), offset).await?;
256        Ok(result)
257    }
258
259    async fn fd_write(
260        &mut self,
261        memory: &mut GuestMemory<'_>,
262        fd: types::Fd,
263        ciovs: types::CiovecArray,
264    ) -> Result<types::Size, Error> {
265        assert_ciovec_array_same();
266        let result = Snapshot1::fd_write(self, memory, fd.into(), ciovs.cast()).await?;
267        Ok(result)
268    }
269
270    async fn fd_pwrite(
271        &mut self,
272        memory: &mut GuestMemory<'_>,
273        fd: types::Fd,
274        ciovs: types::CiovecArray,
275        offset: types::Filesize,
276    ) -> Result<types::Size, Error> {
277        assert_ciovec_array_same();
278        let result = Snapshot1::fd_pwrite(self, memory, fd.into(), ciovs.cast(), offset).await?;
279        Ok(result)
280    }
281
282    fn fd_prestat_get(
283        &mut self,
284        memory: &mut GuestMemory<'_>,
285        fd: types::Fd,
286    ) -> Result<types::Prestat, Error> {
287        Ok(Snapshot1::fd_prestat_get(self, memory, fd.into())?.into())
288    }
289
290    fn fd_prestat_dir_name(
291        &mut self,
292        memory: &mut GuestMemory<'_>,
293        fd: types::Fd,
294        path: GuestPtr<u8>,
295        path_max_len: types::Size,
296    ) -> Result<(), Error> {
297        Snapshot1::fd_prestat_dir_name(self, memory, fd.into(), path, path_max_len)?;
298        Ok(())
299    }
300
301    fn fd_renumber(
302        &mut self,
303        memory: &mut GuestMemory<'_>,
304        from: types::Fd,
305        to: types::Fd,
306    ) -> Result<(), Error> {
307        Snapshot1::fd_renumber(self, memory, from.into(), to.into())?;
308        Ok(())
309    }
310
311    async fn fd_seek(
312        &mut self,
313        memory: &mut GuestMemory<'_>,
314        fd: types::Fd,
315        offset: types::Filedelta,
316        whence: types::Whence,
317    ) -> Result<types::Filesize, Error> {
318        Ok(Snapshot1::fd_seek(self, memory, fd.into(), offset, whence.into()).await?)
319    }
320
321    async fn fd_sync(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {
322        Snapshot1::fd_sync(self, memory, fd.into()).await?;
323        Ok(())
324    }
325
326    fn fd_tell(
327        &mut self,
328        memory: &mut GuestMemory<'_>,
329        fd: types::Fd,
330    ) -> Result<types::Filesize, Error> {
331        Ok(Snapshot1::fd_tell(self, memory, fd.into())?)
332    }
333
334    async fn fd_readdir(
335        &mut self,
336        memory: &mut GuestMemory<'_>,
337        fd: types::Fd,
338        buf: GuestPtr<u8>,
339        buf_len: types::Size,
340        cookie: types::Dircookie,
341    ) -> Result<types::Size, Error> {
342        Ok(Snapshot1::fd_readdir(self, memory, fd.into(), buf, buf_len, cookie).await?)
343    }
344
345    async fn path_create_directory(
346        &mut self,
347        memory: &mut GuestMemory<'_>,
348        dirfd: types::Fd,
349        path: GuestPtr<str>,
350    ) -> Result<(), Error> {
351        Snapshot1::path_create_directory(self, memory, dirfd.into(), path).await?;
352        Ok(())
353    }
354
355    async fn path_filestat_get(
356        &mut self,
357        memory: &mut GuestMemory<'_>,
358        dirfd: types::Fd,
359        flags: types::Lookupflags,
360        path: GuestPtr<str>,
361    ) -> Result<types::Filestat, Error> {
362        Ok(
363            Snapshot1::path_filestat_get(self, memory, dirfd.into(), flags.into(), path)
364                .await?
365                .into(),
366        )
367    }
368
369    async fn path_filestat_set_times(
370        &mut self,
371        memory: &mut GuestMemory<'_>,
372        dirfd: types::Fd,
373        flags: types::Lookupflags,
374        path: GuestPtr<str>,
375        atim: types::Timestamp,
376        mtim: types::Timestamp,
377        fst_flags: types::Fstflags,
378    ) -> Result<(), Error> {
379        Snapshot1::path_filestat_set_times(
380            self,
381            memory,
382            dirfd.into(),
383            flags.into(),
384            path,
385            atim,
386            mtim,
387            fst_flags.into(),
388        )
389        .await?;
390        Ok(())
391    }
392
393    async fn path_link(
394        &mut self,
395        memory: &mut GuestMemory<'_>,
396        src_fd: types::Fd,
397        src_flags: types::Lookupflags,
398        src_path: GuestPtr<str>,
399        target_fd: types::Fd,
400        target_path: GuestPtr<str>,
401    ) -> Result<(), Error> {
402        Snapshot1::path_link(
403            self,
404            memory,
405            src_fd.into(),
406            src_flags.into(),
407            src_path,
408            target_fd.into(),
409            target_path,
410        )
411        .await?;
412        Ok(())
413    }
414
415    async fn path_open(
416        &mut self,
417        memory: &mut GuestMemory<'_>,
418        dirfd: types::Fd,
419        dirflags: types::Lookupflags,
420        path: GuestPtr<str>,
421        oflags: types::Oflags,
422        fs_rights_base: types::Rights,
423        fs_rights_inheriting: types::Rights,
424        fdflags: types::Fdflags,
425    ) -> Result<types::Fd, Error> {
426        Ok(Snapshot1::path_open(
427            self,
428            memory,
429            dirfd.into(),
430            dirflags.into(),
431            path,
432            oflags.into(),
433            fs_rights_base.into(),
434            fs_rights_inheriting.into(),
435            fdflags.into(),
436        )
437        .await?
438        .into())
439    }
440
441    async fn path_readlink(
442        &mut self,
443        memory: &mut GuestMemory<'_>,
444        dirfd: types::Fd,
445        path: GuestPtr<str>,
446        buf: GuestPtr<u8>,
447        buf_len: types::Size,
448    ) -> Result<types::Size, Error> {
449        Ok(Snapshot1::path_readlink(self, memory, dirfd.into(), path, buf, buf_len).await?)
450    }
451
452    async fn path_remove_directory(
453        &mut self,
454        memory: &mut GuestMemory<'_>,
455        dirfd: types::Fd,
456        path: GuestPtr<str>,
457    ) -> Result<(), Error> {
458        Snapshot1::path_remove_directory(self, memory, dirfd.into(), path).await?;
459        Ok(())
460    }
461
462    async fn path_rename(
463        &mut self,
464        memory: &mut GuestMemory<'_>,
465        src_fd: types::Fd,
466        src_path: GuestPtr<str>,
467        dest_fd: types::Fd,
468        dest_path: GuestPtr<str>,
469    ) -> Result<(), Error> {
470        Snapshot1::path_rename(
471            self,
472            memory,
473            src_fd.into(),
474            src_path,
475            dest_fd.into(),
476            dest_path,
477        )
478        .await?;
479        Ok(())
480    }
481
482    async fn path_symlink(
483        &mut self,
484        memory: &mut GuestMemory<'_>,
485        src_path: GuestPtr<str>,
486        dirfd: types::Fd,
487        dest_path: GuestPtr<str>,
488    ) -> Result<(), Error> {
489        Snapshot1::path_symlink(self, memory, src_path, dirfd.into(), dest_path).await?;
490        Ok(())
491    }
492
493    async fn path_unlink_file(
494        &mut self,
495        memory: &mut GuestMemory<'_>,
496        dirfd: types::Fd,
497        path: GuestPtr<str>,
498    ) -> Result<(), Error> {
499        Snapshot1::path_unlink_file(self, memory, dirfd.into(), path).await?;
500        Ok(())
501    }
502
503    // The representation of `SubscriptionClock` is different in preview0 and
504    // preview1 so a bit of a hack is employed here. The change was to remove a
505    // field from `SubscriptionClock` so to implement this without copying too
506    // much the `subs` field is overwritten with preview1-compatible structures
507    // and then the preview1 implementation is used. Before returning though
508    // the old values are restored to pretend like we didn't overwrite them.
509    //
510    // Surely no one would pass overlapping pointers to this API right?
511    async fn poll_oneoff(
512        &mut self,
513        memory: &mut GuestMemory<'_>,
514        subs: GuestPtr<types::Subscription>,
515        events: GuestPtr<types::Event>,
516        nsubscriptions: types::Size,
517    ) -> Result<types::Size, Error> {
518        let subs_array = subs.as_array(nsubscriptions);
519        let mut old_subs = Vec::new();
520        for slot in subs_array.iter() {
521            let slot = slot?;
522            let sub = memory.read(slot)?;
523            old_subs.push(sub.clone());
524            memory.write(
525                slot.cast(),
526                snapshot1_types::Subscription {
527                    userdata: sub.userdata,
528                    u: match sub.u {
529                        types::SubscriptionU::Clock(c) => {
530                            snapshot1_types::SubscriptionU::Clock(c.into())
531                        }
532                        types::SubscriptionU::FdRead(c) => {
533                            snapshot1_types::SubscriptionU::FdRead(c.into())
534                        }
535                        types::SubscriptionU::FdWrite(c) => {
536                            snapshot1_types::SubscriptionU::FdWrite(c.into())
537                        }
538                    },
539                },
540            )?;
541        }
542        let ret = Snapshot1::poll_oneoff(self, memory, subs.cast(), events.cast(), nsubscriptions)
543            .await?;
544        for (sub, slot) in old_subs.into_iter().zip(subs_array.iter()) {
545            memory.write(slot?, sub)?;
546        }
547        Ok(ret)
548    }
549
550    fn proc_exit(
551        &mut self,
552        memory: &mut GuestMemory<'_>,
553        status: types::Exitcode,
554    ) -> anyhow::Error {
555        Snapshot1::proc_exit(self, memory, status)
556    }
557
558    fn proc_raise(
559        &mut self,
560        memory: &mut GuestMemory<'_>,
561        sig: types::Signal,
562    ) -> Result<(), Error> {
563        Snapshot1::proc_raise(self, memory, sig.into())?;
564        Ok(())
565    }
566
567    fn sched_yield(&mut self, memory: &mut GuestMemory<'_>) -> Result<(), Error> {
568        Snapshot1::sched_yield(self, memory)?;
569        Ok(())
570    }
571
572    fn random_get(
573        &mut self,
574        memory: &mut GuestMemory<'_>,
575        buf: GuestPtr<u8>,
576        buf_len: types::Size,
577    ) -> Result<(), Error> {
578        Snapshot1::random_get(self, memory, buf, buf_len)?;
579        Ok(())
580    }
581
582    fn sock_recv(
583        &mut self,
584        _memory: &mut GuestMemory<'_>,
585        _fd: types::Fd,
586        _ri_data: types::IovecArray,
587        _ri_flags: types::Riflags,
588    ) -> Result<(types::Size, types::Roflags), Error> {
589        Err(Error::trap(anyhow::Error::msg("sock_recv unsupported")))
590    }
591
592    fn sock_send(
593        &mut self,
594        _memory: &mut GuestMemory<'_>,
595        _fd: types::Fd,
596        _si_data: types::CiovecArray,
597        _si_flags: types::Siflags,
598    ) -> Result<types::Size, Error> {
599        Err(Error::trap(anyhow::Error::msg("sock_send unsupported")))
600    }
601
602    fn sock_shutdown(
603        &mut self,
604        _memory: &mut GuestMemory<'_>,
605        _fd: types::Fd,
606        _how: types::Sdflags,
607    ) -> Result<(), Error> {
608        Err(Error::trap(anyhow::Error::msg("sock_shutdown unsupported")))
609    }
610}
611
612fn assert_iovec_array_same() {
613    // NB: this isn't enough to assert the types are the same, but it's
614    // something. Additionally preview1 and preview0 aren't changing any more
615    // and it's been manually verified that these two types are the same, so
616    // it's ok to cast between them.
617    assert_eq!(
618        std::mem::size_of::<types::IovecArray>(),
619        std::mem::size_of::<snapshot1_types::IovecArray>()
620    );
621}
622
623fn assert_ciovec_array_same() {
624    // NB: see above too
625    assert_eq!(
626        std::mem::size_of::<types::CiovecArray>(),
627        std::mem::size_of::<snapshot1_types::CiovecArray>()
628    );
629}
630
631impl From<snapshot1_types::Error> for Error {
632    fn from(error: snapshot1_types::Error) -> Error {
633        match error.downcast() {
634            Ok(errno) => Error::from(types::Errno::from(errno)),
635            Err(trap) => Error::trap(trap),
636        }
637    }
638}
639
640/// Fd is a newtype wrapper around u32. Unwrap and wrap it.
641impl From<types::Fd> for snapshot1_types::Fd {
642    fn from(fd: types::Fd) -> snapshot1_types::Fd {
643        u32::from(fd).into()
644    }
645}
646
647/// Fd is a newtype wrapper around u32. Unwrap and wrap it.
648impl From<snapshot1_types::Fd> for types::Fd {
649    fn from(fd: snapshot1_types::Fd) -> types::Fd {
650        u32::from(fd).into()
651    }
652}
653
654/// Trivial conversion between two c-style enums that have the exact same set of variants.
655/// Could we do something unsafe and not list all these variants out? Probably, but doing
656/// it this way doesn't bother me much. I copy-pasted the list of variants out of the
657/// rendered rustdocs.
658/// LLVM ought to compile these From impls into no-ops, inshallah
659macro_rules! convert_enum {
660    ($from:ty, $to:ty, $($var:ident),+) => {
661        impl From<$from> for $to {
662            fn from(e: $from) -> $to {
663                match e {
664                    $( <$from>::$var => <$to>::$var, )+
665                }
666            }
667        }
668    }
669}
670convert_enum!(
671    snapshot1_types::Errno,
672    types::Errno,
673    Success,
674    TooBig,
675    Acces,
676    Addrinuse,
677    Addrnotavail,
678    Afnosupport,
679    Again,
680    Already,
681    Badf,
682    Badmsg,
683    Busy,
684    Canceled,
685    Child,
686    Connaborted,
687    Connrefused,
688    Connreset,
689    Deadlk,
690    Destaddrreq,
691    Dom,
692    Dquot,
693    Exist,
694    Fault,
695    Fbig,
696    Hostunreach,
697    Idrm,
698    Ilseq,
699    Inprogress,
700    Intr,
701    Inval,
702    Io,
703    Isconn,
704    Isdir,
705    Loop,
706    Mfile,
707    Mlink,
708    Msgsize,
709    Multihop,
710    Nametoolong,
711    Netdown,
712    Netreset,
713    Netunreach,
714    Nfile,
715    Nobufs,
716    Nodev,
717    Noent,
718    Noexec,
719    Nolck,
720    Nolink,
721    Nomem,
722    Nomsg,
723    Noprotoopt,
724    Nospc,
725    Nosys,
726    Notconn,
727    Notdir,
728    Notempty,
729    Notrecoverable,
730    Notsock,
731    Notsup,
732    Notty,
733    Nxio,
734    Overflow,
735    Ownerdead,
736    Perm,
737    Pipe,
738    Proto,
739    Protonosupport,
740    Prototype,
741    Range,
742    Rofs,
743    Spipe,
744    Srch,
745    Stale,
746    Timedout,
747    Txtbsy,
748    Xdev,
749    Notcapable
750);
751convert_enum!(
752    types::Clockid,
753    snapshot1_types::Clockid,
754    Realtime,
755    Monotonic,
756    ProcessCputimeId,
757    ThreadCputimeId
758);
759
760convert_enum!(
761    types::Advice,
762    snapshot1_types::Advice,
763    Normal,
764    Sequential,
765    Random,
766    Willneed,
767    Dontneed,
768    Noreuse
769);
770convert_enum!(
771    snapshot1_types::Filetype,
772    types::Filetype,
773    Directory,
774    BlockDevice,
775    CharacterDevice,
776    RegularFile,
777    SocketDgram,
778    SocketStream,
779    SymbolicLink,
780    Unknown
781);
782convert_enum!(types::Whence, snapshot1_types::Whence, Cur, End, Set);
783
784convert_enum!(
785    types::Signal,
786    snapshot1_types::Signal,
787    None,
788    Hup,
789    Int,
790    Quit,
791    Ill,
792    Trap,
793    Abrt,
794    Bus,
795    Fpe,
796    Kill,
797    Usr1,
798    Segv,
799    Usr2,
800    Pipe,
801    Alrm,
802    Term,
803    Chld,
804    Cont,
805    Stop,
806    Tstp,
807    Ttin,
808    Ttou,
809    Urg,
810    Xcpu,
811    Xfsz,
812    Vtalrm,
813    Prof,
814    Winch,
815    Poll,
816    Pwr,
817    Sys
818);
819
820/// Prestat isn't a c-style enum, its a union where the variant has a payload. Its the only one of
821/// those we need to convert, so write it by hand.
822impl From<snapshot1_types::Prestat> for types::Prestat {
823    fn from(p: snapshot1_types::Prestat) -> types::Prestat {
824        match p {
825            snapshot1_types::Prestat::Dir(d) => types::Prestat::Dir(d.into()),
826        }
827    }
828}
829
830/// Trivial conversion between two structs that have the exact same set of fields,
831/// with recursive descent into the field types.
832macro_rules! convert_struct {
833    ($from:ty, $to:path, $($field:ident),+) => {
834        impl From<$from> for $to {
835            fn from(e: $from) -> $to {
836                $to {
837                    $( $field: e.$field.into(), )+
838                }
839            }
840        }
841    }
842}
843
844convert_struct!(snapshot1_types::PrestatDir, types::PrestatDir, pr_name_len);
845convert_struct!(
846    snapshot1_types::Fdstat,
847    types::Fdstat,
848    fs_filetype,
849    fs_rights_base,
850    fs_rights_inheriting,
851    fs_flags
852);
853convert_struct!(
854    types::SubscriptionClock,
855    snapshot1_types::SubscriptionClock,
856    id,
857    timeout,
858    precision,
859    flags
860);
861convert_struct!(
862    types::SubscriptionFdReadwrite,
863    snapshot1_types::SubscriptionFdReadwrite,
864    file_descriptor
865);
866
867/// Snapshot1 Filestat is incompatible with Snapshot0 Filestat - the nlink
868/// field is u32 on this Filestat, and u64 on theirs. If you've got more than
869/// 2^32 links I don't know what to tell you
870impl From<snapshot1_types::Filestat> for types::Filestat {
871    fn from(f: snapshot1_types::Filestat) -> types::Filestat {
872        types::Filestat {
873            dev: f.dev.into(),
874            ino: f.ino.into(),
875            filetype: f.filetype.into(),
876            nlink: f.nlink.try_into().unwrap_or(u32::MAX),
877            size: f.size.into(),
878            atim: f.atim.into(),
879            mtim: f.mtim.into(),
880            ctim: f.ctim.into(),
881        }
882    }
883}
884
885/// Trivial conversion between two bitflags that have the exact same set of flags.
886macro_rules! convert_flags {
887    ($from:ty, $to:ty, $($flag:ident),+) => {
888        impl From<$from> for $to {
889            fn from(f: $from) -> $to {
890                let mut out = <$to>::empty();
891                $(
892                    if f.contains(<$from>::$flag) {
893                        out |= <$to>::$flag;
894                    }
895                )+
896                out
897            }
898        }
899    }
900}
901
902/// Need to convert in both directions? This saves listing out the flags twice
903macro_rules! convert_flags_bidirectional {
904    ($from:ty, $to:ty, $($flag:tt)*) => {
905        convert_flags!($from, $to, $($flag)*);
906        convert_flags!($to, $from, $($flag)*);
907    }
908}
909
910convert_flags_bidirectional!(
911    snapshot1_types::Fdflags,
912    types::Fdflags,
913    APPEND,
914    DSYNC,
915    NONBLOCK,
916    RSYNC,
917    SYNC
918);
919convert_flags!(
920    types::Lookupflags,
921    snapshot1_types::Lookupflags,
922    SYMLINK_FOLLOW
923);
924convert_flags!(
925    types::Fstflags,
926    snapshot1_types::Fstflags,
927    ATIM,
928    ATIM_NOW,
929    MTIM,
930    MTIM_NOW
931);
932convert_flags!(
933    types::Oflags,
934    snapshot1_types::Oflags,
935    CREAT,
936    DIRECTORY,
937    EXCL,
938    TRUNC
939);
940convert_flags_bidirectional!(
941    types::Rights,
942    snapshot1_types::Rights,
943    FD_DATASYNC,
944    FD_READ,
945    FD_SEEK,
946    FD_FDSTAT_SET_FLAGS,
947    FD_SYNC,
948    FD_TELL,
949    FD_WRITE,
950    FD_ADVISE,
951    FD_ALLOCATE,
952    PATH_CREATE_DIRECTORY,
953    PATH_CREATE_FILE,
954    PATH_LINK_SOURCE,
955    PATH_LINK_TARGET,
956    PATH_OPEN,
957    FD_READDIR,
958    PATH_READLINK,
959    PATH_RENAME_SOURCE,
960    PATH_RENAME_TARGET,
961    PATH_FILESTAT_GET,
962    PATH_FILESTAT_SET_SIZE,
963    PATH_FILESTAT_SET_TIMES,
964    FD_FILESTAT_GET,
965    FD_FILESTAT_SET_SIZE,
966    FD_FILESTAT_SET_TIMES,
967    PATH_SYMLINK,
968    PATH_REMOVE_DIRECTORY,
969    PATH_UNLINK_FILE,
970    POLL_FD_READWRITE,
971    SOCK_SHUTDOWN
972);
973convert_flags!(
974    types::Subclockflags,
975    snapshot1_types::Subclockflags,
976    SUBSCRIPTION_CLOCK_ABSTIME
977);
978
979impl From<GuestError> for types::Error {
980    fn from(err: GuestError) -> Self {
981        snapshot1_types::Error::from(err).into()
982    }
983}