[WIP] Add support for unstable WebIDL (#1997)

* Re-enable WebGPU WebIDL as experimental

* Add `web_sys_unstable_apis` attribute

* Add test for unstable WebIDL

* Include unstable WebIDL in docs.rs builds

* Add docs and doc comment for unstable APIs

* Add unstable API checks to CI
This commit is contained in:
Josh Groves
2020-02-26 19:00:11 -03:30
committed by GitHub
parent d26068dc6c
commit 99c59a771e
24 changed files with 1387 additions and 792 deletions

View File

@ -51,6 +51,8 @@ pub struct Export {
/// Whether or not this function should be flagged as the wasm start
/// function.
pub start: bool,
/// Whether the API is unstable. This is only used internally.
pub unstable_api: bool,
}
/// The 3 types variations of `self`.
@ -71,6 +73,7 @@ pub struct Import {
pub module: ImportModule,
pub js_namespace: Option<Ident>,
pub kind: ImportKind,
pub unstable_api: bool,
}
#[cfg_attr(feature = "extra-traits", derive(Debug))]
@ -126,6 +129,7 @@ pub struct ImportFunction {
pub kind: ImportFunctionKind,
pub shim: Ident,
pub doc_comment: Option<String>,
pub unstable_api: bool,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
@ -182,6 +186,7 @@ pub struct ImportType {
pub js_name: String,
pub attrs: Vec<syn::Attribute>,
pub typescript_name: Option<String>,
pub unstable_api: bool,
pub doc_comment: Option<String>,
pub instanceof_shim: String,
pub is_type_of: Option<syn::Expr>,
@ -202,6 +207,8 @@ pub struct ImportEnum {
pub variant_values: Vec<String>,
/// Attributes to apply to the Rust enum
pub rust_attrs: Vec<syn::Attribute>,
/// Whether the enum is part of an unstable WebIDL
pub unstable_api: bool,
}
#[cfg_attr(feature = "extra-traits", derive(Debug))]
@ -237,6 +244,7 @@ pub struct StructField {
pub getter: Ident,
pub setter: Ident,
pub comments: Vec<String>,
pub unstable_api: bool,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
@ -246,6 +254,7 @@ pub struct Enum {
pub variants: Vec<Variant>,
pub comments: Vec<String>,
pub hole: u32,
pub unstable_api: bool,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
@ -278,6 +287,7 @@ pub struct Const {
pub class: Option<Ident>,
pub ty: syn::Type,
pub value: ConstValue,
pub unstable_api: bool,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq))]
@ -299,6 +309,7 @@ pub struct Dictionary {
pub ctor: bool,
pub doc_comment: Option<String>,
pub ctor_doc_comment: Option<String>,
pub unstable_api: bool,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]

View File

@ -1,6 +1,6 @@
use crate::ast;
use crate::encode;
use crate::util::ShortHash;
use crate::util::{self, ShortHash};
use crate::Diagnostic;
use proc_macro2::{Ident, Literal, Span, TokenStream};
use quote::{quote, ToTokens};
@ -39,7 +39,10 @@ impl TryToTokens for ast::Program {
}
}
for i in self.imports.iter() {
DescribeImport(&i.kind).to_tokens(tokens);
DescribeImport {
kind: &i.kind,
unstable_api: i.unstable_api,
}.to_tokens(tokens);
// If there is a js namespace, check that name isn't a type. If it is,
// this import might be a method on that type.
@ -296,12 +299,13 @@ impl ToTokens for ast::StructField {
})
.to_tokens(tokens);
Descriptor(
&getter,
quote! {
Descriptor {
ident: &getter,
inner: quote! {
<#ty as WasmDescribe>::describe();
},
)
unstable_api: self.unstable_api,
}
.to_tokens(tokens);
if self.readonly {
@ -528,16 +532,17 @@ impl TryToTokens for ast::Export {
// this, but the tl;dr; is that this is stripped from the final wasm
// binary along with anything it references.
let export = Ident::new(&export_name, Span::call_site());
Descriptor(
&export,
quote! {
Descriptor {
ident: &export,
inner: quote! {
inform(FUNCTION);
inform(0);
inform(#nargs);
#(<#argtys as WasmDescribe>::describe();)*
#describe_ret
},
)
unstable_api: self.unstable_api,
}
.to_tokens(into);
Ok(())
@ -562,6 +567,7 @@ impl ToTokens for ast::ImportType {
let vis = &self.vis;
let rust_name = &self.rust_name;
let attrs = &self.attrs;
let unstable_api_attr = util::maybe_unstable_api_attr(self.unstable_api);
let doc_comment = match &self.doc_comment {
None => "",
Some(comment) => comment,
@ -610,12 +616,14 @@ impl ToTokens for ast::ImportType {
#[doc = #doc_comment]
#[repr(transparent)]
#[allow(clippy::all)]
#unstable_api_attr
#vis struct #rust_name {
obj: #internal_obj
}
#[allow(bad_style)]
#[allow(clippy::all)]
#unstable_api_attr
const #const_name: () = {
use wasm_bindgen::convert::{IntoWasmAbi, FromWasmAbi};
use wasm_bindgen::convert::{OptionIntoWasmAbi, OptionFromWasmAbi};
@ -766,6 +774,7 @@ impl ToTokens for ast::ImportType {
for superclass in self.extends.iter() {
(quote! {
#[allow(clippy::all)]
#unstable_api_attr
impl From<#rust_name> for #superclass {
#[inline]
fn from(obj: #rust_name) -> #superclass {
@ -775,6 +784,7 @@ impl ToTokens for ast::ImportType {
}
#[allow(clippy::all)]
#unstable_api_attr
impl AsRef<#superclass> for #rust_name {
#[inline]
fn as_ref(&self) -> &#superclass {
@ -796,6 +806,7 @@ impl ToTokens for ast::ImportEnum {
let variants = &self.variants;
let variant_strings = &self.variant_values;
let attrs = &self.rust_attrs;
let unstable_api_attr = util::maybe_unstable_api_attr(self.unstable_api);
let mut current_idx: usize = 0;
let variant_indexes: Vec<Literal> = variants
@ -824,6 +835,7 @@ impl ToTokens for ast::ImportEnum {
#[allow(bad_style)]
#(#attrs)*
#[allow(clippy::all)]
#unstable_api_attr
#vis enum #name {
#(#variants = #variant_indexes_ref,)*
#[doc(hidden)]
@ -831,6 +843,7 @@ impl ToTokens for ast::ImportEnum {
}
#[allow(clippy::all)]
#unstable_api_attr
impl #name {
#vis fn from_js_value(obj: &wasm_bindgen::JsValue) -> Option<#name> {
obj.as_string().and_then(|obj_str| match obj_str.as_str() {
@ -841,6 +854,7 @@ impl ToTokens for ast::ImportEnum {
}
#[allow(clippy::all)]
#unstable_api_attr
impl wasm_bindgen::describe::WasmDescribe for #name {
fn describe() {
wasm_bindgen::JsValue::describe()
@ -848,6 +862,7 @@ impl ToTokens for ast::ImportEnum {
}
#[allow(clippy::all)]
#unstable_api_attr
impl wasm_bindgen::convert::IntoWasmAbi for #name {
type Abi = <wasm_bindgen::JsValue as
wasm_bindgen::convert::IntoWasmAbi>::Abi;
@ -859,6 +874,7 @@ impl ToTokens for ast::ImportEnum {
}
#[allow(clippy::all)]
#unstable_api_attr
impl wasm_bindgen::convert::FromWasmAbi for #name {
type Abi = <wasm_bindgen::JsValue as
wasm_bindgen::convert::FromWasmAbi>::Abi;
@ -869,18 +885,21 @@ impl ToTokens for ast::ImportEnum {
}
#[allow(clippy::all)]
#unstable_api_attr
impl wasm_bindgen::convert::OptionIntoWasmAbi for #name {
#[inline]
fn none() -> Self::Abi { Object::none() }
}
#[allow(clippy::all)]
#unstable_api_attr
impl wasm_bindgen::convert::OptionFromWasmAbi for #name {
#[inline]
fn is_none(abi: &Self::Abi) -> bool { Object::is_none(abi) }
}
#[allow(clippy::all)]
#unstable_api_attr
impl From<#name> for wasm_bindgen::JsValue {
fn from(obj: #name) -> wasm_bindgen::JsValue {
match obj {
@ -992,6 +1011,7 @@ impl TryToTokens for ast::ImportFunction {
let arguments = &arguments;
let abi_arguments = &abi_arguments;
let abi_argument_names = &abi_argument_names;
let unstable_api_attr = util::maybe_unstable_api_attr(self.unstable_api);
let doc_comment = match &self.doc_comment {
None => "",
@ -1058,6 +1078,7 @@ impl TryToTokens for ast::ImportFunction {
if let Some(class) = class_ty {
(quote! {
#unstable_api_attr
impl #class {
#invocation
}
@ -1072,11 +1093,14 @@ impl TryToTokens for ast::ImportFunction {
}
// See comment above in ast::Export for what's going on here.
struct DescribeImport<'a>(&'a ast::ImportKind);
struct DescribeImport<'a> {
kind: &'a ast::ImportKind,
unstable_api: bool,
}
impl<'a> ToTokens for DescribeImport<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let f = match *self.0 {
let f = match *self.kind {
ast::ImportKind::Function(ref f) => f,
ast::ImportKind::Static(_) => return,
ast::ImportKind::Type(_) => return,
@ -1089,16 +1113,17 @@ impl<'a> ToTokens for DescribeImport<'a> {
None => quote! { <() as WasmDescribe>::describe(); },
};
Descriptor(
&f.shim,
quote! {
Descriptor {
ident: &f.shim,
inner: quote! {
inform(FUNCTION);
inform(0);
inform(#nargs);
#(<#argtys as WasmDescribe>::describe();)*
#inform_ret
},
)
unstable_api: self.unstable_api,
}
.to_tokens(tokens);
}
}
@ -1107,6 +1132,7 @@ impl ToTokens for ast::Enum {
fn to_tokens(&self, into: &mut TokenStream) {
let enum_name = &self.name;
let hole = &self.hole;
let unstable_api_attr = util::maybe_unstable_api_attr(self.unstable_api);
let cast_clauses = self.variants.iter().map(|variant| {
let variant_name = &variant.name;
quote! {
@ -1117,6 +1143,7 @@ impl ToTokens for ast::Enum {
});
(quote! {
#[allow(clippy::all)]
#unstable_api_attr
impl wasm_bindgen::convert::IntoWasmAbi for #enum_name {
type Abi = u32;
@ -1127,6 +1154,7 @@ impl ToTokens for ast::Enum {
}
#[allow(clippy::all)]
#unstable_api_attr
impl wasm_bindgen::convert::FromWasmAbi for #enum_name {
type Abi = u32;
@ -1139,18 +1167,21 @@ impl ToTokens for ast::Enum {
}
#[allow(clippy::all)]
#unstable_api_attr
impl wasm_bindgen::convert::OptionFromWasmAbi for #enum_name {
#[inline]
fn is_none(val: &u32) -> bool { *val == #hole }
}
#[allow(clippy::all)]
#unstable_api_attr
impl wasm_bindgen::convert::OptionIntoWasmAbi for #enum_name {
#[inline]
fn none() -> Self::Abi { #hole }
}
#[allow(clippy::all)]
#unstable_api_attr
impl wasm_bindgen::describe::WasmDescribe for #enum_name {
fn describe() {
use wasm_bindgen::describe::*;
@ -1196,12 +1227,13 @@ impl ToTokens for ast::ImportStatic {
})
.to_tokens(into);
Descriptor(
&shim_name,
quote! {
Descriptor {
ident: &shim_name,
inner: quote! {
<#ty as WasmDescribe>::describe();
},
)
unstable_api: false,
}
.to_tokens(into);
}
}
@ -1213,6 +1245,7 @@ impl ToTokens for ast::Const {
let vis = &self.vis;
let name = &self.name;
let ty = &self.ty;
let unstable_api_attr = util::maybe_unstable_api_attr(self.unstable_api);
let value: TokenStream = match self.value {
BooleanLiteral(false) => quote!(false),
@ -1244,6 +1277,7 @@ impl ToTokens for ast::Const {
if let Some(class) = &self.class {
(quote! {
#unstable_api_attr
impl #class {
#declaration
}
@ -1257,6 +1291,7 @@ impl ToTokens for ast::Const {
impl ToTokens for ast::Dictionary {
fn to_tokens(&self, tokens: &mut TokenStream) {
let unstable_api_attr = util::maybe_unstable_api_attr(self.unstable_api);
let name = &self.name;
let mut methods = TokenStream::new();
for field in self.fields.iter() {
@ -1304,11 +1339,13 @@ impl ToTokens for ast::Dictionary {
#[repr(transparent)]
#[allow(clippy::all)]
#[doc = #doc_comment]
#unstable_api_attr
pub struct #name {
obj: ::js_sys::Object,
}
#[allow(clippy::all)]
#unstable_api_attr
impl #name {
#ctor
#methods
@ -1316,6 +1353,7 @@ impl ToTokens for ast::Dictionary {
#[allow(bad_style)]
#[allow(clippy::all)]
#unstable_api_attr
const #const_name: () = {
use js_sys::Object;
use wasm_bindgen::describe::WasmDescribe;
@ -1443,7 +1481,11 @@ impl ToTokens for ast::DictionaryField {
/// Emits the necessary glue tokens for "descriptor", generating an appropriate
/// symbol name as well as attributes around the descriptor function itself.
struct Descriptor<'a, T>(&'a Ident, T);
struct Descriptor<'a, T> {
ident: &'a Ident,
inner: T,
unstable_api: bool,
}
impl<'a, T: ToTokens> ToTokens for Descriptor<'a, T> {
fn to_tokens(&self, tokens: &mut TokenStream) {
@ -1458,22 +1500,27 @@ impl<'a, T: ToTokens> ToTokens for Descriptor<'a, T> {
lazy_static::lazy_static! {
static ref DESCRIPTORS_EMITTED: Mutex<HashSet<String>> = Default::default();
}
let ident = self.ident;
if !DESCRIPTORS_EMITTED
.lock()
.unwrap()
.insert(self.0.to_string())
.insert(ident.to_string())
{
return;
}
let name = Ident::new(&format!("__wbindgen_describe_{}", self.0), self.0.span());
let inner = &self.1;
let name = Ident::new(&format!("__wbindgen_describe_{}", ident), ident.span());
let unstable_api_attr = util::maybe_unstable_api_attr(self.unstable_api);
let inner = &self.inner;
(quote! {
#[no_mangle]
#[allow(non_snake_case)]
#[doc(hidden)]
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
#[allow(clippy::all)]
#unstable_api_attr
pub extern "C" fn #name() {
use wasm_bindgen::describe::*;
// See definition of `link_mem_intrinsics` for what this is doing

View File

@ -188,6 +188,7 @@ fn shared_export<'a>(
function: shared_function(&export.function, intern),
method_kind,
start: export.start,
unstable_api: export.unstable_api,
})
}

View File

@ -113,10 +113,12 @@ pub fn ident_ty(ident: Ident) -> syn::Type {
}
pub fn wrap_import_function(function: ast::ImportFunction) -> ast::Import {
let unstable_api = function.unstable_api;
ast::Import {
module: ast::ImportModule::None,
js_namespace: None,
kind: ast::ImportKind::Function(function),
unstable_api,
}
}
@ -154,3 +156,20 @@ impl<T: Hash> fmt::Display for ShortHash<T> {
write!(f, "{:016x}", h.finish())
}
}
/// Create syn attribute for `#[cfg(web_sys_unstable_apis)]` and a doc comment.
pub fn unstable_api_attrs() -> proc_macro2::TokenStream {
quote::quote!(
#[cfg(web_sys_unstable_apis)]
#[doc = "\n\n*This API is unstable and requires `--cfg=web_sys_unstable_apis` to be activated, as [described in the `wasm-bindgen` guide](https://rustwasm.github.io/docs/wasm-bindgen/web-sys/unstable-apis.html)*"]
)
}
pub fn maybe_unstable_api_attr(unstable_api: bool) -> Option<proc_macro2::TokenStream> {
if unstable_api {
Some(unstable_api_attrs())
} else {
None
}
}