https://github.com/d-e-s-o/cell
A replacement of std::cell::RefCell adding advanced support for mapping borrows.
https://github.com/d-e-s-o/cell
cell rust rust-crate rust-library std
Last synced: 9 months ago
JSON representation
A replacement of std::cell::RefCell adding advanced support for mapping borrows.
- Host: GitHub
- URL: https://github.com/d-e-s-o/cell
- Owner: d-e-s-o
- License: apache-2.0
- Created: 2018-10-02T14:15:05.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2021-06-28T14:45:19.000Z (over 4 years ago)
- Last Synced: 2025-03-26T04:24:04.756Z (10 months ago)
- Topics: cell, rust, rust-crate, rust-library, std
- Language: Rust
- Homepage:
- Size: 60.5 KB
- Stars: 8
- Watchers: 2
- Forks: 3
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE-APACHE
Awesome Lists containing this project
README
[](https://gitlab.com/d-e-s-o/cell/commits/master)
[](https://crates.io/crates/cell)
[](https://docs.rs/cell)
[](https://blog.rust-lang.org/2019/05/23/Rust-1.35.0.html)
cell
====
- [Documentation][docs-rs]
- [Changelog](CHANGELOG.md)
**cell** is a crate providing a revised `RefCell` implementation with
additional mapping capabilities. It can be used as a drop-in replacement
for `std::cell::RefCell` where this additional functionality is required.
### *Warning:*
----------------------------------------------------------------------
> **cell** was found to contain [a subtle unsafety][cell-issue-5], a
> work around for which is not known with current versions of Rust.
> Usage of the crate is therefore discouraged.
----------------------------------------------------------------------
The Problem
-----------
A borrowed [`RefCell`][rust-ref-cell] is represented as a
[`Ref`][rust-ref]. Such a `Ref` contains a reference to the data
contained in the `RefCell`. To extend the borrow to a different member
in the original data, the [`map`][rust-ref-map] method can be used.
Using this method a new `Ref` object can be created that contains a
**reference** to a member in the borrowed data.
While having a direct reference to such a data member is appropriate in
many cases, there are some where this is insufficient, and an actual
object that contains such a reference is required.
#### Example
The most prominent example is an iterator. While an iterator internally
keeps a reference to the object being iterated over, it is more than
just a reference to it: it contains state about the progress of the
iteration.
If such an iterator is to be exposed for an object contained in a
`RefCell` that is currently borrowed, the `Ref::map` function is
insufficient:
```rust
struct RefStrings(RefCell>);
impl RefStrings {
fn iter(&self) -> Ref> {
Ref::map(self.0.borrow(), |x| x.iter())
}
}
```
```
error[E0308]: mismatched types
| Ref::map(self.0.borrow(), |x| x.iter())
| ^^^^^^^^ expected reference, found struct `std::slice::Iter`
|
= note: expected type `&_`
found type `std::slice::Iter<'_, std::string::String>`
```
(Note that required lifetimes have been elided in the example for brevity)
A Solution
----------
This crate provides alternative `RefCell` and `Ref` implementations that
solve this problem by introduction of another mapping method: `map_val`.
This method returns a `RefVal` object. `RefVal` is a new type that is
similar to `Ref` but, instead of embedding a reference to its `T` (a
type parameter), it embeds a value of it. `T` in turn would contain the
actual reference to the borrowed object.
In the above example the only changes that need to happen are the
replacement of `std::cell::RefCell` with `cell::RefCell`, that of
`std::cell::Ref` with `cell::Ref`, and the usage of `Ref::map` instead
of `Ref::map_val`.
```patch
--- test.rs
+++ test.rs
@@ -1,13 +1,14 @@
-use std::cell::Ref;
-use std::cell::RefCell;
+use cell::Ref;
+use cell::RefCell;
+use cell::RefVal;
use std::slice::Iter;
struct RefStrings(RefCell>);
impl RefStrings {
- fn iter<'t, 's: 't>(&'s self) -> Ref<'t, Iter> {
- Ref::map(self.0.borrow(), |x| x.iter())
+ fn iter<'t, 's: 't>(&'s self) -> RefVal<'t, Iter> {
+ Ref::map_val(self.0.borrow(), |x| x.iter())
}
}
```
Similar functionality exists for mutable borrow with `RefValMut`.
#### Alternative Implementations
The possibility of providing this functionality by means of a trait has
been investigated but no viable solution has been identified. The main
problem stems from the fact that we require access to `Ref` internals in
order to provide this functionality. Such a trait would alleviate the
need for providing alternative `RefCell` and `Ref` implementations.
No other solutions for this problem have been found, but the discussion
around possible alternatives is still open as part of Rust [issue
#54776][rust-issue-54776].
[cell-issue-5]: https://github.com/d-e-s-o/cell/issues/5
[docs-rs]: https://docs.rs/crate/cell
[rust-ref-cell]: https://doc.rust-lang.org/std/cell/struct.RefCell.html
[rust-ref]: https://doc.rust-lang.org/std/cell/struct.Ref.html
[rust-ref-map]: https://doc.rust-lang.org/std/cell/struct.Ref.html#method.map
[rust-issue-54776]: https://github.com/rust-lang/rust/issues/54776