Joel Galenson | 2370d12 | 2020-10-12 16:02:26 -0700 | [diff] [blame] | 1 | //! Traits for describing strong and weak pointers and their use as elements and keys. |
| 2 | //! |
| 3 | //! These traits provide mechanisms for converting between weak and strong pointers |
| 4 | //! ([`WeakElement`](trait.WeakElement.html)) and for dereferencing strong pointers |
| 5 | //! ([`WeakKey`](trait.WeakKey.html)). Implementations of these traits are provided for |
| 6 | //! `std::rc::Weak` and `std::sync::Weak`. If you would like to use your own pointer type |
| 7 | //! as a weak element, you need to implement `WeakElement` for your weak pointer type; to use it |
| 8 | //! as a weak key, implement `WeakKey` as well. |
| 9 | |
David LeGare | 77e4bb9 | 2022-03-02 16:21:23 +0000 | [diff] [blame] | 10 | use crate::compat::*; |
Joel Galenson | 2370d12 | 2020-10-12 16:02:26 -0700 | [diff] [blame] | 11 | |
| 12 | /// Interface for elements that can be stored in weak hash tables. |
| 13 | /// |
| 14 | /// This trait applies to the weak version of a reference-counted pointer; it can be used to |
| 15 | /// convert a weak pointer into a strong pointer and back. For example, the impl for |
| 16 | /// `std::rc::Weak<T>` defines the `Strong` associated type as `std::rc::Rc<T>`. Then method |
| 17 | /// `new` can be used to downgrade an `Rc<T>` to a `Weak<T>`, and method `view` can be used to |
| 18 | /// upgrade a `Weak<T>` into an `Rc<T>`, if it's still alive. If we think of the weak pointer as |
| 19 | /// what is stored, then the strong pointer is a temporary view of it. |
| 20 | pub trait WeakElement { |
| 21 | /// The type at which a weak element can be viewed. |
| 22 | /// |
| 23 | /// For example, for `std::rc::Weak<T>`, this will be `std::rc::Rc<T>`. |
| 24 | type Strong; |
| 25 | |
| 26 | /// Constructs a weak pointer from a strong pointer. |
| 27 | /// |
| 28 | /// This is usually implemented by a `downgrade` method. |
| 29 | fn new(view: &Self::Strong) -> Self; |
| 30 | |
| 31 | /// Acquires a strong pointer from a weak pointer. |
| 32 | /// |
| 33 | /// This is usually implemented by an `upgrade` method. |
| 34 | fn view(&self) -> Option<Self::Strong>; |
| 35 | |
| 36 | /// Is the given weak element expired? |
| 37 | /// |
| 38 | /// The default implemention checks whether a strong pointer can be obtained via `view`. |
| 39 | fn is_expired(&self) -> bool { |
| 40 | self.view().is_none() |
| 41 | } |
| 42 | |
| 43 | /// Clones a strong pointer. |
| 44 | /// |
| 45 | /// The default implementation uses `new` and `view`; you should override it. |
| 46 | fn clone(view: &Self::Strong) -> Self::Strong |
| 47 | where Self: Sized |
| 48 | { |
| 49 | Self::new(view).view().expect("WeakElement::clone") |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | /// Interface for elements that can act as keys in weak hash tables. |
| 54 | /// |
| 55 | /// To use an element as a weak hash map key or weak hash set element), the hash table |
| 56 | /// needs to be able to view the actual key values to hash and compare them. This trait |
| 57 | /// provides the necessary mechanism. |
| 58 | pub trait WeakKey : WeakElement { |
| 59 | /// The underlying key type. |
| 60 | /// |
| 61 | /// For example, for `std::rc::Weak<T>`, this will be `T`. |
| 62 | type Key: ?Sized + Eq + Hash; |
| 63 | |
| 64 | /// Allows borrowing a view of the key, via a callback. |
| 65 | /// |
| 66 | /// Rather than returning a borrowed reference to the actual key, this method passes a |
| 67 | /// reference to the key to a callback with an implicit higher-order lifetime bound. This is |
| 68 | /// necessary to get the lifetimes right in cases where the key is not actually store in the |
| 69 | /// strong pointer. |
| 70 | fn with_key<F, R>(view: &Self::Strong, f: F) -> R |
| 71 | where F: FnOnce(&Self::Key) -> R; |
David LeGare | 77e4bb9 | 2022-03-02 16:21:23 +0000 | [diff] [blame] | 72 | |
| 73 | /// Hashes the key `view` into the given `Hasher`. |
| 74 | fn hash<H: Hasher>(view: &Self::Strong, h: &mut H) { |
| 75 | Self::with_key(view, |k| k.hash(h)); |
| 76 | } |
| 77 | |
| 78 | /// Returns whether the key `view` equals the given `key`. |
| 79 | fn equals<Q>(view: &Self::Strong, key: &Q) -> bool |
| 80 | where Q: ?Sized + Eq, |
| 81 | Self::Key: Borrow<Q> |
| 82 | { |
| 83 | Self::with_key(view, |k| k.borrow() == key) |
| 84 | } |
Joel Galenson | 2370d12 | 2020-10-12 16:02:26 -0700 | [diff] [blame] | 85 | } |
| 86 | |
| 87 | impl<T: ?Sized> WeakElement for rc::Weak<T> { |
| 88 | type Strong = rc::Rc<T>; |
| 89 | |
| 90 | fn new(view: &Self::Strong) -> Self { |
| 91 | rc::Rc::<T>::downgrade(view) |
| 92 | } |
| 93 | |
| 94 | fn view(&self) -> Option<Self::Strong> { |
| 95 | self.upgrade() |
| 96 | } |
| 97 | |
| 98 | fn clone(view: &Self::Strong) -> Self::Strong { |
| 99 | view.clone() |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | impl<T: ?Sized + Eq + Hash> WeakKey for rc::Weak<T> { |
| 104 | type Key = T; |
| 105 | |
| 106 | fn with_key<F, R>(view: &Self::Strong, f: F) -> R |
| 107 | where F: FnOnce(&Self::Key) -> R |
| 108 | { |
David LeGare | 77e4bb9 | 2022-03-02 16:21:23 +0000 | [diff] [blame] | 109 | f(view) |
Joel Galenson | 2370d12 | 2020-10-12 16:02:26 -0700 | [diff] [blame] | 110 | } |
| 111 | } |
| 112 | |
| 113 | impl<T: ?Sized> WeakElement for sync::Weak<T> { |
| 114 | type Strong = sync::Arc<T>; |
| 115 | |
| 116 | fn new(view: &Self::Strong) -> Self { |
| 117 | sync::Arc::<T>::downgrade(view) |
| 118 | } |
| 119 | |
| 120 | fn view(&self) -> Option<Self::Strong> { |
| 121 | self.upgrade() |
| 122 | } |
| 123 | |
| 124 | fn clone(view: &Self::Strong) -> Self::Strong { |
| 125 | view.clone() |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | impl<T: ?Sized + Eq + Hash> WeakKey for sync::Weak<T> |
| 130 | { |
| 131 | type Key = T; |
| 132 | |
| 133 | fn with_key<F, R>(view: &Self::Strong, f: F) -> R |
| 134 | where F: FnOnce(&Self::Key) -> R |
| 135 | { |
David LeGare | 77e4bb9 | 2022-03-02 16:21:23 +0000 | [diff] [blame] | 136 | f(view) |
Joel Galenson | 2370d12 | 2020-10-12 16:02:26 -0700 | [diff] [blame] | 137 | } |
| 138 | } |
| 139 | |