1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3#![warn(rustdoc::missing_crate_level_docs)]
4use std::mem;
17#[cfg(feature = "sync")]
18#[doc(hidden)]
19pub use std::sync::{Arc as Strong, Weak};
20
21#[cfg(not(feature = "sync"))]
22#[doc(hidden)]
23pub use std::rc::{Rc as Strong, Weak};
24
25#[derive(Debug)]
27pub enum RCell<T> {
28 Strong(Strong<T>),
30 Weak(Weak<T>),
32 Empty,
34}
35
36impl<T> RCell<T> {
37 pub fn new(value: T) -> Self {
39 RCell::Strong(Strong::new(value))
40 }
41
42 pub fn retained(&self) -> bool {
44 matches!(*self, RCell::Strong(_))
45 }
46
47 pub fn refcount(&self) -> usize {
51 match self {
52 RCell::Strong(arc) => Strong::strong_count(arc),
53 RCell::Weak(weak) => weak.strong_count(),
54 RCell::Empty => 0,
55 }
56 }
57
58 pub fn retain(&mut self) -> Option<Strong<T>> {
62 match self {
63 RCell::Strong(strong) => Some(strong.clone()),
64 RCell::Weak(weak) => {
65 if let Some(strong) = weak.upgrade() {
66 let _ = mem::replace(self, RCell::Strong(strong.clone()));
67 Some(strong)
68 } else {
69 None
70 }
71 }
72 RCell::Empty => None,
73 }
74 }
75
76 pub fn release(&mut self) {
79 if let Some(weak) = match self {
80 RCell::Strong(strong) => Some(Strong::downgrade(strong)),
81 RCell::Weak(weak) => Some(weak.clone()),
82 RCell::Empty => None,
83 } {
84 if weak.strong_count() > 0 {
85 let _ = mem::replace(self, RCell::Weak(weak));
86 } else {
87 let _ = mem::replace(self, RCell::Empty);
88 }
89 }
90 }
91
92 pub fn remove(&mut self) {
96 let _ = mem::replace(self, RCell::Empty);
97 }
98
99 pub fn request(&self) -> Option<Strong<T>> {
102 match self {
103 RCell::Strong(arc) => Some(arc.clone()),
104 RCell::Weak(weak) => weak.upgrade(),
105 RCell::Empty => None,
106 }
107 }
108}
109
110pub trait Replace<T> {
112 fn replace(&mut self, new: T);
114}
115
116impl<T> Replace<Strong<T>> for RCell<T> {
117 fn replace(&mut self, strong: Strong<T>) {
119 let _ = mem::replace(self, RCell::Strong(strong));
120 }
121}
122
123impl<T> Replace<Weak<T>> for RCell<T> {
124 fn replace(&mut self, weak: Weak<T>) {
126 let _ = mem::replace(self, RCell::Weak(weak));
127 }
128}
129
130impl<T> From<Strong<T>> for RCell<T> {
131 fn from(strong: Strong<T>) -> Self {
133 RCell::Strong(strong)
134 }
135}
136
137impl<T> From<Weak<T>> for RCell<T> {
138 fn from(weak: Weak<T>) -> Self {
140 RCell::Weak(weak)
141 }
142}
143
144impl<T> Default for RCell<T> {
145 fn default() -> Self {
147 RCell::Empty
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use crate::{RCell, Strong, Replace};
154
155 #[test]
156 fn smoke() {
157 let rcell = RCell::new("foobar");
158 assert!(rcell.retained());
159 }
160
161 #[test]
162 fn new() {
163 let mut rcell = RCell::new("foobar");
164 assert!(rcell.retained());
165 assert_eq!(*rcell.request().unwrap(), "foobar");
166 rcell.release();
167 assert_eq!(rcell.request(), None);
168 }
169
170 #[test]
171 fn default() {
172 let rcell = RCell::<i32>::default();
173 assert!(!rcell.retained());
174 assert_eq!(rcell.request(), None);
175 }
176
177 #[test]
178 fn from_strong() {
179 let strong = Strong::new("foobar");
180 let mut rcell = RCell::from(strong);
181 assert!(rcell.retained());
182 assert_eq!(*rcell.request().unwrap(), "foobar");
183 rcell.release();
184 assert_eq!(rcell.request(), None);
185 }
186
187 #[test]
188 fn from_weak_release() {
189 let strong = Strong::new("foobar");
190 let weak = Strong::downgrade(&strong);
191 let mut rcell = RCell::from(weak);
192 assert!(!rcell.retained());
193 assert_eq!(*rcell.request().unwrap(), "foobar");
194 rcell.release();
195 assert_eq!(*rcell.request().unwrap(), "foobar");
196 rcell.remove();
197 assert_eq!(rcell.request(), None);
198 }
199
200 #[test]
201 fn from_weak_drop_original() {
202 let strong = Strong::new("foobar");
203 let weak = Strong::downgrade(&strong);
204 let mut rcell = RCell::from(weak);
205 assert!(!rcell.retained());
206 assert_eq!(*rcell.request().unwrap(), "foobar");
207 drop(strong);
208 assert_eq!(rcell.request(), None);
209 rcell.remove();
210 assert_eq!(rcell.request(), None);
211 }
212
213 #[test]
214 fn replace_strong() {
215 let mut rcell = RCell::default();
216 assert!(!rcell.retained());
217 rcell.replace(Strong::new("foobar"));
218 assert_eq!(*rcell.request().unwrap(), "foobar");
219 rcell.remove();
220 assert_eq!(rcell.request(), None);
221 }
222
223 #[test]
224 fn replace_weak() {
225 let strong = Strong::new("foobar");
226 let mut rcell = RCell::default();
227 assert!(!rcell.retained());
228 rcell.replace(Strong::downgrade(&strong));
229 assert_eq!(*rcell.request().unwrap(), "foobar");
230 rcell.remove();
231 assert_eq!(rcell.request(), None);
232 }
233}