Skip to content

Commit f4a9989

Browse files
committed
Adding in Cancel and AutoCancel
1 parent 1b1f3ef commit f4a9989

File tree

8 files changed

+103
-39
lines changed

8 files changed

+103
-39
lines changed

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ pub mod web {
207207
};
208208
pub use webapi::cross_origin_setting::CrossOriginSetting;
209209
pub use webapi::date::Date;
210-
pub use webapi::event_target::{IEventTarget, EventTarget, EventListenerHandle};
210+
pub use webapi::event_target::{IEventTarget, EventTarget, EventListener};
211211
pub use webapi::window::RequestAnimationFrameHandle;
212212
pub use webapi::node::{INode, Node, CloneKind};
213213
pub use webapi::element::{IElement, Element};

src/webapi/event_target.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,33 @@ use webcore::value::Reference;
44
use webcore::try_from::TryInto;
55
use webcore::reference_type::ReferenceType;
66
use webapi::event::{ConcreteEvent, IEvent};
7+
use webcore::cancel::{Cancel, AutoCancel};
78
use private::TODO;
89

910
/// A handle to a particular event listener.
10-
pub struct EventListenerHandle {
11+
pub struct EventListener {
1112
event_type: &'static str,
1213
reference: Reference,
1314
listener_reference: Reference
1415
}
1516

16-
impl fmt::Debug for EventListenerHandle {
17+
impl fmt::Debug for EventListener {
1718
fn fmt( &self, formatter: &mut fmt::Formatter ) -> fmt::Result {
18-
write!( formatter, "EventListenerHandle {{ event_type: {}, reference: {:?} }}", self.event_type, self.reference )
19+
write!( formatter, "EventListener {{ event_type: {}, reference: {:?} }}", self.event_type, self.reference )
1920
}
2021
}
2122

22-
impl EventListenerHandle {
23-
/// Removes the handler from the [IEventTarget](trait.IEventTarget.html) on
23+
impl Cancel for EventListener {
24+
/// Removes the listener from the [IEventTarget](trait.IEventTarget.html) on
2425
/// which it was previously registered.
2526
///
2627
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener)
2728
// https://dom.spec.whatwg.org/#ref-for-dom-eventtarget-removeeventlistener%E2%91%A0
28-
pub fn remove( self ) {
29+
fn cancel( &mut self ) {
2930
js! { @(no_return)
30-
var self = @{self.reference};
31-
var event_type = @{self.event_type};
32-
var listener = @{self.listener_reference};
31+
var listener = @{&self.listener_reference};
32+
@{&self.reference}.removeEventListener( @{self.event_type}, listener );
3333
listener.drop();
34-
self.removeEventListener( event_type, listener );
3534
}
3635
}
3736
}
@@ -42,26 +41,27 @@ impl EventListenerHandle {
4241
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)
4342
// https://dom.spec.whatwg.org/#eventtarget
4443
pub trait IEventTarget: ReferenceType {
45-
/// Adds given event handler to the list the list of event listeners for
44+
/// Adds given event handler to the list of event listeners for
4645
/// the specified `EventTarget` on which it's called.
4746
///
4847
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
4948
// https://dom.spec.whatwg.org/#ref-for-dom-eventtarget-addeventlistener%E2%91%A0
50-
fn add_event_listener< T, F >( &self, listener: F ) -> EventListenerHandle
49+
fn add_event_listener< T, F >( &self, listener: F ) -> AutoCancel< EventListener >
5150
where T: ConcreteEvent, F: FnMut( T ) + 'static
5251
{
5352
let reference = self.as_ref();
53+
5454
let listener_reference = js! {
5555
var listener = @{listener};
5656
@{reference}.addEventListener( @{T::EVENT_TYPE}, listener );
5757
return listener;
5858
}.try_into().unwrap();
5959

60-
EventListenerHandle {
60+
AutoCancel::new( EventListener {
6161
event_type: T::EVENT_TYPE,
6262
reference: reference.clone(),
6363
listener_reference: listener_reference
64-
}
64+
} )
6565
}
6666

6767
/// Dispatches an `Event` at this `EventTarget`, invoking the affected event listeners in the

src/webapi/mutation_observer.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use webcore::value::{Reference, Value, ConversionError};
33
use webapi::node_list::NodeList;
44
use webcore::try_from::{TryFrom, TryInto};
55
use webapi::node::{INode, Node};
6+
use webcore::cancel::{Cancel, AutoCancel};
67
use private::TODO;
78

89
/// Provides a way to receive notifications about changes to the DOM.
@@ -62,17 +63,17 @@ impl MutationObserver {
6263
///
6364
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver#Constructor)
6465
// https://dom.spec.whatwg.org/#ref-for-dom-mutationobserver-mutationobserver
65-
pub fn new< F >( callback: F ) -> MutationObserverHandle
66+
pub fn new< F >( callback: F ) -> AutoCancel< MutationObserverHandle >
6667
where F: FnMut( Vec< MutationRecord >, Self ) + 'static {
6768
let callback_reference: Reference = js! ( return @{callback}; ).try_into().unwrap();
6869

69-
MutationObserverHandle {
70+
AutoCancel::new( MutationObserverHandle {
7071
callback_reference: callback_reference.clone(),
7172

7273
mutation_observer: js! (
7374
return new MutationObserver( @{callback_reference} );
7475
).try_into().unwrap(),
75-
}
76+
} )
7677
}
7778

7879
/// Starts observing changes to the `target`.
@@ -159,7 +160,7 @@ impl MutationObserver {
159160
/// This is created by the [`MutationObserver::new`](struct.MutationObserver.html#method.new) method, and
160161
/// it can use the same methods as [`MutationObserver`](struct.MutationObserver.html).
161162
///
162-
/// When the `MutationObserverHandle` is dropped, the [`disconnect`](#method.disconnect)
163+
/// When the `MutationObserverHandle` is cancelled, the [`disconnect`](#method.disconnect)
163164
/// method will automatically be called.
164165
#[ derive( Debug ) ]
165166
pub struct MutationObserverHandle {
@@ -171,14 +172,14 @@ impl std::ops::Deref for MutationObserverHandle {
171172
type Target = MutationObserver;
172173

173174
#[inline]
174-
fn deref(&self) -> &Self::Target {
175+
fn deref( &self ) -> &Self::Target {
175176
&self.mutation_observer
176177
}
177178
}
178179

179-
impl Drop for MutationObserverHandle {
180+
impl Cancel for MutationObserverHandle {
180181
#[inline]
181-
fn drop( &mut self ) {
182+
fn cancel( &mut self ) {
182183
self.disconnect();
183184

184185
js! { @(no_return)

src/webapi/window.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,22 @@ use webapi::location::Location;
77
use webapi::history::History;
88
use webcore::once::Once;
99
use webcore::value::Value;
10+
use webcore::cancel::{Cancel, AutoCancel};
1011

1112
/// A handle to a pending animation frame request.
1213
#[derive(Debug)]
1314
pub struct RequestAnimationFrameHandle(Value);
1415

15-
impl RequestAnimationFrameHandle {
16+
impl Cancel for RequestAnimationFrameHandle {
1617
/// Cancels an animation frame request.
1718
///
1819
/// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelAnimationFrame)
19-
pub fn cancel(self) {
20-
js!{
21-
var val = @{self.0};
20+
fn cancel( &mut self ) {
21+
js! { @(no_return)
22+
var val = @{&self.0};
2223
val.window.cancelAnimationFrame(val.request);
2324
val.callback.drop();
24-
};
25+
}
2526
}
2627
}
2728

@@ -123,13 +124,13 @@ impl Window {
123124
///
124125
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame)
125126
// https://html.spec.whatwg.org/#the-window-object:dom-window-requestanimationframe
126-
pub fn request_animation_frame< F: FnOnce(f64) + 'static>( &self, callback: F) -> RequestAnimationFrameHandle {
127+
pub fn request_animation_frame< F: FnOnce(f64) + 'static>( &self, callback: F) -> AutoCancel< RequestAnimationFrameHandle > {
127128
let values: Value = js!{
128129
var callback = @{Once(callback)};
129130
var request = @{self}.requestAnimationFrame(callback);
130131
return { request: request, callback: callback, window: @{self} };
131132
};
132-
RequestAnimationFrameHandle(values)
133+
AutoCancel::new( RequestAnimationFrameHandle(values) )
133134
}
134135

135136
/// Returns the global [History](struct.History.html) object, which provides methods to

src/webcore/cancel.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use std::ops::{Deref, DerefMut};
2+
3+
4+
pub trait Cancel {
5+
fn cancel( &mut self );
6+
}
7+
8+
9+
#[must_use = "
10+
The AutoCancel will be automatically cancelled when it is dropped.
11+
You probably don't want this to happen.
12+
How to fix this: either use the AutoCancel, or use .leak() which will cause it to not be cancelled (this will leak memory!)
13+
"]
14+
#[derive(Debug)]
15+
pub struct AutoCancel< A: Cancel >( Option< A > );
16+
17+
impl< A: Cancel > AutoCancel< A > {
18+
#[inline]
19+
pub fn new( canceler: A ) -> Self {
20+
AutoCancel( Some( canceler ) )
21+
}
22+
23+
#[inline]
24+
pub fn leak( mut self ) -> A {
25+
self.0.take().unwrap()
26+
}
27+
}
28+
29+
impl< A: Cancel > Drop for AutoCancel< A > {
30+
#[inline]
31+
fn drop( &mut self ) {
32+
match self.0 {
33+
Some( ref mut canceler ) => canceler.cancel(),
34+
None => {},
35+
}
36+
}
37+
}
38+
39+
impl< A: Cancel > Deref for AutoCancel< A > {
40+
type Target = A;
41+
42+
#[inline]
43+
fn deref( &self ) -> &Self::Target {
44+
match self.0 {
45+
Some( ref canceler ) => canceler,
46+
None => unreachable!(),
47+
}
48+
}
49+
}
50+
51+
impl< A: Cancel > DerefMut for AutoCancel< A > {
52+
#[inline]
53+
fn deref_mut( &mut self ) -> &mut Self::Target {
54+
match self.0 {
55+
Some( ref mut canceler ) => canceler,
56+
None => unreachable!(),
57+
}
58+
}
59+
}

src/webcore/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub mod once;
1717
pub mod instance_of;
1818
pub mod reference_type;
1919
pub mod promise;
20+
pub mod cancel;
2021

2122
#[cfg(feature = "futures")]
2223
pub mod promise_future;

src/webcore/promise.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std;
22
use webcore::once::Once;
33
use webcore::value::{Value, Reference};
44
use webcore::try_from::{TryInto, TryFrom};
5+
use webcore::cancel::{Cancel, AutoCancel};
56

67
#[cfg(feature = "futures")]
78
use futures::unsync::oneshot::channel;
@@ -19,8 +20,8 @@ pub struct DoneHandle {
1920
done: Value,
2021
}
2122

22-
impl Drop for DoneHandle {
23-
fn drop( &mut self ) {
23+
impl Cancel for DoneHandle {
24+
fn cancel( &mut self ) {
2425
js! { @(no_return)
2526
@{&self.done}[0] = true;
2627
@{&self.callback}.drop();
@@ -100,13 +101,13 @@ impl Promise {
100101
/// If the `Promise` never succeeds / fails then the `callback` will never be called.
101102
///
102103
/// This method returns a [`DoneHandle`](struct.DoneHandle.html). When the [`DoneHandle`](struct.DoneHandle.html)
103-
/// is dropped it will drop the `callback` and the `callback` will never be called. This is useful if you are
104+
/// is cancelled it will drop the `callback` and the `callback` will never be called. This is useful if you are
104105
/// no longer interested in the `Promise`'s result.
105106
///
106-
/// But if you *are* interested in the `Promise`'s result, then you need to make sure to keep the handle alive
107-
/// until after the callback is called.
107+
/// But if you *are* interested in the `Promise`'s result, then you either need to make sure to keep the handle
108+
/// alive until after the callback is called, or you need to use the `leak` method.
108109
///
109-
/// Dropping the [`DoneHandle`](struct.DoneHandle.html) does ***not*** cancel the `Promise`, because promises
110+
/// Cancelling the [`DoneHandle`](struct.DoneHandle.html) does ***not*** cancel the `Promise`, because promises
110111
/// do not support cancellation.
111112
///
112113
/// # Examples
@@ -122,7 +123,7 @@ impl Promise {
122123
///
123124
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)
124125
// https://www.ecma-international.org/ecma-262/6.0/#sec-performpromisethen
125-
pub fn done< A, B, F >( &self, callback: F ) -> DoneHandle
126+
pub fn done< A, B, F >( &self, callback: F ) -> AutoCancel< DoneHandle >
126127
where A: TryFrom< Value >,
127128
B: TryFrom< Value >,
128129
// TODO these Debug constraints are only needed because of unwrap
@@ -165,10 +166,10 @@ impl Promise {
165166
return done;
166167
);
167168

168-
DoneHandle {
169+
AutoCancel::new( DoneHandle {
169170
callback,
170171
done,
171-
}
172+
} )
172173
}
173174

174175
/// This method should rarely be needed, instead use [`value.try_into()`](unstable/trait.TryInto.html) to convert directly from a [`Value`](enum.Value.html) into a [`PromiseFuture`](struct.PromiseFuture.html).

src/webcore/promise_future.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use webapi::error;
55
use futures::{Future, Poll, Async};
66
use futures::unsync::oneshot::Receiver;
77
use webcore::promise_executor::spawn;
8+
use webcore::cancel::AutoCancel;
89
use super::promise::{Promise, DoneHandle};
910

1011

@@ -21,7 +22,7 @@ use super::promise::{Promise, DoneHandle};
2122
/// ```
2223
pub struct PromiseFuture< Value, Error = error::Error > {
2324
pub(crate) future: Receiver< Result< Value, Error > >,
24-
pub(crate) _done_handle: DoneHandle,
25+
pub(crate) _done_handle: AutoCancel< DoneHandle >,
2526
}
2627

2728
impl PromiseFuture< (), () > {

0 commit comments

Comments
 (0)