diff -Nru rust-wasm-bindgen-webidl-0.2.58/Cargo.lock rust-wasm-bindgen-webidl-0.2.75/Cargo.lock --- rust-wasm-bindgen-webidl-0.2.58/Cargo.lock 1970-01-01 00:00:00.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/Cargo.lock 1970-01-01 00:00:01.000000000 +0000 @@ -0,0 +1,378 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "bumpalo" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" + +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "memchr", + "version_check", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "sourcefile" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "580aa3a91a63d23aac5b6b267e2d13cb4f363e31dce6c352fca4752ae12e479f" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e0c4a743a309662d45f4ede961d7afa4ba4131a59a639f29b0069c3798bbcc2" + +[[package]] +name = "wasm-bindgen-webidl" +version = "0.2.75" +dependencies = [ + "anyhow", + "env_logger", + "heck", + "lazy_static", + "log", + "proc-macro2", + "quote", + "sourcefile", + "structopt", + "syn", + "wasm-bindgen-backend", + "weedle", +] + +[[package]] +name = "weedle" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610950904727748ca09682e857f0d6d6437f0ca862f32f9229edba8cec8b2635" +dependencies = [ + "nom", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff -Nru rust-wasm-bindgen-webidl-0.2.58/Cargo.toml rust-wasm-bindgen-webidl-0.2.75/Cargo.toml --- rust-wasm-bindgen-webidl-0.2.58/Cargo.toml 2020-01-07 19:48:47.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/Cargo.toml 1970-01-01 00:00:01.000000000 +0000 @@ -13,7 +13,7 @@ [package] edition = "2018" name = "wasm-bindgen-webidl" -version = "0.2.58" +version = "0.2.75" authors = ["The wasm-bindgen Developers"] description = "Support for parsing WebIDL specific to wasm-bindgen\n" homepage = "https://rustwasm.github.io/wasm-bindgen/" @@ -24,9 +24,15 @@ [dependencies.anyhow] version = "1.0" +[dependencies.env_logger] +version = "0.8.1" + [dependencies.heck] version = "0.3" +[dependencies.lazy_static] +version = "1.0.2" + [dependencies.log] version = "0.4.1" @@ -36,12 +42,18 @@ [dependencies.quote] version = "1.0" +[dependencies.sourcefile] +version = "0.1" + +[dependencies.structopt] +version = "0.3.9" + [dependencies.syn] version = "1.0" features = ["full"] [dependencies.wasm-bindgen-backend] -version = "=0.2.58" +version = "=0.2.75" [dependencies.weedle] -version = "0.10" +version = "0.12" diff -Nru rust-wasm-bindgen-webidl-0.2.58/Cargo.toml.orig rust-wasm-bindgen-webidl-0.2.75/Cargo.toml.orig --- rust-wasm-bindgen-webidl-0.2.58/Cargo.toml.orig 2020-01-07 17:34:55.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/Cargo.toml.orig 1973-11-29 21:33:09.000000000 +0000 @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-webidl" -version = "0.2.58" +version = "0.2.75" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" categories = ["wasm"] @@ -13,11 +13,15 @@ edition = "2018" [dependencies] +env_logger = "0.8.1" anyhow = "1.0" heck = "0.3" log = "0.4.1" proc-macro2 = "1.0" quote = '1.0' syn = { version = '1.0', features = ['full'] } -wasm-bindgen-backend = { version = "=0.2.58", path = "../backend" } -weedle = "0.10" +wasm-bindgen-backend = { version = "=0.2.75", path = "../backend" } +weedle = "0.12" +lazy_static = "1.0.2" +sourcefile = "0.1" +structopt = "0.3.9" diff -Nru rust-wasm-bindgen-webidl-0.2.58/.cargo_vcs_info.json rust-wasm-bindgen-webidl-0.2.75/.cargo_vcs_info.json --- rust-wasm-bindgen-webidl-0.2.58/.cargo_vcs_info.json 1970-01-01 00:00:00.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/.cargo_vcs_info.json 1970-01-01 00:00:01.000000000 +0000 @@ -0,0 +1,5 @@ +{ + "git": { + "sha1": "e104d1695a89de8c8050b7abaedf5ea9330f3cd8" + } +} diff -Nru rust-wasm-bindgen-webidl-0.2.58/debian/cargo-checksum.json rust-wasm-bindgen-webidl-0.2.75/debian/cargo-checksum.json --- rust-wasm-bindgen-webidl-0.2.58/debian/cargo-checksum.json 2020-01-08 14:08:03.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/debian/cargo-checksum.json 2022-01-08 14:50:00.000000000 +0000 @@ -1 +1 @@ -{"package":"ef012a0d93fc0432df126a8eaf547b2dce25a8ce9212e1d3cbeef5c11157975d","files":{}} +{"package":"Could not get crate checksum","files":{}} diff -Nru rust-wasm-bindgen-webidl-0.2.58/debian/changelog rust-wasm-bindgen-webidl-0.2.75/debian/changelog --- rust-wasm-bindgen-webidl-0.2.58/debian/changelog 2020-01-08 14:08:03.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/debian/changelog 2022-01-08 14:50:00.000000000 +0000 @@ -1,3 +1,12 @@ +rust-wasm-bindgen-webidl (0.2.75-1) unstable; urgency=medium + + * Team upload. + * Package wasm-bindgen-webidl 0.2.75 from crates.io using debcargo 2.5.0 + * Relax dependencies on wasm-bindgen-backend and env-logger. + * Disable build of binary to avoid trip through NEW. + + -- Peter Michael Green Sat, 08 Jan 2022 14:50:00 +0000 + rust-wasm-bindgen-webidl (0.2.58-1) unstable; urgency=medium * Package wasm-bindgen-webidl 0.2.58 from crates.io using debcargo 2.4.0 diff -Nru rust-wasm-bindgen-webidl-0.2.58/debian/compat rust-wasm-bindgen-webidl-0.2.75/debian/compat --- rust-wasm-bindgen-webidl-0.2.58/debian/compat 2020-01-08 14:08:03.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/debian/compat 2022-01-08 14:50:00.000000000 +0000 @@ -1 +1 @@ -11 +12 diff -Nru rust-wasm-bindgen-webidl-0.2.58/debian/control rust-wasm-bindgen-webidl-0.2.75/debian/control --- rust-wasm-bindgen-webidl-0.2.58/debian/control 2020-01-08 14:08:03.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/debian/control 2022-01-08 14:50:00.000000000 +0000 @@ -1,29 +1,34 @@ Source: rust-wasm-bindgen-webidl Section: rust Priority: optional -Build-Depends: debhelper (>= 11), - dh-cargo (>= 18), +Build-Depends: debhelper (>= 12), + dh-cargo (>= 25), cargo:native , rustc:native , libstd-rust-dev , librust-anyhow-1+default-dev , + librust-env-logger-0.9+default-dev | librust-env-logger-0.8+default-dev (>= 0.8.1-~~) , librust-heck-0.3+default-dev , + librust-lazy-static-1+default-dev (>= 1.0.2-~~) , librust-log-0.4+default-dev (>= 0.4.1-~~) , librust-proc-macro2-1+default-dev , librust-quote-1+default-dev , + librust-sourcefile-0.1+default-dev , + librust-structopt-0.3+default-dev (>= 0.3.9-~~) , librust-syn-1+default-dev , librust-syn-1+full-dev , - librust-wasm-bindgen-backend-0.2.58+default-dev , - librust-weedle-0.10+default-dev + librust-wasm-bindgen-backend-0.2.78+default-dev | librust-wasm-bindgen-backend-0.2.77+default-dev | librust-wasm-bindgen-backend-0.2.76+default-dev | librust-wasm-bindgen-backend-0.2.75+default-dev , + librust-weedle-0.12+default-dev Maintainer: Debian Rust Maintainers Uploaders: kpcyrd , - Nicolas Braud-Santoni , + nicoo , Wolfgang Silbermayr -Standards-Version: 4.2.0 +Standards-Version: 4.5.1 Vcs-Git: https://salsa.debian.org/rust-team/debcargo-conf.git [src/wasm-bindgen-webidl] Vcs-Browser: https://salsa.debian.org/rust-team/debcargo-conf/tree/master/src/wasm-bindgen-webidl Homepage: https://rustwasm.github.io/wasm-bindgen/ +Rules-Requires-Root: no Package: librust-wasm-bindgen-webidl-dev Architecture: any @@ -31,22 +36,26 @@ Depends: ${misc:Depends}, librust-anyhow-1+default-dev, + librust-env-logger-0.9+default-dev | librust-env-logger-0.8+default-dev (>= 0.8.1-~~), librust-heck-0.3+default-dev, + librust-lazy-static-1+default-dev (>= 1.0.2-~~), librust-log-0.4+default-dev (>= 0.4.1-~~), librust-proc-macro2-1+default-dev, librust-quote-1+default-dev, + librust-sourcefile-0.1+default-dev, + librust-structopt-0.3+default-dev (>= 0.3.9-~~), librust-syn-1+default-dev, librust-syn-1+full-dev, - librust-wasm-bindgen-backend-0.2.58+default-dev, - librust-weedle-0.10+default-dev + librust-wasm-bindgen-backend-0.2.78+default-dev | librust-wasm-bindgen-backend-0.2.77+default-dev | librust-wasm-bindgen-backend-0.2.76+default-dev | librust-wasm-bindgen-backend-0.2.75+default-dev, + librust-weedle-0.12+default-dev Provides: librust-wasm-bindgen-webidl+default-dev (= ${binary:Version}), librust-wasm-bindgen-webidl-0-dev (= ${binary:Version}), librust-wasm-bindgen-webidl-0+default-dev (= ${binary:Version}), librust-wasm-bindgen-webidl-0.2-dev (= ${binary:Version}), librust-wasm-bindgen-webidl-0.2+default-dev (= ${binary:Version}), - librust-wasm-bindgen-webidl-0.2.58-dev (= ${binary:Version}), - librust-wasm-bindgen-webidl-0.2.58+default-dev (= ${binary:Version}) + librust-wasm-bindgen-webidl-0.2.75-dev (= ${binary:Version}), + librust-wasm-bindgen-webidl-0.2.75+default-dev (= ${binary:Version}) Description: Support for parsing WebIDL specific to wasm-bindgen - Rust source code This package contains the source for the Rust wasm-bindgen-webidl crate, packaged by debcargo for use with cargo and dh-cargo. diff -Nru rust-wasm-bindgen-webidl-0.2.58/debian/copyright rust-wasm-bindgen-webidl-0.2.75/debian/copyright --- rust-wasm-bindgen-webidl-0.2.58/debian/copyright 2020-01-08 14:08:03.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/debian/copyright 2022-01-08 14:50:00.000000000 +0000 @@ -4,14 +4,14 @@ Source: https://github.com/rustwasm/wasm-bindgen/tree/master/crates/webidl Files: * -Copyright: 2018-2019 The wasm-bindgen Developers +Copyright: 2018-2021 The wasm-bindgen Developers License: MIT or Apache-2.0 Files: debian/* Copyright: - 2019-2020 Debian Rust Maintainers + 2019-2022 Debian Rust Maintainers 2019-2020 kpcyrd - 2019-2020 Nicolas Braud-Santoni + 2019-2020 nicoo 2019-2020 Wolfgang Silbermayr License: MIT or Apache-2.0 diff -Nru rust-wasm-bindgen-webidl-0.2.58/debian/copyright.debcargo.hint rust-wasm-bindgen-webidl-0.2.75/debian/copyright.debcargo.hint --- rust-wasm-bindgen-webidl-0.2.58/debian/copyright.debcargo.hint 2020-01-08 14:08:03.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/debian/copyright.debcargo.hint 2022-01-08 14:50:00.000000000 +0000 @@ -12,12 +12,19 @@ be correct information so you should review and fix this before uploading to the archive. +Files: ./LICENSE-MIT +Copyright: 2014 Alex Crichton +License: UNKNOWN-LICENSE; FIXME (overlay) +Comment: + FIXME (overlay): These notices are extracted from files. Please review them + before uploading to the archive. + Files: debian/* Copyright: - 2019-2020 Debian Rust Maintainers - 2019-2020 kpcyrd - 2019-2020 Nicolas Braud-Santoni - 2019-2020 Wolfgang Silbermayr + 2019-2022 Debian Rust Maintainers + 2019-2022 kpcyrd + 2019-2022 nicoo + 2019-2022 Wolfgang Silbermayr License: MIT or Apache-2.0 License: Apache-2.0 diff -Nru rust-wasm-bindgen-webidl-0.2.58/debian/debcargo.toml rust-wasm-bindgen-webidl-0.2.75/debian/debcargo.toml --- rust-wasm-bindgen-webidl-0.2.58/debian/debcargo.toml 2020-01-08 14:08:03.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/debian/debcargo.toml 2022-01-08 14:50:00.000000000 +0000 @@ -1,6 +1,7 @@ overlay = "." uploaders = [ "kpcyrd ", - "Nicolas Braud-Santoni ", + "nicoo ", "Wolfgang Silbermayr " ] +bin = false diff -Nru rust-wasm-bindgen-webidl-0.2.58/debian/patches/relax-dep.diff rust-wasm-bindgen-webidl-0.2.75/debian/patches/relax-dep.diff --- rust-wasm-bindgen-webidl-0.2.58/debian/patches/relax-dep.diff 1970-01-01 00:00:00.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/debian/patches/relax-dep.diff 2022-01-08 14:50:00.000000000 +0000 @@ -0,0 +1,22 @@ +Index: wasm-bindgen-webidl/Cargo.toml +=================================================================== +--- wasm-bindgen-webidl.orig/Cargo.toml ++++ wasm-bindgen-webidl/Cargo.toml +@@ -25,7 +25,7 @@ repository = "https://github.com/rustwas + version = "1.0" + + [dependencies.env_logger] +-version = "0.8.1" ++version = ">= 0.8.1, < 0.10" + + [dependencies.heck] + version = "0.3" +@@ -53,7 +53,7 @@ version = "1.0" + features = ["full"] + + [dependencies.wasm-bindgen-backend] +-version = "=0.2.75" ++version = ">= 0.2.75, < 0.2.79" + + [dependencies.weedle] + version = "0.12" diff -Nru rust-wasm-bindgen-webidl-0.2.58/debian/patches/series rust-wasm-bindgen-webidl-0.2.75/debian/patches/series --- rust-wasm-bindgen-webidl-0.2.58/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/debian/patches/series 2022-01-08 14:50:00.000000000 +0000 @@ -0,0 +1 @@ +relax-dep.diff diff -Nru rust-wasm-bindgen-webidl-0.2.58/debian/tests/control rust-wasm-bindgen-webidl-0.2.75/debian/tests/control --- rust-wasm-bindgen-webidl-0.2.58/debian/tests/control 2020-01-08 14:08:03.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/debian/tests/control 2022-01-08 14:50:00.000000000 +0000 @@ -1,7 +1,14 @@ -Test-Command: /usr/share/cargo/bin/cargo-auto-test wasm-bindgen-webidl 0.2.58 --all-targets --all-features +Test-Command: /usr/share/cargo/bin/cargo-auto-test wasm-bindgen-webidl 0.2.75 --all-targets --all-features +Features: test-name=rust-wasm-bindgen-webidl:@ Depends: dh-cargo (>= 18), @ Restrictions: allow-stderr, skip-not-installable -Test-Command: /usr/share/cargo/bin/cargo-auto-test wasm-bindgen-webidl 0.2.58 --all-targets --no-default-features -Depends: dh-cargo (>= 18), librust-wasm-bindgen-webidl-dev +Test-Command: /usr/share/cargo/bin/cargo-auto-test wasm-bindgen-webidl 0.2.75 --all-targets +Features: test-name=librust-wasm-bindgen-webidl-dev:default +Depends: dh-cargo (>= 18), @ +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test wasm-bindgen-webidl 0.2.75 --all-targets --no-default-features +Features: test-name=librust-wasm-bindgen-webidl-dev: +Depends: dh-cargo (>= 18), @ Restrictions: allow-stderr, skip-not-installable diff -Nru rust-wasm-bindgen-webidl-0.2.58/debian/watch rust-wasm-bindgen-webidl-0.2.75/debian/watch --- rust-wasm-bindgen-webidl-0.2.58/debian/watch 2020-01-08 14:08:03.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/debian/watch 2022-01-08 14:50:00.000000000 +0000 @@ -2,4 +2,3 @@ opts=filenamemangle=s/.*\/(.*)\/download/wasm-bindgen-webidl-$1\.tar\.gz/g,\ uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/ \ https://qa.debian.org/cgi-bin/fakeupstream.cgi?upstream=crates.io/wasm-bindgen-webidl .*/crates/wasm-bindgen-webidl/@ANY_VERSION@/download - diff -Nru rust-wasm-bindgen-webidl-0.2.58/LICENSE-APACHE rust-wasm-bindgen-webidl-0.2.75/LICENSE-APACHE --- rust-wasm-bindgen-webidl-0.2.58/LICENSE-APACHE 1970-01-01 00:00:00.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/LICENSE-APACHE 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff -Nru rust-wasm-bindgen-webidl-0.2.58/LICENSE-MIT rust-wasm-bindgen-webidl-0.2.75/LICENSE-MIT --- rust-wasm-bindgen-webidl-0.2.58/LICENSE-MIT 1970-01-01 00:00:00.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/LICENSE-MIT 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff -Nru rust-wasm-bindgen-webidl-0.2.58/src/constants.rs rust-wasm-bindgen-webidl-0.2.75/src/constants.rs --- rust-wasm-bindgen-webidl-0.2.58/src/constants.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/src/constants.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,95 @@ +use lazy_static::lazy_static; +use std::collections::BTreeSet; +use std::iter::FromIterator; + +lazy_static! { + pub(crate) static ref BUILTIN_IDENTS: BTreeSet<&'static str> = BTreeSet::from_iter(vec![ + "str", + "char", + "bool", + "JsValue", + "u8", + "i8", + "u16", + "i16", + "u32", + "i32", + "u64", + "i64", + "usize", + "isize", + "f32", + "f64", + "Result", + "String", + "Vec", + "Option", + "Array", + "ArrayBuffer", + "Object", + "Promise", + "Function", + "Clamped", + "DataView", + ]); + + + // whitelist a few names that have known polyfills + pub(crate) static ref POLYFILL_INTERFACES: BTreeSet<&'static str> = BTreeSet::from_iter(vec![ + "AudioContext", + "OfflineAudioContext", + ]); + + + pub(crate) static ref IMMUTABLE_SLICE_WHITELIST: BTreeSet<&'static str> = BTreeSet::from_iter(vec![ + // ImageData + "ImageData", + // WebGlRenderingContext, WebGl2RenderingContext + "uniform1fv", + "uniform2fv", + "uniform3fv", + "uniform4fv", + "uniform1iv", + "uniform2iv", + "uniform3iv", + "uniform4iv", + "uniformMatrix2fv", + "uniformMatrix3fv", + "uniformMatrix4fv", + "uniformMatrix2x3fv", + "uniformMatrix2x4fv", + "uniformMatrix3x2fv", + "uniformMatrix3x4fv", + "uniformMatrix4x2fv", + "uniformMatrix4x3fv", + "vertexAttrib1fv", + "vertexAttrib2fv", + "vertexAttrib3fv", + "vertexAttrib4fv", + "bufferData", + "bufferSubData", + "texImage2D", + "texSubImage2D", + "compressedTexImage2D", + // WebGl2RenderingContext + "uniform1uiv", + "uniform2uiv", + "uniform3uiv", + "uniform4uiv", + "texImage3D", + "texSubImage3D", + "compressedTexImage3D", + "clearBufferfv", + "clearBufferiv", + "clearBufferuiv", + // WebSocket + "send", + // WebGPU + "setBindGroup", + "writeBuffer", + "writeTexture", + // AudioBuffer + "copyToChannel" + // TODO: Add another type's functions here. Leave a comment header with the type name + ]); +} diff -Nru rust-wasm-bindgen-webidl-0.2.58/src/first_pass.rs rust-wasm-bindgen-webidl-0.2.75/src/first_pass.rs --- rust-wasm-bindgen-webidl-0.2.58/src/first_pass.rs 2019-06-05 21:58:54.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/src/first_pass.rs 1973-11-29 21:33:09.000000000 +0000 @@ -10,7 +10,6 @@ use std::cmp::Ordering; use std::collections::{BTreeMap, BTreeSet}; -use proc_macro2::Ident; use weedle; use weedle::argument::Argument; use weedle::attribute::*; @@ -20,15 +19,16 @@ 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, 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>>, @@ -37,7 +37,11 @@ pub(crate) dictionaries: BTreeMap<&'src str, DictionaryData<'src>>, pub(crate) callbacks: BTreeSet<&'src str>, pub(crate) callback_interfaces: BTreeMap<&'src str, CallbackInterfaceData<'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. @@ -47,11 +51,17 @@ pub(crate) partial: bool, pub(crate) has_interface: bool, pub(crate) deprecated: Option, - pub(crate) attributes: Vec<&'src AttributeInterfaceMember<'src>>, + pub(crate) attributes: Vec>, pub(crate) consts: Vec<&'src ConstMember<'src>>, pub(crate) operations: BTreeMap, 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 MixinData<'src> { /// Whether only partial mixins were encountered pub(crate) partial: bool, - pub(crate) attributes: Vec<&'src AttributeMixinMember<'src>>, + pub(crate) attributes: Vec>, pub(crate) consts: Vec<&'src ConstMember<'src>>, pub(crate) operations: BTreeMap, 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 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> { @@ -84,7 +101,11 @@ #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] pub(crate) enum OperationId<'src> { - Constructor(IgnoreTraits<&'src str>), + /// The name of a constructor in crates/web-sys/webidls/enabled/*.webidl + /// + /// ex: Constructor(Some("ImageData")) + Constructor(Option<&'src str>), + NamedConstructor(IgnoreTraits<&'src str>), /// The name of a function in crates/web-sys/webidls/enabled/*.webidl /// /// ex: Operation(Some("vertexAttrib1fv")) @@ -121,29 +142,37 @@ 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 +183,21 @@ } } -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 - .dictionaries - .entry(self.identifier.0) - .or_default() - .definition = Some(self); + let dictionary_data = record.dictionaries.entry(self.identifier.0).or_default(); + + dictionary_data.definition = Some(self); + dictionary_data.stability = stability; + Ok(()) } } @@ -181,17 +214,27 @@ .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 +341,12 @@ } } -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 +358,7 @@ 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 +366,7 @@ } for member in &self.members.body { - member.first_pass(record, self.identifier.0)?; + member.first_pass(record, (self.identifier.0, stability))?; } Ok(()) @@ -345,7 +393,7 @@ record, FirstPassOperationType::Interface, self_name, - &[OperationId::Constructor(IgnoreTraits(self_name))], + &[OperationId::Constructor(Some(self_name))], &list.args.body.list, &return_ty, &None, @@ -357,7 +405,7 @@ record, FirstPassOperationType::Interface, self_name, - &[OperationId::Constructor(IgnoreTraits(self_name))], + &[OperationId::Constructor(Some(self_name))], &[], &return_ty, &None, @@ -369,7 +417,7 @@ record, FirstPassOperationType::Interface, self_name, - &[OperationId::Constructor(IgnoreTraits( + &[OperationId::NamedConstructor(IgnoreTraits( list.rhs_identifier.0, ))], &list.args.body.list, @@ -382,8 +430,12 @@ } } -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,36 +444,45 @@ .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_); Ok(()) } + InterfaceMember::Constructor(_) => { + log::warn!( + "Unsupported WebIDL Constructor interface member: {:?}", + self + ); + Ok(()) + } InterfaceMember::Iterable(_iterable) => { log::warn!("Unsupported WebIDL iterable interface member: {:?}", self); Ok(()) @@ -442,6 +503,13 @@ log::warn!("Unsupported WebIDL Setlike interface member: {:?}", self); Ok(()) } + InterfaceMember::AsyncIterable(_iterable) => { + log::warn!( + "Unsupported WebIDL async iterable interface member: {:?}", + self + ); + Ok(()) + } } } } @@ -484,11 +552,13 @@ } } -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 +566,23 @@ 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 +591,23 @@ 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 +617,32 @@ .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 +653,13 @@ } } -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 +669,7 @@ 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 +680,26 @@ } } -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(()) } } diff -Nru rust-wasm-bindgen-webidl-0.2.58/src/generator.rs rust-wasm-bindgen-webidl-0.2.75/src/generator.rs --- rust-wasm-bindgen-webidl-0.2.58/src/generator.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/src/generator.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,915 @@ +use proc_macro2::Literal; +use proc_macro2::TokenStream; +use quote::quote; +use std::collections::BTreeSet; +use syn::{Ident, Type}; +use wasm_bindgen_backend::util::{raw_ident, rust_ident}; + +use crate::constants::{BUILTIN_IDENTS, POLYFILL_INTERFACES}; +use crate::traverse::TraverseType; +use crate::util::{get_cfg_features, mdn_doc, required_doc_string, snake_case_ident}; +use crate::Options; + +fn add_features(features: &mut BTreeSet, ty: &impl TraverseType) { + ty.traverse_type(&mut |ident| { + let ident = ident.to_string(); + + if !BUILTIN_IDENTS.contains(ident.as_str()) { + features.insert(ident); + } + }); +} + +fn get_features_doc(options: &Options, name: String) -> Option { + let mut features = BTreeSet::new(); + features.insert(name); + required_doc_string(options, &features) +} + +fn comment(mut comment: String, features: &Option) -> TokenStream { + if let Some(s) = features { + comment.push_str(s); + } + + let lines = comment.lines().map(|doc| quote!( #[doc = #doc] )); + + quote! { + #(#lines)* + } +} + +fn maybe_unstable_attr(unstable: bool) -> Option { + if unstable { + Some(quote! { + #[cfg(web_sys_unstable_apis)] + }) + } else { + None + } +} + +fn maybe_unstable_docs(unstable: bool) -> Option { + if unstable { + Some(quote! { + #[doc = ""] + #[doc = "*This API is unstable and requires `--cfg=web_sys_unstable_apis` to be activated, as"] + #[doc = "[described in the `wasm-bindgen` guide](https://rustwasm.github.io/docs/wasm-bindgen/web-sys/unstable-apis.html)*"] + }) + } else { + None + } +} + +fn generate_arguments(arguments: &[(Ident, Type)], variadic: bool) -> Vec { + arguments + .into_iter() + .enumerate() + .map(|(i, (name, ty))| { + if variadic && i + 1 == arguments.len() { + quote!( #name: &::js_sys::Array ) + } else { + quote!( #name: #ty ) + } + }) + .collect::>() +} + +fn generate_variadic(variadic: bool) -> Option { + if variadic { + Some(quote!(variadic,)) + } else { + None + } +} + +pub struct EnumVariant { + pub name: Ident, + pub value: String, +} + +impl EnumVariant { + fn generate(&self) -> TokenStream { + let EnumVariant { name, value } = self; + + quote!( #name = #value ) + } +} + +pub struct Enum { + pub name: Ident, + pub variants: Vec, + pub unstable: bool, +} + +impl Enum { + pub fn generate(&self, options: &Options) -> TokenStream { + let Enum { + name, + variants, + unstable, + } = self; + + let unstable_attr = maybe_unstable_attr(*unstable); + let unstable_docs = maybe_unstable_docs(*unstable); + + let doc_comment = comment( + format!("The `{}` enum.", name), + &get_features_doc(options, name.to_string()), + ); + + let variants = variants + .into_iter() + .map(|variant| variant.generate()) + .collect::>(); + + quote! { + #![allow(unused_imports)] + use wasm_bindgen::prelude::*; + + #unstable_attr + #[wasm_bindgen] + #doc_comment + #unstable_docs + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + pub enum #name { + #(#variants),* + } + } + } +} + +pub enum InterfaceAttributeKind { + Getter, + Setter, +} + +pub struct InterfaceAttribute { + pub js_name: String, + pub ty: Type, + pub is_static: bool, + pub structural: bool, + pub catch: bool, + pub kind: InterfaceAttributeKind, + pub unstable: bool, +} + +impl InterfaceAttribute { + fn generate( + &self, + options: &Options, + parent_name: &Ident, + parent_js_name: &str, + parents: &[Ident], + ) -> TokenStream { + let InterfaceAttribute { + js_name, + ty, + is_static, + structural, + catch, + kind, + unstable, + } = self; + + let unstable_attr = maybe_unstable_attr(*unstable); + let unstable_docs = maybe_unstable_docs(*unstable); + + let mdn_docs = mdn_doc(parent_js_name, Some(js_name)); + + let mut features = BTreeSet::new(); + + add_features(&mut features, ty); + + for parent in parents { + features.remove(&parent.to_string()); + } + + features.remove(&parent_name.to_string()); + + let cfg_features = get_cfg_features(options, &features); + + features.insert(parent_name.to_string()); + + let doc_comment = required_doc_string(options, &features); + + let structural = if *structural { + quote!(structural,) + } else { + quote!(final,) + }; + + let (method, this) = if *is_static { + (quote!( static_method_of = #parent_name, ), None) + } else { + (quote!(method,), Some(quote!( this: &#parent_name, ))) + }; + + let (prefix, attr, def) = match kind { + InterfaceAttributeKind::Getter => { + let name = rust_ident(&snake_case_ident(js_name)); + + let ty = if *catch { + quote!( Result<#ty, JsValue> ) + } else { + quote!( #ty ) + }; + + ( + "Getter", + quote!(getter,), + quote!( pub fn #name(#this) -> #ty; ), + ) + } + + InterfaceAttributeKind::Setter => { + let name = rust_ident(&format!("set_{}", snake_case_ident(js_name))); + + let ret_ty = if *catch { + Some(quote!( -> Result<(), JsValue> )) + } else { + None + }; + + ( + "Setter", + quote!(setter,), + quote!( pub fn #name(#this value: #ty) #ret_ty; ), + ) + } + }; + + let catch = if *catch { Some(quote!(catch,)) } else { None }; + + let doc_comment = comment( + format!( + "{} for the `{}` field of this object.\n\n{}", + prefix, js_name, mdn_docs + ), + &doc_comment, + ); + + let js_name = raw_ident(js_name); + + quote! { + #unstable_attr + #cfg_features + #[wasm_bindgen( + #structural + #catch + #method + #attr + js_class = #parent_js_name, + js_name = #js_name + )] + #doc_comment + #unstable_docs + #def + } + } +} + +#[derive(Debug, Clone)] +pub enum InterfaceMethodKind { + Constructor(Option), + Regular, + IndexingGetter, + IndexingSetter, + IndexingDeleter, +} + +pub struct InterfaceMethod { + pub name: Ident, + pub js_name: String, + pub arguments: Vec<(Ident, Type)>, + pub ret_ty: Option, + pub kind: InterfaceMethodKind, + pub is_static: bool, + pub structural: bool, + pub catch: bool, + pub variadic: bool, + pub unstable: bool, +} + +impl InterfaceMethod { + fn generate( + &self, + options: &Options, + parent_name: &Ident, + parent_js_name: String, + parents: &[Ident], + ) -> TokenStream { + let InterfaceMethod { + name, + js_name, + arguments, + ret_ty, + kind, + is_static, + structural, + catch, + variadic, + unstable, + } = self; + + let unstable_attr = maybe_unstable_attr(*unstable); + let unstable_docs = maybe_unstable_docs(*unstable); + + let mut is_constructor = false; + + let mut extra_args = vec![quote!( js_class = #parent_js_name )]; + + let doc_comment = match kind { + InterfaceMethodKind::Constructor(name) => { + is_constructor = true; + if let Some(name) = name { + extra_args[0] = quote!( js_class = #name ); + } + format!( + "The `new {}(..)` constructor, creating a new \ + instance of `{0}`.\n\n{}", + parent_name, + mdn_doc(&parent_js_name, Some(&parent_js_name)) + ) + } + InterfaceMethodKind::Regular => { + { + let js_name = raw_ident(js_name); + extra_args.push(quote!( js_name = #js_name )); + } + format!( + "The `{}()` method.\n\n{}", + js_name, + mdn_doc(&parent_js_name, Some(js_name)) + ) + } + InterfaceMethodKind::IndexingGetter => { + extra_args.push(quote!(indexing_getter)); + format!("Indexing getter.\n\n") + } + InterfaceMethodKind::IndexingSetter => { + extra_args.push(quote!(indexing_setter)); + format!("Indexing setter.\n\n") + } + InterfaceMethodKind::IndexingDeleter => { + extra_args.push(quote!(indexing_deleter)); + format!("Indexing deleter.\n\n") + } + }; + + let mut features = BTreeSet::new(); + + for (_, ty) in arguments.iter() { + add_features(&mut features, ty); + } + + if let Some(ty) = ret_ty { + add_features(&mut features, ty); + } + + for parent in parents { + features.remove(&parent.to_string()); + } + + features.remove(&parent_name.to_string()); + + let cfg_features = get_cfg_features(options, &features); + + features.insert(parent_name.to_string()); + + let doc_comment = comment(doc_comment, &required_doc_string(options, &features)); + + let ret = ret_ty.as_ref().map(|ret| quote!( #ret )); + + let ret = if *catch { + let ret = ret.unwrap_or_else(|| quote!(())); + Some(quote!( Result<#ret, JsValue> )) + } else { + ret + }; + + let ret = ret.as_ref().map(|ret| quote!( -> #ret )); + + let catch = if *catch { Some(quote!(catch,)) } else { None }; + + let (method, this) = if is_constructor { + assert!(!is_static); + + (quote!(constructor,), None) + } else if *is_static { + (quote!( static_method_of = #parent_name, ), None) + } else { + let structural = if *structural { + quote!(structural) + } else { + quote!(final) + }; + + ( + quote!( method, #structural, ), + Some(quote!( this: &#parent_name, )), + ) + }; + + let arguments = generate_arguments(arguments, *variadic); + let variadic = generate_variadic(*variadic); + + quote! { + #unstable_attr + #cfg_features + #[wasm_bindgen( + #catch + #method + #variadic + #(#extra_args),* + )] + #doc_comment + #unstable_docs + pub fn #name(#this #(#arguments),*) #ret; + } + } +} + +pub enum InterfaceConstValue { + BooleanLiteral(bool), + FloatLiteral(f64), + SignedIntegerLiteral(i64), + UnsignedIntegerLiteral(u64), +} + +impl InterfaceConstValue { + fn generate(&self) -> TokenStream { + use InterfaceConstValue::*; + + match self { + BooleanLiteral(false) => quote!(false), + BooleanLiteral(true) => quote!(true), + // the actual type is unknown because of typedefs + // so we cannot use std::fxx::INFINITY + // but we can use type inference + FloatLiteral(f) if f.is_infinite() && f.is_sign_positive() => quote!(1.0 / 0.0), + FloatLiteral(f) if f.is_infinite() && f.is_sign_negative() => quote!(-1.0 / 0.0), + FloatLiteral(f) if f.is_nan() => quote!(0.0 / 0.0), + // again no suffix + // panics on +-inf, nan + FloatLiteral(f) => { + let f = Literal::f64_suffixed(*f); + quote!(#f) + } + SignedIntegerLiteral(i) => { + let i = Literal::i64_suffixed(*i); + quote!(#i) + } + UnsignedIntegerLiteral(i) => { + let i = Literal::u64_suffixed(*i); + quote!(#i) + } + } + } +} + +pub struct InterfaceConst { + pub name: Ident, + pub js_name: String, + pub ty: syn::Type, + pub value: InterfaceConstValue, + pub unstable: bool, +} + +impl InterfaceConst { + fn generate( + &self, + options: &Options, + parent_name: &Ident, + parent_js_name: &str, + ) -> TokenStream { + let name = &self.name; + let ty = &self.ty; + let js_name = &self.js_name; + let value = self.value.generate(); + let unstable = self.unstable; + + let unstable_attr = maybe_unstable_attr(unstable); + let unstable_docs = maybe_unstable_docs(unstable); + + let doc_comment = comment( + format!("The `{}.{}` const.", parent_js_name, js_name), + &get_features_doc(options, parent_name.to_string()), + ); + + quote! { + #unstable_attr + #doc_comment + #unstable_docs + pub const #name: #ty = #value as #ty; + } + } +} + +pub struct Interface { + pub name: Ident, + pub js_name: String, + pub deprecated: Option, + pub has_interface: bool, + pub parents: Vec, + pub consts: Vec, + pub attributes: Vec, + pub methods: Vec, + pub unstable: bool, +} + +impl Interface { + pub fn generate(&self, options: &Options) -> TokenStream { + let Interface { + name, + js_name, + deprecated, + has_interface, + parents, + consts, + attributes, + methods, + unstable, + } = self; + + let unstable_attr = maybe_unstable_attr(*unstable); + let unstable_docs = maybe_unstable_docs(*unstable); + + let doc_comment = comment( + format!("The `{}` class.\n\n{}", name, mdn_doc(js_name, None)), + &get_features_doc(options, name.to_string()), + ); + + let deprecated = deprecated + .as_ref() + .map(|msg| quote!( #[deprecated(note = #msg)] )); + + let is_type_of = if *has_interface { + None + } else { + Some(quote!(is_type_of = |_| false,)) + }; + + let prefixes = if POLYFILL_INTERFACES.contains(js_name.as_str()) { + Some(quote!(vendor_prefix = webkit,)) + } else { + None + }; + + let extends = parents + .into_iter() + .map(|x| quote!( extends = #x, )) + .collect::>(); + + let consts = consts + .into_iter() + .map(|x| x.generate(options, &name, js_name)) + .collect::>(); + + let consts = if consts.is_empty() { + None + } else { + Some(quote! { + #unstable_attr + impl #name { + #(#deprecated #consts)* + } + }) + }; + + let attributes = attributes + .into_iter() + .map(|x| x.generate(options, &name, js_name, &parents)) + .collect::>(); + + let methods = methods + .into_iter() + .map(|x| x.generate(options, &name, js_name.to_string(), &parents)) + .collect::>(); + + let js_ident = raw_ident(js_name); + + quote! { + #![allow(unused_imports)] + use super::*; + use wasm_bindgen::prelude::*; + + #unstable_attr + #[wasm_bindgen] + extern "C" { + #[wasm_bindgen( + #is_type_of + #prefixes + #(#extends)* + extends = ::js_sys::Object, + js_name = #js_ident, + typescript_type = #js_name + )] + #[derive(Debug, Clone, PartialEq, Eq)] + #doc_comment + #unstable_docs + #deprecated + pub type #name; + + #(#deprecated #attributes)* + #(#deprecated #methods)* + } + + #consts + } + } +} + +pub struct DictionaryField { + pub name: Ident, + pub js_name: String, + pub ty: Type, + pub required: bool, + pub unstable: bool, +} + +impl DictionaryField { + fn generate_rust(&self, options: &Options, parent_name: String) -> TokenStream { + let DictionaryField { + name, + js_name, + ty, + required: _, + unstable, + } = self; + + let unstable_attr = maybe_unstable_attr(*unstable); + let unstable_docs = maybe_unstable_docs(*unstable); + + let mut features = BTreeSet::new(); + + add_features(&mut features, ty); + + features.remove(&parent_name); + + let cfg_features = get_cfg_features(options, &features); + + features.insert(parent_name); + + let doc_comment = comment( + format!("Change the `{}` field of this object.", js_name), + &required_doc_string(options, &features), + ); + + quote! { + #unstable_attr + #cfg_features + #doc_comment + #unstable_docs + pub fn #name(&mut self, val: #ty) -> &mut Self { + use wasm_bindgen::JsValue; + let r = ::js_sys::Reflect::set( + self.as_ref(), + &JsValue::from(#js_name), + &JsValue::from(val), + ); + debug_assert!(r.is_ok(), "setting properties should never fail on our dictionary objects"); + let _ = r; + self + } + } + } +} + +pub struct Dictionary { + pub name: Ident, + pub js_name: String, + pub fields: Vec, + pub unstable: bool, +} + +impl Dictionary { + pub fn generate(&self, options: &Options) -> TokenStream { + let Dictionary { + name, + js_name, + fields, + unstable, + } = self; + + let unstable_attr = maybe_unstable_attr(*unstable); + let unstable_docs = maybe_unstable_docs(*unstable); + + let js_name = raw_ident(js_name); + + let mut required_features = BTreeSet::new(); + let mut required_args = vec![]; + let mut required_calls = vec![]; + + for field in fields.iter() { + if field.required { + let name = &field.name; + let ty = &field.ty; + required_args.push(quote!( #name: #ty )); + required_calls.push(quote!( ret.#name(#name); )); + add_features(&mut required_features, &field.ty); + } + } + + // The constructor is unstable if any of the fields are + let (unstable_ctor, unstable_ctor_docs) = match unstable { + true => (None, None), + false => { + let unstable = fields.iter().any(|f| f.unstable); + (maybe_unstable_attr(unstable), maybe_unstable_docs(unstable)) + } + }; + + required_features.remove(&name.to_string()); + + let cfg_features = get_cfg_features(options, &required_features); + + required_features.insert(name.to_string()); + + let doc_comment = comment( + format!("The `{}` dictionary.", name), + &get_features_doc(options, name.to_string()), + ); + let ctor_doc_comment = comment( + format!("Construct a new `{}`.", name), + &required_doc_string(options, &required_features), + ); + + let fields = fields + .into_iter() + .map(|field| field.generate_rust(options, name.to_string())) + .collect::>(); + + let mut base_stream = quote! { + #![allow(unused_imports)] + use super::*; + use wasm_bindgen::prelude::*; + + #unstable_attr + #[wasm_bindgen] + extern "C" { + #[wasm_bindgen(extends = ::js_sys::Object, js_name = #js_name)] + #[derive(Debug, Clone, PartialEq, Eq)] + #doc_comment + #unstable_docs + pub type #name; + } + + #unstable_attr + impl #name { + #unstable_ctor + #cfg_features + #ctor_doc_comment + #unstable_docs + #unstable_ctor_docs + pub fn new(#(#required_args),*) -> Self { + #[allow(unused_mut)] + let mut ret: Self = ::wasm_bindgen::JsCast::unchecked_into(::js_sys::Object::new()); + #(#required_calls)* + ret + } + + #(#fields)* + } + }; + + if required_args.is_empty() { + let default_impl = quote! { + #unstable_attr + impl Default for #name { + fn default() -> Self { + Self::new() + } + } + }; + + base_stream.extend(default_impl.into_iter()); + } + + base_stream + } +} + +pub struct Function { + pub name: Ident, + pub js_name: String, + pub arguments: Vec<(Ident, Type)>, + pub ret_ty: Option, + pub catch: bool, + pub variadic: bool, + pub unstable: bool, +} + +impl Function { + fn generate( + &self, + options: &Options, + parent_name: &Ident, + parent_js_name: String, + ) -> TokenStream { + let Function { + name, + js_name, + arguments, + ret_ty, + catch, + variadic, + unstable, + } = self; + + let unstable_attr = maybe_unstable_attr(*unstable); + let unstable_docs = maybe_unstable_docs(*unstable); + + let js_namespace = raw_ident(&parent_js_name); + + let doc_comment = format!( + "The `{}.{}()` function.\n\n{}", + parent_js_name, + js_name, + mdn_doc(&parent_js_name, Some(&js_name)) + ); + + let mut features = BTreeSet::new(); + + for (_, ty) in arguments.iter() { + add_features(&mut features, ty); + } + + if let Some(ty) = ret_ty { + add_features(&mut features, ty); + } + + features.remove(&parent_name.to_string()); + + let cfg_features = get_cfg_features(options, &features); + + features.insert(parent_name.to_string()); + + let doc_comment = comment(doc_comment, &required_doc_string(options, &features)); + + let ret = ret_ty.as_ref().map(|ret| quote!( #ret )); + + let ret = if *catch { + let ret = ret.unwrap_or_else(|| quote!(())); + Some(quote!( Result<#ret, JsValue> )) + } else { + ret + }; + + let ret = ret.as_ref().map(|ret| quote!( -> #ret )); + + let catch = if *catch { Some(quote!(catch,)) } else { None }; + + let arguments = generate_arguments(arguments, *variadic); + let variadic = generate_variadic(*variadic); + + let js_name = raw_ident(js_name); + + quote! { + #unstable_attr + #cfg_features + #[wasm_bindgen( + #catch + #variadic + js_namespace = #js_namespace, + js_name = #js_name + )] + #doc_comment + #unstable_docs + pub fn #name(#(#arguments),*) #ret; + } + } +} + +pub struct Namespace { + pub name: Ident, + pub js_name: String, + pub functions: Vec, +} + +impl Namespace { + pub fn generate(&self, options: &Options) -> TokenStream { + let Namespace { + name, + js_name, + functions, + } = self; + + let functions = functions + .into_iter() + .map(|x| x.generate(options, &name, js_name.to_string())) + .collect::>(); + + quote! { + pub mod #name { + #![allow(unused_imports)] + use super::super::*; + use wasm_bindgen::prelude::*; + + #[wasm_bindgen] + extern "C" { + #(#functions)* + } + } + } + } +} diff -Nru rust-wasm-bindgen-webidl-0.2.58/src/idl_type.rs rust-wasm-bindgen-webidl-0.2.75/src/idl_type.rs --- rust-wasm-bindgen-webidl-0.2.58/src/idl_type.rs 2019-08-13 19:12:38.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/src/idl_type.rs 1973-11-29 21:33:09.000000000 +0000 @@ -83,7 +83,7 @@ Union(Vec>), Any, - Void, + Undefined, UnknownInterface(&'a str), } @@ -298,7 +298,7 @@ impl<'a> ToIdlType<'a> for ReturnType<'a> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> { match self { - ReturnType::Void(t) => t.to_idl_type(record), + ReturnType::Undefined(t) => t.to_idl_type(record), ReturnType::Type(t) => t.to_idl_type(record), } } @@ -388,7 +388,7 @@ Object => Object Octet => Octet Short => Short - Void => Void + Undefined => Undefined ArrayBuffer => ArrayBuffer DataView => DataView Error => Error @@ -408,6 +408,11 @@ Uint8ClampedArray => Uint8ClampedArray } +#[derive(Debug, Clone)] +pub enum TypeError { + CannotConvert, +} + impl<'a> IdlType<'a> { /// Generates a snake case type name. pub(crate) fn push_snake_case_name(&self, dst: &mut String) { @@ -485,13 +490,13 @@ } IdlType::Any => dst.push_str("any"), - IdlType::Void => dst.push_str("void"), + IdlType::Undefined => dst.push_str("undefined"), } } /// Converts to syn type if possible. - pub(crate) fn to_syn_type(&self, pos: TypePosition) -> Option { - let anyref = |ty| { + pub(crate) fn to_syn_type(&self, pos: TypePosition) -> Result, TypeError> { + let externref = |ty| { Some(match pos { TypePosition::Argument => shared_ref(ty, false), TypePosition::Return => ty, @@ -500,20 +505,20 @@ let js_sys = |name: &str| { let path = vec![rust_ident("js_sys"), rust_ident(name)]; let ty = leading_colon_path_ty(path); - anyref(ty) + externref(ty) }; let js_value = { let path = vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")]; - anyref(leading_colon_path_ty(path)) + externref(leading_colon_path_ty(path)) }; match self { - IdlType::Boolean => Some(ident_ty(raw_ident("bool"))), - IdlType::Byte => Some(ident_ty(raw_ident("i8"))), - IdlType::Octet => Some(ident_ty(raw_ident("u8"))), - IdlType::Short => Some(ident_ty(raw_ident("i16"))), - IdlType::UnsignedShort => Some(ident_ty(raw_ident("u16"))), - IdlType::Long => Some(ident_ty(raw_ident("i32"))), - IdlType::UnsignedLong => Some(ident_ty(raw_ident("u32"))), + IdlType::Boolean => Ok(Some(ident_ty(raw_ident("bool")))), + IdlType::Byte => Ok(Some(ident_ty(raw_ident("i8")))), + IdlType::Octet => Ok(Some(ident_ty(raw_ident("u8")))), + IdlType::Short => Ok(Some(ident_ty(raw_ident("i16")))), + IdlType::UnsignedShort => Ok(Some(ident_ty(raw_ident("u16")))), + IdlType::Long => Ok(Some(ident_ty(raw_ident("i32")))), + IdlType::UnsignedLong => Ok(Some(ident_ty(raw_ident("u32")))), // Technically these are 64-bit numbers, but we're binding web // APIs that don't actually have return the corresponding 64-bit @@ -527,74 +532,81 @@ // // Perhaps one day we'll bind to u64/i64 here, but we need `BigInt` // to see more usage! - IdlType::LongLong | IdlType::UnsignedLongLong => Some(ident_ty(raw_ident("f64"))), + IdlType::LongLong | IdlType::UnsignedLongLong => Ok(Some(ident_ty(raw_ident("f64")))), - IdlType::Float => Some(ident_ty(raw_ident("f32"))), - IdlType::UnrestrictedFloat => Some(ident_ty(raw_ident("f32"))), - IdlType::Double => Some(ident_ty(raw_ident("f64"))), - IdlType::UnrestrictedDouble => Some(ident_ty(raw_ident("f64"))), + IdlType::Float => Ok(Some(ident_ty(raw_ident("f32")))), + IdlType::UnrestrictedFloat => Ok(Some(ident_ty(raw_ident("f32")))), + IdlType::Double => Ok(Some(ident_ty(raw_ident("f64")))), + IdlType::UnrestrictedDouble => Ok(Some(ident_ty(raw_ident("f64")))), IdlType::DomString | IdlType::ByteString | IdlType::UsvString => match pos { - TypePosition::Argument => Some(shared_ref(ident_ty(raw_ident("str")), false)), - TypePosition::Return => Some(ident_ty(raw_ident("String"))), + TypePosition::Argument => Ok(Some(shared_ref(ident_ty(raw_ident("str")), false))), + TypePosition::Return => Ok(Some(ident_ty(raw_ident("String")))), }, - IdlType::Object => js_sys("Object"), - IdlType::Symbol => None, - IdlType::Error => None, - - IdlType::ArrayBuffer => js_sys("ArrayBuffer"), - IdlType::DataView => None, - IdlType::Int8Array { immutable } => Some(array("i8", pos, *immutable)), - IdlType::Uint8Array { immutable } => Some(array("u8", pos, *immutable)), - IdlType::Uint8ClampedArray { immutable } => Some(clamped(array("u8", pos, *immutable))), - IdlType::Int16Array { immutable } => Some(array("i16", pos, *immutable)), - IdlType::Uint16Array { immutable } => Some(array("u16", pos, *immutable)), - IdlType::Int32Array { immutable } => Some(array("i32", pos, *immutable)), - IdlType::Uint32Array { immutable } => Some(array("u32", pos, *immutable)), - IdlType::Float32Array { immutable } => Some(array("f32", pos, *immutable)), - IdlType::Float64Array { immutable } => Some(array("f64", pos, *immutable)), + IdlType::Object => Ok(js_sys("Object")), + IdlType::Symbol => Err(TypeError::CannotConvert), + IdlType::Error => Err(TypeError::CannotConvert), + + IdlType::ArrayBuffer => Ok(js_sys("ArrayBuffer")), + IdlType::DataView => Ok(js_sys("DataView")), + IdlType::Int8Array { immutable } => Ok(Some(array("i8", pos, *immutable))), + IdlType::Uint8Array { immutable } => Ok(Some(array("u8", pos, *immutable))), + IdlType::Uint8ClampedArray { immutable } => { + Ok(Some(clamped(array("u8", pos, *immutable)))) + } + IdlType::Int16Array { immutable } => Ok(Some(array("i16", pos, *immutable))), + IdlType::Uint16Array { immutable } => Ok(Some(array("u16", pos, *immutable))), + IdlType::Int32Array { immutable } => Ok(Some(array("i32", pos, *immutable))), + IdlType::Uint32Array { immutable } => Ok(Some(array("u32", pos, *immutable))), + IdlType::Float32Array { immutable } => Ok(Some(array("f32", pos, *immutable))), + IdlType::Float64Array { immutable } => Ok(Some(array("f64", pos, *immutable))), - IdlType::ArrayBufferView { .. } | IdlType::BufferSource { .. } => js_sys("Object"), + IdlType::ArrayBufferView { .. } | IdlType::BufferSource { .. } => Ok(js_sys("Object")), IdlType::Interface(name) | IdlType::Dictionary(name) | IdlType::CallbackInterface { name, .. } => { let ty = ident_ty(rust_ident(camel_case_ident(name).as_str())); - anyref(ty) + Ok(externref(ty)) } - IdlType::Enum(name) => Some(ident_ty(rust_ident(camel_case_ident(name).as_str()))), + IdlType::Enum(name) => Ok(Some(ident_ty(rust_ident(camel_case_ident(name).as_str())))), IdlType::Nullable(idl_type) => { let inner = idl_type.to_syn_type(pos)?; - // TODO: this is a bit of a hack, but `Option` isn't - // supported right now. As a result if we see `JsValue` for our - // inner type, leave that as the same when we create a nullable - // version of that. That way `any?` just becomes `JsValue` and - // it's up to users to dispatch and/or create instances - // appropriately. - if let syn::Type::Path(path) = &inner { - if path.qself.is_none() - && path - .path - .segments - .last() - .map(|p| p.ident == "JsValue") - .unwrap_or(false) - { - return Some(inner.clone()); + match inner { + Some(inner) => { + // TODO: this is a bit of a hack, but `Option` isn't + // supported right now. As a result if we see `JsValue` for our + // inner type, leave that as the same when we create a nullable + // version of that. That way `any?` just becomes `JsValue` and + // it's up to users to dispatch and/or create instances + // appropriately. + if let syn::Type::Path(path) = &inner { + if path.qself.is_none() + && path + .path + .segments + .last() + .map(|p| p.ident == "JsValue") + .unwrap_or(false) + { + return Ok(Some(inner.clone())); + } + } + + Ok(Some(option_ty(inner))) } + None => Ok(None), } - - Some(option_ty(inner)) } - IdlType::FrozenArray(_idl_type) => None, // webidl sequences must always be returned as javascript `Array`s. They may accept // anything implementing the @@iterable interface. - IdlType::Sequence(_idl_type) => match pos { - TypePosition::Argument => js_value, - TypePosition::Return => js_sys("Array"), + // The same implementation is fine for `FrozenArray` + IdlType::FrozenArray(_idl_type) | IdlType::Sequence(_idl_type) => match pos { + TypePosition::Argument => Ok(js_value), + TypePosition::Return => Ok(js_sys("Array")), }, - IdlType::Promise(_idl_type) => js_sys("Promise"), - IdlType::Record(_idl_type_from, _idl_type_to) => None, + IdlType::Promise(_idl_type) => Ok(js_sys("Promise")), + IdlType::Record(_idl_type_from, _idl_type_to) => Err(TypeError::CannotConvert), IdlType::Union(idl_types) => { // Note that most union types have already been expanded to // their components via `flatten`. Unions in a return position @@ -629,10 +641,10 @@ } } - IdlType::Any => js_value, - IdlType::Void => None, - IdlType::Callback => js_sys("Function"), - IdlType::UnknownInterface(_) => None, + IdlType::Any => Ok(js_value), + IdlType::Undefined => Ok(None), + IdlType::Callback => Ok(js_sys("Function")), + IdlType::UnknownInterface(_) => Err(TypeError::CannotConvert), } } diff -Nru rust-wasm-bindgen-webidl-0.2.58/src/lib.rs rust-wasm-bindgen-webidl-0.2.75/src/lib.rs --- rust-wasm-bindgen-webidl-0.2.58/src/lib.rs 2019-12-02 17:11:50.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/src/lib.rs 1973-11-29 21:33:09.000000000 +0000 @@ -9,38 +9,64 @@ #![deny(missing_debug_implementations)] #![doc(html_root_url = "https://docs.rs/wasm-bindgen-webidl/0.2")] +mod constants; mod first_pass; +mod generator; mod idl_type; +mod traverse; mod util; use crate::first_pass::{CallbackInterfaceData, OperationData}; use crate::first_pass::{FirstPass, FirstPassRecord, InterfaceData, OperationId}; +use crate::generator::{ + Dictionary, DictionaryField, Enum, EnumVariant, Function, Interface, InterfaceAttribute, + InterfaceAttributeKind, InterfaceConst, InterfaceMethod, Namespace, +}; use crate::idl_type::ToIdlType; +use crate::traverse::TraverseType; use crate::util::{ - camel_case_ident, mdn_doc, public, shouty_snake_case_ident, snake_case_ident, - webidl_const_v_to_backend_const_v, TypePosition, + camel_case_ident, is_structural, is_type_unstable, read_dir, shouty_snake_case_ident, + snake_case_ident, throws, webidl_const_v_to_backend_const_v, TypePosition, }; -use anyhow::{bail, Result}; -use proc_macro2::{Ident, Span}; -use quote::{quote, ToTokens}; -use std::collections::{BTreeSet, HashSet}; -use std::env; +use anyhow::Context; +use anyhow::Result; +use proc_macro2::{Ident, TokenStream}; +use quote::ToTokens; +use sourcefile::SourceFile; +use std::collections::{BTreeMap, BTreeSet, HashSet}; +use std::ffi::OsStr; use std::fmt; -use std::fmt::Display; use std::fs; -use std::iter::FromIterator; -use wasm_bindgen_backend::ast; -use wasm_bindgen_backend::defined::ImportedTypeReferences; -use wasm_bindgen_backend::defined::{ImportedTypeDefinitions, RemoveUndefinedImports}; -use wasm_bindgen_backend::util::{ident_ty, raw_ident, rust_ident, wrap_import_function}; -use wasm_bindgen_backend::TryToTokens; +use std::path::{Path, PathBuf}; +use std::process::Command; +use wasm_bindgen_backend::util::rust_ident; use weedle::attribute::ExtendedAttributeList; +use weedle::common::Identifier; use weedle::dictionary::DictionaryMember; use weedle::interface::InterfaceMember; +use weedle::Parse; + +/// Options to configure the conversion process +#[derive(Debug)] +pub struct Options { + /// Whether to generate cfg features or not + pub features: bool, +} +#[derive(Default)] struct Program { - main: ast::Program, - submodules: Vec<(String, ast::Program)>, + tokens: TokenStream, + required_features: BTreeSet, +} + +impl Program { + fn to_string(&self) -> Option { + if self.tokens.is_empty() { + None + } else { + Some(self.tokens.to_string()) + } + } } /// A parse error indicating where parsing failed @@ -55,309 +81,241 @@ 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 { - 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; - - bail!(WebIDLParseError(pos)) - } - } - } - }; +#[derive(Clone, Copy, PartialEq)] +pub(crate) enum ApiStability { + Stable, + Unstable, +} - let mut first_pass_record: FirstPassRecord = Default::default(); - first_pass_record.builtin_idents = builtin_idents(); - first_pass_record.immutable_slice_whitelist = immutable_slice_whitelist(); +impl ApiStability { + pub(crate) fn is_unstable(self) -> bool { + self == Self::Unstable + } +} - definitions.first_pass(&mut first_pass_record, ())?; - let mut program = Default::default(); - let mut submodules = Vec::new(); - - let allowed_types = allowed_types.map(|list| list.iter().cloned().collect::>()); - let filter = |name: &str| match &allowed_types { - Some(set) => set.contains(name), - None => true, - }; +impl Default for ApiStability { + fn default() -> Self { + Self::Stable + } +} - for (name, e) in first_pass_record.enums.iter() { - if filter(&camel_case_ident(name)) { - first_pass_record.append_enum(&mut program, e); +fn parse_source(source: &str) -> Result> { + match weedle::Definitions::parse(source) { + Ok(("", parsed)) => Ok(parsed), + + Ok((remaining, _)) + | Err(weedle::Err::Error((remaining, _))) + | Err(weedle::Err::Failure((remaining, _))) => { + Err(WebIDLParseError(source.len() - remaining.len()).into()) } - } - for (name, d) in first_pass_record.dictionaries.iter() { - if filter(&camel_case_ident(name)) { - first_pass_record.append_dictionary(&mut program, d); + + Err(weedle::Err::Incomplete(needed)) => { + Err(anyhow::anyhow!("needed {:?} more bytes", needed)) } } - for (name, n) in first_pass_record.namespaces.iter() { - if filter(&snake_case_ident(name)) { - let prog = first_pass_record.append_ns(name, n); - submodules.push((snake_case_ident(name).to_string(), prog)); - } +} + +/// Parse a string of WebIDL source text into a wasm-bindgen AST. +fn parse( + webidl_source: &str, + unstable_source: &str, + options: Options, +) -> Result> { + let mut first_pass_record: FirstPassRecord = Default::default(); + + let definitions = parse_source(webidl_source)?; + definitions.first_pass(&mut first_pass_record, ApiStability::Stable)?; + + let unstable_definitions = parse_source(unstable_source)?; + + // Gather unstable type Identifiers so that stable APIs can be downgraded + // to unstable if they accept one of these types + let unstable_types: HashSet = unstable_definitions + .iter() + .flat_map(|definition| { + use weedle::Definition::*; + match definition { + Dictionary(v) => Some(v.identifier), + Enum(v) => Some(v.identifier), + Interface(v) => Some(v.identifier), + _ => None, + } + }) + .collect(); + + unstable_definitions.first_pass(&mut first_pass_record, ApiStability::Unstable)?; + + let mut types: BTreeMap = BTreeMap::new(); + + for (js_name, e) in first_pass_record.enums.iter() { + let name = rust_ident(&camel_case_ident(js_name)); + let program = types.entry(name.to_string()).or_default(); + first_pass_record.append_enum(&options, program, name, js_name, e); + } + for (js_name, d) in first_pass_record.dictionaries.iter() { + let name = rust_ident(&camel_case_ident(js_name)); + let program = types.entry(name.to_string()).or_default(); + first_pass_record.append_dictionary( + &options, + program, + name, + js_name.to_string(), + d, + &unstable_types, + ); } - for (name, d) in first_pass_record.interfaces.iter() { - if filter(&camel_case_ident(name)) { - first_pass_record.append_interface(&mut program, name, d); - } + for (js_name, n) in first_pass_record.namespaces.iter() { + let name = rust_ident(&snake_case_ident(js_name)); + let program = types.entry(name.to_string()).or_default(); + first_pass_record.append_ns(&options, program, name, js_name.to_string(), n); + } + for (js_name, d) in first_pass_record.interfaces.iter() { + let name = rust_ident(&camel_case_ident(js_name)); + let program = types.entry(name.to_string()).or_default(); + first_pass_record.append_interface( + &options, + program, + name, + js_name.to_string(), + &unstable_types, + d, + ); } - for (name, d) in first_pass_record.callback_interfaces.iter() { - if filter(&camel_case_ident(name)) { - first_pass_record.append_callback_interface(&mut program, d); - } + for (js_name, d) in first_pass_record.callback_interfaces.iter() { + let name = rust_ident(&camel_case_ident(js_name)); + let program = types.entry(name.to_string()).or_default(); + first_pass_record.append_callback_interface( + &options, + program, + name, + js_name.to_string(), + d, + ); } - // Prune out `extends` annotations that aren't defined as these shouldn't - // prevent the type from being usable entirely. They're just there for - // `AsRef` and such implementations. - for import in program.imports.iter_mut() { - if let ast::ImportKind::Type(t) = &mut import.kind { - t.extends.retain(|n| { - let ident = &n.segments.last().unwrap().ident; - first_pass_record.builtin_idents.contains(ident) || filter(&ident.to_string()) - }); - } - } + Ok(types) +} - Ok(Program { - main: program, - submodules: submodules, - }) +/// Data for a single feature +#[derive(Debug)] +pub struct Feature { + /// Generated code + pub code: String, + + /// Required features + pub required_features: Vec, } /// 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 { - let ast = parse(webidl_source, allowed_types)?; - Ok(compile_ast(ast)) -} - -fn builtin_idents() -> BTreeSet { - BTreeSet::from_iter( - vec![ - "str", - "char", - "bool", - "JsValue", - "u8", - "i8", - "u16", - "i16", - "u32", - "i32", - "u64", - "i64", - "usize", - "isize", - "f32", - "f64", - "Result", - "String", - "Vec", - "Option", - "Array", - "ArrayBuffer", - "Object", - "Promise", - "Function", - "Clamped", - ] +pub fn compile( + webidl_source: &str, + experimental_source: &str, + options: Options, +) -> Result> { + let ast = parse(webidl_source, experimental_source, options)?; + + let features = ast .into_iter() - .map(|id| proc_macro2::Ident::new(id, proc_macro2::Span::call_site())), - ) -} + .filter_map(|(name, program)| { + let code = program.to_string()?; + let required_features = program.required_features.into_iter().collect(); + Some(( + name, + Feature { + required_features, + code, + }, + )) + }) + .collect(); -fn immutable_slice_whitelist() -> BTreeSet<&'static str> { - BTreeSet::from_iter(vec![ - // WebGlRenderingContext, WebGl2RenderingContext - "uniform1fv", - "uniform2fv", - "uniform3fv", - "uniform4fv", - "uniform1iv", - "uniform2iv", - "uniform3iv", - "uniform4iv", - "uniformMatrix2fv", - "uniformMatrix3fv", - "uniformMatrix4fv", - "vertexAttrib1fv", - "vertexAttrib2fv", - "vertexAttrib3fv", - "vertexAttrib4fv", - "bufferData", - "bufferSubData", - "texImage2D", - "texSubImage2D", - "compressedTexImage2D", - // WebGl2RenderingContext - "uniform1uiv", - "uniform2uiv", - "uniform3uiv", - "uniform4uiv", - "texImage3D", - "texSubImage3D", - "compressedTexImage3D", - "clearBufferfv", - "clearBufferiv", - "clearBufferuiv", - // TODO: Add another type's functions here. Leave a comment header with the type name - ]) -} - -/// Run codegen on the AST to generate rust code. -fn compile_ast(mut ast: Program) -> String { - // Iteratively prune all entries from the AST which reference undefined - // fields. Each pass may remove definitions of types and so we need to - // reexecute this pass to see if we need to keep removing types until we - // reach a steady state. - let builtin = builtin_idents(); - let mut all_definitions = BTreeSet::new(); - let track = env::var_os("__WASM_BINDGEN_DUMP_FEATURES"); - loop { - let mut defined = builtin.clone(); - { - let mut cb = |id: &Ident| { - defined.insert(id.clone()); - if track.is_some() { - all_definitions.insert(id.clone()); - } - }; - ast.main.imported_type_definitions(&mut cb); - for (name, m) in ast.submodules.iter() { - cb(&Ident::new(name, Span::call_site())); - m.imported_type_references(&mut cb); - } - } - let changed = ast - .main - .remove_undefined_imports(&|id| defined.contains(id)) - || ast - .submodules - .iter_mut() - .any(|(_, m)| m.remove_undefined_imports(&|id| defined.contains(id))); - if !changed { - break; - } - } - if let Some(path) = track { - let contents = all_definitions - .into_iter() - .filter(|def| !builtin.contains(def)) - .map(|s| format!("{} = []", s)) - .collect::>() - .join("\n"); - fs::write(path, contents).unwrap(); - } + Ok(features) +} - let mut tokens = proc_macro2::TokenStream::new(); - if let Err(e) = ast.main.try_to_tokens(&mut tokens) { - e.panic(); - } - for (name, m) in ast.submodules.iter() { - let mut m_tokens = proc_macro2::TokenStream::new(); - if let Err(e) = m.try_to_tokens(&mut m_tokens) { - e.panic(); - } +impl<'src> FirstPassRecord<'src> { + fn append_enum( + &self, + options: &Options, + program: &mut Program, + name: Ident, + js_name: &str, + data: &first_pass::EnumData<'src>, + ) { + let enum_ = data.definition; + let unstable = data.stability.is_unstable(); - let name = Ident::new(name, Span::call_site()); + assert_eq!(js_name, enum_.identifier.0); - (quote! { - pub mod #name { #m_tokens } - }) - .to_tokens(&mut tokens); - } - tokens.to_string() -} + let variants = enum_ + .values + .body + .list + .iter() + .map(|v| { + let name = if !v.0.is_empty() { + rust_ident(camel_case_ident(&v.0).as_str()) + } else { + rust_ident("None") + }; + + let value = v.0.to_string(); + + EnumVariant { name, value } + }) + .collect::>(); -impl<'src> FirstPassRecord<'src> { - fn append_enum(&self, program: &mut ast::Program, enum_: &'src weedle::EnumDefinition<'src>) { - let variants = &enum_.values.body.list; - program.imports.push(ast::Import { - module: ast::ImportModule::None, - js_namespace: None, - kind: ast::ImportKind::Enum(ast::ImportEnum { - vis: public(), - name: rust_ident(camel_case_ident(enum_.identifier.0).as_str()), - variants: variants - .iter() - .map(|v| { - if !v.0.is_empty() { - rust_ident(camel_case_ident(&v.0).as_str()) - } else { - rust_ident("None") - } - }) - .collect(), - variant_values: variants.iter().map(|v| v.0.to_string()).collect(), - rust_attrs: vec![syn::parse_quote!(#[derive(Copy, Clone, PartialEq, Debug)])], - }), - }); + Enum { + name, + variants, + unstable, + } + .generate(options) + .to_tokens(&mut program.tokens); } // tons more data for what's going on here at // https://www.w3.org/TR/WebIDL-1/#idl-dictionaries fn append_dictionary( &self, - program: &mut ast::Program, + options: &Options, + program: &mut Program, + name: Ident, + js_name: String, data: &first_pass::DictionaryData<'src>, + unstable_types: &HashSet, ) { let def = match data.definition { Some(def) => def, None => return, }; + + assert_eq!(js_name, def.identifier.0); + + let unstable = data.stability.is_unstable(); + let mut fields = Vec::new(); - if !self.append_dictionary_members(def.identifier.0, &mut fields) { + + if !self.append_dictionary_members(&js_name, &mut fields, unstable, unstable_types) { return; } - let name = rust_ident(&camel_case_ident(def.identifier.0)); - let extra_feature = name.to_string(); - for field in fields.iter_mut() { - let mut doc_comment = Some(format!( - "Configure the `{}` field of this object\n", - field.js_name, - )); - self.append_required_features_doc(&*field, &mut doc_comment, &[&extra_feature]); - field.doc_comment = doc_comment; - } - - let mut doc_comment = format!("The `{}` dictionary\n", def.identifier.0); - if let Some(s) = self.required_doc_string(vec![name.clone()]) { - doc_comment.push_str(&s); - } - let mut dict = ast::Dictionary { + + Dictionary { name, + js_name, fields, - ctor: true, - doc_comment: Some(doc_comment), - ctor_doc_comment: None, - }; - 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]); - dict.ctor_doc_comment = ctor_doc_comment; - - program.dictionaries.push(dict); + unstable, + } + .generate(options) + .to_tokens(&mut program.tokens); } fn append_dictionary_members( &self, dict: &'src str, - dst: &mut Vec, + dst: &mut Vec, + unstable: bool, + unstable_types: &HashSet, ) -> bool { let dict_data = &self.dictionaries[&dict]; let definition = dict_data.definition.unwrap(); @@ -366,7 +324,7 @@ // > such that inherited dictionary members are ordered before // > non-inherited members ... if let Some(parent) = &definition.inheritance { - if !self.append_dictionary_members(parent.identifier.0, dst) { + if !self.append_dictionary_members(parent.identifier.0, dst, unstable, unstable_types) { return false; } } @@ -379,7 +337,7 @@ let members = definition.members.body.iter(); let partials = dict_data.partials.iter().flat_map(|d| &d.members.body); for member in members.chain(partials) { - match self.dictionary_field(member) { + match self.dictionary_field(member, unstable, unstable_types) { Some(f) => dst.push(f), None => { log::warn!( @@ -404,12 +362,20 @@ fn dictionary_field( &self, field: &'src DictionaryMember<'src>, - ) -> Option { + unstable: bool, + unstable_types: &HashSet, + ) -> Option { + let unstable_override = match unstable { + true => true, + false => is_type_unstable(&field.type_, unstable_types), + }; + // use argument position now as we're just binding setters let ty = field .type_ .to_idl_type(self) - .to_syn_type(TypePosition::Argument)?; + .to_syn_type(TypePosition::Argument) + .unwrap_or(None)?; // Slice types aren't supported because they don't implement // `Into` @@ -440,189 +406,168 @@ // Similarly i64/u64 aren't supported because they don't // implement `Into` let mut any_64bit = false; - ty.imported_type_references(&mut |i| { - any_64bit = any_64bit || i == "u64" || i == "i64"; + + ty.traverse_type(&mut |ident| { + if !any_64bit { + if ident == "u64" || ident == "i64" { + any_64bit = true; + } + } }); + if any_64bit { return None; } - Some(ast::DictionaryField { + Some(DictionaryField { required: field.required.is_some(), - rust_name: rust_ident(&snake_case_ident(field.identifier.0)), + name: rust_ident(&snake_case_ident(field.identifier.0)), js_name: field.identifier.0.to_string(), ty, - doc_comment: None, + unstable: unstable_override, }) } fn append_ns( &'src self, - name: &'src str, + options: &Options, + program: &mut Program, + name: Ident, + js_name: String, ns: &'src first_pass::NamespaceData<'src>, - ) -> ast::Program { - let mut ret = Default::default(); + ) { + let mut functions = vec![]; for (id, data) in ns.operations.iter() { - self.append_ns_member(&mut ret, name, id, data); + self.append_ns_member(&mut functions, &js_name, id, data); } - return ret; + if !functions.is_empty() { + Namespace { + name, + js_name, + functions, + } + .generate(options) + .to_tokens(&mut program.tokens); + } } fn append_ns_member( &self, - module: &mut ast::Program, - self_name: &'src str, + functions: &mut Vec, + js_name: &'src str, id: &OperationId<'src>, data: &OperationData<'src>, ) { - let name = match id { - OperationId::Operation(Some(name)) => name, + match id { + OperationId::Operation(Some(_)) => {} OperationId::Constructor(_) + | OperationId::NamedConstructor(_) | OperationId::Operation(None) | OperationId::IndexingGetter | OperationId::IndexingSetter | OperationId::IndexingDeleter => { - log::warn!("Unsupported unnamed operation: on {:?}", self_name); + log::warn!("Unsupported unnamed operation: on {:?}", js_name); return; } - }; - let doc_comment = format!( - "The `{}.{}()` function\n\n{}", - self_name, - name, - mdn_doc(self_name, Some(&name)) - ); + } - 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) { - let mut doc = Some(doc_comment.clone()); - self.append_required_features_doc(&import_function, &mut doc, extra); - import_function.doc_comment = doc; - module.imports.push(ast::Import { - module: ast::ImportModule::None, - js_namespace: Some(raw_ident(self_name)), - kind: ast::ImportKind::Function(import_function), + for x in self.create_imports(None, id, data, false, &HashSet::new()) { + functions.push(Function { + name: x.name, + js_name: x.js_name, + arguments: x.arguments, + ret_ty: x.ret_ty, + catch: x.catch, + variadic: x.variadic, + unstable: false, }); } } fn append_const( &self, - program: &mut ast::Program, - self_name: &'src str, + consts: &mut Vec, member: &'src weedle::interface::ConstMember<'src>, + unstable: bool, ) { let idl_type = member.const_type.to_idl_type(self); - let ty = match idl_type.to_syn_type(TypePosition::Return) { - Some(ty) => ty, - None => { - log::warn!( - "Cannot convert const type to syn type: {:?} in {:?} on {:?}", - idl_type, - member, - self_name - ); - return; - } - }; + let ty = idl_type.to_syn_type(TypePosition::Return).unwrap().unwrap(); + + let js_name = member.identifier.0; + let name = rust_ident(shouty_snake_case_ident(js_name).as_str()); + let value = webidl_const_v_to_backend_const_v(&member.const_value); - program.consts.push(ast::Const { - vis: public(), - name: rust_ident(shouty_snake_case_ident(member.identifier.0).as_str()), - class: Some(rust_ident(camel_case_ident(&self_name).as_str())), + consts.push(InterfaceConst { + name, + js_name: js_name.to_string(), ty, - value: webidl_const_v_to_backend_const_v(&member.const_value), + value, + unstable, }); } fn append_interface( &self, - program: &mut ast::Program, - name: &'src str, + options: &Options, + program: &mut Program, + name: Ident, + js_name: String, + unstable_types: &HashSet, data: &InterfaceData<'src>, ) { - let mut doc_comment = Some(format!("The `{}` object\n\n{}", name, mdn_doc(name, None),)); + let unstable = data.stability.is_unstable(); + let has_interface = data.has_interface; - let mut attrs = Vec::new(); - attrs.push(syn::parse_quote!( #[derive(Debug, Clone, PartialEq, Eq)] )); - self.add_deprecated(data, &mut attrs); - let mut import_type = ast::ImportType { - vis: public(), - rust_name: rust_ident(camel_case_ident(name).as_str()), - js_name: name.to_string(), - attrs, - doc_comment: None, - instanceof_shim: format!("__widl_instanceof_{}", name), - is_type_of: if data.has_interface { - None - } else { - Some(syn::parse_quote! { |_| false }) - }, - extends: Vec::new(), - vendor_prefixes: Vec::new(), - }; + let deprecated = data.deprecated.clone(); - // whitelist a few names that have known polyfills - match name { - "AudioContext" | "OfflineAudioContext" => { - import_type - .vendor_prefixes - .push(Ident::new("webkit", Span::call_site())); - } - _ => {} - } - let extra = camel_case_ident(name); - let extra = &[&extra[..]]; - self.append_required_features_doc(&import_type, &mut doc_comment, extra); - import_type.extends = self - .all_superclasses(name) - .map(|name| Ident::new(&name, Span::call_site()).into()) - .chain(Some(Ident::new("Object", Span::call_site()).into())) - .collect(); - import_type.doc_comment = doc_comment; - - program.imports.push(ast::Import { - module: ast::ImportModule::None, - js_namespace: None, - kind: ast::ImportKind::Type(import_type), - }); + let parents = self + .all_superclasses(&js_name) + .map(|parent| { + let ident = rust_ident(&camel_case_ident(&parent)); + program.required_features.insert(parent); + ident + }) + .collect::>(); + + let mut consts = vec![]; + let mut attributes = vec![]; + let mut methods = vec![]; - 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(&mut consts, member, unstable); } + for member in data.attributes.iter() { + let unstable = unstable || member.stability.is_unstable(); + let member = member.definition; self.member_attribute( - program, - name, - data, + &mut attributes, member.modifier, member.readonly.is_some(), &member.type_, - member.identifier.0, + member.identifier.0.to_string(), &member.attributes, data.definition_attributes, + unstable, ); } - for mixin_data in self.all_mixins(name) { - for (id, op_data) in mixin_data.operations.iter() { - self.member_operation(program, name, data, id, op_data); - } + for (id, op_data) in data.operations.iter() { + self.member_operation(&mut methods, data, id, op_data, unstable_types); + } + + for mixin_data in self.all_mixins(&js_name) { for member in &mixin_data.consts { - self.append_const(program, name, member); + self.append_const(&mut consts, member, unstable); } + for member in &mixin_data.attributes { + let unstable = unstable || member.stability.is_unstable(); + let member = member.definition; self.member_attribute( - program, - name, - data, + &mut attributes, if let Some(s) = member.stringifier { Some(weedle::interface::StringifierOrInheritOrStatic::Stringifier(s)) } else { @@ -630,25 +575,43 @@ }, member.readonly.is_some(), &member.type_, - member.identifier.0, + member.identifier.0.to_string(), &member.attributes, data.definition_attributes, + unstable, ); } + + for (id, op_data) in mixin_data.operations.iter() { + self.member_operation(&mut methods, data, id, op_data, unstable_types); + } } + + Interface { + name, + js_name, + deprecated, + has_interface, + parents, + consts, + attributes, + methods, + unstable, + } + .generate(options) + .to_tokens(&mut program.tokens); } fn member_attribute( &self, - program: &mut ast::Program, - self_name: &'src str, - data: &InterfaceData<'src>, + attributes: &mut Vec, modifier: Option, readonly: bool, type_: &'src weedle::types::AttributedType<'src>, - identifier: &'src str, + js_name: String, attrs: &'src Option>, container_attrs: Option<&'src ExtendedAttributeList<'src>>, + unstable: bool, ) { use weedle::interface::StringifierOrInheritOrStatic::*; @@ -659,152 +622,81 @@ None => false, }; - for mut import_function in self.create_getter( - identifier, - &type_.type_, - self_name, - is_static, - attrs, - container_attrs, - ) { - let mut doc = import_function.doc_comment.take(); - self.append_required_features_doc(&import_function, &mut doc, &[]); - import_function.doc_comment = doc; - program.imports.push(wrap_import_function(import_function)); + let structural = is_structural(attrs.as_ref(), container_attrs); + + let catch = throws(attrs); + + let ty = type_ + .type_ + .to_idl_type(self) + .to_syn_type(TypePosition::Return) + .unwrap_or(None); + + // Skip types which can't be converted + if let Some(ty) = ty { + let kind = InterfaceAttributeKind::Getter; + attributes.push(InterfaceAttribute { + is_static, + structural, + catch, + ty, + js_name: js_name.clone(), + kind, + unstable, + }); } if !readonly { - for mut import_function in self.create_setter( - identifier, - &type_.type_, - self_name, - is_static, - attrs, - container_attrs, - ) { - let mut doc = import_function.doc_comment.take(); - self.append_required_features_doc(&import_function, &mut doc, &[]); - import_function.doc_comment = doc; - self.add_deprecated(data, &mut import_function.function.rust_attrs); - program.imports.push(wrap_import_function(import_function)); + let ty = type_ + .type_ + .to_idl_type(self) + .to_syn_type(TypePosition::Argument) + .unwrap_or(None); + + // Skip types which can't be converted + if let Some(ty) = ty { + let kind = InterfaceAttributeKind::Setter; + attributes.push(InterfaceAttribute { + is_static, + structural, + catch, + ty, + js_name, + kind, + unstable, + }); } } } fn member_operation( &self, - program: &mut ast::Program, - self_name: &str, + methods: &mut Vec, data: &InterfaceData<'src>, id: &OperationId<'src>, op_data: &OperationData<'src>, + unstable_types: &HashSet, ) { - let import_function_kind = - |opkind| self.import_function_kind(self_name, op_data.is_static, opkind); - let kind = match id { - OperationId::Constructor(ctor_name) => { - let self_ty = ident_ty(rust_ident(&camel_case_ident(self_name))); - ast::ImportFunctionKind::Method { - class: ctor_name.0.to_string(), - ty: self_ty.clone(), - kind: ast::MethodKind::Constructor, - } - } - OperationId::Operation(_) => import_function_kind(ast::OperationKind::Regular), - OperationId::IndexingGetter => import_function_kind(ast::OperationKind::IndexingGetter), - OperationId::IndexingSetter => import_function_kind(ast::OperationKind::IndexingSetter), - OperationId::IndexingDeleter => { - import_function_kind(ast::OperationKind::IndexingDeleter) - } - }; - let doc = match id { - OperationId::Operation(None) => Some(String::new()), - OperationId::Constructor(_) => Some(format!( - "The `new {}(..)` constructor, creating a new \ - instance of `{0}`\n\n{}", - self_name, - mdn_doc(self_name, Some(self_name)) - )), - OperationId::Operation(Some(name)) => Some(format!( - "The `{}()` method\n\n{}", - name, - mdn_doc(self_name, Some(name)) - )), - OperationId::IndexingGetter => Some(format!("The indexing getter\n\n")), - OperationId::IndexingSetter => Some(format!("The indexing setter\n\n")), - 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) { - let mut doc = doc.clone(); - self.append_required_features_doc(&method, &mut doc, &[]); - method.doc_comment = doc; - self.add_deprecated(data, &mut method.function.rust_attrs); - program.imports.push(wrap_import_function(method)); - } - } - - fn add_deprecated(&self, data: &InterfaceData<'src>, dst: &mut Vec) { - let msg = match &data.deprecated { - Some(s) => s, - None => return, - }; - dst.push(syn::parse_quote!( #[deprecated(note = #msg)] )); - } - - fn append_required_features_doc( - &self, - item: impl ImportedTypeReferences, - doc: &mut Option, - extra: &[&str], - ) { - let doc = match doc { - Some(doc) => doc, - None => return, - }; - let mut required = extra - .iter() - .map(|s| Ident::new(s, Span::call_site())) - .collect::>(); - item.imported_type_references(&mut |f| { - if !self.builtin_idents.contains(f) { - required.insert(f.clone()); - } - }); - if required.len() == 0 { - return; - } - if let Some(extra) = self.required_doc_string(required) { - doc.push_str(&extra); - } - } + let unstable = data.stability.is_unstable(); - fn required_doc_string( - &self, - features: impl IntoIterator, - ) -> Option { - let features = features.into_iter().collect::>(); - if features.len() == 0 { - return None; + for method in self.create_imports(attrs, id, op_data, unstable, unstable_types) { + methods.push(method); } - let list = features - .iter() - .map(|ident| format!("`{}`", ident)) - .collect::>() - .join(", "); - Some(format!( - "\n\n*This API requires the following crate features \ - to be activated: {}*", - list, - )) } fn append_callback_interface( &self, - program: &mut ast::Program, + options: &Options, + program: &mut Program, + name: Ident, + js_name: String, item: &CallbackInterfaceData<'src>, ) { + assert_eq!(js_name, item.definition.identifier.0); + let mut fields = Vec::new(); + for member in item.definition.members.body.iter() { match member { InterfaceMember::Operation(op) => { @@ -813,13 +705,17 @@ None => continue, }; let pos = TypePosition::Argument; - fields.push(ast::DictionaryField { + + fields.push(DictionaryField { required: false, - rust_name: rust_ident(&snake_case_ident(identifier)), + name: rust_ident(&snake_case_ident(identifier)), js_name: identifier.to_string(), - ty: idl_type::IdlType::Callback.to_syn_type(pos).unwrap(), - doc_comment: None, - }); + ty: idl_type::IdlType::Callback + .to_syn_type(pos) + .unwrap() + .unwrap(), + unstable: false, + }) } _ => { log::warn!( @@ -830,12 +726,137 @@ } } - program.dictionaries.push(ast::Dictionary { - name: rust_ident(&camel_case_ident(item.definition.identifier.0)), + Dictionary { + name, + js_name, fields, - ctor: true, - doc_comment: None, - ctor_doc_comment: None, - }); + unstable: false, + } + .generate(options) + .to_tokens(&mut program.tokens); + } +} + +/// Generates Rust source code with #[wasm_bindgen] annotations. +/// +/// * Reads WebIDL files in `from` +/// * Generates Rust source code in the directory `to` +/// * `options.features` indicates whether everything is gated by features or +/// not +/// +/// If features are enabled, returns a string that should be appended to +/// `Cargo.toml` which lists all the known features. +pub fn generate(from: &Path, to: &Path, options: Options) -> Result { + let generate_features = options.features; + + let source = read_source_from_path(&from.join("enabled"))?; + let unstable_source = read_source_from_path(&from.join("unstable"))?; + + let features = parse_webidl(generate_features, source, unstable_source)?; + + if to.exists() { + fs::remove_dir_all(&to).context("Removing features directory")?; + } + + fs::create_dir_all(&to).context("Creating features directory")?; + + for (name, feature) in features.iter() { + let out_file_path = to.join(format!("gen_{}.rs", name)); + + fs::write(&out_file_path, &feature.code)?; + + rustfmt(&out_file_path, name)?; + } + + let binding_file = features.keys().map(|name| { + if generate_features { + format!("#[cfg(feature = \"{name}\")] #[allow(non_snake_case)] mod gen_{name};\n#[cfg(feature = \"{name}\")] pub use gen_{name}::*;", name = name) + } else { + format!("#[allow(non_snake_case)] mod gen_{name};\npub use gen_{name}::*;", name = name) + } + }).collect::>().join("\n\n"); + + fs::write(to.join("mod.rs"), binding_file)?; + + rustfmt(&to.join("mod.rs"), "mod")?; + + return if generate_features { + let features = features + .iter() + .map(|(name, feature)| { + let features = feature + .required_features + .iter() + .map(|x| format!("\"{}\"", x)) + .collect::>() + .join(", "); + format!("{} = [{}]", name, features) + }) + .collect::>() + .join("\n"); + Ok(features) + } else { + Ok(String::new()) + }; + + /// Read all WebIDL files in a directory into a single `SourceFile` + fn read_source_from_path(dir: &Path) -> Result { + let entries = read_dir(dir).context("reading webidls directory")?; + let mut source = SourceFile::default(); + for path in entries { + if path.extension() != Some(OsStr::new("webidl")) { + continue; + } + source = source + .add_file(&path) + .with_context(|| format!("reading contents of file \"{}\"", path.display()))?; + } + + Ok(source) + } + + fn rustfmt(path: &PathBuf, name: &str) -> Result<()> { + // run rustfmt on the generated file - really handy for debugging + let result = Command::new("rustfmt") + .arg("--edition") + .arg("2018") + .arg(&path) + .status() + .context(format!("rustfmt on file {}", name))?; + + assert!(result.success(), "rustfmt on file {}", name); + + Ok(()) + } + + fn parse_webidl( + generate_features: bool, + enabled: SourceFile, + unstable: SourceFile, + ) -> Result> { + let options = Options { + features: generate_features, + }; + + match compile(&enabled.contents, &unstable.contents, options) { + Ok(features) => Ok(features), + Err(e) => { + if let Some(err) = e.downcast_ref::() { + if let Some(pos) = enabled.resolve_offset(err.0) { + let ctx = format!( + "compiling WebIDL into wasm-bindgen bindings in file \ + \"{}\", line {} column {}", + pos.filename, + pos.line + 1, + pos.col + 1 + ); + return Err(e.context(ctx)); + } else { + return Err(e.context("compiling WebIDL into wasm-bindgen bindings")); + } + } + return Err(e.context("compiling WebIDL into wasm-bindgen bindings")); + } + } } } diff -Nru rust-wasm-bindgen-webidl-0.2.58/src/main.rs rust-wasm-bindgen-webidl-0.2.75/src/main.rs --- rust-wasm-bindgen-webidl-0.2.58/src/main.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/src/main.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,41 @@ +use anyhow::{Context, Result}; +use std::fs; +use std::path::PathBuf; +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt( + name = "wasm-bindgen-webidl", + about = "Converts WebIDL into wasm-bindgen compatible code." +)] +struct Opt { + #[structopt(parse(from_os_str))] + input_dir: PathBuf, + + #[structopt(parse(from_os_str))] + output_dir: PathBuf, + + #[structopt(long)] + no_features: bool, +} + +fn main() -> Result<()> { + env_logger::init(); + + let opt = Opt::from_args(); + + let features = !opt.no_features; + + let generated_features = wasm_bindgen_webidl::generate( + &opt.input_dir, + &opt.output_dir, + wasm_bindgen_webidl::Options { features }, + )?; + + if features { + fs::write(&"features", generated_features) + .context("writing features to current directory")?; + } + + Ok(()) +} diff -Nru rust-wasm-bindgen-webidl-0.2.58/src/traverse.rs rust-wasm-bindgen-webidl-0.2.75/src/traverse.rs --- rust-wasm-bindgen-webidl-0.2.58/src/traverse.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/src/traverse.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,203 @@ +use syn::{Ident, Type}; + +pub trait TraverseType { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident); +} + +impl TraverseType for Type { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + match self { + Type::Array(x) => x.traverse_type(f), + Type::BareFn(x) => x.traverse_type(f), + Type::Group(x) => x.traverse_type(f), + Type::Paren(x) => x.traverse_type(f), + Type::Path(x) => x.traverse_type(f), + Type::Ptr(x) => x.traverse_type(f), + Type::Reference(x) => x.traverse_type(f), + Type::Slice(x) => x.traverse_type(f), + Type::Tuple(x) => x.traverse_type(f), + _ => {} + } + } +} + +impl TraverseType for syn::TypeArray { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + self.elem.traverse_type(f); + } +} + +impl TraverseType for syn::TypeBareFn { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + for input in self.inputs.iter() { + input.ty.traverse_type(f); + } + + self.output.traverse_type(f); + } +} + +impl TraverseType for syn::ReturnType { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + match self { + Self::Default => {} + Self::Type(_, ty) => { + ty.traverse_type(f); + } + } + } +} + +impl TraverseType for syn::TypeGroup { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + self.elem.traverse_type(f); + } +} + +impl TraverseType for syn::TypeParen { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + self.elem.traverse_type(f); + } +} + +impl TraverseType for syn::TypePath { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + if let Some(qself) = self.qself.as_ref() { + qself.traverse_type(f); + } + + if let Some(last) = self.path.segments.last() { + f(&last.ident); + last.arguments.traverse_type(f); + } + } +} + +impl TraverseType for syn::QSelf { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + self.ty.traverse_type(f); + } +} + +impl TraverseType for syn::PathArguments { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + match self { + Self::None => {} + Self::AngleBracketed(x) => x.traverse_type(f), + Self::Parenthesized(x) => x.traverse_type(f), + } + } +} + +impl TraverseType for syn::AngleBracketedGenericArguments { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + for ty in self.args.iter() { + ty.traverse_type(f); + } + } +} + +impl TraverseType for syn::GenericArgument { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + match self { + Self::Type(x) => x.traverse_type(f), + Self::Binding(x) => x.traverse_type(f), + _ => {} + } + } +} + +impl TraverseType for syn::Binding { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + self.ty.traverse_type(f); + } +} + +impl TraverseType for syn::ParenthesizedGenericArguments { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + for ty in self.inputs.iter() { + ty.traverse_type(f); + } + + self.output.traverse_type(f); + } +} + +impl TraverseType for syn::TypePtr { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + self.elem.traverse_type(f); + } +} + +impl TraverseType for syn::TypeReference { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + self.elem.traverse_type(f); + } +} + +impl TraverseType for syn::TypeTuple { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + for ty in self.elems.iter() { + ty.traverse_type(f); + } + } +} + +impl TraverseType for syn::TypeSlice { + fn traverse_type(&self, f: &mut F) + where + F: FnMut(&Ident), + { + self.elem.traverse_type(f); + } +} diff -Nru rust-wasm-bindgen-webidl-0.2.58/src/util.rs rust-wasm-bindgen-webidl-0.2.75/src/util.rs --- rust-wasm-bindgen-webidl-0.2.58/src/util.rs 2020-01-06 19:17:34.000000000 +0000 +++ rust-wasm-bindgen-webidl-0.2.75/src/util.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,17 +1,25 @@ +use std::collections::{BTreeSet, HashSet}; +use std::fs; use std::iter::FromIterator; +use std::path::{Path, PathBuf}; use std::ptr; use heck::{CamelCase, ShoutySnakeCase, SnakeCase}; -use proc_macro2::{Ident, Span}; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; use syn; -use wasm_bindgen_backend::ast; -use wasm_bindgen_backend::util::{ident_ty, leading_colon_path_ty, raw_ident, rust_ident}; +use wasm_bindgen_backend::util::{ident_ty, raw_ident, rust_ident}; use weedle; use weedle::attribute::{ExtendedAttribute, ExtendedAttributeList, IdentifierOrString}; +use weedle::common::Identifier; use weedle::literal::{ConstValue, FloatLit, IntegerLit}; +use weedle::types::{NonAnyType, SingleType}; +use crate::constants::IMMUTABLE_SLICE_WHITELIST; use crate::first_pass::{FirstPassRecord, OperationData, OperationId, Signature}; +use crate::generator::{InterfaceConstValue, InterfaceMethod, InterfaceMethodKind}; use crate::idl_type::{IdlType, ToIdlType}; +use crate::Options; /// For variadic operations an overload with a `js_sys::Array` argument is generated alongside with /// `operation_name_0`, `operation_name_1`, `operation_name_2`, ..., `operation_name_n` overloads @@ -19,6 +27,21 @@ /// in their names, where `n` is this constant. const MAX_VARIADIC_ARGUMENTS_COUNT: usize = 7; +/// Similar to std::fs::read_dir except it returns a sorted Vec, +/// which is important to make the code generation deterministic. +pub(crate) fn read_dir

