mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-31 01:11:06 +00:00
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:
parent
d10ca579e4
commit
7b495468f6
@ -35,6 +35,7 @@ tys! {
|
|||||||
CHAR
|
CHAR
|
||||||
OPTIONAL
|
OPTIONAL
|
||||||
UNIT
|
UNIT
|
||||||
|
CLAMPED
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -63,6 +64,7 @@ pub enum Descriptor {
|
|||||||
Char,
|
Char,
|
||||||
Option(Box<Descriptor>),
|
Option(Box<Descriptor>),
|
||||||
Unit,
|
Unit,
|
||||||
|
Clamped(Box<Descriptor>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -81,6 +83,7 @@ pub struct Closure {
|
|||||||
pub enum VectorKind {
|
pub enum VectorKind {
|
||||||
I8,
|
I8,
|
||||||
U8,
|
U8,
|
||||||
|
ClampedU8,
|
||||||
I16,
|
I16,
|
||||||
U16,
|
U16,
|
||||||
I32,
|
I32,
|
||||||
@ -131,6 +134,7 @@ impl Descriptor {
|
|||||||
}
|
}
|
||||||
CHAR => Descriptor::Char,
|
CHAR => Descriptor::Char,
|
||||||
UNIT => Descriptor::Unit,
|
UNIT => Descriptor::Unit,
|
||||||
|
CLAMPED => Descriptor::Clamped(Box::new(Descriptor::_decode(data))),
|
||||||
other => panic!("unknown descriptor: {}", other),
|
other => panic!("unknown descriptor: {}", other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,6 +223,12 @@ impl Descriptor {
|
|||||||
Descriptor::Slice(ref d) => &**d,
|
Descriptor::Slice(ref d) => &**d,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
},
|
},
|
||||||
|
Descriptor::Clamped(ref d) => {
|
||||||
|
match d.vector_kind()? {
|
||||||
|
VectorKind::U8 => return Some(VectorKind::ClampedU8),
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
match *inner {
|
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 {
|
pub fn is_mut_ref(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Descriptor::RefMut(_) => true,
|
Descriptor::RefMut(_) => true,
|
||||||
@ -311,6 +328,7 @@ impl VectorKind {
|
|||||||
VectorKind::String => "string",
|
VectorKind::String => "string",
|
||||||
VectorKind::I8 => "Int8Array",
|
VectorKind::I8 => "Int8Array",
|
||||||
VectorKind::U8 => "Uint8Array",
|
VectorKind::U8 => "Uint8Array",
|
||||||
|
VectorKind::ClampedU8 => "Uint8ClampedArray",
|
||||||
VectorKind::I16 => "Int16Array",
|
VectorKind::I16 => "Int16Array",
|
||||||
VectorKind::U16 => "Uint16Array",
|
VectorKind::U16 => "Uint16Array",
|
||||||
VectorKind::I32 => "Int32Array",
|
VectorKind::I32 => "Int32Array",
|
||||||
@ -328,6 +346,7 @@ impl VectorKind {
|
|||||||
VectorKind::String => 1,
|
VectorKind::String => 1,
|
||||||
VectorKind::I8 => 1,
|
VectorKind::I8 => 1,
|
||||||
VectorKind::U8 => 1,
|
VectorKind::U8 => 1,
|
||||||
|
VectorKind::ClampedU8 => 1,
|
||||||
VectorKind::I16 => 2,
|
VectorKind::I16 => 2,
|
||||||
VectorKind::U16 => 2,
|
VectorKind::U16 => 2,
|
||||||
VectorKind::I32 => 4,
|
VectorKind::I32 => 4,
|
||||||
|
@ -159,7 +159,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
i = i,
|
i = i,
|
||||||
val = val,
|
val = val,
|
||||||
));
|
));
|
||||||
if arg.is_by_ref() {
|
if arg.is_by_ref() || arg.is_clamped_by_ref() {
|
||||||
if optional {
|
if optional {
|
||||||
bail!("optional slices aren't currently supported");
|
bail!("optional slices aren't currently supported");
|
||||||
}
|
}
|
||||||
|
@ -1173,6 +1173,11 @@ impl<'a> Context<'a> {
|
|||||||
self.arrayget("getArrayU8FromWasm", "getUint8Memory", 1);
|
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) {
|
fn expose_get_array_i16_from_wasm(&mut self) {
|
||||||
self.expose_int16_memory();
|
self.expose_int16_memory();
|
||||||
self.arrayget("getArrayI16FromWasm", "getInt16Memory", 2);
|
self.arrayget("getArrayI16FromWasm", "getInt16Memory", 2);
|
||||||
@ -1237,6 +1242,10 @@ impl<'a> Context<'a> {
|
|||||||
self.memview("getUint8Memory", "Uint8Array");
|
self.memview("getUint8Memory", "Uint8Array");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expose_clamped_uint8_memory(&mut self) {
|
||||||
|
self.memview("getUint8ClampedMemory", "Uint8ClampedArray");
|
||||||
|
}
|
||||||
|
|
||||||
fn expose_int16_memory(&mut self) {
|
fn expose_int16_memory(&mut self) {
|
||||||
self.memview("getInt16Memory", "Int16Array");
|
self.memview("getInt16Memory", "Int16Array");
|
||||||
}
|
}
|
||||||
@ -1283,6 +1292,10 @@ impl<'a> Context<'a> {
|
|||||||
self.expose_uint8_memory();
|
self.expose_uint8_memory();
|
||||||
"getUint8Memory"
|
"getUint8Memory"
|
||||||
}
|
}
|
||||||
|
VectorKind::ClampedU8 => {
|
||||||
|
self.expose_clamped_uint8_memory();
|
||||||
|
"getUint8ClampedMemory"
|
||||||
|
}
|
||||||
VectorKind::I16 => {
|
VectorKind::I16 => {
|
||||||
self.expose_int16_memory();
|
self.expose_int16_memory();
|
||||||
"getInt16Memory"
|
"getInt16Memory"
|
||||||
@ -1444,7 +1457,7 @@ impl<'a> Context<'a> {
|
|||||||
self.expose_pass_string_to_wasm()?;
|
self.expose_pass_string_to_wasm()?;
|
||||||
"passStringToWasm"
|
"passStringToWasm"
|
||||||
}
|
}
|
||||||
VectorKind::I8 | VectorKind::U8 => {
|
VectorKind::I8 | VectorKind::U8 | VectorKind::ClampedU8 => {
|
||||||
self.expose_pass_array8_to_wasm()?;
|
self.expose_pass_array8_to_wasm()?;
|
||||||
"passArray8ToWasm"
|
"passArray8ToWasm"
|
||||||
}
|
}
|
||||||
@ -1490,6 +1503,10 @@ impl<'a> Context<'a> {
|
|||||||
self.expose_get_array_u8_from_wasm();
|
self.expose_get_array_u8_from_wasm();
|
||||||
"getArrayU8FromWasm"
|
"getArrayU8FromWasm"
|
||||||
}
|
}
|
||||||
|
VectorKind::ClampedU8 => {
|
||||||
|
self.expose_get_clamped_array_u8_from_wasm();
|
||||||
|
"getClampedArrayU8FromWasm"
|
||||||
|
}
|
||||||
VectorKind::I16 => {
|
VectorKind::I16 => {
|
||||||
self.expose_get_array_i16_from_wasm();
|
self.expose_get_array_i16_from_wasm();
|
||||||
"getArrayI16FromWasm"
|
"getArrayI16FromWasm"
|
||||||
|
@ -112,7 +112,7 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
prefix = if optional { format!("{} == 0 ? undefined : ", abi) } else { String::new() },
|
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!(
|
self.prelude(&format!(
|
||||||
"\
|
"\
|
||||||
{start}
|
{start}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use js_sys::Object;
|
use js_sys::Object;
|
||||||
|
use wasm_bindgen::Clamped;
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/array.rs"));
|
include!(concat!(env!("OUT_DIR"), "/array.rs"));
|
||||||
@ -9,12 +10,13 @@ fn take_and_return_a_bunch_of_slices() {
|
|||||||
assert_eq!(f.strings("y"), "x");
|
assert_eq!(f.strings("y"), "x");
|
||||||
assert_eq!(f.byte_strings("yz"), "xx");
|
assert_eq!(f.byte_strings("yz"), "xx");
|
||||||
assert_eq!(f.usv_strings("abc"), "efg");
|
assert_eq!(f.usv_strings("abc"), "efg");
|
||||||
assert_eq!(f.f32(&[1.0, 2.0]), [3.0, 4.0, 5.0]);
|
assert_eq!(f.f32(&mut [1.0, 2.0]), [3.0, 4.0, 5.0]);
|
||||||
assert_eq!(f.f64(&[1.0, 2.0]), [3.0, 4.0, 5.0]);
|
assert_eq!(f.f64(&mut [1.0, 2.0]), [3.0, 4.0, 5.0]);
|
||||||
assert_eq!(f.i8(&[1, 2]), [3, 4, 5]);
|
assert_eq!(f.i8(&mut [1, 2]), [3, 4, 5]);
|
||||||
assert_eq!(f.i16(&[1, 2]), [3, 4, 5]);
|
assert_eq!(f.i16(&mut [1, 2]), [3, 4, 5]);
|
||||||
assert_eq!(f.i32(&[1, 2]), [3, 4, 5]);
|
assert_eq!(f.i32(&mut [1, 2]), [3, 4, 5]);
|
||||||
assert_eq!(f.u8(&[1, 2]), [3, 4, 5]);
|
assert_eq!(f.u8(&mut [1, 2]), [3, 4, 5]);
|
||||||
assert_eq!(f.u16(&[1, 2]), [3, 4, 5]);
|
assert_eq!(f.u16(&mut [1, 2]), [3, 4, 5]);
|
||||||
assert_eq!(f.u32(&[1, 2]), [3, 4, 5]);
|
assert_eq!(f.u32(&mut [1, 2]), [3, 4, 5]);
|
||||||
|
assert_eq!(f.u8_clamped(Clamped(&mut [1, 2])).0, [3, 4, 5]);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use backend::util::{ident_ty, leading_colon_path_ty, raw_ident, rust_ident};
|
use backend::util::{ident_ty, leading_colon_path_ty, raw_ident, rust_ident};
|
||||||
|
use proc_macro2::{Ident, Span};
|
||||||
use syn;
|
use syn;
|
||||||
use weedle::common::Identifier;
|
use weedle::common::Identifier;
|
||||||
use weedle::term;
|
use weedle::term;
|
||||||
@ -501,16 +502,16 @@ impl<'a> IdlType<'a> {
|
|||||||
|
|
||||||
IdlType::ArrayBuffer => js_sys("ArrayBuffer"),
|
IdlType::ArrayBuffer => js_sys("ArrayBuffer"),
|
||||||
IdlType::DataView => None,
|
IdlType::DataView => None,
|
||||||
IdlType::Int8Array => Some(array("i8", pos, false)),
|
IdlType::Int8Array => Some(array("i8", pos)),
|
||||||
IdlType::Uint8Array => Some(array("u8", pos, false)),
|
IdlType::Uint8Array => Some(array("u8", pos)),
|
||||||
IdlType::Uint8ArrayMut => Some(array("u8", pos, true)),
|
IdlType::Uint8ArrayMut => Some(array("u8", pos)),
|
||||||
IdlType::Uint8ClampedArray => None, // FIXME(#421)
|
IdlType::Uint8ClampedArray => Some(clamped(array("u8", pos))),
|
||||||
IdlType::Int16Array => Some(array("i16", pos, false)),
|
IdlType::Int16Array => Some(array("i16", pos)),
|
||||||
IdlType::Uint16Array => Some(array("u16", pos, false)),
|
IdlType::Uint16Array => Some(array("u16", pos)),
|
||||||
IdlType::Int32Array => Some(array("i32", pos, false)),
|
IdlType::Int32Array => Some(array("i32", pos)),
|
||||||
IdlType::Uint32Array => Some(array("u32", pos, false)),
|
IdlType::Uint32Array => Some(array("u32", pos)),
|
||||||
IdlType::Float32Array => Some(array("f32", pos, false)),
|
IdlType::Float32Array => Some(array("f32", pos)),
|
||||||
IdlType::Float64Array => Some(array("f64", pos, false)),
|
IdlType::Float64Array => Some(array("f64", pos)),
|
||||||
|
|
||||||
IdlType::ArrayBufferView | IdlType::BufferSource => js_sys("Object"),
|
IdlType::ArrayBufferView | IdlType::BufferSource => js_sys("Object"),
|
||||||
IdlType::Interface(name)
|
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()
|
||||||
|
}
|
||||||
|
@ -156,7 +156,7 @@ fn builtin_idents() -> BTreeSet<Ident> {
|
|||||||
vec![
|
vec![
|
||||||
"str", "char", "bool", "JsValue", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64",
|
"str", "char", "bool", "JsValue", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64",
|
||||||
"usize", "isize", "f32", "f64", "Result", "String", "Vec", "Option",
|
"usize", "isize", "f32", "f64", "Result", "String", "Vec", "Option",
|
||||||
"Array", "ArrayBuffer", "Object", "Promise", "Function",
|
"Array", "ArrayBuffer", "Object", "Promise", "Function", "Clamped",
|
||||||
].into_iter()
|
].into_iter()
|
||||||
.map(|id| proc_macro2::Ident::new(id, proc_macro2::Span::call_site())),
|
.map(|id| proc_macro2::Ident::new(id, proc_macro2::Span::call_site())),
|
||||||
)
|
)
|
||||||
|
@ -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>`).
|
// 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 {
|
match pos {
|
||||||
TypePosition::Argument => {
|
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 => {
|
TypePosition::Return => {
|
||||||
vec_ty(ident_ty(raw_ident(base_ty)))
|
vec_ty(ident_ty(raw_ident(base_ty)))
|
||||||
|
@ -8,7 +8,6 @@ crate-type = ["cdylib"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasm-bindgen = { path = "../.." }
|
wasm-bindgen = { path = "../.." }
|
||||||
js-sys = { path = '../../crates/js-sys' }
|
|
||||||
|
|
||||||
[dependencies.web-sys]
|
[dependencies.web-sys]
|
||||||
path = '../../crates/web-sys'
|
path = '../../crates/web-sys'
|
||||||
|
@ -1,24 +1,10 @@
|
|||||||
extern crate js_sys;
|
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
extern crate web_sys;
|
extern crate web_sys;
|
||||||
|
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::Clamped;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use web_sys::CanvasRenderingContext2d;
|
use web_sys::{CanvasRenderingContext2d, ImageData};
|
||||||
use js_sys::{WebAssembly, Uint8ClampedArray};
|
|
||||||
|
|
||||||
// Unfortunately `web-sys` at this time doesn't bind APIs with
|
|
||||||
// `Uint8ClampedArray`. For more information see rustwasm/wasm-bindgen#421.
|
|
||||||
//
|
|
||||||
// For now we just bind it ourselves and do some manual frobbing below.
|
|
||||||
#[wasm_bindgen]
|
|
||||||
extern "C" {
|
|
||||||
type ImageData;
|
|
||||||
|
|
||||||
#[wasm_bindgen(constructor)]
|
|
||||||
fn new(arr: &Uint8ClampedArray, width: u32, height: u32) -> ImageData;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn draw(
|
pub fn draw(
|
||||||
@ -30,22 +16,9 @@ pub fn draw(
|
|||||||
) -> Result<(), JsValue> {
|
) -> Result<(), JsValue> {
|
||||||
// The real workhorse of this algorithm, generating pixel data
|
// The real workhorse of this algorithm, generating pixel data
|
||||||
let c = Complex { real, imaginary, };
|
let c = Complex { real, imaginary, };
|
||||||
let data = get_julia_set(width, height, c);
|
let mut data = get_julia_set(width, height, c);
|
||||||
|
let data = ImageData::new_with_u8_clamped_array_and_sh(Clamped(&mut data), width, height)?;
|
||||||
// And now that we've got some pixels, let's create an `ImageData` with the
|
ctx.put_image_data(&data, 0.0, 0.0)
|
||||||
// pixels and then ship it off to the canvas.
|
|
||||||
//
|
|
||||||
// See notes in the `wasm-in-wasm` example for why this is a bit dangerous
|
|
||||||
let my_memory = wasm_bindgen::memory()
|
|
||||||
.dyn_into::<WebAssembly::Memory>()
|
|
||||||
.unwrap();
|
|
||||||
let uint8_array = Uint8ClampedArray::new(&my_memory.buffer())
|
|
||||||
.subarray(
|
|
||||||
data.as_ptr() as u32,
|
|
||||||
data.as_ptr() as u32 + data.len() as u32,
|
|
||||||
);
|
|
||||||
let data = ImageData::new(&uint8_array, width, height);
|
|
||||||
ctx.put_image_data(data.unchecked_ref(), 0.0, 0.0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_julia_set(width: u32, height: u32, c: Complex) -> Vec<u8> {
|
fn get_julia_set(width: u32, height: u32, c: Complex) -> Vec<u8> {
|
||||||
|
@ -4,7 +4,7 @@ use core::mem::{self, ManuallyDrop};
|
|||||||
use convert::{Stack, FromWasmAbi, IntoWasmAbi, RefFromWasmAbi};
|
use convert::{Stack, FromWasmAbi, IntoWasmAbi, RefFromWasmAbi};
|
||||||
use convert::{OptionIntoWasmAbi, OptionFromWasmAbi, ReturnWasmAbi};
|
use convert::{OptionIntoWasmAbi, OptionFromWasmAbi, ReturnWasmAbi};
|
||||||
use convert::traits::WasmAbi;
|
use convert::traits::WasmAbi;
|
||||||
use JsValue;
|
use {JsValue, Clamped};
|
||||||
|
|
||||||
unsafe impl WasmAbi for () {}
|
unsafe impl WasmAbi for () {}
|
||||||
|
|
||||||
@ -373,6 +373,22 @@ impl<T: OptionFromWasmAbi> FromWasmAbi for Option<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: IntoWasmAbi> IntoWasmAbi for Clamped<T> {
|
||||||
|
type Abi = T::Abi;
|
||||||
|
|
||||||
|
fn into_abi(self, extra: &mut Stack) -> Self::Abi {
|
||||||
|
self.0.into_abi(extra)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: FromWasmAbi> FromWasmAbi for Clamped<T> {
|
||||||
|
type Abi = T::Abi;
|
||||||
|
|
||||||
|
unsafe fn from_abi(js: T::Abi, extra: &mut Stack) -> Self {
|
||||||
|
Clamped(T::from_abi(js, extra))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl IntoWasmAbi for () {
|
impl IntoWasmAbi for () {
|
||||||
type Abi = ();
|
type Abi = ();
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#![doc(hidden)]
|
#![doc(hidden)]
|
||||||
|
|
||||||
use JsValue;
|
use {JsValue, Clamped};
|
||||||
|
|
||||||
macro_rules! tys {
|
macro_rules! tys {
|
||||||
($($a:ident)*) => (tys! { @ ($($a)*) 0 });
|
($($a:ident)*) => (tys! { @ ($($a)*) 0 });
|
||||||
@ -40,6 +40,7 @@ tys! {
|
|||||||
CHAR
|
CHAR
|
||||||
OPTIONAL
|
OPTIONAL
|
||||||
UNIT
|
UNIT
|
||||||
|
CLAMPED
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] // see `interpret.rs` in the the cli-support crate
|
#[inline(always)] // see `interpret.rs` in the the cli-support crate
|
||||||
@ -202,3 +203,10 @@ impl<T: WasmDescribe> WasmDescribe for Result<T, JsValue> {
|
|||||||
T::describe()
|
T::describe()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: WasmDescribe> WasmDescribe for Clamped<T> {
|
||||||
|
fn describe() {
|
||||||
|
inform(CLAMPED);
|
||||||
|
T::describe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
31
src/lib.rs
31
src/lib.rs
@ -19,7 +19,7 @@ extern crate wasm_bindgen_macro;
|
|||||||
use core::cell::UnsafeCell;
|
use core::cell::UnsafeCell;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::ops::Deref;
|
use core::ops::{Deref, DerefMut};
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
use convert::FromWasmAbi;
|
use convert::FromWasmAbi;
|
||||||
@ -864,3 +864,32 @@ pub mod __rt {
|
|||||||
FOO.store(0, Ordering::SeqCst);
|
FOO.store(0, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A wrapper type around slices and vectors for binding the `Uint8ClampedArray`
|
||||||
|
/// array in JS.
|
||||||
|
///
|
||||||
|
/// If you need to invoke a JS API which must take `Uint8ClampedArray` array,
|
||||||
|
/// then you can define it as taking one of these types:
|
||||||
|
///
|
||||||
|
/// * `Clamped<&[u8]>`
|
||||||
|
/// * `Clamped<&mut [u8]>`
|
||||||
|
/// * `Clamped<Vec<u8>>`
|
||||||
|
///
|
||||||
|
/// All of these types will show up as `Uint8ClampedArray` in JS and will have
|
||||||
|
/// different forms of ownership in Rust.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Debug, Eq)]
|
||||||
|
pub struct Clamped<T>(pub T);
|
||||||
|
|
||||||
|
impl<T> Deref for Clamped<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DerefMut for Clamped<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -204,3 +204,11 @@ exports.js_return_vec = () => {
|
|||||||
assert.strictEqual(bad[8], 9);
|
assert.strictEqual(bad[8], 9);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.js_clamped = (a, offset) => {
|
||||||
|
assert.ok(a instanceof Uint8ClampedArray);
|
||||||
|
assert.equal(a.length, 3);
|
||||||
|
assert.equal(a[0], offset + 0);
|
||||||
|
assert.equal(a[1], offset + 1);
|
||||||
|
assert.equal(a[2], offset + 2);
|
||||||
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
|
use wasm_bindgen::Clamped;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
#[wasm_bindgen(module = "tests/wasm/slice.js")]
|
#[wasm_bindgen(module = "tests/wasm/slice.js")]
|
||||||
@ -12,6 +13,12 @@ extern {
|
|||||||
fn js_export_mut();
|
fn js_export_mut();
|
||||||
|
|
||||||
fn js_return_vec();
|
fn js_return_vec();
|
||||||
|
|
||||||
|
fn js_clamped(val: Clamped<&[u8]>, offset: u8);
|
||||||
|
#[wasm_bindgen(js_name = js_clamped)]
|
||||||
|
fn js_clamped2(val: Clamped<Vec<u8>>, offset: u8);
|
||||||
|
#[wasm_bindgen(js_name = js_clamped)]
|
||||||
|
fn js_clamped3(val: Clamped<&mut [u8]>, offset: u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! export_macro {
|
macro_rules! export_macro {
|
||||||
@ -208,3 +215,10 @@ impl ReturnVecApplication {
|
|||||||
fn return_vec() {
|
fn return_vec() {
|
||||||
js_return_vec();
|
js_return_vec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn take_clamped() {
|
||||||
|
js_clamped(Clamped(&[1, 2, 3]), 1);
|
||||||
|
js_clamped2(Clamped(vec![4, 5, 6]), 4);
|
||||||
|
js_clamped3(Clamped(&mut [7, 8, 9]), 7);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user