Skip to content

Commit 84a95e8

Browse files
committed
Adding in custom DiscardOnDrop struct
1 parent e645988 commit 84a95e8

File tree

5 files changed

+171
-10
lines changed

5 files changed

+171
-10
lines changed

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ pub use webcore::instance_of::InstanceOf;
175175
pub use webcore::reference_type::ReferenceType;
176176
pub use webcore::serialization::JsSerialize;
177177

178+
pub use webcore::discard::DiscardOnDrop;
179+
178180
#[cfg(feature = "experimental_features_which_may_break_on_minor_version_bumps")]
179181
pub use webcore::promise::{Promise, DoneHandle};
180182

src/webcore/discard.rs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
use discard;
2+
use discard::Discard;
3+
use std::ops::{Deref, DerefMut};
4+
5+
6+
/// If you have a value which implements [`Discard`](https://docs.rs/discard/%5E1.0.3/discard/trait.Discard.html), you can use
7+
/// [`DiscardOnDrop::new(value)`](struct.DiscardOnDrop.html#method.new) which will wrap the value.
8+
/// When the wrapper is dropped it will automatically call [`value.discard()`](https://docs.rs/discard/%5E1.0.3/discard/trait.Discard.html#tymethod.discard).
9+
///
10+
/// You can use the [`leak`](#method.leak) method to unwrap it (which returns `value`). This causes
11+
/// it to no longer call [`discard`](https://docs.rs/discard/%5E1.0.3/discard/trait.Discard.html#tymethod.discard) when it is dropped, which
12+
/// means it will usually leak memory unless you manually call [`discard`](https://docs.rs/discard/%5E1.0.3/discard/trait.Discard.html#tymethod.discard).
13+
#[must_use = "
14+
15+
The DiscardOnDrop is unused, which causes it to be immediately discarded.
16+
You probably don't want that to happen.
17+
18+
How to fix this:
19+
20+
* Store the DiscardOnDrop in a variable or data structure.
21+
22+
* Or use the leak() method which will cause it to not be
23+
discarded (this will usually leak memory!)
24+
25+
See the documentation for more details.
26+
"]
27+
#[derive(Debug)]
28+
pub struct DiscardOnDrop< A: Discard >( discard::DiscardOnDrop< A > );
29+
30+
impl< A: Discard > DiscardOnDrop< A > {
31+
/// Creates a new `DiscardOnDrop`.
32+
///
33+
/// When the `DiscardOnDrop` is dropped it will automatically call [`discarder.discard()`](https://docs.rs/discard/%5E1.0.3/discard/trait.Discard.html#tymethod.discard).
34+
#[inline]
35+
pub fn new( discarder: A ) -> Self {
36+
DiscardOnDrop( discard::DiscardOnDrop::new( discarder ) )
37+
}
38+
39+
/// Returns the wrapped `discarder`.
40+
///
41+
/// It will no longer automatically call [`discarder.discard()`](https://docs.rs/discard/%5E1.0.3/discard/trait.Discard.html#tymethod.discard), so this will usually leak
42+
/// memory unless you manually call [`discarder.discard()`](https://docs.rs/discard/%5E1.0.3/discard/trait.Discard.html#tymethod.discard).
43+
#[inline]
44+
pub fn leak( self ) -> A {
45+
discard::DiscardOnDrop::leak( self.0 )
46+
}
47+
}
48+
49+
impl< A: Discard > Deref for DiscardOnDrop< A > {
50+
type Target = A;
51+
52+
#[inline]
53+
fn deref( &self ) -> &Self::Target {
54+
&*self.0
55+
}
56+
}
57+
58+
impl< A: Discard > DerefMut for DiscardOnDrop< A > {
59+
#[inline]
60+
fn deref_mut( &mut self ) -> &mut Self::Target {
61+
&mut *self.0
62+
}
63+
}
64+
65+
66+
#[cfg(test)]
67+
mod tests {
68+
use discard::Discard;
69+
use super::DiscardOnDrop;
70+
use std::rc::Rc;
71+
use std::cell::Cell;
72+
73+
struct Foo( Rc< Cell< bool > > );
74+
75+
impl Foo {
76+
fn new() -> Self {
77+
Foo( Rc::new( Cell::new( false ) ) )
78+
}
79+
80+
fn dropped( &self ) -> Rc< Cell< bool > > {
81+
self.0.clone()
82+
}
83+
84+
fn as_mut( &mut self ) -> &mut Self {
85+
self
86+
}
87+
}
88+
89+
impl Discard for Foo {
90+
fn discard( self ) {
91+
self.0.set( true );
92+
}
93+
}
94+
95+
96+
#[test]
97+
fn unused() {
98+
Foo::new();
99+
}
100+
101+
#[test]
102+
fn unused_discard_on_drop() {
103+
DiscardOnDrop::new( Foo::new() );
104+
}
105+
106+
#[test]
107+
fn discard() {
108+
let foo = Foo::new();
109+
110+
let dropped = foo.dropped();
111+
112+
assert_eq!( dropped.get(), false );
113+
foo.discard();
114+
assert_eq!( dropped.get(), true );
115+
}
116+
117+
#[test]
118+
fn no_discard() {
119+
let foo = Foo::new();
120+
121+
let dropped = foo.dropped();
122+
123+
assert_eq!( dropped.get(), false );
124+
drop( foo );
125+
assert_eq!( dropped.get(), false );
126+
}
127+
128+
#[test]
129+
fn discard_on_drop() {
130+
let foo = DiscardOnDrop::new( Foo::new() );
131+
132+
let dropped = foo.dropped();
133+
134+
assert_eq!( dropped.get(), false );
135+
drop( foo );
136+
assert_eq!( dropped.get(), true );
137+
}
138+
139+
#[test]
140+
fn leak() {
141+
let foo = DiscardOnDrop::new(Foo::new());
142+
143+
let dropped = foo.dropped();
144+
145+
assert_eq!( dropped.get(), false );
146+
drop( foo.leak() );
147+
assert_eq!( dropped.get(), false );
148+
}
149+
150+
#[test]
151+
fn deref_mut() {
152+
let mut foo = DiscardOnDrop::new( Foo::new() );
153+
154+
let dropped = foo.as_mut().dropped();
155+
156+
assert_eq!( dropped.get(), false );
157+
drop( foo.leak() );
158+
assert_eq!( dropped.get(), false );
159+
}
160+
}

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 discard;
2021

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

