| Crates.io | fieldwork-borrow |
| lib.rs | fieldwork-borrow |
| version | 0.1.0 |
| created_at | 2025-12-08 13:00:10.406601+00 |
| updated_at | 2025-12-08 13:00:10.406601+00 |
| description | Field-level borrow splitting for Rust |
| homepage | |
| repository | https://github.com/Erio-Harrison/fieldwork-borrow |
| max_upload_size | |
| id | 1973482 |
| size | 47,713 |
Field-level borrow splitting for Rust.
Rust's borrow checker operates at the function boundary level, which sometimes rejects code that is actually safe. fieldwork-borrow provides a with_! macro that enables field-level borrow splitting, allowing you to work around these "false positive" borrow checker errors.
Consider this common pattern that Rust rejects:
struct Viewer {
db: Database,
model_id: usize,
object_mats: Vec<f64>,
}
impl Viewer {
fn cur_model(&self) -> &Model {
&self.db.models[self.model_id]
}
fn problem(&mut self) {
// ERROR: cannot borrow `self.object_mats` as mutable because
// `self` is also borrowed as immutable (by cur_model)
for obj in &self.cur_model().objects {
self.object_mats.push(obj.matrix);
}
}
}
The code is safe because cur_model() only reads db and model_id, while we're mutating object_mats. But Rust can't see through the method boundary.
use fieldwork_borrow::with_;
impl Viewer {
fn problem(&mut self) {
with_!(self, {
methods {
cur_model(&db, copy model_id) -> &Model {
&db.models[model_id]
}
}
fields {
mut object_mats
}
body {
for obj in &self.cur_model().objects {
object_mats.push(obj.matrix);
}
}
});
}
}
The with_! macro:
self.field accesses to use the local variableswith_!(self, {
methods {
method_name(field1, mut field2, copy field3, extra_arg: Type) -> ReturnType {
// method body - field1/field2/field3 are available here
}
}
fields {
field_a // immutable borrow (&self.field_a)
mut field_b // mutable borrow (&mut self.field_b)
}
body {
// your code here
// - self.method_name(...) calls are inlined
// - self.field_a / self.field_b access the local variables
// - field_a / field_b also work directly
}
});
In method signatures:
field or &field - immutable borrowmut field - mutable borrowcopy field - copy by value (for Copy types)In fields block:
field - immutable borrowmut field - mutable borrowget_or_insert_withfn problem(&mut self) -> &mut SomeState {
with_!(self, {
methods {
assign_next_page(mut page) -> u32 {
let p = *page;
*page += 1;
p
}
}
fields { mut state }
body {
state.get_or_insert_with(|| {
let x = self.assign_next_page();
new_state(x)
})
}
})
}
fn problem(&mut self) {
with_!(self, {
methods {
append_slice(mut slices, val: u64, idx: usize) {
slices.some_code();
}
}
fields { segments }
body {
for (i, s) in segments.iter().enumerate() {
self.append_slice(some_f(s), i);
}
}
});
}
fn problem(&mut self) {
with_!(self, {
methods {
cur_model(&db, copy model_id) -> &Model {
&db.models[model_id]
}
cur_animation(&db, &conn, copy model_id) -> Option<&Animation> {
conn.models[model_id].animations.get(0)
.map(|&id| &db.animations[id])
}
}
fields { mut uv_mats, mat_anim_state }
body {
if let Some(anim) = self.cur_animation() {
for (i, _) in self.cur_model().materials.iter().enumerate() {
uv_mats[i] = anim.tracks[0].eval(mat_anim_state.frame);
}
}
}
});
}
with_! are inlined at call sites, so they cannot be recursive? operator in method bodies may need adjustment since the method is inlined[dependencies]
fieldwork-borrow = "0.1"
MIT