Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the MozMap type. #13332

Merged
merged 7 commits into from Sep 21, 2016
Prev

Implement the MozMap type.

Fixes #13144.
  • Loading branch information
Ms2ger committed Sep 21, 2016
commit 2d83e5a78880724713366a38f599a1dac65403dc
@@ -93,13 +93,15 @@ def stripTrailingWhitespace(text):


def innerContainerType(type):
assert type.isSequence()
assert type.isSequence() or type.isMozMap()
return type.inner.inner if type.nullable() else type.inner


def wrapInNativeContainerType(type, inner):
if type.isSequence():
containerType = "Vec"
elif type.isMozMap():
containerType = "MozMap"
else:
raise TypeError("Unexpected container type %s", type)

@@ -733,7 +735,7 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type,
if type.isArray():
raise TypeError("Can't handle array arguments yet")

if type.isSequence():
if type.isSequence() or type.isMozMap():
innerInfo = getJSToNativeConversionInfo(innerContainerType(type),
descriptorProvider,
isMember=isMember)
@@ -1274,7 +1276,7 @@ def typeNeedsCx(type, retVal=False):

# Returns a conversion behavior suitable for a type
def getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs):
if type.isSequence():
if type.isSequence() or type.isMozMap():
return getConversionConfigForType(innerContainerType(type), isEnforceRange, isClamp, treatNullAs)
if type.isDOMString():
assert not isEnforceRange and not isClamp
@@ -1359,7 +1361,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
if returnType.nullable():
result = CGWrapper(result, pre="Option<", post=">")
return result
if returnType.isSequence():
if returnType.isSequence() or returnType.isMozMap():
result = getRetvalDeclarationForType(innerContainerType(returnType), descriptorProvider)
result = wrapInNativeContainerType(returnType, result)
if returnType.nullable():
@@ -1894,6 +1896,8 @@ def removeWrapperAndNullableTypes(types):
parentName = getIdentifier(descriptor.interface.parent).name
descriptor = descriptorProvider.getDescriptor(parentName)
extras += [descriptor.path, descriptor.bindingPath]
elif t.isType() and t.isMozMap():
extras += ['dom::bindings::mozmap::MozMap']
else:
if t.isEnum():
extras += [getModuleFromObject(t) + '::' + getIdentifier(t).name + 'Values']
@@ -2186,6 +2190,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
'dom::bindings::conversions::root_from_handlevalue',
'dom::bindings::error::throw_not_in_union',
'dom::bindings::js::Root',
'dom::bindings::mozmap::MozMap',
'dom::bindings::str::ByteString',
'dom::bindings::str::DOMString',
'dom::bindings::str::USVString',
@@ -4004,7 +4009,7 @@ def getUnionTypeTemplateVars(type, descriptorProvider):
elif type.isEnum():
name = type.inner.identifier.name
typeName = name
elif type.isSequence():
elif type.isSequence() or type.isMozMap():
name = type.name
inner = getUnionTypeTemplateVars(innerContainerType(type), descriptorProvider)
typeName = wrapInNativeContainerType(type, CGGeneric(inner["typeName"])).define()
@@ -4153,14 +4158,25 @@ def get_match(name):
else:
object = None

hasObjectTypes = interfaceObject or arrayObject or dateObject or nonPlatformObject or object
mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes)
if len(mozMapMemberTypes) > 0:
assert len(mozMapMemberTypes) == 1
typeName = mozMapMemberTypes[0].name
mozMapObject = CGGeneric(get_match(typeName))
names.append(typeName)
else:
mozMapObject = None

hasObjectTypes = interfaceObject or arrayObject or dateObject or nonPlatformObject or object or mozMapObject
if hasObjectTypes:
assert interfaceObject or arrayObject
assert interfaceObject or arrayObject or mozMapObject
templateBody = CGList([], "\n")
if interfaceObject:
templateBody.append(interfaceObject)
if arrayObject:
templateBody.append(arrayObject)
if mozMapObject:
templateBody.append(mozMapObject)
conversions.append(CGIfWrapper("value.get().is_object()", templateBody))
stringTypes = [t for t in memberTypes if t.isString() or t.isEnum()]
numericTypes = [t for t in memberTypes if t.isNumeric()]
@@ -5545,6 +5561,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'dom::bindings::proxyhandler::fill_property_descriptor',
'dom::bindings::proxyhandler::get_expando_object',
'dom::bindings::proxyhandler::get_property_descriptor',
'dom::bindings::mozmap::MozMap',
'dom::bindings::num::Finite',
'dom::bindings::str::ByteString',
'dom::bindings::str::DOMString',
@@ -44,6 +44,7 @@ pub use js::conversions::ConversionBehavior;
use js::conversions::latin1_to_string;
use js::error::throw_type_error;
use js::glue::{GetProxyPrivate, IsWrapper};
use js::glue::{RUST_JSID_IS_INT, RUST_JSID_TO_INT};
use js::glue::{RUST_JSID_IS_STRING, RUST_JSID_TO_STRING, UnwrapObject};
use js::jsapi::{HandleId, HandleObject, HandleValue, JSClass, JSContext};
use js::jsapi::{JSObject, JSString, JS_GetArrayBufferViewType, JS_GetClass};
@@ -129,6 +130,22 @@ pub fn string_jsid_to_string(cx: *mut JSContext, id: HandleId) -> DOMString {
}
}

