1use crate::util::impl_fmt_with;
2
3macro_rules! impl_fixed_point_number {
4 (
5 $(#[$outer:meta])*
6 $vis:vis struct $Name:ident(
7 $int:ty as [u8; $bytes:literal];
8 $integer_bits:literal | $fraction_bits:literal as $fp:ty, $wide:ty
9 );
10 DENOM = $denom:literal;
11 STEP = $step:literal;
12 MIN = $min:literal;
13 MAX = $max:literal;
14 ) => {
15 #[doc = concat!("The [OpenType ", stringify!($Name), "][spec] type, a")]
16 #[doc = concat!($integer_bits, ".", $fraction_bits, "-bit signed fixed-point type.")]
17 $(#[$outer])*
20 #[derive(Copy, Hash)]
21 #[derive_const(Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
22 #[repr(transparent)]
23 $vis struct $Name($int);
24
25 const _: () = {
26 assert!(size_of::<$int>() == $bytes);
27 assert!($integer_bits + $fraction_bits == <$int>::BITS);
28 };
29
30 impl $Name {
31 const F_STEP: $fp = 1.0 / (1 << $fraction_bits) as $fp;
32 const F_MIN: $fp = -(1 << ($integer_bits - 1)) as $fp;
33 const F_MAX_EXCLUSIVE: $fp = (1 << ($integer_bits - 1)) as $fp;
34
35 #[doc = concat!("The difference between adjacent [`", stringify!($Name), "`] values.")]
36 #[doc = concat!("# use ttf_view::types::", stringify!($Name), ";")]
41 #[doc = concat!("assert_eq!(", stringify!($Name), "::STEP, ", $step, ");")]
42 pub const STEP: Self = Self(1);
44
45 #[doc = concat!("# use ttf_view::types::", stringify!($Name), ";")]
51 #[doc = concat!("assert_eq!(", stringify!($Name), "::MIN, ", $min, ");")]
52 pub const MIN: Self = Self(<$int>::MIN);
54 #[doc = concat!("# use ttf_view::types::", stringify!($Name), ";")]
60 #[doc = concat!("assert_eq!(", stringify!($Name), "::MAX, ", $max, ");")]
61 pub const MAX: Self = Self(<$int>::MAX);
63
64 #[doc = concat!("# use ttf_view::types::", stringify!($Name), ";")]
70 #[doc = concat!("assert_eq!(", stringify!($Name), "::ZERO, 0.0);")]
71 pub const ZERO: Self = Self::new(0.0).unwrap();
73 #[doc = concat!("# use ttf_view::types::", stringify!($Name), ";")]
79 #[doc = concat!("assert_eq!(", stringify!($Name), "::ONE, 1.0);")]
80 pub const ONE: Self = Self::new(1.0).unwrap();
82
83 #[doc = concat!("# use ttf_view::types::", stringify!($Name), ";")]
89 #[doc = concat!("assert_eq!(", stringify!($Name), "::DENOM, ", $denom, ");")]
90 pub const DENOM: $int = Self::ONE.0;
92
93 #[doc = concat!("Creates a [`", stringify!($Name), "`] from [`", stringify!($fp), "`],")]
94 #[doc = concat!("returning `None` if the value is out of `", stringify!($Name), "`'s range.")]
95 #[doc = concat!("use ttf_view::types::", stringify!($Name), ";")]
100 #[doc = concat!("assert_eq!(", stringify!($Name), "::new(-0.125).unwrap(), -0.125);")]
102 #[doc = concat!("assert_eq!(", stringify!($Name), "::new(1.99609375).unwrap(), 1.99609375);")]
103 #[doc = concat!("assert_eq!(", stringify!($Name), "::new(-34000.0), None);")]
104 #[doc = concat!("assert_eq!(", stringify!($Name), "::new(34000.0), None);")]
105 #[doc = concat!("assert_eq!(", stringify!($Name), "::new(", stringify!($fp), "::NAN), None);")]
106 #[doc = concat!("// numbers are rounded towards the closest value representable by ", stringify!($Name))]
108 #[doc = concat!("assert_eq!(", stringify!($Name), "::new(0.5156247).unwrap(), 0.515625);")]
109 #[doc = concat!("assert_eq!(", stringify!($Name), "::new(0.5156250).unwrap(), 0.515625);")]
110 #[doc = concat!("assert_eq!(", stringify!($Name), "::new(0.5156254).unwrap(), 0.515625);")]
111 pub const fn new(num: $fp) -> Option<Self> {
113 if matches!(num, Self::F_MIN..Self::F_MAX_EXCLUSIVE) {
114 Some(Self::new_saturating(num))
115 } else {
116 None
117 }
118 }
119 #[doc = concat!("Creates a [`", stringify!($Name), "`] from [`", stringify!($fp), "`],")]
120 #[doc = concat!("use ttf_view::types::", stringify!($Name), ";")]
126 #[doc = concat!("assert_eq!(", stringify!($Name), "::new_saturating(-0.125), -0.125);")]
128 #[doc = concat!("assert_eq!(", stringify!($Name), "::new_saturating(1.99609375), 1.99609375);")]
129 #[doc = concat!("assert_eq!(", stringify!($Name), "::new_saturating(-34000.0), ", $min, ");")]
130 #[doc = concat!("assert_eq!(", stringify!($Name), "::new_saturating(34000.0), ", $max, ");")]
131 #[doc = concat!("assert_eq!(", stringify!($Name), "::new_saturating(", stringify!($fp), "::NAN), 0.0);")]
132 #[doc = concat!("// numbers are rounded towards the closest value representable by ", stringify!($Name))]
134 #[doc = concat!("assert_eq!(", stringify!($Name), "::new_saturating(0.5156247), 0.515625);")]
135 #[doc = concat!("assert_eq!(", stringify!($Name), "::new_saturating(0.5156250), 0.515625);")]
136 #[doc = concat!("assert_eq!(", stringify!($Name), "::new_saturating(0.5156254), 0.515625);")]
137 pub const fn new_saturating(num: $fp) -> Self {
139 Self((num / Self::F_STEP).round() as $int)
142 }
143
144 #[doc = concat!("Creates a [`", stringify!($Name), "`] from big-endian bytes.")]
145 pub const fn from_be_bytes(bytes: [u8; $bytes]) -> Self {
146 Self(<$int>::from_be_bytes(bytes))
147 }
148 #[doc = concat!("Gets this [`", stringify!($Name), "`]'s big-endian bytes.")]
149 pub const fn to_be_bytes(self) -> [u8; $bytes] {
150 self.0.to_be_bytes()
151 }
152
153 #[doc = concat!("Creates a [`", stringify!($Name), "`] from its integer fraction's numerator")]
154 #[doc = concat!("(`", stringify!($Name), "` represented as <span class=\"hidden\">`numerator/", $denom, "`</span><math><mfrac><mi>numerator</mi><mn>", $denom, "</mn></mfrac></math>).")]
155 pub const fn from_frac_num(numerator: $int) -> Self {
156 Self(numerator)
157 }
158 #[doc = concat!("Returns this [`", stringify!($Name), "`]'s integer fraction's numerator")]
159 #[doc = concat!("(`", stringify!($Name), "` represented as <span class=\"hidden\">`numerator/", $denom, "`</span><math><mfrac><mi>numerator</mi><mn>", $denom, "</mn></mfrac></math>).")]
160 pub const fn frac_num(self) -> $int {
161 self.0
162 }
163
164 #[doc = concat!("Returns this [`", stringify!($Name), "`]'s value as [`", stringify!($fp), "`].")]
165 pub const fn get(self) -> $fp {
166 self.frac_num() as $fp * Self::F_STEP
167 }
168
169 pub(crate) const fn wmul(self, rhs: Self) -> $wide {
174 self.0.widening_mul(rhs.0)
175 }
176
177 pub const fn wrapping_neg(self) -> Self {
178 Self(self.0.wrapping_neg())
179 }
180 pub const fn wrapping_add(self, rhs: Self) -> Self {
181 Self(self.0.wrapping_add(rhs.0))
182 }
183 pub const fn wrapping_sub(self, rhs: Self) -> Self {
184 Self(self.0.wrapping_sub(rhs.0))
185 }
186 pub const fn wrapping_mul(self, rhs: Self) -> Self {
187 Self((self.wmul(rhs) / $denom) as $int)
188 }
189 pub const fn wrapping_div(self, rhs: Self) -> Self {
193 Self((self.wmul(Self::ONE) / rhs.0 as $wide) as $int)
194 }
195 pub const fn wrapping_rem(self, rhs: Self) -> Self {
199 Self(self.0.wrapping_rem(rhs.0))
200 }
201
202 pub const fn saturating_neg(self) -> Self {
203 Self(self.0.saturating_neg())
204 }
205 pub const fn saturating_add(self, rhs: Self) -> Self {
206 Self(self.0.saturating_add(rhs.0))
207 }
208 pub const fn saturating_sub(self, rhs: Self) -> Self {
209 Self(self.0.saturating_sub(rhs.0))
210 }
211 pub const fn saturating_mul(self, rhs: Self) -> Self {
212 Self((self.wmul(rhs) / $denom).saturating_cast())
213 }
214 pub const fn saturating_div(self, rhs: Self) -> Self {
218 Self((self.wmul(Self::ONE) / rhs.0 as $wide).saturating_cast())
219 }
220
221 pub const fn checked_neg(self) -> Option<Self> {
222 self.0.checked_neg().map(Self)
223 }
224 pub const fn checked_add(self, rhs: Self) -> Option<Self> {
225 self.0.checked_add(rhs.0).map(Self)
226 }
227 pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
228 self.0.checked_sub(rhs.0).map(Self)
229 }
230 pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
231 (self.wmul(rhs) / $denom).checked_cast().map(Self)
232 }
233 pub const fn checked_div(self, rhs: Self) -> Option<Self> {
234 (self.wmul(Self::ONE).checked_div(rhs.0 as $wide)?).checked_cast().map(Self)
235 }
236 pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
237 self.0.checked_rem(rhs.0).map(Self)
238 }
239
240 pub(crate) const fn wrapping_maddp(a: Self, b: Self, c: Self, d: Self, p: Self) -> Self {
242 let sum = a.wmul(b).wrapping_add(c.wmul(d)) / $denom;
243 Self(sum.wrapping_add(p.0 as $wide) as $int)
244 }
245 pub(crate) const fn saturating_maddp(a: Self, b: Self, c: Self, d: Self, p: Self) -> Self {
247 let sum = a.wmul(b).saturating_add(c.wmul(d)) / $denom;
248 Self(sum.saturating_add(p.0 as $wide).saturating_cast())
249 }
250 pub(crate) const fn checked_maddp(a: Self, b: Self, c: Self, d: Self, p: Self) -> Option<Self> {
252 let sum = a.wmul(b).checked_add(c.wmul(d))? / $denom;
253 Some(Self(sum.checked_add(p.0 as $wide)?.try_into().ok()?))
254 }
255 }
256
257 const impl std::ops::Neg for $Name {
259 type Output = Self;
260 fn neg(self) -> Self::Output {
261 #[cfg(debug_assertions)]
262 { self.checked_neg().expect("attempt to negate with overflow") }
263 #[cfg(not(debug_assertions))]
264 { self.wrapping_neg() }
265 }
266 }
267 const impl std::ops::Add for $Name {
269 type Output = Self;
270 fn add(self, rhs: Self) -> Self::Output {
271 #[cfg(debug_assertions)]
272 { self.checked_add(rhs).expect("attempt to add with overflow") }
273 #[cfg(not(debug_assertions))]
274 { self.wrapping_add(rhs) }
275 }
276 }
277 const impl std::ops::Sub for $Name {
279 type Output = Self;
280 fn sub(self, rhs: Self) -> Self::Output {
281 #[cfg(debug_assertions)]
282 { self.checked_sub(rhs).expect("attempt to subtract with overflow") }
283 #[cfg(not(debug_assertions))]
284 { self.wrapping_sub(rhs) }
285 }
286 }
287 const impl std::ops::Mul for $Name {
289 type Output = Self;
290 fn mul(self, rhs: Self) -> Self::Output {
291 #[cfg(debug_assertions)]
292 { self.checked_mul(rhs).expect("attempt to multiply with overflow") }
293 #[cfg(not(debug_assertions))]
294 { self.wrapping_mul(rhs) }
295 }
296 }
297 const impl std::ops::Div for $Name {
303 type Output = Self;
304 fn div(self, rhs: Self) -> Self::Output {
305 #[cfg(debug_assertions)]
306 { self.checked_div(rhs).expect("attempt to divide by zero or with overflow") }
307 #[cfg(not(debug_assertions))]
308 { self.wrapping_div(rhs) }
309 }
310 }
311 const impl std::ops::Rem for $Name {
317 type Output = Self;
318 fn rem(self, rhs: Self) -> Self::Output {
319 #[cfg(debug_assertions)]
320 { self.checked_rem(rhs).expect("attempt to calculate the remainder with a divisor of zero or with overflow") }
321 #[cfg(not(debug_assertions))]
322 { self.wrapping_rem(rhs) }
323 }
324 }
325
326 impl_fmt_with! { Debug, Display, LowerExp, UpperExp: |x: &$Name| x.get() }
327 impl_fmt_with! { Binary, LowerHex, UpperHex: |x: &$Name| x.0 }
328
329 const impl PartialEq<$fp> for $Name {
330 fn eq(&self, other: &$fp) -> bool {
331 self.get().eq(other)
332 }
333 }
334 const impl PartialOrd<$fp> for $Name {
335 fn partial_cmp(&self, other: &$fp) -> Option<std::cmp::Ordering> {
336 self.get().partial_cmp(other)
337 }
338 }
339
340 const impl std::ops::Mul<$fp> for $Name {
341 type Output = $fp;
342 fn mul(self, other: $fp) -> Self::Output {
343 self.get().mul(other)
344 }
345 }
346 const impl std::ops::Div<$fp> for $Name {
347 type Output = $fp;
348 fn div(self, other: $fp) -> Self::Output {
349 self.get().div(other)
350 }
351 }
352
353 impl std::str::FromStr for $Name {
354 type Err = ();
355 fn from_str(s: &str) -> Result<Self, Self::Err> {
356 <$fp>::from_str(s).or(Err(())).and_then(Self::try_from)
357 }
358 }
359 const impl TryFrom<$fp> for $Name {
360 type Error = ();
361 fn try_from(value: $fp) -> Result<Self, Self::Error> {
362 Self::new(value).ok_or(())
363 }
364 }
365 const impl From<$Name> for $fp {
366 fn from(value: $Name) -> Self {
367 value.get()
368 }
369 }
370 }
371}
372
373impl_fixed_point_number! {
375 pub struct Fixed(i32 as [u8; 4]; 16|16 as f64, i64);
376 DENOM = 65536;
377 STEP = 0.0000152587890625;
378 MIN = -32768.0;
379 MAX = 32767.99998474121;
380}
381impl_fixed_point_number! {
382 pub struct F2Dot14(i16 as [u8; 2]; 2|14 as f32, i32);
383 DENOM = 16384;
384 STEP = 0.000061035156;
385 MIN = -2.0;
386 MAX = 1.999939;
387}
388
389#[cfg(test)]
390mod tests {
391 use super::*;
392
393 #[test]
394 fn fixed() {
395 assert_eq!(Fixed::new(32767.999999999996), Some(Fixed::MAX));
397 assert_eq!(Fixed::new(32768.0), None);
398 assert_eq!(Fixed::new(-32768.0), Some(Fixed::MIN));
399 assert_eq!(Fixed::new(-32768.00000000001), None);
400
401 let nums: [(u32, f64); _] = [
403 (0x7FFF_FFFF, 32767.999985),
404 (0x7FFF_FF00, 32767.996094),
405 (0x7FFF_2000, 32767.125000),
406 (0x7FFF_0000, 32767.000000),
407 (0x0040_0100, 64.003906),
408 (0x0040_0000, 64.000000),
409 (0x0001_0000, 1.000000),
410 (0x0000_0001, 0.000015),
411 (0x0000_0000, 0.000000),
412 (0xFFFF_0000, -1.000000),
413 (0xFFBF_FF00, -64.003906),
414 (0x8000_0000, -32768.000000),
415 ];
416
417 for (raw, fp) in nums {
418 let real = Fixed::new(fp).unwrap();
419 assert_eq!(real.0 as u32, raw, "{real:#X} != {raw:#X} ({fp})");
420
421 let diff = (real.get() - fp).abs();
422 assert!(diff <= 0.1 * Fixed::F_STEP, "{real} != {fp} (Δ={diff})");
423 }
424 }
425
426 #[test]
427 fn f2dot14() {
428 assert_eq!(F2Dot14::new(1.9999999), Some(F2Dot14::MAX));
430 assert_eq!(F2Dot14::new(2.0), None);
431 assert_eq!(F2Dot14::new(-2.0), Some(F2Dot14::MIN));
432 assert_eq!(F2Dot14::new(-2.0000002), None);
433
434 let nums: [(u16, f32); _] = [
436 (0x7FFF, 1.999939),
437 (0x7000, 1.750000),
438 (0x0085, 0.008118),
439 (0x0002, 0.000122),
440 (0x0001, 0.000061),
441 (0x0000, 0.000000),
442 (0xFFFF, -0.000061),
443 (0xFFFE, -0.000122),
444 (0xFF7B, -0.008118),
445 (0x8000, -2.000000),
446 ];
447
448 for (raw, fp) in nums {
449 let real = F2Dot14::new(fp).unwrap();
450 assert_eq!(real.0 as u16, raw, "{real:#X} != {raw:#X} ({fp})");
451
452 let diff = (real.get() - fp).abs();
453 assert!(diff <= 0.1 * F2Dot14::F_STEP, "{real} != {fp} (Δ={diff})");
454 }
455 }
456}