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