Last active
December 20, 2025 19:48
-
-
Save DarinM223/cf720814cec736258603f618a13382ef to your computer and use it in GitHub Desktop.
Abstract over dereferenceable containers in Rust
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
| use std::fmt::Debug; | |
| use std::ops::Deref; | |
| use std::ptr::NonNull; | |
| trait Ptr { | |
| type T<'a, U: 'a>: Deref<Target = U>; | |
| } | |
| struct BoxPtr; | |
| impl Ptr for BoxPtr { | |
| type T<'a, U: 'a> = Box<U>; | |
| } | |
| struct UnsafeNonNull<T>(NonNull<T>); | |
| impl<T: Sized> Deref for UnsafeNonNull<T> { | |
| type Target = T; | |
| fn deref(&self) -> &Self::Target { | |
| unsafe { self.0.as_ref() } | |
| } | |
| } | |
| struct NonNullPtr; | |
| impl Ptr for NonNullPtr { | |
| type T<'a, U: 'a> = UnsafeNonNull<U>; | |
| } | |
| struct RefPtr; | |
| impl Ptr for RefPtr { | |
| type T<'a, U: 'a> = &'a U; | |
| } | |
| struct Node<'a, T: 'a, P: Ptr + 'a> { | |
| data: T, | |
| left: Option<P::T<'a, Node<'a, T, P>>>, | |
| right: Option<P::T<'a, Node<'a, T, P>>>, | |
| } | |
| impl<'a, T: Debug, P: Ptr> Node<'a, T, P> { | |
| fn print(&self) { | |
| println!("{:?}", self.data); | |
| if let Some(ref left) = self.left { | |
| left.print(); | |
| } | |
| if let Some(ref right) = self.right { | |
| right.print(); | |
| } | |
| } | |
| } | |
| fn main() { | |
| let node: Node<i32, BoxPtr> = Node { | |
| data: 0, | |
| left: None, | |
| right: Some(Box::new(Node { | |
| data: 1, | |
| left: None, | |
| right: None, | |
| })), | |
| }; | |
| node.print(); | |
| let node: Node<i32, NonNullPtr> = Node { | |
| data: 2, | |
| left: None, | |
| right: None, | |
| }; | |
| node.print(); | |
| let node: Node<i32, RefPtr> = Node { | |
| data: 3, | |
| left: Some(&Node { | |
| data: 4, | |
| left: None, | |
| right: None, | |
| }), | |
| right: Some(&Node { | |
| data: 5, | |
| left: None, | |
| right: None, | |
| }), | |
| }; | |
| node.print(); | |
| } |
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
| use ghost_cell::{GhostCell, GhostToken}; | |
| use slotmap::{SlotMap, new_key_type}; | |
| use std::{ | |
| cell::RefCell, | |
| fmt::Debug, | |
| marker::PhantomData, | |
| ops::{AddAssign, Deref, DerefMut}, | |
| rc::Rc, | |
| }; | |
| trait BorrowSuper { | |
| type Ref<'a, U: 'a>: Deref<Target = U> + Clone; | |
| } | |
| trait Borrow<'brand>: BorrowSuper { | |
| type Token; | |
| type Target; | |
| fn get<'a>(&'a self, token: &'a Self::Token) -> Self::Ref<'a, Self::Target>; | |
| } | |
| trait BorrowMutSuper { | |
| type RefMut<'a, U: 'a>: Deref<Target = U> + DerefMut<Target = U>; | |
| } | |
| trait BorrowMut<'brand>: BorrowMutSuper + Borrow<'brand> { | |
| fn get_mut<'a>(&'a self, token: &'a mut Self::Token) -> Self::RefMut<'a, Self::Target>; | |
| } | |
| trait Ptr { | |
| type T<'a, 'b: 'a, U: 'a>: Borrow<'b, Target = U>; | |
| } | |
| trait PtrMut { | |
| type T<'a, 'b: 'a, U: 'a>: Borrow<'b, Target = U> + BorrowMut<'b, Target = U>; | |
| } | |
| struct Ref<T>(T); | |
| impl<T> BorrowSuper for &Ref<T> { | |
| type Ref<'a, U: 'a> = &'a U; | |
| } | |
| impl<T> Borrow<'_> for &Ref<T> { | |
| type Token = (); | |
| type Target = T; | |
| fn get(&self, _token: &Self::Token) -> &Self::Target { | |
| &self.0 | |
| } | |
| } | |
| impl<T> BorrowSuper for Box<T> { | |
| type Ref<'a, U: 'a> = &'a U; | |
| } | |
| impl<T> Borrow<'_> for Box<T> { | |
| type Token = (); | |
| type Target = T; | |
| fn get(&self, _token: &Self::Token) -> &Self::Target { | |
| self | |
| } | |
| } | |
| impl<T> BorrowSuper for &GhostCell<'_, T> { | |
| type Ref<'a, U: 'a> = &'a U; | |
| } | |
| impl<'brand, T> Borrow<'brand> for &GhostCell<'brand, T> { | |
| type Token = GhostToken<'brand>; | |
| type Target = T; | |
| fn get<'a>(&'a self, token: &'a Self::Token) -> &'a Self::Target { | |
| self.borrow(token) | |
| } | |
| } | |
| impl<T> BorrowMutSuper for &GhostCell<'_, T> { | |
| type RefMut<'a, U: 'a> = &'a mut U; | |
| } | |
| impl<'brand, T> BorrowMut<'brand> for &GhostCell<'brand, T> { | |
| fn get_mut<'a>(&'a self, token: &'a mut Self::Token) -> &'a mut Self::Target { | |
| self.borrow_mut(token) | |
| } | |
| } | |
| struct BoxPtr; | |
| impl Ptr for BoxPtr { | |
| type T<'a, 'b: 'a, U: 'a> = Box<U>; | |
| } | |
| struct RefPtr; | |
| impl Ptr for RefPtr { | |
| type T<'a, 'b: 'a, U: 'a> = &'a Ref<U>; | |
| } | |
| struct GhostCellPtr; | |
| impl Ptr for GhostCellPtr { | |
| type T<'a, 'b: 'a, U: 'a> = &'a GhostCell<'b, U>; | |
| } | |
| impl PtrMut for GhostCellPtr { | |
| type T<'a, 'b: 'a, U: 'a> = &'a GhostCell<'b, U>; | |
| } | |
| new_key_type! { struct GraphId; } | |
| struct GraphKey<T> { | |
| id: GraphId, | |
| _phantom: PhantomData<T>, | |
| } | |
| impl<T> Clone for GraphKey<T> { | |
| fn clone(&self) -> Self { | |
| Self { | |
| id: self.id, | |
| _phantom: PhantomData, | |
| } | |
| } | |
| } | |
| impl<T> Copy for GraphKey<T> {} | |
| impl<T> From<GraphId> for GraphKey<T> { | |
| fn from(value: GraphId) -> Self { | |
| GraphKey { | |
| id: value, | |
| _phantom: PhantomData, | |
| } | |
| } | |
| } | |
| type GraphMap<T> = SlotMap<GraphId, T>; | |
| impl<T> BorrowSuper for GraphKey<T> { | |
| type Ref<'a, U: 'a> = &'a U; | |
| } | |
| impl<T> Borrow<'_> for GraphKey<T> { | |
| type Token = GraphMap<T>; | |
| type Target = T; | |
| fn get<'a>(&'a self, token: &'a Self::Token) -> &'a Self::Target { | |
| token.get(self.id).unwrap() | |
| } | |
| } | |
| impl<T> BorrowMutSuper for GraphKey<T> { | |
| type RefMut<'a, U: 'a> = &'a mut U; | |
| } | |
| impl<T> BorrowMut<'_> for GraphKey<T> { | |
| fn get_mut<'a>(&'a self, token: &'a mut Self::Token) -> &'a mut Self::Target { | |
| token.get_mut(self.id).unwrap() | |
| } | |
| } | |
| struct GraphKeyPtr; | |
| impl Ptr for GraphKeyPtr { | |
| type T<'a, 'b: 'a, U: 'a> = GraphKey<U>; | |
| } | |
| impl PtrMut for GraphKeyPtr { | |
| type T<'a, 'b: 'a, U: 'a> = GraphKey<U>; | |
| } | |
| struct CellRef<'a, T>(std::cell::Ref<'a, T>); | |
| impl<T> Deref for CellRef<'_, T> { | |
| type Target = T; | |
| fn deref(&self) -> &Self::Target { | |
| self.0.deref() | |
| } | |
| } | |
| impl<T> Clone for CellRef<'_, T> { | |
| fn clone(&self) -> Self { | |
| Self(std::cell::Ref::clone(&self.0)) | |
| } | |
| } | |
| impl<T> BorrowSuper for Rc<RefCell<T>> { | |
| type Ref<'a, U: 'a> = CellRef<'a, U>; | |
| } | |
| impl<T> Borrow<'_> for Rc<RefCell<T>> { | |
| type Token = (); | |
| type Target = T; | |
| fn get<'a>(&'a self, _token: &'a Self::Token) -> Self::Ref<'a, Self::Target> { | |
| CellRef(self.borrow()) | |
| } | |
| } | |
| impl<T> BorrowMutSuper for Rc<RefCell<T>> { | |
| type RefMut<'a, U: 'a> = std::cell::RefMut<'a, U>; | |
| } | |
| impl<T> BorrowMut<'_> for Rc<RefCell<T>> { | |
| fn get_mut<'a>(&'a self, _token: &'a mut Self::Token) -> Self::RefMut<'a, Self::Target> { | |
| self.borrow_mut() | |
| } | |
| } | |
| struct RcRefCellPtr; | |
| impl Ptr for RcRefCellPtr { | |
| type T<'a, 'b: 'a, U: 'a> = Rc<RefCell<U>>; | |
| } | |
| impl PtrMut for RcRefCellPtr { | |
| type T<'a, 'b: 'a, U: 'a> = Rc<RefCell<U>>; | |
| } | |
| struct TreeNode<'a, 'b: 'a, T: 'a, P: Ptr + 'a> { | |
| data: T, | |
| left: Option<P::T<'a, 'b, TreeNode<'a, 'b, T, P>>>, | |
| right: Option<P::T<'a, 'b, TreeNode<'a, 'b, T, P>>>, | |
| } | |
| impl<'a, 'b, T: Debug, P: Ptr> TreeNode<'a, 'b, T, P> { | |
| fn print(&self, token: &'a <<P as Ptr>::T<'a, 'b, Self> as Borrow<'b>>::Token) { | |
| println!("{:?}", self.data); | |
| if let Some(ref left) = self.left { | |
| left.get(token).print(token); | |
| } | |
| if let Some(ref right) = self.right { | |
| right.get(token).print(token); | |
| } | |
| } | |
| } | |
| struct GraphNode<'a, 'b: 'a, T: 'a, P: PtrMut + 'a> { | |
| data: T, | |
| edges: Vec<P::T<'a, 'b, GraphNode<'a, 'b, T, P>>>, | |
| } | |
| impl<'a, 'b, T: Copy + AddAssign<T>, P: PtrMut> GraphNode<'a, 'b, T, P> | |
| where | |
| <P as PtrMut>::T<'a, 'b, Self>: Clone, | |
| { | |
| fn incr( | |
| this: <P as PtrMut>::T<'a, 'b, Self>, | |
| token: &mut <<P as PtrMut>::T<'a, 'b, Self> as Borrow<'b>>::Token, | |
| ) { | |
| let data = this.get(token).data; | |
| let edges = this.get(token).edges.clone(); | |
| for edge in edges.clone() { | |
| edge.get_mut(token).data += data; | |
| } | |
| for edge in edges { | |
| Self::incr(edge, token); | |
| } | |
| } | |
| } | |
| fn main() { | |
| let node = TreeNode::<i32, BoxPtr> { | |
| data: 0, | |
| left: None, | |
| right: Some(Box::new(TreeNode { | |
| data: 1, | |
| left: None, | |
| right: None, | |
| })), | |
| }; | |
| node.print(&()); | |
| let node = TreeNode::<i32, RefPtr> { | |
| data: 2, | |
| left: Some(&Ref(TreeNode { | |
| data: 4, | |
| left: None, | |
| right: None, | |
| })), | |
| right: Some(&Ref(TreeNode { | |
| data: 3, | |
| left: None, | |
| right: None, | |
| })), | |
| }; | |
| node.print(&()); | |
| // GhostToken usage: | |
| GhostToken::new(|mut token| { | |
| let cell1 = GhostCell::new(GraphNode::<i32, GhostCellPtr> { | |
| data: 1, | |
| edges: vec![], | |
| }); | |
| let cell2 = GhostCell::new(GraphNode::<i32, GhostCellPtr> { | |
| data: 2, | |
| edges: vec![], | |
| }); | |
| let cell3 = GhostCell::new(GraphNode::<i32, GhostCellPtr> { | |
| data: 3, | |
| edges: vec![], | |
| }); | |
| cell1.borrow_mut(&mut token).edges.push(&cell2); | |
| cell2.borrow_mut(&mut token).edges.push(&cell3); | |
| GraphNode::<_, GhostCellPtr>::incr(&cell1, &mut token); | |
| println!( | |
| "{:?} {:?} {:?}", | |
| cell1.borrow(&token).data, | |
| cell2.borrow(&token).data, | |
| cell3.borrow(&token).data | |
| ); | |
| }); | |
| // Slotmap usage: | |
| let mut nodes: GraphMap<GraphNode<i32, GraphKeyPtr>> = SlotMap::with_key(); | |
| let node1 = nodes.insert(GraphNode { | |
| data: 1, | |
| edges: vec![], | |
| }); | |
| let node2 = nodes.insert(GraphNode { | |
| data: 2, | |
| edges: vec![], | |
| }); | |
| let node3 = nodes.insert(GraphNode { | |
| data: 3, | |
| edges: vec![], | |
| }); | |
| nodes[node1].edges.push(node2.into()); | |
| nodes[node2].edges.push(node3.into()); | |
| GraphNode::<_, GraphKeyPtr>::incr(node1.into(), &mut nodes); | |
| println!( | |
| "{:?} {:?} {:?}", | |
| nodes[node1].data, nodes[node2].data, nodes[node3].data, | |
| ); | |
| // Rc Refcell usage: | |
| let rc1 = Rc::new(RefCell::new(GraphNode::<i32, RcRefCellPtr> { | |
| data: 1, | |
| edges: vec![], | |
| })); | |
| let rc2 = Rc::new(RefCell::new(GraphNode::<i32, RcRefCellPtr> { | |
| data: 2, | |
| edges: vec![], | |
| })); | |
| let rc3 = Rc::new(RefCell::new(GraphNode::<i32, RcRefCellPtr> { | |
| data: 3, | |
| edges: vec![], | |
| })); | |
| rc1.borrow_mut().edges.push(rc2.clone()); | |
| rc2.borrow_mut().edges.push(rc3.clone()); | |
| GraphNode::<_, RcRefCellPtr>::incr(rc1.clone(), &mut ()); | |
| println!( | |
| "{:?} {:?} {:?}", | |
| rc1.borrow().data, | |
| rc2.borrow().data, | |
| rc3.borrow().data, | |
| ); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment