Skip to content

Commit 6ac61b5

Browse files
authored
Merge pull request #1572 from alexcrichton/dictionary-fields
Fix small issues around web-sys dictionaries
2 parents 618b5d3 + 117928f commit 6ac61b5

File tree

4 files changed

+85
-23
lines changed

4 files changed

+85
-23
lines changed

crates/backend/src/ast.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,9 @@ pub enum ConstValue {
292292
pub struct Dictionary {
293293
pub name: Ident,
294294
pub fields: Vec<DictionaryField>,
295+
pub ctor: bool,
296+
pub doc_comment: Option<String>,
297+
pub ctor_doc_comment: Option<String>,
295298
}
296299

297300
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
@@ -301,6 +304,7 @@ pub struct DictionaryField {
301304
pub js_name: String,
302305
pub required: bool,
303306
pub ty: syn::Type,
307+
pub doc_comment: Option<String>,
304308
}
305309

306310
impl Export {

crates/backend/src/codegen.rs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,24 +1281,41 @@ impl ToTokens for ast::Dictionary {
12811281
.collect::<Vec<_>>();
12821282
let required_names2 = required_names;
12831283
let required_names3 = required_names;
1284+
let doc_comment = match &self.doc_comment {
1285+
None => "",
1286+
Some(doc_string) => doc_string,
1287+
};
1288+
1289+
let ctor = if self.ctor {
1290+
let doc_comment = match &self.ctor_doc_comment {
1291+
None => "",
1292+
Some(doc_string) => doc_string,
1293+
};
1294+
quote! {
1295+
#[doc = #doc_comment]
1296+
pub fn new(#(#required_names: #required_types),*) -> #name {
1297+
let mut _ret = #name { obj: ::js_sys::Object::new() };
1298+
#(_ret.#required_names2(#required_names3);)*
1299+
return _ret
1300+
}
1301+
}
1302+
} else {
1303+
quote! {}
1304+
};
12841305

12851306
let const_name = Ident::new(&format!("_CONST_{}", name), Span::call_site());
12861307
(quote! {
12871308
#[derive(Clone, Debug)]
12881309
#[repr(transparent)]
12891310
#[allow(clippy::all)]
1311+
#[doc = #doc_comment]
12901312
pub struct #name {
12911313
obj: ::js_sys::Object,
12921314
}
12931315

12941316
#[allow(clippy::all)]
12951317
impl #name {
1296-
pub fn new(#(#required_names: #required_types),*) -> #name {
1297-
let mut _ret = #name { obj: ::js_sys::Object::new() };
1298-
#(_ret.#required_names2(#required_names3);)*
1299-
return _ret
1300-
}
1301-
1318+
#ctor
13021319
#methods
13031320
}
13041321

@@ -1407,8 +1424,13 @@ impl ToTokens for ast::DictionaryField {
14071424
let rust_name = &self.rust_name;
14081425
let js_name = &self.js_name;
14091426
let ty = &self.ty;
1427+
let doc_comment = match &self.doc_comment {
1428+
None => "",
1429+
Some(doc_string) => doc_string,
1430+
};
14101431
(quote! {
14111432
#[allow(clippy::all)]
1433+
#[doc = #doc_comment]
14121434
pub fn #rust_name(&mut self, val: #ty) -> &mut Self {
14131435
use wasm_bindgen::JsValue;
14141436
let r = ::js_sys::Reflect::set(

crates/backend/src/defined.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -348,25 +348,20 @@ impl RemoveUndefinedImports for ast::Program {
348348
let mut changed = self.imports.remove_undefined_imports(is_defined);
349349
changed = self.consts.remove_undefined_imports(is_defined) || changed;
350350

351-
let mut dictionaries_to_remove = Vec::new();
352-
for (i, dictionary) in self.dictionaries.iter_mut().enumerate() {
351+
for dictionary in self.dictionaries.iter_mut() {
353352
let num_required =
354353
|dict: &ast::Dictionary| dict.fields.iter().filter(|f| f.required).count();
355354
let before = num_required(dictionary);
356355
changed = dictionary.fields.remove_undefined_imports(is_defined) || changed;
356+
357+
// If a required field was removed we can no longer construct this
358+
// dictionary so disable the constructor.
357359
if before != num_required(dictionary) {
358-
log::warn!(
359-
"removing {} due to a required field being removed",
360-
dictionary.name
361-
);
362-
dictionaries_to_remove.push(i);
360+
dictionary.ctor = false;
363361
}
364362
}
365-
for i in dictionaries_to_remove.iter().rev() {
366-
self.dictionaries.swap_remove(*i);
367-
}
368363

369-
changed || dictionaries_to_remove.len() > 0
364+
changed
370365
}
371366
}
372367

crates/webidl/src/lib.rs

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use proc_macro2::{Ident, Span};
2626
use quote::{quote, ToTokens};
2727
use std::collections::{BTreeSet, HashSet};
2828
use std::env;
29+
use std::fmt::Display;
2930
use std::fs;
3031
use std::iter::FromIterator;
3132
use wasm_bindgen_backend::ast;
@@ -313,11 +314,33 @@ impl<'src> FirstPassRecord<'src> {
313314
if !self.append_dictionary_members(def.identifier.0, &mut fields) {
314315
return;
315316
}
317+
let name = rust_ident(&camel_case_ident(def.identifier.0));
318+
let extra_feature = name.to_string();
319+
for field in fields.iter_mut() {
320+
let mut doc_comment = Some(format!(
321+
"Configure the `{}` field of this object\n",
322+
field.js_name,
323+
));
324+
self.append_required_features_doc(&*field, &mut doc_comment, &[&extra_feature]);
325+
field.doc_comment = doc_comment;
326+
}
316327

317-
program.dictionaries.push(ast::Dictionary {
318-
name: rust_ident(&camel_case_ident(def.identifier.0)),
328+
let mut doc_comment = format!("The `{}` dictionary\n", def.identifier.0);
329+
if let Some(s) = self.required_doc_string(vec![name.clone()]) {
330+
doc_comment.push_str(&s);
331+
}
332+
let mut dict = ast::Dictionary {
333+
name,
319334
fields,
320-
});
335+
ctor: true,
336+
doc_comment: Some(doc_comment),
337+
ctor_doc_comment: None,
338+
};
339+
let mut ctor_doc_comment = Some(format!("Construct a new `{}`\n", def.identifier.0));
340+
self.append_required_features_doc(&dict, &mut ctor_doc_comment, &[&extra_feature]);
341+
dict.ctor_doc_comment = ctor_doc_comment;
342+
343+
program.dictionaries.push(dict);
321344
}
322345

323346
fn append_dictionary_members(
@@ -418,6 +441,7 @@ impl<'src> FirstPassRecord<'src> {
418441
rust_name: rust_ident(&snake_case_ident(field.identifier.0)),
419442
js_name: field.identifier.0.to_string(),
420443
ty,
444+
doc_comment: None,
421445
})
422446
}
423447

@@ -739,16 +763,29 @@ impl<'src> FirstPassRecord<'src> {
739763
if required.len() == 0 {
740764
return;
741765
}
742-
let list = required
766+
if let Some(extra) = self.required_doc_string(required) {
767+
doc.push_str(&extra);
768+
}
769+
}
770+
771+
fn required_doc_string<T: Display>(
772+
&self,
773+
features: impl IntoIterator<Item = T>,
774+
) -> Option<String> {
775+
let features = features.into_iter().collect::<Vec<_>>();
776+
if features.len() == 0 {
777+
return None;
778+
}
779+
let list = features
743780
.iter()
744781
.map(|ident| format!("`{}`", ident))
745782
.collect::<Vec<_>>()
746783
.join(", ");
747-
doc.push_str(&format!(
784+
Some(format!(
748785
"\n\n*This API requires the following crate features \
749786
to be activated: {}*",
750787
list,
751-
));
788+
))
752789
}
753790

754791
fn append_callback_interface(
@@ -770,6 +807,7 @@ impl<'src> FirstPassRecord<'src> {
770807
rust_name: rust_ident(&snake_case_ident(identifier)),
771808
js_name: identifier.to_string(),
772809
ty: idl_type::IdlType::Callback.to_syn_type(pos).unwrap(),
810+
doc_comment: None,
773811
});
774812
}
775813
_ => {
@@ -784,6 +822,9 @@ impl<'src> FirstPassRecord<'src> {
784822
program.dictionaries.push(ast::Dictionary {
785823
name: rust_ident(&camel_case_ident(item.definition.identifier.0)),
786824
fields,
825+
ctor: true,
826+
doc_comment: None,
827+
ctor_doc_comment: None,
787828
});
788829
}
789830
}

0 commit comments

Comments
 (0)