#![allow(warnings)]
use crate::rt::object::Object;
use crate::rt::{self, Access, Synchronize};
use std::sync::atomic::Ordering::{Acquire, Release};
#[derive(Debug, Copy, Clone)]
pub(crate) struct Arc {
obj: Object,
}
#[derive(Debug)]
pub(super) struct State {
ref_cnt: usize,
synchronize: Synchronize,
last_ref_inc: Option<Access>,
last_ref_dec: Option<Access>,
}
#[derive(Debug, Copy, Clone)]
pub(super) enum Action {
RefInc,
RefDec,
}
impl Arc {
pub(crate) fn new() -> Arc {
rt::execution(|execution| {
let obj = execution.objects.insert_arc(State {
ref_cnt: 1,
synchronize: Synchronize::new(execution.max_threads),
last_ref_inc: None,
last_ref_dec: None,
});
Arc { obj }
})
}
pub(crate) fn ref_inc(self) {
self.obj.branch(Action::RefInc);
rt::execution(|execution| {
let state = self.obj.arc_mut(&mut execution.objects);
state.ref_cnt = state.ref_cnt.checked_add(1).expect("overflow");
})
}
pub(crate) fn get_mut(self) -> bool {
self.obj.branch(Action::RefDec);
rt::execution(|execution| {
let state = self.obj.arc_mut(&mut execution.objects);
assert!(state.ref_cnt >= 1, "Arc is released");
state.synchronize.sync_load(&mut execution.threads, Acquire);
if state.ref_cnt == 1 {
true
} else {
false
}
})
}
pub(crate) fn ref_dec(self) -> bool {
self.obj.branch(Action::RefDec);
rt::execution(|execution| {
let state = self.obj.arc_mut(&mut execution.objects);
assert!(state.ref_cnt >= 1, "Arc is already released");
state.ref_cnt -= 1;
state
.synchronize
.sync_store(&mut execution.threads, Release);
if state.ref_cnt == 0 {
state.synchronize.sync_load(&mut execution.threads, Acquire);
true
} else {
false
}
})
}
}
impl State {
pub(super) fn check_for_leaks(&self) {
assert_eq!(0, self.ref_cnt, "Arc leaked");
}
pub(super) fn last_dependent_accesses<'a>(
&'a self,
action: Action,
) -> Box<dyn Iterator<Item = &'a Access> + 'a> {
match action {
Action::RefInc => Box::new([].into_iter()),
Action::RefDec => Box::new(self.last_ref_dec.iter()),
}
}
pub(super) fn set_last_access(&mut self, action: Action, access: Access) {
match action {
Action::RefInc => self.last_ref_inc = Some(access),
Action::RefDec => self.last_ref_dec = Some(access),
}
}
}