/// Convert `id` to a `DOMString`. Returns `None` if `id` is not a string or
/// integer.
///
/// Handling of invalid UTF-16 in strings depends on the relevant option.

This comment has been minimized.

@jdm

jdm Sep 20, 2016

Member

Relevant option?

pub unsafe fn jsid_to_string(cx: *mut JSContext, id: HandleId) -> Option<DOMString> {
if RUST_JSID_IS_STRING(id) {
return Some(jsstring_to_str(cx, RUST_JSID_TO_STRING(id)));
}

if RUST_JSID_IS_INT(id) {
return Some(RUST_JSID_TO_INT(id).to_string().into());
}

None
}

// http://heycam.github.io/webidl/#es-USVString
impl ToJSValConvertible for USVString {
unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
@@ -140,6 +140,7 @@ pub mod inheritance;
pub mod interface;
pub mod iterable;
pub mod js;
pub mod mozmap;
pub mod namespace;
pub mod num;
pub mod proxyhandler;
@@ -0,0 +1,109 @@
/* 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::{FromJSValConvertible, ToJSValConvertible, ConversionResult};
use js::jsapi::GetPropertyKeys;
use js::jsapi::HandleValue;
use js::jsapi::JSContext;
use js::jsapi::JSITER_OWNONLY;
use js::jsapi::JSPROP_ENUMERATE;
use js::jsapi::JS_DefineUCProperty2;
use js::jsapi::JS_GetPropertyById;
use js::jsapi::JS_NewPlainObject;
use js::jsapi::MutableHandleValue;
use js::jsval::ObjectValue;
use js::jsval::UndefinedValue;
use js::rust::IdVector;
use std::collections::HashMap;
use std::ops::Deref;

/// The `MozMap` (open-ended dictionary) type.
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 try!(T::from_jsval(cx, property.handle(), config.clone())) {
ConversionResult::Success(property) => property,
ConversionResult::Failure(message) => return Ok(ConversionResult::Failure(message)),

This comment has been minimized.

@jdm

jdm Sep 20, 2016

Member

failure => return Ok(failure),

This comment has been minimized.

@Ms2ger

Ms2ger Sep 21, 2016

Author Contributor
   |
73 |                 failure => return Ok(failure),
   |                                      ^^^^^^^ expected struct `dom::bindings::mozmap::MozMap`, found type parameter
   |
   = note: expected type `js::conversions::ConversionResult<dom::bindings::mozmap::MozMap<T>>`
   = note:    found type `js::conversions::ConversionResult<T>`
};

let key = jsid_to_string(cx, id.handle()).unwrap();

This comment has been minimized.

@jdm

jdm Sep 20, 2016

Member

Couldn't this panic on an unpaired surrogate?

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, 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()));
}
}
@@ -10,6 +10,7 @@ use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::codegen::Bindings::TestBindingBinding;
use dom::bindings::codegen::Bindings::TestBindingBinding::{TestBindingMethods, TestDictionary};
use dom::bindings::codegen::Bindings::TestBindingBinding::{TestDictionaryDefaults, TestEnum};
use dom::bindings::codegen::UnionTypes;
use dom::bindings::codegen::UnionTypes::{BlobOrBoolean, BlobOrBlobSequence, LongOrLongSequenceSequence};
use dom::bindings::codegen::UnionTypes::{BlobOrString, BlobOrUnsignedLong, EventOrString};
use dom::bindings::codegen::UnionTypes::{ByteStringOrLong, ByteStringSequenceOrLongOrString};
@@ -21,6 +22,7 @@ use dom::bindings::codegen::UnionTypes::{StringOrUnsignedLong, StringOrBoolean,
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root;
use dom::bindings::mozmap::MozMap;
use dom::bindings::num::Finite;
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::str::{ByteString, DOMString, USVString};
@@ -619,6 +621,32 @@ impl TestBindingMethods for TestBinding {
fn FuncControlledMethodDisabled(&self) {}
fn FuncControlledMethodEnabled(&self) {}

fn PassMozMap(&self, _: MozMap<i32>) {}
fn PassNullableMozMap(&self, _: Option<MozMap<i32> >) {}
fn PassMozMapOfNullableInts(&self, _: MozMap<Option<i32>>) {}
fn PassOptionalMozMapOfNullableInts(&self, _: Option<MozMap<Option<i32>>>) {}
fn PassOptionalNullableMozMapOfNullableInts(&self, _: Option<Option<MozMap<Option<i32>> >>) {}
fn PassCastableObjectMozMap(&self, _: MozMap<Root<TestBinding>>) {}
fn PassNullableCastableObjectMozMap(&self, _: MozMap<Option<Root<TestBinding>>>) {}
fn PassCastableObjectNullableMozMap(&self, _: Option<MozMap<Root<TestBinding>>>) {}
fn PassNullableCastableObjectNullableMozMap(&self, _: Option<MozMap<Option<Root<TestBinding>>>>) {}
fn PassOptionalMozMap(&self, _: Option<MozMap<i32>>) {}
fn PassOptionalNullableMozMap(&self, _: Option<Option<MozMap<i32>>>) {}
fn PassOptionalNullableMozMapWithDefaultValue(&self, _: Option<MozMap<i32>>) {}
fn PassOptionalObjectMozMap(&self, _: Option<MozMap<Root<TestBinding>>>) {}
fn PassStringMozMap(&self, _: MozMap<DOMString>) {}
fn PassByteStringMozMap(&self, _: MozMap<ByteString>) {}
fn PassMozMapOfMozMaps(&self, _: MozMap<MozMap<i32>>) {}
fn PassMozMapUnion(&self, _: UnionTypes::LongOrByteStringMozMap) {}
fn PassMozMapUnion2(&self, _: UnionTypes::TestBindingOrByteStringMozMap) {}
fn PassMozMapUnion3(&self, _: UnionTypes::TestBindingOrByteStringSequenceSequenceOrByteStringMozMap) {}
fn ReceiveMozMap(&self) -> MozMap<i32> { MozMap::new() }
fn ReceiveNullableMozMap(&self) -> Option<MozMap<i32>> { Some(MozMap::new()) }
fn ReceiveMozMapOfNullableInts(&self) -> MozMap<Option<i32>> { MozMap::new() }
fn ReceiveNullableMozMapOfNullableInts(&self) -> Option<MozMap<Option<i32>>> { Some(MozMap::new()) }
fn ReceiveMozMapOfMozMaps(&self) -> MozMap<MozMap<i32>> { MozMap::new() }
fn ReceiveAnyMozMap(&self) -> MozMap<JSVal> { MozMap::new() }

fn PassSequenceSequence(&self, _seq: Vec<Vec<i32>>) {}
fn ReturnSequenceSequence(&self) -> Vec<Vec<i32>> { vec![] }
fn PassUnionSequenceSequence(&self, seq: LongOrLongSequenceSequence) {
@@ -429,6 +429,34 @@ interface TestBinding {
sequence<sequence<long>> returnSequenceSequence();
void passUnionSequenceSequence((long or sequence<sequence<long>>) seq);

void passMozMap(MozMap<long> arg);
void passNullableMozMap(MozMap<long>? arg);
void passMozMapOfNullableInts(MozMap<long?> arg);
void passOptionalMozMapOfNullableInts(optional MozMap<long?> arg);
void passOptionalNullableMozMapOfNullableInts(optional MozMap<long?>? arg);
void passCastableObjectMozMap(MozMap<TestBinding> arg);
void passNullableCastableObjectMozMap(MozMap<TestBinding?> arg);
void passCastableObjectNullableMozMap(MozMap<TestBinding>? arg);
void passNullableCastableObjectNullableMozMap(MozMap<TestBinding?>? arg);
void passOptionalMozMap(optional MozMap<long> arg);
void passOptionalNullableMozMap(optional MozMap<long>? arg);
void passOptionalNullableMozMapWithDefaultValue(optional MozMap<long>? arg = null);
void passOptionalObjectMozMap(optional MozMap<TestBinding> arg);
void passStringMozMap(MozMap<DOMString> arg);
void passByteStringMozMap(MozMap<ByteString> arg);
void passMozMapOfMozMaps(MozMap<MozMap<long>> arg);

void passMozMapUnion((long or MozMap<ByteString>) init);
void passMozMapUnion2((TestBinding or MozMap<ByteString>) init);
void passMozMapUnion3((TestBinding or sequence<sequence<ByteString>> or MozMap<ByteString>) init);

MozMap<long> receiveMozMap();
MozMap<long>? receiveNullableMozMap();
MozMap<long?> receiveMozMapOfNullableInts();
MozMap<long?>? receiveNullableMozMapOfNullableInts();
MozMap<MozMap<long>> receiveMozMapOfMozMaps();
MozMap<any> receiveAnyMozMap();

static attribute boolean booleanAttributeStatic;
static void receiveVoidStatic();
boolean BooleanMozPreference(DOMString pref_name);
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.