X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-core%2Fsrc%2Frefs.rs;h=e4cde3a369f7c114c7d7d1daffb8de81f7bd8c7f;hb=5f031d75f99167db3aca5e0bb25c06c487deb236;hp=b83aa25428b7c75df67182efa73536a646fb7d7d;hpb=49db8a1187bd05535f13a5d13effb9f0bb8ac394;p=nihav.git diff --git a/nihav-core/src/refs.rs b/nihav-core/src/refs.rs index b83aa25..e4cde3a 100644 --- a/nihav-core/src/refs.rs +++ b/nihav-core/src/refs.rs @@ -1,4 +1,26 @@ +//! Reference-counted buffer data type. +//! +//! NihAV requires some reference-counted type especially for frame buffer pools. +//! `Arc` does not allow mutability with several references present, `RwLock` does not work reliably in a single thread mode (at least for me) so I ended up NIHing something. +//! +//! Currently it does not prevent code from reading the data that is being written to. +//! Maybe in the future this will be replaced by something better and using more standard components. +//! +//! Also it contains `unsafe{}` so I should not write in Rust at all. +//! +//! # Examples +//! +//! ``` +//! use nihav_core::refs::NABufferRef; +//! +//! let vec = vec![42u8; 16]; +//! let vec_ref = NABufferRef::new(vec); +//! let vec_ref2 = vec_ref.clone(); +//! let ref_count = vec_ref.get_num_refs(); // should be 2 +//! println!("vector element 4 is {}", vec_ref[4]); // should print the fourth vector element +//! ``` use std::ops::{Deref, DerefMut}; +use std::convert::AsRef; use std::sync::atomic::*; struct NABufferData { @@ -9,17 +31,15 @@ struct NABufferData { impl NABufferData { fn new(data: T) -> Self { Self { - data: data, + data, refs: AtomicUsize::new(1), } } fn inc_refs(obj: &mut Self) { obj.refs.fetch_add(1, Ordering::SeqCst); } - fn dec_refs(obj: &mut Self) { - if obj.refs.fetch_sub(1, Ordering::SeqCst) == 0 { - std::mem::forget(obj); - } + fn dec_refs(obj: &mut Self) -> bool { + obj.refs.fetch_sub(1, Ordering::SeqCst) == 1 } fn get_num_refs(obj: &Self) -> usize { obj.refs.load(Ordering::Relaxed) @@ -32,29 +52,39 @@ impl NABufferData { } } +/// Reference-counted buffer reference. pub struct NABufferRef { ptr: *mut NABufferData, } +unsafe impl Sync for NABufferRef {} +unsafe impl Send for NABufferRef {} + impl NABufferRef { + /// Constructs a new instance of `NABufferRef`. pub fn new(val: T) -> Self { let bdata = NABufferData::new(val); let nbox: Box<_> = Box::new(bdata); Self { ptr: Box::into_raw(nbox) } } + /// Reports the number of references for the current instance. pub fn get_num_refs(&self) -> usize { unsafe { NABufferData::get_num_refs(self.ptr.as_mut().unwrap()) } } - pub fn as_ref(&self) -> &T { + /// Returns a mutable pointer to the underlying data if possible. + pub fn as_mut(&mut self) -> Option<&mut T> { unsafe { - NABufferData::get_read_ptr(self.ptr.as_mut().unwrap()) + NABufferData::get_write_ptr(self.ptr.as_mut().unwrap()) } } - pub fn as_mut(&mut self) -> Option<&mut T> { +} + +impl AsRef for NABufferRef { + fn as_ref(&self) -> &T { unsafe { - NABufferData::get_write_ptr(self.ptr.as_mut().unwrap()) + NABufferData::get_read_ptr(self.ptr.as_mut().unwrap()) } } } @@ -80,7 +110,10 @@ impl Clone for NABufferRef { impl Drop for NABufferRef { fn drop(&mut self) { unsafe { - NABufferData::dec_refs(self.ptr.as_mut().unwrap()); + if NABufferData::dec_refs(self.ptr.as_mut().unwrap()) { + let data = Box::from_raw(self.ptr); + std::mem::drop(data); + } } } }