Crate partial_ref[−][src]
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
Expands A | B | ... | Z
to Nested<...Nested<A, B>, ..., Z>
Declares a [Part
].
Concise syntax for partial reference types.
Helper macro for splitting a partial reference.
Structs
Type of an abstract part.
A constant (immutable) part of a partial reference.
Type of a part that corresponds to a struct field.
(internal) Select the first part.
(internal) Skip the first part.
(internal) Split the first part.
A mutable part of a partial reference.
A nested part.
An empty partial reference borrowing no parts.
(internal) Construct a subset index from a part index and another subset index.
(internal) Index for the empty subset.
Traits
(internal) Check whether a part is nested inside another part.
Implemented when a reference target has a part.
(internal) Asserts that the parts of the partial reference Reference
are a subset of the
parts of the partial reference having this trait.
Helper trait to associate the target type with a PartialRef
without needing a lifetime.
Construction of partial references.
Construction of partial references from mutable references.
Marker types for a part of a type.
Helper trait to strip lifetimes from a part.
Type of a part, determines what can be done with a part.
A partial reference.
A type that can be the target of partial references.
(internal) Extracts the constant part PluckedPart
at position Index
from the partial
reference having this trait, leaving Self::Remainder
.
(internal) Extracts the mutable part PluckedPart
at position Index
from the partial
reference having this trait, leaving Self::Remainder
.
(internal) Split a part into nested parts.
Derive Macros
Derives instances of PartialRefTarget and associated traits.