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

@ -1,4 +1,5 @@
use backend::util::{ident_ty, leading_colon_path_ty, raw_ident, rust_ident};
use proc_macro2::{Ident, Span};
use syn;
use weedle::common::Identifier;
use weedle::term;
@ -501,16 +502,16 @@ impl<'a> IdlType<'a> {
IdlType::ArrayBuffer => js_sys("ArrayBuffer"),
IdlType::DataView => None,
IdlType::Int8Array => Some(array("i8", pos, false)),
IdlType::Uint8Array => Some(array("u8", pos, false)),
IdlType::Uint8ArrayMut => Some(array("u8", pos, true)),
IdlType::Uint8ClampedArray => None, // FIXME(#421)
IdlType::Int16Array => Some(array("i16", pos, false)),
IdlType::Uint16Array => Some(array("u16", pos, false)),
IdlType::Int32Array => Some(array("i32", pos, false)),
IdlType::Uint32Array => Some(array("u32", pos, false)),
IdlType::Float32Array => Some(array("f32", pos, false)),
IdlType::Float64Array => Some(array("f64", pos, false)),
IdlType::Int8Array => Some(array("i8", pos)),
IdlType::Uint8Array => Some(array("u8", pos)),
IdlType::Uint8ArrayMut => Some(array("u8", pos)),
IdlType::Uint8ClampedArray => Some(clamped(array("u8", pos))),
IdlType::Int16Array => Some(array("i16", pos)),
IdlType::Uint16Array => Some(array("u16", pos)),
IdlType::Int32Array => Some(array("i32", pos)),
IdlType::Uint32Array => Some(array("u32", pos)),
IdlType::Float32Array => Some(array("f32", pos)),
IdlType::Float64Array => Some(array("f64", pos)),
IdlType::ArrayBufferView | IdlType::BufferSource => js_sys("Object"),
IdlType::Interface(name)
@ -709,3 +710,26 @@ fn idl_type_flatten_test() {
],
);
}
/// From `T` create `::wasm_bindgen::Clamped<T>`
fn clamped(t: syn::Type) -> syn::Type {
let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
colon2_token: None,
lt_token: Default::default(),
args: vec![syn::GenericArgument::Type(t)].into_iter().collect(),
gt_token: Default::default(),
});
let ident = raw_ident("Clamped");
let seg = syn::PathSegment { ident, arguments };
syn::TypePath {
qself: None,
path: syn::Path {
leading_colon: Some(Default::default()),
segments: vec![
Ident::new("wasm_bindgen", Span::call_site()).into(),
seg,
].into_iter().collect(),
},
}.into()
}

View File

@ -156,7 +156,7 @@ fn builtin_idents() -> BTreeSet<Ident> {
vec![
"str", "char", "bool", "JsValue", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64",
"usize", "isize", "f32", "f64", "Result", "String", "Vec", "Option",
"Array", "ArrayBuffer", "Object", "Promise", "Function",
"Array", "ArrayBuffer", "Object", "Promise", "Function", "Clamped",
].into_iter()
.map(|id| proc_macro2::Ident::new(id, proc_macro2::Span::call_site())),
)

View File

@ -63,10 +63,10 @@ pub fn mdn_doc(class: &str, method: Option<&str>) -> String {
}
// Array type is borrowed for arguments (`&[T]`) and owned for return value (`Vec<T>`).
pub(crate) fn array(base_ty: &str, pos: TypePosition, mutable: bool) -> syn::Type {
pub(crate) fn array(base_ty: &str, pos: TypePosition) -> syn::Type {
match pos {
TypePosition::Argument => {
shared_ref(slice_ty(ident_ty(raw_ident(base_ty))), mutable)
shared_ref(slice_ty(ident_ty(raw_ident(base_ty))), /*mutable =*/ true)
}
TypePosition::Return => {
vec_ty(ident_ty(raw_ident(base_ty)))