Skip to content

Instantly share code, notes, and snippets.

@shadowmint
Created February 28, 2018 09:21
Show Gist options
  • Save shadowmint/7417c6cd531817b24f218da972c42123 to your computer and use it in GitHub Desktop.
Save shadowmint/7417c6cd531817b24f218da972c42123 to your computer and use it in GitHub Desktop.
Rust observable
extern crate core;
use std::sync::atomic::AtomicBool;
use std::mem::transmute;
use std::sync::atomic::Ordering;
pub struct Observer {
hidden: Option<*const HiddenState>
}
pub struct Observable {
hidden: Option<*const HiddenState>
}
struct HiddenState {
observer: AtomicBool,
observable: AtomicBool,
}
impl Observable {
pub fn new() -> (Observer, Observable) {
let state = Box::new(HiddenState {
observable: AtomicBool::new(true),
observer: AtomicBool::new(true),
});
let raw_state: *const HiddenState;
unsafe {
// This pointer is now an indefinitely valid static reference.
raw_state = transmute(state);
}
let observer = Observer { hidden: Some(raw_state) };
let observable = Observable { hidden: Some(raw_state) };
return (observer, observable);
}
// This is safe because no other mutable references can exist of HiddenState::observable
fn atomic_state(&mut self) -> &mut AtomicBool {
unsafe {
let state_ref = self.immutable_state();
let atomic_state_ref = &state_ref.observable as *const AtomicBool;
return &mut (*(atomic_state_ref as *mut AtomicBool));
}
}
// This is safe because it returns an immutable reference
fn immutable_state(&mut self) -> &HiddenState {
unsafe {
let state_ref = &(**(self.hidden.as_ref().unwrap()));
return state_ref;
}
}
}
impl Observer {
// This is safe because no other mutable references can exist of HiddenState::observer
fn atomic_state(&mut self) -> &mut AtomicBool {
unsafe {
let state_ref = self.immutable_state();
let atomic_state_ref = &state_ref.observer as *const AtomicBool;
return &mut (*(atomic_state_ref as *mut AtomicBool));
}
}
// This is safe because it returns an immutable reference
fn immutable_state(&mut self) -> &HiddenState {
unsafe {
let state_ref = &(**(self.hidden.as_ref().unwrap()));
return state_ref;
}
}
}
impl HiddenState {
fn should_drop(&self) -> bool {
return !self.observer.fetch_or(self.observable.load(Ordering::Acquire), Ordering::Acquire);
}
}
impl Drop for Observable {
fn drop(&mut self) {
self.atomic_state().store(false, Ordering::Acquire);
if self.immutable_state().should_drop() {
unsafe {
transmute::<*const HiddenState, Box<HiddenState>>(self.hidden.take().unwrap());
}
}
}
}
impl Drop for Observer {
fn drop(&mut self) {
self.atomic_state().store(false, Ordering::Acquire);
if self.immutable_state().should_drop() {
unsafe {
transmute::<*const HiddenState, Box<HiddenState>>(self.hidden.take().unwrap());
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment