1use crate::error::TimerError;
7use std::time::Duration;
8
9#[derive(Debug, Clone)]
34pub struct WheelConfig {
35 pub l0_tick_duration: Duration,
38 pub l0_slot_count: usize,
41
42 pub l1_tick_duration: Duration,
45 pub l1_slot_count: usize,
48}
49
50impl Default for WheelConfig {
51 fn default() -> Self {
52 Self {
53 l0_tick_duration: Duration::from_millis(10),
54 l0_slot_count: 512,
55 l1_tick_duration: Duration::from_secs(1),
56 l1_slot_count: 64,
57 }
58 }
59}
60
61impl WheelConfig {
62 pub fn builder() -> WheelConfigBuilder {
64 WheelConfigBuilder::default()
65 }
66}
67
68#[derive(Debug, Clone)]
70pub struct WheelConfigBuilder {
71 l0_tick_duration: Duration,
72 l0_slot_count: usize,
73 l1_tick_duration: Duration,
74 l1_slot_count: usize,
75}
76
77impl Default for WheelConfigBuilder {
78 fn default() -> Self {
79 Self {
80 l0_tick_duration: Duration::from_millis(10),
81 l0_slot_count: 512,
82 l1_tick_duration: Duration::from_secs(1),
83 l1_slot_count: 64,
84 }
85 }
86}
87
88impl WheelConfigBuilder {
89 pub fn l0_tick_duration(mut self, duration: Duration) -> Self {
91 self.l0_tick_duration = duration;
92 self
93 }
94
95 pub fn l0_slot_count(mut self, count: usize) -> Self {
97 self.l0_slot_count = count;
98 self
99 }
100
101 pub fn l1_tick_duration(mut self, duration: Duration) -> Self {
103 self.l1_tick_duration = duration;
104 self
105 }
106
107 pub fn l1_slot_count(mut self, count: usize) -> Self {
109 self.l1_slot_count = count;
110 self
111 }
112
113 pub fn build(self) -> Result<WheelConfig, TimerError> {
134 if self.l0_tick_duration.is_zero() {
136 return Err(TimerError::InvalidConfiguration {
137 field: "l0_tick_duration".to_string(),
138 reason: "L0 层 tick 时长必须大于 0".to_string(),
139 });
140 }
141
142 if self.l0_slot_count == 0 {
143 return Err(TimerError::InvalidSlotCount {
144 slot_count: self.l0_slot_count,
145 reason: "L0 层槽位数量必须大于 0",
146 });
147 }
148
149 if !self.l0_slot_count.is_power_of_two() {
150 return Err(TimerError::InvalidSlotCount {
151 slot_count: self.l0_slot_count,
152 reason: "L0 层槽位数量必须是 2 的幂次方",
153 });
154 }
155
156 if self.l1_tick_duration.is_zero() {
158 return Err(TimerError::InvalidConfiguration {
159 field: "l1_tick_duration".to_string(),
160 reason: "L1 层 tick 时长必须大于 0".to_string(),
161 });
162 }
163
164 if self.l1_slot_count == 0 {
165 return Err(TimerError::InvalidSlotCount {
166 slot_count: self.l1_slot_count,
167 reason: "L1 层槽位数量必须大于 0",
168 });
169 }
170
171 if !self.l1_slot_count.is_power_of_two() {
172 return Err(TimerError::InvalidSlotCount {
173 slot_count: self.l1_slot_count,
174 reason: "L1 层槽位数量必须是 2 的幂次方",
175 });
176 }
177
178 let l0_ms = self.l0_tick_duration.as_millis() as u64;
180 let l1_ms = self.l1_tick_duration.as_millis() as u64;
181 if l1_ms % l0_ms != 0 {
182 return Err(TimerError::InvalidConfiguration {
183 field: "l1_tick_duration".to_string(),
184 reason: format!(
185 "L1 tick 时长 ({} ms) 必须是 L0 tick 时长 ({} ms) 的整数倍",
186 l1_ms, l0_ms
187 ),
188 });
189 }
190
191 Ok(WheelConfig {
192 l0_tick_duration: self.l0_tick_duration,
193 l0_slot_count: self.l0_slot_count,
194 l1_tick_duration: self.l1_tick_duration,
195 l1_slot_count: self.l1_slot_count,
196 })
197 }
198}
199
200#[derive(Debug, Clone)]
220pub struct ServiceConfig {
221 pub command_channel_capacity: usize,
223 pub timeout_channel_capacity: usize,
225}
226
227impl Default for ServiceConfig {
228 fn default() -> Self {
229 Self {
230 command_channel_capacity: 512,
231 timeout_channel_capacity: 1000,
232 }
233 }
234}
235
236impl ServiceConfig {
237 pub fn builder() -> ServiceConfigBuilder {
239 ServiceConfigBuilder::default()
240 }
241}
242
243#[derive(Debug, Clone)]
245pub struct ServiceConfigBuilder {
246 command_channel_capacity: usize,
247 timeout_channel_capacity: usize,
248}
249
250impl Default for ServiceConfigBuilder {
251 fn default() -> Self {
252 let config = ServiceConfig::default();
253 Self {
254 command_channel_capacity: config.command_channel_capacity,
255 timeout_channel_capacity: config.timeout_channel_capacity,
256 }
257 }
258}
259
260impl ServiceConfigBuilder {
261 pub fn command_channel_capacity(mut self, capacity: usize) -> Self {
263 self.command_channel_capacity = capacity;
264 self
265 }
266
267 pub fn timeout_channel_capacity(mut self, capacity: usize) -> Self {
269 self.timeout_channel_capacity = capacity;
270 self
271 }
272
273 pub fn build(self) -> Result<ServiceConfig, TimerError> {
286 if self.command_channel_capacity == 0 {
287 return Err(TimerError::InvalidConfiguration {
288 field: "command_channel_capacity".to_string(),
289 reason: "命令通道容量必须大于 0".to_string(),
290 });
291 }
292
293 if self.timeout_channel_capacity == 0 {
294 return Err(TimerError::InvalidConfiguration {
295 field: "timeout_channel_capacity".to_string(),
296 reason: "超时通道容量必须大于 0".to_string(),
297 });
298 }
299
300 Ok(ServiceConfig {
301 command_channel_capacity: self.command_channel_capacity,
302 timeout_channel_capacity: self.timeout_channel_capacity,
303 })
304 }
305}
306
307#[derive(Debug, Clone)]
325pub struct BatchConfig {
326 pub small_batch_threshold: usize,
332}
333
334impl Default for BatchConfig {
335 fn default() -> Self {
336 Self {
337 small_batch_threshold: 10,
338 }
339 }
340}
341
342#[derive(Debug, Clone)]
362pub struct TimerConfig {
363 pub wheel: WheelConfig,
365 pub service: ServiceConfig,
367 pub batch: BatchConfig,
369}
370
371impl Default for TimerConfig {
372 fn default() -> Self {
373 Self {
374 wheel: WheelConfig::default(),
375 service: ServiceConfig::default(),
376 batch: BatchConfig::default(),
377 }
378 }
379}
380
381impl TimerConfig {
382 pub fn builder() -> TimerConfigBuilder {
384 TimerConfigBuilder::default()
385 }
386}
387
388#[derive(Debug)]
390pub struct TimerConfigBuilder {
391 wheel_builder: WheelConfigBuilder,
392 service_builder: ServiceConfigBuilder,
393 batch_config: BatchConfig,
394}
395
396impl Default for TimerConfigBuilder {
397 fn default() -> Self {
398 Self {
399 wheel_builder: WheelConfigBuilder::default(),
400 service_builder: ServiceConfigBuilder::default(),
401 batch_config: BatchConfig::default(),
402 }
403 }
404}
405
406impl TimerConfigBuilder {
407 pub fn command_channel_capacity(mut self, capacity: usize) -> Self {
409 self.service_builder = self.service_builder.command_channel_capacity(capacity);
410 self
411 }
412
413 pub fn timeout_channel_capacity(mut self, capacity: usize) -> Self {
415 self.service_builder = self.service_builder.timeout_channel_capacity(capacity);
416 self
417 }
418
419 pub fn small_batch_threshold(mut self, threshold: usize) -> Self {
421 self.batch_config.small_batch_threshold = threshold;
422 self
423 }
424
425 pub fn build(self) -> Result<TimerConfig, TimerError> {
434 Ok(TimerConfig {
435 wheel: self.wheel_builder.build()?,
436 service: self.service_builder.build()?,
437 batch: self.batch_config,
438 })
439 }
440}
441
442#[cfg(test)]
443mod tests {
444 use super::*;
445
446 #[test]
447 fn test_wheel_config_default() {
448 let config = WheelConfig::default();
449 assert_eq!(config.l0_tick_duration, Duration::from_millis(10));
450 assert_eq!(config.l0_slot_count, 512);
451 assert_eq!(config.l1_tick_duration, Duration::from_secs(1));
452 assert_eq!(config.l1_slot_count, 64);
453 }
454
455 #[test]
456 fn test_wheel_config_builder() {
457 let config = WheelConfig::builder()
458 .l0_tick_duration(Duration::from_millis(20))
459 .l0_slot_count(1024)
460 .l1_tick_duration(Duration::from_secs(2))
461 .l1_slot_count(128)
462 .build()
463 .unwrap();
464
465 assert_eq!(config.l0_tick_duration, Duration::from_millis(20));
466 assert_eq!(config.l0_slot_count, 1024);
467 assert_eq!(config.l1_tick_duration, Duration::from_secs(2));
468 assert_eq!(config.l1_slot_count, 128);
469 }
470
471 #[test]
472 fn test_wheel_config_validation_zero_tick() {
473 let result = WheelConfig::builder()
474 .l0_tick_duration(Duration::ZERO)
475 .build();
476
477 assert!(result.is_err());
478 }
479
480 #[test]
481 fn test_wheel_config_validation_invalid_slot_count() {
482 let result = WheelConfig::builder()
483 .l0_slot_count(100)
484 .build();
485
486 assert!(result.is_err());
487 }
488
489 #[test]
490 fn test_service_config_default() {
491 let config = ServiceConfig::default();
492 assert_eq!(config.command_channel_capacity, 512);
493 assert_eq!(config.timeout_channel_capacity, 1000);
494 }
495
496 #[test]
497 fn test_service_config_builder() {
498 let config = ServiceConfig::builder()
499 .command_channel_capacity(1024)
500 .timeout_channel_capacity(2000)
501 .build()
502 .unwrap();
503
504 assert_eq!(config.command_channel_capacity, 1024);
505 assert_eq!(config.timeout_channel_capacity, 2000);
506 }
507
508 #[test]
509 fn test_batch_config_default() {
510 let config = BatchConfig::default();
511 assert_eq!(config.small_batch_threshold, 10);
512 }
513
514 #[test]
515 fn test_timer_config_default() {
516 let config = TimerConfig::default();
517 assert_eq!(config.wheel.l0_slot_count, 512);
518 assert_eq!(config.service.command_channel_capacity, 512);
519 assert_eq!(config.batch.small_batch_threshold, 10);
520 }
521
522 #[test]
523 fn test_timer_config_builder() {
524 let config = TimerConfig::builder()
525 .command_channel_capacity(1024)
526 .timeout_channel_capacity(2000)
527 .small_batch_threshold(20)
528 .build()
529 .unwrap();
530
531 assert_eq!(config.service.command_channel_capacity, 1024);
532 assert_eq!(config.service.timeout_channel_capacity, 2000);
533 assert_eq!(config.batch.small_batch_threshold, 20);
534 }
535}
536