Implement WebIDL callback interfaces

This commit implements callback interfaces for WebIDL, the final WebIDL
construct that we were unconditionally ignoring! Callback interfaces are
implemented as dictionaries of callbacks. Single-operation callback interfaces
are also expanded when flattening to accept a `Function` as well, in accordance
with the WebIDL spec.

New features have been added to `web-sys` for all the new callback interface
types. Additionally the `EventTarget.webidl` was tweaked to not have
`EventListener?` as this is required for all functional usage and there's no
need to keep that sort of web browser compat here.

Closes #258
This commit is contained in:
Alex Crichton
2018-09-10 11:16:55 -07:00
parent 2cf82bc0b3
commit 8181f7fa95
9 changed files with 165 additions and 11 deletions

View File

@ -12,6 +12,7 @@ use std::collections::{BTreeMap, BTreeSet};
use proc_macro2::Ident;
use weedle::{DictionaryDefinition, PartialDictionaryDefinition};
use weedle::CallbackInterfaceDefinition;
use weedle::argument::Argument;
use weedle::attribute::*;
use weedle::interface::*;
@ -35,6 +36,7 @@ pub(crate) struct FirstPassRecord<'src> {
pub(crate) includes: BTreeMap<&'src str, BTreeSet<&'src str>>,
pub(crate) dictionaries: BTreeMap<&'src str, DictionaryData<'src>>,
pub(crate) callbacks: BTreeSet<&'src str>,
pub(crate) callback_interfaces: BTreeMap<&'src str, CallbackInterfaceData<'src>>,
}
/// We need to collect interface data during the first pass, to be used later.
@ -64,17 +66,20 @@ pub(crate) struct MixinData<'src> {
/// We need to collect namespace data during the first pass, to be used later.
#[derive(Default)]
pub(crate) struct NamespaceData<'src> {
/// Whether only partial namespaces were encountered
pub(crate) operations: BTreeMap<OperationId<'src>, OperationData<'src>>,
}
#[derive(Default)]
pub(crate) struct DictionaryData<'src> {
/// Whether only partial namespaces were encountered
pub(crate) partials: Vec<&'src PartialDictionaryDefinition<'src>>,
pub(crate) definition: Option<&'src DictionaryDefinition<'src>>,
}
pub(crate) struct CallbackInterfaceData<'src> {
pub(crate) definition: &'src CallbackInterfaceDefinition<'src>,
pub(crate) single_function: bool,
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub(crate) enum OperationId<'src> {
Constructor(IgnoreTraits<&'src str>),
@ -137,12 +142,8 @@ impl<'src> FirstPass<'src, ()> for weedle::Definition<'src> {
PartialNamespace(namespace) => namespace.first_pass(record, ()),
Typedef(typedef) => typedef.first_pass(record, ()),
Callback(callback) => callback.first_pass(record, ()),
CallbackInterface(iface) => iface.first_pass(record, ()),
Implements(_) => Ok(()),
CallbackInterface(..) => {
warn!("Unsupported WebIDL CallbackInterface definition: {:?}", self);
Ok(())
}
}
}
}
@ -690,6 +691,25 @@ impl<'src> FirstPass<'src, ()> for weedle::CallbackDefinition<'src> {
}
}
impl<'src> FirstPass<'src, ()> for weedle::CallbackInterfaceDefinition<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, _: ()) -> Result<()> {
if util::is_chrome_only(&self.attributes) {
return Ok(())
}
if self.inheritance.is_some() {
warn!("skipping callback interface with inheritance: {}",
self.identifier.0);
return Ok(())
}
let data = CallbackInterfaceData {
definition: self,
single_function: self.members.body.len() == 1,
};
record.callback_interfaces.insert(self.identifier.0, data);
Ok(())
}
}
impl<'a> FirstPassRecord<'a> {
pub fn all_superclasses<'me>(&'me self, interface: &str)
-> impl Iterator<Item = String> + 'me