mappable_rc/
lib.rs

1//! Provides mappable `Rc` and `Arc` implementations.
2//!
3//! This crate provides two types: [`Marc`] and [`Mrc`], corresponding to `std`'s [`Arc`] and [`Rc`]
4//! types. For the most part, these types are near drop in replacements; they also provide shared
5//! ownership via reference countings, many of the same methods, and almost all of the same trait
6//! impls. The key difference is the existence of the `map` method on both types. For example, you
7//! can use [`Mrc::map`] to subslice an `Mrc<[u32]>`:
8//!
9//! ```rust
10//! use mappable_rc::Mrc;
11//!
12//! let m: Mrc<[u32]> = vec![1, 2, 3, 4].into();
13//! assert_eq!(m.as_ref(), &[1, 2, 3, 4]);
14//!
15//! let m: Mrc<[u32]> = Mrc::map(m, |slice| &slice[1..=2]);
16//! assert_eq!(m.as_ref(), &[2, 3]);
17//! ```
18//!
19//! The `map` functions do not require preserving types. For example:
20//!
21//! ```rust
22//! use mappable_rc::Mrc;
23//!
24//! struct S(u32);
25//!
26//! let m: Mrc<S> = Mrc::new(S(5));
27//! let inner: Mrc<u32> = Mrc::map(m, |s| &s.0);
28//!
29//! assert_eq!(inner.as_ref(), &5);
30//! ```
31//!
32//! You can use the types provided by this crate even if other code hands you an `Rc` or an `Arc`.
33//! See the [`Mrc::from_rc`] and [`Marc::from_arc`] methods, and the corresponding `From` impls.
34//!
35//! ## Performance
36//!
37//! The performance characteristics of the types in this crate are very similar to the corresponding
38//! `std` types. The data pointer is stored directly in the struct, and so the referenced data is
39//! only one indirection away. The `Marc` implementation internally reuses the `Arc` from `std`, and
40//! so the atomic operations are expected to be no more or less efficient.
41//!
42//! A number of the trait implementations in this crate are more efficient than the corresponding
43//! `std` implementsions. `Mrc<[T]>: From<Vec<T>>` is implemented like this:
44//!
45//! ```rust
46//! use mappable_rc::Mrc;
47//!
48//! let v = vec![1; 1000];
49//! let m: Mrc<Vec<i32>> = Mrc::new(v);
50//! let m: Mrc<[i32]> = Mrc::map(m, |v| &v[..]);
51//! ```
52//!
53//! This means that the data in the `Vec` is never copied and only a small allocation is performed.
54//! The same implementation for `Arc<[T]>` will perform a copy of the `Vec`'s data, to ensure that
55//! the memory format complies with the more stringent requirements of `Arc`.
56//!
57//! The main performance downside of these types is that the size of `Mrc` and `Marc` is two
58//! `usize`s greater than the size of the corresponding `std` type.
59//!
60//! ## `#![no_std]`
61//!
62//! This crate is `#![no_std]` by default, but of course depends on `alloc`. There is a non-default
63//! `std` feature that provides implementations of `std::error::Error`, `From<OsString>` and
64//! `From<PathBuf>`. Activating this feature introduces an `std` dependency.
65//!
66//! This crate has no other dependencies.
67
68#![no_std]
69
70use core::ptr::NonNull;
71use core::{any::Any, ops::Deref};
72
73use alloc::rc::Rc;
74use alloc::sync::Arc;
75
76extern crate alloc;
77
78#[cfg(feature = "std")]
79extern crate std;
80
81mod std_impls;
82
83pub struct Marc<T: ?Sized + 'static> {
84    // SAFETY:
85    //  - This is well aligned and points to a valid `T`
86    //  - This is valid for at least as long as `alloc`
87    data: NonNull<T>,
88    alloc: Arc<dyn Any + Send>,
89}
90
91// SAFETY: A `Marc<T>` only gives shared access to a `T`. This impl does not have the `Send` bound
92// that the std impl has; that's because we never hand out a `&mut T` (doing so would be UB anyway).
93// The equivalent of the `Send` bound, is the `Send` requirement for the `alloc`.
94unsafe impl<T: Sync + ?Sized> Send for Marc<T> {}
95
96// SAFETY: A `Marc<T>` being `Sync` is basically equivalent to it being `Send`, so we require the
97// same bounds.
98unsafe impl<T: Sync + ?Sized> Sync for Marc<T> {}
99
100pub struct Mrc<T: ?Sized + 'static> {
101    // SAFETY:
102    //  - This is well aligned and points to a valid `T`
103    //  - This is valid for at least as long as `alloc`
104    data: NonNull<T>,
105    // Guarantees that we're non-`Send` and non-`Sync`
106    alloc: Rc<dyn Any>,
107}
108
109macro_rules! impls {
110    ($name:ident, $l:literal) => {
111        impl<T: ?Sized> Deref for $name<T> {
112            type Target = T;
113
114            fn deref(&self) -> &T {
115                // SAFETY: See safety comment on the field
116                unsafe { self.data.as_ref() }
117            }
118        }
119
120        impl<T: ?Sized> $name<T> {
121            /// Returns a read-only pointer to the referred to data.
122            ///
123            /// The pointer is valid for as long as this value is alive.
124            pub fn as_ptr(&self) -> *const T {
125                self.data.as_ptr() as *const _
126            }
127
128            /// Maps the value to a new
129            #[doc = concat!("`", $l, "`")]
130            /// that refers to the data returned by the closure.
131            ///
132            /// This only changes what data *this particular*
133            #[doc = concat!("`", $l, "`")]
134            /// refers to. It does not introduce mutability - any
135            #[doc = concat!("`", $l, "<T>`s")]
136            /// you've cloned from this one in the past still point to the same thing. Of course, if
137            /// you clone the value returned by this function, then the resulting
138            #[doc = concat!("`", $l, "<U>`s")]
139            /// will also point to the mapped value.
140            ///
141            /// This does not cause the `T` to be dropped early. Even if the `&U` refers to only a
142            /// part of the `&T`, no part of the `T` is dropped until all references to or into the
143            /// `T` are gone, at which point the entire `T` is dropped at once.
144            pub fn map<U: ?Sized + 'static, F: FnOnce(&T) -> &U>(self_: Self, f: F) -> $name<U> {
145                let r = self_.deref();
146                // Panic safety: Panicking here only causes `orig` to be dropped
147                let out = f(r) as *const _;
148                // SAFETY: Pointer is the result of a reference, so not null.
149                let data = unsafe { NonNull::new_unchecked(out as *mut _) };
150                // SAFETY: The "actual" lifetime being passed to `f` should be understood to be the lifetime
151                // of `self.alloc`. In other words the reference passed into `f` is valid as long as
152                // `alloc` is. Hence it satisfies the safety requirements for `data`. Using a fake lifetime
153                // here is ok because lifetime specilization is not possible.
154                $name {
155                    data,
156                    alloc: self_.alloc,
157                }
158            }
159
160            /// Attempts to map the
161            #[doc = concat!("`", $l, "<T>`")]
162            /// , returning the new value on success and the old value otherwise.
163            ///
164            /// This is simply a fallible version of
165            #[doc = concat!("[`", $l, "::map`]")]
166            /// , and generally has all the same properties.
167            pub fn try_map<U: ?Sized + 'static, F: FnOnce(&T) -> Option<&U>>(
168                self_: Self,
169                f: F,
170            ) -> Result<$name<U>, $name<T>> {
171                let r = self_.deref();
172                match f(r) {
173                    Some(p) => {
174                        // SAFETY: For all safety concerns, see `map`
175                        let data = unsafe { NonNull::new_unchecked(p as *const _ as *mut _) };
176                        Ok($name {
177                            data,
178                            alloc: self_.alloc,
179                        })
180                    }
181                    None => Err(self_),
182                }
183            }
184
185            /// Maps the value that the
186            #[doc = concat!("`", $l, "`")]
187            /// refers to, without taking ownership.
188            ///
189            /// This is equivalent to cloning, mapping, and then writing to `self`, except that it
190            /// is slightly more efficient because it avoids the clone.
191            ///
192            /// `self` is left unchanged if `f` panics.
193            pub fn map_in_place<F: FnOnce(&T) -> &T>(self_: &mut Self, f: F) {
194                let r = self_.deref();
195                // Panic safety: `self` is unmodified and the data pointer continues to be valid as
196                // we only hand out immutable references.
197                let out = f(r);
198                // SAFETY: This is effectively the same operation as in `map`.
199                self_.data = unsafe { NonNull::new_unchecked(out as *const _ as *mut _) };
200            }
201        }
202    };
203}
204
205impls!(Marc, "Marc");
206impls!(Mrc, "Mrc");
207
208impl<T: Send + 'static> Marc<T> {
209    /// Creates a new `Marc` from an [`Arc`] that shares ownership of the `Arc`'s data.
210    ///
211    /// Like [`Marc::new`], this method requires `T: Send + Sized + 'static`. If you have an
212    /// `Arc<T>` where `T: ?Sized`, then you can create an `Marc<T>` via [`Marc::from_borrow`].
213    ///
214    /// As long as the returned `Marc` is alive, the strong count of the `Arc` will be at least one.
215    /// This is also the case if any `Marc`'s derived from the return value via [`Clone`] and
216    /// [`Marc::map`] are alive. The strong count of the input `Arc` could be observed by another
217    /// `Arc` also sharing ownership of the data. It is not specified whether clones of the return
218    /// value will be reflected in that strong count.
219    ///
220    /// This function is essentially free to call. After inlining, it will consist of one to two
221    /// pointer copies.
222    pub fn from_arc(arc: Arc<T>) -> Self {
223        let p = Arc::as_ptr(&arc) as *mut T;
224        // SAFETY: The pointer was returned by `Arc::as_ptr` and so is not null
225        unsafe {
226            Self {
227                data: NonNull::new_unchecked(p),
228                alloc: arc,
229            }
230        }
231    }
232
233    /// Creates a new `Marc` that provides shared ownership of the `T`.
234    ///
235    /// This method, like all ways of creating an `Marc`, has a `Send + 'static` bound that is not
236    /// found on the corresponding `Arc` method. You can avoid the `Send` requirement by using
237    /// [`Mrc::from_borrow`] to create an [`Mrc`] instead. The `'static` requirement is
238    /// fundamentally necessary for the soundness of this type and cannot be circumvented.
239    pub fn new(t: T) -> Self {
240        Marc::from_arc(Arc::new(t))
241    }
242}
243
244/// Creates a new `Marc<T>` sharing ownership of the same data.
245impl<T: ?Sized> Clone for Marc<T> {
246    fn clone(&self) -> Self {
247        Self {
248            data: self.data,
249            alloc: Arc::clone(&self.alloc),
250        }
251    }
252}
253
254impl<T: Send + 'static> From<Arc<T>> for Marc<T> {
255    fn from(a: Arc<T>) -> Self {
256        Marc::from_arc(a)
257    }
258}
259
260impl<T: 'static> Mrc<T> {
261    /// Creates a new `Mrc` from an [`Rc`] that shares ownership of the `Rc`'s data.
262    ///
263    /// Like [`Mrc::new`], this method requires `T: Sized + 'static`. If you have an
264    /// `Rc<T>` where `T: ?Sized`, then you can create an `Mrc<T>` via [`Mrc::from_borrow`].
265    ///
266    /// As long as the returned `Mrc` is alive, the strong count of the `Rc` will be at least one.
267    /// This is also the case if any `Mrc`'s derived from the return value via [`Clone`] and
268    /// [`Mrc::map`] are alive. The strong count of the input `Rc` could be observed by another `Rc`
269    /// also sharing ownership of the data. It is not specified whether clones of the return value
270    /// will be reflected in that strong count.
271    ///
272    /// This function is essentially free to call. After inlining, it will consist of one to two
273    /// pointer copies.
274    pub fn from_rc(rc: Rc<T>) -> Self {
275        let p = Rc::as_ptr(&rc) as *mut T;
276        // SAFETY: The pointer was returned by `Rc::as_ptr` and so is not null
277        unsafe {
278            Self {
279                data: NonNull::new_unchecked(p),
280                alloc: rc,
281            }
282        }
283    }
284
285    /// Creates a new `Mrc` that provides shared ownership of the `T`.
286    ///
287    /// This method, like all ways of creating an `Mrc`, has a `'static` bound that is not found on
288    /// the corresponding `Rc` method. That requirement is fundamentally necessary for the soundness
289    /// of this type and cannot be circumvented.
290    pub fn new(t: T) -> Self {
291        Mrc::from_rc(Rc::new(t))
292    }
293}
294
295/// Creates a new `Mrc<T>` sharing ownership of the same data.
296impl<T: ?Sized> Clone for Mrc<T> {
297    fn clone(&self) -> Self {
298        Self {
299            data: self.data,
300            alloc: Rc::clone(&self.alloc),
301        }
302    }
303}
304
305impl<T: 'static> From<Rc<T>> for Mrc<T> {
306    fn from(a: Rc<T>) -> Self {
307        Mrc::from_rc(a)
308    }
309}
310
311#[cfg(test)]
312mod tests {
313    use core::{cell::RefCell, marker::PhantomData, ops::DerefMut, panic::AssertUnwindSafe};
314
315    extern crate std;
316
317    use std::panic::catch_unwind;
318
319    use alloc::{string::ToString, vec};
320
321    use crate::*;
322
323    fn is_send<T: Send>(_: &T) {}
324    fn is_sync<T: Sync>(_: &T) {}
325
326    #[test]
327    fn clone_validity() {
328        let v = Mrc::new(vec![1, 2, 3]);
329        let c = v.clone();
330        let c = Mrc::map(c, |c| &c[1..]);
331
332        let v = v;
333        let c = c;
334
335        assert_eq!(&v[..], &[1, 2, 3]);
336        assert_eq!(&c[..], &[2, 3]);
337    }
338
339    #[test]
340    fn rc_validity() {
341        let a = Rc::new(vec![1, 2, 3]);
342        let m = Mrc::from_rc(Rc::clone(&a));
343        let m = Mrc::map(m, |m| &m[1..]);
344
345        let a = a;
346        let m = m;
347
348        assert_eq!(&a[..], &[1, 2, 3]);
349        assert_eq!(&m[..], &[2, 3]);
350    }
351
352    #[test]
353    fn init_correctness() {
354        let a = Rc::new(5);
355        assert_eq!(a.as_ref(), &5);
356
357        let b: Mrc<[i32]> = Mrc::from_borrow(vec![1, 2, 3, 4]);
358        assert_eq!(b.as_ref(), &[1, 2, 3, 4]);
359
360        let c: Mrc<i32> = Mrc::from_rc(Rc::new(5));
361        assert_eq!(c.as_ref(), &5);
362    }
363
364    // Ensures we get a compile error if we break this
365    #[test]
366    fn minimum_impls() {
367        let a = Marc::new(5);
368        is_send(&a);
369        is_sync(&a);
370    }
371
372    // Ensures we get a compile error if we break this
373    #[test]
374    fn non_sized_send_and_sync() {
375        let a: Marc<str> = "foobar".to_string().into();
376        is_send(&a);
377        is_sync(&a);
378    }
379
380    #[test]
381    fn mapped_sync() {
382        // Send, not Sync
383        struct S(i32, PhantomData<RefCell<i32>>);
384
385        let m = Marc::new(S(10, PhantomData));
386        let m = Marc::map(m, |s| &s.0);
387        is_send(&m);
388    }
389
390    #[test]
391    fn in_place_panic() {
392        let mut m = Mrc::new(5);
393        let mut r = AssertUnwindSafe(&mut m);
394        catch_unwind(move || Mrc::map_in_place(r.deref_mut(), |_| panic!())).unwrap_err();
395        assert_eq!(m.as_ref(), &5);
396    }
397}