rhai/api/
files.rs

1//! Module that defines the public file-based API of [`Engine`].
2#![cfg(not(feature = "no_std"))]
3#![cfg(any(not(target_family = "wasm"), not(target_os = "unknown")))]
4
5use crate::types::dynamic::Variant;
6use crate::{Engine, RhaiResultOf, Scope, AST, ERR};
7#[cfg(feature = "no_std")]
8use std::prelude::v1::*;
9use std::{
10    fs::File,
11    io::Read,
12    path::{Path, PathBuf},
13};
14
15impl Engine {
16    /// Read the contents of a file into a string.
17    fn read_file(path: impl AsRef<Path>) -> RhaiResultOf<String> {
18        let path = path.as_ref();
19
20        let mut f = File::open(path).map_err(|err| {
21            ERR::ErrorSystem(
22                format!("Cannot open script file '{}'", path.to_string_lossy()),
23                err.into(),
24            )
25        })?;
26
27        let mut contents = String::new();
28
29        f.read_to_string(&mut contents).map_err(|err| {
30            ERR::ErrorSystem(
31                format!("Cannot read script file '{}'", path.to_string_lossy()),
32                err.into(),
33            )
34        })?;
35
36        if contents.starts_with("#!") {
37            // Remove shebang
38            match contents.find('\n') {
39                Some(n) => {
40                    contents.drain(0..n).count();
41                }
42                None => contents.clear(),
43            }
44        };
45
46        Ok(contents)
47    }
48    /// Compile a script file into an [`AST`], which can be used later for evaluation.
49    ///
50    /// Not available under `no_std` or `WASM`.
51    ///
52    /// # Example
53    ///
54    /// ```no_run
55    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
56    /// use rhai::Engine;
57    ///
58    /// let engine = Engine::new();
59    ///
60    /// // Compile a script file to an AST and store it for later evaluation.
61    /// // Notice that a PathBuf is required which can easily be constructed from a string.
62    /// let ast = engine.compile_file("script.rhai".into())?;
63    ///
64    /// for _ in 0..42 {
65    ///     engine.eval_ast::<i64>(&ast)?;
66    /// }
67    /// # Ok(())
68    /// # }
69    /// ```
70    #[inline(always)]
71    pub fn compile_file(&self, path: PathBuf) -> RhaiResultOf<AST> {
72        self.compile_file_with_scope(&Scope::new(), path)
73    }
74    /// Compile a script file into an [`AST`] using own scope, which can be used later for evaluation.
75    ///
76    /// Not available under `no_std` or `WASM`.
77    ///
78    /// ## Constants Propagation
79    ///
80    /// If not [`OptimizationLevel::None`][crate::OptimizationLevel::None], constants defined within
81    /// the scope are propagated throughout the script _including_ functions.
82    ///
83    /// This allows functions to be optimized based on dynamic global constants.
84    ///
85    /// # Example
86    ///
87    /// ```no_run
88    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
89    /// # #[cfg(not(feature = "no_optimize"))]
90    /// # {
91    /// use rhai::{Engine, Scope, OptimizationLevel};
92    ///
93    /// let mut engine = Engine::new();
94    ///
95    /// // Create initialized scope
96    /// let mut scope = Scope::new();
97    /// scope.push_constant("x", 42_i64);   // 'x' is a constant
98    ///
99    /// // Compile a script to an AST and store it for later evaluation.
100    /// // Notice that a PathBuf is required which can easily be constructed from a string.
101    /// let ast = engine.compile_file_with_scope(&scope, "script.rhai".into())?;
102    ///
103    /// let result = engine.eval_ast::<i64>(&ast)?;
104    /// # }
105    /// # Ok(())
106    /// # }
107    /// ```
108    #[inline]
109    pub fn compile_file_with_scope(&self, scope: &Scope, path: PathBuf) -> RhaiResultOf<AST> {
110        Self::read_file(&path).and_then(|contents| {
111            let mut ast = self.compile_with_scope(scope, contents)?;
112            ast.set_source(path.to_string_lossy().as_ref());
113            Ok(ast)
114        })
115    }
116    /// Evaluate a script file, returning the result value or an error.
117    ///
118    /// Not available under `no_std` or `WASM`.
119    ///
120    /// # Example
121    ///
122    /// ```no_run
123    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
124    /// use rhai::Engine;
125    ///
126    /// let engine = Engine::new();
127    ///
128    /// // Notice that a PathBuf is required which can easily be constructed from a string.
129    /// let result = engine.eval_file::<i64>("script.rhai".into())?;
130    /// # Ok(())
131    /// # }
132    /// ```
133    #[inline]
134    pub fn eval_file<T: Variant + Clone>(&self, path: PathBuf) -> RhaiResultOf<T> {
135        Self::read_file(path).and_then(|contents| self.eval::<T>(&contents))
136    }
137    /// Evaluate a script file with own scope, returning the result value or an error.
138    ///
139    /// Not available under `no_std` or `WASM`.
140    ///
141    /// ## Constants Propagation
142    ///
143    /// If not [`OptimizationLevel::None`][crate::OptimizationLevel::None], constants defined within
144    /// the scope are propagated throughout the script _including_ functions.
145    ///
146    /// This allows functions to be optimized based on dynamic global constants.
147    ///
148    /// # Example
149    ///
150    /// ```no_run
151    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
152    /// use rhai::{Engine, Scope};
153    ///
154    /// let engine = Engine::new();
155    ///
156    /// // Create initialized scope
157    /// let mut scope = Scope::new();
158    /// scope.push("x", 42_i64);
159    ///
160    /// // Notice that a PathBuf is required which can easily be constructed from a string.
161    /// let result = engine.eval_file_with_scope::<i64>(&mut scope, "script.rhai".into())?;
162    /// # Ok(())
163    /// # }
164    /// ```
165    #[inline]
166    pub fn eval_file_with_scope<T: Variant + Clone>(
167        &self,
168        scope: &mut Scope,
169        path: PathBuf,
170    ) -> RhaiResultOf<T> {
171        Self::read_file(path).and_then(|contents| self.eval_with_scope(scope, &contents))
172    }
173    /// Evaluate a file.
174    ///
175    /// Not available under `no_std` or `WASM`.
176    ///
177    /// # Example
178    ///
179    /// ```no_run
180    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
181    /// use rhai::Engine;
182    ///
183    /// let engine = Engine::new();
184    ///
185    /// // Notice that a PathBuf is required which can easily be constructed from a string.
186    /// engine.run_file("script.rhai".into())?;
187    /// # Ok(())
188    /// # }
189    /// ```
190    #[inline]
191    pub fn run_file(&self, path: PathBuf) -> RhaiResultOf<()> {
192        Self::read_file(path).and_then(|contents| self.run(&contents))
193    }
194    /// Evaluate a file with own scope.
195    ///
196    /// Not available under `no_std` or `WASM`.
197    ///
198    /// ## Constants Propagation
199    ///
200    /// If not [`OptimizationLevel::None`][crate::OptimizationLevel::None], constants defined within
201    /// the scope are propagated throughout the script _including_ functions.
202    ///
203    /// This allows functions to be optimized based on dynamic global constants.
204    ///
205    /// # Example
206    ///
207    /// ```no_run
208    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
209    /// use rhai::{Engine, Scope};
210    ///
211    /// let engine = Engine::new();
212    ///
213    /// // Create initialized scope
214    /// let mut scope = Scope::new();
215    /// scope.push("x", 42_i64);
216    ///
217    /// // Notice that a PathBuf is required which can easily be constructed from a string.
218    /// engine.run_file_with_scope(&mut scope, "script.rhai".into())?;
219    /// # Ok(())
220    /// # }
221    /// ```
222    #[inline]
223    pub fn run_file_with_scope(&self, scope: &mut Scope, path: PathBuf) -> RhaiResultOf<()> {
224        Self::read_file(path).and_then(|contents| self.run_with_scope(scope, &contents))
225    }
226}
227
228/// Evaluate a script file, returning the result value or an error.
229///
230/// Not available under `no_std` or `WASM`.
231///
232/// # Example
233///
234/// ```no_run
235/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
236/// let result = rhai::eval_file::<i64>("script.rhai")?;
237/// # Ok(())
238/// # }
239/// ```
240#[inline]
241pub fn eval_file<T: Variant + Clone>(path: impl AsRef<Path>) -> RhaiResultOf<T> {
242    Engine::read_file(path).and_then(|contents| Engine::new().eval::<T>(&contents))
243}
244
245/// Evaluate a file.
246///
247/// Not available under `no_std` or `WASM`.
248///
249/// # Example
250///
251/// ```no_run
252/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
253/// rhai::run_file("script.rhai")?;
254/// # Ok(())
255/// # }
256/// ```
257#[inline]
258pub fn run_file(path: impl AsRef<Path>) -> RhaiResultOf<()> {
259    Engine::read_file(path).and_then(|contents| Engine::new().run(&contents))
260}