1use crate::error::TimerError;
7use std::time::Duration;
8
9#[derive(Debug, Clone)]
35pub struct WheelConfig {
36 pub l0_tick_duration: Duration,
40
41 pub l0_slot_count: usize,
45
46 pub l1_tick_duration: Duration,
50
51 pub l1_slot_count: usize,
55}
56
57impl Default for WheelConfig {
58 fn default() -> Self {
59 Self {
60 l0_tick_duration: Duration::from_millis(10),
61 l0_slot_count: 512,
62 l1_tick_duration: Duration::from_secs(1),
63 l1_slot_count: 64,
64 }
65 }
66}
67
68impl WheelConfig {
69 pub fn builder() -> WheelConfigBuilder {
71 WheelConfigBuilder::default()
72 }
73}
74
75#[derive(Debug, Clone)]
77pub struct WheelConfigBuilder {
78 l0_tick_duration: Duration,
79 l0_slot_count: usize,
80 l1_tick_duration: Duration,
81 l1_slot_count: usize,
82}
83
84impl Default for WheelConfigBuilder {
85 fn default() -> Self {
86 Self {
87 l0_tick_duration: Duration::from_millis(10),
88 l0_slot_count: 512,
89 l1_tick_duration: Duration::from_secs(1),
90 l1_slot_count: 64,
91 }
92 }
93}
94
95impl WheelConfigBuilder {
96 pub fn l0_tick_duration(mut self, duration: Duration) -> Self {
98 self.l0_tick_duration = duration;
99 self
100 }
101
102 pub fn l0_slot_count(mut self, count: usize) -> Self {
104 self.l0_slot_count = count;
105 self
106 }
107
108 pub fn l1_tick_duration(mut self, duration: Duration) -> Self {
110 self.l1_tick_duration = duration;
111 self
112 }
113
114 pub fn l1_slot_count(mut self, count: usize) -> Self {
116 self.l1_slot_count = count;
117 self
118 }
119
120 pub fn build(self) -> Result<WheelConfig, TimerError> {
133 if self.l0_tick_duration.is_zero() {
135 return Err(TimerError::InvalidConfiguration {
136 field: "l0_tick_duration".to_string(),
137 reason: "L0 layer tick duration must be greater than 0".to_string(),
138 });
139 }
140
141 if self.l0_slot_count == 0 {
142 return Err(TimerError::InvalidSlotCount {
143 slot_count: self.l0_slot_count,
144 reason: "L0 layer slot count must be greater than 0",
145 });
146 }
147
148 if !self.l0_slot_count.is_power_of_two() {
149 return Err(TimerError::InvalidSlotCount {
150 slot_count: self.l0_slot_count,
151 reason: "L0 layer slot count must be power of 2",
152 });
153 }
154
155 if self.l1_tick_duration.is_zero() {
157 return Err(TimerError::InvalidConfiguration {
158 field: "l1_tick_duration".to_string(),
159 reason: "L1 layer tick duration must be greater than 0".to_string(),
160 });
161 }
162
163 if self.l1_slot_count == 0 {
164 return Err(TimerError::InvalidSlotCount {
165 slot_count: self.l1_slot_count,
166 reason: "L1 layer slot count must be greater than 0",
167 });
168 }
169
170 if !self.l1_slot_count.is_power_of_two() {
171 return Err(TimerError::InvalidSlotCount {
172 slot_count: self.l1_slot_count,
173 reason: "L1 layer slot count must be power of 2",
174 });
175 }
176
177 let l0_ms = self.l0_tick_duration.as_millis() as u64;
179 let l1_ms = self.l1_tick_duration.as_millis() as u64;
180 if l1_ms % l0_ms != 0 {
181 return Err(TimerError::InvalidConfiguration {
182 field: "l1_tick_duration".to_string(),
183 reason: format!(
184 "L1 tick duration ({} ms) must be an integer multiple of L0 tick duration ({} ms)",
185 l1_ms, l0_ms
186 ),
187 });
188 }
189
190 Ok(WheelConfig {
191 l0_tick_duration: self.l0_tick_duration,
192 l0_slot_count: self.l0_slot_count,
193 l1_tick_duration: self.l1_tick_duration,
194 l1_slot_count: self.l1_slot_count,
195 })
196 }
197}
198
199#[derive(Debug, Clone)]
222pub struct ServiceConfig {
223 pub command_channel_capacity: usize,
227
228 pub timeout_channel_capacity: usize,
232}
233
234impl Default for ServiceConfig {
235 fn default() -> Self {
236 Self {
237 command_channel_capacity: 512,
238 timeout_channel_capacity: 1000,
239 }
240 }
241}
242
243impl ServiceConfig {
244 pub fn builder() -> ServiceConfigBuilder {
246 ServiceConfigBuilder::default()
247 }
248}
249
250#[derive(Debug, Clone)]
254pub struct ServiceConfigBuilder {
255 pub command_channel_capacity: usize,
259
260 pub timeout_channel_capacity: usize,
264}
265
266impl Default for ServiceConfigBuilder {
267 fn default() -> Self {
268 let config = ServiceConfig::default();
269 Self {
270 command_channel_capacity: config.command_channel_capacity,
271 timeout_channel_capacity: config.timeout_channel_capacity,
272 }
273 }
274}
275
276impl ServiceConfigBuilder {
277 pub fn command_channel_capacity(mut self, capacity: usize) -> Self {
279 self.command_channel_capacity = capacity;
280 self
281 }
282
283 pub fn timeout_channel_capacity(mut self, capacity: usize) -> Self {
285 self.timeout_channel_capacity = capacity;
286 self
287 }
288
289 pub fn build(self) -> Result<ServiceConfig, TimerError> {
308 if self.command_channel_capacity == 0 {
309 return Err(TimerError::InvalidConfiguration {
310 field: "command_channel_capacity".to_string(),
311 reason: "Command channel capacity must be greater than 0 (命令通道容量必须大于 0)".to_string(),
312 });
313 }
314
315 if self.timeout_channel_capacity == 0 {
316 return Err(TimerError::InvalidConfiguration {
317 field: "timeout_channel_capacity".to_string(),
318 reason: "Timeout channel capacity must be greater than 0 (超时通道容量必须大于 0)".to_string(),
319 });
320 }
321
322 Ok(ServiceConfig {
323 command_channel_capacity: self.command_channel_capacity,
324 timeout_channel_capacity: self.timeout_channel_capacity,
325 })
326 }
327}
328
329#[derive(Debug, Clone)]
352pub struct BatchConfig {
353 pub small_batch_threshold: usize,
360}
361
362impl Default for BatchConfig {
363 fn default() -> Self {
364 Self {
365 small_batch_threshold: 10,
366 }
367 }
368}
369
370#[derive(Debug, Clone)]
394pub struct TimerConfig {
395 pub wheel: WheelConfig,
397 pub service: ServiceConfig,
399 pub batch: BatchConfig,
401}
402
403impl Default for TimerConfig {
404 fn default() -> Self {
405 Self {
406 wheel: WheelConfig::default(),
407 service: ServiceConfig::default(),
408 batch: BatchConfig::default(),
409 }
410 }
411}
412
413impl TimerConfig {
414 pub fn builder() -> TimerConfigBuilder {
416 TimerConfigBuilder::default()
417 }
418}
419
420#[derive(Debug)]
424pub struct TimerConfigBuilder {
425 wheel_builder: WheelConfigBuilder,
426 service_builder: ServiceConfigBuilder,
427 batch_config: BatchConfig,
428}
429
430impl Default for TimerConfigBuilder {
431 fn default() -> Self {
432 Self {
433 wheel_builder: WheelConfigBuilder::default(),
434 service_builder: ServiceConfigBuilder::default(),
435 batch_config: BatchConfig::default(),
436 }
437 }
438}
439
440impl TimerConfigBuilder {
441 pub fn command_channel_capacity(mut self, capacity: usize) -> Self {
443 self.service_builder = self.service_builder.command_channel_capacity(capacity);
444 self
445 }
446
447 pub fn timeout_channel_capacity(mut self, capacity: usize) -> Self {
449 self.service_builder = self.service_builder.timeout_channel_capacity(capacity);
450 self
451 }
452
453 pub fn small_batch_threshold(mut self, threshold: usize) -> Self {
455 self.batch_config.small_batch_threshold = threshold;
456 self
457 }
458
459 pub fn build(self) -> Result<TimerConfig, TimerError> {
472 Ok(TimerConfig {
473 wheel: self.wheel_builder.build()?,
474 service: self.service_builder.build()?,
475 batch: self.batch_config,
476 })
477 }
478}
479
480#[cfg(test)]
481mod tests {
482 use super::*;
483
484 #[test]
485 fn test_wheel_config_default() {
486 let config = WheelConfig::default();
487 assert_eq!(config.l0_tick_duration, Duration::from_millis(10));
488 assert_eq!(config.l0_slot_count, 512);
489 assert_eq!(config.l1_tick_duration, Duration::from_secs(1));
490 assert_eq!(config.l1_slot_count, 64);
491 }
492
493 #[test]
494 fn test_wheel_config_builder() {
495 let config = WheelConfig::builder()
496 .l0_tick_duration(Duration::from_millis(20))
497 .l0_slot_count(1024)
498 .l1_tick_duration(Duration::from_secs(2))
499 .l1_slot_count(128)
500 .build()
501 .unwrap();
502
503 assert_eq!(config.l0_tick_duration, Duration::from_millis(20));
504 assert_eq!(config.l0_slot_count, 1024);
505 assert_eq!(config.l1_tick_duration, Duration::from_secs(2));
506 assert_eq!(config.l1_slot_count, 128);
507 }
508
509 #[test]
510 fn test_wheel_config_validation_zero_tick() {
511 let result = WheelConfig::builder()
512 .l0_tick_duration(Duration::ZERO)
513 .build();
514
515 assert!(result.is_err());
516 }
517
518 #[test]
519 fn test_wheel_config_validation_invalid_slot_count() {
520 let result = WheelConfig::builder()
521 .l0_slot_count(100)
522 .build();
523
524 assert!(result.is_err());
525 }
526
527 #[test]
528 fn test_service_config_default() {
529 let config = ServiceConfig::default();
530 assert_eq!(config.command_channel_capacity, 512);
531 assert_eq!(config.timeout_channel_capacity, 1000);
532 }
533
534 #[test]
535 fn test_service_config_builder() {
536 let config = ServiceConfig::builder()
537 .command_channel_capacity(1024)
538 .timeout_channel_capacity(2000)
539 .build()
540 .unwrap();
541
542 assert_eq!(config.command_channel_capacity, 1024);
543 assert_eq!(config.timeout_channel_capacity, 2000);
544 }
545
546 #[test]
547 fn test_batch_config_default() {
548 let config = BatchConfig::default();
549 assert_eq!(config.small_batch_threshold, 10);
550 }
551
552 #[test]
553 fn test_timer_config_default() {
554 let config = TimerConfig::default();
555 assert_eq!(config.wheel.l0_slot_count, 512);
556 assert_eq!(config.service.command_channel_capacity, 512);
557 assert_eq!(config.batch.small_batch_threshold, 10);
558 }
559
560 #[test]
561 fn test_timer_config_builder() {
562 let config = TimerConfig::builder()
563 .command_channel_capacity(1024)
564 .timeout_channel_capacity(2000)
565 .small_batch_threshold(20)
566 .build()
567 .unwrap();
568
569 assert_eq!(config.service.command_channel_capacity, 1024);
570 assert_eq!(config.service.timeout_channel_capacity, 2000);
571 assert_eq!(config.batch.small_batch_threshold, 20);
572 }
573}
574