reborrow/
lib.rs

1//! Emulate reborrowing for user types.
2//!
3//! A generalized reference is a type that has reference semantics, without actually being
4//! a native Rust reference (like `&T` and `&mut T`). e.g.:
5//!
6//! ```
7//! struct MyRefMut<'borrow> {
8//!     a: &'borrow mut i32,
9//!     b: &'borrow mut i32,
10//! }
11//! ```
12//!
13//! Given a `&'a` \[mut\] reference of a `&'b` view over some owned object,
14//! reborrowing it means getting an active `&'a` view over the owned object,
15//! which renders the original reference inactive until it's dropped, at which point
16//! the original reference becomes active again.
17//!
18//! This crate defines traits to make generalized references more ergonomic to use by giving the
19//! ability to borrow and reborrow them.
20//!
21//! # Examples:
22//! This fails to compile since we can't use a non-`Copy` value after it's moved.
23//! ```compile_fail
24//! fn takes_mut_option(o: Option<&mut i32>) {}
25//!
26//! let mut x = 0;
27//! let o = Some(&mut x);
28//! takes_mut_option(o); // `o` is moved here,
29//! takes_mut_option(o); // so it can't be used here.
30//! ```
31//!
32//! This can be worked around by unwrapping the option, reborrowing it, and then wrapping it again.
33//! ```
34//! fn takes_mut_option(o: Option<&mut i32>) {}
35//!
36//! let mut x = 0;
37//! let mut o = Some(&mut x);
38//! takes_mut_option(o.as_mut().map(|r| &mut **r)); // "Reborrowing" the `Option`
39//! takes_mut_option(o.as_mut().map(|r| &mut **r)); // allows us to use it later on.
40//! drop(o); // can still be used here
41//! ```
42//!
43//! Using this crate, this can be shortened to
44//! ```
45//! use reborrow::ReborrowMut;
46//!
47//! fn takes_mut_option(o: Option<&mut i32>) {}
48//!
49//! let mut x = 0;
50//! let mut o = Some(&mut x);
51//! takes_mut_option(o.rb_mut()); // "Reborrowing" the `Option`
52//! takes_mut_option(o.rb_mut()); // allows us to use it later on.
53//! drop(o); // can still be used here
54//! ```
55//!
56//! The derive macro can be used with structs or tuple structs, on the mutable variant and
57//! generates the trait definitions for [`Reborrow`], [`ReborrowMut`], and [`IntoConst`].
58//!
59//! ```
60//! use reborrow::{ReborrowCopyTraits, ReborrowTraits};
61//!
62//! #[derive(ReborrowCopyTraits)]
63//! pub struct I32Ref<'a, 'b> {
64//!     pub i: i32,
65//!     pub j: &'a i32,
66//!     pub k: &'b i32,
67//! }
68//!
69//! #[derive(ReborrowCopyTraits)]
70//! pub struct I32TupleRef<'a, 'b>(pub i32, pub &'a i32, pub &'b i32);
71//!
72//! #[derive(ReborrowTraits)]
73//! #[Const(I32Ref)]
74//! struct I32RefMut<'a, 'b> {
75//!     i: i32,
76//!     #[reborrow]
77//!     j: &'a mut i32,
78//!     #[reborrow]
79//!     k: &'b mut i32,
80//! }
81//!
82//! #[derive(ReborrowTraits)]
83//! #[Const(I32TupleRef)]
84//! pub struct I32TupleRefMut<'a, 'b>(
85//!     i32,
86//!     #[reborrow] &'a mut i32,
87//!     #[reborrow] &'b mut i32,
88//! );
89//! ```
90#![no_std]
91
92// _Outlives: suggestion from /u/YatoRust
93// https://www.reddit.com/r/rust/comments/tjzy97/reborrow_emulating_reborrowing_for_user_types/i1nco4i/
94
95#[cfg(feature = "derive")]
96pub use reborrow_derive::{ReborrowCopyTraits, ReborrowTraits};
97
98/// Immutable reborrowing.
99pub trait Reborrow<'short, _Outlives = &'short Self> {
100    type Target;
101    #[must_use]
102    fn rb(&'short self) -> Self::Target;
103}
104
105/// Mutable reborrowing.
106pub trait ReborrowMut<'short, _Outlives = &'short Self> {
107    type Target;
108    #[must_use]
109    fn rb_mut(&'short mut self) -> Self::Target;
110}
111
112/// Consume a mutable reference to produce an immutable one.
113pub trait IntoConst {
114    type Target;
115    #[must_use]
116    fn into_const(self) -> Self::Target;
117}
118
119/// This trait is similar to [`std::convert::AsRef`], but works with generalized reference
120/// types, instead of being limited to native Rust references.
121pub trait AsGeneralizedRef<'short, Target, _Outlives = &'short Self> {
122    #[must_use]
123    fn as_generalized_ref(&'short self) -> Target;
124}
125
126/// This trait is similar to [`std::convert::AsMut`], but works with generalized reference
127/// types, instead of being limited to native Rust references.
128pub trait AsGeneralizedMut<'short, Target, _Outlives = &'short Self> {
129    #[must_use]
130    fn as_generalized_mut(&'short mut self) -> Target;
131}
132
133impl<'short, T: ?Sized + AsRef<Target>, Target: ?Sized> AsGeneralizedRef<'short, &'short Target>
134    for T
135{
136    #[inline]
137    fn as_generalized_ref(&'short self) -> &'short Target {
138        self.as_ref()
139    }
140}
141
142impl<'short, T: ?Sized + AsMut<Target>, Target: ?Sized> AsGeneralizedMut<'short, &'short mut Target>
143    for T
144{
145    #[inline]
146    fn as_generalized_mut(&'short mut self) -> &'short mut Target {
147        self.as_mut()
148    }
149}
150
151impl<'short, 'a, T> Reborrow<'short> for &'a T
152where
153    T: ?Sized,
154{
155    type Target = &'short T;
156
157    #[inline]
158    fn rb(&'short self) -> Self::Target {
159        *self
160    }
161}
162
163impl<'short, 'a, T> ReborrowMut<'short> for &'a T
164where
165    T: ?Sized,
166{
167    type Target = &'short T;
168
169    #[inline]
170    fn rb_mut(&'short mut self) -> Self::Target {
171        *self
172    }
173}
174
175impl<'a, T> IntoConst for &'a T
176where
177    T: ?Sized,
178{
179    type Target = &'a T;
180
181    #[inline]
182    fn into_const(self) -> Self::Target {
183        self
184    }
185}
186
187impl<'short, 'a, T> Reborrow<'short> for &'a mut T
188where
189    T: ?Sized,
190{
191    type Target = &'short T;
192
193    #[inline]
194    fn rb(&'short self) -> Self::Target {
195        *self
196    }
197}
198
199impl<'short, 'a, T> ReborrowMut<'short> for &'a mut T
200where
201    T: ?Sized,
202{
203    type Target = &'short mut T;
204
205    #[inline]
206    fn rb_mut(&'short mut self) -> Self::Target {
207        *self
208    }
209}
210
211impl<'a, T> IntoConst for &'a mut T
212where
213    T: ?Sized,
214{
215    type Target = &'a T;
216
217    #[inline]
218    fn into_const(self) -> Self::Target {
219        self
220    }
221}
222
223impl<'short, T> Reborrow<'short> for Option<T>
224where
225    T: Reborrow<'short>,
226{
227    type Target = Option<T::Target>;
228
229    #[inline]
230    fn rb(&'short self) -> Self::Target {
231        match self {
232            &None => None,
233            &Some(ref x) => Some(x.rb()),
234        }
235    }
236}
237
238impl<'short, T> ReborrowMut<'short> for Option<T>
239where
240    T: ReborrowMut<'short>,
241{
242    type Target = Option<T::Target>;
243
244    #[inline]
245    fn rb_mut(&'short mut self) -> Self::Target {
246        match self {
247            &mut None => None,
248            &mut Some(ref mut x) => Some(x.rb_mut()),
249        }
250    }
251}
252
253impl<T> IntoConst for Option<T>
254where
255    T: IntoConst,
256{
257    type Target = Option<T::Target>;
258
259    #[inline]
260    fn into_const(self) -> Self::Target {
261        match self {
262            None => None,
263            Some(x) => Some(x.into_const()),
264        }
265    }
266}
267
268impl<'short, T: AsGeneralizedRef<'short, Target>, Target> AsGeneralizedRef<'short, Option<Target>>
269    for Option<T>
270{
271    #[inline]
272    fn as_generalized_ref(&'short self) -> Option<Target> {
273        match self {
274            None => None,
275            &Some(ref x) => Some(x.as_generalized_ref()),
276        }
277    }
278}
279
280impl<'short, T: AsGeneralizedMut<'short, Target>, Target> AsGeneralizedMut<'short, Option<Target>>
281    for Option<T>
282{
283    #[inline]
284    fn as_generalized_mut(&'short mut self) -> Option<Target> {
285        match self {
286            None => None,
287            &mut Some(ref mut x) => Some(x.as_generalized_mut()),
288        }
289    }
290}
291
292#[cfg(test)]
293mod tests {
294    use super::*;
295
296    #[test]
297    fn option() {
298        let mut a = 0;
299        let mut opt = Some(&mut a);
300        let opt_mut = &mut opt;
301        let _ = opt_mut.rb_mut();
302    }
303
304    #[test]
305    fn custom_view_type() {
306        struct MyViewType<'a> {
307            r: &'a mut i32,
308        }
309
310        impl<'short, 'a> ReborrowMut<'short> for MyViewType<'a> {
311            type Target = MyViewType<'short>;
312
313            fn rb_mut(&'short mut self) -> Self::Target {
314                MyViewType { r: self.r }
315            }
316        }
317
318        fn takes_mut_option(_o: Option<MyViewType>) {}
319
320        let mut x = 0;
321        let mut o = Some(MyViewType { r: &mut x });
322        takes_mut_option(o.rb_mut());
323        takes_mut_option(o.rb_mut());
324        drop(o);
325    }
326
327    #[test]
328    fn as_ref() {
329        let v = [()];
330        let _r: &[()] = v.as_generalized_ref();
331    }
332}