Skip to content

Commit

Permalink
Merge pull request #909 from alexcrichton/fix-webidl
Browse files Browse the repository at this point in the history
Fix our WebIDL for Safari
  • Loading branch information
alexcrichton authored Oct 1, 2018
2 parents 473258f + bb7271a commit 3001d1e
Show file tree
Hide file tree
Showing 13 changed files with 90 additions and 48 deletions.
1 change: 1 addition & 0 deletions crates/web-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions crates/web-sys/webidls/enabled/AudioBufferSourceNode.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
2 changes: 2 additions & 0 deletions crates/web-sys/webidls/enabled/AudioContext.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ interface AudioContext : BaseAudioContext {
[NewObject, Throws]
MediaStreamAudioDestinationNode createMediaStreamDestination();
};

AudioContext includes rustBaseAudioContext;
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions crates/web-sys/webidls/enabled/BaseAudioContext.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions crates/web-sys/webidls/enabled/ConstantSourceNode.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ dictionary ConstantSourceOptions {
interface ConstantSourceNode : AudioScheduledSourceNode {
readonly attribute AudioParam offset;
};

ConstantSourceNode includes rustAudioScheduledSourceNode;
2 changes: 2 additions & 0 deletions crates/web-sys/webidls/enabled/OfflineAudioContext.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ interface OfflineAudioContext : BaseAudioContext {
readonly attribute unsigned long length;
attribute EventHandler oncomplete;
};

OfflineAudioContext includes rustBaseAudioContext;
2 changes: 2 additions & 0 deletions crates/web-sys/webidls/enabled/OscillatorNode.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ interface OscillatorNode : AudioScheduledSourceNode {

void setPeriodicWave(PeriodicWave periodicWave);
};

OscillatorNode includes rustAudioScheduledSourceNode;
3 changes: 3 additions & 0 deletions crates/webidl/src/first_pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>,
Expand Down Expand Up @@ -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() {
Expand Down
26 changes: 18 additions & 8 deletions crates/webidl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -539,6 +536,7 @@ impl<'src> FirstPassRecord<'src> {
self.member_attribute(
program,
name,
data,
member.modifier,
member.readonly.is_some(),
&member.type_,
Expand All @@ -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 {
Expand All @@ -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>,
Expand Down Expand Up @@ -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));
}
}
Expand Down Expand Up @@ -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,
Expand Down
25 changes: 24 additions & 1 deletion crates/webidl/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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>,
Expand Down
2 changes: 0 additions & 2 deletions examples/webaudio/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ features = [
'AudioDestinationNode',
'AudioNode',
'AudioParam',
'AudioScheduledSourceNode',
'BaseAudioContext',
'GainNode',
'OscillatorNode',
'OscillatorType',
Expand Down
56 changes: 19 additions & 37 deletions examples/webaudio/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
///
Expand Down Expand Up @@ -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);
Expand All @@ -76,50 +66,42 @@ 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();

FmOsc {
primary.start()?;
fm_osc.start()?;

Ok(FmOsc {
ctx,
primary,
gain,
fm_gain,
fm_osc,
fm_freq_ratio: 0.0,
fm_gain_ratio: 0.0,
}
})
}

/// Sets the gain for this oscillator, between 0.0 and 1.0.
Expand Down

0 comments on commit 3001d1e

Please sign in to comment.