use core::cell::{Ref, RefCell, RefMut};
use core::ops::{Deref, DerefMut};
use avr_oxide::alloc::boxed::Box;
pub struct StaticWrap<T: 'static> {
wrapped: *mut RefCell<T>
}
pub struct StaticRef<'sr, T: ?Sized + 'sr> {
r: Ref<'sr,T>
}
pub struct StaticRefMut<'sr, T: ?Sized + 'sr> {
rm: RefMut<'sr,T>
}
pub trait AsStaticRef<T>
where
T: ?Sized
{
unsafe fn as_static_ref(&self) -> &'static T;
}
pub trait AsStaticRefMut<T> : AsStaticRef<T>
where
T: ?Sized
{
unsafe fn as_static_ref_mut(&mut self) -> &'static mut T;
}
impl<'sr,T: ?Sized + 'sr> AsStaticRef<T> for StaticRef<'sr, T> {
unsafe fn as_static_ref(&self) -> &'static T {
self.static_ref()
}
}
impl<'sr,T: ?Sized + 'sr> AsStaticRef<T> for StaticRefMut<'sr, T> {
unsafe fn as_static_ref(&self) -> &'static T {
self.static_ref()
}
}
impl<'sr,T: ?Sized + 'sr> AsStaticRefMut<T> for StaticRefMut<'sr, T> {
unsafe fn as_static_ref_mut(&mut self) -> &'static mut T {
self.static_ref_mut()
}
}
impl<T: ?Sized> AsStaticRef<T> for &'static T {
unsafe fn as_static_ref(&self) -> &'static T {
self
}
}
impl<T> StaticWrap<T> {
pub fn new(wrapping: T) -> Self {
StaticWrap {
wrapped: Box::leak(Box::new(RefCell::new(wrapping)))
}
}
pub fn borrow(&self) -> StaticRef<'static,T> {
unsafe {
StaticRef {
r: match (&*self.wrapped).try_borrow() {
Ok(b) => b,
#[cfg(not(feature="panic_unwind"))]
Err(_e) => {
avr_oxide::oserror::halt(avr_oxide::oserror::OsError::StaticBorrow);
}
#[cfg(feature="panic_unwind")]
Err(e) => {
panic!(e);
}
}
}
}
}
pub fn borrow_mut(&mut self) -> StaticRefMut<'static, T> {
unsafe {
StaticRefMut {
rm: match (&mut *self.wrapped).try_borrow_mut() {
Ok(b) => b,
#[cfg(not(feature="panic_unwind"))]
Err(_e) => {
avr_oxide::oserror::halt(avr_oxide::oserror::OsError::StaticBorrow);
}
#[cfg(feature="panic_unwind")]
Err(e) => {
panic!(e);
}
}
}
}
}
}
impl<'sr,T: ?Sized + 'sr> Deref for StaticRef<'sr, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.r
}
}
impl<'sr,T: ?Sized + 'sr> Deref for StaticRefMut<'sr, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.rm
}
}
impl<'sr,T: ?Sized + 'sr> DerefMut for StaticRefMut<'sr, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.rm
}
}
impl<'sr,T: ?Sized + 'sr> StaticRef<'sr, T> {
pub unsafe fn static_ref(&self) -> &'static T {
core::mem::transmute(self.deref())
}
pub fn clone(orig: &Self) -> Self {
StaticRef {
r: Ref::clone(&orig.r)
}
}
}
impl<'sr,T: ?Sized + 'sr> StaticRefMut<'sr, T> {
pub unsafe fn static_ref(&self) -> &'static T {
core::mem::transmute(self.deref())
}
pub unsafe fn static_ref_mut(&mut self) -> &'static mut T {
core::mem::transmute(self.deref_mut())
}
}
#[cfg(feature="runtime_checks")]
impl<T> Drop for StaticWrap<T> {
fn drop(&mut self) {
#[cfg(not(test))]
avr_oxide::oserror::halt(avr_oxide::oserror::OsError::StaticDropped);
#[cfg(test)]
println!("((StaticWrap dropped - only allowed in testing))");
}
}
unsafe impl<'sr,T: ?Sized + Send + 'sr> Send for StaticRef<'sr,T> {}
unsafe impl<'sr,T: ?Sized + Sync + 'sr> Sync for StaticRef<'sr,T> {}
unsafe impl<'sr,T: ?Sized + Send + 'sr> Send for StaticRefMut<'sr,T> {}
unsafe impl<'sr,T: ?Sized + Sync + 'sr> Sync for StaticRefMut<'sr,T> {}
#[cfg(test)]
mod tests {
use avr_oxide::StaticWrap;
#[test]
fn test_multiple_borrows() {
let thing = StaticWrap::new(0x123);
let borrow_one = thing.borrow();
let borrow_two = thing.borrow();
}
#[test]
#[should_panic]
fn test_no_mut_with_immut() {
let mut thing = StaticWrap::new(0x123);
let borrow_one = thing.borrow();
let borrow_two = thing.borrow_mut();
}
}