Skip to main content

sof_gossip_tuning/domain/
value_objects.rs

1//! Domain value objects for validated tuning inputs.
2
3use std::{
4    num::{NonZeroU32, NonZeroUsize},
5    time::Duration,
6};
7
8use crate::domain::error::TuningValueError;
9
10/// Typed wrapper for bounded channel capacities.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct QueueCapacity(NonZeroU32);
13
14impl QueueCapacity {
15    /// Creates a validated queue capacity.
16    ///
17    /// # Errors
18    /// Returns [`TuningValueError::ZeroCapacity`] when `value` is zero.
19    pub fn new(value: u32) -> Result<Self, TuningValueError> {
20        NonZeroU32::new(value)
21            .map(Self)
22            .ok_or(TuningValueError::ZeroCapacity)
23    }
24
25    /// Returns the raw capacity value.
26    #[must_use]
27    pub const fn get(self) -> u32 {
28        self.0.get()
29    }
30
31    /// Builds one fixed queue capacity for internal presets.
32    pub(crate) const fn fixed(value: u32) -> Self {
33        match NonZeroU32::new(value) {
34            Some(value) => Self(value),
35            None => Self(NonZeroU32::MIN),
36        }
37    }
38}
39
40/// Typed wrapper for a millisecond coalesce window.
41#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
42pub struct ReceiverCoalesceWindow(Duration);
43
44impl ReceiverCoalesceWindow {
45    /// Creates a validated coalesce window from milliseconds.
46    ///
47    /// # Errors
48    /// Returns [`TuningValueError::ZeroMillis`] when `value` is zero.
49    pub const fn from_millis(value: u64) -> Result<Self, TuningValueError> {
50        if value == 0 {
51            return Err(TuningValueError::ZeroMillis);
52        }
53        Ok(Self(Duration::from_millis(value)))
54    }
55
56    /// Returns the value in milliseconds.
57    #[must_use]
58    pub const fn as_millis_u64(self) -> u64 {
59        self.0.as_millis() as u64
60    }
61
62    /// Returns the underlying duration.
63    #[must_use]
64    pub const fn as_duration(self) -> Duration {
65        self.0
66    }
67
68    /// Builds one fixed coalesce window for internal presets.
69    pub(crate) const fn fixed(value: u64) -> Self {
70        Self(Duration::from_millis(if value == 0 { 1 } else { value }))
71    }
72}
73
74/// Typed wrapper for a CPU core index.
75#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
76pub struct CpuCoreIndex(usize);
77
78impl CpuCoreIndex {
79    /// Creates a CPU core index.
80    #[must_use]
81    pub const fn new(value: usize) -> Self {
82        Self(value)
83    }
84
85    /// Returns the raw zero-based index.
86    #[must_use]
87    pub const fn get(self) -> usize {
88        self.0
89    }
90}
91
92/// Number of TVU receive sockets to create during gossip bootstrap.
93#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
94pub struct TvuReceiveSocketCount(NonZeroUsize);
95
96impl TvuReceiveSocketCount {
97    /// Creates a validated TVU socket count.
98    ///
99    /// # Errors
100    /// Returns [`TuningValueError::ZeroSocketCount`] when `value` is zero.
101    pub fn new(value: usize) -> Result<Self, TuningValueError> {
102        NonZeroUsize::new(value)
103            .map(Self)
104            .ok_or(TuningValueError::ZeroSocketCount)
105    }
106
107    /// Returns the raw socket count.
108    #[must_use]
109    pub const fn get(self) -> usize {
110        self.0.get()
111    }
112
113    /// Builds one fixed TVU socket count for internal presets.
114    pub(crate) const fn fixed(value: usize) -> Self {
115        match NonZeroUsize::new(value) {
116            Some(value) => Self(value),
117            None => Self(NonZeroUsize::MIN),
118        }
119    }
120}