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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! The `MozMap` (open-ended dictionary) type.
use dom::bindings::conversions::jsid_to_string;
use dom::bindings::str::DOMString;
use js::conversions::{ConversionResult, FromJSValConvertible, ToJSValConvertible};
use js::jsapi::JSContext;
use js::jsapi::JSITER_OWNONLY;
use js::jsapi::JSPROP_ENUMERATE;
use js::jsapi::JS_NewPlainObject;
use js::jsval::ObjectValue;
use js::jsval::UndefinedValue;
use js::rust::HandleValue;
use js::rust::IdVector;
use js::rust::MutableHandleValue;
use js::rust::wrappers::GetPropertyKeys;
use js::rust::wrappers::JS_DefineUCProperty2;
use js::rust::wrappers::JS_GetPropertyById;
use std::collections::HashMap;
use std::ops::Deref;
/// The `MozMap` (open-ended dictionary) type.
#[derive(Clone, JSTraceable)]
pub struct MozMap<T> {
map: HashMap<DOMString, T>,
}
impl<T> MozMap<T> {
/// Create an empty `MozMap`.
pub fn new() -> Self {
MozMap {
map: HashMap::new(),
}
}
}
impl<T> Deref for MozMap<T> {
type Target = HashMap<DOMString, T>;
fn deref(&self) -> &HashMap<DOMString, T> {
&self.map
}
}
impl<T, C> FromJSValConvertible for MozMap<T>
where T: FromJSValConvertible<Config=C>,
C: Clone,
{
type Config = C;
unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, config: C)
-> Result<ConversionResult<Self>, ()> {
if !value.is_object() {
return Ok(ConversionResult::Failure("MozMap value was not an object".into()));
}
rooted!(in(cx) let object = value.to_object());
let ids = IdVector::new(cx);
assert!(GetPropertyKeys(cx, object.handle(), JSITER_OWNONLY, ids.get()));
let mut map = HashMap::new();
for id in &*ids {
rooted!(in(cx) let id = *id);
rooted!(in(cx) let mut property = UndefinedValue());
if !JS_GetPropertyById(cx, object.handle(), id.handle(), property.handle_mut()) {
return Err(());
}
let property = match T::from_jsval(cx, property.handle(), config.clone())? {
ConversionResult::Success(property) => property,
ConversionResult::Failure(message) => return Ok(ConversionResult::Failure(message)),
};
let key = jsid_to_string(cx, id.handle()).unwrap();
map.insert(key, property);
}
Ok(ConversionResult::Success(MozMap {
map: map,
}))
}
}
impl<T: ToJSValConvertible> ToJSValConvertible for MozMap<T> {
#[inline]
unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
rooted!(in(cx) let js_object = JS_NewPlainObject(cx));
assert!(!js_object.handle().is_null());
rooted!(in(cx) let mut js_value = UndefinedValue());
for (key, value) in &self.map {
let key = key.encode_utf16().collect::<Vec<_>>();
value.to_jsval(cx, js_value.handle_mut());
assert!(JS_DefineUCProperty2(cx,
js_object.handle(),
key.as_ptr(),
key.len(),
js_value.handle(),
JSPROP_ENUMERATE,
None,
None));
}
rval.set(ObjectValue(js_object.handle().get()));
}
}
|