1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
use crate::cell::cell::ShareCell;
use crate::Core;
use std::rc::{Rc, Weak};
/// Ref-counted shared mutable data
///
/// This allows synchronous modification of shared state from actor
/// methods. Note that if you only wish to share immutable data
/// between actors, it's less verbose to simply use `Rc` from the
/// standard library. Also you might wish to handle very small
/// amounts of shared mutable data with `Rc<Cell>` instead.
///
/// [`Share`] is provided as a compile-time-checked zero-cost
/// alternative to `Rc<RefCell>`. If [`Share`] didn't exist, the
/// temptation to use `Rc<RefCell>` occasionally would likely be too
/// great. However `Rc<RefCell>` brings the risk of unexpected
/// runtime panics. Modification of one piece of code might
/// unexpectedly cause another distant piece of code to crash, but
/// quite possibly only under certain conditions which makes that
/// failure hard to anticipate in testing. In short `Rc<RefCell>`
/// should be avoided wherever possible. With [`Share`] everything is
/// checked at compile time.
///
/// Note that using [`Share`], `Rc<RefCell>` or `Rc<Cell>` breaks the
/// actor model. Using them to share mutable data between actors
/// effectively causes those actors to be bound together in a group.
/// It would be impossible to split one of those actors off to another
/// process or over a remote link. However the actor model still
/// applies to the group's external interface.
///
/// So this must be used with some knowledge of the trade-offs. It
/// could easily lead to dependency on the order of execution of
/// actors. Treat this as similar in danger level to shared memory
/// between threads or IPC shared memory between processes. You don't
/// need locking however because if you get a mutable reference to the
/// contents you'll have exclusive access until you give it up thanks
/// to Rust's borrow checker.
///
/// To borrow more than one [`Share`] instance at a time, see
/// [`Core::share_rw2`] and [`Core::share_rw3`].
///
/// It's not possible to pass a [`Core`] reference to methods on a
/// [`Share`] item due to borrowing restrictions. If you need a
/// [`Core`] reference, then use arguments of "`this: &Share<Self>,
/// core: &mut Core`" instead of "`&mut self`", and do `self` access
/// via `this.rw(core)`. (However if it's getting this complicated,
/// maybe consider whether the shared data should be made into an
/// actor instead, or whether some other approach would be better.)
///
/// By default borrow-checking of access to the contents of the
/// [`Share`] is handled at compile-time using a `TCell` or `TLCell`
/// with its owner in [`Core`], so it is zero-cost and compiles down
/// to a direct pointer access to the contents of a `struct`, just as
/// if the [`Share`] wasn't there. However cloning a [`Share`] has
/// the normal `Rc` overheads.
///
/// [`Core::share_rw2`]: struct.Core.html#method.share_rw2
/// [`Core::share_rw3`]: struct.Core.html#method.share_rw3
/// [`Core`]: struct.Core.html
/// [`Share`]: struct.Share.html
pub struct Share<T> {
pub(crate) rc: Rc<ShareCell<T>>,
}
impl<T> Share<T> {
/// Create a new Share instance
pub fn new(core: &Core, val: T) -> Self {
Self {
rc: Rc::new(core.sharecell_owner.cell(val)),
}
}
/// Get a read-only (immutable, shared) reference to the contents
/// of the [`Share`] instance. By default this is a static check,
/// which compiles down to a direct access.
///
/// [`Share`]: struct.Share.html
#[inline]
pub fn ro<'a>(&'a self, core: &'a Core) -> &'a T {
core.sharecell_owner.ro(&self.rc)
}
/// Get a read-write (mutable, exclusive) reference to the
/// contents of the [`Share`] instance. By default this is a
/// static check, which compiles down to a direct access.
///
/// To access more than one [`Share`] instance at the same time,
/// see [`Core::share_rw2`] and [`Core::share_rw3`].
///
/// [`Core::share_rw2`]: struct.Core.html#method.share_rw2
/// [`Core::share_rw3`]: struct.Core.html#method.share_rw3
/// [`Share`]: struct.Share.html
#[inline]
pub fn rw<'a>(&'a self, core: &'a mut Core) -> &'a mut T {
core.sharecell_owner.rw(&self.rc)
}
/// Create a [`ShareWeak`] reference to the contained object
///
/// [`ShareWeak`]: struct.ShareWeak.html
#[inline]
pub fn downgrade(&self) -> ShareWeak<T> {
ShareWeak {
weak: Rc::downgrade(&self.rc),
}
}
/// Return the number of strong references to the shared data
#[inline]
pub fn strong_count(&self) -> usize {
Rc::strong_count(&self.rc)
}
/// Return the number of weak references to the shared data
#[inline]
pub fn weak_count(&self) -> usize {
Rc::weak_count(&self.rc)
}
}
impl<T> Clone for Share<T> {
/// Return another reference to the shared data
fn clone(&self) -> Self {
Self {
rc: self.rc.clone(),
}
}
}
/// Weak reference to a [`Share`]
///
/// This reference does not stop the [`Share`] from being dropped, but
/// can be used to recover a [`Share`] reference if it is still alive
/// due to a strong reference held elsewhere.
///
/// [`Share`]: struct.Share.html
pub struct ShareWeak<T> {
weak: Weak<ShareCell<T>>,
}
impl<T> ShareWeak<T> {
/// If there are still strong references to the shared data,
/// returns a new [`Share`]. Otherwise the shared data has been
/// dropped, and so returns `None`.
///
/// [`Share`]: struct.Share.html
pub fn upgrade(&self) -> Option<Share<T>> {
self.weak.upgrade().map(|rc| Share { rc })
}
/// Return the number of strong references to the shared data
pub fn strong_count(&self) -> usize {
self.weak.strong_count()
}
/// Return the number of weak references to the shared data,
/// including this one, or 0 if there are no strong pointers
/// remaining.
pub fn weak_count(&self) -> usize {
self.weak.weak_count()
}
}
impl<T> Clone for ShareWeak<T> {
/// Return another weak reference to the shared data
fn clone(&self) -> Self {
Self {
weak: self.weak.clone(),
}
}
}