rhai/src/packages/map_basic.rs

315 lines
8.8 KiB
Rust
Raw Normal View History

#![cfg(not(feature = "no_object"))]
use crate::engine::OP_EQUALS;
2022-11-23 04:36:30 +01:00
use crate::module::ModuleFlags;
2020-08-14 18:04:10 +02:00
use crate::plugin::*;
2022-09-29 16:46:59 +02:00
use crate::{def_package, Dynamic, ImmutableString, Map, NativeCallContext, 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) {
2022-11-23 04:36:30 +01:00
lib.flags |= ModuleFlags::STANDARD_LIB;
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
}
/// Return true if the map is empty.
2022-08-24 15:58:08 +02:00
#[rhai_fn(pure)]
pub fn is_empty(map: &mut Map) -> bool {
map.len() == 0
}
/// Returns `true` if the object map contains a specified property.
///
/// # Example
///
/// ```rhai
/// let m = #{a: 1, b: 2, c: 3};
///
/// print(m.contains("b")); // prints true
///
/// print(m.contains("x")); // prints false
/// ```
pub fn contains(map: &mut Map, property: &str) -> bool {
map.contains_key(property)
}
/// 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) {
2022-10-10 10:46:35 +02:00
match map.get_mut(property) {
Some(value_ref) => *value_ref = value,
_ => {
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 {
2022-07-27 12:04:59 +02:00
if map.is_empty() {
Dynamic::UNIT
2022-07-27 12:04:59 +02:00
} else {
map.remove(property).unwrap_or(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 {
2022-07-27 12:04:59 +02:00
for (key, value) in map2 {
map.entry(key).or_insert(value);
2022-07-27 12:04:59 +02:00
}
}
}
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
2022-10-14 10:57:14 +02:00
.call_native_fn_raw(OP_EQUALS, true, &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 {
2022-09-29 16:46:59 +02:00
#[cfg(feature = "metadata")]
return serde_json::to_string(map).unwrap_or_else(|_| "ERROR".into());
#[cfg(not(feature = "metadata"))]
return crate::format_map_as_json(map);
2022-04-21 06:15:21 +02:00
}
2020-08-14 18:04:10 +02:00
}