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}