mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-04-25 06:02:13 +00:00
[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:
parent
d26068dc6c
commit
99c59a771e
@ -14,7 +14,8 @@ Easy support for interacting between JS and Rust.
|
||||
edition = "2018"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ['serde-serialize']
|
||||
features = ["serde-serialize"]
|
||||
rustc-args = ["--cfg=web_sys_unstable_apis"]
|
||||
|
||||
[lib]
|
||||
test = false
|
||||
|
@ -122,6 +122,10 @@ jobs:
|
||||
- script: cargo build --manifest-path crates/web-sys/Cargo.toml --target wasm32-unknown-unknown --features Element
|
||||
- script: cargo build --manifest-path crates/web-sys/Cargo.toml --target wasm32-unknown-unknown --features Window
|
||||
- script: cargo test --manifest-path crates/web-sys/Cargo.toml --target wasm32-unknown-unknown --all-features
|
||||
- script: cargo test --manifest-path crates/web-sys/Cargo.toml --target wasm32-unknown-unknown --all-features
|
||||
displayName: "web-sys unstable APIs"
|
||||
env:
|
||||
RUSTFLAGS: --cfg=web_sys_unstable_apis
|
||||
|
||||
- job: test_js_sys
|
||||
displayName: "Run js-sys crate tests"
|
||||
@ -150,6 +154,10 @@ jobs:
|
||||
- script: cargo test -p webidl-tests --target wasm32-unknown-unknown
|
||||
env:
|
||||
WBINDGEN_I_PROMISE_JS_SYNTAX_WORKS_IN_NODE: 1
|
||||
- script: cargo test -p webidl-tests --target wasm32-unknown-unknown
|
||||
displayName: "webidl-tests unstable APIs"
|
||||
env:
|
||||
RUSTFLAGS: --cfg=web_sys_unstable_apis
|
||||
|
||||
- job: test_ui
|
||||
displayName: "Run UI tests"
|
||||
@ -319,6 +327,8 @@ jobs:
|
||||
displayName: "Document js-sys"
|
||||
- script: cargo doc --no-deps --manifest-path crates/web-sys/Cargo.toml --all-features
|
||||
displayName: "Document web-sys"
|
||||
env:
|
||||
RUSTFLAGS: --cfg=web_sys_unstable_apis
|
||||
- script: cargo doc --no-deps --manifest-path crates/futures/Cargo.toml
|
||||
displayName: "Document wasm-bindgen-futures"
|
||||
# Make a tarball even though a zip is uploaded, it looks like the tarball
|
||||
|
@ -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))]
|
||||
|
@ -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
|
||||
|
@ -188,6 +188,7 @@ fn shared_export<'a>(
|
||||
function: shared_function(&export.function, intern),
|
||||
method_kind,
|
||||
start: export.start,
|
||||
unstable_api: export.unstable_api,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ struct AttributeParseState {
|
||||
pub struct BindgenAttrs {
|
||||
/// List of parsed attributes
|
||||
pub attrs: Vec<(Cell<bool>, BindgenAttr)>,
|
||||
pub unstable_api_attr: Option<syn::Attribute>,
|
||||
}
|
||||
|
||||
macro_rules! attrgen {
|
||||
@ -186,7 +187,7 @@ impl Default for BindgenAttrs {
|
||||
// sanity check that we call `check_used` an appropriate number of
|
||||
// times.
|
||||
ATTRS.with(|state| state.parsed.set(state.parsed.get() + 1));
|
||||
BindgenAttrs { attrs: Vec::new() }
|
||||
BindgenAttrs { attrs: Vec::new(), unstable_api_attr: None, }
|
||||
}
|
||||
}
|
||||
|
||||
@ -353,6 +354,7 @@ impl<'a> ConvertToAst<BindgenAttrs> for &'a mut syn::ItemStruct {
|
||||
getter: Ident::new(&getter, Span::call_site()),
|
||||
setter: Ident::new(&setter, Span::call_site()),
|
||||
comments,
|
||||
unstable_api: false,
|
||||
});
|
||||
attrs.check_used()?;
|
||||
}
|
||||
@ -513,6 +515,7 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a ast::ImportModule)> for syn::ForeignIte
|
||||
rust_name: self.sig.ident.clone(),
|
||||
shim: Ident::new(&shim, Span::call_site()),
|
||||
doc_comment: None,
|
||||
unstable_api: false,
|
||||
});
|
||||
opts.check_used()?;
|
||||
|
||||
@ -550,6 +553,7 @@ impl ConvertToAst<BindgenAttrs> for syn::ForeignItemType {
|
||||
Ok(ast::ImportKind::Type(ast::ImportType {
|
||||
vis: self.vis,
|
||||
attrs: self.attrs,
|
||||
unstable_api: false,
|
||||
doc_comment: None,
|
||||
instanceof_shim: shim,
|
||||
is_type_of,
|
||||
@ -777,6 +781,7 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
|
||||
rust_class: None,
|
||||
rust_name,
|
||||
start,
|
||||
unstable_api: false,
|
||||
});
|
||||
}
|
||||
syn::Item::Struct(mut s) => {
|
||||
@ -977,6 +982,7 @@ impl<'a, 'b> MacroParse<(&'a Ident, &'a str)> for &'b mut syn::ImplItemMethod {
|
||||
rust_class: Some(class.clone()),
|
||||
rust_name: self.sig.ident.clone(),
|
||||
start: false,
|
||||
unstable_api: false,
|
||||
});
|
||||
opts.check_used()?;
|
||||
Ok(())
|
||||
@ -1071,6 +1077,7 @@ impl MacroParse<()> for syn::ItemEnum {
|
||||
variants,
|
||||
comments,
|
||||
hole,
|
||||
unstable_api: false,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
@ -1175,6 +1182,7 @@ impl MacroParse<ast::ImportModule> for syn::ForeignItem {
|
||||
module,
|
||||
js_namespace,
|
||||
kind,
|
||||
unstable_api: false,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
@ -94,6 +94,7 @@ macro_rules! shared_api {
|
||||
function: Function<'a>,
|
||||
method_kind: MethodKind<'a>,
|
||||
start: bool,
|
||||
unstable_api: bool,
|
||||
}
|
||||
|
||||
struct Enum<'a> {
|
||||
|
@ -389,6 +389,105 @@ Geolocation = []
|
||||
GetNotificationOptions = []
|
||||
GetRootNodeOptions = []
|
||||
GetUserMediaRequest = []
|
||||
Gpu = []
|
||||
GpuAdapter = []
|
||||
GpuAddressMode = []
|
||||
GpuBindGroup = []
|
||||
GpuBindGroupBinding = []
|
||||
GpuBindGroupDescriptor = []
|
||||
GpuBindGroupLayout = []
|
||||
GpuBindGroupLayoutBinding = []
|
||||
GpuBindGroupLayoutDescriptor = []
|
||||
GpuBindingType = []
|
||||
GpuBlendDescriptor = []
|
||||
GpuBlendFactor = []
|
||||
GpuBlendOperation = []
|
||||
GpuBuffer = []
|
||||
GpuBufferBinding = []
|
||||
GpuBufferCopyView = []
|
||||
GpuBufferDescriptor = []
|
||||
GpuBufferUsage = []
|
||||
GpuCanvasContext = []
|
||||
GpuColorDict = []
|
||||
GpuColorStateDescriptor = []
|
||||
GpuColorWrite = []
|
||||
GpuCommandBuffer = []
|
||||
GpuCommandBufferDescriptor = []
|
||||
GpuCommandEncoder = []
|
||||
GpuCommandEncoderDescriptor = []
|
||||
GpuCompareFunction = []
|
||||
GpuComputePassDescriptor = []
|
||||
GpuComputePassEncoder = []
|
||||
GpuComputePipeline = []
|
||||
GpuComputePipelineDescriptor = []
|
||||
GpuCullMode = []
|
||||
GpuDepthStencilStateDescriptor = []
|
||||
GpuDevice = []
|
||||
GpuDeviceDescriptor = []
|
||||
GpuDeviceLostInfo = []
|
||||
GpuErrorFilter = []
|
||||
GpuExtensionName = []
|
||||
GpuExtent3dDict = []
|
||||
GpuFence = []
|
||||
GpuFenceDescriptor = []
|
||||
GpuFilterMode = []
|
||||
GpuFrontFace = []
|
||||
GpuImageBitmapCopyView = []
|
||||
GpuIndexFormat = []
|
||||
GpuInputStepMode = []
|
||||
GpuLimits = []
|
||||
GpuLoadOp = []
|
||||
GpuObjectDescriptorBase = []
|
||||
GpuOrigin2dDict = []
|
||||
GpuOrigin3dDict = []
|
||||
GpuOutOfMemoryError = []
|
||||
GpuPipelineDescriptorBase = []
|
||||
GpuPipelineLayout = []
|
||||
GpuPipelineLayoutDescriptor = []
|
||||
GpuPowerPreference = []
|
||||
GpuPrimitiveTopology = []
|
||||
GpuProgrammableStageDescriptor = []
|
||||
GpuQueue = []
|
||||
GpuRasterizationStateDescriptor = []
|
||||
GpuRenderBundle = []
|
||||
GpuRenderBundleDescriptor = []
|
||||
GpuRenderBundleEncoder = []
|
||||
GpuRenderBundleEncoderDescriptor = []
|
||||
GpuRenderPassColorAttachmentDescriptor = []
|
||||
GpuRenderPassDepthStencilAttachmentDescriptor = []
|
||||
GpuRenderPassDescriptor = []
|
||||
GpuRenderPassEncoder = []
|
||||
GpuRenderPipeline = []
|
||||
GpuRenderPipelineDescriptor = []
|
||||
GpuRequestAdapterOptions = []
|
||||
GpuSampler = []
|
||||
GpuSamplerDescriptor = []
|
||||
GpuShaderModule = []
|
||||
GpuShaderModuleDescriptor = []
|
||||
GpuShaderStage = []
|
||||
GpuStencilOperation = []
|
||||
GpuStencilStateFaceDescriptor = []
|
||||
GpuStoreOp = []
|
||||
GpuSwapChain = []
|
||||
GpuSwapChainDescriptor = []
|
||||
GpuTexture = []
|
||||
GpuTextureAspect = []
|
||||
GpuTextureComponentType = []
|
||||
GpuTextureCopyView = []
|
||||
GpuTextureDescriptor = []
|
||||
GpuTextureDimension = []
|
||||
GpuTextureFormat = []
|
||||
GpuTextureUsage = []
|
||||
GpuTextureView = []
|
||||
GpuTextureViewDescriptor = []
|
||||
GpuTextureViewDimension = []
|
||||
GpuUncapturedErrorEvent = []
|
||||
GpuUncapturedErrorEventInit = []
|
||||
GpuValidationError = []
|
||||
GpuVertexAttributeDescriptor = []
|
||||
GpuVertexBufferLayoutDescriptor = []
|
||||
GpuVertexFormat = []
|
||||
GpuVertexStateDescriptor = []
|
||||
GridDeclaration = []
|
||||
GridTrackState = []
|
||||
GroupedHistoryEventInit = []
|
||||
|
@ -7,16 +7,12 @@ use std::fs;
|
||||
use std::path::{self, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
#[cfg(feature = "env_logger")]
|
||||
env_logger::init();
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=webidls/enabled");
|
||||
|
||||
let entries = fs::read_dir("webidls/enabled").context("reading webidls/enabled directory")?;
|
||||
/// Read all WebIDL files in a directory into a single `SourceFile`
|
||||
fn read_source_from_path(dir: &str) -> Result<SourceFile> {
|
||||
let entries = fs::read_dir(dir).context("reading webidls/enabled directory")?;
|
||||
let mut source = SourceFile::default();
|
||||
for entry in entries {
|
||||
let entry = entry.context("getting webidls/enabled/*.webidl entry")?;
|
||||
let entry = entry.context(format!("getting {}/*.webidl entry", dir))?;
|
||||
let path = entry.path();
|
||||
if path.extension() != Some(OsStr::new("webidl")) {
|
||||
continue;
|
||||
@ -27,6 +23,16 @@ fn main() -> Result<()> {
|
||||
.with_context(|| format!("reading contents of file \"{}\"", path.display()))?;
|
||||
}
|
||||
|
||||
Ok(source)
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
#[cfg(feature = "env_logger")]
|
||||
env_logger::init();
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=webidls/enabled");
|
||||
println!("cargo:rerun-if-changed=webidls/unstable");
|
||||
|
||||
// Read our manifest, learn all `[feature]` directives with "toml parsing".
|
||||
// Use all these names to match against environment variables set by Cargo
|
||||
// to figure out which features are activated to we can pass that down to
|
||||
@ -63,7 +69,10 @@ fn main() -> Result<()> {
|
||||
Some(&allowed[..])
|
||||
};
|
||||
|
||||
let bindings = match wasm_bindgen_webidl::compile(&source.contents, allowed) {
|
||||
let source = read_source_from_path("webidls/enabled")?;
|
||||
let unstable_source = read_source_from_path("webidls/unstable")?;
|
||||
|
||||
let bindings = match wasm_bindgen_webidl::compile(&source.contents, &unstable_source.contents, allowed) {
|
||||
Ok(bindings) => bindings,
|
||||
Err(e) => {
|
||||
if let Some(err) = e.downcast_ref::<wasm_bindgen_webidl::WebIDLParseError>() {
|
||||
|
638
crates/web-sys/webidls/disabled/WebGPU.webidl
vendored
638
crates/web-sys/webidls/disabled/WebGPU.webidl
vendored
@ -1,638 +0,0 @@
|
||||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
|
||||
*/
|
||||
|
||||
typedef unsigned long u32;
|
||||
typedef unsigned long long u64;
|
||||
|
||||
// ****************************************************************************
|
||||
// ERROR HANDLING
|
||||
// ****************************************************************************
|
||||
|
||||
enum WebGPULogEntryType {
|
||||
"device-lost",
|
||||
"validation-error",
|
||||
"recoverable-out-of-memory",
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPULogEntry {
|
||||
readonly attribute WebGPULogEntryType type;
|
||||
readonly attribute any obj;
|
||||
readonly attribute DOMString? reason;
|
||||
};
|
||||
|
||||
enum WebGPUObjectStatus {
|
||||
"valid",
|
||||
"out-of-memory",
|
||||
"invalid",
|
||||
};
|
||||
|
||||
typedef (WebGPUBuffer or WebGPUTexture) WebGPUStatusable;
|
||||
|
||||
callback WebGPULogCallback = void (WebGPULogEntry error);
|
||||
|
||||
// ****************************************************************************
|
||||
// SHADER RESOURCES (buffer, textures, texture views, samples)
|
||||
// ****************************************************************************
|
||||
|
||||
// Buffer
|
||||
typedef u32 WebGPUBufferUsageFlags;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUBufferUsage {
|
||||
const u32 NONE = 0;
|
||||
const u32 MAP_READ = 1;
|
||||
const u32 MAP_WRITE = 2;
|
||||
const u32 TRANSFER_SRC = 4;
|
||||
const u32 TRANSFER_DST = 8;
|
||||
const u32 INDEX = 16;
|
||||
const u32 VERTEX = 32;
|
||||
const u32 UNIFORM = 64;
|
||||
const u32 STORAGE = 128;
|
||||
};
|
||||
|
||||
dictionary WebGPUBufferDescriptor {
|
||||
u32 size;
|
||||
WebGPUBufferUsageFlags usage;
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUBuffer {
|
||||
readonly attribute ArrayBuffer? mapping;
|
||||
void unmap();
|
||||
};
|
||||
|
||||
// Texture view
|
||||
dictionary WebGPUTextureViewDescriptor {
|
||||
// TODO Investigate what goes in there.
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUTextureView {
|
||||
};
|
||||
|
||||
// Texture
|
||||
typedef u32 WebGPUTextureDimensionEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUTextureDimension {
|
||||
const u32 e1D = 0;
|
||||
const u32 e2D = 1;
|
||||
const u32 e3D = 2;
|
||||
// TODO other dimensions (cube, arrays)
|
||||
};
|
||||
|
||||
typedef u32 WebGPUTextureFormatEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUTextureFormat {
|
||||
const u32 R8_G8_B8_A8_UNORM = 0;
|
||||
const u32 R8_G8_B8_A8_UINT = 1;
|
||||
const u32 B8_G8_R8_A8_UNORM = 2;
|
||||
const u32 D32_FLOAT_S8_UINT = 3;
|
||||
// TODO other formats
|
||||
};
|
||||
|
||||
typedef u32 WebGPUTextureUsageFlags;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUTextureUsage {
|
||||
const u32 NONE = 0;
|
||||
const u32 TRANSFER_SRC = 1;
|
||||
const u32 TRANSFER_DST = 2;
|
||||
const u32 SAMPLED = 4;
|
||||
const u32 STORAGE = 8;
|
||||
const u32 OUTPUT_ATTACHMENT = 16;
|
||||
const u32 PRESENT = 32;
|
||||
};
|
||||
|
||||
dictionary WebGPUTextureDescriptor {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 depth;
|
||||
u32 arraySize;
|
||||
WebGPUTextureDimensionEnum dimension;
|
||||
WebGPUTextureFormatEnum format;
|
||||
WebGPUTextureUsageFlags usage;
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUTexture {
|
||||
WebGPUTextureView createTextureView(optional WebGPUTextureViewDescriptor desc);
|
||||
};
|
||||
|
||||
// Sampler
|
||||
typedef u32 WebGPUFilterModeEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUFilterMode {
|
||||
const u32 NEAREST = 0;
|
||||
const u32 LINEAR = 1;
|
||||
};
|
||||
|
||||
dictionary WebGPUSamplerDescriptor {
|
||||
WebGPUFilterModeEnum magFilter;
|
||||
WebGPUFilterModeEnum minFilter;
|
||||
WebGPUFilterModeEnum mipmapFilter;
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUSampler {
|
||||
};
|
||||
|
||||
// ****************************************************************************
|
||||
// BINDING MODEL (bindgroup layout, bindgroup)
|
||||
// ****************************************************************************
|
||||
|
||||
// BindGroupLayout
|
||||
typedef u32 WebGPUShaderStageFlags;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUShaderStageBit {
|
||||
const u32 NONE = 0;
|
||||
const u32 VERTEX = 1;
|
||||
const u32 FRAGMENT = 2;
|
||||
const u32 COMPUTE = 4;
|
||||
};
|
||||
|
||||
typedef u32 WebGPUBindingTypeEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUBindingType {
|
||||
const u32 UNIFORM_BUFFER = 0;
|
||||
const u32 SAMPLER = 1;
|
||||
const u32 SAMPLED_TEXTURE = 2;
|
||||
const u32 STORAGE_BUFFER = 3;
|
||||
// TODO other binding types (storage images, ...)
|
||||
};
|
||||
|
||||
dictionary WebGPUBindGroupBinding {
|
||||
WebGPUShaderStageFlags visibility;
|
||||
WebGPUBindingTypeEnum type;
|
||||
u32 start;
|
||||
u32 count;
|
||||
};
|
||||
|
||||
dictionary WebGPUBindGroupLayoutDescriptor {
|
||||
sequence<WebGPUBindGroupBinding> bindingTypes;
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUBindGroupLayout {
|
||||
};
|
||||
|
||||
// PipelineLayout
|
||||
dictionary WebGPUPipelineLayoutDescriptor {
|
||||
sequence<WebGPUBindGroupLayout> bindGroupLayouts;
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUPipelineLayout {
|
||||
};
|
||||
|
||||
// BindGroup
|
||||
/* Moved to WebGPUExtras.webidl for now.
|
||||
dictionary WebGPUBufferBinding {
|
||||
WebGPUBuffer buffer;
|
||||
u32 offset;
|
||||
u32 size;
|
||||
};
|
||||
*/
|
||||
|
||||
typedef (WebGPUSampler or WebGPUTextureView or WebGPUBufferBinding) WebGPUBindingResource;
|
||||
|
||||
dictionary WebGPUBinding {
|
||||
sequence<WebGPUBindingResource> resources;
|
||||
u32 start;
|
||||
u32 count;
|
||||
};
|
||||
|
||||
dictionary WebGPUBindGroupDescriptor {
|
||||
WebGPUBindGroupLayout layout;
|
||||
sequence<WebGPUBinding> bindings;
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUBindGroup {
|
||||
};
|
||||
|
||||
// ****************************************************************************
|
||||
// PIPELINE CREATION (blend state, DS state, ..., pipelines)
|
||||
// ****************************************************************************
|
||||
|
||||
// BlendState
|
||||
typedef u32 WebGPUBlendFactorEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUBlendFactor {
|
||||
const u32 ZERO = 0;
|
||||
const u32 ONE = 1;
|
||||
const u32 SRC_COLOR = 2;
|
||||
const u32 ONE_MINUS_SRC_COLOR = 3;
|
||||
const u32 SRC_ALPHA = 4;
|
||||
const u32 ONE_MINUS_SRC_ALPHA = 5;
|
||||
const u32 DST_COLOR = 6;
|
||||
const u32 ONE_MINUS_DST_COLOR = 7;
|
||||
const u32 DST_ALPHA = 8;
|
||||
const u32 ONE_MINUS_DST_ALPHA = 9;
|
||||
const u32 SRC_ALPHA_SATURATED = 10;
|
||||
const u32 BLEND_COLOR = 11;
|
||||
const u32 ONE_MINUS_BLEND_COLOR = 12;
|
||||
};
|
||||
|
||||
typedef u32 WebGPUBlendOperationEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUBlendOperation {
|
||||
const u32 ADD = 0;
|
||||
const u32 SUBTRACT = 1;
|
||||
const u32 REVERSE_SUBTRACT = 2;
|
||||
const u32 MIN = 3;
|
||||
const u32 MAX = 4;
|
||||
};
|
||||
|
||||
typedef u32 WebGPUColorWriteFlags;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUColorWriteBits {
|
||||
const u32 NONE = 0;
|
||||
const u32 RED = 1;
|
||||
const u32 GREEN = 2;
|
||||
const u32 BLUE = 4;
|
||||
const u32 ALPHA = 8;
|
||||
const u32 ALL = 15;
|
||||
};
|
||||
|
||||
dictionary WebGPUBlendDescriptor {
|
||||
WebGPUBlendFactorEnum srcFactor;
|
||||
WebGPUBlendFactorEnum dstFactor;
|
||||
WebGPUBlendOperationEnum operation;
|
||||
};
|
||||
|
||||
dictionary WebGPUBlendStateDescriptor {
|
||||
boolean blendEnabled;
|
||||
WebGPUBlendDescriptor alpha;
|
||||
WebGPUBlendDescriptor color;
|
||||
WebGPUColorWriteFlags writeMask;
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUBlendState {
|
||||
};
|
||||
|
||||
// DepthStencilState
|
||||
typedef u32 WebGPUCompareFunctionEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUCompareFunction {
|
||||
const u32 NEVER = 0;
|
||||
const u32 LESS = 1;
|
||||
const u32 LESS_EQUAL = 2;
|
||||
const u32 GREATER = 3;
|
||||
const u32 GREATER_EQUAL = 4;
|
||||
const u32 EQUAL = 5;
|
||||
const u32 NOT_EQUAL = 6;
|
||||
const u32 ALWAYS = 7;
|
||||
};
|
||||
|
||||
typedef u32 WebGPUStencilOperationEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUStencilOperation {
|
||||
const u32 KEEP = 0;
|
||||
const u32 ZERO = 1;
|
||||
const u32 REPLACE = 2;
|
||||
const u32 INVERT = 3;
|
||||
const u32 INCREMENT_CLAMP = 4;
|
||||
const u32 DECREMENT_CLAMP = 5;
|
||||
const u32 INCREMENT_WRAP = 6;
|
||||
const u32 DECREMENT_WRAP = 7;
|
||||
};
|
||||
|
||||
dictionary WebGPUStencilStateFaceDescriptor {
|
||||
WebGPUCompareFunctionEnum compare;
|
||||
WebGPUStencilOperationEnum stencilFailOp;
|
||||
WebGPUStencilOperationEnum depthFailOp;
|
||||
WebGPUStencilOperationEnum passOp;
|
||||
};
|
||||
|
||||
dictionary WebGPUDepthStencilStateDescriptor {
|
||||
boolean depthWriteEnabled;
|
||||
WebGPUCompareFunctionEnum depthCompare;
|
||||
|
||||
WebGPUStencilStateFaceDescriptor front;
|
||||
WebGPUStencilStateFaceDescriptor back;
|
||||
|
||||
u32 stencilReadMask;
|
||||
u32 stencilWriteMask;
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUDepthStencilState {
|
||||
};
|
||||
|
||||
// InputState
|
||||
typedef u32 WebGPUIndexFormatEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUIndexFormat {
|
||||
const u32 UINT16 = 0;
|
||||
const u32 UINT32 = 1;
|
||||
};
|
||||
|
||||
typedef u32 WebGPUVertexFormatEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUVertexFormat {
|
||||
const u32 FLOAT_R32_G32_B32_A32 = 0;
|
||||
const u32 FLOAT_R32_G32_B32 = 1;
|
||||
const u32 FLOAT_R32_G32 = 2;
|
||||
const u32 FLOAT_R32 = 3;
|
||||
// TODO other vertex formats
|
||||
};
|
||||
|
||||
typedef u32 WebGPUInputStepModeEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUInputStepMode {
|
||||
const u32 VERTEX = 0;
|
||||
const u32 INSTANCE = 1;
|
||||
};
|
||||
|
||||
dictionary WebGPUVertexAttributeDescriptor {
|
||||
u32 shaderLocation;
|
||||
u32 inputSlot;
|
||||
u32 offset;
|
||||
WebGPUVertexFormatEnum format;
|
||||
};
|
||||
|
||||
dictionary WebGPUVertexInputDescriptor {
|
||||
u32 inputSlot;
|
||||
u32 stride;
|
||||
WebGPUInputStepModeEnum stepMode;
|
||||
};
|
||||
|
||||
dictionary WebGPUInputStateDescriptor {
|
||||
WebGPUIndexFormatEnum indexFormat;
|
||||
|
||||
sequence<WebGPUVertexAttributeDescriptor> attributes;
|
||||
sequence<WebGPUVertexInputDescriptor> inputs;
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUInputState {
|
||||
};
|
||||
|
||||
// ShaderModule
|
||||
dictionary WebGPUShaderModuleDescriptor {
|
||||
required ArrayBuffer code;
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUShaderModule {
|
||||
};
|
||||
|
||||
// AttachmentState
|
||||
dictionary WebGPUAttachmentStateDescriptor {
|
||||
sequence<WebGPUTextureFormatEnum> formats;
|
||||
// TODO other stuff like sample count etc.
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUAttachmentState {
|
||||
};
|
||||
|
||||
// Common stuff for ComputePipeline and RenderPipeline
|
||||
typedef u32 WebGPUShaderStageEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUShaderStage {
|
||||
const u32 VERTEX = 0;
|
||||
const u32 FRAGMENT = 1;
|
||||
const u32 COMPUTE = 2;
|
||||
};
|
||||
|
||||
dictionary WebGPUPipelineStageDescriptor {
|
||||
required WebGPUShaderModule shaderModule;
|
||||
required WebGPUShaderStageEnum stage;
|
||||
required DOMString entryPoint;
|
||||
// TODO other stuff like specialization constants?
|
||||
};
|
||||
|
||||
dictionary WebGPUPipelineDescriptorBase {
|
||||
required WebGPUPipelineLayout layout;
|
||||
sequence<WebGPUPipelineStageDescriptor> stages;
|
||||
};
|
||||
|
||||
// ComputePipeline
|
||||
dictionary WebGPUComputePipelineDescriptor : WebGPUPipelineDescriptorBase {
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUComputePipeline {
|
||||
};
|
||||
|
||||
// WebGPURenderPipeline
|
||||
typedef u32 WebGPUPrimitiveTopologyEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUPrimitiveTopology {
|
||||
const u32 POINT_LIST = 0;
|
||||
const u32 LINE_LIST = 1;
|
||||
const u32 LINE_STRIP = 2;
|
||||
const u32 TRIANGLE_LIST = 3;
|
||||
const u32 TRIANGLE_STRIP = 4;
|
||||
};
|
||||
|
||||
dictionary WebGPURenderPipelineDescriptor : WebGPUPipelineDescriptorBase {
|
||||
WebGPUPrimitiveTopologyEnum primitiveTopology;
|
||||
sequence<WebGPUBlendState> blendState;
|
||||
WebGPUDepthStencilState depthStencilState;
|
||||
WebGPUInputState inputState;
|
||||
WebGPUAttachmentState attachmentState;
|
||||
// TODO other properties
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPURenderPipeline {
|
||||
};
|
||||
// ****************************************************************************
|
||||
// COMMAND RECORDING (Command buffer and all relevant structures)
|
||||
// ****************************************************************************
|
||||
|
||||
typedef u32 WebGPULoadOpEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPULoadOp {
|
||||
const u32 CLEAR = 0;
|
||||
const u32 LOAD = 1;
|
||||
};
|
||||
|
||||
typedef u32 WebGPUStoreOpEnum;
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUStoreOp {
|
||||
const u32 STORE = 0;
|
||||
};
|
||||
|
||||
dictionary WebGPURenderPassAttachmentDescriptor {
|
||||
WebGPUTextureView attachment;
|
||||
WebGPULoadOpEnum loadOp;
|
||||
WebGPUStoreOpEnum storeOp;
|
||||
};
|
||||
|
||||
dictionary WebGPURenderPassDescriptor {
|
||||
sequence<WebGPURenderPassAttachmentDescriptor> colorAttachments;
|
||||
WebGPURenderPassAttachmentDescriptor depthStencilAttachment;
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUCommandBuffer {
|
||||
};
|
||||
|
||||
dictionary WebGPUCommandEncoderDescriptor {
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUCommandEncoder {
|
||||
WebGPUCommandBuffer finishEncoding();
|
||||
|
||||
// Commands allowed outside of "passes"
|
||||
void copyBufferToBuffer(WebGPUBuffer src,
|
||||
u32 srcOffset,
|
||||
WebGPUBuffer dst,
|
||||
u32 dstOffset,
|
||||
u32 size);
|
||||
// TODO figure out all the arguments required for these
|
||||
void copyBufferToTexture();
|
||||
void copyTextureToBuffer();
|
||||
void copyTextureToTexture();
|
||||
void blit();
|
||||
|
||||
void transitionBuffer(WebGPUBuffer b, WebGPUBufferUsageFlags f);
|
||||
|
||||
// Allowed in both compute and render passes
|
||||
void setPushConstants(WebGPUShaderStageFlags stage,
|
||||
u32 offset,
|
||||
u32 count,
|
||||
ArrayBuffer data);
|
||||
void setBindGroup(u32 index, WebGPUBindGroup bindGroup);
|
||||
void setPipeline((WebGPUComputePipeline or WebGPURenderPipeline) pipeline);
|
||||
|
||||
// Compute pass commands
|
||||
void beginComputePass();
|
||||
void endComputePass();
|
||||
|
||||
void dispatch(u32 x, u32 y, u32 z);
|
||||
|
||||
// Render pass commands
|
||||
void beginRenderPass(optional WebGPURenderPassDescriptor descriptor);
|
||||
void endRenderPass();
|
||||
|
||||
void setBlendColor(float r, float g, float b, float a);
|
||||
void setIndexBuffer(WebGPUBuffer buffer, u32 offset);
|
||||
void setVertexBuffers(u32 startSlot, sequence<WebGPUBuffer> buffers, sequence<u32> offsets);
|
||||
|
||||
void draw(u32 vertexCount, u32 instanceCount, u32 firstVertex, u32 firstInstance);
|
||||
void drawIndexed(u32 indexCount, u32 instanceCount, u32 firstIndex, u32 firstInstance, u32 firstVertex);
|
||||
|
||||
// TODO add missing commands
|
||||
};
|
||||
|
||||
// ****************************************************************************
|
||||
// OTHER (Fence, Queue SwapChain, Device)
|
||||
// ****************************************************************************
|
||||
|
||||
// Fence
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUFence {
|
||||
boolean wait(double milliseconds);
|
||||
readonly attribute Promise<void> promise;
|
||||
};
|
||||
|
||||
// Queue
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUQueue {
|
||||
void submit(sequence<WebGPUCommandBuffer> buffers);
|
||||
WebGPUFence insertFence();
|
||||
};
|
||||
|
||||
// SwapChain / RenderingContext
|
||||
dictionary WebGPUSwapChainDescriptor {
|
||||
WebGPUTextureUsageFlags usage;
|
||||
WebGPUTextureFormatEnum format;
|
||||
u32 width;
|
||||
u32 height;
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUSwapChain {
|
||||
void configure(optional WebGPUSwapChainDescriptor descriptor);
|
||||
WebGPUTexture getNextTexture();
|
||||
void present();
|
||||
};
|
||||
|
||||
//[Pref="dom.webgpu.enable"]
|
||||
//interface WebGPURenderingContext : WebGPUSwapChain {
|
||||
//};
|
||||
|
||||
// WebGPU "namespace" used for device creation
|
||||
dictionary WebGPUExtensions {
|
||||
boolean anisotropicFiltering;
|
||||
boolean logicOp; // Previously a "Feature".
|
||||
};
|
||||
|
||||
dictionary WebGPULimits {
|
||||
u32 maxBindGroups;
|
||||
};
|
||||
|
||||
// Device
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUDevice {
|
||||
readonly attribute WebGPUAdapter adapter;
|
||||
WebGPUExtensions extensions();
|
||||
WebGPULimits limits();
|
||||
|
||||
WebGPUBuffer createBuffer(optional WebGPUBufferDescriptor descriptor);
|
||||
WebGPUTexture createTexture(optional WebGPUTextureDescriptor descriptor);
|
||||
WebGPUSampler createSampler(optional WebGPUSamplerDescriptor descriptor);
|
||||
|
||||
WebGPUBindGroupLayout createBindGroupLayout(optional WebGPUBindGroupLayoutDescriptor descriptor);
|
||||
WebGPUPipelineLayout createPipelineLayout(optional WebGPUPipelineLayoutDescriptor descriptor);
|
||||
WebGPUBindGroup createBindGroup(optional WebGPUBindGroupDescriptor descriptor);
|
||||
|
||||
WebGPUBlendState createBlendState(optional WebGPUBlendStateDescriptor descriptor);
|
||||
WebGPUDepthStencilState createDepthStencilState(optional WebGPUDepthStencilStateDescriptor descriptor);
|
||||
WebGPUInputState createInputState(optional WebGPUInputStateDescriptor descriptor);
|
||||
WebGPUShaderModule createShaderModule(WebGPUShaderModuleDescriptor descriptor);
|
||||
WebGPUAttachmentState createAttachmentState(optional WebGPUAttachmentStateDescriptor descriptor);
|
||||
WebGPUComputePipeline createComputePipeline(WebGPUComputePipelineDescriptor descriptor);
|
||||
WebGPURenderPipeline createRenderPipeline(WebGPURenderPipelineDescriptor descriptor);
|
||||
|
||||
WebGPUCommandEncoder createCommandEncoder(optional WebGPUCommandEncoderDescriptor descriptor);
|
||||
|
||||
WebGPUQueue getQueue();
|
||||
|
||||
attribute WebGPULogCallback onLog;
|
||||
Promise<WebGPUObjectStatus> getObjectStatus(WebGPUStatusable obj);
|
||||
};
|
||||
|
||||
dictionary WebGPUDeviceDescriptor {
|
||||
WebGPUExtensions extensions;
|
||||
//WebGPULimits limits; Don't expose higher limits for now.
|
||||
|
||||
// TODO are other things configurable like queues?
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPUAdapter {
|
||||
readonly attribute DOMString name;
|
||||
WebGPUExtensions extensions();
|
||||
//WebGPULimits limits(); Don't expose higher limits for now.
|
||||
|
||||
WebGPUDevice createDevice(optional WebGPUDeviceDescriptor descriptor);
|
||||
};
|
||||
|
||||
enum WebGPUPowerPreference { "default", "low-power", "high-performance" };
|
||||
|
||||
dictionary WebGPUAdapterDescriptor {
|
||||
WebGPUPowerPreference powerPreference;
|
||||
};
|
||||
|
||||
[Pref="dom.webgpu.enable"]
|
||||
interface WebGPU {
|
||||
WebGPUAdapter getAdapter(optional WebGPUAdapterDescriptor desc);
|
||||
};
|
||||
|
||||
// Add a "webgpu" member to Window that contains the global instance of a "WebGPU"
|
||||
interface mixin WebGPUProvider {
|
||||
[SameObject, Replaceable, Pref="dom.webgpu.enable"] readonly attribute WebGPU webgpu;
|
||||
};
|
||||
//Window includes WebGPUProvider;
|
@ -1,14 +0,0 @@
|
||||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Some parts of WebGPU.webidl need to be pulled into a different file due to a codegen
|
||||
* bug/missing support.
|
||||
*/
|
||||
|
||||
dictionary WebGPUBufferBinding {
|
||||
WebGPUBuffer buffer;
|
||||
u32 offset;
|
||||
u32 size;
|
||||
};
|
2
crates/web-sys/webidls/enabled/Window.webidl
vendored
2
crates/web-sys/webidls/enabled/Window.webidl
vendored
@ -272,5 +272,3 @@ dictionary IdleRequestOptions {
|
||||
};
|
||||
|
||||
callback IdleRequestCallback = void (IdleDeadline deadline);
|
||||
|
||||
//Window includes WebGPUProvider;
|
||||
|
864
crates/web-sys/webidls/unstable/WebGPU.webidl
vendored
Normal file
864
crates/web-sys/webidls/unstable/WebGPU.webidl
vendored
Normal file
@ -0,0 +1,864 @@
|
||||
interface mixin GPUObjectBase {
|
||||
attribute DOMString? label;
|
||||
};
|
||||
|
||||
dictionary GPUObjectDescriptorBase {
|
||||
DOMString label;
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
partial interface Navigator {
|
||||
[SameObject] readonly attribute GPU gpu;
|
||||
};
|
||||
|
||||
[Exposed=DedicatedWorker]
|
||||
partial interface WorkerNavigator {
|
||||
[SameObject] readonly attribute GPU gpu;
|
||||
};
|
||||
|
||||
[Exposed=(Window, DedicatedWorker)]
|
||||
interface GPU {
|
||||
Promise<GPUAdapter> requestAdapter(optional GPURequestAdapterOptions options = {});
|
||||
};
|
||||
|
||||
dictionary GPURequestAdapterOptions {
|
||||
GPUPowerPreference powerPreference;
|
||||
};
|
||||
|
||||
enum GPUPowerPreference {
|
||||
"low-power",
|
||||
"high-performance"
|
||||
};
|
||||
|
||||
interface GPUAdapter {
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute FrozenArray<GPUExtensionName> extensions;
|
||||
//readonly attribute GPULimits limits; Don’t expose higher limits for now.
|
||||
|
||||
Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {});
|
||||
};
|
||||
|
||||
dictionary GPUDeviceDescriptor : GPUObjectDescriptorBase {
|
||||
sequence<GPUExtensionName> extensions = [];
|
||||
GPULimits limits = {};
|
||||
};
|
||||
|
||||
enum GPUExtensionName {
|
||||
"texture-compression-bc"
|
||||
};
|
||||
|
||||
dictionary GPULimits {
|
||||
GPUSize32 maxBindGroups = 4;
|
||||
GPUSize32 maxDynamicUniformBuffersPerPipelineLayout = 8;
|
||||
GPUSize32 maxDynamicStorageBuffersPerPipelineLayout = 4;
|
||||
GPUSize32 maxSampledTexturesPerShaderStage = 16;
|
||||
GPUSize32 maxSamplersPerShaderStage = 16;
|
||||
GPUSize32 maxStorageBuffersPerShaderStage = 4;
|
||||
GPUSize32 maxStorageTexturesPerShaderStage = 4;
|
||||
GPUSize32 maxUniformBuffersPerShaderStage = 12;
|
||||
};
|
||||
|
||||
[Exposed=(Window, DedicatedWorker), Serializable]
|
||||
interface GPUDevice : EventTarget {
|
||||
[SameObject] readonly attribute GPUAdapter adapter;
|
||||
readonly attribute FrozenArray<GPUExtensionName> extensions;
|
||||
readonly attribute object limits;
|
||||
|
||||
[SameObject] readonly attribute GPUQueue defaultQueue;
|
||||
|
||||
GPUBuffer createBuffer(GPUBufferDescriptor descriptor);
|
||||
GPUMappedBuffer createBufferMapped(GPUBufferDescriptor descriptor);
|
||||
GPUTexture createTexture(GPUTextureDescriptor descriptor);
|
||||
GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {});
|
||||
|
||||
GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
|
||||
GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
|
||||
GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);
|
||||
|
||||
GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor);
|
||||
GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor);
|
||||
GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor);
|
||||
|
||||
GPUCommandEncoder createCommandEncoder(optional GPUCommandEncoderDescriptor descriptor = {});
|
||||
GPURenderBundleEncoder createRenderBundleEncoder(GPURenderBundleEncoderDescriptor descriptor);
|
||||
};
|
||||
GPUDevice includes GPUObjectBase;
|
||||
|
||||
[Serializable]
|
||||
interface GPUBuffer {
|
||||
Promise<ArrayBuffer> mapReadAsync();
|
||||
Promise<ArrayBuffer> mapWriteAsync();
|
||||
void unmap();
|
||||
|
||||
void destroy();
|
||||
};
|
||||
GPUBuffer includes GPUObjectBase;
|
||||
|
||||
dictionary GPUBufferDescriptor : GPUObjectDescriptorBase {
|
||||
required GPUSize64 size;
|
||||
required GPUBufferUsageFlags usage;
|
||||
};
|
||||
|
||||
typedef [EnforceRange] unsigned long GPUBufferUsageFlags;
|
||||
interface GPUBufferUsage {
|
||||
const GPUBufferUsageFlags MAP_READ = 0x0001;
|
||||
const GPUBufferUsageFlags MAP_WRITE = 0x0002;
|
||||
const GPUBufferUsageFlags COPY_SRC = 0x0004;
|
||||
const GPUBufferUsageFlags COPY_DST = 0x0008;
|
||||
const GPUBufferUsageFlags INDEX = 0x0010;
|
||||
const GPUBufferUsageFlags VERTEX = 0x0020;
|
||||
const GPUBufferUsageFlags UNIFORM = 0x0040;
|
||||
const GPUBufferUsageFlags STORAGE = 0x0080;
|
||||
const GPUBufferUsageFlags INDIRECT = 0x0100;
|
||||
};
|
||||
|
||||
[Serializable]
|
||||
interface GPUTexture {
|
||||
GPUTextureView createView(optional GPUTextureViewDescriptor descriptor = {});
|
||||
|
||||
void destroy();
|
||||
};
|
||||
GPUTexture includes GPUObjectBase;
|
||||
|
||||
dictionary GPUTextureDescriptor : GPUObjectDescriptorBase {
|
||||
required GPUExtent3D size;
|
||||
GPUIntegerCoordinate arrayLayerCount = 1;
|
||||
GPUIntegerCoordinate mipLevelCount = 1;
|
||||
GPUSize32 sampleCount = 1;
|
||||
GPUTextureDimension dimension = "2d";
|
||||
required GPUTextureFormat format;
|
||||
required GPUTextureUsageFlags usage;
|
||||
};
|
||||
|
||||
enum GPUTextureDimension {
|
||||
"1d",
|
||||
"2d",
|
||||
"3d"
|
||||
};
|
||||
|
||||
typedef [EnforceRange] unsigned long GPUTextureUsageFlags;
|
||||
interface GPUTextureUsage {
|
||||
const GPUTextureUsageFlags COPY_SRC = 0x01;
|
||||
const GPUTextureUsageFlags COPY_DST = 0x02;
|
||||
const GPUTextureUsageFlags SAMPLED = 0x04;
|
||||
const GPUTextureUsageFlags STORAGE = 0x08;
|
||||
const GPUTextureUsageFlags OUTPUT_ATTACHMENT = 0x10;
|
||||
};
|
||||
|
||||
interface GPUTextureView {
|
||||
};
|
||||
GPUTextureView includes GPUObjectBase;
|
||||
|
||||
dictionary GPUTextureViewDescriptor : GPUObjectDescriptorBase {
|
||||
GPUTextureFormat format;
|
||||
GPUTextureViewDimension dimension;
|
||||
GPUTextureAspect aspect = "all";
|
||||
GPUIntegerCoordinate baseMipLevel = 0;
|
||||
GPUIntegerCoordinate mipLevelCount = 0;
|
||||
GPUIntegerCoordinate baseArrayLayer = 0;
|
||||
GPUIntegerCoordinate arrayLayerCount = 0;
|
||||
};
|
||||
|
||||
enum GPUTextureViewDimension {
|
||||
"1d",
|
||||
"2d",
|
||||
"2d-array",
|
||||
"cube",
|
||||
"cube-array",
|
||||
"3d"
|
||||
};
|
||||
|
||||
enum GPUTextureAspect {
|
||||
"all",
|
||||
"stencil-only",
|
||||
"depth-only"
|
||||
};
|
||||
|
||||
enum GPUTextureFormat {
|
||||
// 8-bit formats
|
||||
"r8unorm",
|
||||
"r8snorm",
|
||||
"r8uint",
|
||||
"r8sint",
|
||||
|
||||
// 16-bit formats
|
||||
"r16uint",
|
||||
"r16sint",
|
||||
"r16float",
|
||||
"rg8unorm",
|
||||
"rg8snorm",
|
||||
"rg8uint",
|
||||
"rg8sint",
|
||||
|
||||
// 32-bit formats
|
||||
"r32uint",
|
||||
"r32sint",
|
||||
"r32float",
|
||||
"rg16uint",
|
||||
"rg16sint",
|
||||
"rg16float",
|
||||
"rgba8unorm",
|
||||
"rgba8unorm-srgb",
|
||||
"rgba8snorm",
|
||||
"rgba8uint",
|
||||
"rgba8sint",
|
||||
"bgra8unorm",
|
||||
"bgra8unorm-srgb",
|
||||
// Packed 32-bit formats
|
||||
"rgb10a2unorm",
|
||||
"rg11b10float",
|
||||
|
||||
// 64-bit formats
|
||||
"rg32uint",
|
||||
"rg32sint",
|
||||
"rg32float",
|
||||
"rgba16uint",
|
||||
"rgba16sint",
|
||||
"rgba16float",
|
||||
|
||||
// 128-bit formats
|
||||
"rgba32uint",
|
||||
"rgba32sint",
|
||||
"rgba32float",
|
||||
|
||||
// Depth and stencil formats
|
||||
"depth32float",
|
||||
"depth24plus",
|
||||
"depth24plus-stencil8"
|
||||
};
|
||||
|
||||
enum GPUTextureComponentType {
|
||||
"float",
|
||||
"sint",
|
||||
"uint"
|
||||
};
|
||||
|
||||
interface GPUSampler {
|
||||
};
|
||||
GPUSampler includes GPUObjectBase;
|
||||
|
||||
dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase {
|
||||
GPUAddressMode addressModeU = "clamp-to-edge";
|
||||
GPUAddressMode addressModeV = "clamp-to-edge";
|
||||
GPUAddressMode addressModeW = "clamp-to-edge";
|
||||
GPUFilterMode magFilter = "nearest";
|
||||
GPUFilterMode minFilter = "nearest";
|
||||
GPUFilterMode mipmapFilter = "nearest";
|
||||
float lodMinClamp = 0;
|
||||
float lodMaxClamp = 0xffffffff; // TODO: What should this be? Was Number.MAX_VALUE.
|
||||
GPUCompareFunction compare = "never";
|
||||
};
|
||||
|
||||
enum GPUAddressMode {
|
||||
"clamp-to-edge",
|
||||
"repeat",
|
||||
"mirror-repeat"
|
||||
};
|
||||
|
||||
enum GPUFilterMode {
|
||||
"nearest",
|
||||
"linear"
|
||||
};
|
||||
|
||||
enum GPUCompareFunction {
|
||||
"never",
|
||||
"less",
|
||||
"equal",
|
||||
"less-equal",
|
||||
"greater",
|
||||
"not-equal",
|
||||
"greater-equal",
|
||||
"always"
|
||||
};
|
||||
|
||||
[Serializable]
|
||||
interface GPUBindGroupLayout {
|
||||
};
|
||||
GPUBindGroupLayout includes GPUObjectBase;
|
||||
|
||||
dictionary GPUBindGroupLayoutDescriptor : GPUObjectDescriptorBase {
|
||||
required sequence<GPUBindGroupLayoutBinding> bindings;
|
||||
};
|
||||
|
||||
dictionary GPUBindGroupLayoutBinding {
|
||||
required GPUIndex32 binding;
|
||||
required GPUShaderStageFlags visibility;
|
||||
required GPUBindingType type;
|
||||
GPUTextureViewDimension textureDimension = "2d";
|
||||
GPUTextureComponentType textureComponentType = "float";
|
||||
boolean multisampled = false;
|
||||
boolean hasDynamicOffset = false;
|
||||
};
|
||||
|
||||
typedef [EnforceRange] unsigned long GPUShaderStageFlags;
|
||||
interface GPUShaderStage {
|
||||
const GPUShaderStageFlags VERTEX = 0x1;
|
||||
const GPUShaderStageFlags FRAGMENT = 0x2;
|
||||
const GPUShaderStageFlags COMPUTE = 0x4;
|
||||
};
|
||||
|
||||
enum GPUBindingType {
|
||||
"uniform-buffer",
|
||||
"storage-buffer",
|
||||
"readonly-storage-buffer",
|
||||
"sampler",
|
||||
"sampled-texture",
|
||||
"storage-texture"
|
||||
// TODO: other binding types
|
||||
};
|
||||
|
||||
interface GPUBindGroup {
|
||||
};
|
||||
GPUBindGroup includes GPUObjectBase;
|
||||
|
||||
dictionary GPUBindGroupDescriptor : GPUObjectDescriptorBase {
|
||||
required GPUBindGroupLayout layout;
|
||||
required sequence<GPUBindGroupBinding> bindings;
|
||||
};
|
||||
|
||||
typedef (GPUSampler or GPUTextureView or GPUBufferBinding) GPUBindingResource;
|
||||
|
||||
dictionary GPUBindGroupBinding {
|
||||
required GPUIndex32 binding;
|
||||
required GPUBindingResource resource;
|
||||
};
|
||||
|
||||
dictionary GPUBufferBinding {
|
||||
required GPUBuffer buffer;
|
||||
GPUSize64 offset = 0;
|
||||
GPUSize64 size;
|
||||
};
|
||||
|
||||
interface GPUPipelineLayout {
|
||||
};
|
||||
GPUPipelineLayout includes GPUObjectBase;
|
||||
|
||||
dictionary GPUPipelineLayoutDescriptor : GPUObjectDescriptorBase {
|
||||
required sequence<GPUBindGroupLayout> bindGroupLayouts;
|
||||
};
|
||||
|
||||
[Serializable]
|
||||
interface GPUShaderModule {
|
||||
};
|
||||
GPUShaderModule includes GPUObjectBase;
|
||||
|
||||
typedef (Uint32Array or DOMString) GPUShaderCode;
|
||||
|
||||
dictionary GPUShaderModuleDescriptor : GPUObjectDescriptorBase {
|
||||
required GPUShaderCode code;
|
||||
};
|
||||
|
||||
dictionary GPUPipelineDescriptorBase : GPUObjectDescriptorBase {
|
||||
required GPUPipelineLayout layout;
|
||||
};
|
||||
|
||||
dictionary GPUProgrammableStageDescriptor {
|
||||
required GPUShaderModule module;
|
||||
required DOMString entryPoint;
|
||||
// TODO: other stuff like specialization constants?
|
||||
};
|
||||
|
||||
[Serializable]
|
||||
interface GPUComputePipeline {
|
||||
};
|
||||
GPUComputePipeline includes GPUObjectBase;
|
||||
|
||||
dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase {
|
||||
required GPUProgrammableStageDescriptor computeStage;
|
||||
};
|
||||
|
||||
[Serializable]
|
||||
interface GPURenderPipeline {
|
||||
};
|
||||
GPURenderPipeline includes GPUObjectBase;
|
||||
|
||||
dictionary GPURenderPipelineDescriptor : GPUPipelineDescriptorBase {
|
||||
required GPUProgrammableStageDescriptor vertexStage;
|
||||
GPUProgrammableStageDescriptor fragmentStage;
|
||||
|
||||
required GPUPrimitiveTopology primitiveTopology;
|
||||
GPURasterizationStateDescriptor rasterizationState = {};
|
||||
required sequence<GPUColorStateDescriptor> colorStates;
|
||||
GPUDepthStencilStateDescriptor depthStencilState;
|
||||
GPUVertexStateDescriptor vertexState = {};
|
||||
|
||||
GPUSize32 sampleCount = 1;
|
||||
GPUSampleMask sampleMask = 0xFFFFFFFF;
|
||||
boolean alphaToCoverageEnabled = false;
|
||||
// TODO: other properties
|
||||
};
|
||||
|
||||
enum GPUPrimitiveTopology {
|
||||
"point-list",
|
||||
"line-list",
|
||||
"line-strip",
|
||||
"triangle-list",
|
||||
"triangle-strip"
|
||||
};
|
||||
|
||||
dictionary GPURasterizationStateDescriptor {
|
||||
GPUFrontFace frontFace = "ccw";
|
||||
GPUCullMode cullMode = "none";
|
||||
|
||||
GPUDepthBias depthBias = 0;
|
||||
float depthBiasSlopeScale = 0;
|
||||
float depthBiasClamp = 0;
|
||||
};
|
||||
|
||||
enum GPUFrontFace {
|
||||
"ccw",
|
||||
"cw"
|
||||
};
|
||||
|
||||
enum GPUCullMode {
|
||||
"none",
|
||||
"front",
|
||||
"back"
|
||||
};
|
||||
|
||||
dictionary GPUColorStateDescriptor {
|
||||
required GPUTextureFormat format;
|
||||
|
||||
GPUBlendDescriptor alphaBlend = {};
|
||||
GPUBlendDescriptor colorBlend = {};
|
||||
GPUColorWriteFlags writeMask = 0xF; // GPUColorWrite.ALL
|
||||
};
|
||||
|
||||
typedef [EnforceRange] unsigned long GPUColorWriteFlags;
|
||||
interface GPUColorWrite {
|
||||
const GPUColorWriteFlags RED = 0x1;
|
||||
const GPUColorWriteFlags GREEN = 0x2;
|
||||
const GPUColorWriteFlags BLUE = 0x4;
|
||||
const GPUColorWriteFlags ALPHA = 0x8;
|
||||
const GPUColorWriteFlags ALL = 0xF;
|
||||
};
|
||||
|
||||
dictionary GPUBlendDescriptor {
|
||||
GPUBlendFactor srcFactor = "one";
|
||||
GPUBlendFactor dstFactor = "zero";
|
||||
GPUBlendOperation operation = "add";
|
||||
};
|
||||
|
||||
enum GPUBlendFactor {
|
||||
"zero",
|
||||
"one",
|
||||
"src-color",
|
||||
"one-minus-src-color",
|
||||
"src-alpha",
|
||||
"one-minus-src-alpha",
|
||||
"dst-color",
|
||||
"one-minus-dst-color",
|
||||
"dst-alpha",
|
||||
"one-minus-dst-alpha",
|
||||
"src-alpha-saturated",
|
||||
"blend-color",
|
||||
"one-minus-blend-color"
|
||||
};
|
||||
|
||||
enum GPUBlendOperation {
|
||||
"add",
|
||||
"subtract",
|
||||
"reverse-subtract",
|
||||
"min",
|
||||
"max"
|
||||
};
|
||||
|
||||
enum GPUStencilOperation {
|
||||
"keep",
|
||||
"zero",
|
||||
"replace",
|
||||
"invert",
|
||||
"increment-clamp",
|
||||
"decrement-clamp",
|
||||
"increment-wrap",
|
||||
"decrement-wrap"
|
||||
};
|
||||
|
||||
dictionary GPUDepthStencilStateDescriptor {
|
||||
required GPUTextureFormat format;
|
||||
|
||||
boolean depthWriteEnabled = false;
|
||||
GPUCompareFunction depthCompare = "always";
|
||||
|
||||
GPUStencilStateFaceDescriptor stencilFront = {};
|
||||
GPUStencilStateFaceDescriptor stencilBack = {};
|
||||
|
||||
GPUStencilValue stencilReadMask = 0xFFFFFFFF;
|
||||
GPUStencilValue stencilWriteMask = 0xFFFFFFFF;
|
||||
};
|
||||
|
||||
dictionary GPUStencilStateFaceDescriptor {
|
||||
GPUCompareFunction compare = "always";
|
||||
GPUStencilOperation failOp = "keep";
|
||||
GPUStencilOperation depthFailOp = "keep";
|
||||
GPUStencilOperation passOp = "keep";
|
||||
};
|
||||
|
||||
enum GPUIndexFormat {
|
||||
"uint16",
|
||||
"uint32"
|
||||
};
|
||||
|
||||
enum GPUVertexFormat {
|
||||
"uchar2",
|
||||
"uchar4",
|
||||
"char2",
|
||||
"char4",
|
||||
"uchar2norm",
|
||||
"uchar4norm",
|
||||
"char2norm",
|
||||
"char4norm",
|
||||
"ushort2",
|
||||
"ushort4",
|
||||
"short2",
|
||||
"short4",
|
||||
"ushort2norm",
|
||||
"ushort4norm",
|
||||
"short2norm",
|
||||
"short4norm",
|
||||
"half2",
|
||||
"half4",
|
||||
"float",
|
||||
"float2",
|
||||
"float3",
|
||||
"float4",
|
||||
"uint",
|
||||
"uint2",
|
||||
"uint3",
|
||||
"uint4",
|
||||
"int",
|
||||
"int2",
|
||||
"int3",
|
||||
"int4"
|
||||
};
|
||||
|
||||
enum GPUInputStepMode {
|
||||
"vertex",
|
||||
"instance"
|
||||
};
|
||||
|
||||
dictionary GPUVertexStateDescriptor {
|
||||
GPUIndexFormat indexFormat = "uint32";
|
||||
sequence<GPUVertexBufferLayoutDescriptor?> vertexBuffers = [];
|
||||
};
|
||||
|
||||
dictionary GPUVertexBufferLayoutDescriptor {
|
||||
required GPUSize64 arrayStride;
|
||||
GPUInputStepMode stepMode = "vertex";
|
||||
required sequence<GPUVertexAttributeDescriptor> attributes;
|
||||
};
|
||||
|
||||
dictionary GPUVertexAttributeDescriptor {
|
||||
required GPUVertexFormat format;
|
||||
required GPUSize64 offset;
|
||||
|
||||
required GPUIndex32 shaderLocation;
|
||||
};
|
||||
|
||||
interface GPUCommandBuffer {
|
||||
};
|
||||
GPUCommandBuffer includes GPUObjectBase;
|
||||
|
||||
dictionary GPUCommandBufferDescriptor : GPUObjectDescriptorBase {
|
||||
};
|
||||
|
||||
interface GPUCommandEncoder {
|
||||
GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor);
|
||||
GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {});
|
||||
|
||||
void copyBufferToBuffer(
|
||||
GPUBuffer source,
|
||||
GPUSize64 sourceOffset,
|
||||
GPUBuffer destination,
|
||||
GPUSize64 destinationOffset,
|
||||
GPUSize64 size);
|
||||
|
||||
void copyBufferToTexture(
|
||||
GPUBufferCopyView source,
|
||||
GPUTextureCopyView destination,
|
||||
GPUExtent3D copySize);
|
||||
|
||||
void copyTextureToBuffer(
|
||||
GPUTextureCopyView source,
|
||||
GPUBufferCopyView destination,
|
||||
GPUExtent3D copySize);
|
||||
|
||||
void copyTextureToTexture(
|
||||
GPUTextureCopyView source,
|
||||
GPUTextureCopyView destination,
|
||||
GPUExtent3D copySize);
|
||||
|
||||
void pushDebugGroup(DOMString groupLabel);
|
||||
void popDebugGroup();
|
||||
void insertDebugMarker(DOMString markerLabel);
|
||||
|
||||
GPUCommandBuffer finish(optional GPUCommandBufferDescriptor descriptor = {});
|
||||
};
|
||||
GPUCommandEncoder includes GPUObjectBase;
|
||||
|
||||
dictionary GPUCommandEncoderDescriptor : GPUObjectDescriptorBase {
|
||||
// TODO: reusability flag?
|
||||
};
|
||||
|
||||
dictionary GPUBufferCopyView {
|
||||
required GPUBuffer buffer;
|
||||
GPUSize64 offset = 0;
|
||||
required GPUSize32 rowPitch;
|
||||
required GPUSize32 imageHeight;
|
||||
};
|
||||
|
||||
dictionary GPUTextureCopyView {
|
||||
required GPUTexture texture;
|
||||
GPUIntegerCoordinate mipLevel = 0;
|
||||
GPUIntegerCoordinate arrayLayer = 0;
|
||||
GPUOrigin3D origin = {};
|
||||
};
|
||||
|
||||
dictionary GPUImageBitmapCopyView {
|
||||
required ImageBitmap imageBitmap;
|
||||
GPUOrigin2D origin = {};
|
||||
};
|
||||
|
||||
interface mixin GPUProgrammablePassEncoder {
|
||||
void setBindGroup(GPUIndex32 index, GPUBindGroup bindGroup,
|
||||
optional sequence<GPUBufferDynamicOffset> dynamicOffsets = []);
|
||||
|
||||
void setBindGroup(GPUIndex32 index, GPUBindGroup bindGroup,
|
||||
Uint32Array dynamicOffsetsData,
|
||||
GPUSize64 dynamicOffsetsDataStart,
|
||||
GPUSize32 dynamicOffsetsDataLength);
|
||||
|
||||
void pushDebugGroup(DOMString groupLabel);
|
||||
void popDebugGroup();
|
||||
void insertDebugMarker(DOMString markerLabel);
|
||||
};
|
||||
|
||||
interface GPUComputePassEncoder {
|
||||
void setPipeline(GPUComputePipeline pipeline);
|
||||
void dispatch(GPUSize32 x, optional GPUSize32 y = 1, optional GPUSize32 z = 1);
|
||||
void dispatchIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset);
|
||||
|
||||
void endPass();
|
||||
};
|
||||
GPUComputePassEncoder includes GPUObjectBase;
|
||||
GPUComputePassEncoder includes GPUProgrammablePassEncoder;
|
||||
|
||||
dictionary GPUComputePassDescriptor : GPUObjectDescriptorBase {
|
||||
};
|
||||
|
||||
interface mixin GPURenderEncoderBase {
|
||||
void setPipeline(GPURenderPipeline pipeline);
|
||||
|
||||
void setIndexBuffer(GPUBuffer buffer, optional GPUSize64 offset = 0);
|
||||
void setVertexBuffer(GPUIndex32 slot, GPUBuffer buffer, optional GPUSize64 offset = 0);
|
||||
|
||||
void draw(GPUSize32 vertexCount, GPUSize32 instanceCount,
|
||||
GPUSize32 firstVertex, GPUSize32 firstInstance);
|
||||
void drawIndexed(GPUSize32 indexCount, GPUSize32 instanceCount,
|
||||
GPUSize32 firstIndex, GPUSignedOffset32 baseVertex, GPUSize32 firstInstance);
|
||||
|
||||
void drawIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset);
|
||||
void drawIndexedIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset);
|
||||
};
|
||||
|
||||
interface GPURenderPassEncoder {
|
||||
void setViewport(float x, float y,
|
||||
float width, float height,
|
||||
float minDepth, float maxDepth);
|
||||
|
||||
void setScissorRect(GPUIntegerCoordinate x, GPUIntegerCoordinate y,
|
||||
GPUIntegerCoordinate width, GPUIntegerCoordinate height);
|
||||
|
||||
void setBlendColor(GPUColor color);
|
||||
void setStencilReference(GPUStencilValue reference);
|
||||
|
||||
void executeBundles(sequence<GPURenderBundle> bundles);
|
||||
void endPass();
|
||||
};
|
||||
GPURenderPassEncoder includes GPUObjectBase;
|
||||
GPURenderPassEncoder includes GPUProgrammablePassEncoder;
|
||||
GPURenderPassEncoder includes GPURenderEncoderBase;
|
||||
|
||||
dictionary GPURenderPassDescriptor : GPUObjectDescriptorBase {
|
||||
required sequence<GPURenderPassColorAttachmentDescriptor> colorAttachments;
|
||||
GPURenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
|
||||
};
|
||||
|
||||
dictionary GPURenderPassColorAttachmentDescriptor {
|
||||
required GPUTextureView attachment;
|
||||
GPUTextureView resolveTarget;
|
||||
|
||||
required (GPULoadOp or GPUColor) loadValue;
|
||||
GPUStoreOp storeOp = "store";
|
||||
};
|
||||
|
||||
dictionary GPURenderPassDepthStencilAttachmentDescriptor {
|
||||
required GPUTextureView attachment;
|
||||
|
||||
required (GPULoadOp or float) depthLoadValue;
|
||||
required GPUStoreOp depthStoreOp;
|
||||
|
||||
required (GPULoadOp or GPUStencilValue) stencilLoadValue;
|
||||
required GPUStoreOp stencilStoreOp;
|
||||
};
|
||||
|
||||
enum GPULoadOp {
|
||||
"load"
|
||||
};
|
||||
|
||||
enum GPUStoreOp {
|
||||
"store",
|
||||
"clear"
|
||||
};
|
||||
|
||||
interface GPURenderBundle {
|
||||
};
|
||||
GPURenderBundle includes GPUObjectBase;
|
||||
|
||||
dictionary GPURenderBundleDescriptor : GPUObjectDescriptorBase {
|
||||
};
|
||||
|
||||
interface GPURenderBundleEncoder {
|
||||
GPURenderBundle finish(optional GPURenderBundleDescriptor descriptor = {});
|
||||
};
|
||||
GPURenderBundleEncoder includes GPUObjectBase;
|
||||
GPURenderBundleEncoder includes GPUProgrammablePassEncoder;
|
||||
GPURenderBundleEncoder includes GPURenderEncoderBase;
|
||||
|
||||
dictionary GPURenderBundleEncoderDescriptor : GPUObjectDescriptorBase {
|
||||
required sequence<GPUTextureFormat> colorFormats;
|
||||
GPUTextureFormat depthStencilFormat;
|
||||
GPUSize32 sampleCount = 1;
|
||||
};
|
||||
|
||||
interface GPUQueue {
|
||||
void submit(sequence<GPUCommandBuffer> commandBuffers);
|
||||
|
||||
GPUFence createFence(optional GPUFenceDescriptor descriptor = {});
|
||||
void signal(GPUFence fence, GPUFenceValue signalValue);
|
||||
|
||||
void copyImageBitmapToTexture(
|
||||
GPUImageBitmapCopyView source,
|
||||
GPUTextureCopyView destination,
|
||||
GPUExtent3D copySize);
|
||||
};
|
||||
GPUQueue includes GPUObjectBase;
|
||||
|
||||
interface GPUFence {
|
||||
GPUFenceValue getCompletedValue();
|
||||
Promise<void> onCompletion(GPUFenceValue completionValue);
|
||||
};
|
||||
GPUFence includes GPUObjectBase;
|
||||
|
||||
dictionary GPUFenceDescriptor : GPUObjectDescriptorBase {
|
||||
GPUFenceValue initialValue = 0;
|
||||
};
|
||||
|
||||
interface GPUCanvasContext {
|
||||
GPUSwapChain configureSwapChain(GPUSwapChainDescriptor descriptor);
|
||||
|
||||
Promise<GPUTextureFormat> getSwapChainPreferredFormat(GPUDevice device);
|
||||
};
|
||||
|
||||
dictionary GPUSwapChainDescriptor : GPUObjectDescriptorBase {
|
||||
required GPUDevice device;
|
||||
required GPUTextureFormat format;
|
||||
GPUTextureUsageFlags usage = 0x10; // GPUTextureUsage.OUTPUT_ATTACHMENT
|
||||
};
|
||||
|
||||
interface GPUSwapChain {
|
||||
GPUTexture getCurrentTexture();
|
||||
};
|
||||
GPUSwapChain includes GPUObjectBase;
|
||||
|
||||
interface GPUDeviceLostInfo {
|
||||
readonly attribute DOMString message;
|
||||
};
|
||||
|
||||
partial interface GPUDevice {
|
||||
readonly attribute Promise<GPUDeviceLostInfo> lost;
|
||||
};
|
||||
|
||||
enum GPUErrorFilter {
|
||||
"none",
|
||||
"out-of-memory",
|
||||
"validation"
|
||||
};
|
||||
|
||||
interface GPUOutOfMemoryError {
|
||||
constructor();
|
||||
};
|
||||
|
||||
interface GPUValidationError {
|
||||
constructor(DOMString message);
|
||||
readonly attribute DOMString message;
|
||||
};
|
||||
|
||||
typedef (GPUOutOfMemoryError or GPUValidationError) GPUError;
|
||||
|
||||
partial interface GPUDevice {
|
||||
void pushErrorScope(GPUErrorFilter filter);
|
||||
Promise<GPUError?> popErrorScope();
|
||||
};
|
||||
|
||||
[
|
||||
Exposed=(Window, DedicatedWorker)
|
||||
]
|
||||
interface GPUUncapturedErrorEvent : Event {
|
||||
constructor(
|
||||
DOMString type,
|
||||
GPUUncapturedErrorEventInit gpuUncapturedErrorEventInitDict
|
||||
);
|
||||
[SameObject] readonly attribute GPUError error;
|
||||
};
|
||||
|
||||
dictionary GPUUncapturedErrorEventInit : EventInit {
|
||||
required GPUError error;
|
||||
};
|
||||
|
||||
partial interface GPUDevice {
|
||||
[Exposed=(Window, DedicatedWorker)]
|
||||
attribute EventHandler onuncapturederror;
|
||||
};
|
||||
|
||||
typedef [EnforceRange] unsigned long GPUBufferDynamicOffset;
|
||||
typedef [EnforceRange] unsigned long long GPUFenceValue;
|
||||
typedef [EnforceRange] unsigned long GPUStencilValue;
|
||||
typedef [EnforceRange] unsigned long GPUSampleMask;
|
||||
typedef [EnforceRange] long GPUDepthBias;
|
||||
|
||||
typedef [EnforceRange] unsigned long long GPUSize64;
|
||||
typedef [EnforceRange] unsigned long GPUIntegerCoordinate;
|
||||
typedef [EnforceRange] unsigned long GPUIndex32;
|
||||
typedef [EnforceRange] unsigned long GPUSize32;
|
||||
typedef [EnforceRange] long GPUSignedOffset32;
|
||||
|
||||
dictionary GPUColorDict {
|
||||
required double r;
|
||||
required double g;
|
||||
required double b;
|
||||
required double a;
|
||||
};
|
||||
typedef (sequence<double> or GPUColorDict) GPUColor;
|
||||
|
||||
dictionary GPUOrigin2DDict {
|
||||
GPUIntegerCoordinate x = 0;
|
||||
GPUIntegerCoordinate y = 0;
|
||||
};
|
||||
typedef (sequence<GPUIntegerCoordinate> or GPUOrigin2DDict) GPUOrigin2D;
|
||||
|
||||
dictionary GPUOrigin3DDict {
|
||||
GPUIntegerCoordinate x = 0;
|
||||
GPUIntegerCoordinate y = 0;
|
||||
GPUIntegerCoordinate z = 0;
|
||||
};
|
||||
typedef (sequence<GPUIntegerCoordinate> or GPUOrigin3DDict) GPUOrigin3D;
|
||||
|
||||
dictionary GPUExtent3DDict {
|
||||
required GPUIntegerCoordinate width;
|
||||
required GPUIntegerCoordinate height;
|
||||
required GPUIntegerCoordinate depth;
|
||||
};
|
||||
typedef (sequence<GPUIntegerCoordinate> or GPUExtent3DDict) GPUExtent3D;
|
||||
|
||||
typedef sequence<(GPUBuffer or ArrayBuffer)> GPUMappedBuffer;
|
@ -11,13 +11,22 @@ fn main() {
|
||||
let idls = fs::read_dir(".")
|
||||
.unwrap()
|
||||
.map(|f| f.unwrap().path())
|
||||
.filter(|f| f.extension().and_then(|s| s.to_str()) == Some("webidl"))
|
||||
.map(|f| (fs::read_to_string(&f).unwrap(), f));
|
||||
.filter(|path| path.extension().and_then(|s| s.to_str()) == Some("webidl"))
|
||||
.map(|path| {
|
||||
let unstable = path.file_name().and_then(|s| s.to_str()) == Some("unstable.webidl");
|
||||
let file = fs::read_to_string(&path).unwrap();
|
||||
(file, path, unstable)
|
||||
});
|
||||
|
||||
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
for (i, (idl, path)) in idls.enumerate() {
|
||||
for (i, (idl, path, unstable)) in idls.enumerate() {
|
||||
println!("processing {:?}", path);
|
||||
let mut generated_rust = wasm_bindgen_webidl::compile(&idl, None).unwrap();
|
||||
let (stable_source, experimental_source) = if unstable {
|
||||
(String::new(), idl)
|
||||
} else {
|
||||
(idl, String::new())
|
||||
};
|
||||
let mut generated_rust = wasm_bindgen_webidl::compile(&stable_source, &experimental_source, None).unwrap();
|
||||
|
||||
generated_rust.insert_str(
|
||||
0,
|
||||
|
@ -13,3 +13,4 @@ pub mod namespace;
|
||||
pub mod no_interface;
|
||||
pub mod simple;
|
||||
pub mod throws;
|
||||
pub mod unstable;
|
||||
|
13
crates/webidl-tests/unstable.js
Normal file
13
crates/webidl-tests/unstable.js
Normal file
@ -0,0 +1,13 @@
|
||||
global.GetUnstableInterface = class {
|
||||
static get() {
|
||||
return {
|
||||
enum_value(dict) {
|
||||
if (!dict) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dict.unstableEnum === "a" ? 1 : 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
crates/webidl-tests/unstable.rs
Normal file
17
crates/webidl-tests/unstable.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/unstable.rs"));
|
||||
|
||||
#[cfg(web_sys_unstable_apis)]
|
||||
#[wasm_bindgen_test]
|
||||
fn can_use_unstable_apis() {
|
||||
let unstable_interface = GetUnstableInterface::get();
|
||||
assert_eq!(0u32, unstable_interface.enum_value());
|
||||
|
||||
let mut dict = UnstableDictionary::new();
|
||||
dict.unstable_enum(UnstableEnum::B);
|
||||
assert_eq!(
|
||||
2u32,
|
||||
unstable_interface.enum_value_with_unstable_dictionary(&dict)
|
||||
);
|
||||
}
|
19
crates/webidl-tests/unstable.webidl
vendored
Normal file
19
crates/webidl-tests/unstable.webidl
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
enum UnstableEnum {
|
||||
"a",
|
||||
"b"
|
||||
};
|
||||
|
||||
dictionary UnstableDictionary {
|
||||
UnstableEnum unstableEnum;
|
||||
};
|
||||
|
||||
typedef unsigned long UnstableTypedef;
|
||||
|
||||
[NoInterfaceObject]
|
||||
partial interface UnstableInterface {
|
||||
UnstableTypedef enum_value(optional UnstableDictionary unstableDictionary = {});
|
||||
};
|
||||
|
||||
interface GetUnstableInterface {
|
||||
static UnstableInterface get();
|
||||
};
|
@ -20,15 +20,14 @@ use weedle::CallbackInterfaceDefinition;
|
||||
use weedle::{DictionaryDefinition, PartialDictionaryDefinition};
|
||||
|
||||
use super::Result;
|
||||
use crate::util;
|
||||
use crate::util::camel_case_ident;
|
||||
use crate::{util::{self, camel_case_ident}, ApiStability};
|
||||
|
||||
/// Collection of constructs that may use partial.
|
||||
#[derive(Default)]
|
||||
pub(crate) struct FirstPassRecord<'src> {
|
||||
pub(crate) builtin_idents: BTreeSet<Ident>,
|
||||
pub(crate) interfaces: BTreeMap<&'src str, InterfaceData<'src>>,
|
||||
pub(crate) enums: BTreeMap<&'src str, &'src weedle::EnumDefinition<'src>>,
|
||||
pub(crate) enums: BTreeMap<&'src str, EnumData<'src>>,
|
||||
/// The mixins, mapping their name to the webidl ast node for the mixin.
|
||||
pub(crate) mixins: BTreeMap<&'src str, MixinData<'src>>,
|
||||
pub(crate) typedefs: BTreeMap<&'src str, &'src weedle::types::Type<'src>>,
|
||||
@ -40,6 +39,11 @@ pub(crate) struct FirstPassRecord<'src> {
|
||||
pub(crate) immutable_slice_whitelist: BTreeSet<&'static str>,
|
||||
}
|
||||
|
||||
pub(crate) struct AttributeInterfaceData<'src> {
|
||||
pub(crate) definition: &'src AttributeInterfaceMember<'src>,
|
||||
pub(crate) stability: ApiStability,
|
||||
}
|
||||
|
||||
/// We need to collect interface data during the first pass, to be used later.
|
||||
#[derive(Default)]
|
||||
pub(crate) struct InterfaceData<'src> {
|
||||
@ -47,11 +51,17 @@ pub(crate) struct InterfaceData<'src> {
|
||||
pub(crate) partial: bool,
|
||||
pub(crate) has_interface: bool,
|
||||
pub(crate) deprecated: Option<String>,
|
||||
pub(crate) attributes: Vec<&'src AttributeInterfaceMember<'src>>,
|
||||
pub(crate) attributes: Vec<AttributeInterfaceData<'src>>,
|
||||
pub(crate) consts: Vec<&'src ConstMember<'src>>,
|
||||
pub(crate) operations: BTreeMap<OperationId<'src>, OperationData<'src>>,
|
||||
pub(crate) superclass: Option<&'src str>,
|
||||
pub(crate) definition_attributes: Option<&'src ExtendedAttributeList<'src>>,
|
||||
pub(crate) stability: ApiStability,
|
||||
}
|
||||
|
||||
pub(crate) struct AttributeMixinData<'src> {
|
||||
pub(crate) definition: &'src AttributeMixinMember<'src>,
|
||||
pub(crate) stability: ApiStability,
|
||||
}
|
||||
|
||||
/// We need to collect mixin data during the first pass, to be used later.
|
||||
@ -59,10 +69,11 @@ pub(crate) struct InterfaceData<'src> {
|
||||
pub(crate) struct MixinData<'src> {
|
||||
/// Whether only partial mixins were encountered
|
||||
pub(crate) partial: bool,
|
||||
pub(crate) attributes: Vec<&'src AttributeMixinMember<'src>>,
|
||||
pub(crate) attributes: Vec<AttributeMixinData<'src>>,
|
||||
pub(crate) consts: Vec<&'src ConstMember<'src>>,
|
||||
pub(crate) operations: BTreeMap<OperationId<'src>, OperationData<'src>>,
|
||||
pub(crate) definition_attributes: Option<&'src ExtendedAttributeList<'src>>,
|
||||
pub(crate) stability: ApiStability,
|
||||
}
|
||||
|
||||
/// We need to collect namespace data during the first pass, to be used later.
|
||||
@ -75,6 +86,12 @@ pub(crate) struct NamespaceData<'src> {
|
||||
pub(crate) struct DictionaryData<'src> {
|
||||
pub(crate) partials: Vec<&'src PartialDictionaryDefinition<'src>>,
|
||||
pub(crate) definition: Option<&'src DictionaryDefinition<'src>>,
|
||||
pub(crate) stability: ApiStability,
|
||||
}
|
||||
|
||||
pub(crate) struct EnumData<'src> {
|
||||
pub(crate) definition: &'src weedle::EnumDefinition<'src>,
|
||||
pub(crate) stability: ApiStability,
|
||||
}
|
||||
|
||||
pub(crate) struct CallbackInterfaceData<'src> {
|
||||
@ -121,29 +138,29 @@ pub(crate) trait FirstPass<'src, Ctx> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, ctx: Ctx) -> Result<()>;
|
||||
}
|
||||
|
||||
impl<'src> FirstPass<'src, ()> for [weedle::Definition<'src>] {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
|
||||
impl<'src> FirstPass<'src, ApiStability> for [weedle::Definition<'src>] {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, stability: ApiStability) -> Result<()> {
|
||||
for def in self {
|
||||
def.first_pass(record, ())?;
|
||||
def.first_pass(record, stability)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> FirstPass<'src, ()> for weedle::Definition<'src> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
|
||||
impl<'src> FirstPass<'src, ApiStability> for weedle::Definition<'src> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, stability: ApiStability) -> Result<()> {
|
||||
use weedle::Definition::*;
|
||||
|
||||
match self {
|
||||
Dictionary(dictionary) => dictionary.first_pass(record, ()),
|
||||
Dictionary(dictionary) => dictionary.first_pass(record, stability),
|
||||
PartialDictionary(dictionary) => dictionary.first_pass(record, ()),
|
||||
Enum(enum_) => enum_.first_pass(record, ()),
|
||||
Enum(enum_) => enum_.first_pass(record, stability),
|
||||
IncludesStatement(includes) => includes.first_pass(record, ()),
|
||||
Interface(interface) => interface.first_pass(record, ()),
|
||||
PartialInterface(interface) => interface.first_pass(record, ()),
|
||||
InterfaceMixin(mixin) => mixin.first_pass(record, ()),
|
||||
PartialInterfaceMixin(mixin) => mixin.first_pass(record, ()),
|
||||
Interface(interface) => interface.first_pass(record, stability),
|
||||
PartialInterface(interface) => interface.first_pass(record, stability),
|
||||
InterfaceMixin(mixin) => mixin.first_pass(record, stability),
|
||||
PartialInterfaceMixin(mixin) => mixin.first_pass(record, stability),
|
||||
Namespace(namespace) => namespace.first_pass(record, ()),
|
||||
PartialNamespace(namespace) => namespace.first_pass(record, ()),
|
||||
Typedef(typedef) => typedef.first_pass(record, ()),
|
||||
@ -154,17 +171,20 @@ impl<'src> FirstPass<'src, ()> for weedle::Definition<'src> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> FirstPass<'src, ()> for weedle::DictionaryDefinition<'src> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
|
||||
impl<'src> FirstPass<'src, ApiStability> for weedle::DictionaryDefinition<'src> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, stability: ApiStability) -> Result<()> {
|
||||
if util::is_chrome_only(&self.attributes) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
record
|
||||
let dictionary_data = record
|
||||
.dictionaries
|
||||
.entry(self.identifier.0)
|
||||
.or_default()
|
||||
.definition = Some(self);
|
||||
.or_default();
|
||||
|
||||
dictionary_data.definition = Some(self);
|
||||
dictionary_data.stability = stability;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -181,17 +201,23 @@ impl<'src> FirstPass<'src, ()> for weedle::PartialDictionaryDefinition<'src> {
|
||||
.or_default()
|
||||
.partials
|
||||
.push(self);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> FirstPass<'src, ()> for weedle::EnumDefinition<'src> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
|
||||
impl<'src> FirstPass<'src, ApiStability> for weedle::EnumDefinition<'src> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, stability: ApiStability) -> Result<()> {
|
||||
if util::is_chrome_only(&self.attributes) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if record.enums.insert(self.identifier.0, self).is_some() {
|
||||
let enum_data = EnumData {
|
||||
definition: self,
|
||||
stability,
|
||||
};
|
||||
|
||||
if record.enums.insert(self.identifier.0, enum_data).is_some() {
|
||||
log::info!(
|
||||
"Encountered multiple enum declarations: {}",
|
||||
self.identifier.0
|
||||
@ -298,8 +324,8 @@ fn first_pass_operation<'src>(
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> FirstPass<'src, ()> for weedle::InterfaceDefinition<'src> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
|
||||
impl<'src> FirstPass<'src, ApiStability> for weedle::InterfaceDefinition<'src> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, stability: ApiStability) -> Result<()> {
|
||||
if util::is_chrome_only(&self.attributes) {
|
||||
return Ok(());
|
||||
}
|
||||
@ -311,6 +337,7 @@ impl<'src> FirstPass<'src, ()> for weedle::InterfaceDefinition<'src> {
|
||||
interface_data.deprecated =
|
||||
util::get_rust_deprecated(&self.attributes).map(|s| s.to_string());
|
||||
interface_data.has_interface = !util::is_no_interface_object(&self.attributes);
|
||||
interface_data.stability = stability;
|
||||
if let Some(attrs) = &self.attributes {
|
||||
for attr in attrs.body.list.iter() {
|
||||
process_interface_attribute(record, self.identifier.0, attr);
|
||||
@ -318,7 +345,7 @@ impl<'src> FirstPass<'src, ()> for weedle::InterfaceDefinition<'src> {
|
||||
}
|
||||
|
||||
for member in &self.members.body {
|
||||
member.first_pass(record, self.identifier.0)?;
|
||||
member.first_pass(record, (self.identifier.0, stability))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -382,8 +409,8 @@ fn process_interface_attribute<'src>(
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> FirstPass<'src, ()> for weedle::PartialInterfaceDefinition<'src> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
|
||||
impl<'src> FirstPass<'src, ApiStability> for weedle::PartialInterfaceDefinition<'src> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, stability: ApiStability) -> Result<()> {
|
||||
if util::is_chrome_only(&self.attributes) {
|
||||
return Ok(());
|
||||
}
|
||||
@ -392,31 +419,33 @@ impl<'src> FirstPass<'src, ()> for weedle::PartialInterfaceDefinition<'src> {
|
||||
.entry(self.identifier.0)
|
||||
.or_insert_with(|| InterfaceData {
|
||||
partial: true,
|
||||
stability,
|
||||
..Default::default()
|
||||
});
|
||||
for member in &self.members.body {
|
||||
member.first_pass(record, self.identifier.0)?;
|
||||
member.first_pass(record, (self.identifier.0, stability))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> FirstPass<'src, &'src str> for weedle::interface::InterfaceMember<'src> {
|
||||
impl<'src> FirstPass<'src, (&'src str, ApiStability)> for weedle::interface::InterfaceMember<'src> {
|
||||
fn first_pass(
|
||||
&'src self,
|
||||
record: &mut FirstPassRecord<'src>,
|
||||
self_name: &'src str,
|
||||
ctx: (&'src str, ApiStability),
|
||||
) -> Result<()> {
|
||||
match self {
|
||||
InterfaceMember::Attribute(attr) => attr.first_pass(record, self_name),
|
||||
InterfaceMember::Operation(op) => op.first_pass(record, self_name),
|
||||
InterfaceMember::Attribute(attr) => attr.first_pass(record, ctx),
|
||||
InterfaceMember::Operation(op) => op.first_pass(record, ctx.0),
|
||||
InterfaceMember::Const(const_) => {
|
||||
if util::is_chrome_only(&const_.attributes) {
|
||||
return Ok(());
|
||||
}
|
||||
record
|
||||
.interfaces
|
||||
.get_mut(self_name)
|
||||
.get_mut(ctx.0)
|
||||
.unwrap()
|
||||
.consts
|
||||
.push(const_);
|
||||
@ -484,11 +513,11 @@ impl<'src> FirstPass<'src, &'src str> for weedle::interface::OperationInterfaceM
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> FirstPass<'src, &'src str> for weedle::interface::AttributeInterfaceMember<'src> {
|
||||
impl<'src> FirstPass<'src, (&'src str, ApiStability)> for weedle::interface::AttributeInterfaceMember<'src> {
|
||||
fn first_pass(
|
||||
&'src self,
|
||||
record: &mut FirstPassRecord<'src>,
|
||||
self_name: &'src str,
|
||||
ctx: (&'src str, ApiStability),
|
||||
) -> Result<()> {
|
||||
if util::is_chrome_only(&self.attributes) {
|
||||
return Ok(());
|
||||
@ -496,16 +525,19 @@ impl<'src> FirstPass<'src, &'src str> for weedle::interface::AttributeInterfaceM
|
||||
|
||||
record
|
||||
.interfaces
|
||||
.get_mut(self_name)
|
||||
.get_mut(ctx.0)
|
||||
.unwrap()
|
||||
.attributes
|
||||
.push(self);
|
||||
.push(AttributeInterfaceData {
|
||||
definition: self,
|
||||
stability: ctx.1
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> FirstPass<'src, ()> for weedle::InterfaceMixinDefinition<'src> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
|
||||
impl<'src> FirstPass<'src, ApiStability> for weedle::InterfaceMixinDefinition<'src> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, stability: ApiStability) -> Result<()> {
|
||||
if util::is_chrome_only(&self.attributes) {
|
||||
return Ok(());
|
||||
}
|
||||
@ -514,18 +546,19 @@ impl<'src> FirstPass<'src, ()> for weedle::InterfaceMixinDefinition<'src> {
|
||||
let mixin_data = record.mixins.entry(self.identifier.0).or_default();
|
||||
mixin_data.partial = false;
|
||||
mixin_data.definition_attributes = self.attributes.as_ref();
|
||||
mixin_data.stability = stability;
|
||||
}
|
||||
|
||||
for member in &self.members.body {
|
||||
member.first_pass(record, self.identifier.0)?;
|
||||
member.first_pass(record, (self.identifier.0, stability))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> FirstPass<'src, ()> for weedle::PartialInterfaceMixinDefinition<'src> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
|
||||
impl<'src> FirstPass<'src, ApiStability> for weedle::PartialInterfaceMixinDefinition<'src> {
|
||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, stability: ApiStability) -> Result<()> {
|
||||
if util::is_chrome_only(&self.attributes) {
|
||||
return Ok(());
|
||||
}
|
||||
@ -535,31 +568,32 @@ impl<'src> FirstPass<'src, ()> for weedle::PartialInterfaceMixinDefinition<'src>
|
||||
.entry(self.identifier.0)
|
||||
.or_insert_with(|| MixinData {
|
||||
partial: true,
|
||||
stability,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
for member in &self.members.body {
|
||||
member.first_pass(record, self.identifier.0)?;
|
||||
member.first_pass(record, (self.identifier.0, stability))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> FirstPass<'src, &'src str> for weedle::mixin::MixinMember<'src> {
|
||||
impl<'src> FirstPass<'src, (&'src str, ApiStability)> for weedle::mixin::MixinMember<'src> {
|
||||
fn first_pass(
|
||||
&'src self,
|
||||
record: &mut FirstPassRecord<'src>,
|
||||
self_name: &'src str,
|
||||
ctx: (&'src str, ApiStability),
|
||||
) -> Result<()> {
|
||||
match self {
|
||||
MixinMember::Operation(op) => op.first_pass(record, self_name),
|
||||
MixinMember::Attribute(a) => a.first_pass(record, self_name),
|
||||
MixinMember::Operation(op) => op.first_pass(record, ctx),
|
||||
MixinMember::Attribute(a) => a.first_pass(record, ctx),
|
||||
MixinMember::Const(a) => {
|
||||
if util::is_chrome_only(&a.attributes) {
|
||||
return Ok(());
|
||||
}
|
||||
record.mixins.get_mut(self_name).unwrap().consts.push(a);
|
||||
record.mixins.get_mut(ctx.0).unwrap().consts.push(a);
|
||||
Ok(())
|
||||
}
|
||||
MixinMember::Stringifier(_) => {
|
||||
@ -570,11 +604,11 @@ impl<'src> FirstPass<'src, &'src str> for weedle::mixin::MixinMember<'src> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> FirstPass<'src, &'src str> for weedle::mixin::OperationMixinMember<'src> {
|
||||
impl<'src> FirstPass<'src, (&'src str, ApiStability)> for weedle::mixin::OperationMixinMember<'src> {
|
||||
fn first_pass(
|
||||
&'src self,
|
||||
record: &mut FirstPassRecord<'src>,
|
||||
self_name: &'src str,
|
||||
ctx: (&'src str, ApiStability),
|
||||
) -> Result<()> {
|
||||
if self.stringifier.is_some() {
|
||||
log::warn!("Unsupported webidl stringifier: {:?}", self);
|
||||
@ -584,7 +618,7 @@ impl<'src> FirstPass<'src, &'src str> for weedle::mixin::OperationMixinMember<'s
|
||||
first_pass_operation(
|
||||
record,
|
||||
FirstPassOperationType::Mixin,
|
||||
self_name,
|
||||
ctx.0,
|
||||
&[OperationId::Operation(self.identifier.map(|s| s.0.clone()))],
|
||||
&self.args.body.list,
|
||||
&self.return_type,
|
||||
@ -595,21 +629,24 @@ impl<'src> FirstPass<'src, &'src str> for weedle::mixin::OperationMixinMember<'s
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> FirstPass<'src, &'src str> for weedle::mixin::AttributeMixinMember<'src> {
|
||||
impl<'src> FirstPass<'src, (&'src str, ApiStability)> for weedle::mixin::AttributeMixinMember<'src> {
|
||||
fn first_pass(
|
||||
&'src self,
|
||||
record: &mut FirstPassRecord<'src>,
|
||||
self_name: &'src str,
|
||||
ctx: (&'src str, ApiStability),
|
||||
) -> Result<()> {
|
||||
if util::is_chrome_only(&self.attributes) {
|
||||
return Ok(());
|
||||
}
|
||||
record
|
||||
.mixins
|
||||
.get_mut(self_name)
|
||||
.get_mut(ctx.0)
|
||||
.unwrap()
|
||||
.attributes
|
||||
.push(self);
|
||||
.push(AttributeMixinData {
|
||||
definition: self,
|
||||
stability: ctx.1
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ use crate::util::{
|
||||
camel_case_ident, mdn_doc, public, shouty_snake_case_ident, snake_case_ident,
|
||||
webidl_const_v_to_backend_const_v, TypePosition,
|
||||
};
|
||||
use anyhow::{bail, Result};
|
||||
use anyhow::Result;
|
||||
use proc_macro2::{Ident, Span};
|
||||
use quote::{quote, ToTokens};
|
||||
use std::collections::{BTreeSet, HashSet};
|
||||
@ -55,37 +55,59 @@ impl fmt::Display for WebIDLParseError {
|
||||
|
||||
impl std::error::Error for WebIDLParseError {}
|
||||
|
||||
/// Parse a string of WebIDL source text into a wasm-bindgen AST.
|
||||
fn parse(webidl_source: &str, allowed_types: Option<&[&str]>) -> Result<Program> {
|
||||
let definitions = match weedle::parse(webidl_source) {
|
||||
Ok(def) => def,
|
||||
Err(e) => {
|
||||
match &e {
|
||||
weedle::Err::Incomplete(needed) => bail!("needed {:?} more bytes", needed),
|
||||
weedle::Err::Error(cx) | weedle::Err::Failure(cx) => {
|
||||
// Note that #[allow] here is a workaround for Geal/nom#843
|
||||
// because the `Context` type here comes from `nom` and if
|
||||
// something else in our crate graph enables the
|
||||
// `verbose-errors` feature then we need to still compiled
|
||||
// against the changed enum definition.
|
||||
#[allow(unreachable_patterns)]
|
||||
let remaining = match cx {
|
||||
weedle::Context::Code(remaining, _) => remaining.len(),
|
||||
_ => 0,
|
||||
};
|
||||
let pos = webidl_source.len() - remaining;
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub(crate) enum ApiStability {
|
||||
Stable,
|
||||
Unstable,
|
||||
}
|
||||
|
||||
bail!(WebIDLParseError(pos))
|
||||
}
|
||||
impl ApiStability {
|
||||
pub(crate) fn is_unstable(self) -> bool {
|
||||
self == Self::Unstable
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ApiStability {
|
||||
fn default() -> Self {
|
||||
Self::Stable
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_source(source: &str) -> Result<Vec<weedle::Definition>> {
|
||||
weedle::parse(source).map_err(|e| {
|
||||
match &e {
|
||||
weedle::Err::Incomplete(needed) => anyhow::anyhow!("needed {:?} more bytes", needed),
|
||||
weedle::Err::Error(cx) | weedle::Err::Failure(cx) => {
|
||||
// Note that #[allow] here is a workaround for Geal/nom#843
|
||||
// because the `Context` type here comes from `nom` and if
|
||||
// something else in our crate graph enables the
|
||||
// `verbose-errors` feature then we need to still compiled
|
||||
// against the changed enum definition.
|
||||
#[allow(unreachable_patterns)]
|
||||
let remaining = match cx {
|
||||
weedle::Context::Code(remaining, _) => remaining.len(),
|
||||
_ => 0,
|
||||
};
|
||||
let pos = source.len() - remaining;
|
||||
|
||||
WebIDLParseError(pos).into()
|
||||
}
|
||||
}
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse a string of WebIDL source text into a wasm-bindgen AST.
|
||||
fn parse(webidl_source: &str, unstable_source: &str, allowed_types: Option<&[&str]>) -> Result<Program> {
|
||||
let mut first_pass_record: FirstPassRecord = Default::default();
|
||||
first_pass_record.builtin_idents = builtin_idents();
|
||||
first_pass_record.immutable_slice_whitelist = immutable_slice_whitelist();
|
||||
|
||||
definitions.first_pass(&mut first_pass_record, ())?;
|
||||
let definitions = parse_source(webidl_source)?;
|
||||
definitions.first_pass(&mut first_pass_record, ApiStability::Stable)?;
|
||||
|
||||
let unstable_definitions = parse_source(unstable_source)?;
|
||||
unstable_definitions.first_pass(&mut first_pass_record, ApiStability::Unstable)?;
|
||||
|
||||
let mut program = Default::default();
|
||||
let mut submodules = Vec::new();
|
||||
|
||||
@ -136,14 +158,14 @@ fn parse(webidl_source: &str, allowed_types: Option<&[&str]>) -> Result<Program>
|
||||
|
||||
Ok(Program {
|
||||
main: program,
|
||||
submodules: submodules,
|
||||
submodules,
|
||||
})
|
||||
}
|
||||
|
||||
/// Compile the given WebIDL source text into Rust source text containing
|
||||
/// `wasm-bindgen` bindings to the things described in the WebIDL.
|
||||
pub fn compile(webidl_source: &str, allowed_types: Option<&[&str]>) -> Result<String> {
|
||||
let ast = parse(webidl_source, allowed_types)?;
|
||||
pub fn compile(webidl_source: &str, experimental_source: &str, allowed_types: Option<&[&str]>) -> Result<String> {
|
||||
let ast = parse(webidl_source, experimental_source, allowed_types)?;
|
||||
Ok(compile_ast(ast))
|
||||
}
|
||||
|
||||
@ -292,8 +314,10 @@ fn compile_ast(mut ast: Program) -> String {
|
||||
}
|
||||
|
||||
impl<'src> FirstPassRecord<'src> {
|
||||
fn append_enum(&self, program: &mut ast::Program, enum_: &'src weedle::EnumDefinition<'src>) {
|
||||
fn append_enum(&self, program: &mut ast::Program, data: &first_pass::EnumData<'src>) {
|
||||
let enum_ = data.definition;
|
||||
let variants = &enum_.values.body.list;
|
||||
let unstable_api = data.stability.is_unstable();
|
||||
program.imports.push(ast::Import {
|
||||
module: ast::ImportModule::None,
|
||||
js_namespace: None,
|
||||
@ -312,7 +336,9 @@ impl<'src> FirstPassRecord<'src> {
|
||||
.collect(),
|
||||
variant_values: variants.iter().map(|v| v.0.to_string()).collect(),
|
||||
rust_attrs: vec![syn::parse_quote!(#[derive(Copy, Clone, PartialEq, Debug)])],
|
||||
unstable_api,
|
||||
}),
|
||||
unstable_api,
|
||||
});
|
||||
}
|
||||
|
||||
@ -352,6 +378,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
ctor: true,
|
||||
doc_comment: Some(doc_comment),
|
||||
ctor_doc_comment: None,
|
||||
unstable_api: data.stability.is_unstable(),
|
||||
};
|
||||
let mut ctor_doc_comment = Some(format!("Construct a new `{}`\n", def.identifier.0));
|
||||
self.append_required_features_doc(&dict, &mut ctor_doc_comment, &[&extra_feature]);
|
||||
@ -504,7 +531,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
let kind = ast::ImportFunctionKind::Normal;
|
||||
let extra = snake_case_ident(self_name);
|
||||
let extra = &[&extra[..]];
|
||||
for mut import_function in self.create_imports(None, kind, id, data) {
|
||||
for mut import_function in self.create_imports(None, kind, id, data, false) {
|
||||
let mut doc = Some(doc_comment.clone());
|
||||
self.append_required_features_doc(&import_function, &mut doc, extra);
|
||||
import_function.doc_comment = doc;
|
||||
@ -512,6 +539,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
module: ast::ImportModule::None,
|
||||
js_namespace: Some(raw_ident(self_name)),
|
||||
kind: ast::ImportKind::Function(import_function),
|
||||
unstable_api: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -521,6 +549,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
program: &mut ast::Program,
|
||||
self_name: &'src str,
|
||||
member: &'src weedle::interface::ConstMember<'src>,
|
||||
unstable_api: bool,
|
||||
) {
|
||||
let idl_type = member.const_type.to_idl_type(self);
|
||||
let ty = match idl_type.to_syn_type(TypePosition::Return) {
|
||||
@ -542,6 +571,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
class: Some(rust_ident(camel_case_ident(&self_name).as_str())),
|
||||
ty,
|
||||
value: webidl_const_v_to_backend_const_v(&member.const_value),
|
||||
unstable_api,
|
||||
});
|
||||
}
|
||||
|
||||
@ -553,6 +583,8 @@ impl<'src> FirstPassRecord<'src> {
|
||||
) {
|
||||
let mut doc_comment = Some(format!("The `{}` object\n\n{}", name, mdn_doc(name, None),));
|
||||
|
||||
let interface_unstable = data.stability.is_unstable();
|
||||
|
||||
let mut attrs = Vec::new();
|
||||
attrs.push(syn::parse_quote!( #[derive(Debug, Clone, PartialEq, Eq)] ));
|
||||
self.add_deprecated(data, &mut attrs);
|
||||
@ -561,6 +593,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
rust_name: rust_ident(camel_case_ident(name).as_str()),
|
||||
js_name: name.to_string(),
|
||||
attrs,
|
||||
unstable_api: interface_unstable,
|
||||
doc_comment: None,
|
||||
instanceof_shim: format!("__widl_instanceof_{}", name),
|
||||
is_type_of: if data.has_interface {
|
||||
@ -596,25 +629,28 @@ impl<'src> FirstPassRecord<'src> {
|
||||
module: ast::ImportModule::None,
|
||||
js_namespace: None,
|
||||
kind: ast::ImportKind::Type(import_type),
|
||||
unstable_api: interface_unstable,
|
||||
});
|
||||
|
||||
for (id, op_data) in data.operations.iter() {
|
||||
self.member_operation(program, name, data, id, op_data);
|
||||
}
|
||||
for member in data.consts.iter() {
|
||||
self.append_const(program, name, member);
|
||||
self.append_const(program, name, member, interface_unstable);
|
||||
}
|
||||
for member in data.attributes.iter() {
|
||||
let member_def = member.definition;
|
||||
self.member_attribute(
|
||||
program,
|
||||
name,
|
||||
data,
|
||||
member.modifier,
|
||||
member.readonly.is_some(),
|
||||
&member.type_,
|
||||
member.identifier.0,
|
||||
&member.attributes,
|
||||
member_def.modifier,
|
||||
member_def.readonly.is_some(),
|
||||
&member_def.type_,
|
||||
member_def.identifier.0,
|
||||
&member_def.attributes,
|
||||
data.definition_attributes,
|
||||
interface_unstable || member.stability.is_unstable(),
|
||||
);
|
||||
}
|
||||
|
||||
@ -623,23 +659,25 @@ impl<'src> FirstPassRecord<'src> {
|
||||
self.member_operation(program, name, data, id, op_data);
|
||||
}
|
||||
for member in &mixin_data.consts {
|
||||
self.append_const(program, name, member);
|
||||
self.append_const(program, name, member, interface_unstable);
|
||||
}
|
||||
for member in &mixin_data.attributes {
|
||||
let member_def = member.definition;
|
||||
self.member_attribute(
|
||||
program,
|
||||
name,
|
||||
data,
|
||||
if let Some(s) = member.stringifier {
|
||||
if let Some(s) = member_def.stringifier {
|
||||
Some(weedle::interface::StringifierOrInheritOrStatic::Stringifier(s))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
member.readonly.is_some(),
|
||||
&member.type_,
|
||||
member.identifier.0,
|
||||
&member.attributes,
|
||||
member_def.readonly.is_some(),
|
||||
&member_def.type_,
|
||||
member_def.identifier.0,
|
||||
&member_def.attributes,
|
||||
data.definition_attributes,
|
||||
interface_unstable || member.stability.is_unstable(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -656,6 +694,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
identifier: &'src str,
|
||||
attrs: &'src Option<ExtendedAttributeList<'src>>,
|
||||
container_attrs: Option<&'src ExtendedAttributeList<'src>>,
|
||||
unstable_api: bool,
|
||||
) {
|
||||
use weedle::interface::StringifierOrInheritOrStatic::*;
|
||||
|
||||
@ -673,6 +712,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
is_static,
|
||||
attrs,
|
||||
container_attrs,
|
||||
unstable_api,
|
||||
) {
|
||||
let mut doc = import_function.doc_comment.take();
|
||||
self.append_required_features_doc(&import_function, &mut doc, &[]);
|
||||
@ -688,6 +728,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
is_static,
|
||||
attrs,
|
||||
container_attrs,
|
||||
unstable_api,
|
||||
) {
|
||||
let mut doc = import_function.doc_comment.take();
|
||||
self.append_required_features_doc(&import_function, &mut doc, &[]);
|
||||
@ -742,7 +783,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
OperationId::IndexingDeleter => Some(format!("The indexing deleter\n\n")),
|
||||
};
|
||||
let attrs = data.definition_attributes;
|
||||
for mut method in self.create_imports(attrs, kind, id, op_data) {
|
||||
for mut method in self.create_imports(attrs, kind, id, op_data, data.stability.is_unstable()) {
|
||||
let mut doc = doc.clone();
|
||||
self.append_required_features_doc(&method, &mut doc, &[]);
|
||||
method.doc_comment = doc;
|
||||
@ -843,6 +884,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
ctor: true,
|
||||
doc_comment: None,
|
||||
ctor_doc_comment: None,
|
||||
unstable_api: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -231,6 +231,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
catch: bool,
|
||||
variadic: bool,
|
||||
doc_comment: Option<String>,
|
||||
unstable_api: bool,
|
||||
) -> Option<ast::ImportFunction>
|
||||
where
|
||||
'src: 'a,
|
||||
@ -327,6 +328,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
},
|
||||
kind,
|
||||
doc_comment,
|
||||
unstable_api,
|
||||
})
|
||||
}
|
||||
|
||||
@ -339,6 +341,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
is_static: bool,
|
||||
attrs: &Option<ExtendedAttributeList>,
|
||||
container_attrs: Option<&ExtendedAttributeList>,
|
||||
unstable_api: bool,
|
||||
) -> Option<ast::ImportFunction> {
|
||||
let kind = ast::OperationKind::Getter(Some(raw_ident(name)));
|
||||
let kind = self.import_function_kind(self_name, is_static, kind);
|
||||
@ -357,6 +360,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
name,
|
||||
mdn_doc(self_name, Some(name))
|
||||
)),
|
||||
unstable_api,
|
||||
)
|
||||
}
|
||||
|
||||
@ -369,6 +373,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
is_static: bool,
|
||||
attrs: &Option<ExtendedAttributeList>,
|
||||
container_attrs: Option<&ExtendedAttributeList>,
|
||||
unstable_api: bool,
|
||||
) -> Option<ast::ImportFunction> {
|
||||
let kind = ast::OperationKind::Setter(Some(raw_ident(name)));
|
||||
let kind = self.import_function_kind(self_name, is_static, kind);
|
||||
@ -387,6 +392,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
name,
|
||||
mdn_doc(self_name, Some(name))
|
||||
)),
|
||||
unstable_api,
|
||||
)
|
||||
}
|
||||
|
||||
@ -414,6 +420,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
kind: ast::ImportFunctionKind,
|
||||
id: &OperationId<'src>,
|
||||
data: &OperationData<'src>,
|
||||
unstable_api: bool,
|
||||
) -> Vec<ast::ImportFunction> {
|
||||
// First up, prune all signatures that reference unsupported arguments.
|
||||
// We won't consider these until said arguments are implemented.
|
||||
@ -618,6 +625,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
catch,
|
||||
variadic,
|
||||
None,
|
||||
unstable_api,
|
||||
),
|
||||
);
|
||||
if !variadic {
|
||||
@ -644,6 +652,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
catch,
|
||||
false,
|
||||
None,
|
||||
unstable_api,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -88,6 +88,7 @@
|
||||
- [Function Overloads](./web-sys/function-overloads.md)
|
||||
- [Type Translations](./web-sys/type-translations.md)
|
||||
- [Inheritance](./web-sys/inheritance.md)
|
||||
- [Unstable APIs](./web-sys/unstable-apis.md)
|
||||
|
||||
- [Testing with `wasm-bindgen-test`](./wasm-bindgen-test/index.md)
|
||||
- [Usage](./wasm-bindgen-test/usage.md)
|
||||
|
31
guide/src/web-sys/unstable-apis.md
Normal file
31
guide/src/web-sys/unstable-apis.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Unstable APIs
|
||||
|
||||
It's common for browsers to implement parts of a web API while the specification
|
||||
for that API is still being written. The API may require frequent changes as the
|
||||
specification continues to be developed, so the WebIDL is relatively unstable.
|
||||
|
||||
This causes some challenges for `web-sys` because it means `web-sys` would have
|
||||
to make breaking API changes whenever the WebIDL changes. It also means that
|
||||
previously published `web-sys` versions would be invalid, because the browser
|
||||
API may have been changed to match the updated WebIDL.
|
||||
|
||||
To avoid frequent breaking changes for unstable APIs, `web-sys` hides all
|
||||
unstable APIs through an attribute that looks like:
|
||||
|
||||
```rust
|
||||
#[cfg(web_sys_unstable_apis)]
|
||||
pub struct Foo;
|
||||
```
|
||||
|
||||
By hiding unstable APIs through an attribute, it's necessary for crates to
|
||||
explicitly opt-in to these reduced stability guarantees in order to use these
|
||||
APIs. Specifically, these APIs do not follow semver and may break whenever the
|
||||
WebIDL changes.
|
||||
|
||||
Crates can opt-in to unstable APIs at compile-time by passing the `cfg` flag
|
||||
`web_sys_unstable_apis`. Typically the `RUSTFLAGS` environment variable is used
|
||||
to do this. For example:
|
||||
|
||||
```bash
|
||||
RUSTFLAGS=--cfg=web_sys_unstable_apis cargo run
|
||||
```
|
Loading…
x
Reference in New Issue
Block a user