(path: P) -> std::io::Result> +where + P: AsRef, +{ + let mut entries = fs::read_dir(path)? + .map(|entry| Ok(entry?.path())) + .collect::>>()?; + + entries.sort(); + + Ok(entries) +} + /// Take a type and create an immutable shared reference to that type. pub(crate) fn shared_ref(ty: syn::Type, mutable: bool) -> syn::Type { syn::TypeReference { @@ -81,16 +104,18 @@ } /// Map a webidl const value to the correct wasm-bindgen const value -pub fn webidl_const_v_to_backend_const_v(v: &ConstValue) -> ast::ConstValue { +pub fn webidl_const_v_to_backend_const_v(v: &ConstValue) -> InterfaceConstValue { use std::f64::{INFINITY, NAN, NEG_INFINITY}; match *v { - ConstValue::Boolean(b) => ast::ConstValue::BooleanLiteral(b.0), - ConstValue::Float(FloatLit::NegInfinity(_)) => ast::ConstValue::FloatLiteral(NEG_INFINITY), - ConstValue::Float(FloatLit::Infinity(_)) => ast::ConstValue::FloatLiteral(INFINITY), - ConstValue::Float(FloatLit::NaN(_)) => ast::ConstValue::FloatLiteral(NAN), + ConstValue::Boolean(b) => InterfaceConstValue::BooleanLiteral(b.0), + ConstValue::Float(FloatLit::NegInfinity(_)) => { + InterfaceConstValue::FloatLiteral(NEG_INFINITY) + } + ConstValue::Float(FloatLit::Infinity(_)) => InterfaceConstValue::FloatLiteral(INFINITY), + ConstValue::Float(FloatLit::NaN(_)) => InterfaceConstValue::FloatLiteral(NAN), ConstValue::Float(FloatLit::Value(s)) => { - ast::ConstValue::FloatLiteral(s.0.parse().unwrap()) + InterfaceConstValue::FloatLiteral(s.0.parse().unwrap()) } ConstValue::Integer(lit) => { let mklit = |orig_text: &str, base: u32, offset: usize| { @@ -100,7 +125,7 @@ (false, orig_text) }; if text == "0" { - return ast::ConstValue::SignedIntegerLiteral(0); + return InterfaceConstValue::SignedIntegerLiteral(0); } let text = &text[offset..]; let n = u64::from_str_radix(text, base) @@ -111,9 +136,9 @@ } else { n.wrapping_neg() as i64 }; - ast::ConstValue::SignedIntegerLiteral(n) + InterfaceConstValue::SignedIntegerLiteral(n) } else { - ast::ConstValue::UnsignedIntegerLiteral(n) + InterfaceConstValue::UnsignedIntegerLiteral(n) } }; match lit { @@ -122,55 +147,10 @@ IntegerLit::Dec(h) => mklit(h.0, 10, 0), } } - ConstValue::Null(_) => ast::ConstValue::Null, - } -} - -/// From `ident` and `Ty`, create `ident: Ty` for use in e.g. `fn(ident: Ty)`. -fn simple_fn_arg(ident: Ident, ty: syn::Type) -> syn::PatType { - syn::PatType { - pat: Box::new(syn::Pat::Ident(syn::PatIdent { - attrs: Vec::new(), - by_ref: None, - ident, - mutability: None, - subpat: None, - })), - colon_token: Default::default(), - ty: Box::new(ty), - attrs: Vec::new(), + ConstValue::Null(_) => unimplemented!(), } } -/// Create `()`. -fn unit_ty() -> syn::Type { - syn::Type::Tuple(syn::TypeTuple { - paren_token: Default::default(), - elems: syn::punctuated::Punctuated::new(), - }) -} - -/// From `T` create `Result`. -fn result_ty(t: syn::Type) -> syn::Type { - let js_value = leading_colon_path_ty(vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")]); - - let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { - colon2_token: None, - lt_token: Default::default(), - args: FromIterator::from_iter(vec![ - syn::GenericArgument::Type(t), - syn::GenericArgument::Type(js_value), - ]), - gt_token: Default::default(), - }); - - let ident = raw_ident("Result"); - let seg = syn::PathSegment { ident, arguments }; - let path: syn::Path = seg.into(); - let ty = syn::TypePath { qself: None, path }; - ty.into() -} - /// From `T` create `[T]`. pub(crate) fn slice_ty(t: syn::Type) -> syn::Type { syn::TypeSlice { @@ -220,201 +200,16 @@ } impl<'src> FirstPassRecord<'src> { - pub fn create_one_function<'a>( - &self, - js_name: &str, - rust_name: &str, - idl_arguments: impl Iterator)>, - ret: &IdlType<'src>, - kind: ast::ImportFunctionKind, - structural: bool, - catch: bool, - variadic: bool, - doc_comment: Option, - ) -> Option - where - 'src: 'a, - { - // Convert all of the arguments from their IDL type to a `syn` type, - // ready to pass to the backend. - // - // Note that for non-static methods we add a `&self` type placeholder, - // but this type isn't actually used so it's just here for show mostly. - let mut arguments = if let &ast::ImportFunctionKind::Method { - ref ty, - kind: - ast::MethodKind::Operation(ast::Operation { - is_static: false, .. - }), - .. - } = &kind - { - let mut res = Vec::with_capacity(idl_arguments.size_hint().0 + 1); - res.push(simple_fn_arg( - raw_ident("self_"), - shared_ref(ty.clone(), false), - )); - res - } else { - Vec::with_capacity(idl_arguments.size_hint().0) - }; - let idl_arguments: Vec<_> = idl_arguments.collect(); - let arguments_count = idl_arguments.len(); - for (i, (argument_name, idl_type)) in idl_arguments.into_iter().enumerate() { - let syn_type = match idl_type.to_syn_type(TypePosition::Argument) { - Some(t) => t, - None => { - log::warn!( - "Unsupported argument type: {:?} on {:?}", - idl_type, - rust_name - ); - return None; - } - }; - let syn_type = if variadic && i == arguments_count - 1 { - let path = vec![rust_ident("js_sys"), rust_ident("Array")]; - shared_ref(leading_colon_path_ty(path), false) - } else { - syn_type - }; - let argument_name = rust_ident(&argument_name.to_snake_case()); - arguments.push(simple_fn_arg(argument_name, syn_type)); - } - - // Convert the return type to a `syn` type, handling the `catch` - // attribute here to use a `Result` in Rust. - let ret = match ret { - IdlType::Void => None, - ret @ _ => match ret.to_syn_type(TypePosition::Return) { - Some(ret) => Some(ret), - None => { - log::warn!("Unsupported return type: {:?} on {:?}", ret, rust_name); - return None; - } - }, - }; - let js_ret = ret.clone(); - let ret = if catch { - Some(ret.map_or_else(|| result_ty(unit_ty()), result_ty)) - } else { - ret - }; - - Some(ast::ImportFunction { - function: ast::Function { - name: js_name.to_string(), - name_span: Span::call_site(), - renamed_via_js_name: false, - arguments, - ret: ret.clone(), - rust_attrs: vec![], - rust_vis: public(), - r#async: false, - }, - rust_name: rust_ident(rust_name), - js_ret: js_ret.clone(), - variadic, - catch, - structural, - assert_no_shim: false, - shim: { - let ns = match kind { - ast::ImportFunctionKind::Normal => "", - ast::ImportFunctionKind::Method { ref class, .. } => class, - }; - raw_ident(&format!("__widl_f_{}_{}", rust_name, ns)) - }, - kind, - doc_comment, - }) - } - - /// Create a wasm-bindgen getter method, if possible. - pub fn create_getter( - &self, - name: &str, - ty: &weedle::types::Type<'src>, - self_name: &str, - is_static: bool, - attrs: &Option, - container_attrs: Option<&ExtendedAttributeList>, - ) -> Option { - let kind = ast::OperationKind::Getter(Some(raw_ident(name))); - let kind = self.import_function_kind(self_name, is_static, kind); - let ret = ty.to_idl_type(self); - self.create_one_function( - &name, - &snake_case_ident(name), - None.into_iter(), - &ret, - kind, - is_structural(attrs.as_ref(), container_attrs), - throws(attrs), - false, - Some(format!( - "The `{}` getter\n\n{}", - name, - mdn_doc(self_name, Some(name)) - )), - ) - } - - /// Create a wasm-bindgen setter method, if possible. - pub fn create_setter( - &self, - name: &str, - field_ty: &weedle::types::Type<'src>, - self_name: &str, - is_static: bool, - attrs: &Option, - container_attrs: Option<&ExtendedAttributeList>, - ) -> Option { - let kind = ast::OperationKind::Setter(Some(raw_ident(name))); - let kind = self.import_function_kind(self_name, is_static, kind); - let field_ty = field_ty.to_idl_type(self); - self.create_one_function( - &name, - &format!("set_{}", name).to_snake_case(), - Some((name, &field_ty)).into_iter(), - &IdlType::Void, - kind, - is_structural(attrs.as_ref(), container_attrs), - throws(attrs), - false, - Some(format!( - "The `{}` setter\n\n{}", - name, - mdn_doc(self_name, Some(name)) - )), - ) - } - - pub fn import_function_kind( - &self, - self_name: &str, - is_static: bool, - operation_kind: ast::OperationKind, - ) -> ast::ImportFunctionKind { - let operation = ast::Operation { - is_static, - kind: operation_kind, - }; - let ty = ident_ty(rust_ident(camel_case_ident(&self_name).as_str())); - ast::ImportFunctionKind::Method { - class: self_name.to_string(), - ty, - kind: ast::MethodKind::Operation(operation), - } - } - pub fn create_imports( &self, container_attrs: Option<&ExtendedAttributeList<'src>>, - kind: ast::ImportFunctionKind, id: &OperationId<'src>, data: &OperationData<'src>, - ) -> Vec { + unstable: bool, + unstable_types: &HashSet, + ) -> Vec { + let is_static = data.is_static; + // First up, prune all signatures that reference unsupported arguments. // We won't consider these until said arguments are implemented. // @@ -492,7 +287,7 @@ } } - let (name, force_structural, force_throws) = match id { + let (name, kind, force_structural, force_throws) = match id { // Constructors aren't annotated with `[Throws]` extended attributes // (how could they be, since they themselves are extended // attributes?) so we must conservatively assume that they can @@ -505,15 +300,29 @@ // > value of a type corresponding to the interface the // > `[Constructor]` extended attribute appears on, **or throw an // > exception**. - OperationId::Constructor(_) => ("new", false, true), - OperationId::Operation(Some(s)) => (*s, false, false), + OperationId::Constructor(_) => { + ("new", InterfaceMethodKind::Constructor(None), false, true) + } + OperationId::NamedConstructor(n) => ( + "new", + InterfaceMethodKind::Constructor(Some(n.0.to_string())), + false, + true, + ), + OperationId::Operation(Some(s)) => (*s, InterfaceMethodKind::Regular, false, false), OperationId::Operation(None) => { log::warn!("unsupported unnamed operation"); return Vec::new(); } - OperationId::IndexingGetter => ("get", true, false), - OperationId::IndexingSetter => ("set", true, false), - OperationId::IndexingDeleter => ("delete", true, false), + OperationId::IndexingGetter => { + ("get", InterfaceMethodKind::IndexingGetter, true, false) + } + OperationId::IndexingSetter => { + ("set", InterfaceMethodKind::IndexingSetter, true, false) + } + OperationId::IndexingDeleter => { + ("delete", InterfaceMethodKind::IndexingDeleter, true, false) + } }; let mut ret = Vec::new(); @@ -603,49 +412,94 @@ .last() .map(|arg| arg.variadic) .unwrap_or(false); - ret.extend( - self.create_one_function( - name, - &rust_name, - signature - .args - .iter() - .zip(&signature.orig.args) - .map(|(idl_type, orig_arg)| (orig_arg.name, idl_type)), - &ret_ty, - kind.clone(), - structural, - catch, - variadic, - None, - ), + + fn idl_arguments<'a>( + args: impl Iterator)>, + ) -> Option> { + let mut output = vec![]; + + for (name, idl_type) in args { + let ty = match idl_type.to_syn_type(TypePosition::Argument) { + Ok(ty) => ty.unwrap(), + Err(_) => { + return None; + } + }; + + output.push((rust_ident(&snake_case_ident(&name[..])), ty)); + } + + Some(output) + } + + let arguments = idl_arguments( + signature + .args + .iter() + .zip(&signature.orig.args) + .map(|(idl_type, orig_arg)| (orig_arg.name.to_string(), idl_type)), ); + + // Stable types can have methods that have unstable argument types. + // If any of the arguments types are `unstable` then this method is downgraded + // to be unstable. + let unstable_override = match unstable { + // only downgrade stable methods + false => signature + .orig + .args + .iter() + .any(|arg| is_type_unstable(arg.ty, unstable_types)), + true => true, + }; + + if let Some(arguments) = arguments { + if let Ok(ret_ty) = ret_ty.to_syn_type(TypePosition::Return) { + ret.push(InterfaceMethod { + name: rust_ident(&rust_name), + js_name: name.to_string(), + arguments, + ret_ty, + kind: kind.clone(), + is_static, + structural, + catch, + variadic, + unstable: unstable_override, + }); + } + } + if !variadic { continue; } let last_idl_type = &signature.args[signature.args.len() - 1]; let last_name = signature.orig.args[signature.args.len() - 1].name; for i in 0..=MAX_VARIADIC_ARGUMENTS_COUNT { - ret.extend( - self.create_one_function( - name, - &format!("{}_{}", rust_name, i), - signature.args[..signature.args.len() - 1] - .iter() - .zip(&signature.orig.args) - .map(|(idl_type, orig_arg)| (orig_arg.name.to_string(), idl_type)) - .chain((1..=i).map(|j| (format!("{}_{}", last_name, j), last_idl_type))) - .collect::>() - .iter() - .map(|(name, idl_type)| (&name[..], idl_type.clone())), - &ret_ty, - kind.clone(), - structural, - catch, - false, - None, - ), + let arguments = idl_arguments( + signature.args[..signature.args.len() - 1] + .iter() + .zip(&signature.orig.args) + .map(|(idl_type, orig_arg)| (orig_arg.name.to_string(), idl_type)) + .chain((1..=i).map(|j| (format!("{}_{}", last_name, j), last_idl_type))), ); + + if let Some(arguments) = arguments { + if let Ok(ret_ty) = ret_ty.to_syn_type(TypePosition::Return) { + ret.push(InterfaceMethod { + name: rust_ident(&format!("{}_{}", rust_name, i)), + js_name: name.to_string(), + arguments, + kind: kind.clone(), + ret_ty, + is_static, + structural, + catch, + variadic: false, + unstable: unstable_override, + }); + } + } } } return ret; @@ -664,10 +518,11 @@ fn maybe_adjust<'a>(&self, mut idl_type: IdlType<'a>, id: &'a OperationId) -> IdlType<'a> { let op = match id { OperationId::Operation(Some(op)) => op, + OperationId::Constructor(Some(op)) => op, _ => return idl_type, }; - if self.immutable_slice_whitelist.contains(op) { + if IMMUTABLE_SLICE_WHITELIST.contains(op) { flag_slices_immutable(&mut idl_type) } @@ -675,6 +530,16 @@ } } +pub fn is_type_unstable(ty: &weedle::types::Type, unstable_types: &HashSet) -> bool { + match ty { + weedle::types::Type::Single(SingleType::NonAny(NonAnyType::Identifier(i))) => { + // Check if the type in the unstable type list + unstable_types.contains(&i.type_) + } + _ => false, + } +} + /// Search for an attribute by name in some webidl object's attributes. fn has_named_attribute(list: Option<&ExtendedAttributeList>, attribute: &str) -> bool { let list = match list { @@ -746,13 +611,6 @@ has_named_attribute(attrs.as_ref(), "Throws") } -/// Create a syn `pub` token -pub fn public() -> syn::Visibility { - syn::Visibility::Public(syn::VisPublic { - pub_token: Default::default(), - }) -} - fn flag_slices_immutable(ty: &mut IdlType) { match ty { IdlType::Int8Array { immutable } @@ -783,3 +641,39 @@ _ => {} } } + +pub fn required_doc_string(options: &Options, features: &BTreeSet) -> Option { + if !options.features || features.len() == 0 { + return None; + } + let list = features + .iter() + .map(|ident| format!("`{}`", ident)) + .collect::>() + .join(", "); + Some(format!( + "\n\n*This API requires the following crate features \ + to be activated: {}*", + list, + )) +} + +pub fn get_cfg_features(options: &Options, features: &BTreeSet) -> Option { + let len = features.len(); + + if !options.features || len == 0 { + None + } else { + let features = features + .into_iter() + .map(|feature| quote!( feature = #feature, )) + .collect::(); + + // This is technically unneeded but it generates more idiomatic code + if len == 1 { + Some(syn::parse_quote!( #[cfg(#features)] )) + } else { + Some(syn::parse_quote!( #[cfg(all(#features))] )) + } + } +}