Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
An ergonomic way of saying Rc<RefCell>
use std::rc::Rc;
use std::cell::{RefCell,Ref, RefMut};
use std::ops::Deref;
use std::fmt;
#[derive(Clone)]
struct Shared<T> {
v: Rc<RefCell<T>>
}
impl <T> Shared<T> {
fn new(t: T)-> Shared<T> {
Shared{v: Rc::new(RefCell::new(t))}
}
}
impl <T> Shared<T> {
fn borrow(&self) -> Ref<T> {
self.v.borrow()
}
fn borrow_mut(&self) -> RefMut<T> {
self.v.borrow_mut()
}
fn as_ptr(&self) -> *mut T {
self.v.as_ptr()
}
}
impl <T: fmt::Display> fmt::Display for Shared<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.deref())
}
}
impl <T: fmt::Debug> fmt::Debug for Shared<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.deref())
}
}
impl <'a,T> Deref for Shared<T>{
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe {self.as_ptr().as_ref().unwrap()}
}
}
/*
// Cute, but useless, since it needs to be mutable
// and so can't be shared anyway
impl <'a, T> DerefMut for Shared<T>
{ #[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe {self.as_ptr().as_mut().unwrap()}
}
}
*/
fn split (s: Shared<String>) -> Vec<String> {
s.split_whitespace().map(|s| s.to_string()).collect()
}
fn main() {
let s = Shared::new("hello".to_string());
let s2 = s.clone();
s2.borrow_mut().push('!');
println!("{:?}",s2);
// Deref kicking in...
let n = s2.len();
println!("{:?}", n);
// mutation has to be explicit
s2.borrow_mut().push_str(" dolly");
println!("{:?} {}",s2.borrow(), s);
println!("{:?}", split(s2.clone()));
}
@the-shank

This comment has been minimized.

Copy link

the-shank commented Aug 2, 2019

This is great! And so readable!

@wdanilo

This comment has been minimized.

Copy link

wdanilo commented Nov 20, 2019

@stevedonovan I think the implementation is unsound. The unsafe {self.as_ptr().as_ref().unwrap()} part gives you what is inside the RefCell but does not prevent anyone from calling borrow_mut while the deref is still in scope.

@stevedonovan

This comment has been minimized.

Copy link
Owner Author

stevedonovan commented Nov 20, 2019

You are completely correct, alas.

@mamcx

This comment has been minimized.

Copy link

mamcx commented Dec 15, 2019

Some way to fix it?

@stevedonovan

This comment has been minimized.

Copy link
Owner Author

stevedonovan commented Dec 17, 2019

I don't think that Deref can be fixed safely. It basically says that the handed-out reference has same lifetime as shared pointer, which is insufficient. Ref<T> gives you the right guarantee. A pity, really - can still say borrow everywhere (or make it shorter ref :) )

@wdanilo

This comment has been minimized.

Copy link

wdanilo commented Dec 28, 2019

It cannot be fixed currently. Deref has associated type Target which cannot be polymorphic (forall t'), because of a few reasons, including lack of HKT. I don't think it will be possible even if GATs land, as forall t' is not what we want to tell there, really. What we want to express is that this 't in Target is the same as t on &'t self. In order to express that, we would either need to change the definition of Deref (not going to happen), or we would need to have some special type checking rules. I do feel that the type system around lifetimes is not flexible as it should be, so hopefully, it could be expressible in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.