maycoon_core/
reference.rs

1use std::ops::Deref;
2use std::sync::RwLockReadGuard;
3
4/// Represents a reference to a value of type `T`.
5///
6/// Due to Rust's temporal borrowing rules,
7/// returning a reference to a value may not be always possible,
8/// so this enum is used to represent one by having multiple variants for multiple types of references.
9pub enum Ref<'a, T> {
10    /// An owned value. Useful for [Copy] types.
11    Owned(T),
12    /// A borrowed reference.
13    Borrow(&'a T),
14    /// A reference of a [std::cell::Ref].
15    Ref(std::cell::Ref<'a, T>),
16    /// A [RwLockReadGuard] reference.
17    ReadGuard(RwLockReadGuard<'a, T>),
18}
19
20impl<'a, T> Deref for Ref<'a, T> {
21    type Target = T;
22
23    #[inline(always)]
24    fn deref(&self) -> &Self::Target {
25        match self {
26            Ref::Owned(value) => value,
27            Ref::Borrow(value) => value,
28            Ref::Ref(value) => value,
29            Ref::ReadGuard(value) => value,
30        }
31    }
32}
33
34impl<'a, T> From<T> for Ref<'a, T> {
35    #[inline(always)]
36    fn from(value: T) -> Self {
37        Ref::Owned(value)
38    }
39}
40
41impl<'a, T> From<&'a T> for Ref<'a, T> {
42    #[inline(always)]
43    fn from(value: &'a T) -> Self {
44        Ref::Borrow(value)
45    }
46}
47
48impl<'a, T> From<std::cell::Ref<'a, T>> for Ref<'a, T> {
49    #[inline(always)]
50    fn from(value: std::cell::Ref<'a, T>) -> Self {
51        Ref::Ref(value)
52    }
53}
54
55impl<'a, T> From<RwLockReadGuard<'a, T>> for Ref<'a, T> {
56    #[inline(always)]
57    fn from(value: RwLockReadGuard<'a, T>) -> Self {
58        Ref::ReadGuard(value)
59    }
60}
61
62#[cfg(all(test, feature = "test"))]
63mod tests {
64    use crate::reference::Ref;
65    use std::cell::RefCell;
66    use std::fmt::Debug;
67    use std::sync::RwLock;
68
69    #[test_case::test_case(1; "with int")]
70    #[test_case::test_case("Test".to_string(); "with string")]
71    #[test_case::test_case(vec![1, 2, 3]; "with vector")]
72    fn test_ref<T: Clone + PartialEq + Debug>(value: T) {
73        let r_bor = Ref::Borrow(&value);
74        assert_eq!(*r_bor, value);
75
76        let r_own = Ref::Owned(value.clone());
77        assert_eq!(*r_own, value);
78
79        let refcell = RefCell::new(value.clone());
80        let r_ref = Ref::Ref(refcell.borrow());
81        assert_eq!(*r_ref, value);
82
83        let rwlock = RwLock::new(value.clone());
84        let r_rw = Ref::ReadGuard(rwlock.read().unwrap());
85        assert_eq!(*r_rw, value);
86    }
87
88    /// Tests if the size of [Ref] is correct.
89    ///
90    /// Useful for not accidentally increasing the stack size of [Ref].
91    #[test]
92    fn test_ref_size() {
93        const SIZE: usize = 24;
94
95        assert_eq!(size_of::<Ref<'_, u8>>(), SIZE);
96    }
97}