1use std::ops::{Deref, DerefMut};
8
9use mozjs::jsapi::{
10 IsMapObject, JSObject, MapClear, MapDelete, MapEntries, MapForEach, MapGet, MapHas, MapKeys, MapSet, MapSize,
11 MapValues, NewMapObject,
12};
13
14use crate::conversions::ToValue as _;
15use crate::{Context, Function, Local, Object, Value};
16
17pub struct Map<'m> {
18 map: Local<'m, *mut JSObject>,
19}
20
21impl<'m> Map<'m> {
22 pub fn new(cx: &'m Context) -> Map<'m> {
24 Map {
25 map: cx.root(unsafe { NewMapObject(cx.as_ptr()) }),
26 }
27 }
28
29 pub fn from(cx: &Context, object: Local<'m, *mut JSObject>) -> Option<Map<'m>> {
33 Map::is_map(cx, &object).then_some(Map { map: object })
34 }
35
36 pub unsafe fn from_unchecked(object: Local<'m, *mut JSObject>) -> Map<'m> {
41 Map { map: object }
42 }
43
44 pub fn size(&self, cx: &Context) -> u32 {
46 unsafe { MapSize(cx.as_ptr(), self.handle().into()) }
47 }
48
49 pub fn has(&self, cx: &Context, key: &Value) -> bool {
51 let mut has = false;
52 unsafe { MapHas(cx.as_ptr(), self.handle().into(), key.handle().into(), &raw mut has) && has }
53 }
54
55 pub fn get<'cx>(&self, cx: &'cx Context, key: &Value) -> Option<Value<'cx>> {
57 self.has(cx, key).then(|| {
58 let mut rval = Value::undefined(cx);
59 unsafe {
60 MapGet(
61 cx.as_ptr(),
62 self.handle().into(),
63 key.handle().into(),
64 rval.handle_mut().into(),
65 );
66 }
67 rval
68 })
69 }
70
71 pub fn set(&self, cx: &Context, key: &Value, value: &Value) -> bool {
73 unsafe {
74 MapSet(
75 cx.as_ptr(),
76 self.handle().into(),
77 key.handle().into(),
78 value.handle().into(),
79 )
80 }
81 }
82
83 pub fn delete(&self, cx: &Context, key: &Value) -> bool {
85 let mut rval = false;
86 unsafe { MapDelete(cx.as_ptr(), self.handle().into(), key.handle().into(), &raw mut rval) && rval }
87 }
88
89 pub fn clear(&self, cx: &Context) -> bool {
91 unsafe { MapClear(cx.as_ptr(), self.handle().into()) }
92 }
93
94 pub fn keys<'cx>(&self, cx: &'cx Context) -> Object<'cx> {
96 let mut keys = Value::undefined(cx);
97 unsafe {
98 MapKeys(cx.as_ptr(), self.handle().into(), keys.handle_mut().into());
99 }
100 keys.to_object(cx)
101 }
102
103 pub fn values<'cx>(&self, cx: &'cx Context) -> Object<'cx> {
105 let mut values = Value::undefined(cx);
106 unsafe {
107 MapValues(cx.as_ptr(), self.handle().into(), values.handle_mut().into());
108 }
109 values.to_object(cx)
110 }
111
112 pub fn entries<'cx>(&self, cx: &'cx Context) -> Object<'cx> {
114 let mut entries = Value::undefined(cx);
115 unsafe {
116 MapEntries(cx.as_ptr(), self.handle().into(), entries.handle_mut().into());
117 }
118 entries.to_object(cx)
119 }
120
121 pub fn for_each(&self, cx: &Context, callback: &Function, this: &Object) -> bool {
123 unsafe {
124 MapForEach(
125 cx.as_ptr(),
126 self.handle().into(),
127 callback.as_value(cx).handle().into(),
128 this.as_value(cx).handle().into(),
129 )
130 }
131 }
132
133 pub fn is_map(cx: &Context, object: &Local<*mut JSObject>) -> bool {
135 let mut map = false;
136 unsafe { IsMapObject(cx.as_ptr(), object.handle().into(), &raw mut map) && map }
137 }
138}
139
140impl<'m> Deref for Map<'m> {
141 type Target = Local<'m, *mut JSObject>;
142
143 fn deref(&self) -> &Self::Target {
144 &self.map
145 }
146}
147
148impl DerefMut for Map<'_> {
149 fn deref_mut(&mut self) -> &mut Self::Target {
150 &mut self.map
151 }
152}