Mutability
You probably have noticed that both the mutable accessor and setter require the object itself to be mutable. While this is a common requirement in Rust, it is not always possible to fulfill. This is where interior mutability comes into play. FieldX provides support for this pattern via the inner_mut
argument, which, combined with the get_mut
and set
arguments, allows you to mutate a field even when the object itself is not mutable.
use fieldx::fxstruct;
#[fxstruct(get, builder)]
struct Book {
title: String,
author: String,
year: u32,
#[fieldx(get(copy), get_mut, inner_mut)]
available: u16,
#[fieldx(set("place_into"), inner_mut)]
location: String,
}
let book = Book::builder()
.title("The Hitchhiker's Guide to the Galaxy".to_string())
.author("Douglas Adams".to_string())
.year(1979)
.available(1)
.location("R12.S2".to_string()) // Row 12, Section 2
.build()
.expect("Failed to create book");
*book.available_mut() = 3;
book.place_into("R12.S4".to_string());
assert_eq!(book.available(), 3);
assert_eq!(*book.location(), "R12.S4");
In the above example, while nothing has changed for the available
field accessor, which carries the copy
sub-argument, the accessor for the location
field now requires dereferencing. This is because both field types are now wrapped in a RefCell
container which, when borrowed, returns a Ref
type. The copy
sub-argument simplifies this since returning a value is straightforward. However, the location
field accessor still returns a reference, just a different kind of it.
In sync and async modes of operation use of the inner_mut
argument is equivalent to using lock
.