Skip to main content

script_bindings/
like.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Implementation of `setlike<...>` and `maplike<..., ...>` WebIDL declarations.
6
7use std::hash::Hash;
8
9use atomic_refcell::AtomicRefCell;
10use indexmap::{IndexMap, IndexSet};
11use js::context::JSContext;
12use js::conversions::ToJSValConvertible;
13
14use crate::cell::DomRefCell;
15use crate::iterable::Iterable;
16
17/// Every Setlike dom_struct must implement this to provide access to underlying storage
18/// so codegen can automatically generate all setlike methods
19///
20/// In case you use a type that implements Setlike as underlying storage it's recommended to use `setlike` macro.
21// In webidl: `setlike<Key>`
22pub trait Setlike {
23    /// The type of the key of the set.
24    type Key: ToJSValConvertible + Clone; // clone is for impl<T: Setlike> Maplike for T
25
26    fn get_index(&self, cx: &mut JSContext, index: u32) -> Option<Self::Key>;
27
28    fn size(&self, cx: &mut JSContext) -> u32;
29    fn add(&self, cx: &mut JSContext, key: Self::Key);
30    fn has(&self, cx: &mut JSContext, key: Self::Key) -> bool;
31    fn clear(&self, cx: &mut JSContext);
32    fn delete(&self, cx: &mut JSContext, key: Self::Key) -> bool;
33}
34
35// we can only have one iterable for T
36// so we have impl<T: Maplike> Iterable for T
37// and minimal:
38impl<T: Setlike> Maplike for T {
39    type Key = <T as Setlike>::Key;
40
41    type Value = <T as Setlike>::Key;
42
43    #[inline]
44    fn get_index(&self, cx: &mut JSContext, index: u32) -> Option<(Self::Key, Self::Value)> {
45        self.get_index(cx, index).map(|k| (k.clone(), k))
46    }
47
48    fn get(&self, _cx: &mut JSContext, _key: Self::Key) -> Option<Self::Value> {
49        unimplemented!()
50    }
51
52    #[inline]
53    fn size(&self, cx: &mut JSContext) -> u32 {
54        self.size(cx)
55    }
56
57    fn set(&self, _cx: &mut JSContext, _key: Self::Key, _value: Self::Value) {
58        unimplemented!()
59    }
60
61    fn has(&self, _cx: &mut JSContext, _key: Self::Key) -> bool {
62        unimplemented!()
63    }
64
65    fn clear(&self, _cx: &mut JSContext) {
66        unimplemented!()
67    }
68
69    fn delete(&self, _cx: &mut JSContext, _key: Self::Key) -> bool {
70        unimplemented!()
71    }
72}
73
74/// Every Maplike dom_struct must implement this
75/// to provide access to underlying storage
76/// so codegen can automatically generate all maplike methods
77///
78/// In case you use a type that implements Maplike as underlying storage it's recommended to use `maplike` macro.
79// In webidl: `maplike<Key, Value>`
80pub trait Maplike {
81    /// The type of the key of the map.
82    type Key: ToJSValConvertible;
83    /// The type of the value of the map.
84    type Value: ToJSValConvertible;
85
86    fn get_index(&self, cx: &mut JSContext, index: u32) -> Option<(Self::Key, Self::Value)>;
87
88    fn get(&self, cx: &mut JSContext, key: Self::Key) -> Option<Self::Value>;
89    fn size(&self, cx: &mut JSContext) -> u32;
90    fn set(&self, cx: &mut JSContext, key: Self::Key, value: Self::Value);
91    fn has(&self, cx: &mut JSContext, key: Self::Key) -> bool;
92    fn clear(&self, cx: &mut JSContext);
93    fn delete(&self, cx: &mut JSContext, key: Self::Key) -> bool;
94}
95
96impl<T: Maplike> Iterable for T {
97    type Key = T::Key;
98
99    type Value = T::Value;
100
101    #[inline]
102    fn get_iterable_length(&self, cx: &mut JSContext) -> u32 {
103        self.size(cx)
104    }
105
106    #[inline]
107    fn get_value_at_index(&self, cx: &mut JSContext, index: u32) -> <T as Maplike>::Value {
108        // We are checking bounds manually
109        self.get_index(cx, index).unwrap().1
110    }
111
112    #[inline]
113    fn get_key_at_index(&self, cx: &mut JSContext, index: u32) -> <T as Maplike>::Key {
114        // We are checking bounds manually
115        self.get_index(cx, index).unwrap().0
116    }
117}
118
119impl<K, V> Maplike for DomRefCell<IndexMap<K, V>>
120where
121    K: ToJSValConvertible + Eq + PartialEq + Hash + Clone,
122    V: ToJSValConvertible + Clone,
123{
124    type Key = K;
125    type Value = V;
126
127    #[inline(always)]
128    fn get_index(&self, _cx: &mut JSContext, index: u32) -> Option<(Self::Key, Self::Value)> {
129        self.borrow()
130            .get_index(index as usize)
131            .map(|(k, v)| (k.to_owned(), v.to_owned()))
132    }
133
134    #[inline(always)]
135    fn get(&self, _cx: &mut JSContext, key: Self::Key) -> Option<Self::Value> {
136        self.borrow().get(&key).cloned()
137    }
138
139    #[inline(always)]
140    fn size(&self, _cx: &mut JSContext) -> u32 {
141        self.borrow().len() as u32
142    }
143
144    #[inline(always)]
145    fn set(&self, _cx: &mut JSContext, key: Self::Key, value: Self::Value) {
146        self.borrow_mut().insert(key, value);
147    }
148
149    #[inline(always)]
150    fn has(&self, _cx: &mut JSContext, key: Self::Key) -> bool {
151        self.borrow().contains_key(&key)
152    }
153
154    #[inline(always)]
155    fn clear(&self, _cx: &mut JSContext) {
156        self.borrow_mut().clear()
157    }
158
159    #[inline(always)]
160    fn delete(&self, _cx: &mut JSContext, key: Self::Key) -> bool {
161        self.borrow_mut().shift_remove(&key).is_some()
162    }
163}
164
165impl<K> Setlike for DomRefCell<IndexSet<K>>
166where
167    K: ToJSValConvertible + Eq + PartialEq + Hash + Clone,
168{
169    type Key = K;
170
171    #[inline(always)]
172    fn get_index(&self, _cx: &mut JSContext, index: u32) -> Option<Self::Key> {
173        self.borrow().get_index(index as usize).cloned()
174    }
175
176    #[inline(always)]
177    fn size(&self, _cx: &mut JSContext) -> u32 {
178        self.borrow().len() as u32
179    }
180
181    #[inline(always)]
182    fn add(&self, _cx: &mut JSContext, key: Self::Key) {
183        self.borrow_mut().insert(key);
184    }
185
186    #[inline(always)]
187    fn has(&self, _cx: &mut JSContext, key: Self::Key) -> bool {
188        self.borrow().contains(&key)
189    }
190
191    #[inline(always)]
192    fn clear(&self, _cx: &mut JSContext) {
193        self.borrow_mut().clear()
194    }
195
196    #[inline(always)]
197    fn delete(&self, _cx: &mut JSContext, key: Self::Key) -> bool {
198        self.borrow_mut().shift_remove(&key)
199    }
200}
201
202impl<K> Setlike for AtomicRefCell<IndexSet<K>>
203where
204    K: ToJSValConvertible + Eq + PartialEq + Hash + Clone,
205{
206    type Key = K;
207
208    #[inline(always)]
209    fn get_index(&self, _cx: &mut JSContext, index: u32) -> Option<Self::Key> {
210        self.borrow().get_index(index as usize).cloned()
211    }
212
213    #[inline(always)]
214    fn size(&self, _cx: &mut JSContext) -> u32 {
215        self.borrow().len() as u32
216    }
217
218    #[inline(always)]
219    fn add(&self, _cx: &mut JSContext, key: Self::Key) {
220        self.borrow_mut().insert(key);
221    }
222
223    #[inline(always)]
224    fn has(&self, _cx: &mut JSContext, key: Self::Key) -> bool {
225        self.borrow().contains(&key)
226    }
227
228    #[inline(always)]
229    fn clear(&self, _cx: &mut JSContext) {
230        self.borrow_mut().clear()
231    }
232
233    #[inline(always)]
234    fn delete(&self, _cx: &mut JSContext, key: Self::Key) -> bool {
235        self.borrow_mut().shift_remove(&key)
236    }
237}