Expand description
Type checked partial references.
This crate provides type checked partial references for rust. Type checked partial references are one solution to solve interprocedural borrowing conflicts.
§Tutorial
With this crate it is possible to declare typed parts (using the part
macro) and to assign
struct fields to these parts (by deriving PartialRefTarget
).
use partial_ref::{part, PartialRefTarget};
part!(pub Neighbors: Vec<Vec<usize>>);
part!(pub Colors: Vec<usize>);
part!(pub Weights: Vec<f32>);
#[derive(PartialRefTarget, Default)]
pub struct Graph {
#[part(Neighbors)]
pub neighbors: Vec<Vec<usize>>,
#[part(Colors)]
pub colors: Vec<usize>,
#[part(Weights)]
pub weights: Vec<f32>,
}
It is then possible to convert a reference to a value using the IntoPartialRef
and
IntoPartialRefMut
traits, which are derived alongside PartialRefTarget. Note that a mutable
partial reference must itself be mutable for mutable access.
use partial_ref::IntoPartialRefMut;
let mut g = Graph::default();
let mut g_ref = g.into_partial_ref_mut();
You can access parts using the part
and part_mut
methods.
use partial_ref::PartialRef;
g_ref.part_mut(Colors).extend(&[0, 1, 0]);
g_ref.part_mut(Weights).extend(&[0.25, 0.5, 0.75]);
g_ref.part_mut(Neighbors).push(vec![1, 2]);
g_ref.part_mut(Neighbors).push(vec![0, 2]);
g_ref.part_mut(Neighbors).push(vec![0, 1]);
assert_eq!(g_ref.part(Colors).len(), g_ref.part(Neighbors).len());
assert_eq!(g_ref.part(Colors).len(), g_ref.part(Weights).len());
We can now write a function that takes parts of a reference. The type of such a partial
reference can be written using the partial
macro, which expands to a combination of Mut
,
Const
and Ref
. Again the parameter g
here must be mutable to allow mutable access to
the referenced value. To call such a function we use the borrow
method,
which will re-borrow just the required parts.
use partial_ref::partial;
pub fn add_color_to_weight(
mut g: partial!(Graph, mut Weights, Colors),
index: usize,
) {
g.part_mut(Weights)[index] += g.part(Colors)[index] as f32;
}
add_color_to_weight(g_ref.borrow(), 1);
assert_eq!(g_ref.part(Weights)[1], 1.5);
So far everything could have been written using plain built-in references. This changes as soon as we want to iterate over the neighbors while invoking our function. Usually we couldn’t pass a mutable reference to the graph while holding the iterator over the neighbors.
This can be easily done using partial references which support splitting. Splitting means
turning a single reference into two references where each has a subset of parts, so that each
mutably referenced part belongs only to a single reference. This is done by the
split_borrow
and split_part
methods.
let (neighbors, mut g_ref) = g_ref.split_part_mut(Neighbors);
let (colors, mut g_ref) = g_ref.split_part(Colors);
for (edges, &color) in neighbors.iter_mut().zip(colors.iter()) {
edges.retain(|&neighbor| colors[neighbor] != color);
for &neighbor in edges.iter() {
add_color_to_weight(g_ref.borrow(), neighbor);
}
}
This covers the basic functionality of this library. Beyond that this library also supports:
- Partial references to nested structs using
Nested
andnested_part
. - Generic functions with bounds on available parts using
HasPart
.
§Notes
Some documented items are marked with (internal). Typical code using this library doesn’t explicitly refer to them. Nevertheless they often appear in error messages and are thus part of this documentation. These items also have to be public for the inference driven meta programming to work. Code that is generic over parts of partial references might also need them.
Many traits in this crate are marked as unsafe without documenting any requirements for implementations. This does not mean they are safe to implement, but rather means that they are not intended to be implemented outside of this library. Feel free to file an issue if you have a good reason to implement them so the requirements can be documented.
Macros§
- nested_
part - Expands
A | B | ... | Z
toNested<...Nested<A, B>, ..., Z>
- part
- Declares a [
Part
]. - partial
- Concise syntax for partial reference types.
- split_
borrow - Helper macro for splitting a partial reference.
Structs§
- Abstract
Part - Type of an abstract part.
- Const
- A constant (immutable) part of a partial reference.
- Field
- Type of a part that corresponds to a struct field.
- Index
Here - (internal) Select the first part.
- Index
Next - (internal) Skip the first part.
- Index
Split - (internal) Split the first part.
- Mut
- A mutable part of a partial reference.
- Nested
- A nested part.
- Ref
- An empty partial reference borrowing no parts.
- Subset
Index Cons - (internal) Construct a subset index from a part index and another subset index.
- Subset
Index End - (internal) Index for the empty subset.
Traits§
- Contains
Nested Part - (internal) Check whether a part is nested inside another part.
- HasPart
- Implemented when a reference target has a part.
- HasSubset
- (internal) Asserts that the parts of the partial reference
Reference
are a subset of the parts of the partial reference having this trait. - HasTarget
- Helper trait to associate the target type with a
PartialRef
without needing a lifetime. - Into
Partial Ref - Construction of partial references.
- Into
Partial RefMut - Construction of partial references from mutable references.
- Part
- Marker types for a part of a type.
- Part
Spec - Helper trait to strip lifetimes from a part.
- Part
Type - Type of a part, determines what can be done with a part.
- Partial
Ref - A partial reference.
- Partial
RefTarget - A type that can be the target of partial references.
- Pluck
Const - (internal) Extracts the constant part
PluckedPart
at positionIndex
from the partial reference having this trait, leavingSelf::Remainder
. - Pluck
Mut - (internal) Extracts the mutable part
PluckedPart
at positionIndex
from the partial reference having this trait, leavingSelf::Remainder
. - Split
Into Parts - (internal) Split a part into nested parts.
Derive Macros§
- Partial
RefTarget - Derives instances of PartialRefTarget and associated traits.