use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RouterType {
LimitOrder,
V2,
V3,
}
impl RouterType {
pub const fn all() -> [RouterType; 3] {
[RouterType::LimitOrder, RouterType::V2, RouterType::V3]
}
pub const fn swap_routers() -> [RouterType; 2] {
[RouterType::V2, RouterType::V3]
}
pub const fn order_routers() -> [RouterType; 1] {
[RouterType::LimitOrder]
}
pub const fn emits_swap_events(&self) -> bool {
matches!(self, RouterType::V2 | RouterType::V3)
}
pub const fn emits_order_events(&self) -> bool {
matches!(self, RouterType::LimitOrder)
}
pub const fn as_str(&self) -> &'static str {
match self {
RouterType::LimitOrder => "LO",
RouterType::V2 => "V2",
RouterType::V3 => "V3",
}
}
}
impl fmt::Display for RouterType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RouterAvailability {
pub limit_order: bool,
pub v2: bool,
pub v3: bool,
}
impl RouterAvailability {
pub const fn all() -> Self {
Self {
limit_order: true,
v2: true,
v3: true,
}
}
pub const fn none() -> Self {
Self {
limit_order: false,
v2: false,
v3: false,
}
}
pub const fn lo_v3_only() -> Self {
Self {
limit_order: true,
v2: false,
v3: true,
}
}
pub const fn v2_v3_only() -> Self {
Self {
limit_order: false,
v2: true,
v3: true,
}
}
pub const fn has(&self, router_type: RouterType) -> bool {
match router_type {
RouterType::LimitOrder => self.limit_order,
RouterType::V2 => self.v2,
RouterType::V3 => self.v3,
}
}
pub fn available_routers(&self) -> Vec<RouterType> {
let mut routers = Vec::new();
if self.limit_order {
routers.push(RouterType::LimitOrder);
}
if self.v2 {
routers.push(RouterType::V2);
}
if self.v3 {
routers.push(RouterType::V3);
}
routers
}
pub const fn count(&self) -> usize {
let mut count = 0;
if self.limit_order {
count += 1;
}
if self.v2 {
count += 1;
}
if self.v3 {
count += 1;
}
count
}
pub const fn has_any(&self) -> bool {
self.limit_order || self.v2 || self.v3
}
}
impl fmt::Display for RouterAvailability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let routers = self.available_routers();
if routers.is_empty() {
write!(f, "No routers available")
} else {
write!(
f,
"{}",
routers
.iter()
.map(|r| r.as_str())
.collect::<Vec<_>>()
.join(", ")
)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_router_type_all() {
let all = RouterType::all();
assert_eq!(all.len(), 3);
assert!(all.contains(&RouterType::LimitOrder));
assert!(all.contains(&RouterType::V2));
assert!(all.contains(&RouterType::V3));
}
#[test]
fn test_router_type_display() {
assert_eq!(RouterType::LimitOrder.to_string(), "LO");
assert_eq!(RouterType::V2.to_string(), "V2");
assert_eq!(RouterType::V3.to_string(), "V3");
}
#[test]
fn test_router_availability_all() {
let avail = RouterAvailability::all();
assert!(avail.limit_order);
assert!(avail.v2);
assert!(avail.v3);
assert_eq!(avail.count(), 3);
}
#[test]
fn test_router_availability_none() {
let avail = RouterAvailability::none();
assert!(!avail.limit_order);
assert!(!avail.v2);
assert!(!avail.v3);
assert_eq!(avail.count(), 0);
assert!(!avail.has_any());
}
#[test]
fn test_router_availability_lo_v3_only() {
let avail = RouterAvailability::lo_v3_only();
assert!(avail.limit_order);
assert!(!avail.v2);
assert!(avail.v3);
assert_eq!(avail.count(), 2);
assert!(avail.has(RouterType::LimitOrder));
assert!(!avail.has(RouterType::V2));
assert!(avail.has(RouterType::V3));
}
#[test]
fn test_router_availability_v2_v3_only() {
let avail = RouterAvailability::v2_v3_only();
assert!(!avail.limit_order);
assert!(avail.v2);
assert!(avail.v3);
assert_eq!(avail.count(), 2);
}
#[test]
fn test_available_routers() {
let avail = RouterAvailability::all();
let routers = avail.available_routers();
assert_eq!(routers.len(), 3);
let avail = RouterAvailability::lo_v3_only();
let routers = avail.available_routers();
assert_eq!(routers.len(), 2);
assert!(routers.contains(&RouterType::LimitOrder));
assert!(routers.contains(&RouterType::V3));
}
#[test]
fn test_display() {
let avail = RouterAvailability::all();
assert_eq!(avail.to_string(), "LO, V2, V3");
let avail = RouterAvailability::lo_v3_only();
assert_eq!(avail.to_string(), "LO, V3");
let avail = RouterAvailability::none();
assert_eq!(avail.to_string(), "No routers available");
}
#[test]
fn test_swap_routers() {
let swap = RouterType::swap_routers();
assert_eq!(swap.len(), 2);
assert!(swap.contains(&RouterType::V2));
assert!(swap.contains(&RouterType::V3));
assert!(!swap.contains(&RouterType::LimitOrder));
}
#[test]
fn test_order_routers() {
let order = RouterType::order_routers();
assert_eq!(order.len(), 1);
assert!(order.contains(&RouterType::LimitOrder));
assert!(!order.contains(&RouterType::V2));
assert!(!order.contains(&RouterType::V3));
}
#[test]
fn test_emits_swap_events() {
assert!(RouterType::V2.emits_swap_events());
assert!(RouterType::V3.emits_swap_events());
assert!(!RouterType::LimitOrder.emits_swap_events());
}
#[test]
fn test_emits_order_events() {
assert!(RouterType::LimitOrder.emits_order_events());
assert!(!RouterType::V2.emits_order_events());
assert!(!RouterType::V3.emits_order_events());
}
#[test]
fn test_swap_and_order_routers_are_exhaustive() {
let all: std::collections::HashSet<_> = RouterType::all().into_iter().collect();
let swap: std::collections::HashSet<_> = RouterType::swap_routers().into_iter().collect();
let order: std::collections::HashSet<_> = RouterType::order_routers().into_iter().collect();
let combined: std::collections::HashSet<_> = swap.union(&order).copied().collect();
assert_eq!(all, combined);
assert!(swap.is_disjoint(&order));
}
}