1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//! Load Ruby and Rust sources into the VM.

use alloc::borrow::Cow;

#[cfg(feature = "std")]
type Path = std::path::Path;
#[cfg(not(feature = "std"))]
type Path = str;

use crate::file::File;

/// Load Ruby sources and Rust extensions into an interpreter.
#[allow(clippy::module_name_repetitions)]
pub trait LoadSources {
    /// Concrete type for interpreter.
    type Artichoke;

    /// Concrete type for errors returned from filesystem IO.
    type Error;

    /// Concrete type for errors returned by `File::require`.
    type Exception;

    /// Add a Rust extension hook to the virtual filesystem. A stub Ruby file is
    /// added to the filesystem and [`File::require`] will dynamically define
    /// Ruby items when invoked via `Kernel#require`.
    ///
    /// If `path` is a relative path, the Ruby source is added to the
    /// filesystem relative to `RUBY_LOAD_PATH`. If the path is absolute, the
    /// file is placed directly on the filesystem. Anscestor directories are
    /// created automatically.
    ///
    /// # Errors
    ///
    /// If the underlying filesystem is inaccessible, an error is returned.
    ///
    /// If writes to the underlying filesystem fail, an error is returned.
    fn def_file_for_type<P, T>(&mut self, path: P) -> Result<(), Self::Error>
    where
        P: AsRef<Path>,
        T: File<Artichoke = Self::Artichoke, Error = Self::Exception>;

    /// Add a Ruby source to the virtual filesystem.
    ///
    /// If `path` is a relative path, the Ruby source is added to the
    /// filesystem relative to `RUBY_LOAD_PATH`. If the path is absolute, the
    /// file is placed directly on the filesystem. Anscestor directories are
    /// created automatically.
    ///
    /// # Errors
    ///
    /// If the underlying filesystem is inaccessible, an error is returned.
    ///
    /// If writes to the underlying filesystem fail, an error is returned.
    fn def_rb_source_file<P, T>(&mut self, path: P, contents: T) -> Result<(), Self::Error>
    where
        P: AsRef<Path>,
        T: Into<Cow<'static, [u8]>>;

    /// Test for a source file at a path.
    ///
    /// Query the underlying virtual filesystem to check if `path` points to a
    /// source file.
    ///
    /// This function returns `false` if `path` does not exist in the virtual
    /// filesystem.
    ///
    /// # Errors
    ///
    /// If the underlying filesystem is inaccessible, an error is returned.
    fn source_is_file<P>(&self, path: P) -> Result<bool, Self::Error>
    where
        P: AsRef<Path>;

    /// Load source located at the given path.
    ///
    /// Query the underlying virtual filesystem for a source file and load it
    /// onto the interpreter. This loads files with the following steps:
    ///
    /// 1. Retrieve and execute the extension hook, if any.
    /// 2. Read file contents and [`eval`](crate::eval::Eval) them.
    ///
    /// If this function returns without error, the feature specified by `path`
    /// is loaded, but is not added to `$LOADED_FEATURES`. This function is
    /// equivalent to `Kernel#load`.
    ///
    /// # Errors
    ///
    /// If the underlying filesystem is inaccessible, an error is returned.
    ///
    /// If reads to the underlying filesystem fail, an error is returned.
    ///
    /// If `path` does not point to a source file, an error is returned.
    ///
    /// If the souce file at `path` has no contents, an error is returned.
    fn load_source<P>(&mut self, path: P) -> Result<bool, Self::Error>
    where
        P: AsRef<Path>;

    /// Require source located at the given path.
    ///
    /// Query the underlying virtual filesystem for a source file and require it
    /// onto the interpreter. This requires files with the following steps:
    ///
    /// 1. Retrieve and execute the extension hook, if any.
    /// 2. Read file contents and [`eval`](crate::eval::Eval) them.
    /// 3. Mark file as required and add to `$LOADED_FEATURES`.
    ///
    /// If this function returns without error, the feature specified by `path`
    /// is loaded and added to `$LOADED_FEATURES`. This function is equivalent
    /// to `Kernel#require`.
    ///
    /// # Errors
    ///
    /// If the underlying filesystem is inaccessible, an error is returned.
    ///
    /// If reads to the underlying filesystem fail, an error is returned.
    ///
    /// If `path` does not point to a source file, an error is returned.
    ///
    /// If the souce file at `path` has no contents, an error is returned.
    fn require_source<P>(&mut self, path: P) -> Result<bool, Self::Error>
    where
        P: AsRef<Path>;

    /// Retrieve file contents for a source file.
    ///
    /// Query the underlying virtual filesystem for the file contents of the
    /// source file at `path`.
    ///
    /// # Errors
    ///
    /// If the underlying filesystem is inaccessible, an error is returned.
    ///
    /// If reads to the underlying filesystem fail, an error is returned.
    ///
    /// If `path` does not point to a source file, an error is returned.
    fn read_source_file_contents<P>(&self, path: P) -> Result<Cow<'_, [u8]>, Self::Error>
    where
        P: AsRef<Path>;
}