1use alloc::boxed::Box;
25use alloc::collections::VecDeque;
26use alloc::rc::Rc;
27use alloc::string::{String, ToString};
28use alloc::vec::Vec;
29use core::cell::{Cell, RefCell};
30use core::fmt::Write as _;
31use core::future::Future;
32use core::pin::Pin;
33use core::task::{Context, Poll, Waker};
34use wasmtime::component::{Component, Linker, Resource, ResourceTable};
35use wasmtime::{Engine, Result, Store, bail};
36use wasmtime_wasi_io::{
37 IoView,
38 bytes::Bytes,
39 poll::{DynPollable, Pollable, subscribe},
40 streams::{DynInputStream, DynOutputStream, InputStream, OutputStream},
41};
42
43#[unsafe(no_mangle)]
48pub unsafe extern "C" fn run_wasi(
49 out_buf: *mut u8,
50 out_size: *mut usize,
51 wasi_component: *const u8,
52 wasi_component_size: usize,
53) -> usize {
54 unsafe {
55 let buf = core::slice::from_raw_parts_mut(out_buf, *out_size);
56 let wasi_component = core::slice::from_raw_parts(wasi_component, wasi_component_size);
57 match run(wasi_component) {
58 Ok(output) => {
59 let len = buf.len().min(output.len());
60 buf[..len].copy_from_slice(&output.as_bytes()[..len]);
61 *out_size = len;
62 return 0;
63 }
64 Err(e) => {
65 let msg = format!("{e:?}");
66 let len = buf.len().min(msg.len());
67 buf[..len].copy_from_slice(&msg.as_bytes()[..len]);
68 *out_size = len;
69 return 1;
70 }
71 }
72 }
73}
74
75fn run(wasi_component: &[u8]) -> Result<String> {
76 let config = super::config();
77 let engine = Engine::new(&config)?;
80
81 let component = match deserialize(&engine, wasi_component)? {
83 Some(c) => c,
84 None => return Ok("cannot load native code - requires virtual memory".to_string()),
85 };
86
87 let mut linker = Linker::new(&engine);
91 wasmtime_wasi_io::add_to_linker_async(&mut linker)?;
92 add_to_linker_async(&mut linker)?;
93
94 let instance_pre = linker.instantiate_pre(&component)?;
96 let command_pre = CommandPre::new(instance_pre)?;
98
99 let clock = Clock::new();
101
102 block_on(clock.clone(), async move {
104 let ctx = ExampleCtx {
105 table: ResourceTable::new(),
106 clock,
107 stdout: WriteLog::new(),
108 stderr: WriteLog::new(),
109 };
110 let mut store = Store::new(&engine, ctx);
111 let instance = command_pre.instantiate_async(&mut store).await?;
113 instance
114 .wasi_cli_run()
115 .call_run(&mut store)
116 .await?
117 .map_err(|()| wasmtime::format_err!("wasi cli run returned error"))?;
118
119 store.into_data().output()
120 })
121}
122
123fn deserialize(engine: &Engine, component: &[u8]) -> Result<Option<Component>> {
124 match unsafe { Component::deserialize(engine, component) } {
125 Ok(component) => Ok(Some(component)),
126 Err(e) => {
127 if !cfg!(feature = "custom")
133 && e.to_string()
134 .contains("requires virtual memory to be enabled")
135 {
136 Ok(None)
137 } else {
138 Err(e)
139 }
140 }
141 }
142}
143
144wasmtime::component::bindgen!({
147 path: "../../../crates/wasi/src/p2/wit",
148 world: "wasi:cli/command",
149 imports: { default: trappable },
150 exports: { default: async },
151 require_store_data_send: true,
152 with: {
158 "wasi:io": wasmtime_wasi_io::bindings::wasi::io,
159 }
160});
161
162pub struct ExampleCtx {
167 table: ResourceTable,
168 clock: Clock,
169 stdout: WriteLog,
170 stderr: WriteLog,
171}
172
173impl IoView for ExampleCtx {
176 fn table(&mut self) -> &mut ResourceTable {
177 &mut self.table
178 }
179}
180
181impl ExampleCtx {
182 fn output(&self) -> Result<String> {
186 let mut out = String::new();
187 let stdout = self.stdout.log.borrow();
188 if !stdout.is_empty() {
189 write!(&mut out, "stdout:\n")?;
190 for chunk in stdout.iter() {
191 write!(&mut out, "{}", String::from_utf8_lossy(chunk))?;
192 }
193 }
194 let stderr = self.stderr.log.borrow();
195 if !stderr.is_empty() {
196 write!(&mut out, "stderr:\n")?;
197 for chunk in stderr.iter() {
198 write!(&mut out, "{}", String::from_utf8_lossy(chunk))?;
199 }
200 }
201 Ok(out)
202 }
203}
204
205pub fn add_to_linker_async(linker: &mut Linker<ExampleCtx>) -> Result<()> {
210 type Data = wasmtime::component::HasSelf<ExampleCtx>;
211
212 wasi::clocks::monotonic_clock::add_to_linker::<_, Data>(linker, |t| t)?;
213 wasi::clocks::wall_clock::add_to_linker::<_, Data>(linker, |t| t)?;
214 wasi::cli::environment::add_to_linker::<_, Data>(linker, |t| t)?;
215 wasi::cli::exit::add_to_linker::<_, Data>(linker, &Default::default(), |t| t)?;
216 wasi::cli::stdin::add_to_linker::<_, Data>(linker, |t| t)?;
217 wasi::cli::stdout::add_to_linker::<_, Data>(linker, |t| t)?;
218 wasi::cli::stderr::add_to_linker::<_, Data>(linker, |t| t)?;
219 wasi::random::random::add_to_linker::<_, Data>(linker, |t| t)?;
220 wasi::cli::terminal_input::add_to_linker::<_, Data>(linker, |t| t)?;
221 wasi::cli::terminal_output::add_to_linker::<_, Data>(linker, |t| t)?;
222 wasi::cli::terminal_stdin::add_to_linker::<_, Data>(linker, |t| t)?;
223 wasi::cli::terminal_stdout::add_to_linker::<_, Data>(linker, |t| t)?;
224 wasi::cli::terminal_stderr::add_to_linker::<_, Data>(linker, |t| t)?;
225 wasi::filesystem::preopens::add_to_linker::<_, Data>(linker, |t| t)?;
226 wasi::filesystem::types::add_to_linker::<_, Data>(linker, |t| t)?;
227 Ok(())
228}
229
230#[derive(Clone)]
233struct Clock(Rc<Cell<u64>>);
234impl Clock {
235 fn new() -> Self {
236 Clock(Rc::new(Cell::new(0)))
237 }
238 fn get(&self) -> u64 {
239 self.0.get()
240 }
241 fn set(&self, to: u64) {
242 self.0.set(to)
243 }
244 fn timer(&self, due: u64) -> Deadline {
245 Deadline {
246 clock: self.clone(),
247 due,
248 }
249 }
250}
251unsafe impl Send for Clock {}
253unsafe impl Sync for Clock {}
254
255#[derive(Clone)]
258struct Deadline {
259 clock: Clock,
260 due: u64,
261}
262impl Future for Deadline {
263 type Output = ();
264 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
265 let now = self.clock.get();
266 if now < self.due {
267 Executor::current().push_deadline(self.due, cx.waker().clone());
268 Poll::Pending
269 } else {
270 Poll::Ready(())
271 }
272 }
273}
274#[wasmtime_wasi_io::async_trait]
275impl Pollable for Deadline {
276 async fn ready(&mut self) {
277 self.clone().await
278 }
279}
280
281struct NeverReadable;
284#[wasmtime_wasi_io::async_trait]
285impl Pollable for NeverReadable {
286 async fn ready(&mut self) {
287 struct Pending;
288 impl Future for Pending {
289 type Output = ();
290 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
291 Poll::Pending
292 }
293 }
294 Pending.await
295 }
296}
297impl InputStream for NeverReadable {
298 fn read(&mut self, _: usize) -> wasmtime_wasi_io::streams::StreamResult<Bytes> {
299 unreachable!("never ready for reading")
300 }
301}
302
303#[derive(Clone)]
308struct WriteLog {
309 log: Rc<RefCell<VecDeque<Bytes>>>,
310}
311impl WriteLog {
312 fn new() -> Self {
313 Self {
314 log: Rc::new(RefCell::new(VecDeque::new())),
315 }
316 }
317}
318unsafe impl Send for WriteLog {}
320unsafe impl Sync for WriteLog {}
321
322impl OutputStream for WriteLog {
323 fn check_write(&mut self) -> wasmtime_wasi_io::streams::StreamResult<usize> {
324 Ok(usize::MAX)
325 }
326 fn write(&mut self, contents: Bytes) -> wasmtime_wasi_io::streams::StreamResult<()> {
327 self.log.borrow_mut().push_back(contents);
328 Ok(())
329 }
330 fn flush(&mut self) -> wasmtime_wasi_io::streams::StreamResult<()> {
331 Ok(())
332 }
333}
334#[wasmtime_wasi_io::async_trait]
335impl Pollable for WriteLog {
336 async fn ready(&mut self) {
337 }
339}
340
341static EXECUTOR: ExecutorGlobal = ExecutorGlobal::new();
344
345struct ExecutorGlobal(RefCell<Option<Executor>>);
348impl ExecutorGlobal {
349 const fn new() -> Self {
350 ExecutorGlobal(RefCell::new(None))
351 }
352}
353unsafe impl Send for ExecutorGlobal {}
355unsafe impl Sync for ExecutorGlobal {}
356
357struct Executor(Rc<RefCell<ExecutorInner>>);
360
361impl Executor {
362 pub fn new() -> Self {
363 Executor(Rc::new(RefCell::new(ExecutorInner {
364 schedule: Vec::new(),
365 })))
366 }
367 pub fn current() -> Self {
368 Executor(
369 EXECUTOR
370 .0
371 .borrow_mut()
372 .as_ref()
373 .expect("Executor::current must be called within block_on")
374 .0
375 .clone(),
376 )
377 }
378 pub fn push_deadline(&mut self, due: u64, waker: Waker) {
379 self.0.borrow_mut().schedule.push((due, waker))
380 }
381}
382
383struct ExecutorInner {
386 schedule: Vec<(u64, Waker)>,
387}
388
389impl ExecutorInner {
390 fn earliest_deadline(&self) -> Option<u64> {
393 self.schedule.iter().map(|(due, _)| due).min().copied()
394 }
395 fn ready_deadlines(&mut self, now: u64) -> Vec<Waker> {
399 let mut i = 0;
400 let mut wakers = Vec::new();
401 while i < self.schedule.len() {
404 if let Some((due, _)) = self.schedule.get(i) {
405 if *due <= now {
406 let (_, waker) = self.schedule.remove(i);
407 wakers.push(waker);
408 } else {
409 i += 1;
410 }
411 } else {
412 break;
413 }
414 }
415 wakers
416 }
417}
418
419fn block_on<R>(clock: Clock, f: impl Future<Output = Result<R>> + Send + 'static) -> Result<R> {
420 if EXECUTOR.0.borrow_mut().is_some() {
422 panic!("cannot block_on while executor is running!")
423 }
424 let executor = Executor::new();
425 *EXECUTOR.0.borrow_mut() = Some(Executor(executor.0.clone()));
426
427 let mut cx = Context::from_waker(Waker::noop());
429 let mut f = core::pin::pin!(f);
430
431 let r = 'outer: loop {
433 const POLLS_PER_CLOCK: usize = 200;
438 for _ in 0..POLLS_PER_CLOCK {
439 match f.as_mut().poll(&mut cx) {
440 Poll::Pending => {}
441 Poll::Ready(r) => break 'outer r,
442 }
443 }
444
445 if let Some(sleep_until) = executor.0.borrow().earliest_deadline() {
450 clock.set(sleep_until);
451 } else {
452 clock.set(clock.get() + 1);
453 }
454
455 for waker in executor.0.borrow_mut().ready_deadlines(clock.get()) {
457 waker.wake()
458 }
459 };
460
461 let _ = EXECUTOR
463 .0
464 .borrow_mut()
465 .take()
466 .expect("executor vacated global while running");
467 r
468}
469
470impl wasi::clocks::monotonic_clock::Host for ExampleCtx {
475 fn now(&mut self) -> Result<wasi::clocks::monotonic_clock::Instant> {
476 Ok(self.clock.get())
477 }
478 fn resolution(&mut self) -> Result<wasi::clocks::monotonic_clock::Duration> {
479 Ok(1)
480 }
481 fn subscribe_duration(
482 &mut self,
483 duration: wasi::clocks::monotonic_clock::Duration,
484 ) -> Result<Resource<DynPollable>> {
485 self.subscribe_instant(self.clock.get() + duration)
486 }
487 fn subscribe_instant(
488 &mut self,
489 deadline: wasi::clocks::monotonic_clock::Instant,
490 ) -> Result<Resource<DynPollable>> {
491 let timer = self.clock.timer(deadline);
492 let deadline = self.table().push(timer)?;
493 Ok(subscribe(self.table(), deadline)?)
494 }
495}
496
497impl wasi::clocks::wall_clock::Host for ExampleCtx {
498 fn now(&mut self) -> Result<wasi::clocks::wall_clock::Datetime> {
499 let now = self.clock.get();
502 let seconds = now / 1_000_000_000;
503 let nanoseconds = (now - (seconds * 1_000_000_000)) as u32;
504 Ok(wasi::clocks::wall_clock::Datetime {
505 seconds,
506 nanoseconds,
507 })
508 }
509 fn resolution(&mut self) -> Result<wasi::clocks::wall_clock::Datetime> {
510 Ok(wasi::clocks::wall_clock::Datetime {
511 seconds: 0,
512 nanoseconds: 1,
513 })
514 }
515}
516
517impl wasi::cli::environment::Host for ExampleCtx {
519 fn get_arguments(&mut self) -> Result<Vec<String>> {
520 Ok(Vec::new())
521 }
522 fn get_environment(&mut self) -> Result<Vec<(String, String)>> {
523 Ok(Vec::new())
524 }
525 fn initial_cwd(&mut self) -> Result<Option<String>> {
526 Ok(None)
527 }
528}
529
530impl wasi::cli::exit::Host for ExampleCtx {
536 fn exit(&mut self, code: Result<(), ()>) -> Result<()> {
537 if code.is_ok() {
538 bail!("wasi exit success")
539 } else {
540 bail!("wasi exit error")
541 }
542 }
543 fn exit_with_code(&mut self, _: u8) -> Result<()> {
547 unreachable!("this unstable func is not added to the linker");
548 }
549}
550
551impl wasi::cli::stdin::Host for ExampleCtx {
552 fn get_stdin(&mut self) -> Result<Resource<DynInputStream>> {
553 let stdin: DynInputStream = Box::new(NeverReadable);
554 Ok(self.table().push(stdin)?)
555 }
556}
557
558impl wasi::cli::stdout::Host for ExampleCtx {
559 fn get_stdout(&mut self) -> Result<Resource<DynOutputStream>> {
560 let stdout: DynOutputStream = Box::new(self.stdout.clone());
561 Ok(self.table().push(stdout)?)
562 }
563}
564
565impl wasi::cli::stderr::Host for ExampleCtx {
566 fn get_stderr(&mut self) -> Result<Resource<DynOutputStream>> {
567 let stderr: DynOutputStream = Box::new(self.stderr.clone());
568 Ok(self.table().push(stderr)?)
569 }
570}
571
572impl wasi::cli::terminal_input::Host for ExampleCtx {}
574impl wasi::cli::terminal_input::HostTerminalInput for ExampleCtx {
575 fn drop(&mut self, r: Resource<wasi::cli::terminal_input::TerminalInput>) -> Result<()> {
576 self.table.delete(r)?;
577 Ok(())
578 }
579}
580impl wasi::cli::terminal_output::Host for ExampleCtx {}
581impl wasi::cli::terminal_output::HostTerminalOutput for ExampleCtx {
582 fn drop(&mut self, r: Resource<wasi::cli::terminal_output::TerminalOutput>) -> Result<()> {
583 self.table.delete(r)?;
584 Ok(())
585 }
586}
587impl wasi::cli::terminal_stdin::Host for ExampleCtx {
588 fn get_terminal_stdin(
589 &mut self,
590 ) -> Result<Option<Resource<wasi::cli::terminal_input::TerminalInput>>> {
591 Ok(None)
592 }
593}
594impl wasi::cli::terminal_stdout::Host for ExampleCtx {
595 fn get_terminal_stdout(
596 &mut self,
597 ) -> Result<Option<Resource<wasi::cli::terminal_output::TerminalOutput>>> {
598 Ok(None)
599 }
600}
601impl wasi::cli::terminal_stderr::Host for ExampleCtx {
602 fn get_terminal_stderr(
603 &mut self,
604 ) -> Result<Option<Resource<wasi::cli::terminal_output::TerminalOutput>>> {
605 Ok(None)
606 }
607}
608
609impl wasi::random::random::Host for ExampleCtx {
612 fn get_random_bytes(&mut self, len: u64) -> Result<Vec<u8>> {
613 let mut vec = Vec::new();
614 vec.resize(len as usize, 0u8);
615 Ok(vec)
616 }
617 fn get_random_u64(&mut self) -> Result<u64> {
618 Ok(0)
619 }
620}
621
622impl wasi::filesystem::preopens::Host for ExampleCtx {
627 fn get_directories(
628 &mut self,
629 ) -> Result<Vec<(Resource<wasi::filesystem::types::Descriptor>, String)>> {
630 Ok(Vec::new())
633 }
634}
635
636impl wasi::filesystem::types::HostDescriptor for ExampleCtx {
638 fn read_via_stream(
639 &mut self,
640 _: Resource<wasi::filesystem::types::Descriptor>,
641 _: u64,
642 ) -> Result<Result<Resource<DynInputStream>, wasi::filesystem::types::ErrorCode>> {
643 unreachable!("no filesystem")
644 }
645 fn write_via_stream(
646 &mut self,
647 _: Resource<wasi::filesystem::types::Descriptor>,
648 _: u64,
649 ) -> Result<Result<Resource<DynOutputStream>, wasi::filesystem::types::ErrorCode>> {
650 unreachable!("no filesystem")
651 }
652 fn append_via_stream(
653 &mut self,
654 _: Resource<wasi::filesystem::types::Descriptor>,
655 ) -> Result<Result<Resource<DynOutputStream>, wasi::filesystem::types::ErrorCode>> {
656 unreachable!("no filesystem")
657 }
658 fn advise(
659 &mut self,
660 _: Resource<wasi::filesystem::types::Descriptor>,
661 _: u64,
662 _: u64,
663 _: wasi::filesystem::types::Advice,
664 ) -> Result<Result<(), wasi::filesystem::types::ErrorCode>> {
665 unreachable!("no filesystem")
666 }
667 fn sync_data(
668 &mut self,
669 _: Resource<wasi::filesystem::types::Descriptor>,
670 ) -> Result<Result<(), wasi::filesystem::types::ErrorCode>> {
671 unreachable!("no filesystem")
672 }
673 fn get_flags(
674 &mut self,
675 _: Resource<wasi::filesystem::types::Descriptor>,
676 ) -> Result<Result<wasi::filesystem::types::DescriptorFlags, wasi::filesystem::types::ErrorCode>>
677 {
678 unreachable!("no filesystem")
679 }
680 fn get_type(
681 &mut self,
682 _: Resource<wasi::filesystem::types::Descriptor>,
683 ) -> Result<Result<wasi::filesystem::types::DescriptorType, wasi::filesystem::types::ErrorCode>>
684 {
685 unreachable!("no filesystem")
686 }
687 fn set_size(
688 &mut self,
689 _: Resource<wasi::filesystem::types::Descriptor>,
690 _: u64,
691 ) -> Result<Result<(), wasi::filesystem::types::ErrorCode>> {
692 unreachable!("no filesystem")
693 }
694 fn set_times(
695 &mut self,
696 _: Resource<wasi::filesystem::types::Descriptor>,
697 _: wasi::filesystem::types::NewTimestamp,
698 _: wasi::filesystem::types::NewTimestamp,
699 ) -> Result<Result<(), wasi::filesystem::types::ErrorCode>> {
700 unreachable!("no filesystem")
701 }
702 fn read(
703 &mut self,
704 _: Resource<wasi::filesystem::types::Descriptor>,
705 _: u64,
706 _: u64,
707 ) -> Result<Result<(Vec<u8>, bool), wasi::filesystem::types::ErrorCode>> {
708 unreachable!("no filesystem")
709 }
710 fn write(
711 &mut self,
712 _: Resource<wasi::filesystem::types::Descriptor>,
713 _: Vec<u8>,
714 _: u64,
715 ) -> Result<Result<u64, wasi::filesystem::types::ErrorCode>> {
716 unreachable!("no filesystem")
717 }
718
719 fn read_directory(
720 &mut self,
721 _: Resource<wasi::filesystem::types::Descriptor>,
722 ) -> Result<
723 Result<
724 Resource<wasi::filesystem::types::DirectoryEntryStream>,
725 wasi::filesystem::types::ErrorCode,
726 >,
727 > {
728 unreachable!("no filesystem")
729 }
730 fn sync(
731 &mut self,
732 _: Resource<wasi::filesystem::types::Descriptor>,
733 ) -> Result<Result<(), wasi::filesystem::types::ErrorCode>> {
734 unreachable!("no filesystem")
735 }
736 fn create_directory_at(
737 &mut self,
738 _: Resource<wasi::filesystem::types::Descriptor>,
739 _: String,
740 ) -> Result<Result<(), wasi::filesystem::types::ErrorCode>> {
741 unreachable!("no filesystem")
742 }
743 fn stat(
744 &mut self,
745 _: Resource<wasi::filesystem::types::Descriptor>,
746 ) -> Result<Result<wasi::filesystem::types::DescriptorStat, wasi::filesystem::types::ErrorCode>>
747 {
748 unreachable!("no filesystem")
749 }
750 fn stat_at(
751 &mut self,
752 _: Resource<wasi::filesystem::types::Descriptor>,
753 _: wasi::filesystem::types::PathFlags,
754 _: String,
755 ) -> Result<Result<wasi::filesystem::types::DescriptorStat, wasi::filesystem::types::ErrorCode>>
756 {
757 unreachable!("no filesystem")
758 }
759 fn set_times_at(
760 &mut self,
761 _: Resource<wasi::filesystem::types::Descriptor>,
762 _: wasi::filesystem::types::PathFlags,
763 _: String,
764 _: wasi::filesystem::types::NewTimestamp,
765 _: wasi::filesystem::types::NewTimestamp,
766 ) -> Result<Result<(), wasi::filesystem::types::ErrorCode>> {
767 unreachable!("no filesystem")
768 }
769 fn link_at(
770 &mut self,
771 _: Resource<wasi::filesystem::types::Descriptor>,
772 _: wasi::filesystem::types::PathFlags,
773 _: String,
774 _: Resource<wasi::filesystem::types::Descriptor>,
775 _: String,
776 ) -> Result<Result<(), wasi::filesystem::types::ErrorCode>> {
777 unreachable!("no filesystem")
778 }
779 fn open_at(
780 &mut self,
781 _: Resource<wasi::filesystem::types::Descriptor>,
782 _: wasi::filesystem::types::PathFlags,
783 _: String,
784 _: wasi::filesystem::types::OpenFlags,
785 _: wasi::filesystem::types::DescriptorFlags,
786 ) -> Result<
787 Result<Resource<wasi::filesystem::types::Descriptor>, wasi::filesystem::types::ErrorCode>,
788 > {
789 unreachable!("no filesystem")
790 }
791 fn readlink_at(
792 &mut self,
793 _: Resource<wasi::filesystem::types::Descriptor>,
794 _: String,
795 ) -> Result<Result<String, wasi::filesystem::types::ErrorCode>> {
796 unreachable!("no filesystem")
797 }
798 fn remove_directory_at(
799 &mut self,
800 _: Resource<wasi::filesystem::types::Descriptor>,
801 _: String,
802 ) -> Result<Result<(), wasi::filesystem::types::ErrorCode>> {
803 unreachable!("no filesystem")
804 }
805 fn rename_at(
806 &mut self,
807 _: Resource<wasi::filesystem::types::Descriptor>,
808 _: String,
809 _: Resource<wasi::filesystem::types::Descriptor>,
810 _: String,
811 ) -> Result<Result<(), wasi::filesystem::types::ErrorCode>> {
812 unreachable!("no filesystem")
813 }
814 fn symlink_at(
815 &mut self,
816 _: Resource<wasi::filesystem::types::Descriptor>,
817 _: String,
818 _: String,
819 ) -> Result<Result<(), wasi::filesystem::types::ErrorCode>> {
820 unreachable!("no filesystem")
821 }
822 fn unlink_file_at(
823 &mut self,
824 _: Resource<wasi::filesystem::types::Descriptor>,
825 _: String,
826 ) -> Result<Result<(), wasi::filesystem::types::ErrorCode>> {
827 unreachable!("no filesystem")
828 }
829 fn is_same_object(
830 &mut self,
831 _: Resource<wasi::filesystem::types::Descriptor>,
832 _: Resource<wasi::filesystem::types::Descriptor>,
833 ) -> Result<bool> {
834 unreachable!("no filesystem")
835 }
836 fn metadata_hash(
837 &mut self,
838 _: Resource<wasi::filesystem::types::Descriptor>,
839 ) -> Result<
840 Result<wasi::filesystem::types::MetadataHashValue, wasi::filesystem::types::ErrorCode>,
841 > {
842 unreachable!("no filesystem")
843 }
844 fn metadata_hash_at(
845 &mut self,
846 _: Resource<wasi::filesystem::types::Descriptor>,
847 _: wasi::filesystem::types::PathFlags,
848 _: String,
849 ) -> Result<
850 Result<wasi::filesystem::types::MetadataHashValue, wasi::filesystem::types::ErrorCode>,
851 > {
852 unreachable!("no filesystem")
853 }
854
855 fn drop(&mut self, _: Resource<wasi::filesystem::types::Descriptor>) -> Result<()> {
856 unreachable!("no filesystem")
857 }
858}
859impl wasi::filesystem::types::HostDirectoryEntryStream for ExampleCtx {
862 fn read_directory_entry(
863 &mut self,
864 _: Resource<wasi::filesystem::types::DirectoryEntryStream>,
865 ) -> Result<
866 Result<Option<wasi::filesystem::types::DirectoryEntry>, wasi::filesystem::types::ErrorCode>,
867 > {
868 unreachable!("no filesystem")
869 }
870 fn drop(&mut self, _: Resource<wasi::filesystem::types::DirectoryEntryStream>) -> Result<()> {
871 unreachable!("no filesystem")
872 }
873}
874
875impl wasi::filesystem::types::Host for ExampleCtx {
878 fn filesystem_error_code(
879 &mut self,
880 _: Resource<wasmtime_wasi_io::streams::Error>,
881 ) -> Result<Option<wasi::filesystem::types::ErrorCode>> {
882 Ok(None)
883 }
884}