From 176eedc63b7ecba0f50723470b3e3b3b25eb48da Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 7 Nov 2018 10:37:43 -0800 Subject: [PATCH 1/2] Make `to_idl_type` infallible This commit makes the `to_idl_type` infallible, returning a new enum variant, `UnknownInterface`, in the one location that we still return `None`. By making this infallible we can ensure that expansion of unions which have unknown types still generate methods for all the variants which we actually have all the methods for! --- crates/webidl/src/idl_type.rs | 122 +++++++++++++++++----------------- crates/webidl/src/lib.rs | 8 +-- crates/webidl/src/util.rs | 14 ++-- 3 files changed, 66 insertions(+), 78 deletions(-) diff --git a/crates/webidl/src/idl_type.rs b/crates/webidl/src/idl_type.rs index 8d20eb13a73..6d3847d3090 100644 --- a/crates/webidl/src/idl_type.rs +++ b/crates/webidl/src/idl_type.rs @@ -63,24 +63,26 @@ pub(crate) enum IdlType<'a> { Any, Void, + + UnknownInterface(&'a str), } pub(crate) trait ToIdlType<'a> { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option>; + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a>; } impl<'a> ToIdlType<'a> for UnionType<'a> { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { let mut idl_types = Vec::with_capacity(self.body.list.len()); for t in &self.body.list { - idl_types.push(t.to_idl_type(record)?); + idl_types.push(t.to_idl_type(record)); } - Some(IdlType::Union(idl_types)) + IdlType::Union(idl_types) } } impl<'a> ToIdlType<'a> for Type<'a> { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { match self { Type::Single(t) => t.to_idl_type(record), Type::Union(t) => t.to_idl_type(record), @@ -89,7 +91,7 @@ impl<'a> ToIdlType<'a> for Type<'a> { } impl<'a> ToIdlType<'a> for SingleType<'a> { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { match self { SingleType::Any(t) => t.to_idl_type(record), SingleType::NonAny(t) => t.to_idl_type(record), @@ -98,7 +100,7 @@ impl<'a> ToIdlType<'a> for SingleType<'a> { } impl<'a> ToIdlType<'a> for NonAnyType<'a> { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { match self { NonAnyType::Promise(t) => t.to_idl_type(record), NonAnyType::Integer(t) => t.to_idl_type(record), @@ -134,42 +136,36 @@ impl<'a> ToIdlType<'a> for NonAnyType<'a> { } impl<'a> ToIdlType<'a> for SequenceType<'a> { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { - Some(IdlType::Sequence(Box::new( - self.generics.body.to_idl_type(record)?, - ))) + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { + IdlType::Sequence(Box::new(self.generics.body.to_idl_type(record))) } } impl<'a> ToIdlType<'a> for FrozenArrayType<'a> { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { - Some(IdlType::FrozenArray(Box::new( - self.generics.body.to_idl_type(record)?, - ))) + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { + IdlType::FrozenArray(Box::new(self.generics.body.to_idl_type(record))) } } impl<'a, T: ToIdlType<'a>> ToIdlType<'a> for MayBeNull { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { - let inner_idl_type = self.type_.to_idl_type(record)?; + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { + let inner_idl_type = self.type_.to_idl_type(record); if self.q_mark.is_some() { - Some(IdlType::Nullable(Box::new(inner_idl_type))) + IdlType::Nullable(Box::new(inner_idl_type)) } else { - Some(inner_idl_type) + inner_idl_type } } } impl<'a> ToIdlType<'a> for PromiseType<'a> { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { - Some(IdlType::Promise(Box::new( - self.generics.body.to_idl_type(record)?, - ))) + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { + IdlType::Promise(Box::new(self.generics.body.to_idl_type(record))) } } impl<'a> ToIdlType<'a> for IntegerType { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { match self { IntegerType::LongLong(t) => t.to_idl_type(record), IntegerType::Long(t) => t.to_idl_type(record), @@ -179,37 +175,37 @@ impl<'a> ToIdlType<'a> for IntegerType { } impl<'a> ToIdlType<'a> for LongLongType { - fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> IdlType<'a> { if self.unsigned.is_some() { - Some(IdlType::UnsignedLongLong) + IdlType::UnsignedLongLong } else { - Some(IdlType::LongLong) + IdlType::LongLong } } } impl<'a> ToIdlType<'a> for LongType { - fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> IdlType<'a> { if self.unsigned.is_some() { - Some(IdlType::UnsignedLong) + IdlType::UnsignedLong } else { - Some(IdlType::Long) + IdlType::Long } } } impl<'a> ToIdlType<'a> for ShortType { - fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> IdlType<'a> { if self.unsigned.is_some() { - Some(IdlType::UnsignedShort) + IdlType::UnsignedShort } else { - Some(IdlType::Short) + IdlType::Short } } } impl<'a> ToIdlType<'a> for FloatingPointType { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { match self { FloatingPointType::Float(t) => t.to_idl_type(record), FloatingPointType::Double(t) => t.to_idl_type(record), @@ -218,36 +214,36 @@ impl<'a> ToIdlType<'a> for FloatingPointType { } impl<'a> ToIdlType<'a> for FloatType { - fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> IdlType<'a> { if self.unrestricted.is_some() { - Some(IdlType::UnrestrictedFloat) + IdlType::UnrestrictedFloat } else { - Some(IdlType::Float) + IdlType::Float } } } impl<'a> ToIdlType<'a> for DoubleType { - fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> IdlType<'a> { if self.unrestricted.is_some() { - Some(IdlType::UnrestrictedDouble) + IdlType::UnrestrictedDouble } else { - Some(IdlType::Double) + IdlType::Double } } } impl<'a> ToIdlType<'a> for RecordType<'a> { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { - Some(IdlType::Record( - Box::new(self.generics.body.0.to_idl_type(record)?), - Box::new(self.generics.body.2.to_idl_type(record)?), - )) + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { + IdlType::Record( + Box::new(self.generics.body.0.to_idl_type(record)), + Box::new(self.generics.body.2.to_idl_type(record)), + ) } } impl<'a> ToIdlType<'a> for StringType { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { match self { StringType::Byte(t) => t.to_idl_type(record), StringType::DOM(t) => t.to_idl_type(record), @@ -257,7 +253,7 @@ impl<'a> ToIdlType<'a> for StringType { } impl<'a> ToIdlType<'a> for UnionMemberType<'a> { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { match self { UnionMemberType::Single(t) => t.to_idl_type(record), UnionMemberType::Union(t) => t.to_idl_type(record), @@ -266,7 +262,7 @@ impl<'a> ToIdlType<'a> for UnionMemberType<'a> { } impl<'a> ToIdlType<'a> for ConstType<'a> { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { match self { ConstType::Integer(t) => t.to_idl_type(record), ConstType::FloatingPoint(t) => t.to_idl_type(record), @@ -279,7 +275,7 @@ impl<'a> ToIdlType<'a> for ConstType<'a> { } impl<'a> ToIdlType<'a> for ReturnType<'a> { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { match self { ReturnType::Void(t) => t.to_idl_type(record), ReturnType::Type(t) => t.to_idl_type(record), @@ -288,31 +284,31 @@ impl<'a> ToIdlType<'a> for ReturnType<'a> { } impl<'a> ToIdlType<'a> for AttributedType<'a> { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { self.type_.to_idl_type(record) } } impl<'a> ToIdlType<'a> for Identifier<'a> { - fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option> { + fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { if self.0 == "DOMTimeStamp" { // https://heycam.github.io/webidl/#DOMTimeStamp - Some(IdlType::UnsignedLongLong) + IdlType::UnsignedLongLong } else if let Some(idl_type) = record.typedefs.get(&self.0) { idl_type.to_idl_type(record) } else if record.interfaces.contains_key(self.0) { - Some(IdlType::Interface(self.0)) + IdlType::Interface(self.0) } else if record.dictionaries.contains_key(self.0) { - Some(IdlType::Dictionary(self.0)) + IdlType::Dictionary(self.0) } else if record.enums.contains_key(self.0) { - Some(IdlType::Enum(self.0)) + IdlType::Enum(self.0) } else if record.callbacks.contains(self.0) { - Some(IdlType::Callback) + IdlType::Callback } else if let Some(data) = record.callback_interfaces.get(self.0) { - Some(IdlType::CallbackInterface { + IdlType::CallbackInterface { name: self.0, single_function: data.single_function, - }) + } } else if self.0 == "WindowProxy" { // See this for more info: // @@ -320,10 +316,10 @@ impl<'a> ToIdlType<'a> for Identifier<'a> { // // namely this seems to be "legalese" for "this is a `Window`", so // let's translate it as such. - Some(IdlType::Interface("Window")) + IdlType::Interface("Window") } else { warn!("Unrecognized type: {}", self.0); - None + IdlType::UnknownInterface(self.0) } } } @@ -331,8 +327,8 @@ impl<'a> ToIdlType<'a> for Identifier<'a> { macro_rules! terms_to_idl_type { ($($t:tt => $r:tt)*) => ($( impl<'a> ToIdlType<'a> for term::$t { - fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option> { - Some(IdlType::$r) + fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> IdlType<'a> { + IdlType::$r } } )*) @@ -406,6 +402,7 @@ impl<'a> IdlType<'a> { IdlType::BufferSource => dst.push_str("buffer_source"), IdlType::Interface(name) => dst.push_str(&snake_case_ident(name)), + IdlType::UnknownInterface(name) => dst.push_str(&snake_case_ident(name)), IdlType::Dictionary(name) => dst.push_str(&snake_case_ident(name)), IdlType::Enum(name) => dst.push_str(&snake_case_ident(name)), IdlType::CallbackInterface { name, .. } => dst.push_str(&snake_case_ident(name)), @@ -587,6 +584,7 @@ impl<'a> IdlType<'a> { } IdlType::Void => None, IdlType::Callback => js_sys("Function"), + IdlType::UnknownInterface(_) => None, } } diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index 3c7720f9075..0c1bd0202ba 100644 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -353,7 +353,7 @@ impl<'src> FirstPassRecord<'src> { // use argument position now as we're just binding setters let ty = field .type_ - .to_idl_type(self)? + .to_idl_type(self) .to_syn_type(TypePosition::Argument)?; // Slice types aren't supported because they don't implement @@ -459,11 +459,7 @@ impl<'src> FirstPassRecord<'src> { self_name: &'src str, member: &'src weedle::interface::ConstMember<'src>, ) { - let idl_type = match member.const_type.to_idl_type(self) { - Some(idl_type) => idl_type, - None => return, - }; - + let idl_type = member.const_type.to_idl_type(self); let ty = match idl_type.to_syn_type(TypePosition::Return) { Some(ty) => ty, None => { diff --git a/crates/webidl/src/util.rs b/crates/webidl/src/util.rs index 0cbf684e66e..2acee7d65e6 100644 --- a/crates/webidl/src/util.rs +++ b/crates/webidl/src/util.rs @@ -336,7 +336,7 @@ impl<'src> FirstPassRecord<'src> { ) -> Option { let kind = backend::ast::OperationKind::Getter(Some(raw_ident(name))); let kind = self.import_function_kind(self_name, is_static, kind); - let ret = ty.to_idl_type(self)?; + let ret = ty.to_idl_type(self); self.create_one_function( &name, &snake_case_ident(name), @@ -366,7 +366,7 @@ impl<'src> FirstPassRecord<'src> { ) -> Option { let kind = backend::ast::OperationKind::Setter(Some(raw_ident(name))); let kind = self.import_function_kind(self_name, is_static, kind); - let field_ty = field_ty.to_idl_type(self)?; + let field_ty = field_ty.to_idl_type(self); self.create_one_function( &name, &format!("set_{}", name).to_snake_case(), @@ -431,10 +431,7 @@ impl<'src> FirstPassRecord<'src> { ); signatures.push((signature, idl_args.clone())); } - match arg.ty.to_idl_type(self) { - Some(t) => idl_args.push(t), - None => continue 'outer, - } + idl_args.push(arg.ty.to_idl_type(self)); } signatures.push((signature, idl_args)); } @@ -517,10 +514,7 @@ impl<'src> FirstPassRecord<'src> { // TODO: overloads probably never change return types, so we should // do this much earlier to avoid all the above work if // possible. - let ret_ty = match signature.orig.ret.to_idl_type(self) { - Some(ty) => ty, - None => continue, - }; + let ret_ty = signature.orig.ret.to_idl_type(self); let mut rust_name = snake_case_ident(name); let mut first = true; From 3d1f4263ad2f0e17bf46826a31a65e43eac2f9c9 Mon Sep 17 00:00:00 2001 From: Jake Riesterer Date: Wed, 10 Oct 2018 01:44:40 -0500 Subject: [PATCH 2/2] Change UnionType to IdlType::Union function to include any supported types instead of returning None when there is at least one unsupported type For example, the constructor in Response.webidl accepts multiple types. However, one of those types is `ReadableStream` which isn't defined yet, and that causes all constructors for Response to be skipped even though the other argument types could be supported. --- crates/web-sys/tests/wasm/response.rs | 28 ++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/crates/web-sys/tests/wasm/response.rs b/crates/web-sys/tests/wasm/response.rs index 40c893f56e1..5da87aecbee 100644 --- a/crates/web-sys/tests/wasm/response.rs +++ b/crates/web-sys/tests/wasm/response.rs @@ -1,4 +1,12 @@ +extern crate futures; +extern crate js_sys; +extern crate wasm_bindgen_futures; + +use futures::Future; +use js_sys::{ArrayBuffer, DataView}; use wasm_bindgen::prelude::*; +use wasm_bindgen::JsCast; +use wasm_bindgen_futures::JsFuture; use wasm_bindgen_test::*; use web_sys::Response; @@ -8,9 +16,27 @@ extern "C" { } #[wasm_bindgen_test] -fn test_response() { +fn test_response_from_js() { let response = new_response(); assert!(!response.ok()); assert!(!response.redirected()); assert_eq!(response.status(), 501); } + +#[wasm_bindgen_test(async)] +fn test_response_from_bytes() -> impl Future { + let mut bytes: [u8; 3] = [1, 3, 5]; + let response = Response::new_with_opt_u8_array(Some(&mut bytes)).unwrap(); + assert!(response.ok()); + assert_eq!(response.status(), 200); + + let buf_promise = response.array_buffer().unwrap(); + JsFuture::from(buf_promise).map(move |buf_val| { + assert!(buf_val.is_instance_of::()); + let array_buf: ArrayBuffer = buf_val.dyn_into().unwrap(); + let data_view = DataView::new(&array_buf, 0, bytes.len()); + for (i, byte) in bytes.iter().enumerate() { + assert_eq!(&data_view.get_uint8(i), byte); + } + }) +}