Support variadic interface arguments (fixes #8159)

We use a RootedVec value in codegen, of which we use the `r()` method to
pass `&[&T]` to the interface methods.
This commit is contained in:
Anthony Ramine 2015-10-25 22:43:13 +01:00
parent e66a361e08
commit acb13dc899
7 changed files with 105 additions and 63 deletions

View file

@ -102,29 +102,26 @@ numericTags = [
]
class CastableObjectUnwrapper():
def unwrapCastableObject(descriptor, source, codeOnFailure, conversionFunction):
"""
A class for unwrapping an object named by the "source" argument
based on the passed-in descriptor. Stringifies to a Rust expression of
A function for unwrapping an object named by the "source" argument
based on the passed-in descriptor. Returns the string of the Rust expression of
the appropriate type.
codeOnFailure is the code to run if unwrapping fails.
"""
def __init__(self, descriptor, source, codeOnFailure, handletype):
self.substitution = {
"source": source,
"codeOnFailure": CGIndenter(CGGeneric(codeOnFailure), 8).define(),
"handletype": handletype,
}
def __str__(self):
return string.Template("""\
match root_from_handle${handletype}(${source}) {
args = {
"failureCode": CGIndenter(CGGeneric(codeOnFailure), 8).define(),
"function": conversionFunction,
"source": source,
}
return """\
match %(function)s(%(source)s) {
Ok(val) => val,
Err(()) => {
${codeOnFailure}
%(failureCode)s
}
}""").substitute(self.substitution)
}""" % args
# We'll want to insert the indent at the beginnings of lines, but we
@ -757,12 +754,13 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
return handleOptional(template, declType, handleDefaultNull("None"))
if isMember:
descriptorType = descriptor.memberType
conversionFunction = "root_from_handlevalue"
descriptorType = descriptor.returnType
if isMember == "Variadic":
conversionFunction = "native_from_handlevalue"
descriptorType = descriptor.nativeType
elif isArgument:
descriptorType = descriptor.argumentType
else:
descriptorType = descriptor.nativeType
templateBody = ""
if descriptor.interface.isConsequential():
@ -782,8 +780,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
else:
unwrapFailureCode = failureCode
templateBody = str(
CastableObjectUnwrapper(descriptor, "${val}", unwrapFailureCode, "value"))
templateBody = unwrapCastableObject(
descriptor, "${val}", unwrapFailureCode, conversionFunction)
declType = CGGeneric(descriptorType)
if type.nullable():
@ -1187,31 +1185,26 @@ class CGArgumentConverter(CGThing):
variadicConversion = {
"val": string.Template("${args}.get(variadicArg)").substitute(replacer),
}
innerConverter = instantiateJSToNativeConversionTemplate(
template, variadicConversion, declType, "slot")
innerConverter = [instantiateJSToNativeConversionTemplate(
template, variadicConversion, declType, "slot")]
seqType = CGTemplatedType("Vec", declType)
arg = "arg%d" % index
vec = "Vec::with_capacity((%(argc)s - %(index)s) as usize)" % {'argc': argc, 'index': index}
variadicConversion = string.Template(
"let mut vector: ${seqType} = Vec::with_capacity((${argc} - ${index}) as usize);\n"
"for variadicArg in ${index}..${argc} {\n"
"${inner}\n"
" vector.push(slot);\n"
"}\n"
"vector"
).substitute({
"index": index,
"argc": argc,
"seqType": seqType.define(),
"inner": CGIndenter(innerConverter, 4).define(),
})
if argument.type.isGeckoInterface():
code = "let mut %s = RootedVec::new();\n*%s = %s;\n" % (arg, arg, vec)
innerConverter.append(CGGeneric("%s.push(JS::from_ref(&*slot));" % arg))
else:
code = "let mut %s = %s;\n" % (arg, vec)
innerConverter.append(CGGeneric("%s.push(slot);" % arg))
inner = CGIndenter(CGList(innerConverter, "\n"), 4).define()
variadicConversion = CGIfElseWrapper(condition,
CGGeneric(variadicConversion),
CGGeneric("Vec::new()")).define()
code += """\
for variadicArg in %(index)s..%(argc)s {
%(inner)s
}""" % {'argc': argc, 'index': index, 'inner': inner}
self.converter = instantiateJSToNativeConversionTemplate(
variadicConversion, replacementVariables, seqType, "arg%d" % index)
self.converter = CGGeneric(code)
def define(self):
return self.converter.define()
@ -1693,7 +1686,7 @@ class CGImports(CGWrapper):
class CGIfWrapper(CGWrapper):
def __init__(self, child, condition):
def __init__(self, condition, child):
pre = CGWrapper(CGGeneric(condition), pre="if ", post=" {\n",
reindent=True)
CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
@ -1923,7 +1916,7 @@ class CGList(CGThing):
class CGIfElseWrapper(CGList):
def __init__(self, condition, ifTrue, ifFalse):
kids = [CGIfWrapper(ifTrue, condition),
kids = [CGIfWrapper(condition, ifTrue),
CGWrapper(CGIndenter(ifFalse), pre=" else {\n", post="\n}")]
CGList.__init__(self, kids)
@ -3476,7 +3469,7 @@ def getUnionTypeTemplateVars(type, descriptorProvider):
if type.isGeckoInterface():
name = type.inner.identifier.name
typeName = descriptorProvider.getDescriptor(name).nativeType
typeName = descriptorProvider.getDescriptor(name).returnType
elif type.isEnum():
name = type.inner.identifier.name
typeName = name
@ -3629,7 +3622,7 @@ class CGUnionConversionStruct(CGThing):
if hasObjectTypes:
assert interfaceObject
templateBody = CGList([interfaceObject], "\n")
conversions.append(CGIfWrapper(templateBody, "value.get().is_object()"))
conversions.append(CGIfWrapper("value.get().is_object()", templateBody))
otherMemberTypes = [
t for t in memberTypes if t.isPrimitive() or t.isString() or t.isEnum()
@ -4082,7 +4075,7 @@ class CGProxySpecialOperation(CGPerSignatureCall):
return ""
wrap = CGGeneric(wrapForType(**self.templateValues))
wrap = CGIfWrapper(wrap, "found")
wrap = CGIfWrapper("found", wrap)
return "\n" + wrap.define()
@ -5216,7 +5209,7 @@ class CGBindingRoot(CGThing):
'dom::bindings::callback::wrap_call_this_object',
'dom::bindings::conversions::{ConversionBehavior, DOM_OBJECT_SLOT, IDLInterface}',
'dom::bindings::conversions::{FromJSValConvertible, StringificationBehavior}',
'dom::bindings::conversions::{ToJSValConvertible, jsid_to_str}',
'dom::bindings::conversions::{ToJSValConvertible, jsid_to_str, native_from_handlevalue}',
'dom::bindings::conversions::{private_from_object, root_from_object}',
'dom::bindings::conversions::{root_from_handleobject, root_from_handlevalue}',
'dom::bindings::codegen::{PrototypeList, RegisterBindings, UnionTypes}',
@ -5231,6 +5224,7 @@ class CGBindingRoot(CGThing):
'dom::bindings::num::Finite',
'dom::bindings::str::ByteString',
'dom::bindings::str::USVString',
'dom::bindings::trace::RootedVec',
'mem::heap_size_of_raw_self_and_children',
'libc',
'util::str::DOMString',
@ -5262,7 +5256,10 @@ def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, var
declType = info.declType
if variadic:
declType = CGWrapper(declType, pre="Vec<", post=">")
if ty.isGeckoInterface():
declType = CGWrapper(declType, pre="&[", post="]")
else:
declType = CGWrapper(declType, pre="Vec<", post=">")
elif optional and not defaultValue:
declType = CGWrapper(declType, pre="Option<", post=">")
@ -5636,8 +5633,8 @@ class CallbackMember(CGNativeMember):
).substitute({"arg": arg.identifier.name})
elif arg.optional and not arg.defaultValue:
conversion = (
CGIfWrapper(CGGeneric(conversion),
"%s.is_some()" % arg.identifier.name).define() +
CGIfWrapper("%s.is_some()" % arg.identifier.name,
CGGeneric(conversion)).define() +
" else if argc == %d {\n"
" // This is our current trailing argument; reduce argc\n"
" argc -= 1;\n"