I am a big fan of BorrowMut
as it allows me to provide APIs that allow to take ownership of arguments, or to take references as well. This makes them easier to use, but a little harder to implement for me - an acceptable tradeoff as the needs of the many outweigh the needs of the few :).
Now I am trying to use BorrowMut
with RefCell
and fail as borrow_mut()
is implemented both by RefMut
as well as BorrowMut
. However, RefMut
will take precedence, preventing my to drill down to the actual value contained within BorrowMut
.
Example
The following code allows you to reproduce the issue - the goal is to call doit()
on the Client
type:
use std::cell::RefCell;
use std::borrow::BorrowMut;
struct Hub<C> {
client: RefCell<C>
}
impl<C> Hub<C>
where C: BorrowMut<Client> {
fn new(client: C) -> Hub<C> {
Hub {
client: RefCell::new(client)
}
}
fn builder<'a>(&'a self) -> Builder<'a, C> {
Builder {
hub: self
}
}
}
struct Builder<'a, C: 'a> {
hub: &'a Hub<C>
}
impl<'a, C> Builder<'a, C>
where C: BorrowMut<Client> {
fn use_client(self) {
// 1: borrow_mut() of RefCell
// 2: borrow_mut() of BorrowMut()
// but doesn't work, as RefMut returned by 1) always yields RefMut
self.hub.client.borrow_mut().borrow_mut().doit()
}
}
struct Client;
impl Client {
fn doit(&mut self) {
println!("DID IT!!")
}
}
// HUB USAGE
{
let h = Hub::new(Client);
h.builder().use_client();
}
{
let mut c = Client;
let h = Hub::new(&mut c);
h.builder().use_client();
}
This produces the following error:
tests/lang.rs:1076:55: 1076:61 error: type `&mut core::cell::RefMut<'_, C>` does not implement any method in scope named `doit`
tests/lang.rs:1076 self.hub.client.borrow_mut().borrow_mut().doit()
Can you point out how I would make this call ? Is it possible at all ?
Meta
✗ rustc --version --verbose
rustc 1.0.0-nightly (3e4be02b8 2015-03-13) (built 2015-03-13)
binary: rustc
commit-hash: 3e4be02b80a3dd27bce20870958fe0aef7e7336d
commit-date: 2015-03-13
build-date: 2015-03-13
host: x86_64-apple-darwin
release: 1.0.0-nightly