forked from Restioson/xtra
-
Notifications
You must be signed in to change notification settings - Fork 0
/
refcount.rs
133 lines (111 loc) · 3.7 KB
/
refcount.rs
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
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Weak as ArcWeak};
/// The reference count of a strong address. Strong addresses will prevent the actor from being
/// dropped as long as they live. Read the docs of [`Address`](../address/struct.Address.html) to find
/// out more.
#[derive(Clone)]
// TODO AtomicBool for disconnected when forcibly stopped ?
pub struct Strong(pub(crate) Arc<AtomicBool>);
impl Strong {
pub(crate) fn downgrade(&self) -> Weak {
Weak(Arc::downgrade(&self.0))
}
}
/// The reference count of a weak address. Weak addresses will bit prevent the actor from being
/// dropped. Read the docs of [`Address`](../address/struct.Address.html) to find out more.
#[derive(Clone)]
pub struct Weak(pub(crate) ArcWeak<AtomicBool>);
impl Weak {
pub(crate) fn upgrade(&self) -> Option<Strong> {
ArcWeak::upgrade(&self.0).map(Strong)
}
}
/// A reference counter that can be dynamically either strong or weak.
#[derive(Clone)]
pub enum Either {
/// A strong reference counter.
Strong(Strong),
/// A weak reference counter.
Weak(Weak),
}
impl Either {
pub(crate) fn into_weak(self) -> Weak {
match self {
Either::Strong(strong) => strong.downgrade(),
Either::Weak(weak) => weak,
}
}
}
/// This trait represents the strength of an address's reference counting. It is an internal trait.
/// There are two implementations of this trait: [`Weak`](struct.Weak.html) and
/// [`Strong`](struct.Weak.html). These can be provided as the second type argument to
/// [`Address`](../address/struct.Address.html) in order to change how the address affects the actor's
/// dropping. Read the docs of [`Address`](../address/struct.Address.html) to find out more.
pub trait RefCounter: Clone + Unpin + Send + Sync + 'static {
#[doc(hidden)]
fn is_connected(&self) -> bool;
#[doc(hidden)]
fn is_last_strong(&self) -> bool;
#[doc(hidden)]
fn strong_count(&self) -> usize;
// These above two methods cannot be merged since is_last_strong is always false for Weak. If
// strong_count were used to implement this, a weak being dropped could think it were a strong.
#[doc(hidden)]
fn into_either(self) -> Either;
}
impl RefCounter for Strong {
fn is_connected(&self) -> bool {
self.strong_count() > 0 && self.0.load(Ordering::Acquire)
}
fn is_last_strong(&self) -> bool {
Arc::strong_count(&self.0) == 1
}
fn strong_count(&self) -> usize {
Arc::strong_count(&self.0)
}
fn into_either(self) -> Either {
Either::Strong(self)
}
}
impl RefCounter for Weak {
fn is_connected(&self) -> bool {
let running = self
.0
.upgrade()
.map(|b| b.load(Ordering::Acquire))
.unwrap_or(false);
self.strong_count() > 0 && running
}
fn is_last_strong(&self) -> bool {
false
}
fn strong_count(&self) -> usize {
ArcWeak::strong_count(&self.0)
}
fn into_either(self) -> Either {
Either::Weak(self)
}
}
impl RefCounter for Either {
fn is_connected(&self) -> bool {
match self {
Either::Strong(strong) => strong.is_connected(),
Either::Weak(weak) => weak.is_connected(),
}
}
fn is_last_strong(&self) -> bool {
match self {
Either::Strong(strong) => strong.is_last_strong(),
Either::Weak(weak) => weak.is_last_strong(),
}
}
fn strong_count(&self) -> usize {
match self {
Either::Strong(strong) => strong.strong_count(),
Either::Weak(weak) => weak.strong_count(),
}
}
fn into_either(self) -> Either {
self
}
}