1use core::{mem::forget, ops::Deref};
2
3use super::{
4 block::Block, manager::Dealloc, mut_ref::MutRef, object::Object, optional_block::OptionalBlock,
5 optional_ref::OptionalRef, ref_counter_update::RefCounterUpdate,
6};
7
8pub type Ref<T, D> = OptionalRef<*const Block<T, D>>;
10
11impl<T: Object, D: Dealloc> Ref<T, D> {
12 pub fn try_to_mut_ref(self) -> Result<MutRef<T, D>, Self> {
13 unsafe {
14 if let Some(ptr) = self.internal().ref_counter_update(RefCounterUpdate::Read) {
15 forget(self);
16 Ok(MutRef::new(ptr as _))
17 } else {
18 Err(self)
19 }
20 }
21 }
22}
23
24impl<T: Object, D: Dealloc> Deref for Ref<T, D> {
25 type Target = T;
26 #[inline(always)]
27 fn deref(&self) -> &T {
28 unsafe { (*self.internal()).object() }
29 }
30}
31
32#[cfg(test)]
33mod test {
34 use core::{alloc::Layout, mem::forget, sync::atomic::AtomicIsize};
35
36 use wasm_bindgen_test::wasm_bindgen_test;
37
38 use crate::mem::{
39 block::Block, block_header::BlockHeader, fixed::Fixed, manager::Dealloc,
40 ref_counter_update::RefCounterUpdate,
41 };
42
43 use super::Ref;
44
45 #[derive(Default)]
46 struct BH();
47
48 #[derive(Debug)]
49 struct M();
50
51 impl Dealloc for M {
52 type BlockHeader = BH;
53 unsafe fn dealloc(_: *mut u8, _: core::alloc::Layout) {
54 panic!()
55 }
56 }
57
58 impl BlockHeader for BH {
59 unsafe fn ref_counter_update(&self, _: RefCounterUpdate) -> isize {
60 panic!()
61 }
62 }
63
64 #[test]
65 #[wasm_bindgen_test]
66 fn test() {
67 let mut buffer: [(); 0] = [];
68 let x = buffer.as_mut_ptr() as *mut Block<Fixed<()>, M>;
69 let y = unsafe { Ref::from_internal(x) };
70 forget(y);
71 }
72
73 #[derive(Debug)]
74 struct M1();
75
76 impl Dealloc for M1 {
77 type BlockHeader = AtomicIsize;
78 unsafe fn dealloc(_: *mut u8, _: Layout) {}
79 }
80
81 #[test]
82 #[wasm_bindgen_test]
83 fn test_1() {
84 let mut buffer: [isize; 1] = [0];
85 let x = buffer.as_mut_ptr() as *mut Block<Fixed<()>, M1>;
86 let p = unsafe { &mut (*x).header };
87 assert_eq!(unsafe { p.ref_counter_update(RefCounterUpdate::Read) }, 0);
88 {
89 let y = unsafe { Ref::from_internal(x) };
90 assert_eq!(unsafe { p.ref_counter_update(RefCounterUpdate::Read) }, 0);
91 {
92 let _z = y.clone();
93 assert_eq!(unsafe { p.ref_counter_update(RefCounterUpdate::Read) }, 1);
94 }
95 assert_eq!(unsafe { p.ref_counter_update(RefCounterUpdate::Read) }, 0);
96 }
97 assert_eq!(unsafe { p.ref_counter_update(RefCounterUpdate::Read) }, -1);
98 }
99}