use std::time::Duration;
use serde::Deserialize;
use super::{BoundedQueue, QueueOverflowPolicy};
#[derive(Debug, Clone, Deserialize)]
pub struct QueueConfig {
#[serde(default = "default_capacity")]
pub capacity: usize,
#[serde(default)]
pub overflow_policy: OverflowPolicyConfig,
}
fn default_capacity() -> usize {
super::bounded::DEFAULT_QUEUE_CAPACITY
}
impl Default for QueueConfig {
fn default() -> Self {
Self {
capacity: default_capacity(),
overflow_policy: OverflowPolicyConfig::default(),
}
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
#[derive(Default)]
pub enum OverflowPolicyConfig {
#[default]
DropOldest,
DropNewest,
Block {
#[serde(default = "default_timeout_ms")]
timeout_ms: u64,
},
}
fn default_timeout_ms() -> u64 {
100
}
impl From<OverflowPolicyConfig> for QueueOverflowPolicy {
fn from(config: OverflowPolicyConfig) -> Self {
match config {
OverflowPolicyConfig::DropOldest => QueueOverflowPolicy::DropOldest,
OverflowPolicyConfig::DropNewest => QueueOverflowPolicy::DropNewest,
OverflowPolicyConfig::Block { timeout_ms } => QueueOverflowPolicy::Block {
timeout: Duration::from_millis(timeout_ms),
},
}
}
}
impl QueueConfig {
#[must_use]
pub fn into_queue(self) -> BoundedQueue {
BoundedQueue::with_policy(self.capacity, self.overflow_policy.into())
}
pub fn from_toml(toml_str: &str) -> Result<Self, toml::de::Error> {
toml::from_str(toml_str)
}
}
impl BoundedQueue {
#[must_use]
pub fn from_config(config: &QueueConfig) -> Self {
BoundedQueue::with_policy(config.capacity, config.overflow_policy.clone().into())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = QueueConfig::default();
assert_eq!(config.capacity, 1000);
assert!(matches!(
config.overflow_policy,
OverflowPolicyConfig::DropOldest
));
}
#[test]
fn test_parse_drop_oldest() {
let toml = r#"
capacity = 500
[overflow_policy]
type = "drop_oldest"
"#;
let config: QueueConfig = toml::from_str(toml).unwrap();
assert_eq!(config.capacity, 500);
assert!(matches!(
config.overflow_policy,
OverflowPolicyConfig::DropOldest
));
}
#[test]
fn test_parse_drop_newest() {
let toml = r#"
capacity = 200
[overflow_policy]
type = "drop_newest"
"#;
let config: QueueConfig = toml::from_str(toml).unwrap();
assert_eq!(config.capacity, 200);
assert!(matches!(
config.overflow_policy,
OverflowPolicyConfig::DropNewest
));
}
#[test]
fn test_parse_block() {
let toml = r#"
capacity = 100
[overflow_policy]
type = "block"
timeout_ms = 250
"#;
let config: QueueConfig = toml::from_str(toml).unwrap();
assert_eq!(config.capacity, 100);
match config.overflow_policy {
OverflowPolicyConfig::Block { timeout_ms } => {
assert_eq!(timeout_ms, 250);
}
_ => panic!("Expected Block policy"),
}
}
#[test]
fn test_into_queue() {
let config = QueueConfig {
capacity: 50,
overflow_policy: OverflowPolicyConfig::DropNewest,
};
let queue = config.into_queue();
assert_eq!(queue.capacity(), 50);
assert!(matches!(queue.policy(), QueueOverflowPolicy::DropNewest));
}
#[test]
fn test_policy_conversion() {
let policy: QueueOverflowPolicy = OverflowPolicyConfig::DropOldest.into();
assert!(matches!(policy, QueueOverflowPolicy::DropOldest));
let policy: QueueOverflowPolicy = OverflowPolicyConfig::DropNewest.into();
assert!(matches!(policy, QueueOverflowPolicy::DropNewest));
let policy: QueueOverflowPolicy = OverflowPolicyConfig::Block { timeout_ms: 100 }.into();
assert!(matches!(policy, QueueOverflowPolicy::Block { .. }));
assert_eq!(policy.timeout(), Some(Duration::from_millis(100)));
}
}