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}