use std::collections::HashMap;
use super::{LiquidityScope, SolverPoolHandle};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum ExclusiveAccess {
#[default]
Denied,
Granted,
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct OrderClass {
exclusive_access: ExclusiveAccess,
}
impl OrderClass {
pub(crate) fn new(exclusive_access: ExclusiveAccess) -> Self {
Self { exclusive_access }
}
}
impl SolverPoolHandle {
pub(crate) fn serves(&self, class: OrderClass) -> bool {
match self.liquidity_scope() {
LiquidityScope::PublicOnly => true,
LiquidityScope::IncludeExclusive => class.exclusive_access == ExclusiveAccess::Granted,
}
}
}
pub(crate) struct Allocation<'a> {
worker_pools: Vec<&'a SolverPoolHandle>,
scopes: HashMap<String, LiquidityScope>,
exclusive_routing_active: bool,
}
impl<'a> Allocation<'a> {
pub(crate) fn worker_pools(&self) -> &[&'a SolverPoolHandle] {
&self.worker_pools
}
pub(crate) fn scopes(&self) -> &HashMap<String, LiquidityScope> {
&self.scopes
}
pub(crate) fn exclusive_routing_active(&self) -> bool {
self.exclusive_routing_active
}
pub(crate) fn is_exclusive(&self, worker_pool_name: &str) -> bool {
self.scopes.get(worker_pool_name) == Some(&LiquidityScope::IncludeExclusive)
}
pub(crate) fn is_empty(&self) -> bool {
self.worker_pools.is_empty()
}
}
pub(crate) fn allocate(worker_pools: &[SolverPoolHandle], class: OrderClass) -> Allocation<'_> {
let worker_pools: Vec<&SolverPoolHandle> = worker_pools
.iter()
.filter(|worker_pool| worker_pool.serves(class))
.collect();
let scopes: HashMap<String, LiquidityScope> = worker_pools
.iter()
.map(|worker_pool| (worker_pool.name().to_string(), worker_pool.liquidity_scope()))
.collect();
let exclusive_routing_active = scopes
.values()
.any(|scope| *scope == LiquidityScope::IncludeExclusive);
Allocation { worker_pools, scopes, exclusive_routing_active }
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
use crate::worker_pool::TaskQueueHandle;
#[rstest]
#[case::public_scope_denied(LiquidityScope::PublicOnly, ExclusiveAccess::Denied, true)]
#[case::public_scope_granted(LiquidityScope::PublicOnly, ExclusiveAccess::Granted, true)]
#[case::exclusive_scope_denied(
LiquidityScope::IncludeExclusive,
ExclusiveAccess::Denied,
false
)]
#[case::exclusive_scope_granted(
LiquidityScope::IncludeExclusive,
ExclusiveAccess::Granted,
true
)]
fn test_serves(
#[case] scope: LiquidityScope,
#[case] access: ExclusiveAccess,
#[case] expected: bool,
) {
let (tx, _rx) = async_channel::bounded(1);
let worker_pool = SolverPoolHandle::new("worker_pool", TaskQueueHandle::from_sender(tx))
.with_liquidity_scope(scope);
assert_eq!(worker_pool.serves(OrderClass::new(access)), expected);
}
}