mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-18 23:41:24 +00:00
Dramatically improving the build time of web-sys (#2012)
* Pre-generating web-sys * Fixing build errors * Minor refactor for the unit tests * Changing to generate #[wasm_bindgen} annotations * Fixing code generation * Adding in main bin to wasm-bindgen-webidl * Fixing more problems * Adding in support for unstable APIs * Fixing bug with code generation * More code generation fixes * Improving the webidl program * Removing unnecessary cfg from the generated code * Splitting doc comments onto separate lines * Improving the generation for unstable features * Adding in support for string values in enums * Now runs rustfmt on the mod.rs file * Fixing codegen for constructors * Fixing webidl-tests * Fixing build errors * Another fix for build errors * Renaming typescript_name to typescript_type * Adding in docs for typescript_type * Adding in CI script to verify that web-sys is up to date * Fixing CI script * Fixing CI script * Don't suppress git diff output * Remove duplicate definitions of `Location` Looks to be a preexisting bug in wasm-bindgen? * Regenerate webidl * Try to get the git diff command right * Handle named constructors in WebIDL * Remove stray rustfmt.toml * Add back NamedConstructorBar definition in tests * Run stable rustfmt over everything * Don't run Cargo in a build script Instead refactor things so webidl-tests can use the Rust-code-generation as a library in a build script. Also fixes `cargo fmt` in the repository. * Fixup generated code * Running web-sys checks on stable * Improving the code generation a little * Running rustfmt Co-authored-by: Alex Crichton <alex@alexcrichton.com>
This commit is contained in:
@ -17,18 +17,24 @@ pub struct Program {
|
||||
pub enums: Vec<Enum>,
|
||||
/// rust structs
|
||||
pub structs: Vec<Struct>,
|
||||
/// rust consts
|
||||
pub consts: Vec<Const>,
|
||||
/// "dictionaries", generated for WebIDL, which are basically just "typed
|
||||
/// objects" in the sense that they represent a JS object with a particular
|
||||
/// shape in JIT parlance.
|
||||
pub dictionaries: Vec<Dictionary>,
|
||||
/// custom typescript sections to be included in the definition file
|
||||
pub typescript_custom_sections: Vec<String>,
|
||||
/// Inline JS snippets
|
||||
pub inline_js: Vec<String>,
|
||||
}
|
||||
|
||||
impl Program {
|
||||
/// Returns true if the Program is empty
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.exports.is_empty()
|
||||
&& self.imports.is_empty()
|
||||
&& self.enums.is_empty()
|
||||
&& self.structs.is_empty()
|
||||
&& self.typescript_custom_sections.is_empty()
|
||||
&& self.inline_js.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
/// A rust to js interface. Allows interaction with rust objects/functions
|
||||
/// from javascript.
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug))]
|
||||
@ -51,8 +57,6 @@ pub struct Export {
|
||||
/// Whether or not this function should be flagged as the wasm start
|
||||
/// function.
|
||||
pub start: bool,
|
||||
/// Whether the API is unstable. This is only used internally.
|
||||
pub unstable_api: bool,
|
||||
}
|
||||
|
||||
/// The 3 types variations of `self`.
|
||||
@ -73,7 +77,6 @@ pub struct Import {
|
||||
pub module: ImportModule,
|
||||
pub js_namespace: Option<Ident>,
|
||||
pub kind: ImportKind,
|
||||
pub unstable_api: bool,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug))]
|
||||
@ -129,7 +132,6 @@ pub struct ImportFunction {
|
||||
pub kind: ImportFunctionKind,
|
||||
pub shim: Ident,
|
||||
pub doc_comment: Option<String>,
|
||||
pub unstable_api: bool,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||
@ -185,8 +187,7 @@ pub struct ImportType {
|
||||
pub rust_name: Ident,
|
||||
pub js_name: String,
|
||||
pub attrs: Vec<syn::Attribute>,
|
||||
pub typescript_name: Option<String>,
|
||||
pub unstable_api: bool,
|
||||
pub typescript_type: Option<String>,
|
||||
pub doc_comment: Option<String>,
|
||||
pub instanceof_shim: String,
|
||||
pub is_type_of: Option<syn::Expr>,
|
||||
@ -207,8 +208,6 @@ pub struct ImportEnum {
|
||||
pub variant_values: Vec<String>,
|
||||
/// Attributes to apply to the Rust enum
|
||||
pub rust_attrs: Vec<syn::Attribute>,
|
||||
/// Whether the enum is part of an unstable WebIDL
|
||||
pub unstable_api: bool,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug))]
|
||||
@ -244,7 +243,6 @@ pub struct StructField {
|
||||
pub getter: Ident,
|
||||
pub setter: Ident,
|
||||
pub comments: Vec<String>,
|
||||
pub unstable_api: bool,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||
@ -254,7 +252,6 @@ pub struct Enum {
|
||||
pub variants: Vec<Variant>,
|
||||
pub comments: Vec<String>,
|
||||
pub hole: u32,
|
||||
pub unstable_api: bool,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||
@ -279,49 +276,6 @@ pub enum TypeLocation {
|
||||
ExportRet,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq))]
|
||||
#[derive(Clone)]
|
||||
pub struct Const {
|
||||
pub vis: syn::Visibility,
|
||||
pub name: Ident,
|
||||
pub class: Option<Ident>,
|
||||
pub ty: syn::Type,
|
||||
pub value: ConstValue,
|
||||
pub unstable_api: bool,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq))]
|
||||
#[derive(Clone)]
|
||||
/// same as webidl::ast::ConstValue
|
||||
pub enum ConstValue {
|
||||
BooleanLiteral(bool),
|
||||
FloatLiteral(f64),
|
||||
SignedIntegerLiteral(i64),
|
||||
UnsignedIntegerLiteral(u64),
|
||||
Null,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||
#[derive(Clone)]
|
||||
pub struct Dictionary {
|
||||
pub name: Ident,
|
||||
pub fields: Vec<DictionaryField>,
|
||||
pub ctor: bool,
|
||||
pub doc_comment: Option<String>,
|
||||
pub ctor_doc_comment: Option<String>,
|
||||
pub unstable_api: bool,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||
#[derive(Clone)]
|
||||
pub struct DictionaryField {
|
||||
pub rust_name: Ident,
|
||||
pub js_name: String,
|
||||
pub required: bool,
|
||||
pub ty: syn::Type,
|
||||
pub doc_comment: Option<String>,
|
||||
}
|
||||
|
||||
impl Export {
|
||||
/// Mangles a rust -> javascript export, so that the created Ident will be unique over function
|
||||
/// name and class name, if the function belongs to a javascript class.
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::ast;
|
||||
use crate::encode;
|
||||
use crate::util::{self, ShortHash};
|
||||
use crate::util::ShortHash;
|
||||
use crate::Diagnostic;
|
||||
use proc_macro2::{Ident, Literal, Span, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
@ -39,11 +39,7 @@ impl TryToTokens for ast::Program {
|
||||
}
|
||||
}
|
||||
for i in self.imports.iter() {
|
||||
DescribeImport {
|
||||
kind: &i.kind,
|
||||
unstable_api: i.unstable_api,
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
DescribeImport { kind: &i.kind }.to_tokens(tokens);
|
||||
|
||||
// If there is a js namespace, check that name isn't a type. If it is,
|
||||
// this import might be a method on that type.
|
||||
@ -68,12 +64,6 @@ impl TryToTokens for ast::Program {
|
||||
for e in self.enums.iter() {
|
||||
e.to_tokens(tokens);
|
||||
}
|
||||
for c in self.consts.iter() {
|
||||
c.to_tokens(tokens);
|
||||
}
|
||||
for d in self.dictionaries.iter() {
|
||||
d.to_tokens(tokens);
|
||||
}
|
||||
|
||||
Diagnostic::from_vec(errors)?;
|
||||
|
||||
@ -305,7 +295,7 @@ impl ToTokens for ast::StructField {
|
||||
inner: quote! {
|
||||
<#ty as WasmDescribe>::describe();
|
||||
},
|
||||
unstable_api: self.unstable_api,
|
||||
attrs: vec![],
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
|
||||
@ -542,7 +532,7 @@ impl TryToTokens for ast::Export {
|
||||
#(<#argtys as WasmDescribe>::describe();)*
|
||||
#describe_ret
|
||||
},
|
||||
unstable_api: self.unstable_api,
|
||||
attrs: attrs.clone(),
|
||||
}
|
||||
.to_tokens(into);
|
||||
|
||||
@ -568,7 +558,6 @@ impl ToTokens for ast::ImportType {
|
||||
let vis = &self.vis;
|
||||
let rust_name = &self.rust_name;
|
||||
let attrs = &self.attrs;
|
||||
let unstable_api_attr = util::maybe_unstable_api_attr(self.unstable_api);
|
||||
let doc_comment = match &self.doc_comment {
|
||||
None => "",
|
||||
Some(comment) => comment,
|
||||
@ -586,14 +575,14 @@ impl ToTokens for ast::ImportType {
|
||||
}
|
||||
};
|
||||
|
||||
let description = if let Some(typescript_name) = &self.typescript_name {
|
||||
let typescript_name_len = typescript_name.len() as u32;
|
||||
let typescript_name_chars = typescript_name.chars().map(|c| c as u32);
|
||||
let description = if let Some(typescript_type) = &self.typescript_type {
|
||||
let typescript_type_len = typescript_type.len() as u32;
|
||||
let typescript_type_chars = typescript_type.chars().map(|c| c as u32);
|
||||
quote! {
|
||||
use wasm_bindgen::describe::*;
|
||||
inform(NAMED_ANYREF);
|
||||
inform(#typescript_name_len);
|
||||
#(inform(#typescript_name_chars);)*
|
||||
inform(#typescript_type_len);
|
||||
#(inform(#typescript_type_chars);)*
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
@ -617,14 +606,12 @@ impl ToTokens for ast::ImportType {
|
||||
#[doc = #doc_comment]
|
||||
#[repr(transparent)]
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
#vis struct #rust_name {
|
||||
obj: #internal_obj
|
||||
}
|
||||
|
||||
#[allow(bad_style)]
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
const #const_name: () = {
|
||||
use wasm_bindgen::convert::{IntoWasmAbi, FromWasmAbi};
|
||||
use wasm_bindgen::convert::{OptionIntoWasmAbi, OptionFromWasmAbi};
|
||||
@ -775,7 +762,6 @@ impl ToTokens for ast::ImportType {
|
||||
for superclass in self.extends.iter() {
|
||||
(quote! {
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl From<#rust_name> for #superclass {
|
||||
#[inline]
|
||||
fn from(obj: #rust_name) -> #superclass {
|
||||
@ -785,7 +771,6 @@ impl ToTokens for ast::ImportType {
|
||||
}
|
||||
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl AsRef<#superclass> for #rust_name {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &#superclass {
|
||||
@ -807,7 +792,6 @@ impl ToTokens for ast::ImportEnum {
|
||||
let variants = &self.variants;
|
||||
let variant_strings = &self.variant_values;
|
||||
let attrs = &self.rust_attrs;
|
||||
let unstable_api_attr = util::maybe_unstable_api_attr(self.unstable_api);
|
||||
|
||||
let mut current_idx: usize = 0;
|
||||
let variant_indexes: Vec<Literal> = variants
|
||||
@ -836,7 +820,6 @@ impl ToTokens for ast::ImportEnum {
|
||||
#[allow(bad_style)]
|
||||
#(#attrs)*
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
#vis enum #name {
|
||||
#(#variants = #variant_indexes_ref,)*
|
||||
#[doc(hidden)]
|
||||
@ -844,69 +827,70 @@ impl ToTokens for ast::ImportEnum {
|
||||
}
|
||||
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl #name {
|
||||
#vis fn from_js_value(obj: &wasm_bindgen::JsValue) -> Option<#name> {
|
||||
obj.as_string().and_then(|obj_str| match obj_str.as_str() {
|
||||
fn from_str(s: &str) -> Option<#name> {
|
||||
match s {
|
||||
#(#variant_strings => Some(#variant_paths_ref),)*
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
#(#variant_paths_ref => #variant_strings,)*
|
||||
#name::__Nonexhaustive => panic!(#expect_string),
|
||||
}
|
||||
}
|
||||
|
||||
#vis fn from_js_value(obj: &wasm_bindgen::JsValue) -> Option<#name> {
|
||||
obj.as_string().and_then(|obj_str| Self::from_str(obj_str.as_str()))
|
||||
}
|
||||
}
|
||||
|
||||
// It should really be using &str for all of these, but that requires some major changes to cli-support
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl wasm_bindgen::describe::WasmDescribe for #name {
|
||||
fn describe() {
|
||||
wasm_bindgen::JsValue::describe()
|
||||
<wasm_bindgen::JsValue as wasm_bindgen::describe::WasmDescribe>::describe()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl wasm_bindgen::convert::IntoWasmAbi for #name {
|
||||
type Abi = <wasm_bindgen::JsValue as
|
||||
wasm_bindgen::convert::IntoWasmAbi>::Abi;
|
||||
type Abi = <wasm_bindgen::JsValue as wasm_bindgen::convert::IntoWasmAbi>::Abi;
|
||||
|
||||
#[inline]
|
||||
fn into_abi(self) -> Self::Abi {
|
||||
wasm_bindgen::JsValue::from(self).into_abi()
|
||||
<wasm_bindgen::JsValue as wasm_bindgen::convert::IntoWasmAbi>::into_abi(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl wasm_bindgen::convert::FromWasmAbi for #name {
|
||||
type Abi = <wasm_bindgen::JsValue as
|
||||
wasm_bindgen::convert::FromWasmAbi>::Abi;
|
||||
type Abi = <wasm_bindgen::JsValue as wasm_bindgen::convert::FromWasmAbi>::Abi;
|
||||
|
||||
unsafe fn from_abi(js: Self::Abi) -> Self {
|
||||
#name::from_js_value(&wasm_bindgen::JsValue::from_abi(js)).unwrap_or(#name::__Nonexhaustive)
|
||||
let s = <wasm_bindgen::JsValue as wasm_bindgen::convert::FromWasmAbi>::from_abi(js);
|
||||
#name::from_js_value(&s).unwrap_or(#name::__Nonexhaustive)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl wasm_bindgen::convert::OptionIntoWasmAbi for #name {
|
||||
#[inline]
|
||||
fn none() -> Self::Abi { Object::none() }
|
||||
fn none() -> Self::Abi { <::js_sys::Object as wasm_bindgen::convert::OptionIntoWasmAbi>::none() }
|
||||
}
|
||||
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl wasm_bindgen::convert::OptionFromWasmAbi for #name {
|
||||
#[inline]
|
||||
fn is_none(abi: &Self::Abi) -> bool { Object::is_none(abi) }
|
||||
fn is_none(abi: &Self::Abi) -> bool { <::js_sys::Object as wasm_bindgen::convert::OptionFromWasmAbi>::is_none(abi) }
|
||||
}
|
||||
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl From<#name> for wasm_bindgen::JsValue {
|
||||
fn from(obj: #name) -> wasm_bindgen::JsValue {
|
||||
match obj {
|
||||
#(#variant_paths_ref => wasm_bindgen::JsValue::from_str(#variant_strings),)*
|
||||
#name::__Nonexhaustive => panic!(#expect_string),
|
||||
}
|
||||
wasm_bindgen::JsValue::from(obj.to_str())
|
||||
}
|
||||
}
|
||||
}).to_tokens(tokens);
|
||||
@ -1012,7 +996,6 @@ impl TryToTokens for ast::ImportFunction {
|
||||
let arguments = &arguments;
|
||||
let abi_arguments = &abi_arguments;
|
||||
let abi_argument_names = &abi_argument_names;
|
||||
let unstable_api_attr = util::maybe_unstable_api_attr(self.unstable_api);
|
||||
|
||||
let doc_comment = match &self.doc_comment {
|
||||
None => "",
|
||||
@ -1041,6 +1024,7 @@ impl TryToTokens for ast::ImportFunction {
|
||||
// the best we can in the meantime.
|
||||
let extern_fn = respan(
|
||||
quote! {
|
||||
#(#attrs)*
|
||||
#[link(wasm_import_module = "__wbindgen_placeholder__")]
|
||||
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
|
||||
extern "C" {
|
||||
@ -1079,7 +1063,6 @@ impl TryToTokens for ast::ImportFunction {
|
||||
|
||||
if let Some(class) = class_ty {
|
||||
(quote! {
|
||||
#unstable_api_attr
|
||||
impl #class {
|
||||
#invocation
|
||||
}
|
||||
@ -1096,7 +1079,6 @@ impl TryToTokens for ast::ImportFunction {
|
||||
// See comment above in ast::Export for what's going on here.
|
||||
struct DescribeImport<'a> {
|
||||
kind: &'a ast::ImportKind,
|
||||
unstable_api: bool,
|
||||
}
|
||||
|
||||
impl<'a> ToTokens for DescribeImport<'a> {
|
||||
@ -1123,7 +1105,7 @@ impl<'a> ToTokens for DescribeImport<'a> {
|
||||
#(<#argtys as WasmDescribe>::describe();)*
|
||||
#inform_ret
|
||||
},
|
||||
unstable_api: self.unstable_api,
|
||||
attrs: f.function.rust_attrs.clone(),
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
@ -1133,7 +1115,6 @@ impl ToTokens for ast::Enum {
|
||||
fn to_tokens(&self, into: &mut TokenStream) {
|
||||
let enum_name = &self.name;
|
||||
let hole = &self.hole;
|
||||
let unstable_api_attr = util::maybe_unstable_api_attr(self.unstable_api);
|
||||
let cast_clauses = self.variants.iter().map(|variant| {
|
||||
let variant_name = &variant.name;
|
||||
quote! {
|
||||
@ -1144,7 +1125,6 @@ impl ToTokens for ast::Enum {
|
||||
});
|
||||
(quote! {
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl wasm_bindgen::convert::IntoWasmAbi for #enum_name {
|
||||
type Abi = u32;
|
||||
|
||||
@ -1155,7 +1135,6 @@ impl ToTokens for ast::Enum {
|
||||
}
|
||||
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl wasm_bindgen::convert::FromWasmAbi for #enum_name {
|
||||
type Abi = u32;
|
||||
|
||||
@ -1168,21 +1147,18 @@ impl ToTokens for ast::Enum {
|
||||
}
|
||||
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl wasm_bindgen::convert::OptionFromWasmAbi for #enum_name {
|
||||
#[inline]
|
||||
fn is_none(val: &u32) -> bool { *val == #hole }
|
||||
}
|
||||
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl wasm_bindgen::convert::OptionIntoWasmAbi for #enum_name {
|
||||
#[inline]
|
||||
fn none() -> Self::Abi { #hole }
|
||||
}
|
||||
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl wasm_bindgen::describe::WasmDescribe for #enum_name {
|
||||
fn describe() {
|
||||
use wasm_bindgen::describe::*;
|
||||
@ -1233,259 +1209,18 @@ impl ToTokens for ast::ImportStatic {
|
||||
inner: quote! {
|
||||
<#ty as WasmDescribe>::describe();
|
||||
},
|
||||
unstable_api: false,
|
||||
attrs: vec![],
|
||||
}
|
||||
.to_tokens(into);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ast::Const {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
use crate::ast::ConstValue::*;
|
||||
|
||||
let vis = &self.vis;
|
||||
let name = &self.name;
|
||||
let ty = &self.ty;
|
||||
let unstable_api_attr = util::maybe_unstable_api_attr(self.unstable_api);
|
||||
|
||||
let value: TokenStream = match self.value {
|
||||
BooleanLiteral(false) => quote!(false),
|
||||
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)
|
||||
}
|
||||
Null => unimplemented!(),
|
||||
};
|
||||
|
||||
let declaration = quote!(#vis const #name: #ty = #value as #ty;);
|
||||
|
||||
if let Some(class) = &self.class {
|
||||
(quote! {
|
||||
#unstable_api_attr
|
||||
impl #class {
|
||||
#declaration
|
||||
}
|
||||
})
|
||||
.to_tokens(tokens);
|
||||
} else {
|
||||
declaration.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ast::Dictionary {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let unstable_api_attr = util::maybe_unstable_api_attr(self.unstable_api);
|
||||
let name = &self.name;
|
||||
let mut methods = TokenStream::new();
|
||||
for field in self.fields.iter() {
|
||||
field.to_tokens(&mut methods);
|
||||
}
|
||||
let required_names = &self
|
||||
.fields
|
||||
.iter()
|
||||
.filter(|f| f.required)
|
||||
.map(|f| &f.rust_name)
|
||||
.collect::<Vec<_>>();
|
||||
let required_types = &self
|
||||
.fields
|
||||
.iter()
|
||||
.filter(|f| f.required)
|
||||
.map(|f| &f.ty)
|
||||
.collect::<Vec<_>>();
|
||||
let required_names2 = required_names;
|
||||
let required_names3 = required_names;
|
||||
let doc_comment = match &self.doc_comment {
|
||||
None => "",
|
||||
Some(doc_string) => doc_string,
|
||||
};
|
||||
|
||||
let ctor = if self.ctor {
|
||||
let doc_comment = match &self.ctor_doc_comment {
|
||||
None => "",
|
||||
Some(doc_string) => doc_string,
|
||||
};
|
||||
quote! {
|
||||
#[doc = #doc_comment]
|
||||
pub fn new(#(#required_names: #required_types),*) -> #name {
|
||||
let mut _ret = #name { obj: ::js_sys::Object::new() };
|
||||
#(_ret.#required_names2(#required_names3);)*
|
||||
return _ret
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
let const_name = Ident::new(&format!("_CONST_{}", name), Span::call_site());
|
||||
(quote! {
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(transparent)]
|
||||
#[allow(clippy::all)]
|
||||
#[doc = #doc_comment]
|
||||
#unstable_api_attr
|
||||
pub struct #name {
|
||||
obj: ::js_sys::Object,
|
||||
}
|
||||
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
impl #name {
|
||||
#ctor
|
||||
#methods
|
||||
}
|
||||
|
||||
#[allow(bad_style)]
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
const #const_name: () = {
|
||||
use js_sys::Object;
|
||||
use wasm_bindgen::describe::WasmDescribe;
|
||||
use wasm_bindgen::convert::*;
|
||||
use wasm_bindgen::{JsValue, JsCast};
|
||||
use wasm_bindgen::__rt::core::mem::ManuallyDrop;
|
||||
|
||||
// interop w/ JsValue
|
||||
impl From<#name> for JsValue {
|
||||
#[inline]
|
||||
fn from(val: #name) -> JsValue {
|
||||
val.obj.into()
|
||||
}
|
||||
}
|
||||
impl AsRef<JsValue> for #name {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &JsValue { self.obj.as_ref() }
|
||||
}
|
||||
|
||||
// Boundary conversion impls
|
||||
impl WasmDescribe for #name {
|
||||
fn describe() {
|
||||
Object::describe();
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoWasmAbi for #name {
|
||||
type Abi = <Object as IntoWasmAbi>::Abi;
|
||||
#[inline]
|
||||
fn into_abi(self) -> Self::Abi {
|
||||
self.obj.into_abi()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoWasmAbi for &'a #name {
|
||||
type Abi = <&'a Object as IntoWasmAbi>::Abi;
|
||||
#[inline]
|
||||
fn into_abi(self) -> Self::Abi {
|
||||
(&self.obj).into_abi()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromWasmAbi for #name {
|
||||
type Abi = <Object as FromWasmAbi>::Abi;
|
||||
#[inline]
|
||||
unsafe fn from_abi(abi: Self::Abi) -> Self {
|
||||
#name { obj: Object::from_abi(abi) }
|
||||
}
|
||||
}
|
||||
|
||||
impl OptionIntoWasmAbi for #name {
|
||||
#[inline]
|
||||
fn none() -> Self::Abi { Object::none() }
|
||||
}
|
||||
impl<'a> OptionIntoWasmAbi for &'a #name {
|
||||
#[inline]
|
||||
fn none() -> Self::Abi { <&'a Object>::none() }
|
||||
}
|
||||
impl OptionFromWasmAbi for #name {
|
||||
#[inline]
|
||||
fn is_none(abi: &Self::Abi) -> bool { Object::is_none(abi) }
|
||||
}
|
||||
|
||||
impl RefFromWasmAbi for #name {
|
||||
type Abi = <Object as RefFromWasmAbi>::Abi;
|
||||
type Anchor = ManuallyDrop<#name>;
|
||||
|
||||
#[inline]
|
||||
unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor {
|
||||
let tmp = <Object as RefFromWasmAbi>::ref_from_abi(js);
|
||||
ManuallyDrop::new(#name {
|
||||
obj: ManuallyDrop::into_inner(tmp),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl JsCast for #name {
|
||||
#[inline]
|
||||
fn instanceof(val: &JsValue) -> bool {
|
||||
Object::instanceof(val)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unchecked_from_js(val: JsValue) -> Self {
|
||||
#name { obj: Object::unchecked_from_js(val) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unchecked_from_js_ref(val: &JsValue) -> &Self {
|
||||
unsafe { &*(val as *const JsValue as *const #name) }
|
||||
}
|
||||
}
|
||||
};
|
||||
})
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ast::DictionaryField {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let rust_name = &self.rust_name;
|
||||
let js_name = &self.js_name;
|
||||
let ty = &self.ty;
|
||||
let doc_comment = match &self.doc_comment {
|
||||
None => "",
|
||||
Some(doc_string) => doc_string,
|
||||
};
|
||||
(quote! {
|
||||
#[allow(clippy::all)]
|
||||
#[doc = #doc_comment]
|
||||
pub fn #rust_name(&mut self, val: #ty) -> &mut Self {
|
||||
use wasm_bindgen::JsValue;
|
||||
let r = ::js_sys::Reflect::set(
|
||||
self.obj.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
|
||||
}
|
||||
}).to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
/// Emits the necessary glue tokens for "descriptor", generating an appropriate
|
||||
/// symbol name as well as attributes around the descriptor function itself.
|
||||
struct Descriptor<'a, T> {
|
||||
ident: &'a Ident,
|
||||
inner: T,
|
||||
unstable_api: bool,
|
||||
attrs: Vec<syn::Attribute>,
|
||||
}
|
||||
|
||||
impl<'a, T: ToTokens> ToTokens for Descriptor<'a, T> {
|
||||
@ -1513,15 +1248,15 @@ impl<'a, T: ToTokens> ToTokens for Descriptor<'a, T> {
|
||||
}
|
||||
|
||||
let name = Ident::new(&format!("__wbindgen_describe_{}", ident), ident.span());
|
||||
let unstable_api_attr = util::maybe_unstable_api_attr(self.unstable_api);
|
||||
let inner = &self.inner;
|
||||
let attrs = &self.attrs;
|
||||
(quote! {
|
||||
#(#attrs)*
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
#[doc(hidden)]
|
||||
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
|
||||
#[allow(clippy::all)]
|
||||
#unstable_api_attr
|
||||
pub extern "C" fn #name() {
|
||||
use wasm_bindgen::describe::*;
|
||||
// See definition of `link_mem_intrinsics` for what this is doing
|
||||
|
@ -1,403 +0,0 @@
|
||||
use crate::ast;
|
||||
use proc_macro2::Ident;
|
||||
use syn;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ImportedTypeKind {
|
||||
/// The definition of an imported type.
|
||||
Definition,
|
||||
/// A reference to an imported type.
|
||||
Reference,
|
||||
}
|
||||
|
||||
impl<T> ImportedTypes for Option<T>
|
||||
where
|
||||
T: ImportedTypes,
|
||||
{
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
if let Some(inner) = self {
|
||||
inner.imported_types(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate over definitions of and references to imported types in the AST.
|
||||
pub trait ImportedTypes {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind);
|
||||
}
|
||||
|
||||
/// Iterate over definitions of imported types in the AST.
|
||||
pub trait ImportedTypeDefinitions {
|
||||
fn imported_type_definitions<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident);
|
||||
}
|
||||
|
||||
impl<T> ImportedTypeDefinitions for T
|
||||
where
|
||||
T: ImportedTypes,
|
||||
{
|
||||
fn imported_type_definitions<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident),
|
||||
{
|
||||
self.imported_types(&mut |id, kind| {
|
||||
if let ImportedTypeKind::Definition = kind {
|
||||
f(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate over references to imported types in the AST.
|
||||
pub trait ImportedTypeReferences {
|
||||
fn imported_type_references<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident);
|
||||
}
|
||||
|
||||
impl<T> ImportedTypeReferences for T
|
||||
where
|
||||
T: ImportedTypes,
|
||||
{
|
||||
fn imported_type_references<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident),
|
||||
{
|
||||
self.imported_types(&mut |id, kind| {
|
||||
if let ImportedTypeKind::Reference = kind {
|
||||
f(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ImportedTypes> ImportedTypes for &'a T {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
(*self).imported_types(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for ast::Program {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
self.imports.imported_types(f);
|
||||
self.consts.imported_types(f);
|
||||
self.dictionaries.imported_types(f);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ImportedTypes for Vec<T>
|
||||
where
|
||||
T: ImportedTypes,
|
||||
{
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
for x in self {
|
||||
x.imported_types(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for ast::Import {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
self.kind.imported_types(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for ast::ImportKind {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
match self {
|
||||
ast::ImportKind::Static(s) => s.imported_types(f),
|
||||
ast::ImportKind::Function(fun) => fun.imported_types(f),
|
||||
ast::ImportKind::Type(ty) => ty.imported_types(f),
|
||||
ast::ImportKind::Enum(enm) => enm.imported_types(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for ast::ImportStatic {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
self.ty.imported_types(f);
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for syn::Type {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
match self {
|
||||
syn::Type::Reference(ref r) => r.imported_types(f),
|
||||
syn::Type::Path(ref p) => p.imported_types(f),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for syn::TypeReference {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
self.elem.imported_types(f);
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for syn::TypePath {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
self.qself.imported_types(f);
|
||||
self.path.imported_types(f);
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for syn::QSelf {
|
||||
fn imported_types<F>(&self, _: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for syn::Path {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
for seg in self.segments.iter() {
|
||||
seg.arguments.imported_types(f);
|
||||
}
|
||||
f(
|
||||
&self.segments.last().unwrap().ident,
|
||||
ImportedTypeKind::Reference,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for syn::PathArguments {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
match self {
|
||||
syn::PathArguments::AngleBracketed(data) => {
|
||||
for arg in data.args.iter() {
|
||||
arg.imported_types(f);
|
||||
}
|
||||
}
|
||||
//TOCHECK
|
||||
syn::PathArguments::Parenthesized(data) => {
|
||||
for input in data.inputs.iter() {
|
||||
input.imported_types(f);
|
||||
}
|
||||
// TODO do we need to handle output here?
|
||||
// https://docs.rs/syn/0.14.0/syn/struct.ParenthesizedGenericArguments.html
|
||||
}
|
||||
syn::PathArguments::None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for syn::GenericArgument {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
match self {
|
||||
syn::GenericArgument::Lifetime(_) => {}
|
||||
syn::GenericArgument::Type(ty) => ty.imported_types(f),
|
||||
syn::GenericArgument::Binding(_) => {} // TODO
|
||||
syn::GenericArgument::Const(_) => {} // TODO
|
||||
syn::GenericArgument::Constraint(_) => {} // TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for ast::ImportFunction {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
self.function.imported_types(f);
|
||||
self.kind.imported_types(f);
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for ast::ImportFunctionKind {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
match self {
|
||||
ast::ImportFunctionKind::Method { ty, .. } => ty.imported_types(f),
|
||||
ast::ImportFunctionKind::Normal => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for ast::Function {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
self.arguments.imported_types(f);
|
||||
if let Some(ref r) = self.ret {
|
||||
r.imported_types(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for syn::FnArg {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
match self {
|
||||
syn::FnArg::Receiver(_) => {}
|
||||
syn::FnArg::Typed(p) => p.imported_types(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for syn::PatType {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
self.ty.imported_types(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for ast::ImportType {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
f(&self.rust_name, ImportedTypeKind::Definition);
|
||||
for class in self.extends.iter() {
|
||||
class.imported_types(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for ast::ImportEnum {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
f(&self.name, ImportedTypeKind::Definition);
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for ast::Const {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
self.ty.imported_types(f);
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for ast::Dictionary {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
f(&self.name, ImportedTypeKind::Definition);
|
||||
for field in self.fields.iter() {
|
||||
field.imported_types(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportedTypes for ast::DictionaryField {
|
||||
fn imported_types<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&Ident, ImportedTypeKind),
|
||||
{
|
||||
self.ty.imported_types(f);
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove any methods, statics, &c, that reference types that are *not*
|
||||
/// defined.
|
||||
pub trait RemoveUndefinedImports {
|
||||
fn remove_undefined_imports<F>(&mut self, is_defined: &F) -> bool
|
||||
where
|
||||
F: Fn(&Ident) -> bool;
|
||||
}
|
||||
|
||||
impl RemoveUndefinedImports for ast::Program {
|
||||
fn remove_undefined_imports<F>(&mut self, is_defined: &F) -> bool
|
||||
where
|
||||
F: Fn(&Ident) -> bool,
|
||||
{
|
||||
let mut changed = self.imports.remove_undefined_imports(is_defined);
|
||||
changed = self.consts.remove_undefined_imports(is_defined) || changed;
|
||||
|
||||
for dictionary in self.dictionaries.iter_mut() {
|
||||
let num_required =
|
||||
|dict: &ast::Dictionary| dict.fields.iter().filter(|f| f.required).count();
|
||||
let before = num_required(dictionary);
|
||||
changed = dictionary.fields.remove_undefined_imports(is_defined) || changed;
|
||||
|
||||
// If a required field was removed we can no longer construct this
|
||||
// dictionary so disable the constructor.
|
||||
if before != num_required(dictionary) {
|
||||
dictionary.ctor = false;
|
||||
}
|
||||
}
|
||||
|
||||
changed
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RemoveUndefinedImports for Vec<T>
|
||||
where
|
||||
T: ImportedTypeReferences,
|
||||
{
|
||||
fn remove_undefined_imports<F>(&mut self, is_defined: &F) -> bool
|
||||
where
|
||||
F: Fn(&Ident) -> bool,
|
||||
{
|
||||
let before = self.len();
|
||||
self.retain(|x| {
|
||||
let mut all_defined = true;
|
||||
x.imported_type_references(&mut |id| {
|
||||
if all_defined {
|
||||
if !is_defined(id) {
|
||||
log::info!("removing due to {} not being defined", id);
|
||||
all_defined = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
all_defined
|
||||
});
|
||||
before != self.len()
|
||||
}
|
||||
}
|
@ -188,7 +188,6 @@ fn shared_export<'a>(
|
||||
function: shared_function(&export.function, intern),
|
||||
method_kind,
|
||||
start: export.start,
|
||||
unstable_api: export.unstable_api,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,5 @@ mod error;
|
||||
|
||||
pub mod ast;
|
||||
mod codegen;
|
||||
pub mod defined;
|
||||
mod encode;
|
||||
pub mod util;
|
||||
|
@ -113,12 +113,10 @@ pub fn ident_ty(ident: Ident) -> syn::Type {
|
||||
}
|
||||
|
||||
pub fn wrap_import_function(function: ast::ImportFunction) -> ast::Import {
|
||||
let unstable_api = function.unstable_api;
|
||||
ast::Import {
|
||||
module: ast::ImportModule::None,
|
||||
js_namespace: None,
|
||||
kind: ast::ImportKind::Function(function),
|
||||
unstable_api,
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,19 +154,3 @@ impl<T: Hash> fmt::Display for ShortHash<T> {
|
||||
write!(f, "{:016x}", h.finish())
|
||||
}
|
||||
}
|
||||
|
||||
/// Create syn attribute for `#[cfg(web_sys_unstable_apis)]` and a doc comment.
|
||||
pub fn unstable_api_attrs() -> proc_macro2::TokenStream {
|
||||
quote::quote!(
|
||||
#[cfg(web_sys_unstable_apis)]
|
||||
#[doc = "\n\n*This API is unstable and requires `--cfg=web_sys_unstable_apis` to be activated, as [described in the `wasm-bindgen` guide](https://rustwasm.github.io/docs/wasm-bindgen/web-sys/unstable-apis.html)*"]
|
||||
)
|
||||
}
|
||||
|
||||
pub fn maybe_unstable_api_attr(unstable_api: bool) -> Option<proc_macro2::TokenStream> {
|
||||
if unstable_api {
|
||||
Some(unstable_api_attrs())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user