stdweb/webcore/
discard.rs

1use discard;
2use discard::Discard;
3use 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)]
28pub struct DiscardOnDrop< A: Discard >( discard::DiscardOnDrop< A > );
29
30impl< 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
49impl< 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
58impl< 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)]
67mod 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    #[allow(unused_must_use)]
103    fn unused_discard_on_drop() {
104        DiscardOnDrop::new( Foo::new() );
105    }
106
107    #[test]
108    fn discard() {
109        let foo = Foo::new();
110
111        let dropped = foo.dropped();
112
113        assert_eq!( dropped.get(), false );
114        foo.discard();
115        assert_eq!( dropped.get(), true );
116    }
117
118    #[test]
119    fn no_discard() {
120        let foo = Foo::new();
121
122        let dropped = foo.dropped();
123
124        assert_eq!( dropped.get(), false );
125        drop( foo );
126        assert_eq!( dropped.get(), false );
127    }
128
129    #[test]
130    fn discard_on_drop() {
131        let foo = DiscardOnDrop::new( Foo::new() );
132
133        let dropped = foo.dropped();
134
135        assert_eq!( dropped.get(), false );
136        drop( foo );
137        assert_eq!( dropped.get(), true );
138    }
139
140    #[test]
141    fn leak() {
142        let foo = DiscardOnDrop::new(Foo::new());
143
144        let dropped = foo.dropped();
145
146        assert_eq!( dropped.get(), false );
147        drop( foo.leak() );
148        assert_eq!( dropped.get(), false );
149    }
150
151    #[test]
152    fn deref_mut() {
153        let mut foo = DiscardOnDrop::new( Foo::new() );
154
155        let dropped = foo.as_mut().dropped();
156
157        assert_eq!( dropped.get(), false );
158        drop( foo.leak() );
159        assert_eq!( dropped.get(), false );
160    }
161}