Module rustc_data_structures::owning_ref
source · [−]Expand description
An owning reference.
This crate provides the owning reference types OwningRef
and OwningRefMut
that enables it to bundle a reference together with the owner of the data it points to.
This allows moving and dropping of an OwningRef
without needing to recreate the reference.
This can sometimes be useful because Rust borrowing rules normally prevent moving a type that has been moved from. For example, this kind of code gets rejected:
fn return_owned_and_referenced<'a>() -> (Vec<u8>, &'a [u8]) {
let v = vec![1, 2, 3, 4];
let s = &v[1..3];
(v, s)
}
Even though, from a memory-layout point of view, this can be entirely safe
if the new location of the vector still lives longer than the lifetime 'a
of the reference because the backing allocation of the vector does not change.
This library enables this safe usage by keeping the owner and the reference bundled together in a wrapper type that ensure that lifetime constraint:
fn return_owned_and_referenced() -> OwningRef<Vec<u8>, [u8]> {
let v = vec![1, 2, 3, 4];
let or = OwningRef::new(v);
let or = or.map(|v| &v[1..3]);
or
}
It works by requiring owner types to dereference to stable memory locations
and preventing mutable access to root containers, which in practice requires heap allocation
as provided by Box<T>
, Rc<T>
, etc.
Also provided are typedefs for common owner type combinations,
which allow for less verbose type signatures.
For example, BoxRef<T>
instead of OwningRef<Box<T>, T>
.
The crate also provides the more advanced OwningHandle
type,
which allows more freedom in bundling a dependent handle object
along with the data it depends on, at the cost of some unsafe needed in the API.
See the documentation around OwningHandle
for more details.
Examples
Basics
use rustc_data_structures::owning_ref::BoxRef;
fn main() {
// Create an array owned by a Box.
let arr = Box::new([1, 2, 3, 4]) as Box<[i32]>;
// Transfer into a BoxRef.
let arr: BoxRef<[i32]> = BoxRef::new(arr);
assert_eq!(&*arr, &[1, 2, 3, 4]);
// We can slice the array without losing ownership or changing type.
let arr: BoxRef<[i32]> = arr.map(|arr| &arr[1..3]);
assert_eq!(&*arr, &[2, 3]);
// Also works for Arc, Rc, String and Vec!
}
Caching a reference to a struct field
use rustc_data_structures::owning_ref::BoxRef;
fn main() {
struct Foo {
tag: u32,
x: u16,
y: u16,
z: u16,
}
let foo = Foo { tag: 1, x: 100, y: 200, z: 300 };
let or = BoxRef::new(Box::new(foo)).map(|foo| {
match foo.tag {
0 => &foo.x,
1 => &foo.y,
2 => &foo.z,
_ => panic!(),
}
});
assert_eq!(*or, 200);
}
Caching a reference to an entry in a vector
use rustc_data_structures::owning_ref::VecRef;
fn main() {
let v = VecRef::new(vec![1, 2, 3, 4, 5]).map(|v| &v[3]);
assert_eq!(*v, 4);
}
Caching a subslice of a String
use rustc_data_structures::owning_ref::StringRef;
fn main() {
let s = StringRef::new("hello world".to_owned())
.map(|s| s.split(' ').nth(1).unwrap());
assert_eq!(&*s, "world");
}
Reference counted slices that share ownership of the backing storage
use rustc_data_structures::owning_ref::RcRef;
use std::rc::Rc;
fn main() {
let rc: RcRef<[i32]> = RcRef::new(Rc::new([1, 2, 3, 4]) as Rc<[i32]>);
assert_eq!(&*rc, &[1, 2, 3, 4]);
let rc_a: RcRef<[i32]> = rc.clone().map(|s| &s[0..2]);
let rc_b = rc.clone().map(|s| &s[1..3]);
let rc_c = rc.clone().map(|s| &s[2..4]);
assert_eq!(&*rc_a, &[1, 2]);
assert_eq!(&*rc_b, &[2, 3]);
assert_eq!(&*rc_c, &[3, 4]);
let rc_c_a = rc_c.clone().map(|s| &s[1]);
assert_eq!(&*rc_c_a, &4);
}
Atomic reference counted slices that share ownership of the backing storage
use rustc_data_structures::owning_ref::ArcRef;
use std::sync::Arc;
fn main() {
use std::thread;
fn par_sum(rc: ArcRef<[i32]>) -> i32 {
if rc.len() == 0 {
return 0;
} else if rc.len() == 1 {
return rc[0];
}
let mid = rc.len() / 2;
let left = rc.clone().map(|s| &s[..mid]);
let right = rc.map(|s| &s[mid..]);
let left = thread::spawn(move || par_sum(left));
let right = thread::spawn(move || par_sum(right));
left.join().unwrap() + right.join().unwrap()
}
let rc: Arc<[i32]> = Arc::new([1, 2, 3, 4]);
let rc: ArcRef<[i32]> = rc.into();
assert_eq!(par_sum(rc), 10);
}
References into RAII locks
use rustc_data_structures::owning_ref::RefRef;
use std::cell::{RefCell, Ref};
fn main() {
let refcell = RefCell::new((1, 2, 3, 4));
// Also works with Mutex and RwLock
let refref = {
let refref = RefRef::new(refcell.borrow()).map(|x| &x.3);
assert_eq!(*refref, 4);
// We move the RAII lock and the reference to one of
// the subfields in the data it guards here:
refref
};
assert_eq!(*refref, 4);
drop(refref);
assert_eq!(*refcell.borrow(), (1, 2, 3, 4));
}
Mutable reference
When the owned container implements DerefMut
, it is also possible to make
a mutable owning reference. (e.g., with Box
, RefMut
, MutexGuard
)
use rustc_data_structures::owning_ref::RefMutRefMut;
use std::cell::{RefCell, RefMut};
fn main() {
let refcell = RefCell::new((1, 2, 3, 4));
let mut refmut_refmut = {
let mut refmut_refmut = RefMutRefMut::new(refcell.borrow_mut()).map_mut(|x| &mut x.3);
assert_eq!(*refmut_refmut, 4);
*refmut_refmut *= 2;
refmut_refmut
};
assert_eq!(*refmut_refmut, 8);
*refmut_refmut *= 2;
drop(refmut_refmut);
assert_eq!(*refcell.borrow(), (1, 2, 3, 16));
}
Structs
OwningHandle
is a complement to OwningRef
. Where OwningRef
allows
consumers to pass around an owned object and a dependent reference,
OwningHandle
contains an owned object and a dependent object.Traits
Box<T> -> Box<Erased>
. This would be unneeded with
higher kinded types support in the language.Box<T> -> Box<Erased + Send>
. This would be unneeded with
higher kinded types support in the language.Box<T> -> Box<Erased + Send + Sync>
. This would be unneeded with
higher kinded types support in the language.Type Definitions
Arc
as the owner.Box
as the owner.Box
as the owner.Arc
as the owner.Box
as the owner.Box
as the owner.Rc
as the owner.MutexGuard
as the owner.MutexGuard
as the owner.Rc
as the owner.RefMut
as the owner.RefMut
as the owner.Ref
as the owner.RwLockReadGuard
as the owner.RwLockWriteGuard
as the owner.RwLockWriteGuard
as the owner.String
as the owner.String
as the owner.Vec
as the owner.Vec
as the owner.