fieldwork_borrow/lib.rs
1//! Field-level borrow splitting for Rust.
2//!
3//! Rust's borrow checker operates at the function boundary level, which sometimes
4//! rejects code that is actually safe. This crate provides the [`with_!`] macro
5//! that enables field-level borrow splitting, allowing you to work around these
6//! "false positive" borrow checker errors.
7//!
8//! # The Problem
9//!
10//! Consider this common pattern that Rust rejects:
11//!
12//! ```compile_fail
13//! struct Database { models: Vec<Model> }
14//! struct Model { objects: Vec<Object> }
15//! struct Object { matrix: f64 }
16//!
17//! struct Viewer {
18//! db: Database,
19//! model_id: usize,
20//! object_mats: Vec<f64>,
21//! }
22//!
23//! impl Viewer {
24//! fn cur_model(&self) -> &Model {
25//! &self.db.models[self.model_id]
26//! }
27//!
28//! fn problem(&mut self) {
29//! // ERROR: cannot borrow `self.object_mats` as mutable because
30//! // `self` is also borrowed as immutable (by cur_model)
31//! for obj in &self.cur_model().objects {
32//! self.object_mats.push(obj.matrix);
33//! }
34//! }
35//! }
36//! ```
37//!
38//! The code is safe because `cur_model()` only reads `db` and `model_id`,
39//! while we're mutating `object_mats`. But Rust can't see through the method boundary.
40//!
41//! # The Solution
42//!
43//! ```
44//! use fieldwork_borrow::with_;
45//!
46//! struct Database { models: Vec<Model> }
47//! struct Model { objects: Vec<Object> }
48//! struct Object { matrix: f64 }
49//!
50//! struct Viewer {
51//! db: Database,
52//! model_id: usize,
53//! object_mats: Vec<f64>,
54//! }
55//!
56//! impl Viewer {
57//! fn problem(&mut self) {
58//! with_!(self, {
59//! methods {
60//! cur_model(&db, copy model_id) -> &Model {
61//! &db.models[model_id]
62//! }
63//! }
64//! fields {
65//! mut object_mats
66//! }
67//! body {
68//! for obj in &self.cur_model().objects {
69//! object_mats.push(obj.matrix);
70//! }
71//! }
72//! });
73//! }
74//! }
75//! ```
76//!
77//! # Syntax
78//!
79//! ```text
80//! with_!(receiver, {
81//! methods {
82//! method_name(field1, mut field2, copy field3, arg: Type) -> ReturnType {
83//! // method body
84//! }
85//! }
86//! fields {
87//! field_a // immutable borrow
88//! mut field_b // mutable borrow
89//! }
90//! body {
91//! // code that uses self.method_name() and self.field_x
92//! }
93//! });
94//! ```
95//!
96//! # Field Access Modes
97//!
98//! In method parameters:
99//! - `field` or `&field` — shared reference (`&receiver.field`)
100//! - `mut field` — mutable reference (`&mut receiver.field`)
101//! - `copy field` — by value, requires `Copy` trait
102//!
103//! In `fields` block:
104//! - `field` — shared reference
105//! - `mut field` — mutable reference
106
107pub use fieldwork_macro::with_;