Skip to content

Commit f5a39b7

Browse files
committed
add arc_ref example
1 parent 6b6e41d commit f5a39b7

File tree

1 file changed

+141
-0
lines changed

1 file changed

+141
-0
lines changed

examples/arc_ref.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#![feature(allocator_api)]
2+
3+
use std::{
4+
alloc::{Allocator, Global, Layout},
5+
mem,
6+
ops::Deref,
7+
ptr::{NonNull, drop_in_place},
8+
sync::atomic::{AtomicUsize, Ordering},
9+
};
10+
11+
use field_projection::{
12+
compat,
13+
marker::Field,
14+
ops::{Project, Projectable, SafeProject},
15+
};
16+
use field_projection_internal::{HasFields, p, start_proj};
17+
18+
pub struct ArcRef<T: ?Sized> {
19+
info: NonNull<Info>,
20+
value: NonNull<T>,
21+
}
22+
23+
#[repr(C)]
24+
struct Info {
25+
refcount: AtomicUsize,
26+
layout: Layout,
27+
drop_value: fn(*mut Info),
28+
}
29+
30+
#[repr(C)]
31+
struct Inner<T: ?Sized> {
32+
info: Info,
33+
value: T,
34+
}
35+
36+
impl<T: ?Sized> Drop for ArcRef<T> {
37+
fn drop(&mut self) {
38+
if self.refcount().fetch_sub(1, Ordering::SeqCst) == 1 {
39+
(self.info().drop_value)(self.info.as_ptr());
40+
let layout = self.info().layout;
41+
let ptr = self.info.cast::<u8>();
42+
unsafe { Global.deallocate(ptr, layout) }
43+
}
44+
}
45+
}
46+
47+
impl<T: ?Sized> ArcRef<T> {
48+
pub fn new(val: T) -> Self
49+
where
50+
T: Sized,
51+
{
52+
let layout = Layout::new::<Inner<T>>();
53+
let ptr = Global.allocate(layout).unwrap().cast::<Inner<T>>();
54+
let info: NonNull<Info> = ptr.cast();
55+
let value = unsafe { NonNull::new_unchecked(&raw mut (*ptr.as_ptr()).value) };
56+
57+
let info_value = Info {
58+
refcount: AtomicUsize::new(1),
59+
layout,
60+
drop_value: |ptr| unsafe { drop_in_place(ptr.cast::<Inner<T>>()) },
61+
};
62+
unsafe { info.write(info_value) };
63+
unsafe { value.write(val) };
64+
65+
Self { info, value }
66+
}
67+
68+
fn info(&self) -> &Info {
69+
unsafe { &(*self.info.as_ptr()) }
70+
}
71+
72+
fn refcount(&self) -> &AtomicUsize {
73+
&self.info().refcount
74+
}
75+
}
76+
77+
impl<T: ?Sized> Clone for ArcRef<T> {
78+
fn clone(&self) -> Self {
79+
self.refcount().fetch_add(1, Ordering::Relaxed);
80+
Self {
81+
info: self.info,
82+
value: self.value,
83+
}
84+
}
85+
}
86+
87+
impl<T: ?Sized> Deref for ArcRef<T> {
88+
type Target = T;
89+
fn deref(&self) -> &Self::Target {
90+
unsafe { self.value.as_ref() }
91+
}
92+
}
93+
94+
impl<T: ?Sized> Projectable for ArcRef<T> {
95+
type Inner = T;
96+
}
97+
98+
impl<T, F> Project<F> for ArcRef<T>
99+
where
100+
T: ?Sized,
101+
F: Field<Base = T>,
102+
F::Type: Sized,
103+
{
104+
type Output<'a>
105+
= ArcRef<F::Type>
106+
where
107+
Self: 'a;
108+
109+
unsafe fn project<'a>(this: *const Self) -> Self::Output<'a>
110+
where
111+
Self: 'a,
112+
{
113+
let this = unsafe { &*this };
114+
mem::forget(this.clone());
115+
ArcRef {
116+
info: this.info,
117+
value: unsafe { Project::<F>::project(&this.value) },
118+
}
119+
}
120+
}
121+
122+
unsafe impl<T: ?Sized> SafeProject for ArcRef<T> {}
123+
124+
unsafe impl<T: ?Sized> compat::ProjectableExt for ArcRef<T> {
125+
type Safety = compat::Safe;
126+
}
127+
128+
fn main() {
129+
#[derive(HasFields)]
130+
struct Foo {
131+
x: usize,
132+
y: usize,
133+
}
134+
135+
let foo = ArcRef::new(Foo { x: 42, y: 24 });
136+
start_proj!(foo);
137+
let x = p!(@foo->x);
138+
let y = p!(@foo->y);
139+
assert_ne!(&*x, &*y);
140+
assert_eq!(foo.refcount().load(Ordering::Relaxed), 3);
141+
}

0 commit comments

Comments
 (0)