diff --git a/doc/src/language/arrays.md b/doc/src/language/arrays.md index 56706d86..1b654385 100644 --- a/doc/src/language/arrays.md +++ b/doc/src/language/arrays.md @@ -30,36 +30,36 @@ Built-in Functions The following methods (mostly defined in the [`BasicArrayPackage`][packages] but excluded if using a [raw `Engine`]) operate on arrays: -| Function | Parameter(s) | Description | -| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `push` | element to insert | inserts an element at the end | -| `append` | array to append | concatenates the second array to the end of the first | -| `+=` operator | 1) array
2) element to insert (not another array) | inserts an element at the end | -| `+=` operator | 1) array
2) array to append | concatenates the second array to the end of the first | -| `+` operator | 1) first array
2) second array | concatenates the first array with the second | -| `insert` | 1) element to insert
2) position, beginning if < 0, end if > length | inserts an element at a certain index | -| `pop` | _none_ | removes the last element and returns it ([`()`] if empty) | -| `shift` | _none_ | removes the first element and returns it ([`()`] if empty) | -| `extract` | 1) start position, beginning if < 0, end if > length,
2) _(optional)_ number of items to extract, none if < 0 | extracts a portion of the array into a new array | -| `remove` | index | removes an element at a particular index and returns it ([`()`] if the index is not valid) | -| `reverse` | _none_ | reverses the array | -| `len` method and property | _none_ | returns the number of elements | -| `pad` | 1) target length
2) element to pad | pads the array with an element to at least a specified length | -| `clear` | _none_ | empties the array | -| `truncate` | target length | cuts off the array at exactly a specified length (discarding all subsequent elements) | -| `chop` | target length | cuts off the head of the array, leaving the tail at exactly a specified length | -| `drain` | 1) [function pointer] to predicate (usually a [closure]),
2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | removes all items (returning them) that return `true` when called with the predicate function:
1st parameter: array item,
2nd parameter: _(optional)_ offset index | -| `drain` | 1) start position, beginning if < 0, end if > length,
2) number of items to remove, none if < 0 | removes a portion of the array, returning the removed items (not in original order) | -| `retain` | 1) [function pointer] to predicate (usually a [closure]),
2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | removes all items (returning them) that do not return `true` when called with the predicate function:
1st parameter: array item,
2nd parameter: _(optional)_ offset index | -| `retain` | 1) start position, beginning if < 0, end if > length,
2) number of items to retain, none if < 0 | retains a portion of the array, removes all other items and returning them (not in original order) | -| `splice` | 1) start position, beginning if < 0, end if > length,
2) number of items to remove, none if < 0,
3) array to insert | replaces a portion of the array with another (not necessarily of the same length as the replaced portion) | -| `filter` | [function pointer] to predicate (usually a [closure]) | constructs a new array with all items that return `true` when called with the predicate function:
1st parameter: array item,
2nd parameter: _(optional)_ offset index | -| `map` | [function pointer] to conversion function (usually a [closure]) | constructs a new array with all items mapped to the result of applying the conversion function:
1st parameter: array item,
2nd parameter: _(optional)_ offset index | -| `reduce` | 1) [function pointer] to accumulator function (usually a [closure]),
2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | reduces the array into a single value via the accumulator function:
1st parameter: accumulated value ([`()`] initially),
2nd parameter: array item,
3rd parameter: _(optional)_ offset index | -| `reduce_rev` | 1) [function pointer] to accumulator function (usually a [closure]),
2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | reduces the array (in reverse order) into a single value via the accumulator function:
1st parameter: accumulated value ([`()`] initially),
2nd parameter: array item,
3rd parameter: _(optional)_ offset index | -| `some` | [function pointer] to predicate (usually a [closure]) | returns `true` if any item returns `true` when called with the predicate function:
1st parameter: array item,
2nd parameter: _(optional)_ offset index | -| `all` | [function pointer] to predicate (usually a [closure]) | returns `true` if all items return `true` when called with the predicate function:
1st parameter: array item,
2nd parameter: _(optional)_ offset index | -| `sort` | [function pointer] to a comparison function (usually a [closure]) | sorts the array with a comparison function:
1st parameter: first item,
2nd parameter: second item,
return value: `INT` < 0 if first < second, > 0 if first > second, 0 if first == second | +| Function | Parameter(s) | Description | +| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `push` | element to insert | inserts an element at the end | +| `append` | array to append | concatenates the second array to the end of the first | +| `+=` operator | 1) array
2) element to insert (not another array) | inserts an element at the end | +| `+=` operator | 1) array
2) array to append | concatenates the second array to the end of the first | +| `+` operator | 1) first array
2) second array | concatenates the first array with the second | +| `insert` | 1) element to insert
2) position, beginning if < 0, end if > length | inserts an element at a certain index | +| `pop` | _none_ | removes the last element and returns it ([`()`] if empty) | +| `shift` | _none_ | removes the first element and returns it ([`()`] if empty) | +| `extract` | 1) start position, beginning if < 0, end if > length
2) _(optional)_ number of items to extract, none if < 0 | extracts a portion of the array into a new array | +| `remove` | index | removes an element at a particular index and returns it ([`()`] if the index is not valid) | +| `reverse` | _none_ | reverses the array | +| `len` method and property | _none_ | returns the number of elements | +| `pad` | 1) target length
2) element to pad | pads the array with an element to at least a specified length | +| `clear` | _none_ | empties the array | +| `truncate` | target length | cuts off the array at exactly a specified length (discarding all subsequent elements) | +| `chop` | target length | cuts off the head of the array, leaving the tail at exactly a specified length | +| `drain` | 1) [function pointer] to predicate (usually a [closure])
2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | removes all items (returning them) that return `true` when called with the predicate function:
1st parameter: array item
2nd parameter: _(optional)_ offset index | +| `drain` | 1) start position, beginning if < 0, end if > length
2) number of items to remove, none if < 0 | removes a portion of the array, returning the removed items (not in original order) | +| `retain` | 1) [function pointer] to predicate (usually a [closure])
2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | removes all items (returning them) that do not return `true` when called with the predicate function:
1st parameter: array item
2nd parameter: _(optional)_ offset index | +| `retain` | 1) start position, beginning if < 0, end if > length
2) number of items to retain, none if < 0 | retains a portion of the array, removes all other items and returning them (not in original order) | +| `splice` | 1) start position, beginning if < 0, end if > length
2) number of items to remove, none if < 0
3) array to insert | replaces a portion of the array with another (not necessarily of the same length as the replaced portion) | +| `filter` | [function pointer] to predicate (usually a [closure]) | constructs a new array with all items that return `true` when called with the predicate function:
1st parameter: array item
2nd parameter: _(optional)_ offset index | +| `map` | [function pointer] to conversion function (usually a [closure]) | constructs a new array with all items mapped to the result of applying the conversion function:
1st parameter: array item
2nd parameter: _(optional)_ offset index | +| `reduce` | 1) [function pointer] to accumulator function (usually a [closure])
2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | reduces the array into a single value via the accumulator function:
1st parameter: accumulated value ([`()`] initially)
2nd parameter: array item
3rd parameter: _(optional)_ offset index | +| `reduce_rev` | 1) [function pointer] to accumulator function (usually a [closure])
2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | reduces the array (in reverse order) into a single value via the accumulator function:
1st parameter: accumulated value ([`()`] initially)
2nd parameter: array item
3rd parameter: _(optional)_ offset index | +| `some` | [function pointer] to predicate (usually a [closure]) | returns `true` if any item returns `true` when called with the predicate function:
1st parameter: array item
2nd parameter: _(optional)_ offset index | +| `all` | [function pointer] to predicate (usually a [closure]) | returns `true` if all items return `true` when called with the predicate function:
1st parameter: array item
2nd parameter: _(optional)_ offset index | +| `sort` | [function pointer] to a comparison function (usually a [closure]) | sorts the array with a comparison function:
1st parameter: first item
2nd parameter: second item
return value: `INT` < 0 if first < second, > 0 if first > second, 0 if first == second | Use Custom Types With Arrays diff --git a/doc/src/language/fn-ptr.md b/doc/src/language/fn-ptr.md index acd301eb..00e9edac 100644 --- a/doc/src/language/fn-ptr.md +++ b/doc/src/language/fn-ptr.md @@ -226,7 +226,7 @@ engine.register_raw_fn("super_call", `FnPtr::call_dynamic` takes a parameter of type `NativeCallContext` which holds the _native call context_ of the particular call to a registered Rust function. -This type is normally provided by the [`Engine`] (e.g. when using `Engine::register_fn_raw`(../rust/register-raw.md)). +This type is normally provided by the [`Engine`] (e.g. when using [`Engine::register_fn_raw`](../rust/register-raw.md)). However, it may also be manually constructed from a tuple: ```rust diff --git a/doc/src/language/string-fn.md b/doc/src/language/string-fn.md index 00efd8e1..db3d8b88 100644 --- a/doc/src/language/string-fn.md +++ b/doc/src/language/string-fn.md @@ -9,7 +9,7 @@ using a [raw `Engine`]) operate on [strings]: | Function | Parameter(s) | Description | | ------------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `len` method and property | _none_ | returns the number of characters (not number of bytes) in the string | -| `pad` | 1) character to pad
2) target length | pads the string with an character to at least a specified length | +| `pad` | 1) target length
2) character/string to pad | pads the string with a character or a string to at least a specified length | | `+=` operator, `append` | character/string to append | Adds a character or a string to the end of another string | | `clear` | _none_ | empties the string | | `truncate` | target length | cuts off the string at exactly a specified number of characters | diff --git a/doc/src/plugins/function.md b/doc/src/plugins/function.md index 904d56be..bd31de0c 100644 --- a/doc/src/plugins/function.md +++ b/doc/src/plugins/function.md @@ -102,9 +102,10 @@ as a parameter to the function, thereby implementing a _callback_: use rhai::{Dynamic, FnPtr, NativeCallContext, EvalAltResult}; use rhai::plugin::*; // a "prelude" import for macros -#[export_fn(return_raw)] +#[export_fn] +#[rhai_fn(return_raw)] pub fn greet(context: NativeCallContext, callback: FnPtr) - -> Result> + -> Result> { // Call the callback closure with the current context // to obtain the name to greet! @@ -116,15 +117,16 @@ pub fn greet(context: NativeCallContext, callback: FnPtr) The native call context is also useful in another scenario: protecting a function from malicious scripts. ```rust -use rhai::{Dynamic, INT, Array, NativeCallContext, EvalAltResult, Position}; +use rhai::{Dynamic, Array, NativeCallContext, EvalAltResult, Position}; use rhai::plugin::*; // a "prelude" import for macros // This function builds an array of arbitrary size, but is protected // against attacks by first checking with the allowed limit set // into the 'Engine'. -#[export_fn(return_raw)] -pub fn grow(context: NativeCallContext, size: INT) - -> Result> +#[export_fn] +#[rhai_fn(return_raw)] +pub fn grow(context: NativeCallContext, size: i64) + -> Result> { // Make sure the function does not generate a // data structure larger than the allowed limit diff --git a/doc/src/plugins/module.md b/doc/src/plugins/module.md index aeaeeb58..81195d47 100644 --- a/doc/src/plugins/module.md +++ b/doc/src/plugins/module.md @@ -363,7 +363,7 @@ use rhai::plugin::*; // a "prelude" import for macros mod my_module { #[rhai_fn(return_raw)] pub fn greet(context: NativeCallContext, callback: FnPtr) - -> Result> + -> Result> { // Call the callback closure with the current context // to obtain the name to greet! @@ -376,7 +376,7 @@ mod my_module { The native call context is also useful in another scenario: protecting a function from malicious scripts. ```rust -use rhai::{Dynamic, INT, Array, NativeCallContext, EvalAltResult, Position}; +use rhai::{Dynamic, Array, NativeCallContext, EvalAltResult, Position}; use rhai::plugin::*; // a "prelude" import for macros #[export_module] @@ -385,8 +385,8 @@ mod my_module { // against attacks by first checking with the allowed limit set // into the 'Engine'. #[rhai_fn(return_raw)] - pub fn grow(context: NativeCallContext, size: INT) - -> Result> + pub fn grow(context: NativeCallContext, size: i64) + -> Result> { // Make sure the function does not generate a // data structure larger than the allowed limit diff --git a/doc/src/rust/register-raw.md b/doc/src/rust/register-raw.md index 78990e1c..dc4e3ca2 100644 --- a/doc/src/rust/register-raw.md +++ b/doc/src/rust/register-raw.md @@ -60,7 +60,8 @@ Function Signature The function signature passed to `Engine::register_raw_fn` takes the following form: -> `Fn(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> + 'static` +> `Fn(context: NativeCallContext, args: &mut [&mut Dynamic])` +> `-> Result> + 'static` where: diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index 1a311b5d..cd71fd41 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -58,54 +58,6 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str combine_with_exported_module!(lib, "string", string_functions); - lib.set_raw_fn( - "pad", - &[TypeId::of::(), TypeId::of::(), TypeId::of::()], - |_context, args| { - let len = *args[1].read_lock::().unwrap(); - - // Check if string will be over max size limit - #[cfg(not(feature = "unchecked"))] - if _context.engine().max_string_size() > 0 && len > 0 - && (len as usize) > _context.engine().max_string_size() - { - return EvalAltResult::ErrorDataTooLarge( - "Length of string".to_string(), - _context.engine().max_string_size(), - len as usize, - Position::none(), - ).into(); - } - - if len > 0 { - let ch = mem::take(args[2]).cast::(); - let mut s = args[0].write_lock::().unwrap(); - - let orig_len = s.chars().count(); - - if len as usize > orig_len { - let p = s.make_mut(); - - for _ in 0..(len as usize - orig_len) { - p.push(ch); - } - - #[cfg(not(feature = "unchecked"))] - if _context.engine().max_string_size() > 0 && s.len() > _context.engine().max_string_size() { - return EvalAltResult::ErrorDataTooLarge( - "Length of string".to_string(), - _context.engine().max_string_size(), - s.len(), - Position::none(), - ).into(); - } - } - } - - Ok(()) - }, - ); - // Register string iterator lib.set_iter( TypeId::of::(), @@ -176,7 +128,7 @@ mod string_functions { pub fn index_of_char_starting_from(s: &str, ch: char, start: INT) -> INT { let start = if start < 0 { 0 - } else if (start as usize) >= s.chars().count() { + } else if start as usize >= s.chars().count() { return -1 as INT; } else { s.chars().take(start as usize).collect::().len() @@ -197,7 +149,7 @@ mod string_functions { pub fn index_of_string_starting_from(s: &str, find: ImmutableString, start: INT) -> INT { let start = if start < 0 { 0 - } else if (start as usize) >= s.chars().count() { + } else if start as usize >= s.chars().count() { return -1 as INT; } else { s.chars().take(start as usize).collect::().len() @@ -220,7 +172,7 @@ mod string_functions { return "".to_string().into(); } else if start < 0 { 0 - } else if (start as usize) >= s.chars().count() { + } else if start as usize >= s.chars().count() { return "".to_string().into(); } else { start as usize @@ -228,7 +180,7 @@ mod string_functions { let chars: StaticVec<_> = s.chars().collect(); - let len = if offset + (len as usize) > chars.len() { + let len = if offset + len as usize > chars.len() { chars.len() - offset } else { len as usize @@ -255,7 +207,7 @@ mod string_functions { return; } else if start < 0 { 0 - } else if (start as usize) >= s.chars().count() { + } else if start as usize >= s.chars().count() { s.make_mut().clear(); return; } else { @@ -264,7 +216,7 @@ mod string_functions { let chars: StaticVec<_> = s.chars().collect(); - let len = if offset + (len as usize) > chars.len() { + let len = if offset + len as usize > chars.len() { chars.len() - offset } else { len as usize @@ -295,6 +247,104 @@ mod string_functions { pub fn replace_char(s: &mut ImmutableString, find: char, sub: char) { *s = s.replace(&find.to_string(), &sub.to_string()).into(); } + #[rhai_fn(return_raw)] + pub fn pad( + _context: NativeCallContext, + s: &mut ImmutableString, + len: INT, + ch: char, + ) -> Result> { + // Check if string will be over max size limit + #[cfg(not(feature = "unchecked"))] + if _context.engine().max_string_size() > 0 + && len as usize > _context.engine().max_string_size() + { + return EvalAltResult::ErrorDataTooLarge( + "Length of string".to_string(), + _context.engine().max_string_size(), + len as usize, + Position::none(), + ) + .into(); + } + + if len > 0 { + let orig_len = s.chars().count(); + + if len as usize > orig_len { + let p = s.make_mut(); + + for _ in 0..(len as usize - orig_len) { + p.push(ch); + } + + #[cfg(not(feature = "unchecked"))] + if _context.engine().max_string_size() > 0 + && s.len() > _context.engine().max_string_size() + { + return EvalAltResult::ErrorDataTooLarge( + "Length of string".to_string(), + _context.engine().max_string_size(), + s.len(), + Position::none(), + ) + .into(); + } + } + } + + Ok(().into()) + } + #[rhai_fn(name = "pad", return_raw)] + pub fn pad_with_string( + _context: NativeCallContext, + s: &mut ImmutableString, + len: INT, + padding: &str, + ) -> Result> { + // Check if string will be over max size limit + #[cfg(not(feature = "unchecked"))] + if _context.engine().max_string_size() > 0 + && len as usize > _context.engine().max_string_size() + { + return EvalAltResult::ErrorDataTooLarge( + "Length of string".to_string(), + _context.engine().max_string_size(), + len as usize, + Position::none(), + ) + .into(); + } + + if len > 0 { + let mut str_len = s.chars().count(); + let padding_len = padding.chars().count(); + + if len as usize > str_len { + let p = s.make_mut(); + + while str_len < len as usize { + p.push_str(padding); + str_len += padding_len; + } + + #[cfg(not(feature = "unchecked"))] + if _context.engine().max_string_size() > 0 + && s.len() > _context.engine().max_string_size() + { + return EvalAltResult::ErrorDataTooLarge( + "Length of string".to_string(), + _context.engine().max_string_size(), + s.len(), + Position::none(), + ) + .into(); + } + } + } + + Ok(().into()) + } #[cfg(not(feature = "no_index"))] pub mod arrays {