Merge pull request #909 from alexcrichton/fix-webidl

Fix our WebIDL for Safari
This commit is contained in:
Alex Crichton 2018-10-01 14:40:56 -07:00 committed by GitHub
commit 3001d1e973
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 89 additions and 47 deletions

View File

@ -12,6 +12,7 @@
//! require.
#![doc(html_root_url = "https://docs.rs/web-sys/0.2")]
#![allow(deprecated)]
extern crate js_sys;
extern crate wasm_bindgen;

View File

@ -32,7 +32,12 @@ interface AudioBufferSourceNode : AudioScheduledSourceNode {
attribute double loopStart;
attribute double loopEnd;
attribute EventHandler onended;
[Throws]
void start(optional double when = 0, optional double grainOffset = 0,
optional double grainDuration);
[Throws]
void stop (optional double when = 0);
};

View File

@ -37,3 +37,5 @@ interface AudioContext : BaseAudioContext {
[NewObject, Throws]
MediaStreamAudioDestinationNode createMediaStreamDestination();
};
AudioContext includes rustBaseAudioContext;

View File

@ -10,7 +10,13 @@
* liability, trademark and document use rules apply.
*/
[RustDeprecated="doesn't exist in Safari, use parent class methods instead"]
interface AudioScheduledSourceNode : AudioNode {
};
AudioScheduledSourceNode includes rustAudioScheduledSourceNode;
interface mixin rustAudioScheduledSourceNode {
attribute EventHandler onended;
[Throws]
void start (optional double when = 0);

View File

@ -19,7 +19,13 @@ enum AudioContextState {
"closed"
};
[RustDeprecated="doesn't exist in Safari, use `AudioContext` instead now"]
interface BaseAudioContext : EventTarget {
};
BaseAudioContext includes rustBaseAudioContext;
interface mixin rustBaseAudioContext {
readonly attribute AudioDestinationNode destination;
readonly attribute float sampleRate;
readonly attribute double currentTime;

View File

@ -19,3 +19,5 @@ dictionary ConstantSourceOptions {
interface ConstantSourceNode : AudioScheduledSourceNode {
readonly attribute AudioParam offset;
};
ConstantSourceNode includes rustAudioScheduledSourceNode;

View File

@ -29,3 +29,5 @@ interface OfflineAudioContext : BaseAudioContext {
readonly attribute unsigned long length;
attribute EventHandler oncomplete;
};
OfflineAudioContext includes rustBaseAudioContext;

View File

@ -37,3 +37,5 @@ interface OscillatorNode : AudioScheduledSourceNode {
void setPeriodicWave(PeriodicWave periodicWave);
};
OscillatorNode includes rustAudioScheduledSourceNode;

View File

@ -44,6 +44,7 @@ pub(crate) struct FirstPassRecord<'src> {
pub(crate) struct InterfaceData<'src> {
/// Whether only partial interfaces were encountered
pub(crate) partial: bool,
pub(crate) deprecated: Option<String>,
pub(crate) attributes: Vec<&'src AttributeInterfaceMember<'src>>,
pub(crate) consts: Vec<&'src ConstMember<'src>>,
pub(crate) operations: BTreeMap<OperationId<'src>, OperationData<'src>>,
@ -311,6 +312,8 @@ impl<'src> FirstPass<'src, ()> for weedle::InterfaceDefinition<'src> {
interface_data.partial = false;
interface_data.superclass = self.inheritance.map(|s| s.identifier.0);
interface_data.definition_attributes = self.attributes.as_ref();
interface_data.deprecated = util::get_rust_deprecated(&self.attributes)
.map(|s| s.to_string());
}
if let Some(attrs) = &self.attributes {
for attr in attrs.body.list.iter() {

View File

@ -488,18 +488,15 @@ impl<'src> FirstPassRecord<'src> {
data: &InterfaceData<'src>,
) {
let mut doc_comment = Some(format!("The `{}` object\n\n{}", name, mdn_doc(name, None),));
let derive = syn::Attribute {
pound_token: Default::default(),
style: syn::AttrStyle::Outer,
bracket_token: Default::default(),
path: Ident::new("derive", Span::call_site()).into(),
tts: quote!((Debug, Clone)),
};
let mut attrs = Vec::new();
attrs.push(parse_quote!( #[derive(Debug, Clone)] ));
self.add_deprecated(data, &mut attrs);
let mut import_type = backend::ast::ImportType {
vis: public(),
rust_name: rust_ident(camel_case_ident(name).as_str()),
js_name: name.to_string(),
attrs: vec![derive],
attrs,
doc_comment: None,
instanceof_shim: format!("__widl_instanceof_{}", name),
extends: Vec::new(),
@ -539,6 +536,7 @@ impl<'src> FirstPassRecord<'src> {
self.member_attribute(
program,
name,
data,
member.modifier,
member.readonly.is_some(),
&member.type_,
@ -559,6 +557,7 @@ impl<'src> FirstPassRecord<'src> {
self.member_attribute(
program,
name,
data,
if let Some(s) = member.stringifier {
Some(weedle::interface::StringifierOrInheritOrStatic::Stringifier(s))
} else {
@ -578,6 +577,7 @@ impl<'src> FirstPassRecord<'src> {
&self,
program: &mut backend::ast::Program,
self_name: &'src str,
data: &InterfaceData<'src>,
modifier: Option<weedle::interface::StringifierOrInheritOrStatic>,
readonly: bool,
type_: &'src weedle::types::AttributedType<'src>,
@ -620,6 +620,7 @@ impl<'src> FirstPassRecord<'src> {
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));
}
}
@ -677,10 +678,19 @@ impl<'src> FirstPassRecord<'src> {
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<syn::Attribute>) {
let msg = match &data.deprecated {
Some(s) => s,
None => return,
};
dst.push(parse_quote!( #[deprecated(note = #msg)] ));
}
fn append_required_features_doc(
&self,
item: impl ImportedTypeReferences,

View File

@ -7,7 +7,7 @@ use heck::{CamelCase, ShoutySnakeCase, SnakeCase};
use proc_macro2::{Ident, Span};
use syn;
use weedle;
use weedle::attribute::{ExtendedAttribute, ExtendedAttributeList};
use weedle::attribute::{ExtendedAttribute, ExtendedAttributeList, IdentifierOrString};
use weedle::literal::{ConstValue, FloatLit, IntegerLit};
use first_pass::{FirstPassRecord, OperationData, OperationId, Signature};
@ -666,6 +666,29 @@ pub fn is_no_interface_object(ext_attrs: &Option<ExtendedAttributeList>) -> bool
has_named_attribute(ext_attrs.as_ref(), "NoInterfaceObject")
}
pub fn get_rust_deprecated<'a>(ext_attrs: &Option<ExtendedAttributeList<'a>>)
-> Option<&'a str>
{
ext_attrs.as_ref()?
.body
.list
.iter()
.filter_map(|attr| {
match attr {
ExtendedAttribute::Ident(id) => Some(id),
_ => None,
}
})
.filter_map(|ident| {
match ident.rhs {
IdentifierOrString::String(s) => Some(s),
IdentifierOrString::Identifier(_) => None,
}
})
.next()
.map(|s| s.0)
}
/// Whether a webidl object is marked as structural.
pub fn is_structural(
item_attrs: Option<&ExtendedAttributeList>,

View File

@ -16,8 +16,6 @@ features = [
'AudioDestinationNode',
'AudioNode',
'AudioParam',
'AudioScheduledSourceNode',
'BaseAudioContext',
'GainNode',
'OscillatorNode',
'OscillatorType',

View File

@ -2,9 +2,7 @@ extern crate wasm_bindgen;
extern crate web_sys;
use wasm_bindgen::prelude::*;
use web_sys::{
AudioContext, AudioNode, AudioScheduledSourceNode, BaseAudioContext, OscillatorType,
};
use web_sys::{AudioContext, AudioNode, OscillatorType};
/// Converts a midi note to frequency
///
@ -45,22 +43,14 @@ impl Drop for FmOsc {
#[wasm_bindgen]
impl FmOsc {
#[wasm_bindgen(constructor)]
pub fn new() -> FmOsc {
let ctx = web_sys::AudioContext::new().unwrap();
let primary;
let fm_osc;
let gain;
let fm_gain;
pub fn new() -> Result<FmOsc, JsValue> {
let ctx = web_sys::AudioContext::new()?;
{
let base: &BaseAudioContext = ctx.as_ref();
// Create our web audio objects.
primary = base.create_oscillator().unwrap();
fm_osc = base.create_oscillator().unwrap();
gain = base.create_gain().unwrap();
fm_gain = base.create_gain().unwrap();
}
// Create our web audio objects.
let primary = ctx.create_oscillator()?;
let fm_osc = ctx.create_oscillator()?;
let gain = ctx.create_gain()?;
let fm_gain = ctx.create_gain()?;
// Some initial settings:
primary.set_type(OscillatorType::Sine);
@ -76,42 +66,34 @@ impl FmOsc {
let gain_node: &AudioNode = gain.as_ref();
let fm_osc_node: &AudioNode = fm_osc.as_ref();
let fm_gain_node: &AudioNode = fm_gain.as_ref();
let base: &BaseAudioContext = ctx.as_ref();
let destination = base.destination();
let destination = ctx.destination();
let destination_node: &AudioNode = destination.as_ref();
// Connect the nodes up!
// The primary oscillator is routed through the gain node, so that
// it can control the overall output volume.
primary_node.connect_with_audio_node(gain.as_ref()).unwrap();
primary_node.connect_with_audio_node(gain.as_ref())?;
// Then connect the gain node to the AudioContext destination (aka
// your speakers).
gain_node.connect_with_audio_node(destination_node).unwrap();
gain_node.connect_with_audio_node(destination_node)?;
// The FM oscillator is connected to its own gain node, so it can
// control the amount of modulation.
fm_osc_node
.connect_with_audio_node(fm_gain.as_ref())
.unwrap();
fm_osc_node.connect_with_audio_node(fm_gain.as_ref())?;
// Connect the FM oscillator to the frequency parameter of the main
// oscillator, so that the FM node can modulate its frequency.
fm_gain_node
.connect_with_audio_param(&primary.frequency())
.unwrap();
fm_gain_node.connect_with_audio_param(&primary.frequency())?;
}
// Start the oscillators!
AsRef::<AudioScheduledSourceNode>::as_ref(&primary)
.start()
.unwrap();
AsRef::<AudioScheduledSourceNode>::as_ref(&fm_osc)
.start()
.unwrap();
primary.start()?;
fm_osc.start()?;
FmOsc {
Ok(FmOsc {
ctx,
primary,
gain,
@ -119,7 +101,7 @@ impl FmOsc {
fm_osc,
fm_freq_ratio: 0.0,
fm_gain_ratio: 0.0,
}
})
}
/// Sets the gain for this oscillator, between 0.0 and 1.0.