src/webcore/promise.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use std;
2+
use discard::Discard;
23
use webcore::once::Once;
34
use webcore::value::{Value, Reference};
45
use webcore::try_from::{TryInto, TryFrom};
5-
use discard::{Discard, DiscardOnDrop};
6+
use webcore::discard::DiscardOnDrop;
67

78
#[cfg(feature = "futures")]
89
use webcore::serialization::JsSerialize;
@@ -176,10 +177,9 @@ impl Promise {
176177
/// * Keep the [`DoneHandle`](struct.DoneHandle.html) alive until after the `callback` is called (by storing it in a
177178
/// variable or data structure).
178179
///
179-
/// * Use the [`DiscardOnDrop::leak`](https://docs.rs/discard/1.*/discard/struct.DiscardOnDrop.html#method.leak) function to leak the
180-
/// [`DoneHandle`](struct.DoneHandle.html). If the `Promise` never succeeds or fails then this ***will*** leak the
181-
/// memory of the callback, so only use [`DiscardOnDrop::leak`](https://docs.rs/discard/1.*/discard/struct.DiscardOnDrop.html#method.leak)
182-
/// if you need to.
180+
/// * Use the [`leak`](struct.DiscardOnDrop.html#method.leak) method to leak the [`DoneHandle`](struct.DoneHandle.html).
181+
/// If the `Promise` never succeeds or fails then this ***will*** leak the memory of the callback, so only use
182+
/// [`leak`](struct.DiscardOnDrop.html#method.leak) if you need to.
183183
///
184184
/// # Examples
185185
///
@@ -197,14 +197,12 @@ impl Promise {
197197
/// Leak the [`DoneHandle`](struct.DoneHandle.html) and `callback`:
198198
///
199199
/// ```rust
200-
/// use discard::DiscardOnDrop;
201-
///
202-
/// DiscardOnDrop::leak(promise.done(|result| {
200+
/// promise.done(|result| {
203201
/// match result {
204202
/// Ok(success) => { ... },
205203
/// Err(error) => { ... },
206204
/// }
207-
/// }));
205+
/// }).leak();
208206
/// ```
209207
///
210208
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)

src/webcore/promise_future.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +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 discard::DiscardOnDrop;
8+
use webcore::discard::DiscardOnDrop;
99
use super::promise::{Promise, DoneHandle};
1010

1111

0 commit comments

Comments
 (0)