Last active
October 22, 2024 17:00
-
-
Save itsfrank/2994e70569ca358b8ddd1596002c2c29 to your computer and use it in GitHub Desktop.
Silly rust gc wrappers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![feature(coerce_unsized, unsize)] | |
use std::cell::{Ref, RefCell, RefMut}; | |
use std::marker::Unsize; | |
use std::ops::CoerceUnsized; | |
use std::rc::{Rc, Weak}; | |
// immutable garbage-collected pointer | |
#[derive(Debug, Default)] | |
pub struct Gc<T: ?Sized> { | |
inner: Rc<RefCell<T>>, | |
} | |
impl<T> Gc<T> { | |
pub fn new(value: T) -> Self { | |
Self { | |
inner: Rc::new(RefCell::new(value)), | |
} | |
} | |
} | |
impl<T: ?Sized> Gc<T> { | |
pub fn borrow(&self) -> Ref<T> { | |
self.inner.borrow() | |
} | |
pub fn downgrade(&self) -> GcWeak<T> { | |
GcWeak { | |
inner: Rc::downgrade(&self.inner), | |
} | |
} | |
// consider usign Gc! macro instead | |
pub fn from_rc(value: Rc<RefCell<T>>) -> Self { | |
Self { inner: value } | |
} | |
} | |
impl<T: ?Sized> From<GcMut<T>> for Gc<T> { | |
fn from(value: GcMut<T>) -> Self { | |
Gc { inner: value.inner } | |
} | |
} | |
impl<T: ?Sized> Clone for Gc<T> { | |
fn clone(&self) -> Self { | |
Self { | |
inner: self.inner.clone(), | |
} | |
} | |
} | |
// garbage-collected pointer with interior mutability | |
#[derive(Debug, Default)] | |
pub struct GcMut<T: ?Sized> { | |
inner: Rc<RefCell<T>>, | |
} | |
impl<T> GcMut<T> { | |
pub fn new(value: T) -> Self { | |
Self { | |
inner: Rc::new(RefCell::new(value)), | |
} | |
} | |
} | |
impl<T: ?Sized> GcMut<T> { | |
pub fn borrow(&self) -> Ref<T> { | |
self.inner.borrow() | |
} | |
pub fn borrow_mut(&self) -> RefMut<T> { | |
self.inner.borrow_mut() | |
} | |
pub fn downgrade(&self) -> GcWeakMut<T> { | |
GcWeakMut { | |
inner: Rc::downgrade(&self.inner), | |
} | |
} | |
// consider usign GcMut! macro instead | |
pub fn from_rc(value: Rc<RefCell<T>>) -> Self { | |
Self { inner: value } | |
} | |
// you only need this to coerce a concrete type into a dyn type | |
// let a : GcMut<dyn Bar> = GcMut::new(other.inner_rc()); // where other: GcMut<Foo> | |
pub fn inner_rc(&self) -> Rc<RefCell<T>> { | |
self.inner.clone() | |
} | |
} | |
impl<T: ?Sized> Clone for GcMut<T> { | |
fn clone(&self) -> Self { | |
Self { | |
inner: self.inner.clone(), | |
} | |
} | |
} | |
// weak reference to immutable garbage-collected pointer | |
#[derive(Debug, Default)] | |
pub struct GcWeak<T: ?Sized> { | |
inner: Weak<RefCell<T>>, | |
} | |
impl<T: ?Sized> GcWeak<T> { | |
pub fn upgrade(&self) -> Option<Gc<T>> { | |
self.inner.upgrade().map(|inner| Gc { inner }) | |
} | |
} | |
impl<T: ?Sized> From<GcWeakMut<T>> for GcWeak<T> { | |
fn from(value: GcWeakMut<T>) -> Self { | |
GcWeak { inner: value.inner } | |
} | |
} | |
impl<T: ?Sized> Clone for GcWeak<T> { | |
fn clone(&self) -> Self { | |
Self { | |
inner: self.inner.clone(), | |
} | |
} | |
} | |
// weak reference to garbage-collected pointer with interior mutability | |
#[derive(Debug, Default)] | |
pub struct GcWeakMut<T: ?Sized> { | |
inner: Weak<RefCell<T>>, | |
} | |
impl<T: ?Sized> GcWeakMut<T> { | |
pub fn upgrade(&self) -> Option<GcMut<T>> { | |
self.inner.upgrade().map(|inner| GcMut { inner }) | |
} | |
} | |
impl<T: ?Sized> Clone for GcWeakMut<T> { | |
fn clone(&self) -> Self { | |
Self { | |
inner: self.inner.clone(), | |
} | |
} | |
} | |
// UNSTABLE: required to allow Gc<dyn Foo> = Gc<Bar> where Bar impls Foo | |
impl<T: Unsize<U>, U: ?Sized> CoerceUnsized<Gc<U>> for Gc<T> {} | |
impl<T: Unsize<U>, U: ?Sized> CoerceUnsized<GcMut<U>> for GcMut<T> {} | |
impl<T: Unsize<U>, U: ?Sized> CoerceUnsized<GcWeak<U>> for GcWeak<T> {} | |
impl<T: Unsize<U>, U: ?Sized> CoerceUnsized<GcWeakMut<U>> for GcWeakMut<T> {} | |
#[cfg(test)] | |
mod tests { | |
struct Foo { | |
a: i32, | |
} | |
pub trait Bar { | |
fn get_num(&self) -> i32; | |
fn set_num(&mut self, v: i32); | |
} | |
impl Bar for Foo { | |
fn get_num(&self) -> i32 { | |
self.a | |
} | |
fn set_num(&mut self, v: i32) { | |
self.a = v; | |
} | |
} | |
use super::*; | |
#[test] | |
fn playground() { | |
let gc_mut = GcMut::new(10); // mutable gc ptr | |
let weak_mut = gc_mut.downgrade(); // weak | |
// side-grade into immutable gc ptr | |
let gc: Gc<i32> = gc_mut.clone().into(); | |
let weak = gc.downgrade(); | |
let _also_weak: GcWeak<i32> = weak_mut.clone().into(); // can make immut weaks from mut weaks | |
// upgrate into immutable and mut gc ptr respectively | |
let also_gc = weak.upgrade().unwrap(); | |
let also_gc_mut = weak_mut.upgrade().unwrap(); | |
assert!(*gc.borrow() == 10); | |
assert!(*gc.borrow() == *also_gc.borrow()); | |
assert!(*gc.borrow() == *gc_mut.borrow()); | |
*also_gc_mut.borrow_mut() = 13; | |
assert!(*gc.borrow() == 13); | |
} | |
#[test] | |
fn dyn_playground() { | |
let gc_mut: GcMut<dyn Bar> = GcMut::new(Foo { a: 1 }); | |
let weak_mut = gc_mut.downgrade(); // weak | |
// side-grade into immutable gc ptr | |
let gc: Gc<dyn Bar> = gc_mut.clone().into(); | |
let weak = gc.downgrade(); | |
let _also_weak: GcWeak<dyn Bar> = weak_mut.clone().into(); // can make immut weaks from mut weaks | |
// upgrate into immutable and mut gc ptr respectively | |
let also_gc = weak.upgrade().unwrap(); | |
let also_gc_mut = weak_mut.upgrade().unwrap(); | |
assert!(gc.borrow().get_num() == 10); | |
assert!(gc.borrow().get_num() == also_gc.borrow().get_num()); | |
assert!(gc.borrow().get_num() == gc_mut.borrow().get_num()); | |
also_gc_mut.borrow_mut().set_num(13); | |
assert!(gc.borrow().get_num() == 13); | |
} | |
#[test] | |
fn coersion_test() { | |
let gcmut_con = GcMut::new(Foo { a: 1 }); | |
let _gcmut_dyn: GcMut<dyn Bar> = gcmut_con.clone(); | |
let gc_con = Gc::new(Foo { a: 1 }); | |
let _gc_dyn: Gc<dyn Bar> = gc_con.clone(); | |
let gcweakmut_con = gcmut_con.downgrade(); | |
let _gcweakmut_dyn: GcWeakMut<dyn Bar> = gcweakmut_con.clone(); | |
let gcweak_con = gc_con.downgrade(); | |
let _gcweak_dyn: GcWeak<dyn Bar> = gcweak_con.clone(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment