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 | |
| 10 | use std::hash::Hash; |
| 11 | use std::{rc, sync}; |
| 12 | |
| 13 | /// Interface for elements that can be stored in weak hash tables. |
| 14 | /// |
| 15 | /// This trait applies to the weak version of a reference-counted pointer; it can be used to |
| 16 | /// convert a weak pointer into a strong pointer and back. For example, the impl for |
| 17 | /// `std::rc::Weak<T>` defines the `Strong` associated type as `std::rc::Rc<T>`. Then method |
| 18 | /// `new` can be used to downgrade an `Rc<T>` to a `Weak<T>`, and method `view` can be used to |
| 19 | /// upgrade a `Weak<T>` into an `Rc<T>`, if it's still alive. If we think of the weak pointer as |
| 20 | /// what is stored, then the strong pointer is a temporary view of it. |
| 21 | pub trait WeakElement { |
| 22 | /// The type at which a weak element can be viewed. |
| 23 | /// |
| 24 | /// For example, for `std::rc::Weak<T>`, this will be `std::rc::Rc<T>`. |
| 25 | type Strong; |
| 26 | |
| 27 | /// Constructs a weak pointer from a strong pointer. |
| 28 | /// |
| 29 | /// This is usually implemented by a `downgrade` method. |
| 30 | fn new(view: &Self::Strong) -> Self; |
| 31 | |
| 32 | /// Acquires a strong pointer from a weak pointer. |
| 33 | /// |
| 34 | /// This is usually implemented by an `upgrade` method. |
| 35 | fn view(&self) -> Option<Self::Strong>; |
| 36 | |
| 37 | /// Is the given weak element expired? |
| 38 | /// |
| 39 | /// The default implemention checks whether a strong pointer can be obtained via `view`. |
| 40 | fn is_expired(&self) -> bool { |
| 41 | self.view().is_none() |
| 42 | } |
| 43 | |
| 44 | /// Clones a strong pointer. |
| 45 | /// |
| 46 | /// The default implementation uses `new` and `view`; you should override it. |
| 47 | fn clone(view: &Self::Strong) -> Self::Strong |
| 48 | where Self: Sized |
| 49 | { |
| 50 | Self::new(view).view().expect("WeakElement::clone") |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | /// Interface for elements that can act as keys in weak hash tables. |
| 55 | /// |
| 56 | /// To use an element as a weak hash map key or weak hash set element), the hash table |
| 57 | /// needs to be able to view the actual key values to hash and compare them. This trait |
| 58 | /// provides the necessary mechanism. |
| 59 | pub trait WeakKey : WeakElement { |
| 60 | /// The underlying key type. |
| 61 | /// |
| 62 | /// For example, for `std::rc::Weak<T>`, this will be `T`. |
| 63 | type Key: ?Sized + Eq + Hash; |
| 64 | |
| 65 | /// Allows borrowing a view of the key, via a callback. |
| 66 | /// |
| 67 | /// Rather than returning a borrowed reference to the actual key, this method passes a |
| 68 | /// reference to the key to a callback with an implicit higher-order lifetime bound. This is |
| 69 | /// necessary to get the lifetimes right in cases where the key is not actually store in the |
| 70 | /// strong pointer. |
| 71 | fn with_key<F, R>(view: &Self::Strong, f: F) -> R |
| 72 | where F: FnOnce(&Self::Key) -> R; |
| 73 | } |
| 74 | |
| 75 | impl<T: ?Sized> WeakElement for rc::Weak<T> { |
| 76 | type Strong = rc::Rc<T>; |
| 77 | |
| 78 | fn new(view: &Self::Strong) -> Self { |
| 79 | rc::Rc::<T>::downgrade(view) |
| 80 | } |
| 81 | |
| 82 | fn view(&self) -> Option<Self::Strong> { |
| 83 | self.upgrade() |
| 84 | } |
| 85 | |
| 86 | fn clone(view: &Self::Strong) -> Self::Strong { |
| 87 | view.clone() |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | impl<T: ?Sized + Eq + Hash> WeakKey for rc::Weak<T> { |
| 92 | type Key = T; |
| 93 | |
| 94 | fn with_key<F, R>(view: &Self::Strong, f: F) -> R |
| 95 | where F: FnOnce(&Self::Key) -> R |
| 96 | { |
| 97 | f(&view) |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | impl<T: ?Sized> WeakElement for sync::Weak<T> { |
| 102 | type Strong = sync::Arc<T>; |
| 103 | |
| 104 | fn new(view: &Self::Strong) -> Self { |
| 105 | sync::Arc::<T>::downgrade(view) |
| 106 | } |
| 107 | |
| 108 | fn view(&self) -> Option<Self::Strong> { |
| 109 | self.upgrade() |
| 110 | } |
| 111 | |
| 112 | fn clone(view: &Self::Strong) -> Self::Strong { |
| 113 | view.clone() |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | impl<T: ?Sized + Eq + Hash> WeakKey for sync::Weak<T> |
| 118 | { |
| 119 | type Key = T; |
| 120 | |
| 121 | fn with_key<F, R>(view: &Self::Strong, f: F) -> R |
| 122 | where F: FnOnce(&Self::Key) -> R |
| 123 | { |
| 124 | f(&view) |
| 125 | } |
| 126 | } |
| 127 | |