Skip to main content

hyperi_rustlib/spool/
config.rs

1// Project:   hyperi-rustlib
2// File:      src/spool/config.rs
3// Purpose:   Spool configuration
4// Language:  Rust
5//
6// License:   BUSL-1.1
7// Copyright: (c) 2026 HYPERI PTY LIMITED
8
9//! Spool configuration.
10
11use serde::{Deserialize, Serialize};
12use std::path::PathBuf;
13
14/// Configuration for the disk-backed spool.
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct SpoolConfig {
17    /// Path to the queue file.
18    pub path: PathBuf,
19
20    /// Enable zstd compression. Trades CPU for disk. Default false.
21    #[serde(default)]
22    pub compress: bool,
23
24    /// Zstd level (1-22, higher = smaller/slower). Default 3.
25    #[serde(default = "default_compression_level")]
26    pub compression_level: i32,
27
28    /// Item-count cap. `push` fails when reached. Default unlimited.
29    #[serde(default)]
30    pub max_items: Option<usize>,
31
32    /// Queue file size cap in bytes. `push` fails when reached. Default unlimited.
33    #[serde(default)]
34    pub max_size_bytes: Option<u64>,
35}
36
37fn default_compression_level() -> i32 {
38    3
39}
40
41impl Default for SpoolConfig {
42    fn default() -> Self {
43        Self {
44            path: PathBuf::from("spool.queue"),
45            compress: false,
46            compression_level: default_compression_level(),
47            max_items: None,
48            max_size_bytes: None,
49        }
50    }
51}
52
53impl SpoolConfig {
54    /// Create a new config with the given path.
55    #[must_use]
56    pub fn new(path: impl Into<PathBuf>) -> Self {
57        Self {
58            path: path.into(),
59            ..Default::default()
60        }
61    }
62
63    /// Create a config with compression enabled.
64    #[must_use]
65    pub fn with_compression(path: impl Into<PathBuf>) -> Self {
66        Self {
67            path: path.into(),
68            compress: true,
69            ..Default::default()
70        }
71    }
72
73    /// Set whether compression is enabled.
74    #[must_use]
75    pub fn compress(mut self, enabled: bool) -> Self {
76        self.compress = enabled;
77        self
78    }
79
80    /// Set the compression level (1-22).
81    #[must_use]
82    pub fn compression_level(mut self, level: i32) -> Self {
83        self.compression_level = level.clamp(1, 22);
84        self
85    }
86
87    /// Set the maximum number of items.
88    #[must_use]
89    pub fn max_items(mut self, max: usize) -> Self {
90        self.max_items = Some(max);
91        self
92    }
93
94    /// Set the maximum queue file size in bytes.
95    #[must_use]
96    pub fn max_size_bytes(mut self, max: u64) -> Self {
97        self.max_size_bytes = Some(max);
98        self
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    #[test]
107    fn test_default_config() {
108        let config = SpoolConfig::default();
109        assert_eq!(config.path, PathBuf::from("spool.queue"));
110        assert!(!config.compress);
111        assert_eq!(config.compression_level, 3);
112        assert!(config.max_items.is_none());
113        assert!(config.max_size_bytes.is_none());
114    }
115
116    #[test]
117    fn test_new_with_path() {
118        let config = SpoolConfig::new("/tmp/test.queue");
119        assert_eq!(config.path, PathBuf::from("/tmp/test.queue"));
120    }
121
122    #[test]
123    fn test_with_compression() {
124        let config = SpoolConfig::with_compression("/tmp/test.queue");
125        assert!(config.compress);
126    }
127
128    #[test]
129    fn test_builder_pattern() {
130        let config = SpoolConfig::new("/tmp/test.queue")
131            .compress(true)
132            .compression_level(10)
133            .max_items(1000)
134            .max_size_bytes(1024 * 1024);
135
136        assert!(config.compress);
137        assert_eq!(config.compression_level, 10);
138        assert_eq!(config.max_items, Some(1000));
139        assert_eq!(config.max_size_bytes, Some(1024 * 1024));
140    }
141
142    #[test]
143    fn test_compression_level_clamped() {
144        let config = SpoolConfig::default().compression_level(100);
145        assert_eq!(config.compression_level, 22);
146
147        let config = SpoolConfig::default().compression_level(-5);
148        assert_eq!(config.compression_level, 1);
149    }
150}