wasmer_wasix/runtime/
mod.rs

1pub mod module_cache;
2pub mod package_loader;
3pub mod resolver;
4pub mod task_manager;
5
6use self::module_cache::CacheError;
7pub use self::task_manager::{SpawnType, VirtualTaskManager};
8use module_cache::HashedModuleData;
9use wasmer_config::package::SuggestedCompilerOptimizations;
10use wasmer_types::{
11    CompilationProgressCallback, ModuleHash,
12    target::UserCompilerOptimizations as WasmerSuggestedCompilerOptimizations,
13};
14
15use std::{
16    borrow::Cow,
17    fmt,
18    ops::Deref,
19    sync::{Arc, Mutex},
20};
21
22use futures::future::BoxFuture;
23use virtual_mio::block_on;
24use virtual_net::{DynVirtualNetworking, VirtualNetworking};
25use wasmer::{CompileError, Engine, Module, RuntimeError};
26use wasmer_wasix_types::wasi::ExitCode;
27
28#[cfg(feature = "journal")]
29use crate::journal::{DynJournal, DynReadableJournal};
30use crate::{
31    SpawnError, WasiTtyState,
32    bin_factory::BinaryPackageCommand,
33    http::{DynHttpClient, HttpClient},
34    os::TtyBridge,
35    runtime::{
36        module_cache::{
37            ModuleCache, ThreadLocalCache,
38            progress::{ModuleLoadProgress, ModuleLoadProgressReporter},
39        },
40        package_loader::{PackageLoader, UnsupportedPackageLoader},
41        resolver::{BackendSource, MultiSource, Source},
42    },
43};
44
45#[derive(Clone)]
46pub enum TaintReason {
47    UnknownWasiVersion,
48    NonZeroExitCode(ExitCode),
49    RuntimeError(RuntimeError),
50    DlSymbolResolutionFailed(String),
51}
52
53/// The input to load a module.
54///
55/// Exists because the semantics for resolving modules can vary between
56/// different sources.
57///
58/// All variants are wrapped in `Cow` to allow for zero-copy usage when possible.
59pub enum ModuleInput<'a> {
60    /// Raw bytes.
61    Bytes(Cow<'a, [u8]>),
62    /// Pre-hashed module data.
63    Hashed(Cow<'a, HashedModuleData>),
64    /// A binary package command.
65    Command(Cow<'a, BinaryPackageCommand>),
66}
67
68impl<'a> ModuleInput<'a> {
69    /// Convert to an owned version of the module input.
70    pub fn to_owned(&'a self) -> ModuleInput<'static> {
71        // The manual code below is needed due to compiler issues with the lifetime.
72        match self {
73            Self::Bytes(Cow::Borrowed(b)) => {
74                let v: Vec<u8> = (*b).to_owned();
75                let c: Cow<'static, [u8]> = Cow::from(v);
76                ModuleInput::Bytes(c)
77            }
78            Self::Bytes(Cow::Owned(b)) => ModuleInput::Bytes(Cow::Owned((*b).clone())),
79            Self::Hashed(Cow::Borrowed(h)) => ModuleInput::Hashed(Cow::Owned((*h).clone())),
80            Self::Hashed(Cow::Owned(h)) => ModuleInput::Hashed(Cow::Owned(h.clone())),
81            Self::Command(Cow::Borrowed(c)) => ModuleInput::Command(Cow::Owned((*c).clone())),
82            Self::Command(Cow::Owned(c)) => ModuleInput::Command(Cow::Owned(c.clone())),
83        }
84    }
85
86    /// Get the module hash.
87    ///
88    /// NOTE: may be expensive, depending on the variant.
89    pub fn hash(&self) -> ModuleHash {
90        match self {
91            Self::Bytes(b) => {
92                // Hash on the fly
93                ModuleHash::new(b)
94            }
95            Self::Hashed(hashed) => *hashed.hash(),
96            Self::Command(cmd) => *cmd.hash(),
97        }
98    }
99
100    /// Get the raw WebAssembly bytes.
101    pub fn wasm(&self) -> &[u8] {
102        match self {
103            Self::Bytes(b) => b,
104            Self::Hashed(hashed) => hashed.wasm().as_ref(),
105            Self::Command(cmd) => cmd.atom_ref().as_ref(),
106        }
107    }
108
109    /// Convert to a `HashedModuleData`.
110    ///
111    /// May involve cloning and hashing.
112    pub fn to_hashed(&self) -> HashedModuleData {
113        match self {
114            Self::Bytes(b) => HashedModuleData::new(b.as_ref()),
115            Self::Hashed(hashed) => hashed.as_ref().clone(),
116            Self::Command(cmd) => HashedModuleData::from_command(cmd),
117        }
118    }
119}
120
121/// Runtime components used when running WebAssembly programs.
122///
123/// Think of this as the "System" in "WebAssembly Systems Interface".
124#[allow(unused_variables)]
125pub trait Runtime
126where
127    Self: fmt::Debug,
128{
129    /// Provides access to all the networking related functions such as sockets.
130    fn networking(&self) -> &DynVirtualNetworking;
131
132    /// Retrieve the active [`VirtualTaskManager`].
133    fn task_manager(&self) -> &Arc<dyn VirtualTaskManager>;
134
135    /// A package loader.
136    fn package_loader(&self) -> Arc<dyn PackageLoader + Send + Sync> {
137        Arc::new(UnsupportedPackageLoader)
138    }
139
140    /// A cache for compiled modules.
141    fn module_cache(&self) -> Arc<dyn ModuleCache + Send + Sync> {
142        // Return a cache that uses a thread-local variable. This isn't ideal
143        // because it allows silently sharing state, possibly between runtimes.
144        //
145        // That said, it means people will still get *some* level of caching
146        // because each cache returned by this default implementation will go
147        // through the same thread-local variable.
148        Arc::new(ThreadLocalCache::default())
149    }
150
151    /// The package registry.
152    fn source(&self) -> Arc<dyn Source + Send + Sync>;
153
154    /// Get a [`wasmer::Engine`] for module compilation.
155    fn engine(&self) -> Engine {
156        Engine::default()
157    }
158
159    fn engine_with_suggested_opts(
160        &self,
161        suggested_opts: &SuggestedCompilerOptimizations,
162    ) -> Result<Engine, CompileError> {
163        let mut engine = self.engine();
164        engine.with_opts(&WasmerSuggestedCompilerOptimizations {
165            pass_params: suggested_opts.pass_params,
166        })?;
167        Ok(engine)
168    }
169
170    /// Create a new [`wasmer::Store`].
171    fn new_store(&self) -> wasmer::Store {
172        cfg_if::cfg_if! {
173            if #[cfg(feature = "sys")] {
174                wasmer::Store::new(self.engine())
175            } else {
176                wasmer::Store::default()
177            }
178        }
179    }
180
181    /// Get a custom HTTP client
182    fn http_client(&self) -> Option<&DynHttpClient> {
183        None
184    }
185
186    /// Get access to the TTY used by the environment.
187    fn tty(&self) -> Option<&(dyn TtyBridge + Send + Sync)> {
188        None
189    }
190
191    /// The primary way to load a module given a module input.
192    ///
193    /// The engine to use can be optionally provided, otherwise the most appropriate engine
194    /// should be selected.
195    ///
196    /// An optional progress reporter callback can be provided to report progress during module loading.
197    fn resolve_module<'a>(
198        &'a self,
199        input: ModuleInput<'a>,
200        engine: Option<&Engine>,
201        on_progress: Option<ModuleLoadProgressReporter>,
202    ) -> BoxFuture<'a, Result<Module, SpawnError>> {
203        let data = input.to_hashed();
204
205        let engine = if let Some(e) = engine {
206            e.clone()
207        } else {
208            match &input {
209                ModuleInput::Bytes(_) => self.engine(),
210                ModuleInput::Hashed(_) => self.engine(),
211                ModuleInput::Command(cmd) => {
212                    match self
213                        .engine_with_suggested_opts(&cmd.as_ref().suggested_compiler_optimizations)
214                    {
215                        Ok(engine) => engine,
216                        Err(error) => {
217                            return Box::pin(async move {
218                                Err(SpawnError::CompileError {
219                                    module_hash: *data.hash(),
220                                    error,
221                                })
222                            });
223                        }
224                    }
225                }
226            }
227        };
228
229        let module_cache = self.module_cache();
230
231        let task = async move { load_module(&engine, &module_cache, input, on_progress).await };
232        Box::pin(task)
233    }
234
235    /// Sync variant of [`Self::resolve_module`].
236    fn resolve_module_sync(
237        &self,
238        input: ModuleInput<'_>,
239        engine: Option<&Engine>,
240        on_progress: Option<ModuleLoadProgressReporter>,
241    ) -> Result<Module, SpawnError> {
242        block_on(self.resolve_module(input, engine, on_progress))
243    }
244
245    /// Load the module for a command.
246    ///
247    /// Will load the module from the cache if possible, otherwise will compile.
248    ///
249    /// NOTE: This always be preferred over [`Self::load_module`] to avoid
250    /// re-hashing the module!
251    #[deprecated(since = "0.601.0", note = "Use `resolve_module` instead")]
252    fn load_command_module(
253        &self,
254        cmd: &BinaryPackageCommand,
255    ) -> BoxFuture<'_, Result<Module, SpawnError>> {
256        self.resolve_module(ModuleInput::Command(Cow::Owned(cmd.clone())), None, None)
257    }
258
259    /// Sync version of [`Self::load_command_module`].
260    #[deprecated(since = "0.601.0", note = "Use `resolve_module_sync` instead")]
261    fn load_command_module_sync(&self, cmd: &BinaryPackageCommand) -> Result<Module, SpawnError> {
262        block_on(self.resolve_module(ModuleInput::Command(Cow::Borrowed(cmd)), None, None))
263    }
264
265    /// Load a WebAssembly module from raw bytes.
266    ///
267    /// Will load the module from the cache if possible, otherwise will compile.
268    #[deprecated(since = "0.601.0", note = "Use `resolve_module` instead")]
269    fn load_module<'a>(&'a self, wasm: &'a [u8]) -> BoxFuture<'a, Result<Module, SpawnError>> {
270        self.resolve_module(ModuleInput::Bytes(Cow::Borrowed(wasm)), None, None)
271    }
272
273    /// Synchronous version of [`Self::load_module`].
274    #[deprecated(
275        since = "0.601.0",
276        note = "Use `load_command_module` or `load_hashed_module` instead - this method can have high overhead"
277    )]
278    fn load_module_sync(&self, wasm: &[u8]) -> Result<Module, SpawnError> {
279        block_on(self.resolve_module(ModuleInput::Bytes(Cow::Borrowed(wasm)), None, None))
280    }
281
282    /// Load a WebAssembly module from pre-hashed data.
283    ///
284    /// Will load the module from the cache if possible, otherwise will compile.
285    fn load_hashed_module(
286        &self,
287        module: HashedModuleData,
288        engine: Option<&Engine>,
289    ) -> BoxFuture<'_, Result<Module, SpawnError>> {
290        self.resolve_module(ModuleInput::Hashed(Cow::Owned(module)), engine, None)
291    }
292
293    /// Synchronous version of [`Self::load_hashed_module`].
294    fn load_hashed_module_sync(
295        &self,
296        wasm: HashedModuleData,
297        engine: Option<&Engine>,
298    ) -> Result<Module, SpawnError> {
299        block_on(self.resolve_module(ModuleInput::Hashed(Cow::Owned(wasm)), engine, None))
300    }
301
302    /// Callback thats invokes whenever the instance is tainted, tainting can occur
303    /// for multiple reasons however the most common is a panic within the process
304    fn on_taint(&self, _reason: TaintReason) {}
305
306    /// The list of all read-only journals which will be used to restore the state of the
307    /// runtime at a particular point in time
308    #[cfg(feature = "journal")]
309    fn read_only_journals<'a>(&'a self) -> Box<dyn Iterator<Item = Arc<DynReadableJournal>> + 'a> {
310        Box::new(std::iter::empty())
311    }
312
313    /// The list of writable journals which will be appended to
314    #[cfg(feature = "journal")]
315    fn writable_journals<'a>(&'a self) -> Box<dyn Iterator<Item = Arc<DynJournal>> + 'a> {
316        Box::new(std::iter::empty())
317    }
318
319    /// The snapshot capturer takes and restores snapshots of the WASM process at specific
320    /// points in time by reading and writing log entries
321    #[cfg(feature = "journal")]
322    fn active_journal(&self) -> Option<&'_ DynJournal> {
323        None
324    }
325}
326
327pub type DynRuntime = dyn Runtime + Send + Sync;
328
329/// Load a a Webassembly module, trying to use a pre-compiled version if possible.
330///
331// This function exists to provide a reusable baseline implementation for
332// implementing [`Runtime::load_module`], so custom logic can be added on top.
333#[tracing::instrument(level = "debug", skip_all)]
334pub async fn load_module(
335    engine: &Engine,
336    module_cache: &(dyn ModuleCache + Send + Sync),
337    input: ModuleInput<'_>,
338    on_progress: Option<ModuleLoadProgressReporter>,
339) -> Result<Module, crate::SpawnError> {
340    let wasm_hash = input.hash();
341
342    let result = if let Some(on_progress) = &on_progress {
343        module_cache
344            .load_with_progress(wasm_hash, engine, on_progress.clone())
345            .await
346    } else {
347        module_cache.load(wasm_hash, engine).await
348    };
349
350    match result {
351        Ok(module) => return Ok(module),
352        Err(CacheError::NotFound) => {}
353        Err(other) => {
354            tracing::warn!(
355                %wasm_hash,
356                error=&other as &dyn std::error::Error,
357                "Unable to load the cached module",
358            );
359        }
360    }
361
362    let res = if let Some(progress) = on_progress {
363        #[allow(unused_variables)]
364        let p = CompilationProgressCallback::new(move |p| {
365            progress.notify(ModuleLoadProgress::CompilingModule(p))
366        });
367        #[cfg(feature = "sys-default")]
368        {
369            use wasmer::sys::NativeEngineExt;
370            engine.new_module_with_progress(input.wasm(), p)
371        }
372        #[cfg(not(feature = "sys-default"))]
373        {
374            Module::new(&engine, input.wasm())
375        }
376    } else {
377        Module::new(&engine, input.wasm())
378    };
379
380    let module = res.map_err(|err| crate::SpawnError::CompileError {
381        module_hash: wasm_hash,
382        error: err,
383    })?;
384
385    // TODO: pass a [`HashedModule`] struct that is safe by construction.
386    if let Err(e) = module_cache.save(wasm_hash, engine, &module).await {
387        tracing::warn!(
388            %wasm_hash,
389            error=&e as &dyn std::error::Error,
390            "Unable to cache the compiled module",
391        );
392    }
393
394    Ok(module)
395}
396
397#[derive(Debug, Default)]
398pub struct DefaultTty {
399    state: Mutex<WasiTtyState>,
400}
401
402impl TtyBridge for DefaultTty {
403    fn reset(&self) {
404        let mut state = self.state.lock().unwrap();
405        state.echo = false;
406        state.line_buffered = false;
407        state.line_feeds = false
408    }
409
410    fn tty_get(&self) -> WasiTtyState {
411        let state = self.state.lock().unwrap();
412        state.clone()
413    }
414
415    fn tty_set(&self, tty_state: WasiTtyState) {
416        let mut state = self.state.lock().unwrap();
417        *state = tty_state;
418    }
419}
420
421#[derive(Debug, Clone)]
422pub struct PluggableRuntime {
423    pub rt: Arc<dyn VirtualTaskManager>,
424    pub networking: DynVirtualNetworking,
425    pub http_client: Option<DynHttpClient>,
426    pub package_loader: Arc<dyn PackageLoader + Send + Sync>,
427    pub source: Arc<dyn Source + Send + Sync>,
428    pub engine: Engine,
429    pub module_cache: Arc<dyn ModuleCache + Send + Sync>,
430    pub tty: Option<Arc<dyn TtyBridge + Send + Sync>>,
431    #[cfg(feature = "journal")]
432    pub read_only_journals: Vec<Arc<DynReadableJournal>>,
433    #[cfg(feature = "journal")]
434    pub writable_journals: Vec<Arc<DynJournal>>,
435}
436
437impl PluggableRuntime {
438    pub fn new(rt: Arc<dyn VirtualTaskManager>) -> Self {
439        // TODO: the cfg flags below should instead be handled by separate implementations.
440        cfg_if::cfg_if! {
441            if #[cfg(feature = "host-vnet")] {
442                let networking = Arc::new(virtual_net::host::LocalNetworking::default());
443            } else {
444                let networking = Arc::new(virtual_net::UnsupportedVirtualNetworking::default());
445            }
446        }
447        let http_client =
448            crate::http::default_http_client().map(|client| Arc::new(client) as DynHttpClient);
449
450        let loader = UnsupportedPackageLoader;
451
452        let mut source = MultiSource::default();
453        if let Some(client) = &http_client {
454            source.add_source(BackendSource::new(
455                BackendSource::WASMER_PROD_ENDPOINT.parse().unwrap(),
456                client.clone(),
457            ));
458        }
459
460        Self {
461            rt,
462            networking,
463            http_client,
464            engine: Default::default(),
465            tty: None,
466            source: Arc::new(source),
467            package_loader: Arc::new(loader),
468            module_cache: Arc::new(module_cache::in_memory()),
469            #[cfg(feature = "journal")]
470            read_only_journals: Vec::new(),
471            #[cfg(feature = "journal")]
472            writable_journals: Vec::new(),
473        }
474    }
475
476    pub fn set_networking_implementation<I>(&mut self, net: I) -> &mut Self
477    where
478        I: VirtualNetworking + Sync,
479    {
480        self.networking = Arc::new(net);
481        self
482    }
483
484    pub fn set_engine(&mut self, engine: Engine) -> &mut Self {
485        self.engine = engine;
486        self
487    }
488
489    pub fn set_tty(&mut self, tty: Arc<dyn TtyBridge + Send + Sync>) -> &mut Self {
490        self.tty = Some(tty);
491        self
492    }
493
494    pub fn set_module_cache(
495        &mut self,
496        module_cache: impl ModuleCache + Send + Sync + 'static,
497    ) -> &mut Self {
498        self.module_cache = Arc::new(module_cache);
499        self
500    }
501
502    pub fn set_source(&mut self, source: impl Source + Send + 'static) -> &mut Self {
503        self.source = Arc::new(source);
504        self
505    }
506
507    pub fn set_package_loader(
508        &mut self,
509        package_loader: impl PackageLoader + 'static,
510    ) -> &mut Self {
511        self.package_loader = Arc::new(package_loader);
512        self
513    }
514
515    pub fn set_http_client(
516        &mut self,
517        client: impl HttpClient + Send + Sync + 'static,
518    ) -> &mut Self {
519        self.http_client = Some(Arc::new(client));
520        self
521    }
522
523    #[cfg(feature = "journal")]
524    pub fn add_read_only_journal(&mut self, journal: Arc<DynReadableJournal>) -> &mut Self {
525        self.read_only_journals.push(journal);
526        self
527    }
528
529    #[cfg(feature = "journal")]
530    pub fn add_writable_journal(&mut self, journal: Arc<DynJournal>) -> &mut Self {
531        self.writable_journals.push(journal);
532        self
533    }
534}
535
536impl Runtime for PluggableRuntime {
537    fn networking(&self) -> &DynVirtualNetworking {
538        &self.networking
539    }
540
541    fn http_client(&self) -> Option<&DynHttpClient> {
542        self.http_client.as_ref()
543    }
544
545    fn package_loader(&self) -> Arc<dyn PackageLoader + Send + Sync> {
546        Arc::clone(&self.package_loader)
547    }
548
549    fn source(&self) -> Arc<dyn Source + Send + Sync> {
550        Arc::clone(&self.source)
551    }
552
553    fn engine(&self) -> Engine {
554        self.engine.clone()
555    }
556
557    fn new_store(&self) -> wasmer::Store {
558        wasmer::Store::new(self.engine.clone())
559    }
560
561    fn task_manager(&self) -> &Arc<dyn VirtualTaskManager> {
562        &self.rt
563    }
564
565    fn tty(&self) -> Option<&(dyn TtyBridge + Send + Sync)> {
566        self.tty.as_deref()
567    }
568
569    fn module_cache(&self) -> Arc<dyn ModuleCache + Send + Sync> {
570        self.module_cache.clone()
571    }
572
573    #[cfg(feature = "journal")]
574    fn read_only_journals<'a>(&'a self) -> Box<dyn Iterator<Item = Arc<DynReadableJournal>> + 'a> {
575        Box::new(self.read_only_journals.iter().cloned())
576    }
577
578    #[cfg(feature = "journal")]
579    fn writable_journals<'a>(&'a self) -> Box<dyn Iterator<Item = Arc<DynJournal>> + 'a> {
580        Box::new(self.writable_journals.iter().cloned())
581    }
582
583    #[cfg(feature = "journal")]
584    fn active_journal(&self) -> Option<&DynJournal> {
585        self.writable_journals.iter().last().map(|a| a.as_ref())
586    }
587}
588
589/// Runtime that allows for certain things to be overridden
590/// such as the active journals
591#[derive(Clone, Debug)]
592pub struct OverriddenRuntime {
593    inner: Arc<DynRuntime>,
594    task_manager: Option<Arc<dyn VirtualTaskManager>>,
595    networking: Option<DynVirtualNetworking>,
596    http_client: Option<DynHttpClient>,
597    package_loader: Option<Arc<dyn PackageLoader + Send + Sync>>,
598    source: Option<Arc<dyn Source + Send + Sync>>,
599    engine: Option<Engine>,
600    module_cache: Option<Arc<dyn ModuleCache + Send + Sync>>,
601    tty: Option<Arc<dyn TtyBridge + Send + Sync>>,
602    #[cfg(feature = "journal")]
603    pub read_only_journals: Option<Vec<Arc<DynReadableJournal>>>,
604    #[cfg(feature = "journal")]
605    pub writable_journals: Option<Vec<Arc<DynJournal>>>,
606}
607
608impl OverriddenRuntime {
609    pub fn new(inner: Arc<DynRuntime>) -> Self {
610        Self {
611            inner,
612            task_manager: None,
613            networking: None,
614            http_client: None,
615            package_loader: None,
616            source: None,
617            engine: None,
618            module_cache: None,
619            tty: None,
620            #[cfg(feature = "journal")]
621            read_only_journals: None,
622            #[cfg(feature = "journal")]
623            writable_journals: None,
624        }
625    }
626
627    pub fn with_task_manager(mut self, task_manager: Arc<dyn VirtualTaskManager>) -> Self {
628        self.task_manager.replace(task_manager);
629        self
630    }
631
632    pub fn with_networking(mut self, networking: DynVirtualNetworking) -> Self {
633        self.networking.replace(networking);
634        self
635    }
636
637    pub fn with_http_client(mut self, http_client: DynHttpClient) -> Self {
638        self.http_client.replace(http_client);
639        self
640    }
641
642    pub fn with_package_loader(
643        mut self,
644        package_loader: Arc<dyn PackageLoader + Send + Sync>,
645    ) -> Self {
646        self.package_loader.replace(package_loader);
647        self
648    }
649
650    pub fn with_source(mut self, source: Arc<dyn Source + Send + Sync>) -> Self {
651        self.source.replace(source);
652        self
653    }
654
655    pub fn with_engine(mut self, engine: Engine) -> Self {
656        self.engine.replace(engine);
657        self
658    }
659
660    pub fn with_module_cache(mut self, module_cache: Arc<dyn ModuleCache + Send + Sync>) -> Self {
661        self.module_cache.replace(module_cache);
662        self
663    }
664
665    pub fn with_tty(mut self, tty: Arc<dyn TtyBridge + Send + Sync>) -> Self {
666        self.tty.replace(tty);
667        self
668    }
669
670    #[cfg(feature = "journal")]
671    pub fn with_read_only_journals(mut self, journals: Vec<Arc<DynReadableJournal>>) -> Self {
672        self.read_only_journals.replace(journals);
673        self
674    }
675
676    #[cfg(feature = "journal")]
677    pub fn with_writable_journals(mut self, journals: Vec<Arc<DynJournal>>) -> Self {
678        self.writable_journals.replace(journals);
679        self
680    }
681}
682
683impl Runtime for OverriddenRuntime {
684    fn networking(&self) -> &DynVirtualNetworking {
685        if let Some(net) = self.networking.as_ref() {
686            net
687        } else {
688            self.inner.networking()
689        }
690    }
691
692    fn task_manager(&self) -> &Arc<dyn VirtualTaskManager> {
693        if let Some(rt) = self.task_manager.as_ref() {
694            rt
695        } else {
696            self.inner.task_manager()
697        }
698    }
699
700    fn source(&self) -> Arc<dyn Source + Send + Sync> {
701        if let Some(source) = self.source.clone() {
702            source
703        } else {
704            self.inner.source()
705        }
706    }
707
708    fn package_loader(&self) -> Arc<dyn PackageLoader + Send + Sync> {
709        if let Some(loader) = self.package_loader.clone() {
710            loader
711        } else {
712            self.inner.package_loader()
713        }
714    }
715
716    fn module_cache(&self) -> Arc<dyn ModuleCache + Send + Sync> {
717        if let Some(cache) = self.module_cache.clone() {
718            cache
719        } else {
720            self.inner.module_cache()
721        }
722    }
723
724    fn engine(&self) -> Engine {
725        if let Some(engine) = self.engine.clone() {
726            engine
727        } else {
728            self.inner.engine()
729        }
730    }
731
732    fn new_store(&self) -> wasmer::Store {
733        if let Some(engine) = self.engine.clone() {
734            wasmer::Store::new(engine)
735        } else {
736            self.inner.new_store()
737        }
738    }
739
740    fn http_client(&self) -> Option<&DynHttpClient> {
741        if let Some(client) = self.http_client.as_ref() {
742            Some(client)
743        } else {
744            self.inner.http_client()
745        }
746    }
747
748    fn tty(&self) -> Option<&(dyn TtyBridge + Send + Sync)> {
749        if let Some(tty) = self.tty.as_ref() {
750            Some(tty.deref())
751        } else {
752            self.inner.tty()
753        }
754    }
755
756    #[cfg(feature = "journal")]
757    fn read_only_journals<'a>(&'a self) -> Box<dyn Iterator<Item = Arc<DynReadableJournal>> + 'a> {
758        if let Some(journals) = self.read_only_journals.as_ref() {
759            Box::new(journals.iter().cloned())
760        } else {
761            self.inner.read_only_journals()
762        }
763    }
764
765    #[cfg(feature = "journal")]
766    fn writable_journals<'a>(&'a self) -> Box<dyn Iterator<Item = Arc<DynJournal>> + 'a> {
767        if let Some(journals) = self.writable_journals.as_ref() {
768            Box::new(journals.iter().cloned())
769        } else {
770            self.inner.writable_journals()
771        }
772    }
773
774    #[cfg(feature = "journal")]
775    fn active_journal(&self) -> Option<&'_ DynJournal> {
776        if let Some(journals) = self.writable_journals.as_ref() {
777            journals.iter().last().map(|a| a.as_ref())
778        } else {
779            self.inner.active_journal()
780        }
781    }
782}