Crate mappable_rc

source ·
Expand description

Provides mappable Rc and Arc implementations.

This crate provides two types: Marc and Mrc, corresponding to std’s Arc and Rc types. For the most part, these types are near drop in replacements; they also provide shared ownership via reference countings, many of the same methods, and almost all of the same trait impls. The key difference is the existence of the map method on both types. For example, you can use Mrc::map to subslice an Mrc<[u32]>:

use mappable_rc::Mrc;

let m: Mrc<[u32]> = vec![1, 2, 3, 4].into();
assert_eq!(m.as_ref(), &[1, 2, 3, 4]);

let m: Mrc<[u32]> = Mrc::map(m, |slice| &slice[1..=2]);
assert_eq!(m.as_ref(), &[2, 3]);

The map functions do not require preserving types. For example:

use mappable_rc::Mrc;

struct S(u32);

let m: Mrc<S> = Mrc::new(S(5));
let inner: Mrc<u32> = Mrc::map(m, |s| &s.0);

assert_eq!(inner.as_ref(), &5);

You can use the types provided by this crate even if other code hands you an Rc or an Arc. See the Mrc::from_rc and Marc::from_arc methods, and the corresponding From impls.

Performance

The performance characteristics of the types in this crate are very similar to the corresponding std types. The data pointer is stored directly in the struct, and so the referenced data is only one indirection away. The Marc implementation internally reuses the Arc from std, and so the atomic operations are expected to be no more or less efficient.

A number of the trait implementations in this crate are more efficient than the corresponding std implementsions. Mrc<[T]>: From<Vec<T>> is implemented like this:

use mappable_rc::Mrc;

let v = vec![1; 1000];
let m: Mrc<Vec<i32>> = Mrc::new(v);
let m: Mrc<[i32]> = Mrc::map(m, |v| &v[..]);

This means that the data in the Vec is never copied and only a small allocation is performed. The same implementation for Arc<[T]> will perform a copy of the Vec’s data, to ensure that the memory format complies with the more stringent requirements of Arc.

The main performance downside of these types is that the size of Mrc and Marc is two usizes greater than the size of the corresponding std type.

#![no_std]

This crate is #![no_std] by default, but of course depends on alloc. There is a non-default std feature that provides implementations of std::error::Error, From<OsString> and From<PathBuf>. Activating this feature introduces an std dependency.

This crate has no other dependencies.

Structs