use std::collections::{HashMap, HashSet, VecDeque};
use std::hash::Hash as StdHash;
use std::marker::PhantomData;
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Debug)]
pub struct Orderer<T> {
_marker: PhantomData<T>,
}
impl<T> Orderer<T>
where
T: PartialEq + Eq + StdHash,
{
pub fn init() -> OrdererState<T> {
OrdererState {
ready: HashSet::new(),
ready_queue: VecDeque::new(),
pending: HashMap::new(),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct OrdererState<T>
where
T: PartialEq + Eq + StdHash,
{
ready: HashSet<T>,
ready_queue: VecDeque<T>,
pending: HashMap<T, HashSet<(T, Vec<T>)>>,
}
impl<T> Orderer<T>
where
T: Copy + Clone + PartialEq + Eq + StdHash,
{
pub fn mark_ready(
mut y: OrdererState<T>,
key: T,
) -> Result<(OrdererState<T>, bool), OrdererError> {
let result = y.ready.insert(key);
if result {
y.ready_queue.push_back(key);
}
Ok((y, result))
}
pub fn mark_pending(
mut y: OrdererState<T>,
key: T,
dependencies: Vec<T>,
) -> Result<(OrdererState<T>, bool), OrdererError> {
let insert_occured = false;
for dep_key in &dependencies {
if y.ready.contains(dep_key) {
continue;
}
let dependents = y.pending.entry(*dep_key).or_default();
dependents.insert((key, dependencies.clone()));
}
Ok((y, insert_occured))
}
#[allow(clippy::type_complexity)]
pub fn get_next_pending(
y: &OrdererState<T>,
key: T,
) -> Result<Option<HashSet<(T, Vec<T>)>>, OrdererError> {
Ok(y.pending.get(&key).cloned())
}
pub fn take_next_ready(
mut y: OrdererState<T>,
) -> Result<(OrdererState<T>, Option<T>), OrdererError> {
let result = y.ready_queue.pop_front();
Ok((y, result))
}
pub fn remove_pending(
mut y: OrdererState<T>,
key: T,
) -> Result<(OrdererState<T>, bool), OrdererError> {
let result = y.pending.remove(&key).is_some();
Ok((y, result))
}
pub fn ready(y: &OrdererState<T>, dependencies: &[T]) -> Result<bool, OrdererError> {
let deps_set = HashSet::from_iter(dependencies.iter().cloned());
let result = y.ready.is_superset(&deps_set);
Ok(result)
}
pub fn process_pending(y: OrdererState<T>, key: T) -> Result<OrdererState<T>, OrdererError> {
let Some(dependents) = Self::get_next_pending(&y, key)? else {
return Ok(y);
};
let mut y_loop = y;
for (next_key, next_deps) in dependents {
if !Self::ready(&y_loop, &next_deps)? {
continue;
}
let (y_next, _) = Self::mark_ready(y_loop, next_key)?;
y_loop = y_next;
let y_next = Self::process_pending(y_loop, next_key)?;
y_loop = y_next;
}
let (y_i, _) = Self::remove_pending(y_loop, key)?;
Ok(y_i)
}
}
#[derive(Debug, Error)]
pub enum OrdererError {
}