1use std::cell::BorrowError;
38use std::cell::Cell;
39use std::cell::Ref;
40use std::cell::RefCell;
41use std::cmp::Ordering;
42use std::fmt;
43use std::fmt::Display;
44use std::hash::Hash;
45use std::hash::Hasher;
46use std::mem;
47use std::ops::Deref;
48
49use crate::cast;
50
51#[derive(Debug)]
55pub struct ARef<'a, T: ?Sized + 'a> {
56 value: &'a T,
57 borrow: Option<&'a Cell<isize>>,
58}
59
60impl<T: ?Sized> Drop for ARef<'_, T> {
61 fn drop(&mut self) {
62 if self.borrow.is_some() {
63 let me: ARef<T> = ARef {
64 value: self.value,
65 borrow: self.borrow,
66 };
67 let them: Ref<T> = unsafe { cast::transmute_unchecked(me) };
69 mem::drop(them);
71 }
72 }
73}
74
75impl<T: ?Sized> Deref for ARef<'_, T> {
76 type Target = T;
77
78 fn deref(&self) -> &T {
79 self.value
80 }
81}
82
83impl<'a, T: ?Sized + 'a> ARef<'a, T> {
84 pub fn new_ptr(x: &'a T) -> Self {
86 ARef {
87 value: x,
88 borrow: None,
89 }
90 }
91
92 pub fn new_ref(x: Ref<'a, T>) -> Self {
94 let v: ARef<T> = unsafe { cast::transmute_unchecked(x) };
99 debug_assert!(v.borrow.is_some());
100 v
101 }
102
103 #[allow(clippy::should_implement_trait)]
105 pub fn clone(orig: &Self) -> Self {
106 if orig.borrow.is_none() {
107 ARef::new_ptr(orig.value)
108 } else {
109 let orig: &Ref<T> = unsafe { cast::ptr(orig) };
110 Self::new_ref(Ref::clone(orig))
111 }
112 }
113
114 pub fn map<U: ?Sized, F>(orig: ARef<'a, T>, f: F) -> ARef<'a, U>
116 where
117 F: FnOnce(&T) -> &U,
118 {
119 let res = ARef {
121 value: f(orig.value),
122 borrow: orig.borrow,
123 };
124 #[allow(clippy::mem_forget)]
127 mem::forget(orig);
128 res
129 }
130
131 pub fn map_split<U: ?Sized, V: ?Sized, F>(orig: ARef<'a, T>, f: F) -> (ARef<'a, U>, ARef<'a, V>)
134 where
135 F: FnOnce(&T) -> (&U, &V),
136 {
137 if orig.borrow.is_none() {
138 let (a, b) = f(orig.value);
139 (ARef::new_ptr(a), ARef::new_ptr(b))
140 } else {
141 let orig: Ref<T> = unsafe { cast::transmute_unchecked(orig) };
142 let (a, b) = Ref::map_split(orig, f);
143 (ARef::new_ref(a), ARef::new_ref(b))
144 }
145 }
146
147 pub fn filter_map<U: ?Sized, F>(orig: ARef<'a, T>, f: F) -> Result<ARef<'a, U>, Self>
150 where
151 F: FnOnce(&T) -> Option<&U>,
152 {
153 match f(orig.value) {
154 Some(value) => {
155 let res = Ok(ARef {
156 value,
157 borrow: orig.borrow,
158 });
159 #[allow(clippy::mem_forget)]
162 mem::forget(orig);
163 res
164 }
165 None => Err(orig),
166 }
167 }
168}
169
170impl<T: Display + ?Sized> Display for ARef<'_, T> {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 ARef::deref(self).fmt(f)
177 }
178}
179
180impl<T: Hash + ?Sized> Hash for ARef<'_, T> {
181 fn hash<H: Hasher>(&self, state: &mut H) {
182 ARef::deref(self).hash(state)
183 }
184}
185
186impl<A: PartialEq<B> + ?Sized, B: ?Sized> PartialEq<ARef<'_, B>> for ARef<'_, A> {
187 fn eq(&self, other: &ARef<'_, B>) -> bool {
188 ARef::deref(self).eq(ARef::deref(other))
189 }
190}
191
192impl<A: Eq + ?Sized> Eq for ARef<'_, A> {}
193
194impl<A: PartialOrd<B> + ?Sized, B: ?Sized> PartialOrd<ARef<'_, B>> for ARef<'_, A> {
195 fn partial_cmp(&self, other: &ARef<'_, B>) -> Option<Ordering> {
196 ARef::deref(self).partial_cmp(ARef::deref(other))
197 }
198}
199
200impl<A: Ord + ?Sized> Ord for ARef<'_, A> {
201 fn cmp(&self, other: &Self) -> Ordering {
202 ARef::deref(self).cmp(ARef::deref(other))
203 }
204}
205
206pub trait AsARef<T: ?Sized> {
208 fn as_aref(this: &Self) -> ARef<T>;
210 fn try_as_aref(this: &Self) -> Result<ARef<T>, BorrowError>;
213 fn as_ref_cell(this: &Self) -> Option<&RefCell<T>>;
215}
216
217impl<T: ?Sized> AsARef<T> for T {
218 fn as_aref(this: &Self) -> ARef<T> {
219 ARef::new_ptr(this)
220 }
221 fn try_as_aref(this: &Self) -> Result<ARef<T>, BorrowError> {
222 Ok(ARef::new_ptr(this))
223 }
224 fn as_ref_cell(_this: &Self) -> Option<&RefCell<T>> {
225 None
226 }
227}
228
229impl<T: ?Sized> AsARef<T> for RefCell<T> {
230 fn as_aref(this: &Self) -> ARef<T> {
231 ARef::new_ref(this.borrow())
232 }
233 fn try_as_aref(this: &Self) -> Result<ARef<T>, BorrowError> {
234 Ok(ARef::new_ref(this.try_borrow()?))
235 }
236 fn as_ref_cell(this: &Self) -> Option<&RefCell<T>> {
237 Some(this)
238 }
239}
240
241#[cfg(test)]
242mod tests {
243 use std::cell::RefCell;
244 use std::mem;
245
246 use super::*;
247 use crate::cast;
248
249 #[test]
250 fn test_from_ref_docs() {
251 let c = RefCell::new((5, 'b'));
252 let b1: ARef<(u32, char)> = ARef::new_ref(c.borrow());
253 let b2: ARef<u32> = ARef::map(b1, |t| &t.0);
254 assert_eq!(*b2, 5);
255
256 let cell = RefCell::new([1, 2, 3, 4]);
257 let borrow = ARef::new_ref(cell.borrow());
258 let (begin, end) = ARef::map_split(borrow, |slice| slice.split_at(2));
259 assert_eq!(*begin, [1, 2]);
260 assert_eq!(*end, [3, 4]);
261 }
262
263 #[test]
264 fn test_borrow_guards() {
265 let c = RefCell::new(5);
266 assert!(c.try_borrow_mut().is_ok());
267 let r1 = ARef::new_ref(c.borrow());
268 assert!(c.try_borrow_mut().is_err());
269 let r2 = c.borrow();
270 assert!(c.try_borrow_mut().is_err());
271 mem::drop(r1);
272 assert!(c.try_borrow_mut().is_err());
273 mem::drop(r2);
274 assert!(c.try_borrow_mut().is_ok());
275 }
276
277 #[test]
278 fn test_pointer_basics() {
279 let c = "test".to_owned();
280 let p = ARef::new_ptr(&c);
281 let p2 = ARef::map(p, |x| &x[1..3]);
282 assert_eq!(&*p2, "es");
283 }
284
285 #[test]
286 fn test_ref_map_dropping() {
287 let c = RefCell::new("test".to_owned());
288 let p = ARef::new_ref(c.borrow());
289 let p = ARef::map(p, |x| &x[1..3]);
290 assert_eq!(&*p, "es");
291 mem::drop(p);
292 assert!(c.try_borrow_mut().is_ok());
293 }
294
295 #[test]
296 fn test_ref_filter_map_dropping() {
297 let c = RefCell::new("test".to_owned());
298 let p = ARef::new_ref(c.borrow());
299 let p = ARef::filter_map(p, |x| Some(&x[1..3])).unwrap();
300 assert_eq!(&*p, "es");
301 mem::drop(p);
302 assert!(c.try_borrow_mut().is_ok());
303 }
304
305 #[test]
306 fn test_ref_as_expected() {
308 let orig = RefCell::new("test".to_owned());
309 let p = orig.borrow();
310 let p2 = Ref::clone(&p);
311 let (pointer, cell): (usize, usize) = unsafe { mem::transmute(p) };
312 assert_eq!(pointer, cast::ptr_to_usize(Ref::deref(&p2)));
314 assert_ne!(cell, 0);
316
317 let _ignore: Ref<String> = unsafe { mem::transmute((pointer, cell)) };
319 }
320
321 #[test]
322 fn test_as_aref() {
323 fn get_str(x: &impl AsARef<String>) -> ARef<str> {
324 ARef::map(AsARef::as_aref(x), |x| x.as_str())
325 }
326
327 let a = RefCell::new("hello".to_owned());
328 let b = "world".to_owned();
329 assert_eq!(&*get_str(&a), "hello");
330 assert_eq!(&*get_str(&b), "world");
331 }
332}