Implement support for Uint8ClampedArray

This commit implements support for binding APIs that take
`Uint8ClampedArray` in JS. This is pretty rare but comes up in a
`web-sys` binding or two, and we're now able to bind these APIs instead
of having to omit the bindings.

The `Uint8ClampedArray` type is bound by using the `Clamped` marker
struct in Rust. For example this is declaring a JS API that takes
`Uint8ClampedArray`:

    use wasm_bindgen::Clamped;

    #[wasm_bindgen]
    extern {
        fn takes_clamped(a: Clamped<&[u8]>);
    }

The `Clamped` type currently only works when wrapping the `&[u8]`, `&mut
[u8]`, and `Vec<u8>` types. Everything else will produce an error at
`wasm-bindgen` time.

Closes #421
This commit is contained in:
Alex Crichton
2018-09-24 13:49:12 -07:00
parent d10ca579e4
commit 7b495468f6
15 changed files with 169 additions and 60 deletions

View File

@ -35,6 +35,7 @@ tys! {
CHAR
OPTIONAL
UNIT
CLAMPED
}
#[derive(Debug)]
@ -63,6 +64,7 @@ pub enum Descriptor {
Char,
Option(Box<Descriptor>),
Unit,
Clamped(Box<Descriptor>),
}
#[derive(Debug)]
@ -81,6 +83,7 @@ pub struct Closure {
pub enum VectorKind {
I8,
U8,
ClampedU8,
I16,
U16,
I32,
@ -131,6 +134,7 @@ impl Descriptor {
}
CHAR => Descriptor::Char,
UNIT => Descriptor::Unit,
CLAMPED => Descriptor::Clamped(Box::new(Descriptor::_decode(data))),
other => panic!("unknown descriptor: {}", other),
}
}
@ -219,6 +223,12 @@ impl Descriptor {
Descriptor::Slice(ref d) => &**d,
_ => return None,
},
Descriptor::Clamped(ref d) => {
match d.vector_kind()? {
VectorKind::U8 => return Some(VectorKind::ClampedU8),
_ => return None,
}
}
_ => return None,
};
match *inner {
@ -268,6 +278,13 @@ impl Descriptor {
}
}
pub fn is_clamped_by_ref(&self) -> bool {
match self {
Descriptor::Clamped(d) => d.is_by_ref(),
_ => false,
}
}
pub fn is_mut_ref(&self) -> bool {
match *self {
Descriptor::RefMut(_) => true,
@ -311,6 +328,7 @@ impl VectorKind {
VectorKind::String => "string",
VectorKind::I8 => "Int8Array",
VectorKind::U8 => "Uint8Array",
VectorKind::ClampedU8 => "Uint8ClampedArray",
VectorKind::I16 => "Int16Array",
VectorKind::U16 => "Uint16Array",
VectorKind::I32 => "Int32Array",
@ -328,6 +346,7 @@ impl VectorKind {
VectorKind::String => 1,
VectorKind::I8 => 1,
VectorKind::U8 => 1,
VectorKind::ClampedU8 => 1,
VectorKind::I16 => 2,
VectorKind::U16 => 2,
VectorKind::I32 => 4,

View File

@ -159,7 +159,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
i = i,
val = val,
));
if arg.is_by_ref() {
if arg.is_by_ref() || arg.is_clamped_by_ref() {
if optional {
bail!("optional slices aren't currently supported");
}

View File

@ -1173,6 +1173,11 @@ impl<'a> Context<'a> {
self.arrayget("getArrayU8FromWasm", "getUint8Memory", 1);
}
fn expose_get_clamped_array_u8_from_wasm(&mut self) {
self.expose_clamped_uint8_memory();
self.arrayget("getClampedArrayU8FromWasm", "getUint8ClampedMemory", 1);
}
fn expose_get_array_i16_from_wasm(&mut self) {
self.expose_int16_memory();
self.arrayget("getArrayI16FromWasm", "getInt16Memory", 2);
@ -1237,6 +1242,10 @@ impl<'a> Context<'a> {
self.memview("getUint8Memory", "Uint8Array");
}
fn expose_clamped_uint8_memory(&mut self) {
self.memview("getUint8ClampedMemory", "Uint8ClampedArray");
}
fn expose_int16_memory(&mut self) {
self.memview("getInt16Memory", "Int16Array");
}
@ -1283,6 +1292,10 @@ impl<'a> Context<'a> {
self.expose_uint8_memory();
"getUint8Memory"
}
VectorKind::ClampedU8 => {
self.expose_clamped_uint8_memory();
"getUint8ClampedMemory"
}
VectorKind::I16 => {
self.expose_int16_memory();
"getInt16Memory"
@ -1444,7 +1457,7 @@ impl<'a> Context<'a> {
self.expose_pass_string_to_wasm()?;
"passStringToWasm"
}
VectorKind::I8 | VectorKind::U8 => {
VectorKind::I8 | VectorKind::U8 | VectorKind::ClampedU8 => {
self.expose_pass_array8_to_wasm()?;
"passArray8ToWasm"
}
@ -1490,6 +1503,10 @@ impl<'a> Context<'a> {
self.expose_get_array_u8_from_wasm();
"getArrayU8FromWasm"
}
VectorKind::ClampedU8 => {
self.expose_get_clamped_array_u8_from_wasm();
"getClampedArrayU8FromWasm"
}
VectorKind::I16 => {
self.expose_get_array_i16_from_wasm();
"getArrayI16FromWasm"

View File

@ -112,7 +112,7 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
prefix = if optional { format!("{} == 0 ? undefined : ", abi) } else { String::new() },
));
if !arg.is_by_ref() {
if !arg.is_by_ref() && !arg.is_clamped_by_ref() {
self.prelude(&format!(
"\
{start}