use std::sync::atomic::{AtomicBool, Ordering};
use std::cell::UnsafeCell;
use std::mem::MaybeUninit;
use std::ops;
pub struct UnsafeReadOnlyCell<T: Send>
{
title: &'static str,
inner: UnsafeCell<MaybeUninit<T>>,
blocked: AtomicBool,
}
unsafe impl<T: Send> Sync for UnsafeReadOnlyCell<T> {}
impl<T: Send> ops::Deref for UnsafeReadOnlyCell<T>
{
type Target = T;
fn deref(&self) -> &T
{
if self.blocked.load(Ordering::SeqCst) == false
{
panic!("Assertion trap: Dereference attempt of UnsafeReadOnlyCell \
'{}' which was not inited.", self.title);
}
return unsafe
{
&*(*self.inner.get()).as_ptr()
};
}
}
impl<T: Send> UnsafeReadOnlyCell<T>
{
pub unsafe fn new_uninitialized(
title: &'static str
) -> UnsafeReadOnlyCell<T>
{
return
UnsafeReadOnlyCell
{
title: title,
inner: UnsafeCell::new(MaybeUninit::uninit()),
blocked: AtomicBool::new(false),
};
}
pub unsafe fn init(&self, init: T)
{
if self.blocked.load(Ordering::SeqCst) == false
{
(*self.inner.get()) = MaybeUninit::new(init);
self.blocked.store(true, Ordering::SeqCst);
}
else
{
panic!("Assertion trap: attempt to re-initialize \
the ReadOnlySharedCell: {}", self.title);
}
}
pub fn is_init(&self) -> bool
{
return self.blocked.load(Ordering::SeqCst);
}
}
#[test]
fn test1()
{
struct TestStruct1
{
field1: i64,
field2: i64
}
unsafe impl Send for TestStruct1 {}
unsafe impl Sync for TestStruct1 {}
impl TestStruct1
{
pub fn get1(&self) -> i64
{
return self.field1;
}
pub fn get2(&self) -> i64
{
return self.field2;
}
}
lazy_static! {
static ref SYNC_SYSLOG: UnsafeReadOnlyCell<TestStruct1> =
unsafe { UnsafeReadOnlyCell::new_uninitialized("test_1") };
}
unsafe { SYNC_SYSLOG.init(TestStruct1{field1: 100, field2: 200}) };
assert_eq!((*SYNC_SYSLOG).get1(), 100);
assert_eq!((*SYNC_SYSLOG).get2(), 200);
return;
}
#[test]
#[should_panic]
fn test2()
{
struct TestStruct1
{
#[allow(dead_code)]
field1: i64,
#[allow(dead_code)]
field2: i64
}
unsafe impl Send for TestStruct1 {}
unsafe impl Sync for TestStruct1 {}
lazy_static! {
static ref SYNC_SYSLOG: UnsafeReadOnlyCell<TestStruct1> =
unsafe { UnsafeReadOnlyCell::new_uninitialized("test_1") };
}
unsafe { SYNC_SYSLOG.init(TestStruct1{field1: 100, field2: 200}) };
let s1 = TestStruct1{field1: 100, field2: 200};
unsafe { SYNC_SYSLOG.init(s1) };
return;
}
#[test]
#[should_panic]
fn test3()
{
struct TestStruct1
{
field1: i64,
#[allow(dead_code)]
field2: i64
}
unsafe impl Send for TestStruct1 {}
unsafe impl Sync for TestStruct1 {}
impl TestStruct1
{
pub fn get1(&self) -> i64
{
return self.field1;
}
#[allow(dead_code)]
pub fn get2(&self) -> i64
{
return self.field2;
}
}
lazy_static! {
static ref SYNC_SYSLOG: UnsafeReadOnlyCell<TestStruct1> =
unsafe { UnsafeReadOnlyCell::new_uninitialized("test_1") };
}
assert_eq!((*SYNC_SYSLOG).get1(), 100);
return;
}