Write a Guard type
Notice the use of the atomic::*
operators to generate thread safe checks for when all guards have expired and the target needs to be discarded.
Pointer aliasing
Is it not undefined behavior to deference the *mut T
in multiple locations?
The answer is no: Accessing and writing to data via a raw pointer is not undefined behavior due to pointer aliasing; only references trigger this, as they are marked as noalias
in the LLVM byte code.
Technically a raw pointer is both based on and not marked as noalias
, so it does not violate any of the pointer aliasing rules in LLVM.
However, notice that converting the raw pointer into a mutable reference is locked by a mutex, which prevents multiple mutable references being used concurrently. Since references are marked noalias
, this would trigger undefined behavior.
use std::sync::Arc;
use std::mem::transmute;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::ops::Deref;
use std::ops::DerefMut;
// Trait box
pub struct ABox<T: ?Sized> {
raw:*mut T,
lock:Arc<AtomicBool>,
count:Arc<AtomicUsize>
}
// Trait box guard
pub struct ABoxGuard<'a, T: ?Sized + 'a> {
lock:Arc<AtomicBool>,
raw:&'a mut T
}
impl<T: ?Sized> ABox<T> {
/// Create a new instance
pub fn new(value:Box<T>) -> ABox<T> {
return ABox {
raw: unsafe { transmute(value) },
lock: Arc::new(AtomicBool::new(false)),
count: Arc::new(AtomicUsize::new(1))
};
}
/// Try to lock the instance and return it
pub fn as_ref<'a, 'b>(&'a mut self) -> Option<ABoxGuard<'b, T>> {
if !self.lock.compare_and_swap(false, true, Ordering::Acquire) {
return Some(ABoxGuard {
raw: unsafe { &mut *self.raw },
lock: self.lock.clone()
});
}
return None;
}
/// Create a clone
pub fn clone(&mut self) -> ABox<T> {
self.count.fetch_add(1, Ordering::SeqCst);
return ABox {
raw: self.raw,
lock: self.lock.clone(),
count: self.count.clone()
}
}
}
impl<'b, T: ?Sized> Deref for ABoxGuard<'b, T> {
type Target = T;
fn deref<'a>(&'a self) -> &'a T {
return self.raw;
}
}
impl<'b, T: ?Sized> DerefMut for ABoxGuard<'b, T> {
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
return self.raw;
}
}
impl<'a, T: ?Sized> Drop for ABoxGuard<'a, T> {
fn drop(&mut self) {
self.lock.compare_and_swap(true, false, Ordering::Acquire);
}
}
impl<T: ?Sized> Drop for ABox<T> {
fn drop(&mut self) {
if self.count.fetch_sub(1, Ordering::SeqCst) == 1 {
unsafe {
let _:Box<T> = transmute(self.raw);
}
}
}
}
#[cfg(test)]
mod test {
use super::ABox;
struct Bar;
trait Foo {
fn hi(&self);
fn hi_mut(&mut self);
}
impl Foo for Bar {
fn hi(&self) { println!("\n\nHi\n\n"); }
fn hi_mut(&mut self) { println!("\n\nHi mut\n\n"); }
}
impl Drop for Bar {
fn drop(&mut self) {
println!("Bar dropped!");
}
}
#[test]
fn test_create_instance() {
let y = Box::new(Bar) as Box<Foo>;
let _ = ABox::<Foo>::new(y);
}
#[test]
fn test_lock() {
let y = Box::new(Bar) as Box<Foo>;
let mut x = ABox::<Foo>::new(y);
if let Some(mut xp) = x.as_ref() { xp.hi(); xp.hi_mut(); };
if let Some(mut xp) = x.as_ref() { xp.hi(); xp.hi_mut(); };
}
#[test]
fn test_clone() {
let y = Box::new(Bar) as Box<Foo>;
let mut x = ABox::<Foo>::new(y);
let mut z = x.clone();
if let Some(mut xp) = x.as_ref() { xp.hi(); xp.hi_mut(); };
if let Some(mut xp) = z.as_ref() { xp.hi(); xp.hi_mut(); };
}
}