11 unstable releases (3 breaking)
Uses new Rust 2024
new 0.4.1 | Apr 17, 2025 |
---|---|
0.4.0 | Apr 16, 2025 |
0.3.2 | Apr 5, 2025 |
0.2.0 | Apr 4, 2025 |
0.1.4 | Apr 2, 2025 |
#520 in Rust patterns
1,076 downloads per month
15KB
137 lines
Mutcy
Zero-cost mutable cyclic borrows using borrow relinquishing.
lib.rs
:
Zero-Cost Mutable Cyclic Borrows
A RefCell
-like dynamic borrowing system that permits recursive borrowing
with zero runtime overhead.
This crate implements [KeyCell] of which only a single instance can be mutably borrowed at a time using a [Key]. Simultaneous immutable borrows are permitted.
[Key] is a ZST, and only a single instance can exist per thread. The only dynamic check this library performs is upon calling Key::acquire to ensure that there exists no other instance.
Comparison to RefCell
Unlike RefCell
, borrows on [KeyCell]s will never fail. They also don't
need to perform any runtime checks. All borrow checking is performed at
compile time.
- Borrowing is zero-cost.
- Borrowing will never fail or panic.
- Only a single [KeyCell] can be mutably borrowed per thread.
Examples
This crate uses borrow and borrow_mut to access data.
use mutcy::{Key, KeyCell, KeyMut};
let mut key = Key::acquire();
let kc1 = KeyCell::new(0i32, ());
let kc2 = KeyCell::new(String::new(), ());
*kc2.borrow_mut(&mut key) += "Hello";
*kc1.borrow_mut(&mut key) += 1;
*kc2.borrow_mut(&mut key) += "World";
let item1 = kc1.borrow(&key);
let item2 = kc1.borrow(&key);
println!("{} - {}", *item1, *item2);
With this library it's possible to define methods that take [KeyMut] and transfer mutability to other [KeyCell]s when needed. The compile-time borrow checker ensures that no mutable aliasing occurs.
In the following example we show how a struct can accept a self: KeyMut<Self>
and relinquish its own borrows to access some other
KeyCell
.
#![feature(arbitrary_self_types)]
use mutcy::{Key, KeyCell, KeyMut, Meta};
use std::rc::Rc;
struct MyStruct {
value: i32,
}
impl MyStruct {
fn my_function(self: KeyMut<Self>) {
self.value += 1;
// This relinquishes any borrows to `self`.
let (this, key) = Key::split(self);
// We can now access any other KeyCell using `key`.
let mut string = this.meta().other.borrow_mut(key);
*string += "Hello world";
self.value += 1;
}
}
struct MyStructMeta {
other: Rc<KeyCell<String>>,
}
impl Meta for MyStruct {
type Data = MyStructMeta;
}
let mut key = Key::acquire();
let other = Rc::new(KeyCell::new(String::new(), ()));
let my_struct = KeyCell::new(
MyStruct { value: 0 },
MyStructMeta {
other: other.clone(),
},
);
my_struct.borrow_mut(&mut key).my_function();
println!("{}", *other.borrow(&key));
println!("{}", my_struct.borrow(&key).value);
For more information on metadata see [Meta].