Crate ownref[−][src]
Expand description
References bundled with referee’s owner, ordered by pointer address or data content.
This crate provides the smart pointer type that bundles the data with its owner. It has the folloing features:
- The data is either a reference to a portion of the owner, or a data type that may contain references to the owner.
- The refernce can be ordered by data content or data pointer address.
- The owner is contained in Box or Arc.
The following table shows Box-based reference types. The generic O
denotes the
owner type and I
denotes the data type.
data type (I ) \ ordering | Content ordered | Pointer address ordered |
---|---|---|
Reference | BoxRefC<O, I> | BoxRefA<O, I> |
Owned | BoxOwnedC<O, I> | BoxOwnedA<O, I> |
The following table shows Arc-based reference types.
data type (I ) \ ordering | Content ordered | Pointer address ordered |
---|---|---|
Reference | ArcRefC<O, I> | ArcRefA<O, I> |
Owned | ArcOwnedC<O, I> | ArcOwnedA<O, I> |
For example,
BoxRefA<Vec<str>, str>
is a reference tostr
within the ownerVec<str>
, which is ordered by pointer address.ArcOwnedC<Vec<str>, Option<&str>>
stores the data typeOption<&str>
, which contains a reference within the ownerVec<str>
. The reference is ordered by the data content.
Construction and destruction
The smart references are built in the following ways.
use ownref::{ArcRefA, ArcRefC, BoxRefA, BoxRefC};
struct Owner {
a: u8,
b: f32,
}
// direct method
let _: BoxRefA<Owner, Owner> = BoxRefA::new(Owner { a: 7, b: 3.14 });
let _: ArcRefA<Owner, Owner> = ArcRefA::new(Owner { a: 7, b: 3.14 });
// from boxed data
let boxed = Box::new(Owner { a: 7, b: 3.14 });
let _: BoxRefC<Owner, Owner> = BoxRefC::from(boxed);
let boxed = Arc::new(Owner { a: 7, b: 3.14 });
let _: ArcRefC<Owner, Owner> = ArcRefC::from(boxed);
BoxRef
is destructed by BoxRef::into_owner().
let owner = ['a', 'b'];
let boxref = BoxRefA::new(owner); // box the owner
let owner = BoxRefA::into_owner(boxref); // recover the owner
ArcRef
is destructed by ArcRef::unwrap_owner(). It panics of the strong count is more than one.
let owner = ['a', 'b'];
let arcref = ArcRefA::new(owner); // box the owner
let owner = ArcRefA::unwrap_owner(arcref); // recover the owner
Data type transformation
The family of methods map()
, filter_map()
and try_map()
can transform the data type.
struct Owner {
a: u8,
b: f32,
}
let owner: BoxRefA<Owner, Owner> = BoxRefA::new(Owner { a: 7, b: 3.14 });
let inner: BoxRefA<Owner, f32> = owner.map(|data: &mut Owner| &mut data.b);
// above is equivalent to
let owner: BoxOwnedA<Owner, &mut Owner> = BoxOwnedA::new(Owner { a: 7, b: 3.14 });
let inner: BoxOwnedA<Owner, &mut f32> = owner.map(|data: &mut Owner| &mut data.b);
Note that for Owned
types. It is possible to transform the data such that the outcome
data does not reference to the owner.
let owner: BoxOwnedA<Owner, &mut Owner> = BoxOwnedA::new(Owner { a: 7, b: 3.14 });
let inner: BoxOwnedA<Owner, i32> = owner.map(|_| 5i32);
Ordering
ArcRefA is ordered by pointer address. The code below creates two references pointing to distinct elements of an array, which element values are identical. The references are distinguished by their pointer address.
let own1 = ArcRefA::new(['a', 'a']);
let own2 = own1.clone();
let ref1: ArcRefA<[char; 2], char> = own1.map(|array| &array[0]);
let ref2: ArcRefA<[char; 2], char> = own2.map(|array| &array[1]);
assert!(ref1 != ref2); // differ by pointer address
ArcRefC is ordered by data content. The code below shows two references pointing to distinct elements of an array, and are equalized by identical element value.
let own1 = ArcRefC::new(['a', 'a']);
let own2 = own1.clone();
let ref1: ArcRefC<[char; 2], char> = own1.map(|array| &array[0]);
let ref2: ArcRefC<[char; 2], char> = own2.map(|array| &array[1]);
assert!(ref1 == ref2); // equalized by content
Iterator flattening
ArcRef is able to flatten the referenced data if the data type can be turned into an iterator. For example, it can turn a reference to a vec into a vec of element references.
let vec: ArcRefC<Vec<char>> = ArcRefC::new(vec!['a', 'b', 'c']);
let collected: Vec<ArcRefC<Vec<char>, char>> = vec.flatten().collect();
ArcOwned is more versatile. It can flatten a map to references to its keys, values or key-value pairs.
let map: IndexMap<_, _> = [('a', 1), ('b', 2), ('c', 3)].into_iter().collect();
let own: ArcOwnedC<_> = ArcOwnedC::new(map);
let pairs: Vec<ArcOwnedC<_, (&char, &usize)>> =
own.clone().flat_map(|map| map.iter()).collect();
let keys: Vec<ArcOwnedC<_, &char>> = own.clone().flat_map(|map| map.keys()).collect();
let values: Vec<ArcOwnedC<_, &usize>> = own.flat_map(|map| map.values()).collect();
Owner erasure
The owner type can forget the owner type and keeps the data reference.
let letter: BoxRefC<[char; 2], char> = BoxRefC::new(['a', 'b']).map(|array| &mut array[0]);
// erase the owner
let letter: BoxRefAnyC<char> = BoxRefC::into_any_owner(letter);
// recover the owner
let letter: BoxRefC<[char; 2], char> = match BoxRefC::downcast_owner(letter) {
Ok(new_owner) => new_owner,
Err(_old_owner) => unreachable!(),
};
This example creates two u64
references within distinct owner types.
The owner type of references are erased so that they can be placed into a Vec
.
struct OwnerX {
a: u8,
b: u64,
}
struct OwnerY {
c: f32,
d: u64,
}
let own1 = BoxRefC::new(OwnerX { a: 7, b: 314 });
let ref1 = own1.map(|data| &mut data.b);
let own2 = BoxRefC::new(OwnerY { c: 0.66, d: 52 });
let ref2 = own2.map(|data| &mut data.d);
// ref1 and ref2 have different owners, erase ownwer types
let ref1: BoxRefAnyC<u64> = BoxRefC::into_any_owner(ref1);
let ref2: BoxRefAnyC<u64> = BoxRefC::into_any_owner(ref2);
// so they can be stored in a vec
vec![ref1, ref2];
Modules
Marker types.