From c4a51b139001cf301ee6dd1755a99a8168578fb7 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 1 Apr 2020 22:56:54 +0800 Subject: [PATCH] Add append/mixin functions for arrays and maps. --- README.md | 32 +++++++++++++---------- src/builtin.rs | 19 ++++++++++++++ tests/arrays.rs | 39 +++++++++++++++++++++++++++- tests/maps.rs | 68 +++++++++++++++++++++++++++++++++++++------------ 4 files changed, 127 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 41776cd5..4a168273 100644 --- a/README.md +++ b/README.md @@ -981,15 +981,17 @@ Arrays are disabled via the [`no_index`] feature. The following functions (defined in the standard library but excluded if [`no_stdlib`]) operate on arrays: -| Function | Description | -| ---------- | ------------------------------------------------------------------------------------- | -| `push` | inserts an element at the end | -| `pop` | removes the last element and returns it ([`()`] if empty) | -| `shift` | removes the first element and returns it ([`()`] if empty) | -| `len` | returns the number of elements | -| `pad` | pads the array with an element until a specified length | -| `clear` | empties the array | -| `truncate` | cuts off the array at exactly a specified length (discarding all subsequent elements) | +| Function | Description | +| ------------ | ------------------------------------------------------------------------------------- | +| `push` | inserts an element at the end | +| `append` | concatenates the second array to the end of the first | +| `+` operator | concatenates the first array with the second | +| `pop` | removes the last element and returns it ([`()`] if empty) | +| `shift` | removes the first element and returns it ([`()`] if empty) | +| `len` | returns the number of elements | +| `pad` | pads the array with an element until a specified length | +| `clear` | empties the array | +| `truncate` | cuts off the array at exactly a specified length (discarding all subsequent elements) | Examples: @@ -1070,11 +1072,13 @@ Object maps are disabled via the [`no_object`] feature. The following functions (defined in the standard library but excluded if [`no_stdlib`]) operate on object maps: -| Function | Description | -| -------- | ------------------------------------------------------------ | -| `has` | does the object map contain a property of a particular name? | -| `len` | returns the number of properties | -| `clear` | empties the object map | +| Function | Description | +| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | +| `has` | does the object map contain a property of a particular name? | +| `len` | returns the number of properties | +| `clear` | empties the object map | +| `mixin` | mixes in all the properties of the second object map to the first (values of properties with the same names replace the existing values) | +| `+` operator | merges the first object map with the second | Examples: diff --git a/src/builtin.rs b/src/builtin.rs index ae5feb13..d7f5840e 100644 --- a/src/builtin.rs +++ b/src/builtin.rs @@ -813,6 +813,14 @@ impl Engine<'_> { reg_fn3!(self, "pad", pad, &mut Array, INT, (), INT, bool, char); reg_fn3!(self, "pad", pad, &mut Array, INT, (), String, Array, ()); + self.register_fn("append", |list: &mut Array, array: Array| { + list.extend(array) + }); + self.register_fn("+", |mut list: Array, array: Array| { + list.extend(array); + list + }); + #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] { @@ -853,6 +861,17 @@ impl Engine<'_> { self.register_fn("has", |map: &mut Map, prop: String| map.contains_key(&prop)); self.register_fn("len", |map: &mut Map| map.len() as INT); self.register_fn("clear", |map: &mut Map| map.clear()); + self.register_fn("mixin", |map1: &mut Map, map2: Map| { + map2.into_iter().for_each(|(key, value)| { + map1.insert(key, value); + }); + }); + self.register_fn("+", |mut map1: Map, map2: Map| { + map2.into_iter().for_each(|(key, value)| { + map1.insert(key, value); + }); + map1 + }); } // Register string concatenate functions diff --git a/tests/arrays.rs b/tests/arrays.rs index 5cfec145..1a7517ae 100644 --- a/tests/arrays.rs +++ b/tests/arrays.rs @@ -1,5 +1,5 @@ #![cfg(not(feature = "no_index"))] -use rhai::{Engine, EvalAltResult, RegisterFn, INT}; +use rhai::{Array, Engine, EvalAltResult, RegisterFn, INT}; #[test] fn test_arrays() -> Result<(), EvalAltResult> { @@ -12,6 +12,43 @@ fn test_arrays() -> Result<(), EvalAltResult> { '3' ); + #[cfg(not(feature = "no_stdlib"))] + { + assert_eq!( + engine.eval::( + r" + let x = [1, 2, 3]; + let y = [4, 5]; + x.append(y); + x.len() + " + )?, + 5 + ); + assert_eq!( + engine.eval::( + r" + let x = [1, 2, 3]; + x += [4, 5]; + x.len() + " + )?, + 5 + ); + assert_eq!( + engine + .eval::( + r" + let x = [1, 2, 3]; + let y = [4, 5]; + x + y + " + )? + .len(), + 5 + ); + } + Ok(()) } diff --git a/tests/maps.rs b/tests/maps.rs index 0da9b589..bb8c90cf 100644 --- a/tests/maps.rs +++ b/tests/maps.rs @@ -7,29 +7,65 @@ fn test_map_indexing() -> Result<(), EvalAltResult> { let mut engine = Engine::new(); #[cfg(not(feature = "no_index"))] - assert_eq!( - engine.eval::(r#"let x = #{a: 1, b: 2, c: 3}; x["b"]"#)?, - 2 - ); + { + assert_eq!( + engine.eval::(r#"let x = #{a: 1, b: 2, c: 3}; x["b"]"#)?, + 2 + ); + assert_eq!( + engine.eval::( + r#" + let y = #{d: 1, "e": #{a: 42, b: 88, "": "hello"}, " 123 xyz": 9}; + y.e[""][4] + "# + )?, + 'o' + ); + } assert_eq!( engine.eval::("let y = #{a: 1, b: 2, c: 3}; y.a = 5; y.a")?, 5 ); - - #[cfg(not(feature = "no_index"))] - assert_eq!( - engine.eval::( - r#" - let y = #{d: 1, "e": #{a: 42, b: 88, "": "hello"}, " 123 xyz": 9}; - y.e[""][4] - "# - )?, - 'o' - ); - engine.eval::<()>("let y = #{a: 1, b: 2, c: 3}; y.z")?; + #[cfg(not(feature = "no_stdlib"))] + { + assert_eq!( + engine.eval::( + r" + let x = #{a: 1, b: 2, c: 3}; + let y = #{b: 42, d: 9}; + x.mixin(y); + x.len() + x.b + " + )?, + 46 + ); + assert_eq!( + engine.eval::( + r" + let x = #{a: 1, b: 2, c: 3}; + x += #{b: 42, d: 9}; + x.len() + x.b + " + )?, + 46 + ); + assert_eq!( + engine + .eval::( + r" + let x = #{a: 1, b: 2, c: 3}; + let y = #{b: 42, d: 9}; + x + y + " + )? + .len(), + 4 + ); + } + Ok(()) }