├── .gitignore ├── .vscode └── tasks.json ├── Cargo.toml ├── README.md ├── rustfmt.toml └── src ├── global_ledger.rs ├── lib.rs ├── local_ledger.rs ├── raw_ref.rs └── tracking.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "cargo", 6 | "command": "test", 7 | "problemMatcher": [ 8 | "$rustc" 9 | ], 10 | "presentation": { 11 | "echo": true, 12 | "reveal": "never", 13 | "focus": false, 14 | "panel": "shared", 15 | "showReuseMessage": false, 16 | "clear": true 17 | }, 18 | "group": { 19 | "kind": "test", 20 | "isDefault": true 21 | }, 22 | "label": "rust: cargo test" 23 | }, 24 | { 25 | "type": "cargo", 26 | "command": "build", 27 | "problemMatcher": [ 28 | "$rustc" 29 | ], 30 | "group": { 31 | "kind" : "build", 32 | "isDefault": true 33 | }, 34 | "label": "rust: cargo build" 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "genref" 3 | description = "A variation of Vale's generational references in Rust" 4 | readme = "README.md" 5 | repository = "https://github.com/Kile-Asmussen/genref" 6 | license = "MIT" 7 | version = "0.9.0" 8 | edition = "2021" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | lazy_static = { version = "1.4.0" } 14 | parking_lot = { version = "0.12.1", features = ["nightly"] } 15 | lock_api = { version = "0.4.7" } 16 | bumpalo = { version = "3.12.0" } 17 | 18 | [toolchain] 19 | channel = "nightly" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Generational reference counting in Rust 2 | 3 | An implementation of [Vale's](https://vale.dev/) generational reference counting memory management model. 4 | 5 | ## Soundness advisory 6 | 7 | Versions before the 0.9.0 rewrite have undefined behavior. Do not use them. 8 | 9 | TODO: 10 | 11 | renormalization in weak clone? 12 | use LOCAL | GLOBAL to mean made-sharable? -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | wrap_comments=true 2 | 3 | control_brace_style="AlwaysSameLine" 4 | 5 | brace_style="AlwaysNextLine" 6 | 7 | fn_args_layout="Compressed" 8 | 9 | fn_single_line = true 10 | 11 | format_code_in_doc_comments = true -------------------------------------------------------------------------------- /src/global_ledger.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use lock_api::{RawRwLock, RawRwLockUpgrade}; 3 | use std::sync::atomic::{AtomicU64, Ordering}; 4 | 5 | use super::*; 6 | use crate::tracking::Tracking; 7 | 8 | #[repr(transparent)] 9 | #[derive(Debug, Clone, Copy)] 10 | pub(crate) struct GlobalIndex(&'static GlobalAccount); 11 | 12 | impl Tracking for GlobalIndex 13 | { 14 | fn generation(&self) -> u64 { self.0.generation() } 15 | fn invalidate(&self) -> u64 { self.0.invalidate() } 16 | fn try_lock_exclusive(&self) -> bool { self.0.try_lock_exclusive() } 17 | fn lock_exclusive(&self) { self.0.lock_exclusive() } 18 | fn try_lock_shared(&self) -> bool { self.0.try_lock_shared() } 19 | fn try_upgrade(&self) -> bool { self.0.try_upgrade() } 20 | unsafe fn unlock_exclusive(&self) { self.0.unlock_exclusive() } 21 | unsafe fn unlock_shared(&self) { self.0.unlock_shared() } 22 | } 23 | 24 | struct GlobalAccount 25 | { 26 | lock: parking_lot::RawRwLock, 27 | generation: AtomicU64, 28 | } 29 | 30 | impl std::fmt::Debug for GlobalAccount 31 | { 32 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result 33 | { 34 | f.debug_struct("GlobalAccount") 35 | .field("generation", &self.generation) 36 | .finish_non_exhaustive() 37 | } 38 | } 39 | 40 | impl Tracking for GlobalAccount 41 | { 42 | fn generation(&self) -> u64 43 | { 44 | self.generation.load(Ordering::Relaxed) & RawRef::<()>::COUNTER_MASK 45 | } 46 | 47 | fn invalidate(&self) -> u64 { self.generation.fetch_add(1, Ordering::Relaxed) } 48 | 49 | fn try_lock_exclusive(&self) -> bool { self.lock.try_lock_exclusive() } 50 | 51 | fn lock_exclusive(&self) { self.lock.lock_exclusive() } 52 | 53 | fn try_lock_shared(&self) -> bool { self.lock.try_lock_shared() } 54 | 55 | fn try_upgrade(&self) -> bool 56 | { 57 | if self.lock.try_lock_upgradable() { 58 | unsafe { 59 | self.lock.unlock_shared(); 60 | } 61 | if unsafe { self.lock.try_upgrade() } { 62 | return true; 63 | } 64 | if !self.lock.try_lock_shared() { 65 | panic!("failed to upgrade and then could not re-lock") 66 | } 67 | unsafe { 68 | self.lock.unlock_upgradable(); 69 | } 70 | } 71 | return false; 72 | } 73 | 74 | unsafe fn unlock_exclusive(&self) { self.lock.unlock_exclusive() } 75 | 76 | unsafe fn unlock_shared(&self) { self.lock.unlock_shared() } 77 | } 78 | 79 | pub(crate) fn allocate() -> GlobalIndex { recycle().unwrap_or_else(fresh) } 80 | 81 | fn fresh() -> GlobalIndex 82 | { 83 | GlobalIndex(Box::leak(Box::new(GlobalAccount { 84 | lock: parking_lot::RawRwLock::INIT, 85 | generation: AtomicU64::new(RawRef::<()>::COUNTER_INIT), 86 | })) as &_) 87 | } 88 | 89 | lazy_static! { 90 | static ref FREE_LIST: parking_lot::RwLock> = 91 | parking_lot::RwLock::new(Vec::new()); 92 | } 93 | 94 | fn recycle() -> Option { FREE_LIST.write().pop() } 95 | 96 | /// assumes exclusive lock 97 | pub(crate) unsafe fn free(gi: GlobalIndex) 98 | { 99 | gi.invalidate(); 100 | gi.unlock_exclusive(); 101 | FREE_LIST.write().push(gi) 102 | } 103 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(local_key_cell_methods, assert_matches)] 2 | #![allow(unused)] 3 | 4 | mod global_ledger; 5 | mod local_ledger; 6 | mod raw_ref; 7 | mod tracking; 8 | 9 | use std::{ 10 | assert_matches::assert_matches, 11 | io::Read, 12 | marker::PhantomData, 13 | ops::{Deref, DerefMut}, 14 | ptr::NonNull, 15 | }; 16 | 17 | use raw_ref::*; 18 | use tracking::{AccountEnum, Tracking}; 19 | 20 | #[repr(transparent)] 21 | pub struct Strong(RawRef); 22 | 23 | impl Strong 24 | { 25 | #[cfg(test)] 26 | fn invariant(&self) 27 | { 28 | self.0.invariant(); 29 | assert_matches!( 30 | self.0.pointer(), 31 | PointerEnum::Strong(_), 32 | "strong reference without strong flag" 33 | ); 34 | } 35 | 36 | #[cfg(not(test))] 37 | fn invariant(&self) {} 38 | 39 | pub fn from_box(it: Box) -> Self 40 | { 41 | let res = Self(RawRef::from_box(it)); 42 | res.invariant(); 43 | res 44 | } 45 | 46 | pub fn alias_of(&self, f: F) -> Weak 47 | where 48 | for<'a> F: FnOnce(&'a T) -> &'a U, 49 | { 50 | let acc = self.0.account(); 51 | let ptr = self.0.pointer(); 52 | Weak::new( 53 | self.0 54 | .clone() 55 | .set_weak() 56 | .map(|n| NonNull::from(unsafe { f(n.as_ref()) })), 57 | ) 58 | } 59 | 60 | pub fn alias(&self) -> Weak { self.alias_of(|x| x) } 61 | 62 | pub fn try_take(mut self) -> Result, Self> 63 | { 64 | self.invariant(); 65 | if let Some(b) = unsafe { self.0.try_consume_exclusive() } { 66 | std::mem::forget(self); 67 | Ok(b) 68 | } else { 69 | Err(self) 70 | } 71 | } 72 | 73 | fn try_read(&self) -> Option> 74 | { 75 | self.invariant(); 76 | Reading::try_new(self.0.clone()) 77 | } 78 | 79 | fn try_write(&self) -> Option> 80 | { 81 | self.invariant(); 82 | Writing::try_new(self.0.clone()) 83 | } 84 | } 85 | 86 | impl Drop for Strong 87 | { 88 | fn drop(&mut self) 89 | { 90 | self.invariant(); 91 | unsafe { 92 | self.0.try_consume_exclusive(); 93 | } 94 | } 95 | } 96 | 97 | #[repr(transparent)] 98 | pub struct Weak(RawRef); 99 | impl Clone for Weak 100 | { 101 | fn clone(&self) -> Self { Self(self.0.clone()) } 102 | } 103 | 104 | impl Weak 105 | { 106 | fn invariant(&self) 107 | { 108 | self.0.invariant(); 109 | assert_matches!( 110 | self.0.pointer(), 111 | PointerEnum::Weak(_), 112 | "weak reference without weak flag" 113 | ) 114 | } 115 | 116 | fn new(raw_ref: RawRef) -> Self 117 | { 118 | let res = Weak(raw_ref); 119 | res.invariant(); 120 | res 121 | } 122 | 123 | pub fn try_read(&self) -> Option> { Reading::try_new(self.0.clone()) } 124 | 125 | pub fn try_write(&self) -> Option> { Writing::try_new(self.0.clone()) } 126 | } 127 | 128 | #[repr(transparent)] 129 | struct GenRef(RawRef); 130 | pub enum GenRefEnum 131 | { 132 | Weak(Weak), 133 | Strong(Strong), 134 | } 135 | 136 | #[repr(transparent)] 137 | pub struct Reading<'a, T>(RawRef, PhantomData<&'a ()>); 138 | 139 | impl<'a, T> Reading<'a, T> 140 | { 141 | fn invariant(&self) { self.0.invariant(); } 142 | 143 | pub(crate) fn try_new(raw_ref: RawRef) -> Option 144 | { 145 | raw_ref.invariant(); 146 | if raw_ref.account().try_lock_shared() { 147 | let res = Self(raw_ref, PhantomData); 148 | res.invariant(); 149 | Some(res) 150 | } else { 151 | None 152 | } 153 | } 154 | } 155 | 156 | impl<'a, T> Deref for Reading<'a, T> 157 | { 158 | type Target = T; 159 | 160 | fn deref(&self) -> &Self::Target { unsafe { self.0.pointer().as_ptr().as_ref() } } 161 | } 162 | 163 | impl<'a, T> Drop for Reading<'a, T> 164 | { 165 | fn drop(&mut self) 166 | { 167 | unsafe { 168 | self.0.try_consume_shared(); 169 | } 170 | } 171 | } 172 | 173 | impl<'a, T> Clone for Reading<'a, T> 174 | { 175 | fn clone(&self) -> Self 176 | { 177 | if !self.0.account().try_lock_shared() { 178 | panic!() 179 | } 180 | Self(self.0.clone(), PhantomData) 181 | } 182 | } 183 | 184 | #[repr(transparent)] 185 | pub struct Writing<'a, T>(RawRef, PhantomData<&'a ()>); 186 | 187 | impl<'a, T> Writing<'a, T> 188 | { 189 | fn invariant(&self) { self.0.invariant(); } 190 | 191 | pub(crate) fn try_new(raw_ref: RawRef) -> Option 192 | { 193 | raw_ref.invariant(); 194 | if raw_ref.account().try_lock_exclusive() { 195 | let res = Self(raw_ref, PhantomData); 196 | res.invariant(); 197 | Some(res) 198 | } else { 199 | None 200 | } 201 | } 202 | } 203 | 204 | impl<'a, T> Deref for Writing<'a, T> 205 | { 206 | type Target = T; 207 | 208 | fn deref(&self) -> &Self::Target { unsafe { self.0.pointer().as_ptr().as_ref() } } 209 | } 210 | 211 | impl<'a, T> DerefMut for Writing<'a, T> 212 | { 213 | fn deref_mut(&mut self) -> &mut Self::Target { unsafe { self.0.pointer().as_ptr().as_mut() } } 214 | } 215 | 216 | impl<'a, T> Drop for Writing<'a, T> 217 | { 218 | fn drop(&mut self) 219 | { 220 | unsafe { 221 | self.0.try_consume_exclusive(); 222 | } 223 | } 224 | } 225 | 226 | #[repr(transparent)] 227 | pub struct Sendable(Strong); 228 | 229 | #[repr(transparent)] 230 | pub struct Shareable(Weak); 231 | 232 | #[repr(transparent)] 233 | pub struct Transferrable(GenRef); 234 | 235 | pub enum TransferrableEnum 236 | { 237 | Sendable(Sendable), 238 | Shareable(Shareable), 239 | } 240 | -------------------------------------------------------------------------------- /src/local_ledger.rs: -------------------------------------------------------------------------------- 1 | use super::global_ledger::*; 2 | use super::{tracking::Tracking, *}; 3 | use std::{ 4 | cell::{Cell, Ref, RefCell}, 5 | ptr::NonNull, 6 | }; 7 | 8 | #[repr(transparent)] 9 | #[derive(Debug, Clone, Copy)] 10 | pub(crate) struct LocalIndex(NonNull>); 11 | 12 | impl LocalIndex 13 | { 14 | fn borrow(&self) -> Ref { unsafe { self.0.as_ref() }.borrow() } 15 | 16 | // assumes exclusive lock 17 | pub(crate) unsafe fn make_sharable(&self) -> GlobalIndex 18 | { 19 | let mut cell = self.0.as_ref().borrow_mut(); 20 | let res: GlobalIndex; 21 | let acc = LocalAccount::Global(match &*cell { 22 | LocalAccount::Local(l) => { 23 | res = global_ledger::allocate(); 24 | if !res.try_lock_exclusive() { 25 | panic!("failed to exclusive lock just-allocated global index") 26 | } 27 | res 28 | } 29 | LocalAccount::Global(g) => { 30 | res = *g; 31 | res 32 | } 33 | }); 34 | *cell = acc; 35 | res 36 | } 37 | } 38 | 39 | impl Tracking for LocalIndex 40 | { 41 | fn generation(&self) -> u64 { self.borrow().generation() } 42 | fn invalidate(&self) -> u64 { self.borrow().invalidate() } 43 | fn try_lock_exclusive(&self) -> bool { self.borrow().try_lock_exclusive() } 44 | fn lock_exclusive(&self) { self.borrow().lock_exclusive() } 45 | fn try_lock_shared(&self) -> bool { self.borrow().try_lock_shared() } 46 | fn try_upgrade(&self) -> bool { self.borrow().try_upgrade() } 47 | unsafe fn unlock_exclusive(&self) { self.borrow().unlock_exclusive() } 48 | unsafe fn unlock_shared(&self) { self.borrow().unlock_shared() } 49 | } 50 | 51 | #[derive(Debug, Clone)] 52 | pub(crate) enum LocalAccount 53 | { 54 | Local(LocalCounter), 55 | Global(GlobalIndex), 56 | } 57 | 58 | impl Tracking for LocalAccount 59 | { 60 | fn generation(&self) -> u64 61 | { 62 | match self { 63 | Self::Local(l) => l.generation(), 64 | Self::Global(g) => g.generation(), 65 | } 66 | } 67 | 68 | fn invalidate(&self) -> u64 69 | { 70 | match self { 71 | Self::Local(l) => l.invalidate(), 72 | Self::Global(g) => g.invalidate(), 73 | } 74 | } 75 | 76 | fn try_lock_exclusive(&self) -> bool 77 | { 78 | match self { 79 | Self::Local(l) => l.try_lock_exclusive(), 80 | Self::Global(g) => g.try_lock_exclusive(), 81 | } 82 | } 83 | 84 | fn lock_exclusive(&self) 85 | { 86 | match self { 87 | LocalAccount::Local(l) => l.lock_exclusive(), 88 | LocalAccount::Global(g) => g.lock_exclusive(), 89 | } 90 | } 91 | 92 | fn try_lock_shared(&self) -> bool 93 | { 94 | match self { 95 | Self::Local(l) => l.try_lock_shared(), 96 | Self::Global(g) => g.try_lock_shared(), 97 | } 98 | } 99 | 100 | fn try_upgrade(&self) -> bool 101 | { 102 | match self { 103 | Self::Local(l) => l.try_upgrade(), 104 | Self::Global(g) => g.try_upgrade(), 105 | } 106 | } 107 | 108 | unsafe fn unlock_exclusive(&self) 109 | { 110 | match self { 111 | Self::Local(l) => l.unlock_exclusive(), 112 | Self::Global(g) => g.unlock_exclusive(), 113 | } 114 | } 115 | 116 | unsafe fn unlock_shared(&self) 117 | { 118 | match self { 119 | Self::Local(l) => l.unlock_shared(), 120 | Self::Global(g) => g.unlock_shared(), 121 | } 122 | } 123 | } 124 | 125 | #[derive(Debug, PartialEq, Eq, Clone)] 126 | pub(crate) struct LocalCounter 127 | { 128 | lock: Cell, 129 | generation: Cell, 130 | } 131 | 132 | impl Tracking for LocalCounter 133 | { 134 | fn generation(&self) -> u64 { self.generation.get() & RawRef::<()>::COUNTER_MASK } 135 | 136 | fn invalidate(&self) -> u64 137 | { 138 | let current = self.generation.get(); 139 | self.generation.set(current + 1); 140 | current & RawRef::<()>::COUNTER_MASK 141 | } 142 | 143 | fn try_lock_exclusive(&self) -> bool 144 | { 145 | if self.lock.get() == 0 { 146 | self.lock.set(-1); 147 | return true; 148 | } else { 149 | return false; 150 | } 151 | } 152 | 153 | fn lock_exclusive(&self) 154 | { 155 | if !self.try_lock_exclusive() { 156 | panic!("unconditional locking operation on locked local counter") 157 | } 158 | } 159 | 160 | fn try_lock_shared(&self) -> bool 161 | { 162 | if self.lock.get() >= 0 { 163 | self.lock.set(self.lock.get() + 1); 164 | return true; 165 | } else { 166 | return false; 167 | } 168 | } 169 | 170 | fn try_upgrade(&self) -> bool 171 | { 172 | if self.lock.get() == 1 { 173 | self.lock.set(-1); 174 | return true; 175 | } else { 176 | return false; 177 | } 178 | } 179 | 180 | unsafe fn unlock_exclusive(&self) 181 | { 182 | if self.lock.get() >= 1 { 183 | panic!("unlock_exclusive on share-locked local tracker"); 184 | } else if self.lock.get() == 0 { 185 | panic!("unlock_exclusive on unlocked local tracker"); 186 | } 187 | self.lock.set(0); 188 | } 189 | 190 | unsafe fn unlock_shared(&self) 191 | { 192 | if self.lock.get() < 0 { 193 | panic!("unlock_shared on exclusive-locked local tracker"); 194 | } else if self.lock.get() == 0 { 195 | panic!("unlock_shared on unlocked local tracker"); 196 | } 197 | self.lock.set(self.lock.get() - 1); 198 | } 199 | } 200 | 201 | use bumpalo::Bump; 202 | thread_local! { 203 | static ARENA : RefCell = RefCell::new(Bump::new()); 204 | static FREE_LIST : RefCell> = RefCell::new(Vec::new()); 205 | } 206 | 207 | pub(crate) fn allocate() -> LocalIndex { recycle().unwrap_or_else(fresh) } 208 | 209 | fn fresh() -> LocalIndex 210 | { 211 | ARENA.with_borrow_mut(|arena| { 212 | LocalIndex(NonNull::from(arena.alloc(RefCell::new( 213 | LocalAccount::Local(LocalCounter { 214 | lock: 0.into(), 215 | generation: RawRef::<()>::COUNTER_INIT.into(), 216 | }), 217 | )))) 218 | }) 219 | } 220 | 221 | fn recycle() -> Option { FREE_LIST.with_borrow_mut(|vec| vec.pop()) } 222 | 223 | pub(crate) unsafe fn free(li: LocalIndex) 224 | { 225 | li.invalidate(); 226 | li.unlock_exclusive(); 227 | FREE_LIST.with_borrow_mut(|vec| vec.push(li)) 228 | } 229 | -------------------------------------------------------------------------------- /src/raw_ref.rs: -------------------------------------------------------------------------------- 1 | use std::{mem, num::NonZeroU64, ptr::NonNull}; 2 | 3 | use crate::tracking::{self, Account, AccountEnum}; 4 | 5 | use super::{ 6 | global_ledger::GlobalIndex, 7 | local_ledger::{self}, 8 | tracking::*, 9 | }; 10 | 11 | pub(crate) enum PointerEnum 12 | { 13 | Weak(NonNull), 14 | Strong(NonNull), 15 | } 16 | 17 | impl Clone for PointerEnum 18 | { 19 | fn clone(&self) -> Self 20 | { 21 | match self { 22 | Self::Weak(arg0) => Self::Weak(arg0.clone()), 23 | Self::Strong(arg0) => Self::Strong(arg0.clone()), 24 | } 25 | } 26 | } 27 | 28 | impl std::fmt::Debug for PointerEnum 29 | { 30 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result 31 | { 32 | match self { 33 | Self::Weak(arg0) => f.debug_tuple("Weak").field(arg0).finish(), 34 | Self::Strong(arg0) => f.debug_tuple("Strong").field(arg0).finish(), 35 | } 36 | } 37 | } 38 | 39 | impl PointerEnum 40 | { 41 | pub(crate) fn as_ptr(self) -> NonNull 42 | { 43 | match self { 44 | PointerEnum::Weak(p) => p, 45 | PointerEnum::Strong(p) => p, 46 | } 47 | } 48 | 49 | pub(crate) fn map(self, f: F) -> PointerEnum 50 | where 51 | F: FnOnce(NonNull) -> NonNull, 52 | { 53 | match self { 54 | Self::Weak(p) => PointerEnum::Weak(f(p)), 55 | Self::Strong(p) => PointerEnum::Strong(f(p)), 56 | } 57 | } 58 | } 59 | 60 | #[repr(C)] 61 | pub(crate) struct RawRef 62 | { 63 | account: Account, 64 | pointer: NonNull, 65 | generation: NonZeroU64, 66 | } 67 | 68 | impl Clone for RawRef 69 | { 70 | fn clone(&self) -> Self 71 | { 72 | Self { 73 | account: self.account.clone(), 74 | pointer: self.pointer.clone(), 75 | generation: self.generation.clone(), 76 | } 77 | } 78 | } 79 | 80 | impl RawRef 81 | { 82 | #[cfg(test)] 83 | pub(crate) fn invariant(&self) 84 | { 85 | let reference = self.generation.get() & Self::REFERENCE_MASK; 86 | let account = self.generation.get() & Self::ACCOUNT_MASK; 87 | let counter = self.generation.get() & Self::COUNTER_MASK; 88 | 89 | assert_ne!(counter, 0, "flags set on nil generation count"); 90 | assert_ne!(account, 0, "no account flag on positive generation count"); 91 | assert_ne!(account, Self::ACCOUNT_MASK, "saturated account flags"); 92 | assert_ne!(reference, 0, "no reference flag"); 93 | assert_ne!(reference, Self::REFERENCE_MASK, "saturated reference flags"); 94 | } 95 | 96 | #[cfg(not(test))] 97 | pub(crate) fn invariant(&self) {} 98 | 99 | fn new_from_parts(acc: AccountEnum, ptr: PointerEnum) -> Self 100 | { 101 | let (account, acc_flag) = match acc { 102 | AccountEnum::Local(local) => (tracking::Account { local }, Self::LOCAL_ACCOUNT), 103 | AccountEnum::Global(global) => (tracking::Account { global }, Self::GLOBAL_ACCOUNT), 104 | }; 105 | let (pointer, ref_flag) = match ptr { 106 | PointerEnum::Weak(p) => (p, Self::WEAK_REFERENCE), 107 | PointerEnum::Strong(p) => (p, Self::STRONG_REFERENCE), 108 | }; 109 | let generation = NonZeroU64::new(acc.generation() | acc_flag | ref_flag).unwrap(); 110 | let res = RawRef { 111 | account, 112 | pointer, 113 | generation, 114 | }; 115 | res.invariant(); 116 | res 117 | } 118 | 119 | pub(crate) fn from_box(mut it: Box) -> Self 120 | { 121 | let res = Self::new_from_parts( 122 | AccountEnum::Local(local_ledger::allocate()), 123 | PointerEnum::Strong(NonNull::from(it.as_mut())), 124 | ); 125 | mem::forget(it); 126 | res.invariant(); 127 | res 128 | } 129 | 130 | #[inline] 131 | unsafe fn try_consume(&self, locking_primitive: fn(&AccountEnum) -> bool) -> Option> 132 | { 133 | self.invariant(); 134 | let account = self.account(); 135 | if locking_primitive(&account) { 136 | tracking::free(account); 137 | Some(Box::from_raw(self.pointer().as_ptr().as_ptr())) 138 | } else { 139 | None 140 | } 141 | } 142 | 143 | pub(crate) unsafe fn try_consume_exclusive(&self) -> Option> 144 | { 145 | self.try_consume(AccountEnum::try_lock_exclusive) 146 | } 147 | 148 | pub(crate) unsafe fn try_consume_shared(&self) -> Option> 149 | { 150 | self.try_consume(AccountEnum::try_upgrade) 151 | } 152 | 153 | pub(crate) fn map(self, f: F) -> RawRef 154 | where 155 | F: FnOnce(NonNull) -> NonNull, 156 | { 157 | let res = RawRef::new_from_parts(self.account(), self.pointer().map(f)); 158 | res.invariant(); 159 | res 160 | } 161 | 162 | pub(crate) fn account(&self) -> AccountEnum 163 | { 164 | self.invariant(); 165 | match self.generation.get() & Self::ACCOUNT_MASK { 166 | Self::GLOBAL_ACCOUNT => AccountEnum::Global(unsafe { self.account.global }), 167 | Self::LOCAL_ACCOUNT => AccountEnum::Local(unsafe { self.account.local }), 168 | _ => panic!(), 169 | } 170 | } 171 | 172 | pub(crate) fn pointer(&self) -> PointerEnum 173 | { 174 | self.invariant(); 175 | match self.generation.get() & Self::REFERENCE_MASK { 176 | Self::STRONG_REFERENCE => PointerEnum::Strong(self.pointer), 177 | Self::WEAK_REFERENCE => PointerEnum::Weak(self.pointer), 178 | _ => panic!(), 179 | } 180 | } 181 | 182 | pub(crate) fn set_weak(mut self) -> Self 183 | { 184 | self.invariant(); 185 | self.generation = 186 | NonZeroU64::new((self.generation.get() & !Self::REFERENCE_MASK) | Self::WEAK_REFERENCE) 187 | .unwrap(); 188 | self.invariant(); 189 | self 190 | } 191 | 192 | fn set_global(mut self) -> Self 193 | { 194 | self.invariant(); 195 | self.generation = 196 | NonZeroU64::new((self.generation.get() & !Self::ACCOUNT_MASK) | Self::GLOBAL_ACCOUNT) 197 | .unwrap(); 198 | self.invariant(); 199 | self 200 | } 201 | 202 | fn counter(self) -> u64 { self.generation.get() & Self::COUNTER_MASK } 203 | 204 | const FLAG_MASK: u64 = 0b1111u64.reverse_bits(); 205 | pub(crate) const COUNTER_MASK: u64 = !Self::FLAG_MASK; 206 | pub(crate) const COUNTER_INIT: u64 = 1; 207 | const GLOBAL_ACCOUNT: u64 = 0b0001u64.reverse_bits(); 208 | const LOCAL_ACCOUNT: u64 = 0b0010u64.reverse_bits(); 209 | const ACCOUNT_MASK: u64 = Self::GLOBAL_ACCOUNT | Self::LOCAL_ACCOUNT; 210 | const STRONG_REFERENCE: u64 = 0b0100u64.reverse_bits(); 211 | const WEAK_REFERENCE: u64 = 0b1000u64.reverse_bits(); 212 | const REFERENCE_MASK: u64 = Self::STRONG_REFERENCE | Self::WEAK_REFERENCE; 213 | } 214 | -------------------------------------------------------------------------------- /src/tracking.rs: -------------------------------------------------------------------------------- 1 | use crate::{global_ledger, local_ledger}; 2 | 3 | use super::global_ledger::GlobalIndex; 4 | 5 | use super::local_ledger::LocalIndex; 6 | 7 | pub(crate) trait Tracking 8 | { 9 | fn generation(&self) -> u64; 10 | fn invalidate(&self) -> u64; 11 | fn try_lock_exclusive(&self) -> bool; 12 | fn lock_exclusive(&self); 13 | fn try_lock_shared(&self) -> bool; 14 | fn try_upgrade(&self) -> bool; 15 | unsafe fn unlock_exclusive(&self); 16 | unsafe fn unlock_shared(&self); 17 | } 18 | 19 | #[derive(Clone, Copy)] 20 | pub(crate) union Account 21 | { 22 | pub(crate) local: LocalIndex, 23 | pub(crate) global: GlobalIndex, 24 | } 25 | 26 | #[derive(Clone, Copy)] 27 | pub(crate) enum AccountEnum 28 | { 29 | Local(LocalIndex), 30 | Global(GlobalIndex), 31 | } 32 | 33 | impl Tracking for AccountEnum 34 | { 35 | fn generation(&self) -> u64 36 | { 37 | match self { 38 | Self::Local(l) => l.generation(), 39 | Self::Global(g) => g.generation(), 40 | } 41 | } 42 | 43 | fn invalidate(&self) -> u64 44 | { 45 | match self { 46 | Self::Local(l) => l.invalidate(), 47 | Self::Global(g) => g.invalidate(), 48 | } 49 | } 50 | 51 | fn try_lock_exclusive(&self) -> bool 52 | { 53 | match self { 54 | Self::Local(l) => l.try_lock_exclusive(), 55 | Self::Global(g) => g.try_lock_exclusive(), 56 | } 57 | } 58 | 59 | fn lock_exclusive(&self) 60 | { 61 | match self { 62 | Self::Local(l) => l.lock_exclusive(), 63 | Self::Global(l) => l.lock_exclusive(), 64 | } 65 | } 66 | 67 | fn try_lock_shared(&self) -> bool 68 | { 69 | match self { 70 | Self::Local(l) => l.try_lock_shared(), 71 | Self::Global(g) => g.try_lock_shared(), 72 | } 73 | } 74 | 75 | fn try_upgrade(&self) -> bool 76 | { 77 | match self { 78 | Self::Local(l) => l.try_upgrade(), 79 | Self::Global(g) => g.try_upgrade(), 80 | } 81 | } 82 | 83 | unsafe fn unlock_exclusive(&self) 84 | { 85 | match self { 86 | Self::Local(l) => l.unlock_exclusive(), 87 | Self::Global(g) => g.unlock_exclusive(), 88 | } 89 | } 90 | 91 | unsafe fn unlock_shared(&self) 92 | { 93 | match self { 94 | Self::Local(l) => l.unlock_shared(), 95 | Self::Global(g) => g.unlock_shared(), 96 | } 97 | } 98 | } 99 | 100 | pub(crate) unsafe fn free(ac: AccountEnum) 101 | { 102 | match ac { 103 | AccountEnum::Local(l) => local_ledger::free(l), 104 | AccountEnum::Global(g) => global_ledger::free(g), 105 | } 106 | } 107 | --------------------------------------------------------------------------------