Skip to main content

Crate fieldwork_borrow

Crate fieldwork_borrow 

Source
Expand description

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:

ⓘ
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

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

Macros§

with_
Field-level borrow splitting macro.