Skip to content

Instantly share code, notes, and snippets.

@daxartio
Created November 23, 2023 20:43
Show Gist options
  • Save daxartio/6537d0c13e0d1cdb48734bec31cac3f2 to your computer and use it in GitHub Desktop.
Save daxartio/6537d0c13e0d1cdb48734bec31cac3f2 to your computer and use it in GitHub Desktop.
Custom Rc in Rust
use std::{
cell::Cell,
ops::{Deref, DerefMut},
ptr::NonNull,
};
#[repr(C)]
#[derive(Debug)]
struct MyRcBox<T: ?Sized> {
count: Cell<usize>,
val: T,
}
struct MyRc<T: ?Sized> {
ptr: NonNull<MyRcBox<T>>,
}
impl<T> MyRc<T> {
fn new(val: T) -> Self {
Self {
ptr: Box::leak(Box::new(MyRcBox {
count: Cell::new(1),
val,
}))
.into(),
}
}
}
impl<T: ?Sized> Clone for MyRc<T> {
fn clone(&self) -> Self {
unsafe {
*(*self.ptr.as_ptr()).count.get_mut() += 1;
}
Self { ptr: self.ptr }
}
}
impl<T: ?Sized> Deref for MyRc<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &(*self.ptr.as_ptr()).val }
}
}
impl<T: ?Sized> DerefMut for MyRc<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut (*self.ptr.as_ptr()).val }
}
}
impl<T: ?Sized> Drop for MyRc<T> {
fn drop(&mut self) {
unsafe {
// comment this and memory will leak
let count = (*self.ptr.as_ptr()).count.get_mut();
*count -= 1;
if *count == 1 {
let _ = Box::from_raw(self.ptr.as_ptr());
}
}
}
}
fn main() {
let data = String::from("data");
let val = MyRc::new(data);
let mut cloned_val = val.clone();
let p = val.ptr.as_ptr();
unsafe {
println!("{:?}", *p);
}
*cloned_val = String::from("new data");
println!("Changed to {:?}", &*val);
{
let other = val;
}
unsafe {
println!("{:?}", *p);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment