hashable_rc/
lib.rs

1#![deny(missing_docs)]
2
3//! Hashable wrappers for reference countings.
4//!
5//! Provides hashable wrappers for 
6//! [`Rc<T>`](https://doc.rust-lang.org/std/rc/struct.Rc.html) and
7//! [`Weak<T>`](https://doc.rust-lang.org/std/rc/struct.Weak.html) 
8//! references with the types [`HashableRc<T>`](struct.HashableRc.html)
9//! and [`HashableWeak<T>`](struct.HashableWeak.html), respectively. 
10//! This allows use of both strong and weak reference countings in 
11//! hash-based data structures, such as 
12//! [`HashMap`](https://doc.rust-lang.org/std/collections/struct.HashMap.html)
13//! or
14//! [`HashSet`](https://doc.rust-lang.org/std/collections/struct.HashSet.html).
15//!
16//! # Quick Start
17//!
18//! The most common use cases are wrapping 
19//! [`Rc<T>`](https://doc.rust-lang.org/std/rc/struct.Rc.html) or 
20//! [`Weak<T>`](https://doc.rust-lang.org/std/rc/struct.Weak.html) in
21//! [`HashableRc<T>`](struct.HashableRc.html) or 
22//! [`HashableWeak<T>`](struct.HashableWeak.html) respectively to be
23//! contained in a hash-based container. An example of using both types
24//! as keys in a 
25//! [`HashMap`](https://doc.rust-lang.org/std/collections/struct.HashMap.html)
26//! follows.
27//!
28//! ```
29//! use std::collections::HashMap;
30//! use std::rc::{Rc, Weak};
31//!
32//! use hashable_rc::{HashableRc, HashableWeak};
33//!
34//! // Create a strong reference counting for an object.
35//! let rc: Rc<u32> = Rc::new(42);
36//!
37//! // Use the strong reference as a key for a HashMap.
38//! let mut strong_map = HashMap::new();
39//! strong_map.insert(HashableRc::new(rc.clone()), "foo");
40//! assert_eq!(strong_map[&HashableRc::new(rc.clone())], "foo");
41//!
42//! // Create a weak reference counting for the same object as above.
43//! let weak: Weak<u32> = Rc::downgrade(&rc);
44//!
45//! // Use the weak reference as a key for a HashMap.
46//! let mut weak_map = HashMap::new();
47//! weak_map.insert(HashableWeak::new(weak.clone()), "bar");
48//! assert_eq!(weak_map[&HashableWeak::new(weak.clone())], "bar");
49//! ```
50//!
51//! Insertion into other hash-based containers (such as a 
52//! [`HashSet`](https://doc.rust-lang.org/std/collections/struct.HashSet.html))
53//! follows similarly.
54
55use std::hash::{Hash, Hasher};
56use std::rc::{Rc, Weak};
57
58fn hash_rc<T, H: Hasher>(rc: Rc<T>, state: &mut H) {
59    let raw_ptr = Rc::into_raw(rc);
60    raw_ptr.hash(state);
61    // Convert back to Rc to prevent memory leak.
62    let _ = unsafe {Rc::from_raw(raw_ptr)};
63}
64
65/// A hashable wrapper around the 
66/// [`Rc<T>`](https://doc.rust-lang.org/std/rc/struct.Rc.html) type.
67///
68/// A hash of a [`HashableRc<T>`](struct.HashableRc.html) is taken from
69/// the underlying pointer. Therefore, two separate objects that may be
70/// considered equal will, when contained in a
71/// [`HashableRc<T>`](struct.HashableRc.html), almost always have 
72/// different hashed values. For example, the following holds:
73///
74/// ```
75/// use std::collections::hash_map::DefaultHasher;
76/// use std::hash::{Hash, Hasher};
77/// use std::rc::Rc;
78///
79/// use hashable_rc::HashableRc;
80///
81/// fn hash<H: Hash>(value: &H) -> u64 {
82///     let mut state = DefaultHasher::new();
83///     value.hash(&mut state);
84///     state.finish()
85/// }
86///
87/// // While the underlying values are considered equal, the hash values
88/// // will be different, due to being separate allocated objects with 
89/// // different underlying pointers.
90/// let rc1 = Rc::new(42);
91/// let rc2 = Rc::new(42);
92/// 
93/// // The hashes of the two reference countings are different.
94/// assert_ne!(hash(&HashableRc::new(rc1.clone())), 
95///            hash(&HashableRc::new(rc2.clone())));
96///
97/// // Contrastingly, the hashes of clone reference countings pointing to 
98/// // the same object are the equal.
99/// assert_eq!(hash(&HashableRc::new(rc1.clone())), 
100///            hash(&HashableRc::new(rc1.clone())));
101/// ```
102///
103/// Similarly, equality of [`HashableRc<T>`](struct.HashableRc.html)
104/// objects is done by evaluating pointer equality (using 
105/// [`ptr_eq()`](https://doc.rust-lang.org/std/rc/struct.Rc.html#method.ptr_eq)).
106/// The equality is not from the value itself, but from the pointer.
107///
108/// ```
109/// use std::rc::Rc;
110///
111/// use hashable_rc::HashableRc;
112///
113/// // Again, the values contained are equal, but the underlying pointers
114/// // are different.
115/// let rc1 = Rc::new(42);
116/// let rc2 = Rc::new(42);
117///
118/// // Therefore, two HashableRc wrappers containing these reference 
119/// // counters are not equal.
120/// assert_ne!(HashableRc::new(rc1.clone()),
121///            HashableRc::new(rc2.clone()));
122///
123/// // But HashableRc holding the same underlying object are equal.
124/// assert_eq!(HashableRc::new(rc1.clone()),
125///            HashableRc::new(rc1.clone()));
126/// ```
127#[derive(Debug, Eq)]
128pub struct HashableRc<T> {
129    value: Rc<T>,
130}
131
132impl <T> HashableRc<T> {
133    /// Constructs a new [`HashableRc<T>`](struct.HashableRc.html) 
134    /// wrapping an 
135    /// [`Rc<T>`](https://doc.rust-lang.org/std/rc/struct.Rc.html).
136    pub fn new(value: Rc<T>) -> Self {
137        HashableRc {value}
138    }
139
140    /// Returns a clone of the wrapped `Rc<T>` without consuming `self`.
141    pub fn get_cloned(&self) -> Rc<T> {
142        self.value.clone()
143    }
144}
145
146impl <T> Hash for HashableRc<T> {
147    /// Generate a hash value for the 
148    /// [`HashableRc<T>`](struct.HashableRc.html).
149    ///
150    /// This hash value is based on the underlying pointer. Two unique 
151    /// objects will most likely have different hashes, even if their 
152    /// values are the same.
153    fn hash<H>(&self, state: &mut H) where H: Hasher {
154        hash_rc(self.value.clone(), state);
155    }
156}
157
158impl <T> PartialEq for HashableRc<T> {
159    /// Equality for two [`HashableRc<T>`](struct.HashableRc.html) 
160    /// objects.
161    ///
162    /// Equality is determined by pointer equality, rather than value 
163    /// equality. Objects are only considered equal if they point to 
164    /// the same object.
165    fn eq(&self, other: &Self) -> bool {
166        Rc::ptr_eq(&self.value, &other.value)
167    }
168}
169
170/// A hashable wrapper around the 
171/// [`Weak<T>`](https://doc.rust-lang.org/std/rc/struct.Weak.html)
172/// type.
173///
174/// A hash of a [`HashableWeak<T>`](struct.HashableWeak.html) is taken
175/// from the underlying pointer. Therefore, two separate objects that
176/// may be considered equal will, when contained in a
177/// [`HashableWeak<T>`](struct.HashableWeak.html), almost always have
178/// different hashed values. For example, the following holds:
179///
180/// ```
181/// use std::collections::hash_map::DefaultHasher;
182/// use std::hash::{Hash, Hasher};
183/// use std::rc::Rc;
184///
185/// use hashable_rc::HashableWeak;
186///
187/// fn hash<H: Hash>(value: &H) -> u64 {
188///     let mut state = DefaultHasher::new();
189///     value.hash(&mut state);
190///     state.finish()
191/// }
192///
193/// // While the underlying values are considered equal, the hash values
194/// // will be different, due to being separate allocated objects with 
195/// // different underlying pointers.
196/// let rc1 = Rc::new(42);
197/// let rc2 = Rc::new(42);
198/// 
199/// // The hashes of the two reference countings are different.
200/// assert_ne!(hash(&HashableWeak::new(Rc::downgrade(&rc1))), 
201///            hash(&HashableWeak::new(Rc::downgrade(&rc2))));
202///
203/// // Contrastingly, the hashes of clone reference countings pointing to 
204/// // the same object are the equal.
205/// assert_eq!(hash(&HashableWeak::new(Rc::downgrade(&rc1))), 
206///            hash(&HashableWeak::new(Rc::downgrade(&rc1))));
207/// ```
208///
209/// Similarly, equality of 
210/// [`HashableWeak<T>`](struct.HashableWeak.html) objects is done by
211/// evaluating pointer equality (using 
212/// [`ptr_eq()`](https://doc.rust-lang.org/std/rc/struct.Weak.html#method.ptr_eq)).
213/// The equality is not from the value itself, but from the pointer.
214///
215/// ```
216/// use std::rc::Rc;
217///
218/// use hashable_rc::HashableWeak;
219///
220/// // Again, the values contained are equal, but the underlying pointers
221/// // are different.
222/// let rc1 = Rc::new(42);
223/// let rc2 = Rc::new(42);
224///
225/// // Therefore, two HashableWeak wrappers containing these reference
226/// // counters are not equal.
227/// assert_ne!(HashableWeak::new(Rc::downgrade(&rc1)),
228///            HashableWeak::new(Rc::downgrade(&rc2)));
229///
230/// // But HashableWeak holding the same underlying object are equal.
231/// assert_eq!(HashableWeak::new(Rc::downgrade(&rc1)),
232///            HashableWeak::new(Rc::downgrade(&rc1)));
233/// ```
234///
235/// Since 
236/// [`Weak<T>`](https://doc.rust-lang.org/std/rc/struct.Weak.html) is a
237/// weak reference, the underlying value is not guaranteed to exist. A 
238/// [`Weak<T>`](https://doc.rust-lang.org/std/rc/struct.Weak.html) that
239/// is empty can still be wrapped in a
240/// [`HashableWeak<T>`](struct.HashableWeak.html).
241///
242/// ```
243/// use std::collections::hash_map::DefaultHasher;
244/// use std::hash::{Hash, Hasher};
245/// use std::rc::{Rc, Weak};
246///
247/// use hashable_rc::HashableWeak;
248///
249/// fn hash<H: Hash>(value: &H) -> u64 {
250///     let mut state = DefaultHasher::new();
251///     value.hash(&mut state);
252///     state.finish()
253/// }
254/// 
255/// let weak: Weak<i32> = Weak::new();
256/// let rc = Rc::new(0);
257///
258/// // Hashing still works for a HashableWeak pointing to no value. It will
259/// // hash differently than HashableWeak objects containing values, and
260/// // will hash the same as other empty HashableWeak objects.
261/// assert_ne!(hash(&HashableWeak::new(weak.clone())), 
262///            hash(&HashableWeak::new(Rc::downgrade(&rc))));
263/// assert_eq!(hash(&HashableWeak::new(weak.clone())), 
264///            hash(&HashableWeak::new(weak.clone())));
265///
266/// // Empty HashableWeak objects are also not equal to assigned 
267/// // HashableWeak objects, while being equal to other empty HashableWeak
268/// // objects.
269/// assert_ne!(HashableWeak::new(weak.clone()), 
270///            HashableWeak::new(Rc::downgrade(&rc)));
271/// assert_eq!(HashableWeak::new(weak.clone()), 
272///            HashableWeak::new(weak.clone()));
273/// ```
274#[derive(Debug)]
275pub struct HashableWeak<T> {
276    value: Weak<T>,
277}
278
279impl <T> HashableWeak<T> {
280    /// Constructs a new [`HashableWeak<T>`](struct.HashableWeak.html)
281    /// wrapping a
282    /// [`Weak<T>`](https://doc.rust-lang.org/std/rc/struct.Weak.html).
283    pub fn new(value: Weak<T>) -> Self {
284        HashableWeak {value}
285    }
286
287
288}
289
290impl <T> Hash for HashableWeak<T> {
291    /// Generate a hash value for the 
292    /// [`HashableWeak<T>`](struct.HashableWeak.html).
293    ///
294    /// This hash value is based on the underlying pointer. Two unique 
295    /// objects will most likely have different hashes, even if their 
296    /// values are the same.
297    ///
298    /// If no value is pointed to, the Hasher state remains unaltered.
299    fn hash<H>(&self, state: &mut H) where H: Hasher {
300        let upgraded_weak: Option<Rc<T>> = self.value.clone().upgrade();
301        match upgraded_weak {
302            None => {}
303            Some(rc) => {
304                hash_rc(rc, state);
305            }
306        }
307    }
308}
309
310impl <T> PartialEq for HashableWeak<T> {
311    /// Equality for two [`HashableWeak<T>`](struct.HashableWeak.html)
312    /// objects.
313    ///
314    /// Equality is determined by pointer equality, rather than value 
315    /// equality. Objects are only considered equal if they point to 
316    /// the same object (or if both point to no object).
317    fn eq(&self, other: &Self) -> bool {
318        Weak::ptr_eq(&self.value, &other.value)
319    }
320}
321
322impl <T> Eq for HashableWeak<T> {}
323
324#[cfg(test)]
325mod tests {
326    use crate::{HashableRc, HashableWeak};
327    use std::collections::hash_map::DefaultHasher;
328    use std::hash::{Hash, Hasher};
329    use std::rc::{Rc, Weak};
330    
331    fn hash<H: Hash>(value: &H) -> u64 {
332        let mut state = DefaultHasher::new();
333        value.hash(&mut state);
334        state.finish()
335    }
336    
337    #[test]
338    fn test_hashable_rc_hash() {
339        let rc1 = Rc::new(42);
340        let rc2 = Rc::new(42);
341        
342        assert_ne!(hash(&HashableRc::new(rc1.clone())), hash(&HashableRc::new(rc2.clone())));
343        assert_eq!(hash(&HashableRc::new(rc1.clone())), hash(&HashableRc::new(rc1.clone())));
344    }
345    
346    #[test]
347    fn test_hashable_rc_eq() {
348        let rc1 = Rc::new(42);
349        let rc2 = Rc::new(42);
350        
351        assert_ne!(HashableRc::new(rc1.clone()), HashableRc::new(rc2.clone()));
352        assert_eq!(HashableRc::new(rc1.clone()), HashableRc::new(rc1.clone()));
353    }
354
355    #[test]
356    fn test_hashable_rc_get_clone() {
357        let rc1 = Rc::new(42);
358        let rc2 = Rc::new(42);
359        let rc1_hashable = HashableRc::new(rc1.clone());
360
361        assert_eq!(rc1_hashable.get_cloned(), rc1);
362        assert_eq!(rc1_hashable.get_cloned(), rc2);
363        // Round trip follows from above, but included for completeness.
364        assert_eq!(HashableRc::new(rc1_hashable.get_cloned()), rc1_hashable);
365        // Round trip the other direction.
366        assert_eq!(*rc1_hashable.get_cloned(), 42);
367    }
368    
369    #[test]
370    fn test_hashable_rc_hash_does_not_memory_leak() {
371        let rc = Rc::new(42);
372        
373        hash(&HashableRc::new(rc.clone()));
374        
375        assert_eq!(Rc::strong_count(&rc), 1);
376        assert_eq!(Rc::weak_count(&rc), 0);
377    }
378    
379    #[test]
380    fn test_hashable_weak_hash() {
381        let rc1 = Rc::new(42);
382        let rc2 = Rc::new(42);
383        
384        assert_ne!(hash(&HashableWeak::new(Rc::downgrade(&rc1))), hash(&HashableWeak::new(Rc::downgrade(&rc2))));
385        assert_eq!(hash(&HashableWeak::new(Rc::downgrade(&rc1))), hash(&HashableWeak::new(Rc::downgrade(&rc1))));
386    }
387    
388    #[test]
389    fn test_hashable_weak_eq() {
390        let rc1 = Rc::new(42);
391        let rc2 = Rc::new(42);
392        
393        assert_ne!(HashableWeak::new(Rc::downgrade(&rc1)), HashableWeak::new(Rc::downgrade(&rc2)));
394        assert_eq!(HashableWeak::new(Rc::downgrade(&rc1)), HashableWeak::new(Rc::downgrade(&rc1)));
395    }
396    
397    #[test]
398    fn test_hashable_weak_hash_does_not_memory_leak() {
399        let rc = Rc::new(42);
400        let weak = Rc::downgrade(&rc);
401        
402        hash(&HashableWeak::new(weak.clone()));
403        
404        assert_eq!(Rc::strong_count(&rc), 1);
405        assert_eq!(Rc::weak_count(&rc), 1);
406    }
407    
408    #[test]
409    fn test_hashable_weak_hash_no_value() {
410        // Weak is an empty weak reference.
411        let weak: Weak<i32> = Weak::new();
412        let rc = Rc::new(0);
413        
414        assert_ne!(hash(&HashableWeak::new(weak.clone())), hash(&HashableWeak::new(Rc::downgrade(&rc))));
415        assert_eq!(hash(&HashableWeak::new(weak.clone())), hash(&HashableWeak::new(weak.clone())));
416    }
417    
418    #[test]
419    fn test_hashable_weak_eq_no_value() {
420        // Weak is an empty weak reference.
421        let weak: Weak<i32> = Weak::new();
422        let rc = Rc::new(0);
423        
424        assert_ne!(HashableWeak::new(weak.clone()), HashableWeak::new(Rc::downgrade(&rc)));
425        assert_eq!(HashableWeak::new(weak.clone()), HashableWeak::new(weak.clone()));
426    }
427}