rhai/src/packages/map_basic.rs

292 lines
8.0 KiB
Rust
Raw Normal View History

#![cfg(not(feature = "no_object"))]
use crate::engine::OP_EQUALS;
2020-08-14 18:04:10 +02:00
use crate::plugin::*;
2022-04-21 06:15:21 +02:00
use crate::{def_package, format_map_as_json, Dynamic, ImmutableString, Map, RhaiResultOf, INT};
2021-04-17 09:15:54 +02:00
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
2020-10-15 16:11:18 +02:00
#[cfg(not(feature = "no_index"))]
2020-11-16 09:28:04 +01:00
use crate::Array;
2020-04-24 06:39:24 +02:00
2021-12-20 04:42:39 +01:00
def_package! {
/// Package of basic object map utilities.
2022-02-10 05:33:48 +01:00
pub BasicMapPackage(lib) {
2021-12-20 04:42:39 +01:00
lib.standard = true;
2021-12-20 04:42:39 +01:00
combine_with_exported_module!(lib, "map", map_functions);
}
}
2020-08-14 18:04:10 +02:00
#[export_module]
mod map_functions {
/// Return the number of properties in the object map.
#[rhai_fn(pure)]
2020-08-14 18:04:10 +02:00
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.
2020-08-14 18:04:10 +02:00
pub fn clear(map: &mut Map) {
if !map.is_empty() {
map.clear();
}
2020-08-14 18:04:10 +02:00
}
/// Remove any property of the specified `name` from the object map, returning its value.
///
/// If the property does not exist, `()` is returned.
///
/// # Example
///
/// ```rhai
/// let m = #{a:1, b:2, c:3};
///
/// let x = m.remove("b");
///
/// print(x); // prints 2
///
/// print(m); // prints "#{a:1, c:3}"
/// ```
pub fn remove(map: &mut Map, property: &str) -> Dynamic {
if !map.is_empty() {
2022-07-27 10:04:24 +02:00
map.remove(property).unwrap_or(Dynamic::UNIT)
} else {
Dynamic::UNIT
}
2020-08-14 18:04:10 +02:00
}
/// Add all property values of another object map into the object map.
/// Existing property values of the same names are replaced.
///
/// # Example
///
/// ```rhai
/// let m = #{a:1, b:2, c:3};
/// let n = #{a: 42, d:0};
///
/// m.mixin(n);
///
/// print(m); // prints "#{a:42, b:2, c:3, d:0}"
/// ```
#[rhai_fn(name = "mixin", name = "+=")]
pub fn mixin(map: &mut Map, map2: Map) {
if !map2.is_empty() {
map.extend(map2.into_iter());
}
2020-08-14 18:04:10 +02:00
}
/// Make a copy of the object map, add all property values of another object map
/// (existing property values of the same names are replaced), then returning it.
///
/// # Example
///
/// ```rhai
/// let m = #{a:1, b:2, c:3};
/// let n = #{a: 42, d:0};
///
/// print(m + n); // prints "#{a:42, b:2, c:3, d:0}"
///
/// print(m); // prints "#{a:1, b:2, c:3}"
/// ```
#[rhai_fn(name = "+")]
2021-08-13 07:42:39 +02:00
pub fn merge(map1: Map, map2: Map) -> Map {
if map2.is_empty() {
map1
} else if map1.is_empty() {
map2
} else {
let mut map1 = map1;
map1.extend(map2.into_iter());
map1
}
2020-08-14 18:04:10 +02:00
}
/// Add all property values of another object map into the object map.
/// Only properties that do not originally exist in the object map are added.
///
/// # Example
///
/// ```rhai
/// let m = #{a:1, b:2, c:3};
/// let n = #{a: 42, d:0};
///
/// m.fill_with(n);
///
/// print(m); // prints "#{a:1, b:2, c:3, d:0}"
/// ```
pub fn fill_with(map: &mut Map, map2: Map) {
if !map2.is_empty() {
if map.is_empty() {
*map = map2;
} else {
map2.into_iter().for_each(|(key, value)| {
map.entry(key).or_insert(value);
});
}
}
2020-08-14 18:04:10 +02:00
}
/// Return `true` if two object maps are equal (i.e. all property values are equal).
///
/// The operator `==` is used to compare property values and must be defined,
/// otherwise `false` is assumed.
///
/// # Example
///
/// ```rhai
/// let m1 = #{a:1, b:2, c:3};
/// let m2 = #{a:1, b:2, c:3};
/// let m3 = #{a:1, c:3};
///
/// print(m1 == m2); // prints true
///
/// print(m1 == m3); // prints false
/// ```
#[rhai_fn(name = "==", return_raw, pure)]
2021-12-25 16:49:14 +01:00
pub fn equals(ctx: NativeCallContext, map1: &mut Map, map2: Map) -> RhaiResultOf<bool> {
2021-08-13 07:42:39 +02:00
if map1.len() != map2.len() {
2021-03-22 04:18:09 +01:00
return Ok(false);
2020-11-08 16:00:37 +01:00
}
if !map1.is_empty() {
let mut map2 = map2;
2021-08-13 07:42:39 +02:00
2022-07-05 10:26:38 +02:00
for (m1, v1) in map1 {
if let Some(v2) = map2.get_mut(m1) {
let equals = ctx
.call_fn_raw(OP_EQUALS, true, false, &mut [v1, v2])?
.as_bool()
.unwrap_or(false);
2020-11-08 16:00:37 +01:00
if !equals {
return Ok(false);
}
} else {
2021-03-22 04:18:09 +01:00
return Ok(false);
2020-11-08 16:00:37 +01:00
}
}
}
2021-03-22 04:18:09 +01:00
Ok(true)
2020-11-08 16:00:37 +01:00
}
/// Return `true` if two object maps are not equal (i.e. at least one property value is not equal).
///
/// The operator `==` is used to compare property values and must be defined,
/// otherwise `false` is assumed.
///
/// # Example
///
/// ```rhai
/// let m1 = #{a:1, b:2, c:3};
/// let m2 = #{a:1, b:2, c:3};
/// let m3 = #{a:1, c:3};
///
/// print(m1 != m2); // prints false
///
/// print(m1 != m3); // prints true
/// ```
#[rhai_fn(name = "!=", return_raw, pure)]
2021-12-25 16:49:14 +01:00
pub fn not_equals(ctx: NativeCallContext, map1: &mut Map, map2: Map) -> RhaiResultOf<bool> {
2021-08-13 07:42:39 +02:00
equals(ctx, map1, map2).map(|r| !r)
2020-11-08 16:00:37 +01:00
}
2020-04-21 17:01:10 +02:00
/// Return an array with all the property names in the object map.
///
/// # Example
///
/// ```rhai
/// let m = #{a:1, b:2, c:3};
///
/// print(m.keys()); // prints ["a", "b", "c"]
/// ```
2020-08-22 16:26:49 +02:00
#[cfg(not(feature = "no_index"))]
2021-10-20 10:22:12 +02:00
#[rhai_fn(pure)]
pub fn keys(map: &mut Map) -> Array {
if map.is_empty() {
Array::new()
} else {
2021-12-27 09:59:05 +01:00
map.keys().cloned().map(Into::into).collect()
2020-08-22 16:26:49 +02:00
}
2021-10-20 10:22:12 +02:00
}
/// Return an array with all the property values in the object map.
///
/// # Example
///
/// ```rhai
/// let m = #{a:1, b:2, c:3};
///
/// print(m.values()); // prints "[1, 2, 3]""
/// ```
2021-10-20 10:22:12 +02:00
#[cfg(not(feature = "no_index"))]
#[rhai_fn(pure)]
pub fn values(map: &mut Map) -> Array {
if map.is_empty() {
Array::new()
} else {
map.values().cloned().collect()
2020-08-22 16:26:49 +02:00
}
2020-08-14 18:04:10 +02:00
}
2022-04-21 06:15:21 +02:00
/// Return the JSON representation of the object map.
///
/// # Data types
///
/// Only the following data types should be kept inside the object map:
/// `INT`, `FLOAT`, `ImmutableString`, `char`, `bool`, `()`, `Array`, `Map`.
///
/// # Errors
///
/// Data types not supported by JSON serialize into formats that may
/// invalidate the result.
///
/// # Example
///
/// ```rhai
/// let m = #{a:1, b:2, c:3};
///
/// print(m.to_json()); // prints {"a":1, "b":2, "c":3}
/// ```
pub fn to_json(map: &mut Map) -> String {
format_map_as_json(map)
}
2020-08-14 18:04:10 +02:00
}