Skip to content

Instantly share code, notes, and snippets.

@shadowmint
Created February 26, 2018 09:12
Show Gist options
  • Save shadowmint/a07efff191db93530b68af096d63f3b2 to your computer and use it in GitHub Desktop.
Save shadowmint/a07efff191db93530b68af096d63f3b2 to your computer and use it in GitHub Desktop.
BackRef reference?
use std::sync::Arc;
#[derive(PartialEq)]
enum SafePtrState {
Pending,
Resolved,
}
struct SafePtrData {
s1: SafePtrState,
s2: SafePtrState,
}
pub struct SafePtr {
lock: Arc<Box<SafePtrData>>,
owned_global_ref: *const SafePtrState,
}
impl SafePtr {
pub fn new() -> (SafePtr, SafePtr) {
let data = Box::new(SafePtrData {
s1: SafePtrState::Pending,
s2: SafePtrState::Pending,
});
let rs1 = &data.s1 as *const SafePtrState;
let rs2 = &data.s1 as *const SafePtrState;
let arc1 = Arc::new(data);
let arc2 = arc1.clone();
let p1 = SafePtr {
lock: arc1,
owned_global_ref: rs1,
};
let p2 = SafePtr {
lock: arc2,
owned_global_ref: rs1,
};
return (p1, p2);
}
/// This is safe because the state of owned_global_ref is valid on creation,
/// and the only way to modify it is with resolve(), which consumes the instance.
pub fn is_resolved(&self) -> bool {
unsafe {
let shared_ref = self.lock.as_ref();
return shared_ref.s1 == SafePtrState::Resolved || shared_ref.s2 == SafePtrState::Resolved;
}
}
/// This is safe because it is the only way for any object to modify the reference.
/// The only other time mark_resolved() is called is in Drop, which cannot be hit if we are in this scope.
pub fn resolve(mut self) {
unsafe {
self.mark_resolved()
}
}
unsafe fn mark_resolved(&mut self) {
let owned_global_mut = &mut (*(self.owned_global_ref as *mut SafePtrState));
*owned_global_mut = SafePtrState::Resolved;
}
}
impl Drop for SafePtr {
fn drop(&mut self) {
if !self.is_resolved() {
unsafe {
self.mark_resolved()
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment