diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f4dbfef..9b532505 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,10 @@ New features * Using a script-defined function's name (in place of a variable) implicitly creates a function pointer to the function. +### Top-level functions + +* Crate-level functions `rhai::eval`, `rhai::run`, `rhai::eval_file`, `rhai::run_file` are added as convenient wrappers. + Enhancements ------------ diff --git a/src/api/build_type.rs b/src/api/build_type.rs index cf44e51e..02a5b3cd 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -1,12 +1,16 @@ -use core::marker::PhantomData; +//! Trait to build a custom type for use with [`Engine`]. +#![allow(deprecated)] use crate::{ func::SendSync, types::dynamic::Variant, Engine, Identifier, RegisterNativeFunction, RhaiResultOf, }; +use std::marker::PhantomData; +#[cfg(feature = "no_std")] +use std::prelude::v1::*; -/// Trait to build a custom type for use with the [`Engine`]. -/// i.e. register the type and its getters, setters, methods, etc... +/// Trait to build a custom type for use with an [`Engine`] +/// (i.e. register the type and its getters, setters, methods, etc.). /// /// # Example /// @@ -55,53 +59,47 @@ use crate::{ /// engine.eval::("let x = new_ts(); x.update(41); x")?, /// TestStruct { field: 42 } /// ); -/// /// # Ok(()) /// # } /// ``` +#[deprecated = "This trait is NOT deprecated, but it is considered volatile and may change in the future."] pub trait CustomType: Variant + Clone { /// Builds the custom type for use with the [`Engine`]. - /// i.e. register the type, getters, setters, methods, etc... + /// + /// Methods, property getters/setters, indexers etc. should be registered in this function. fn build(builder: TypeBuilder); } impl Engine { /// Build a custom type for use with the [`Engine`]. - /// i.e. register the type and its getters, setters, methods, etc... /// - /// See [`CustomType`]. + /// The custom type must implement [`CustomType`]. #[inline] - pub fn build_type(&mut self) -> &mut Self - where - T: CustomType, - { + pub fn build_type(&mut self) -> &mut Self { T::build(TypeBuilder::new(self)); self } } -/// Builder to build a custom type i.e. register this type and its getters, setters, methods, etc... +/// Builder to build a custom type for use with an [`Engine`]. /// /// The type is automatically registered when this builder is dropped. /// /// ## Pretty name -/// By default the type is registered with [`Engine::register_type`] i.e. without a pretty name. /// -/// To define a pretty name call `.with_name`, in this case [`Engine::register_type_with_name`] will be used. -pub struct TypeBuilder<'a, T> -where - T: Variant + Clone, -{ +/// By default the type is registered with [`Engine::register_type`] (i.e. without a pretty name). +/// +/// To define a pretty name, call [`with_name`][`TypeBuilder::with_name`], +/// to use [`Engine::register_type_with_name`] instead. +#[deprecated = "This type is NOT deprecated, but it is considered volatile and may change in the future."] +pub struct TypeBuilder<'a, T: Variant + Clone> { engine: &'a mut Engine, name: Option<&'static str>, _marker: PhantomData, } -impl<'a, T> TypeBuilder<'a, T> -where - T: Variant + Clone, -{ - #[inline] +impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { + #[inline(always)] fn new(engine: &'a mut Engine) -> Self { Self { engine, @@ -111,21 +109,16 @@ where } } -impl<'a, T> TypeBuilder<'a, T> -where - T: Variant + Clone, -{ +impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { /// Sets a pretty-print name for the `type_of` function. - #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] - #[inline] + #[inline(always)] pub fn with_name(&mut self, name: &'static str) -> &mut Self { self.name = Some(name); self } /// Register a custom function. - #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] - #[inline] + #[inline(always)] pub fn with_fn(&mut self, name: N, method: F) -> &mut Self where N: AsRef + Into, @@ -136,8 +129,7 @@ where } /// Register a custom fallible function. - #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] - #[inline] + #[inline(always)] pub fn with_result_fn(&mut self, name: N, method: F) -> &mut Self where N: AsRef + Into, @@ -149,17 +141,13 @@ where } #[cfg(not(feature = "no_object"))] -impl<'a, T> TypeBuilder<'a, T> -where - T: Variant + Clone, -{ +impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { /// Register a getter function. /// /// The function signature must start with `&mut self` and not `&self`. /// /// Not available under `no_object`. - #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] - #[inline] + #[inline(always)] pub fn with_get( &mut self, name: impl AsRef, @@ -174,8 +162,7 @@ where /// The function signature must start with `&mut self` and not `&self`. /// /// Not available under `no_object`. - #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] - #[inline] + #[inline(always)] pub fn with_get_result( &mut self, name: impl AsRef, @@ -188,8 +175,7 @@ where /// Register a setter function. /// /// Not available under `no_object`. - #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] - #[inline] + #[inline(always)] pub fn with_set( &mut self, name: impl AsRef, @@ -202,8 +188,7 @@ where /// Register a fallible setter function. /// /// Not available under `no_object`. - #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] - #[inline] + #[inline(always)] pub fn with_set_result( &mut self, name: impl AsRef, @@ -218,8 +203,7 @@ where /// All function signatures must start with `&mut self` and not `&self`. /// /// Not available under `no_object`. - #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] - #[inline] + #[inline(always)] pub fn with_get_set( &mut self, name: impl AsRef, @@ -232,17 +216,13 @@ where } #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] -impl<'a, T> TypeBuilder<'a, T> -where - T: Variant + Clone, -{ +impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { /// Register an index getter. /// /// The function signature must start with `&mut self` and not `&self`. /// /// Not available under both `no_index` and `no_object`. - #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] - #[inline] + #[inline(always)] pub fn with_indexer_get( &mut self, get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static, @@ -256,8 +236,7 @@ where /// The function signature must start with `&mut self` and not `&self`. /// /// Not available under both `no_index` and `no_object`. - #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] - #[inline] + #[inline(always)] pub fn with_indexer_get_result( &mut self, get_fn: impl Fn(&mut T, X) -> RhaiResultOf + SendSync + 'static, @@ -269,8 +248,7 @@ where /// Register an index setter. /// /// Not available under both `no_index` and `no_object`. - #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] - #[inline] + #[inline(always)] pub fn with_indexer_set( &mut self, set_fn: impl Fn(&mut T, X, V) + SendSync + 'static, @@ -282,8 +260,7 @@ where /// Register an fallible index setter. /// /// Not available under both `no_index` and `no_object`. - #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] - #[inline] + #[inline(always)] pub fn with_indexer_set_result( &mut self, set_fn: impl Fn(&mut T, X, V) -> RhaiResultOf<()> + SendSync + 'static, @@ -295,8 +272,7 @@ where /// Short-hand for registering both index getter and setter functions. /// /// Not available under both `no_index` and `no_object`. - #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] - #[inline] + #[inline(always)] pub fn with_indexer_get_set( &mut self, get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static, @@ -307,10 +283,7 @@ where } } -impl<'a, T> Drop for TypeBuilder<'a, T> -where - T: Variant + Clone, -{ +impl<'a, T: Variant + Clone> Drop for TypeBuilder<'a, T> { #[inline] fn drop(&mut self) { if let Some(name) = self.name { diff --git a/src/api/eval.rs b/src/api/eval.rs index cb351301..cfa24a8f 100644 --- a/src/api/eval.rs +++ b/src/api/eval.rs @@ -11,7 +11,7 @@ use std::any::type_name; use std::prelude::v1::*; impl Engine { - /// Evaluate a string. + /// Evaluate a string as a script, returning the result value or an error. /// /// # Example /// @@ -29,7 +29,7 @@ impl Engine { pub fn eval(&self, script: &str) -> RhaiResultOf { self.eval_with_scope(&mut Scope::new(), script) } - /// Evaluate a string with own scope. + /// Evaluate a string as a script with own scope, returning the result value or an error. /// /// ## Constants Propagation /// @@ -71,7 +71,7 @@ impl Engine { )?; self.eval_ast_with_scope(scope, &ast) } - /// Evaluate a string containing an expression. + /// Evaluate a string containing an expression, returning the result value or an error. /// /// # Example /// @@ -89,7 +89,7 @@ impl Engine { pub fn eval_expression(&self, script: &str) -> RhaiResultOf { self.eval_expression_with_scope(&mut Scope::new(), script) } - /// Evaluate a string containing an expression with own scope. + /// Evaluate a string containing an expression with own scope, returning the result value or an error. /// /// # Example /// @@ -130,7 +130,7 @@ impl Engine { self.eval_ast_with_scope(scope, &ast) } - /// Evaluate an [`AST`]. + /// Evaluate an [`AST`], returning the result value or an error. /// /// # Example /// @@ -152,7 +152,7 @@ impl Engine { pub fn eval_ast(&self, ast: &AST) -> RhaiResultOf { self.eval_ast_with_scope(&mut Scope::new(), ast) } - /// Evaluate an [`AST`] with own scope. + /// Evaluate an [`AST`] with own scope, returning the result value or an error. /// /// # Example /// @@ -162,9 +162,6 @@ impl Engine { /// /// let engine = Engine::new(); /// - /// // Compile a script to an AST and store it for later evaluation - /// let ast = engine.compile("x + 2")?; - /// /// // Create initialized scope /// let mut scope = Scope::new(); /// scope.push("x", 40_i64); @@ -209,7 +206,7 @@ impl Engine { ERR::ErrorMismatchOutputType(t, typ.into(), Position::NONE).into() }) } - /// Evaluate an [`AST`] with own scope. + /// Evaluate an [`AST`] with own scope, returning the result value or an error. #[inline] pub(crate) fn eval_ast_with_scope_raw<'a>( &self, @@ -274,3 +271,20 @@ impl Engine { self.eval_global_statements(scope, global, caches, statements, lib, level) } } + +/// Evaluate a string as a script, returning the result value or an error. +/// +/// # Example +/// +/// ``` +/// # fn main() -> Result<(), Box> { +/// let result: i64 = rhai::eval("40 + 2")?; +/// +/// assert_eq!(result, 42); +/// # Ok(()) +/// # } +/// ``` +#[inline(always)] +pub fn eval(script: &str) -> RhaiResultOf { + Engine::new().eval(script) +} diff --git a/src/api/files.rs b/src/api/files.rs index 28272345..9c452e0b 100644 --- a/src/api/files.rs +++ b/src/api/files.rs @@ -102,7 +102,7 @@ impl Engine { pub fn compile_file_with_scope(&self, scope: &Scope, path: PathBuf) -> RhaiResultOf { Self::read_file(path).and_then(|contents| Ok(self.compile_with_scope(scope, &contents)?)) } - /// Evaluate a script file. + /// Evaluate a script file, returning the result value or an error. /// /// Not available under `no_std` or `WASM`. /// @@ -123,7 +123,7 @@ impl Engine { pub fn eval_file(&self, path: PathBuf) -> RhaiResultOf { Self::read_file(path).and_then(|contents| self.eval::(&contents)) } - /// Evaluate a script file with own scope. + /// Evaluate a script file with own scope, returning the result value or an error. /// /// Not available under `no_std` or `WASM`. /// @@ -159,14 +159,28 @@ impl Engine { ) -> RhaiResultOf { Self::read_file(path).and_then(|contents| self.eval_with_scope(scope, &contents)) } - /// Evaluate a file, returning any error (if any). + /// Evaluate a file. /// /// Not available under `no_std` or `WASM`. + /// + /// # Example + /// + /// ```no_run + /// # fn main() -> Result<(), Box> { + /// use rhai::Engine; + /// + /// let engine = Engine::new(); + /// + /// // Notice that a PathBuf is required which can easily be constructed from a string. + /// engine.run_file("script.rhai".into())?; + /// # Ok(()) + /// # } + /// ``` #[inline] pub fn run_file(&self, path: PathBuf) -> RhaiResultOf<()> { Self::read_file(path).and_then(|contents| self.run(&contents)) } - /// Evaluate a file with own scope, returning any error (if any). + /// Evaluate a file with own scope. /// /// Not available under `no_std` or `WASM`. /// @@ -176,8 +190,66 @@ impl Engine { /// the scope are propagated throughout the script _including_ functions. /// /// This allows functions to be optimized based on dynamic global constants. + /// + /// # Example + /// + /// ```no_run + /// # fn main() -> Result<(), Box> { + /// use rhai::{Engine, Scope}; + /// + /// let engine = Engine::new(); + /// + /// // Create initialized scope + /// let mut scope = Scope::new(); + /// scope.push("x", 42_i64); + /// + /// // Notice that a PathBuf is required which can easily be constructed from a string. + /// engine.run_file_with_scope(&mut scope, "script.rhai".into())?; + /// # Ok(()) + /// # } + /// ``` #[inline] pub fn run_file_with_scope(&self, scope: &mut Scope, path: PathBuf) -> RhaiResultOf<()> { Self::read_file(path).and_then(|contents| self.run_with_scope(scope, &contents)) } } + +/// Evaluate a script file. +/// +/// Not available under `no_std` or `WASM`. +/// +/// # Example +/// +/// ```no_run +/// # fn main() -> Result<(), Box> { +/// // Notice that a PathBuf is required which can easily be constructed from a string. +/// let result: i64 = rhai::eval_file("script.rhai".into())?; +/// # Ok(()) +/// # } +/// ``` +#[inline] +pub fn eval_file(path: PathBuf) -> RhaiResultOf { + Engine::read_file(path).and_then(|contents| Engine::new().eval::(&contents)) +} + +/// Evaluate a file. +/// +/// Not available under `no_std` or `WASM`. +/// +/// # Example +/// +/// ```no_run +/// # fn main() -> Result<(), Box> { +/// use rhai::Engine; +/// +/// let engine = Engine::new(); +/// +/// // Notice that a PathBuf is required which can easily be constructed from a string. +/// rhai::run_file("script.rhai".into())?; +/// # Ok(()) +/// # } +/// ``` +#[inline] +pub fn run_file(path: PathBuf) -> RhaiResultOf<()> { + Engine::read_file(path).and_then(|contents| Engine::new().run(&contents)) +} diff --git a/src/api/run.rs b/src/api/run.rs index babb3295..c6bd0b54 100644 --- a/src/api/run.rs +++ b/src/api/run.rs @@ -7,18 +7,52 @@ use crate::{Engine, Module, RhaiResultOf, Scope, AST}; use std::prelude::v1::*; impl Engine { - /// Evaluate a script, returning any error (if any). + /// Evaluate a string as a script. + /// + /// # Example + /// + /// ``` + /// # fn main() -> Result<(), Box> { + /// use rhai::Engine; + /// + /// let engine = Engine::new(); + /// + /// engine.run("print(40 + 2);")?; + /// # Ok(()) + /// # } + /// ``` #[inline(always)] pub fn run(&self, script: &str) -> RhaiResultOf<()> { self.run_with_scope(&mut Scope::new(), script) } - /// Evaluate a script with own scope, returning any error (if any). + /// Evaluate a string as a script with own scope. /// /// ## Constants Propagation /// /// If not [`OptimizationLevel::None`][crate::OptimizationLevel::None], constants defined within - /// the scope are propagated throughout the script _including_ functions. This allows functions - /// to be optimized based on dynamic global constants. + /// the scope are propagated throughout the script _including_ functions. + /// + /// This allows functions to be optimized based on dynamic global constants. + /// + /// # Example + /// + /// ``` + /// # fn main() -> Result<(), Box> { + /// use rhai::{Engine, Scope}; + /// + /// let engine = Engine::new(); + /// + /// // Create initialized scope + /// let mut scope = Scope::new(); + /// scope.push("x", 40_i64); + /// + /// engine.run_with_scope(&mut scope, "x += 2; print(x);")?; + /// + /// // The variable in the scope is modified + /// assert_eq!(scope.get_value::("x").expect("variable x should exist"), 42); + /// # Ok(()) + /// # } + /// ``` #[inline] pub fn run_with_scope(&self, scope: &mut Scope, script: &str) -> RhaiResultOf<()> { let scripts = [script]; @@ -28,12 +62,53 @@ impl Engine { let ast = self.parse(&mut stream.peekable(), &mut state, self.optimization_level)?; self.run_ast_with_scope(scope, &ast) } - /// Evaluate an [`AST`], returning any error (if any). + /// Evaluate an [`AST`]. + /// + /// # Example + /// + /// ``` + /// # fn main() -> Result<(), Box> { + /// use rhai::Engine; + /// + /// let engine = Engine::new(); + /// + /// // Compile a script to an AST and store it for later evaluation + /// let ast = engine.compile("print(40 + 2);")?; + /// + /// // Evaluate it + /// engine.run_ast(&ast)?; + /// # Ok(()) + /// # } + /// ``` #[inline(always)] pub fn run_ast(&self, ast: &AST) -> RhaiResultOf<()> { self.run_ast_with_scope(&mut Scope::new(), ast) } - /// Evaluate an [`AST`] with own scope, returning any error (if any). + /// Evaluate an [`AST`] with own scope. + /// + /// # Example + /// + /// ``` + /// # fn main() -> Result<(), Box> { + /// use rhai::{Engine, Scope}; + /// + /// let engine = Engine::new(); + /// + /// // Create initialized scope + /// let mut scope = Scope::new(); + /// scope.push("x", 40_i64); + /// + /// // Compile a script to an AST and store it for later evaluation + /// let ast = engine.compile("x += 2; x")?; + /// + /// // Evaluate it + /// engine.run_ast_with_scope(&mut scope, &ast)?; + /// + /// // The variable in the scope is modified + /// assert_eq!(scope.get_value::("x").expect("variable x should exist"), 42); + /// # Ok(()) + /// # } + /// ``` #[inline] pub fn run_ast_with_scope(&self, scope: &mut Scope, ast: &AST) -> RhaiResultOf<()> { let caches = &mut Caches::new(); @@ -73,3 +148,18 @@ impl Engine { Ok(()) } } + +/// Evaluate a string as a script. +/// +/// # Example +/// +/// ``` +/// # fn main() -> Result<(), Box> { +/// rhai::run("print(40 + 2);")?; +/// # Ok(()) +/// # } +/// ``` +#[inline(always)] +pub fn run(script: &str) -> RhaiResultOf<()> { + Engine::new().run(script) +} diff --git a/src/lib.rs b/src/lib.rs index 875e1cad..715dd979 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -166,10 +166,12 @@ type ExclusiveRange = std::ops::Range; /// An inclusive integer range. type InclusiveRange = std::ops::RangeInclusive; -pub use api::{ - build_type::{CustomType, TypeBuilder}, - events::VarDefInfo, -}; +#[allow(deprecated)] +pub use api::build_type::{CustomType, TypeBuilder}; +#[cfg(not(feature = "no_std"))] +#[cfg(not(target_family = "wasm"))] +pub use api::files::{eval_file, run_file}; +pub use api::{eval::eval, events::VarDefInfo, run::run}; pub use ast::{FnAccess, AST}; pub use engine::{Engine, OP_CONTAINS, OP_EQUALS}; pub use eval::EvalContext; diff --git a/tests/build_type.rs b/tests/build_type.rs index 76d1bcac..9f8924d4 100644 --- a/tests/build_type.rs +++ b/tests/build_type.rs @@ -1,37 +1,38 @@ -use rhai::{CustomType, Engine, EvalAltResult, Position, TypeBuilder}; +#![cfg(not(feature = "no_object"))] +use rhai::{CustomType, Engine, EvalAltResult, Position, TypeBuilder, INT}; #[test] fn build_type() -> Result<(), Box> { #[derive(Debug, Clone, PartialEq)] struct Vec3 { - x: i64, - y: i64, - z: i64, + x: INT, + y: INT, + z: INT, } impl Vec3 { - fn new(x: i64, y: i64, z: i64) -> Self { + fn new(x: INT, y: INT, z: INT) -> Self { Self { x, y, z } } - fn get_x(&mut self) -> i64 { + fn get_x(&mut self) -> INT { self.x } - fn set_x(&mut self, x: i64) { + fn set_x(&mut self, x: INT) { self.x = x } - fn get_y(&mut self) -> i64 { + fn get_y(&mut self) -> INT { self.y } - fn set_y(&mut self, y: i64) { + fn set_y(&mut self, y: INT) { self.y = y } - fn get_z(&mut self) -> i64 { + fn get_z(&mut self) -> INT { self.z } - fn set_z(&mut self, z: i64) { + fn set_z(&mut self, z: INT) { self.z = z } - fn get_component(&mut self, idx: i64) -> Result> { + fn get_component(&mut self, idx: INT) -> Result> { match idx { 0 => Ok(self.x), 1 => Ok(self.y), @@ -51,8 +52,10 @@ fn build_type() -> Result<(), Box> { .with_fn("vec3", Self::new) .with_get_set("x", Self::get_x, Self::set_x) .with_get_set("y", Self::get_y, Self::set_y) - .with_get_set("z", Self::get_z, Self::set_z) - .with_indexer_get_result(Self::get_component); + .with_get_set("z", Self::get_z, Self::set_z); + + #[cfg(not(feature = "no_index"))] + builder.with_indexer_get_result(Self::get_component); } } @@ -61,55 +64,56 @@ fn build_type() -> Result<(), Box> { assert_eq!( engine.eval::( - r#" - let v = vec3(1, 2, 3); - v -"#, + " + let v = vec3(1, 2, 3); + v + ", )?, Vec3::new(1, 2, 3), ); assert_eq!( - engine.eval::( - r#" - let v = vec3(1, 2, 3); - v.x -"#, + engine.eval::( + " + let v = vec3(1, 2, 3); + v.x + ", )?, 1, ); assert_eq!( - engine.eval::( - r#" - let v = vec3(1, 2, 3); - v.y -"#, + engine.eval::( + " + let v = vec3(1, 2, 3); + v.y + ", )?, 2, ); assert_eq!( - engine.eval::( - r#" - let v = vec3(1, 2, 3); - v.z -"#, + engine.eval::( + " + let v = vec3(1, 2, 3); + v.z + ", )?, 3, ); + #[cfg(not(feature = "no_index"))] assert!(engine.eval::( - r#" - let v = vec3(1, 2, 3); - v.x == v[0] && v.y == v[1] && v.z == v[2] -"#, + " + let v = vec3(1, 2, 3); + v.x == v[0] && v.y == v[1] && v.z == v[2] + ", )?); assert_eq!( engine.eval::( - r#" - let v = vec3(1, 2, 3); - v.x = 5; - v.y = 6; - v.z = 7; - v -"#, + " + let v = vec3(1, 2, 3); + v.x = 5; + v.y = 6; + v.z = 7; + v + ", )?, Vec3::new(5, 6, 7), );