-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathborrow_ref.rs
128 lines (121 loc) · 3.92 KB
/
borrow_ref.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
// Note: you can use `cargo expand path::to::this::file` to debug the macro :)
// Planned/Todo:
// + it might be useful to pass an entire function body to the macro
// the problem is, that you can't pass 'self' to a macro like this:
// borrow_mut![... => RefCell::borrow_mut(self) => ...];
// + might export the macros
// + merge the macros?
use core::cell::{Ref, RefCell};
use core::ops::Deref;
/// A trait for immutably borrowing data.
///
/// The `borrow` function returns an immutable reference to `Self::Target`.
/// I strongly discourage implementing the trait in it's current form, as it will change in the
/// near future!
/// ```
/// use std::ops::Deref;
/// use std::cell::RefCell;
/// use borrow_trait::{ BorrowRef };
///
/// fn takes_bound<T>(value: &T)
/// where
/// T: for<'a> BorrowRef<'a, Target = String>,
/// {
/// assert_eq!(value.borrow().deref(), &"Hello World".to_string());
/// }
///
/// let value = RefCell::new("Hello World".to_string());
/// takes_bound(&value)
/// ```
/// # Implementation Example
/// Implementing `BorrowRef` for RefCell:
/// ``` ignore
/// use std::cell::{ Ref, RefCell };
/// use borrow_trait::{ BorrowRef };
///
/// impl<'a, T: 'a> BorrowRef<'a> for RefCell<T> {
/// type Target = T;
/// type Pointer = Ref<'a, Self::Target>;
///
/// fn borrow(&'a self) -> Self::Pointer { RefCell::borrow(self) }
/// }
/// ```
pub trait BorrowRef<'a> {
/// The type, that is wrapped by the implementation.
/// # Example
/// A `RefCell<T>` wraps around `T`, therefore `Target` has to be `T`
/// ``` ignore
/// type Target = T;
/// ```
type Target;
/// The type returned by the implementor.
/// # Example
/// A `RefCell` returns `RefMut` so `Pointer` has to be `RefMut`.
/// ``` ignore
/// type Pointer = RefMut<'a, Self::Target>;
/// ```
type Pointer: 'a + Deref<Target = Self::Target>;
/// Immutably borrows the wrapped value.
/// Multiple immutable borrows can be taken out at the same time.
/// # Panics
/// The function should panic, if the value is currently mutably borrowed.
/// # Example
/// ```
/// use std::ops::Deref;
/// use std::cell::RefCell;
/// use borrow_trait::{ BorrowRef };
///
/// fn takes_bound<T>(value: &T)
/// where
/// T: for<'a> BorrowRef<'a, Target = String>,
/// {
/// let first_borrow = value.borrow();
/// let second_borrow = value.borrow();
///
/// assert_eq!(first_borrow.deref(), &"Hello World".to_string());
/// assert_eq!(second_borrow.deref(), &"Hello World".to_string());
/// }
///
/// let value = RefCell::new("Hello World".to_string());
/// takes_bound(&value)
/// ```
fn borrow(&'a self) -> Self::Pointer;
}
macro_rules! borrow_ref {
(
$( $pointer:ty => $body:path => $( $name:ty ),* );*
$(;)* // <- allows to have a trailing semi-colon
) => {
$(
$(
impl<'a, T: 'a> BorrowRef<'a> for $name {
type Target = T;
type Pointer = $pointer;
#[inline]
fn borrow(&'a self) -> Self::Pointer { $body(self) }
}
)* // repeat for each value, seperated by ','
)* // repeat for each line, seperated by ';'
};
}
borrow_ref![
Ref<'a, T> => RefCell::borrow => RefCell<T>, &RefCell<T>, &mut RefCell<T>;
];
// AtomicRefCell
#[cfg(all(feature = "atomic_refcell", feature = "alloc"))]
use atomic_refcell::{AtomicRef, AtomicRefCell};
#[cfg(all(feature = "atomic_refcell", feature = "alloc"))]
borrow_ref![
AtomicRef<'a, T> =>
AtomicRefCell::borrow =>
AtomicRefCell<T>, &AtomicRefCell<T>, &mut AtomicRefCell<T>;
];
// Cell
#[cfg(all(feature = "cell", feature = "alloc"))]
use cell;
#[cfg(all(feature = "cell", feature = "alloc"))]
borrow_ref![
cell::Ref<'a, T> =>
cell::RefCell::borrow =>
cell::RefCell<T>, &cell::RefCell<T>, &mut cell::RefCell<T>;
];