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}