The RefCell structure is often used in conjunction with the Rc in order to allow multiple reference-counted references to mutable data in Rust, with the borrow checking pushed into run-time, using a bit of memory and performing run-time checks.
With RefCell
, as long as the try_borrow
and try_borrow_mut
functions are not used, and as long as sufficiently done testing has empirically verified that the borrow
and borrow_mut
function don't panic on run-time, then the overhead of RefCell
can be reduced to zero using a feature enablement in the compilation stage, treating it as an UnsafeCell
, its underlying implementation, without changing program semantics.
Thus, the czc-refcell
module makes a proxy to the standard library RefCell
that allows it to function as an UnsafeCell
, if the unsafe_refcell_as_safe
feature is enabled, using a different type for RefCell
. Otherwise, and by default, the standard std::cell::RefCell
is proxied as it is with all the guarantees it provides.
This provided compile-time conditional type has the same overhead of UnsafeCell
, but mimics the interface of RefCell
. Its implementation is based on a stripped-down RefCell
from the standard library, where the borrow
and borrow_mut
are in-lined to a direct proxy into the UnsafeCell
without any checking.
Note that under the non-default unchecked RefCell
build mode, code paths that would originally result in RefCell
-led panics will instead lead to undefined behavior, which can be exploitable, from a security perspective, and introduce program instabilities from a correctness perspective. This is a tradeoff between risk and performance, and users of unchecked RefCell
builds should be aware of that.
Import RefCell from czc_refcell::cell
instead of std::cell
and use it, barring the try_borrow
and try_borrow_mut
methods.
extern czc_refcell;
use czc_refcell::cell::RefCell;
...
You should allow the users of your library to control whether you'd be giving them a checked or an unchecked RefCell types. At any case, if there is a mismatch of expectation, Rust's compiler will present a meaningful error.
[features]
unsafe_refcell_as_safe = ["czc-refcell/unsafe_refcell_as_safe"]
You can test the performance of a unchecked RefCell
with a build feature flag, e.g:
cargo build --features 'unsafe_refcell_as_safe'
- For the exported stub type, think whether to export the
try_borrow
andtry_borrow_mut
as versions that always returnErr
. Currently, these methods are not implemented.