Refine package API.

This commit is contained in:
Stephen Chung 2020-04-22 14:55:40 +08:00
parent c40c0a0bc3
commit 9a1c715aad
13 changed files with 147 additions and 36 deletions

View File

@ -597,18 +597,16 @@ impl Engine {
let result = func(args, pos)?; let result = func(args, pos)?;
// See if the function match print/debug (which requires special processing) // See if the function match print/debug (which requires special processing)
return match fn_name { return Ok(match fn_name {
KEYWORD_PRINT if self.on_print.is_some() => { KEYWORD_PRINT if self.on_print.is_some() => {
self.on_print.as_ref().unwrap()(cast_to_string(&result, pos)?); self.on_print.as_ref().unwrap()(cast_to_string(&result, pos)?).into()
Ok(().into())
} }
KEYWORD_DEBUG if self.on_debug.is_some() => { KEYWORD_DEBUG if self.on_debug.is_some() => {
self.on_debug.as_ref().unwrap()(cast_to_string(&result, pos)?); self.on_debug.as_ref().unwrap()(cast_to_string(&result, pos)?).into()
Ok(().into())
} }
KEYWORD_PRINT | KEYWORD_DEBUG => Ok(().into()), KEYWORD_PRINT | KEYWORD_DEBUG => ().into(),
_ => Ok(result), _ => result,
}; });
} }
if let Some(prop) = extract_prop_from_getter(fn_name) { if let Some(prop) = extract_prop_from_getter(fn_name) {

View File

@ -272,7 +272,7 @@ macro_rules! reg_op { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
$(reg_binary($lib, $op, $func::<$par>, map);)* }; $(reg_binary($lib, $op, $func::<$par>, map);)* };
} }
def_package!(ArithmeticPackage:"Basic arithmetic", lib, { def_package!(crate:ArithmeticPackage:"Basic arithmetic", lib, {
// Checked basic arithmetic // Checked basic arithmetic
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
{ {

View File

@ -37,7 +37,7 @@ macro_rules! reg_tri { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
} }
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
def_package!(BasicArrayPackage:"Basic array utilities.", lib, { def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, {
reg_op!(lib, "push", push, INT, bool, char, String, Array, ()); reg_op!(lib, "push", push, INT, bool, char, String, Array, ());
reg_tri!(lib, "pad", pad, INT, bool, char, String, Array, ()); reg_tri!(lib, "pad", pad, INT, bool, char, String, Array, ());
reg_tri!(lib, "insert", ins, INT, bool, char, String, Array, ()); reg_tri!(lib, "insert", ins, INT, bool, char, String, Array, ());
@ -71,7 +71,7 @@ def_package!(BasicArrayPackage:"Basic array utilities.", lib, {
reg_unary_mut( reg_unary_mut(
lib, lib,
"pop", "pop",
|list: &mut Array| list.pop().unwrap_or_else(|| Dynamic::from_unit()), |list: &mut Array| list.pop().unwrap_or_else(|| ().into()),
pass, pass,
); );
reg_unary_mut( reg_unary_mut(
@ -79,7 +79,7 @@ def_package!(BasicArrayPackage:"Basic array utilities.", lib, {
"shift", "shift",
|list: &mut Array| { |list: &mut Array| {
if !list.is_empty() { if !list.is_empty() {
Dynamic::from_unit() ().into()
} else { } else {
list.remove(0) list.remove(0)
} }
@ -91,7 +91,7 @@ def_package!(BasicArrayPackage:"Basic array utilities.", lib, {
"remove", "remove",
|list: &mut Array, len: INT| { |list: &mut Array, len: INT| {
if len < 0 || (len as usize) >= list.len() { if len < 0 || (len as usize) >= list.len() {
Dynamic::from_unit() ().into()
} else { } else {
list.remove(len as usize) list.remove(len as usize)
} }

View File

@ -75,7 +75,7 @@ where
); );
} }
def_package!(BasicIteratorPackage:"Basic range iterators.", lib, { def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
fn get_range<T>(from: T, to: T) -> Range<T> { fn get_range<T>(from: T, to: T) -> Range<T> {
from..to from..to
} }

View File

@ -40,7 +40,7 @@ macro_rules! reg_op { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
$(reg_binary($lib, $op, $func::<$par>, map);)* }; $(reg_binary($lib, $op, $func::<$par>, map);)* };
} }
def_package!(LogicPackage:"Logical operators.", lib, { def_package!(crate:LogicPackage:"Logical operators.", lib, {
reg_op!(lib, "<", lt, INT, char); reg_op!(lib, "<", lt, INT, char);
reg_op!(lib, "<=", lte, INT, char); reg_op!(lib, "<=", lte, INT, char);
reg_op!(lib, ">", gt, INT, char); reg_op!(lib, ">", gt, INT, char);

View File

@ -8,7 +8,7 @@ use crate::parser::INT;
fn map_get_keys(map: &mut Map) -> Vec<Dynamic> { fn map_get_keys(map: &mut Map) -> Vec<Dynamic> {
map.iter() map.iter()
.map(|(k, _)| Dynamic::from_string(k.to_string())) .map(|(k, _)| k.to_string().into())
.collect::<Vec<_>>() .collect::<Vec<_>>()
} }
fn map_get_values(map: &mut Map) -> Vec<Dynamic> { fn map_get_values(map: &mut Map) -> Vec<Dynamic> {
@ -16,7 +16,7 @@ fn map_get_values(map: &mut Map) -> Vec<Dynamic> {
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
def_package!(BasicMapPackage:"Basic object map utilities.", lib, { def_package!(crate:BasicMapPackage:"Basic object map utilities.", lib, {
reg_binary_mut( reg_binary_mut(
lib, lib,
"has", "has",
@ -28,7 +28,7 @@ def_package!(BasicMapPackage:"Basic object map utilities.", lib, {
reg_binary_mut( reg_binary_mut(
lib, lib,
"remove", "remove",
|x: &mut Map, name: String| x.remove(&name).unwrap_or_else(|| Dynamic::from_unit()), |x: &mut Map, name: String| x.remove(&name).unwrap_or_else(|| ().into()),
map, map,
); );
reg_binary_mut( reg_binary_mut(

View File

@ -16,7 +16,7 @@ pub const MAX_INT: INT = i32::MAX;
#[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i32"))]
pub const MAX_INT: INT = i64::MAX; pub const MAX_INT: INT = i64::MAX;
def_package!(BasicMathPackage:"Basic mathematic functions.", lib, { def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, {
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
{ {
// Advanced math functions // Advanced math functions

View File

@ -5,7 +5,7 @@ use super::string_basic::BasicStringPackage;
use crate::def_package; use crate::def_package;
def_package!(CorePackage:"_Core_ package containing basic facilities.", lib, { def_package!(crate:CorePackage:"_Core_ package containing basic facilities.", lib, {
ArithmeticPackage::init(lib); ArithmeticPackage::init(lib);
LogicPackage::init(lib); LogicPackage::init(lib);
BasicStringPackage::init(lib); BasicStringPackage::init(lib);

View File

@ -9,7 +9,7 @@ use super::time_basic::BasicTimePackage;
use crate::def_package; use crate::def_package;
def_package!(StandardPackage:"_Standard_ package containing all built-in features.", lib, { def_package!(crate:StandardPackage:"_Standard_ package containing all built-in features.", lib, {
CorePackage::init(lib); CorePackage::init(lib);
BasicMathPackage::init(lib); BasicMathPackage::init(lib);
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]

View File

@ -25,7 +25,7 @@ macro_rules! reg_op { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
$(reg_unary_mut($lib, $op, $func::<$par>, map);)* }; $(reg_unary_mut($lib, $op, $func::<$par>, map);)* };
} }
def_package!(BasicStringPackage:"Basic string utilities, including printing.", lib, { def_package!(crate:BasicStringPackage:"Basic string utilities, including printing.", lib, {
reg_op!(lib, KEYWORD_PRINT, to_string, INT, bool, char); reg_op!(lib, KEYWORD_PRINT, to_string, INT, bool, char);
reg_op!(lib, FUNC_TO_STRING, to_string, INT, bool, char); reg_op!(lib, FUNC_TO_STRING, to_string, INT, bool, char);

View File

@ -66,7 +66,7 @@ macro_rules! reg_op { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
$(reg_binary($lib, $op, $func::<$par>, map);)* }; $(reg_binary($lib, $op, $func::<$par>, map);)* };
} }
def_package!(MoreStringPackage:"Additional string utilities, including string building.", lib, { def_package!(crate:MoreStringPackage:"Additional string utilities, including string building.", lib, {
reg_op!(lib, "+", append, INT, bool, char); reg_op!(lib, "+", append, INT, bool, char);
reg_binary_mut(lib, "+", |x: &mut String, _: ()| x.clone(), map); reg_binary_mut(lib, "+", |x: &mut String, _: ()| x.clone(), map);

View File

@ -10,7 +10,7 @@ use crate::token::Position;
use crate::stdlib::time::Instant; use crate::stdlib::time::Instant;
def_package!(BasicTimePackage:"Basic timing utilities.", lib, { def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, {
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
{ {
// Register date/time functions // Register date/time functions

View File

@ -13,45 +13,49 @@ use crate::stdlib::{any::TypeId, boxed::Box};
/// Functions can be added to the package using a number of helper functions under the `packages` module, /// Functions can be added to the package using a number of helper functions under the `packages` module,
/// such as `reg_unary`, `reg_binary_mut`, `reg_trinary_mut` etc. /// such as `reg_unary`, `reg_binary_mut`, `reg_trinary_mut` etc.
/// ///
/// ```,ignore /// # Examples
///
/// ```
/// use rhai::Dynamic;
/// use rhai::def_package; /// use rhai::def_package;
/// use rhai::packages::reg_binary; /// use rhai::packages::reg_binary;
/// ///
/// fn add(x: i64, y: i64) { x + y } /// fn add(x: i64, y: i64) -> i64 { x + y }
/// ///
/// def_package!(MyPackage:"My super-duper package", lib, /// def_package!(rhai:MyPackage:"My super-duper package", lib,
/// { /// {
/// reg_binary(lib, "my_add", add, |v| Ok(v.into_dynamic())); /// reg_binary(lib, "my_add", add, |v, _| Ok(v.into()));
/// // ^^^^^^^^^^^^^^^^^^^^ /// // ^^^^^^^^^^^^^^^^^^^
/// // map into Result<Dynamic, EvalAltResult> /// // map into Result<Dynamic, Box<EvalAltResult>>
/// }); /// });
/// ``` /// ```
/// ///
/// The above defines a package named 'MyPackage' with a single function named 'my_add'. /// The above defines a package named 'MyPackage' with a single function named 'my_add'.
#[macro_export] #[macro_export]
macro_rules! def_package { macro_rules! def_package {
($package:ident : $comment:expr , $lib:ident , $block:stmt) => { ($root:ident : $package:ident : $comment:expr , $lib:ident , $block:stmt) => {
#[doc=$comment] #[doc=$comment]
pub struct $package(super::PackageLibrary); pub struct $package($root::packages::PackageLibrary);
impl crate::packages::Package for $package { impl $root::packages::Package for $package {
fn new() -> Self { fn new() -> Self {
let mut pkg = crate::packages::PackageStore::new(); let mut pkg = $root::packages::PackageStore::new();
Self::init(&mut pkg); Self::init(&mut pkg);
Self(pkg.into()) Self(pkg.into())
} }
fn get(&self) -> crate::packages::PackageLibrary { fn get(&self) -> $root::packages::PackageLibrary {
self.0.clone() self.0.clone()
} }
fn init($lib: &mut crate::packages::PackageStore) { fn init($lib: &mut $root::packages::PackageStore) {
$block $block
} }
} }
}; };
} }
/// Check whether the correct number of arguments is passed to the function.
fn check_num_args( fn check_num_args(
name: &str, name: &str,
num_args: usize, num_args: usize,
@ -73,6 +77,25 @@ fn check_num_args(
/// Add a function with no parameters to the package. /// Add a function with no parameters to the package.
/// ///
/// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`. /// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`.
///
/// # Examples
///
/// ```
/// use rhai::Dynamic;
/// use rhai::def_package;
/// use rhai::packages::reg_none;
///
/// fn get_answer() -> i64 { 42 }
///
/// def_package!(rhai:MyPackage:"My super-duper package", lib,
/// {
/// reg_none(lib, "my_answer", get_answer, |v, _| Ok(v.into()));
/// // ^^^^^^^^^^^^^^^^^^^
/// // map into Result<Dynamic, Box<EvalAltResult>>
/// });
/// ```
///
/// The above defines a package named 'MyPackage' with a single function named 'my_add_1'.
pub fn reg_none<R>( pub fn reg_none<R>(
lib: &mut PackageStore, lib: &mut PackageStore,
fn_name: &'static str, fn_name: &'static str,
@ -102,6 +125,25 @@ pub fn reg_none<R>(
/// Add a function with one parameter to the package. /// Add a function with one parameter to the package.
/// ///
/// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`. /// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`.
///
/// # Examples
///
/// ```
/// use rhai::Dynamic;
/// use rhai::def_package;
/// use rhai::packages::reg_unary;
///
/// fn add_1(x: i64) -> i64 { x + 1 }
///
/// def_package!(rhai:MyPackage:"My super-duper package", lib,
/// {
/// reg_unary(lib, "my_add_1", add_1, |v, _| Ok(v.into()));
/// // ^^^^^^^^^^^^^^^^^^^
/// // map into Result<Dynamic, Box<EvalAltResult>>
/// });
/// ```
///
/// The above defines a package named 'MyPackage' with a single function named 'my_add_1'.
pub fn reg_unary<T: Variant + Clone, R>( pub fn reg_unary<T: Variant + Clone, R>(
lib: &mut PackageStore, lib: &mut PackageStore,
fn_name: &'static str, fn_name: &'static str,
@ -136,6 +178,32 @@ pub fn reg_unary<T: Variant + Clone, R>(
/// Add a function with one mutable reference parameter to the package. /// Add a function with one mutable reference parameter to the package.
/// ///
/// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`. /// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`.
///
/// # Examples
///
/// ```
/// use rhai::{Dynamic, EvalAltResult};
/// use rhai::def_package;
/// use rhai::packages::reg_unary_mut;
///
/// fn inc(x: &mut i64) -> Result<Dynamic, Box<EvalAltResult>> {
/// if *x == 0 {
/// return Err("boo! zero cannot be incremented!".into())
/// }
/// *x += 1;
/// Ok(().into())
/// }
///
/// def_package!(rhai:MyPackage:"My super-duper package", lib,
/// {
/// reg_unary_mut(lib, "try_inc", inc, |r, _| r);
/// // ^^^^^^^^
/// // map into Result<Dynamic, Box<EvalAltResult>>
/// });
/// ```
///
/// The above defines a package named 'MyPackage' with a single fallible function named 'try_inc'
/// which takes a first argument of `&mut`, return a `Result<Dynamic, Box<EvalAltResult>>`.
pub fn reg_unary_mut<T: Variant + Clone, R>( pub fn reg_unary_mut<T: Variant + Clone, R>(
lib: &mut PackageStore, lib: &mut PackageStore,
fn_name: &'static str, fn_name: &'static str,
@ -207,6 +275,25 @@ pub(crate) fn reg_test<'a, A: Variant + Clone, B: Variant + Clone, X, R>(
/// Add a function with two parameters to the package. /// Add a function with two parameters to the package.
/// ///
/// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`. /// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`.
///
/// # Examples
///
/// ```
/// use rhai::Dynamic;
/// use rhai::def_package;
/// use rhai::packages::reg_binary;
///
/// fn add(x: i64, y: i64) -> i64 { x + y }
///
/// def_package!(rhai:MyPackage:"My super-duper package", lib,
/// {
/// reg_binary(lib, "my_add", add, |v, _| Ok(v.into()));
/// // ^^^^^^^^^^^^^^^^^^^
/// // map into Result<Dynamic, Box<EvalAltResult>>
/// });
/// ```
///
/// The above defines a package named 'MyPackage' with a single function named 'my_add'.
pub fn reg_binary<A: Variant + Clone, B: Variant + Clone, R>( pub fn reg_binary<A: Variant + Clone, B: Variant + Clone, R>(
lib: &mut PackageStore, lib: &mut PackageStore,
fn_name: &'static str, fn_name: &'static str,
@ -245,6 +332,32 @@ pub fn reg_binary<A: Variant + Clone, B: Variant + Clone, R>(
/// Add a function with two parameters (the first one being a mutable reference) to the package. /// Add a function with two parameters (the first one being a mutable reference) to the package.
/// ///
/// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`. /// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`.
///
/// # Examples
///
/// ```
/// use rhai::{Dynamic, EvalAltResult};
/// use rhai::def_package;
/// use rhai::packages::reg_binary_mut;
///
/// fn add(x: &mut i64, y: i64) -> Result<Dynamic, Box<EvalAltResult>> {
/// if y == 0 {
/// return Err("boo! cannot add zero!".into())
/// }
/// *x += y;
/// Ok(().into())
/// }
///
/// def_package!(rhai:MyPackage:"My super-duper package", lib,
/// {
/// reg_binary_mut(lib, "try_add", add, |r, _| r);
/// // ^^^^^^^^
/// // map into Result<Dynamic, Box<EvalAltResult>>
/// });
/// ```
///
/// The above defines a package named 'MyPackage' with a single fallible function named 'try_add'
/// which takes a first argument of `&mut`, return a `Result<Dynamic, Box<EvalAltResult>>`.
pub fn reg_binary_mut<A: Variant + Clone, B: Variant + Clone, R>( pub fn reg_binary_mut<A: Variant + Clone, B: Variant + Clone, R>(
lib: &mut PackageStore, lib: &mut PackageStore,
fn_name: &'static str, fn_name: &'static str,