I'm struggling with the implementing a struct in Rust that is able to hold either Rc<RefCell<T>>
or Arc<RwLock<T>>
.
The motivation of such a design is to allow the user to use cheaper and faster Rc<RefCell<T>>
when the code will run in a single thread and only go to Arc<RwLock<T>>
when parallelization is needed.
That's what I'm doing now:
struct Structure {}
struct Sel<R,DR>
where
R: Deref<Target=DR>,
DR: Borrow<Structure>,
{
structure: R,
}
impl<R,DR> Sel<R,DR>
where
R: Deref<Target=DR>,
DR: Borrow<Structure>,
{
fn new(structure: R) -> Self {
Self{structure}
}
}
fn main() {
let st = Rc::new(RefCell::new(Structure{}));
let sel = Sel::new(st);
}
The structure Sel can hold any type R that dereferences to whatever type DR, which in turn implements Borrow (Structure is the user type to wrap). In theory both Rc<RefCell<T>>
and Arc<RwLock<T>>
should satisfy these trait bounds, but the compiler shouts at me:
error[E0277]: the trait bound `RefCell<Structure>: Borrow<Structure>` is not satisfied
--> src/main.rs:26:15
|
26 | let sel = Sel::new(st);
| ^^^^^^^^ the trait `Borrow<Structure>` is not implemented for `RefCell<Structure>`
What is the correct way of implementing this? Which trait bound I can use to express that DR could be used in place of &Structure?
After some excellent hints in the comments I've found a solution, which appeared to be universal enough to justify creation of the crate for it. I've called it UniRcLock.
It is based on the idea to define a common trait for
Rc<RefCell<T>>
andArc<RwLock<T>>
. The implementation requires some advanced trait magic with generic associated types that allows to handle the lifetimes and to express the behavior of scoped read and write access guards in a generic manner.It could be used like this (copy-pasted from the crate docs):
I hope it could be useful :)