switch to refcounted buffers
[nihav.git] / nihav-core / src / refs.rs
1 use std::ops::{Deref, DerefMut};
2 use std::sync::atomic::*;
3
4 struct NABufferData<T> {
5 data: T,
6 refs: AtomicUsize,
7 }
8
9 impl<T> NABufferData<T> {
10 fn new(data: T) -> Self {
11 Self {
12 data: data,
13 refs: AtomicUsize::new(1),
14 }
15 }
16 fn inc_refs(obj: &mut Self) {
17 obj.refs.fetch_add(1, Ordering::SeqCst);
18 }
19 fn dec_refs(obj: &mut Self) {
20 if obj.refs.fetch_sub(1, Ordering::SeqCst) == 0 {
21 std::mem::forget(obj);
22 }
23 }
24 fn get_num_refs(obj: &Self) -> usize {
25 obj.refs.load(Ordering::Relaxed)
26 }
27 fn get_read_ptr(obj: &Self) -> &T {
28 &obj.data
29 }
30 fn get_write_ptr(obj: &mut Self) -> Option<&mut T> {
31 Some(&mut obj.data)
32 }
33 }
34
35 pub struct NABufferRef<T> {
36 ptr: *mut NABufferData<T>,
37 }
38
39 impl<T> NABufferRef<T> {
40 pub fn new(val: T) -> Self {
41 let bdata = NABufferData::new(val);
42 let nbox: Box<_> = Box::new(bdata);
43 Self { ptr: Box::into_raw(nbox) }
44 }
45 pub fn get_num_refs(&self) -> usize {
46 unsafe {
47 NABufferData::get_num_refs(self.ptr.as_mut().unwrap())
48 }
49 }
50 pub fn as_ref(&self) -> &T {
51 unsafe {
52 NABufferData::get_read_ptr(self.ptr.as_mut().unwrap())
53 }
54 }
55 pub fn as_mut(&mut self) -> Option<&mut T> {
56 unsafe {
57 NABufferData::get_write_ptr(self.ptr.as_mut().unwrap())
58 }
59 }
60 }
61
62 impl<T> Deref for NABufferRef<T> {
63 type Target = T;
64 fn deref(&self) -> &T { self.as_ref() }
65 }
66
67 impl<T> DerefMut for NABufferRef<T> {
68 fn deref_mut(&mut self) -> &mut T { self.as_mut().unwrap() }
69 }
70
71 impl<T> Clone for NABufferRef<T> {
72 fn clone(&self) -> Self {
73 unsafe {
74 NABufferData::inc_refs(self.ptr.as_mut().unwrap());
75 }
76 Self { ptr: self.ptr }
77 }
78 }
79
80 impl<T> Drop for NABufferRef<T> {
81 fn drop(&mut self) {
82 unsafe {
83 NABufferData::dec_refs(self.ptr.as_mut().unwrap());
84 }
85 }
86 }
87