second_music_system/
posfloat.rs1use std::{
2 cmp::Ordering,
3 fmt::{Debug, Display, Formatter, Result as FmtResult},
4 hash::{Hash, Hasher},
5 num::ParseFloatError,
6 ops::{Add, Deref, Div, Mul},
7 str::FromStr,
8};
9
10use super::SpeakerLayout;
11
12#[derive(Clone, Copy, PartialEq)]
13pub struct PosFloat(f32);
19
20impl PosFloat {
21 pub const HALF: PosFloat = PosFloat(0.5);
22 pub const ZERO: PosFloat = PosFloat(0.0);
23 pub const ONE: PosFloat = PosFloat(1.0);
24 pub const THOUSAND: PosFloat = PosFloat(1000.0);
25 pub const MILLION: PosFloat = PosFloat(1000000.0);
26 pub const BILLION: PosFloat = PosFloat(1000000.0);
27 pub const SECONDS_PER_MINUTE: PosFloat = PosFloat(60.0);
28 pub const SECONDS_PER_HOUR: PosFloat = PosFloat(3600.0);
29 pub const SECONDS_PER_DAY: PosFloat = PosFloat(86400.0);
30 pub fn new(x: f32) -> Result<PosFloat, &'static str> {
32 if !x.is_finite() {
33 Err("PosFloat must be finite")
34 } else if !x.is_sign_positive() {
35 Err("PosFloat must be positive")
36 } else {
37 Ok(PosFloat(x))
38 }
39 }
40 pub const unsafe fn new_unchecked(x: f32) -> PosFloat {
47 PosFloat(x)
53 }
54 pub fn new_clamped(x: f32) -> PosFloat {
57 if x.is_finite() && x.is_sign_positive() {
58 PosFloat(x)
59 } else {
60 PosFloat::ZERO
61 }
62 }
63 pub fn seconds_to_frames(&self, sample_rate: PosFloat) -> u64 {
66 (self.0 * sample_rate.0).floor() as u64
67 }
68 pub fn seconds_to_frac_frames(&self, sample_rate: PosFloat) -> PosFloat {
71 PosFloat((self.0 * sample_rate.0).floor())
72 }
73 pub fn seconds_to_samples(
76 &self,
77 sample_rate: PosFloat,
78 speaker_layout: SpeakerLayout,
79 ) -> u64 {
80 self.seconds_to_frames(sample_rate)
81 * speaker_layout.get_num_channels() as u64
82 }
83 pub fn saturating_sub(&self, differend: PosFloat) -> PosFloat {
87 let ret = self.0 - differend.0;
88 if ret.is_sign_negative() || !ret.is_finite() {
89 PosFloat::ZERO
90 } else {
91 PosFloat(ret)
92 }
93 }
94}
95
96impl Display for PosFloat {
97 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
98 Display::fmt(&**self, f)
99 }
100}
101
102impl Debug for PosFloat {
103 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
104 Debug::fmt(&**self, f)
105 }
106}
107
108impl Eq for PosFloat {}
109
110impl PartialOrd for PosFloat {
111 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
112 Some(self.cmp(other))
113 }
114}
115
116impl Ord for PosFloat {
118 fn cmp(&self, other: &Self) -> Ordering {
119 self.0.to_bits().cmp(&other.0.to_bits())
120 }
121}
122
123impl Hash for PosFloat {
124 fn hash<H: Hasher>(&self, state: &mut H) {
125 debug_assert!(self.0.is_finite() && self.0.is_sign_positive());
126 self.0.to_bits().hash(state);
127 }
128}
129
130impl Deref for PosFloat {
131 type Target = f32;
132 fn deref(&self) -> &f32 {
133 &self.0
134 }
135}
136
137impl From<u8> for PosFloat {
138 fn from(value: u8) -> PosFloat {
139 PosFloat(value as f32)
140 }
141}
142
143impl From<u16> for PosFloat {
144 fn from(value: u16) -> PosFloat {
145 PosFloat(value as f32)
146 }
147}
148
149impl From<u32> for PosFloat {
150 fn from(value: u32) -> PosFloat {
151 PosFloat(value as f32)
152 }
153}
154
155impl From<u64> for PosFloat {
156 fn from(value: u64) -> PosFloat {
157 PosFloat(value as f32)
158 }
159}
160
161impl From<usize> for PosFloat {
162 fn from(value: usize) -> PosFloat {
163 PosFloat(value as f32)
164 }
165}
166
167pub enum TimePointFromStrError {
168 ParseFloatError(ParseFloatError),
169 NewTimePointError(&'static str),
170}
171
172impl From<ParseFloatError> for TimePointFromStrError {
173 fn from(e: ParseFloatError) -> Self {
174 Self::ParseFloatError(e)
175 }
176}
177
178impl From<&'static str> for TimePointFromStrError {
179 fn from(e: &'static str) -> Self {
180 Self::NewTimePointError(e)
181 }
182}
183
184impl FromStr for PosFloat {
185 type Err = TimePointFromStrError;
186 fn from_str(s: &str) -> Result<PosFloat, TimePointFromStrError> {
187 Ok(PosFloat::new(s.parse::<f32>()?)?)
188 }
189}
190
191impl Add<PosFloat> for PosFloat {
192 type Output = PosFloat;
193 fn add(self, rhs: PosFloat) -> PosFloat {
194 PosFloat(self.0 + rhs.0)
195 }
196}
197
198impl Div<PosFloat> for PosFloat {
199 type Output = PosFloat;
200 fn div(self, rhs: PosFloat) -> PosFloat {
201 PosFloat(self.0 / rhs.0)
202 }
203}
204
205impl Mul<PosFloat> for PosFloat {
206 type Output = PosFloat;
207 fn mul(self, rhs: PosFloat) -> PosFloat {
208 PosFloat(self.0 * rhs.0)
209 }
210}