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