1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#![cfg(not(feature = "no_object"))]

use crate::engine::OP_EQUALS;
use crate::plugin::*;
use crate::{def_package, Dynamic, ImmutableString, Map, INT};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;

#[cfg(not(feature = "no_index"))]
use crate::Array;

def_package!(crate:BasicMapPackage:"Basic object map utilities.", lib, {
    combine_with_exported_module!(lib, "map", map_functions);
});

#[export_module]
mod map_functions {
    #[rhai_fn(name = "has", pure)]
    pub fn contains(map: &mut Map, prop: ImmutableString) -> bool {
        map.contains_key(prop.as_str())
    }
    #[rhai_fn(pure)]
    pub fn len(map: &mut Map) -> INT {
        map.len() as INT
    }
    pub fn clear(map: &mut Map) {
        map.clear();
    }
    pub fn remove(map: &mut Map, name: ImmutableString) -> Dynamic {
        map.remove(name.as_str()).unwrap_or_else(|| ().into())
    }
    #[rhai_fn(name = "mixin", name = "+=")]
    pub fn mixin(map: &mut Map, map2: Map) {
        map.extend(map2.into_iter());
    }
    #[rhai_fn(name = "+")]
    pub fn merge(mut map: Map, map2: Map) -> Map {
        map.extend(map2.into_iter());
        map
    }
    pub fn fill_with(map: &mut Map, map2: Map) {
        map2.into_iter().for_each(|(key, value)| {
            map.entry(key).or_insert(value);
        });
    }
    #[rhai_fn(name = "==", return_raw, pure)]
    pub fn equals(
        ctx: NativeCallContext,
        map: &mut Map,
        mut map2: Map,
    ) -> Result<bool, Box<EvalAltResult>> {
        if map.len() != map2.len() {
            return Ok(false);
        }
        if map.is_empty() {
            return Ok(true);
        }

        for (m1, v1) in map.iter_mut() {
            if let Some(v2) = map2.get_mut(m1) {
                let equals = ctx
                    .call_fn_dynamic_raw(OP_EQUALS, true, &mut [v1, v2])
                    .map(|v| v.as_bool().unwrap_or(false))?;

                if !equals {
                    return Ok(false);
                }
            } else {
                return Ok(false);
            }
        }

        Ok(true)
    }
    #[rhai_fn(name = "!=", return_raw, pure)]
    pub fn not_equals(
        ctx: NativeCallContext,
        map: &mut Map,
        map2: Map,
    ) -> Result<bool, Box<EvalAltResult>> {
        equals(ctx, map, map2).map(|r| !r)
    }

    #[cfg(not(feature = "no_index"))]
    pub mod indexing {
        #[rhai_fn(pure)]
        pub fn keys(map: &mut Map) -> Array {
            map.iter().map(|(k, _)| k.clone().into()).collect()
        }
        #[rhai_fn(pure)]
        pub fn values(map: &mut Map) -> Array {
            map.iter().map(|(_, v)| v.clone()).collect()
        }
    }
}