Add get/set methods to arrays, blobs, maps and strings.

This commit is contained in:
Stephen Chung 2022-01-17 10:21:03 +08:00
parent 573bfe46dd
commit 5232bbbff8
5 changed files with 261 additions and 4 deletions

View File

@ -22,6 +22,7 @@ Enhancements
* Formatting of return types in functions metadata info is improved.
* Use `SmartString` for `Scope` variable names and remove `unsafe` lifetime casting.
* Functions in the standard library now have doc-comments (which can be obtained via `Engine::gen_fn_metadata_to_json`).
* `get` and `set` methods are added to arrays, BLOB's, object maps and strings.
Version 1.4.0

View File

@ -31,6 +31,70 @@ pub mod array_functions {
pub fn len(array: &mut Array) -> INT {
array.len() as INT
}
/// Get a copy of the element at the `index` position in the array.
///
/// * If `index` < 0, position counts from the end of the array (`-1` is the last element).
/// * If `index` < -length of array, `()` is returned.
/// * If `index` ≥ length of array, `()` is returned.
///
/// # Example
///
/// ```rhai
/// let x = [1, 2, 3];
///
/// print(x.get(0)); // prints 1
///
/// print(x.get(-1)); // prints 3
///
/// print(x.get(99)); // prints empty (for '()')
/// ```
pub fn get(array: &mut Array, index: INT) -> Dynamic {
if array.is_empty() {
return Dynamic::UNIT;
}
let (index, _) = calc_offset_len(array.len(), index, 0);
if index >= array.len() {
Dynamic::UNIT
} else {
array[index].clone()
}
}
/// Set the element at the `index` position in the array to a new `value`.
///
/// * If `index` < 0, position counts from the end of the array (`-1` is the last element).
/// * If `index` < -length of array, the array is not modified.
/// * If `index` ≥ length of array, the array is not modified.
///
/// # Example
///
/// ```rhai
/// let x = [1, 2, 3];
///
/// x.set(0, 42);
///
/// print(x); // prints "[42, 2, 3]"
///
/// x.set(-3, 0);
///
/// print(x); // prints "[0, 2, 3]"
///
/// x.set(99, 123);
///
/// print(x); // prints "[0, 2, 3]"
/// ```
pub fn set(array: &mut Array, index: INT, value: Dynamic) {
if array.is_empty() {
return;
}
let (index, _) = calc_offset_len(array.len(), index, 0);
if index < array.len() {
array[index] = value;
}
}
/// Add a new element, which is not another array, to the end of the array.
///
/// If `item` is `Array`, then `append` is more specific and will be called instead.

View File

@ -100,6 +100,75 @@ pub mod blob_functions {
pub fn len(blob: &mut Blob) -> INT {
blob.len() as INT
}
/// Get the byte value at the `index` position in the BLOB.
///
/// * If `index` < 0, position counts from the end of the BLOB (`-1` is the last element).
/// * If `index` < -length of BLOB, zero is returned.
/// * If `index` ≥ length of BLOB, zero is returned.
///
/// # Example
///
/// ```rhai
/// let b = blob();
///
/// b += 1; b += 2; b += 3; b += 4; b += 5;
///
/// print(b.get(0)); // prints 1
///
/// print(b.get(-1)); // prints 5
///
/// print(b.get(99)); // prints 0
/// ```
pub fn get(blob: &mut Blob, index: INT) -> INT {
if blob.is_empty() {
return 0;
}
let (index, _) = calc_offset_len(blob.len(), index, 0);
if index >= blob.len() {
0
} else {
blob[index] as INT
}
}
/// Set the particular `index` position in the BLOB to a new byte `value`.
///
/// * If `index` < 0, position counts from the end of the BLOB (`-1` is the last byte).
/// * If `index` < -length of BLOB, the BLOB is not modified.
/// * If `index` ≥ length of BLOB, the BLOB is not modified.
///
/// # Example
///
/// ```rhai
/// let b = blob();
///
/// b += 1; b += 2; b += 3; b += 4; b += 5;
///
/// b.set(0, 0x42);
///
/// print(b); // prints "[4202030405]"
///
/// b.set(-3, 0);
///
/// print(b); // prints "[4202000405]"
///
/// b.set(99, 123);
///
/// print(b); // prints "[4202000405]"
/// ```
pub fn set(blob: &mut Blob, index: INT, value: INT) {
if blob.is_empty() {
return;
}
let (index, _) = calc_offset_len(blob.len(), index, 0);
if index < blob.len() {
blob[index] = (value & 0x000000ff) as u8;
}
}
/// Add a new byte `value` to the end of the BLOB.
///
/// Only the lower 8 bits of the `value` are used; all other bits are ignored.
@ -114,8 +183,7 @@ pub mod blob_functions {
/// print(b); // prints "[42]"
/// ```
pub fn push(blob: &mut Blob, value: INT) {
let value = (value & 0x000000ff) as u8;
blob.push(value);
blob.push((value & 0x000000ff) as u8);
}
/// Add another BLOB to the end of the BLOB.
///

View File

@ -25,6 +25,51 @@ mod map_functions {
pub fn len(map: &mut Map) -> INT {
map.len() as INT
}
/// Get the value of the `property` in the object map and return a copy.
///
/// If `property` does not exist in the object map, `()` is returned.
///
/// # Example
///
/// ```rhai
/// let m = #{a: 1, b: 2, c: 3};
///
/// print(m.get("b")); // prints 2
///
/// print(m.get("x")); // prints empty (for '()')
/// ```
pub fn get(map: &mut Map, property: &str) -> Dynamic {
if map.is_empty() {
return Dynamic::UNIT;
}
map.get(property).cloned().unwrap_or(Dynamic::UNIT)
}
/// Set the value of the `property` in the object map to a new `value`.
///
/// If `property` does not exist in the object map, it is added.
///
/// # Example
///
/// ```rhai
/// let m = #{a: 1, b: 2, c: 3};
///
/// m.set("b", 42)'
///
/// print(m); // prints "#{a: 1, b: 42, c: 3}"
///
/// x.set("x", 0);
///
/// print(m); // prints "#{a: 1, b: 42, c: 3, x: 0}"
/// ```
pub fn set(map: &mut Map, property: &str, value: Dynamic) {
if let Some(value_ref) = map.get_mut(property) {
*value_ref = value;
} else {
map.insert(property.into(), value);
}
}
/// Clear the object map.
pub fn clear(map: &mut Map) {
if !map.is_empty() {
@ -46,9 +91,9 @@ mod map_functions {
///
/// print(m); // prints "#{a:1, c:3}"
/// ```
pub fn remove(map: &mut Map, name: ImmutableString) -> Dynamic {
pub fn remove(map: &mut Map, property: &str) -> Dynamic {
if !map.is_empty() {
map.remove(name.as_str()).unwrap_or_else(|| Dynamic::UNIT)
map.remove(property).unwrap_or_else(|| Dynamic::UNIT)
} else {
Dynamic::UNIT
}

View File

@ -551,6 +551,85 @@ mod string_functions {
}
}
/// Get the character at the `index` position in the string.
///
/// * If `index` < 0, position counts from the end of the string (`-1` is the last character).
/// * If `index` < -length of string, zero is returned.
/// * If `index` ≥ length of string, zero is returned.
///
/// # Example
///
/// ```rhai
/// let text = "hello, world!";
///
/// print(text.get(0)); // prints 'h'
///
/// print(text.get(-1)); // prints '!'
///
/// print(text.get(99)); // prints empty (for '()')'
/// ```
pub fn get(string: &str, index: INT) -> Dynamic {
if index >= 0 {
string
.chars()
.nth(index as usize)
.map_or_else(|| Dynamic::UNIT, Into::into)
} else if let Some(abs_index) = index.checked_abs() {
// Count from end if negative
string
.chars()
.rev()
.nth((abs_index as usize) - 1)
.map_or_else(|| Dynamic::UNIT, Into::into)
} else {
Dynamic::UNIT
}
}
/// Set the `index` position in the string to a new `character`.
///
/// * If `index` < 0, position counts from the end of the string (`-1` is the last character).
/// * If `index` < -length of string, the string is not modified.
/// * If `index` ≥ length of string, the string is not modified.
///
/// # Example
///
/// ```rhai
/// let text = "hello, world!";
///
/// text.set(3, 'x');
///
/// print(text); // prints "helxo, world!"
///
/// text.set(-3, 'x');
///
/// print(text); // prints "hello, worxd!"
///
/// text.set(99, 'x');
///
/// print(text); // prints "hello, worxd!"
/// ```
pub fn set(string: &mut ImmutableString, index: INT, character: char) {
if index >= 0 {
let index = index as usize;
*string = string
.chars()
.enumerate()
.map(|(i, ch)| if i == index { character } else { ch })
.collect();
} else if let Some(abs_index) = index.checked_abs() {
let string_len = string.chars().count();
if abs_index as usize <= string_len {
let index = string_len - (abs_index as usize);
*string = string
.chars()
.enumerate()
.map(|(i, ch)| if i == index { character } else { ch })
.collect();
}
}
}
/// Copy an exclusive range of characters from the string and return it as a new string.
///
/// # Example