use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use slab::Slab;
use super::common::InternalMoc;
static STORE: RwLock<Slab<(u8, InternalMoc)>> = RwLock::new(Slab::new());
fn exec_on_readonly_store<R, F>(op: F) -> Result<R, String>
where
F: FnOnce(RwLockReadGuard<'_, Slab<(u8, InternalMoc)>>) -> Result<R, String>,
{
STORE
.read()
.map_err(|e| format!("Read lock poisoned: {}", e))
.and_then(op)
}
fn exec_on_readwrite_store<R, F>(op: F) -> Result<R, String>
where
F: FnOnce(RwLockWriteGuard<'_, Slab<(u8, InternalMoc)>>) -> Result<R, String>,
{
STORE
.write()
.map_err(|e| format!("Write lock poisoned: {}", e))
.and_then(op)
}
pub(crate) fn exec_on_one_readonly_moc<T, F>(index: usize, op: F) -> Result<T, String>
where
F: FnOnce(&InternalMoc) -> Result<T, String>,
{
exec_on_readonly_store(|store| {
store
.get(index)
.ok_or_else(|| format!("MOC at index '{}' not found", index))
.and_then(|(_, moc)| op(moc))
})
}
pub(crate) fn exec_on_one_readwrite_moc<T, F>(index: usize, op: F) -> Result<T, String>
where
F: FnOnce(&mut InternalMoc) -> Result<T, String>,
{
exec_on_readwrite_store(|mut store| {
store
.get_mut(index)
.ok_or_else(|| format!("MOC at index '{}' not found", index))
.and_then(|(_, moc)| op(moc))
})
}
pub(crate) fn exec_on_two_readonly_mocs<T, F>(il: usize, ir: usize, op: F) -> Result<T, String>
where
F: Fn(&InternalMoc, &InternalMoc) -> Result<T, String>,
{
exec_on_readonly_store(|store| {
let (_, l) = store
.get(il)
.ok_or_else(|| format!("MOC at index '{}' not found", il))?;
let (_, r) = store
.get(ir)
.ok_or_else(|| format!("MOC at index '{}' not found", ir))?;
op(l, r)
})
}
fn exec_on_n_readonly_mocs<T, F>(indices: &[usize], op: F) -> Result<T, String>
where
F: Fn(Vec<&InternalMoc>) -> Result<T, String>,
{
exec_on_readonly_store(|store| {
let mocs: Vec<&InternalMoc> = indices
.iter()
.cloned()
.map(|i| {
store
.get(i)
.map(|(_, moc)| moc)
.ok_or_else(|| format!("MOC at index '{}' not found", i))
})
.collect::<Result<_, _>>()?;
op(mocs)
})
}
pub(crate) fn add<T: Into<InternalMoc>>(moc: T) -> Result<usize, String> {
exec_on_readwrite_store(|mut store| Ok(store.insert((1, moc.into()))))
}
pub(crate) fn copy_moc(index: usize) -> Result<(), String> {
exec_on_readwrite_store(|mut store| {
store
.get_mut(index)
.ok_or_else(|| format!("MOC at index '{}' not found", index))
.and_then(|entry| {
if entry.0 == 255 {
Err(String::from(
"Unable to copy MOC: 255 copies already reached",
))
} else {
entry.0 += 1;
Ok(())
}
})
})
}
pub(crate) fn drop(index: usize) -> Result<Option<InternalMoc>, String> {
exec_on_readwrite_store(move |mut store| {
let count = store
.get_mut(index)
.map(|entry| {
entry.0 -= 1;
entry.0
})
.ok_or_else(|| format!("MOC at index '{}' not found", index))?;
Ok(if count == 0 {
let moc = store.remove(index).1;
Some(moc)
} else {
None
})
})
}
pub(crate) fn op1<F>(index: usize, op: F) -> Result<usize, String>
where
F: Fn(&InternalMoc) -> Result<InternalMoc, String>,
{
let moc = exec_on_one_readonly_moc(index, op)?;
add(moc)
}
pub(crate) fn op1_multi_res<F>(index: usize, op: F) -> Result<Vec<usize>, String>
where
F: Fn(&InternalMoc) -> Result<Vec<InternalMoc>, String>,
{
let mut mocs = exec_on_one_readonly_moc(index, op)?;
exec_on_readwrite_store(move |mut store| {
Ok(
mocs
.drain(..)
.map(move |moc| store.insert((1, moc)))
.collect(),
)
})
}
pub(crate) fn op2<F>(left_index: usize, right_index: usize, op: F) -> Result<usize, String>
where
F: Fn(&InternalMoc, &InternalMoc) -> Result<InternalMoc, String>,
{
let moc = exec_on_two_readonly_mocs(left_index, right_index, op)?;
add(moc)
}
pub(crate) fn opn<F>(indices: &[usize], op: F) -> Result<usize, String>
where
F: Fn(Vec<&InternalMoc>) -> Result<InternalMoc, String>,
{
let moc = exec_on_n_readonly_mocs(indices, op)?;
add(moc)
}