Skip to main content

font_types/
fixed.rs

1//! fixed-point numerical types
2
3use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
4
5// shared between Fixed, F26Dot6, F2Dot14, F4Dot12, F6Dot10
6macro_rules! fixed_impl {
7    ($name:ident, $bits:literal, $fract_bits:literal, $ty:ty) => {
8        #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
9        #[cfg_attr(feature = "bytemuck", derive(bytemuck::AnyBitPattern, bytemuck::NoUninit))]
10        #[repr(transparent)]
11        #[doc = concat!(stringify!($bits), "-bit signed fixed point number with ", stringify!($fract_bits), " bits of fraction." )]
12        pub struct $name($ty);
13        impl $name {
14            /// Minimum value.
15            pub const MIN: Self = Self(<$ty>::MIN);
16
17            /// Maximum value.
18            pub const MAX: Self = Self(<$ty>::MAX);
19
20            /// This type's smallest representable value
21            pub const EPSILON: Self = Self(1);
22
23            /// Representation of 0.0.
24            pub const ZERO: Self = Self(0);
25
26            /// Representation of 1.0.
27            pub const ONE: Self = Self(1 << $fract_bits);
28
29            /// Representation of -1.0.
30            pub const NEG_ONE: Self = Self((!0 << $fract_bits) as $ty);
31
32            const INT_MASK: $ty = !0 << $fract_bits;
33            const ROUND: $ty = 1 << ($fract_bits - 1);
34            const FRACT_BITS: usize = $fract_bits;
35
36            /// Creates a new fixed point value from the underlying bit representation.
37            #[inline(always)]
38            pub const fn from_bits(bits: $ty) -> Self {
39                Self(bits)
40            }
41
42            /// Returns the underlying bit representation of the value.
43            #[inline(always)]
44            pub const fn to_bits(self) -> $ty {
45                self.0
46            }
47
48            //TODO: is this actually useful?
49            /// Returns the nearest integer value.
50            #[inline(always)]
51            pub const fn round(self) -> Self {
52                Self(self.0.wrapping_add(Self::ROUND) & Self::INT_MASK)
53            }
54
55            /// Returns the absolute value of the number.
56            #[inline(always)]
57            pub const fn abs(self) -> Self {
58                Self(self.0.wrapping_abs())
59            }
60
61            /// Returns the largest integer less than or equal to the number.
62            #[inline(always)]
63            pub const fn floor(self) -> Self {
64                Self(self.0 & Self::INT_MASK)
65            }
66
67            /// Returns the fractional part of the number.
68            #[inline(always)]
69            pub const fn fract(self) -> Self {
70                Self(self.0 - self.floor().0)
71            }
72
73            /// Wrapping addition.
74            #[inline(always)]
75            pub fn wrapping_add(self, other: Self) -> Self {
76                Self(self.0.wrapping_add(other.0))
77            }
78
79            /// Saturating addition.
80            #[inline(always)]
81            pub const fn saturating_add(self, other: Self) -> Self {
82                Self(self.0.saturating_add(other.0))
83            }
84
85            /// Checked addition.
86            #[inline(always)]
87            pub fn checked_add(self, other: Self) -> Option<Self> {
88                self.0.checked_add(other.0).map(|inner| Self(inner))
89            }
90
91            /// Wrapping substitution.
92            #[inline(always)]
93            pub const fn wrapping_sub(self, other: Self) -> Self {
94                Self(self.0.wrapping_sub(other.0))
95            }
96
97            /// Saturating substitution.
98            #[inline(always)]
99            pub const fn saturating_sub(self, other: Self) -> Self {
100                Self(self.0.saturating_sub(other.0))
101            }
102
103            /// The representation of this number as a big-endian byte array.
104            #[inline(always)]
105            pub const fn to_be_bytes(self) -> [u8; $bits / 8] {
106                self.0.to_be_bytes()
107            }
108        }
109
110        impl Add for $name {
111            type Output = Self;
112            #[inline(always)]
113            fn add(self, other: Self) -> Self {
114                Self(self.0.wrapping_add(other.0))
115            }
116        }
117
118        impl AddAssign for $name {
119            #[inline(always)]
120            fn add_assign(&mut self, other: Self) {
121                *self = *self + other;
122            }
123        }
124
125        impl Sub for $name {
126            type Output = Self;
127            #[inline(always)]
128            fn sub(self, other: Self) -> Self {
129                Self(self.0.wrapping_sub(other.0))
130            }
131        }
132
133        impl SubAssign for $name {
134            #[inline(always)]
135            fn sub_assign(&mut self, other: Self) {
136                *self = *self - other;
137            }
138        }
139
140        impl Neg for $name {
141            type Output = Self;
142            #[inline(always)]
143            fn neg(self) -> Self {
144                Self(self.0.wrapping_neg())
145            }
146        }
147    };
148}
149
150impl Fixed {
151    /// Multiplies `self` by `a` and divides the product by `b`.
152    // This one is specifically not always inlined due to size and
153    // frequency of use. We leave it to compiler discretion.
154    #[inline]
155    pub const fn mul_div(&self, a: Self, b: Self) -> Self {
156        let mut sign = 1;
157        let mut su = self.0 as u64;
158        let mut au = a.0 as u64;
159        let mut bu = b.0 as u64;
160        if self.0 < 0 {
161            su = 0u64.wrapping_sub(su);
162            sign = -1;
163        }
164        if a.0 < 0 {
165            au = 0u64.wrapping_sub(au);
166            sign = -sign;
167        }
168        if b.0 < 0 {
169            bu = 0u64.wrapping_sub(bu);
170            sign = -sign;
171        }
172        let result = if bu > 0 {
173            su.wrapping_mul(au).wrapping_add(bu >> 1) / bu
174        } else {
175            0x7FFFFFFF
176        };
177        Self(if sign < 0 {
178            (result as i32).wrapping_neg()
179        } else {
180            result as i32
181        })
182    }
183}
184
185impl Mul for Fixed {
186    type Output = Self;
187
188    #[inline(always)]
189    fn mul(self, other: Self) -> Self::Output {
190        let ab = self.0 as i64 * other.0 as i64;
191        Self(((ab + 0x8000 - i64::from(ab < 0)) >> 16) as i32)
192    }
193}
194
195impl Div for Fixed {
196    type Output = Self;
197
198    fn div(self, other: Self) -> Self {
199        let sign = (self.0 < 0) ^ (other.0 < 0);
200        let au = self.0.unsigned_abs() as u64;
201        let bu = other.0.unsigned_abs() as u64;
202        let q = if bu == 0 {
203            0x7FFFFFFF_u32
204        } else {
205            (((au << 16) + (bu >> 1)) / bu) as u32
206        };
207        Self(if sign {
208            (q as i32).wrapping_neg()
209        } else {
210            q as i32
211        })
212    }
213}
214
215impl Mul for F26Dot6 {
216    type Output = Self;
217
218    #[inline(always)]
219    fn mul(self, other: Self) -> Self::Output {
220        let ab = self.0 as i64 * other.0 as i64;
221        Self(((ab + 32 - i64::from(ab < 0)) >> 6) as i32)
222    }
223}
224
225impl Div for F26Dot6 {
226    type Output = Self;
227
228    fn div(self, other: Self) -> Self {
229        let sign = (self.0 < 0) ^ (other.0 < 0);
230        let au = self.0.unsigned_abs() as u64;
231        let bu = other.0.unsigned_abs() as u64;
232        let q = if bu == 0 {
233            0x7FFFFFFF_u32
234        } else {
235            (((au << 6) + (bu >> 1)) / bu) as u32
236        };
237        Self(if sign {
238            (q as i32).wrapping_neg()
239        } else {
240            q as i32
241        })
242    }
243}
244
245/// Implements multiplication and division assignment operators for fixed
246/// types.
247macro_rules! fixed_mul_div_assign {
248    ($ty:ty) => {
249        impl MulAssign for $ty {
250            #[inline(always)]
251            fn mul_assign(&mut self, rhs: Self) {
252                *self = *self * rhs;
253            }
254        }
255
256        impl DivAssign for $ty {
257            #[inline(always)]
258            fn div_assign(&mut self, rhs: Self) {
259                *self = *self / rhs;
260            }
261        }
262    };
263}
264
265/// impl float conversion methods.
266///
267/// We convert to different float types in order to ensure we can roundtrip
268/// without floating point error.
269macro_rules! float_conv {
270    // default invocation: we will impl Display/Default/Serialize/Deserialize
271    ($name:ident, $to:ident, $from:ident, $ty:ty) => {
272        float_conv!($name, $to, $from, $ty, no_fmt);
273
274        impl std::fmt::Display for $name {
275            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
276                if f.precision().is_some() {
277                    return std::fmt::Display::fmt(&self.$to(), f);
278                }
279                fmt_shortest(self.0 as i64, Self::FRACT_BITS as u32, f)
280            }
281        }
282
283        impl std::fmt::Debug for $name {
284            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
285                std::fmt::Display::fmt(self, f)
286            }
287        }
288
289        #[cfg(feature = "serde")]
290        impl ::serde::Serialize for $name {
291            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
292            where
293                S: ::serde::Serializer,
294            {
295                <$ty>::serialize(&$name::$to(*self), serializer)
296            }
297        }
298
299        #[cfg(feature = "serde")]
300        impl<'de> ::serde::Deserialize<'de> for $name {
301            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
302            where
303                D: ::serde::Deserializer<'de>,
304            {
305                <$ty>::deserialize(deserializer).map($name::$from)
306            }
307        }
308    };
309    // explicitly opt out of Display/Default/Serialize/Deserialize
310    // (for types that get both f32 & f64)
311    ($name:ident, $to:ident, $from:ident, $ty:ty, no_fmt) => {
312        impl $name {
313            #[doc = concat!("Creates a fixed point value from a ", stringify!($ty), ".")]
314            ///
315            /// This operation is lossy; the float will be rounded to the nearest
316            /// representable value.
317            #[inline(always)]
318            pub fn $from(x: $ty) -> Self {
319                // When x is positive: 1.0 - 0.5 =  0.5
320                // When x is negative: 0.0 - 0.5 = -0.5
321                let frac = (x.is_sign_positive() as u8 as $ty) - 0.5;
322                Self((x * Self::ONE.0 as $ty + frac) as _)
323            }
324
325            #[doc = concat!("Returns the value as an ", stringify!($ty), ".")]
326            ///
327            /// This operation is lossless: all representable values can be
328            /// round-tripped.
329            #[inline(always)]
330            pub fn $to(self) -> $ty {
331                let int = ((self.0 & Self::INT_MASK) >> Self::FRACT_BITS) as $ty;
332                let fract = (self.0 & !Self::INT_MASK) as $ty / Self::ONE.0 as $ty;
333                int + fract
334            }
335        }
336    };
337}
338
339/// Format a fixed-point value as the shortest decimal that parses back to it.
340///
341/// The value is exactly `raw / 2^fract_bits`. We pick the fewest fractional
342/// digits whose nearest decimal is strictly within half a step of it, as
343/// `fontTools`' `fixedToStr` does, and omit the decimal point for integral
344/// values. Width, fill, alignment and sign flags behave as they do for
345/// floats.
346fn fmt_shortest(raw: i64, fract_bits: u32, f: &mut std::fmt::Formatter) -> std::fmt::Result {
347    let one = 1u128 << fract_bits;
348    let magnitude = u128::from(raw.unsigned_abs());
349    for places in 0..=5 {
350        let pow = 10u128.pow(places);
351        let digits = (2 * magnitude * pow + one) / (2 * one);
352        if (digits * one).abs_diff(magnitude * pow) * 2 < pow {
353            let mut buf = [0u8; 32];
354            return f.pad_integral(raw >= 0, "", write_decimal(digits, places, &mut buf));
355        }
356    }
357    // Rounding leaves `digits * one` within `one / 2` of `magnitude * pow`,
358    // so five places always pass since `one <= 2^16 < 10^5`.
359    unreachable!()
360}
361
362/// Write `digits / 10^places` as a decimal at the end of `buf` and return it.
363fn write_decimal(mut digits: u128, places: u32, buf: &mut [u8; 32]) -> &str {
364    let mut pos = buf.len();
365    let mut written = 0;
366    while written <= places || digits != 0 {
367        if written == places && places != 0 {
368            pos -= 1;
369            buf[pos] = b'.';
370        }
371        pos -= 1;
372        buf[pos] = b'0' + (digits % 10) as u8;
373        digits /= 10;
374        written += 1;
375    }
376    std::str::from_utf8(&buf[pos..]).expect("only ASCII digits and '.'")
377}
378
379fixed_impl!(F2Dot14, 16, 14, i16);
380fixed_impl!(F4Dot12, 16, 12, i16);
381fixed_impl!(F6Dot10, 16, 10, i16);
382fixed_impl!(Fixed, 32, 16, i32);
383fixed_impl!(F26Dot6, 32, 6, i32);
384fixed_impl!(F48Dot16, 64, 16, i64);
385
386fixed_mul_div_assign!(Fixed);
387fixed_mul_div_assign!(F26Dot6);
388
389float_conv!(F2Dot14, to_f32, from_f32, f32);
390float_conv!(F4Dot12, to_f32, from_f32, f32);
391float_conv!(F6Dot10, to_f32, from_f32, f32);
392float_conv!(F48Dot16, to_f64, from_f64, f64);
393float_conv!(F2Dot14, to_f64, from_f64, f64, no_fmt);
394float_conv!(F4Dot12, to_f64, from_f64, f64, no_fmt);
395float_conv!(F6Dot10, to_f64, from_f64, f64, no_fmt);
396
397float_conv!(Fixed, to_f64, from_f64, f64);
398float_conv!(F26Dot6, to_f64, from_f64, f64);
399crate::newtype_scalar!(F2Dot14, [u8; 2]);
400crate::newtype_scalar!(F4Dot12, [u8; 2]);
401crate::newtype_scalar!(F6Dot10, [u8; 2]);
402crate::newtype_scalar!(Fixed, [u8; 4]);
403
404impl Fixed {
405    /// Creates a 16.16 fixed point value from a 32 bit integer.
406    #[inline(always)]
407    pub const fn from_i32(i: i32) -> Self {
408        Self(i << 16)
409    }
410
411    /// Converts a 16.16 fixed point value to a 32 bit integer, rounding off
412    /// the fractional bits.
413    #[inline(always)]
414    pub const fn to_i32(self) -> i32 {
415        self.0.wrapping_add(0x8000) >> 16
416    }
417
418    /// Converts a 16.16 to 26.6 fixed point value.
419    #[inline(always)]
420    pub const fn to_f26dot6(self) -> F26Dot6 {
421        F26Dot6(self.0.wrapping_add(0x200) >> 10)
422    }
423
424    /// Converts a 16.16 to 2.14 fixed point value.
425    ///
426    /// This specific conversion is defined by the spec:
427    /// <https://learn.microsoft.com/en-us/typography/opentype/spec/otvaroverview#coordinate-scales-and-normalization>
428    ///
429    /// "5. Convert the final, normalized 16.16 coordinate value to 2.14 by this method: add 0x00000002,
430    /// and sign-extend shift to the right by 2."
431    #[inline(always)]
432    pub const fn to_f2dot14(self) -> F2Dot14 {
433        F2Dot14((self.0.wrapping_add(2) >> 2) as _)
434    }
435
436    /// Converts a 16.16 fixed point value to a single precision floating
437    /// point value.
438    ///
439    /// This operation is lossy. Use `to_f64()` for a lossless conversion.
440    #[inline(always)]
441    pub fn to_f32(self) -> f32 {
442        const SCALE_FACTOR: f32 = 1.0 / 65536.0;
443        self.0 as f32 * SCALE_FACTOR
444    }
445
446    /// Converts a 16.16 to a 48.16 fixed point value.
447    ///
448    /// This conversion is exact.
449    #[inline(always)]
450    pub const fn to_f48dot16(self) -> F48Dot16 {
451        F48Dot16(self.0 as i64)
452    }
453
454    /// Applies an item variation delta, returning the varied value as a
455    /// single precision floating point number.
456    ///
457    /// A delta for a 16.16 valued target is a raw integer count of the
458    /// target's own quantum, so the accumulated 48.16 delta is scaled by
459    /// 1/65536 on application. The result is intentionally not rounded
460    /// back to 16.16.
461    #[inline(always)]
462    pub fn apply_delta(self, delta: F48Dot16) -> f32 {
463        self.to_f32() + (delta.to_f64() / 65536.0) as f32
464    }
465
466    /// Multiplies by a 32 bit integer, producing the product as a 48.16
467    /// fixed point value.
468    ///
469    /// This is the shape of variation delta accumulation: a raw integer
470    /// delta scaled by a 16.16 scalar. The arithmetic wraps rather than
471    /// panicking, following this module's style -- though the widened
472    /// product of two 32 bit values is at most 2^62 and cannot actually
473    /// wrap.
474    #[inline(always)]
475    pub const fn mul_i32(self, value: i32) -> F48Dot16 {
476        F48Dot16((self.0 as i64).wrapping_mul(value as i64))
477    }
478}
479
480impl From<i32> for Fixed {
481    fn from(value: i32) -> Self {
482        Self::from_i32(value)
483    }
484}
485
486impl F26Dot6 {
487    /// Creates a 26.6 fixed point value from a 32 bit integer.
488    #[inline(always)]
489    pub const fn from_i32(i: i32) -> Self {
490        Self(i << 6)
491    }
492
493    /// Converts a 26.6 fixed point value to a 32 bit integer, rounding off
494    /// the fractional bits.
495    #[inline(always)]
496    pub const fn to_i32(self) -> i32 {
497        self.0.wrapping_add(32) >> 6
498    }
499
500    /// Converts a 26.6 fixed point value to a single precision floating
501    /// point value.
502    ///
503    /// This operation is lossy. Use `to_f64()` for a lossless conversion.
504    #[inline(always)]
505    pub fn to_f32(self) -> f32 {
506        const SCALE_FACTOR: f32 = 1.0 / 64.0;
507        self.0 as f32 * SCALE_FACTOR
508    }
509}
510
511impl F48Dot16 {
512    /// Creates a 48.16 fixed point value from a 64 bit integer.
513    #[inline(always)]
514    pub const fn from_i64(i: i64) -> Self {
515        Self(i << 16)
516    }
517
518    /// Creates a 48.16 fixed point value from a 32 bit integer.
519    #[inline(always)]
520    pub const fn from_i32(i: i32) -> Self {
521        Self((i as i64) << 16)
522    }
523
524    /// Converts a 48.16 fixed point value to a 64 bit integer, rounding off
525    /// the fractional bits.
526    #[inline(always)]
527    pub const fn to_i64(self) -> i64 {
528        self.0.wrapping_add(0x8000) >> 16
529    }
530
531    /// Converts a 48.16 fixed point value to a 32 bit integer, rounding off
532    /// the fractional bits.
533    ///
534    /// This truncates the integral bits if the value is too large to fit.
535    #[inline(always)]
536    pub const fn to_i32(self) -> i32 {
537        self.to_i64() as i32
538    }
539
540    /// Converts a 48.16 fixed point value to a single precision floating
541    /// point value.
542    ///
543    /// This operation is lossy.
544    #[inline(always)]
545    pub const fn to_f32(self) -> f32 {
546        const SCALE_FACTOR: f64 = 1.0 / 65536.0;
547        (self.0 as f64 * SCALE_FACTOR) as f32
548    }
549
550    /// Converts a 48.16 to a 16.16 fixed point value.
551    ///
552    /// The fractional bits carry over exactly; this truncates the integral
553    /// bits if the value is too large to fit.
554    #[inline(always)]
555    pub const fn to_fixed(self) -> Fixed {
556        Fixed(self.0 as i32)
557    }
558}
559
560impl F2Dot14 {
561    /// Applies an item variation delta, returning the varied value as a
562    /// single precision floating point number.
563    ///
564    /// A delta for a 2.14 valued target is a raw integer count of the
565    /// target's own quantum, so the accumulated 48.16 delta is scaled by
566    /// one quarter of one percent -- 1/16384 -- on application. The result
567    /// is intentionally not rounded back to 2.14.
568    #[inline(always)]
569    pub fn apply_delta(self, delta: F48Dot16) -> f32 {
570        self.to_f32() + (delta.to_f64() / 16384.0) as f32
571    }
572
573    /// Converts a 2.14 to 16.16 fixed point value.
574    #[inline(always)]
575    pub const fn to_fixed(self) -> Fixed {
576        Fixed(self.0 as i32 * 4)
577    }
578}
579
580#[cfg(test)]
581mod tests {
582    #![allow(overflowing_literals)] // we want to specify byte values directly
583    use super::*;
584
585    #[test]
586    fn f2dot14_floats() {
587        // Examples from https://docs.microsoft.com/en-us/typography/opentype/spec/otff#data-types
588        assert_eq!(F2Dot14(0x7fff), F2Dot14::from_f32(1.999939));
589        assert_eq!(F2Dot14(0x7000), F2Dot14::from_f32(1.75));
590        assert_eq!(F2Dot14(0x0001), F2Dot14::from_f32(0.0000610356));
591        assert_eq!(F2Dot14(0x0000), F2Dot14::from_f32(0.0));
592        assert_eq!(F2Dot14(0xffff), F2Dot14::from_f32(-0.000061));
593        assert_eq!(F2Dot14(0x8000), F2Dot14::from_f32(-2.0));
594    }
595
596    #[test]
597    fn roundtrip_f2dot14() {
598        for i in i16::MIN..=i16::MAX {
599            let val = F2Dot14(i);
600            assert_eq!(val, F2Dot14::from_f32(val.to_f32()));
601        }
602    }
603
604    #[test]
605    fn round_f2dot14() {
606        assert_eq!(F2Dot14(0x7000).round(), F2Dot14::from_f32(-2.0));
607        assert_eq!(F2Dot14(0x1F00).round(), F2Dot14::from_f32(0.0));
608        assert_eq!(F2Dot14(0x2000).round(), F2Dot14::from_f32(1.0));
609    }
610
611    #[test]
612    fn round_fixed() {
613        //TODO: make good test cases
614        assert_eq!(Fixed(0x0001_7FFE).round(), Fixed(0x0001_0000));
615        assert_eq!(Fixed(0x0001_7FFF).round(), Fixed(0x0001_0000));
616        assert_eq!(Fixed(0x0001_8000).round(), Fixed(0x0002_0000));
617    }
618
619    // disabled because it's slow; these were just for my edification anyway
620    //#[test]
621    //fn roundtrip_fixed() {
622    //for i in i32::MIN..=i32::MAX {
623    //let val = Fixed(i);
624    //assert_eq!(val, Fixed::from_f64(val.to_f64()));
625    //}
626    //}
627
628    #[test]
629    fn fixed_floats() {
630        assert_eq!(Fixed(0x7fff_0000), Fixed::from_f64(32767.));
631        assert_eq!(Fixed(0x7000_0001), Fixed::from_f64(28672.00001525879));
632        assert_eq!(Fixed(0x0001_0000), Fixed::from_f64(1.0));
633        assert_eq!(Fixed(0x0000_0000), Fixed::from_f64(0.0));
634        assert_eq!(
635            Fixed(i32::from_be_bytes([0xff; 4])),
636            Fixed::from_f64(-0.000015259)
637        );
638        assert_eq!(Fixed(0x7fff_ffff), Fixed::from_f64(32768.0));
639    }
640
641    // We lost the f64::round() intrinsic when dropping std and the
642    // alternative implementation was very slightly incorrect, throwing
643    // off some tests. This makes sure we match.
644    #[test]
645    fn fixed_floats_rounding() {
646        fn with_round_intrinsic(x: f64) -> Fixed {
647            Fixed((x * 65536.0).round() as i32)
648        }
649        // These particular values were tripping up tests
650        let inputs = [0.05, 0.6, 0.2, 0.4, 0.67755];
651        for input in inputs {
652            assert_eq!(Fixed::from_f64(input), with_round_intrinsic(input));
653            // Test negated values as well for good measure
654            assert_eq!(Fixed::from_f64(-input), with_round_intrinsic(-input));
655        }
656    }
657
658    #[test]
659    fn fixed_to_int() {
660        assert_eq!(Fixed::from_f64(1.0).to_i32(), 1);
661        assert_eq!(Fixed::from_f64(1.5).to_i32(), 2);
662        assert_eq!(F26Dot6::from_f64(1.0).to_i32(), 1);
663        assert_eq!(F26Dot6::from_f64(1.5).to_i32(), 2);
664    }
665
666    #[test]
667    fn fixed_from_int() {
668        assert_eq!(Fixed::from_i32(1000).to_bits(), 1000 << 16);
669        assert_eq!(F26Dot6::from_i32(1000).to_bits(), 1000 << 6);
670    }
671
672    #[test]
673    fn fixed_to_f26dot6() {
674        assert_eq!(Fixed::from_f64(42.5).to_f26dot6(), F26Dot6::from_f64(42.5));
675    }
676
677    #[test]
678    fn fixed_muldiv() {
679        assert_eq!(
680            Fixed::from_f64(0.5) * Fixed::from_f64(2.0),
681            Fixed::from_f64(1.0)
682        );
683        assert_eq!(
684            Fixed::from_f64(0.5) / Fixed::from_f64(2.0),
685            Fixed::from_f64(0.25)
686        );
687    }
688
689    // OSS Fuzz caught panic with overflow in fixed point division.
690    // See <https://oss-fuzz.com/testcase-detail/5666843647082496> and
691    // <https://issues.oss-fuzz.com/issues/443104630>
692    #[test]
693    fn fixed_div_neg_overflow() {
694        let a = Fixed::from_f64(-92.5);
695        let b = Fixed::from_f64(0.0028228759765625);
696        // Just don't panic with overflow
697        let _ = a / b;
698    }
699
700    #[test]
701    fn fixed_mul_div_neg_overflow() {
702        let a = Fixed::from_f64(-92.5);
703        let b = Fixed::from_f64(0.0028228759765625);
704        // Just don't panic with overflow
705        let _ = a.mul_div(Fixed::ONE, b);
706    }
707
708    #[test]
709    fn fixed_div_min_value() {
710        // i32::MIN.abs() overflows i32, unsigned_abs() handles this correctly
711        let min = Fixed(i32::MIN);
712        let one = Fixed::ONE;
713        // Just don't panic with overflow
714        let _ = min / one;
715        // Dividing by -1 is also an edge case
716        let neg_one = Fixed(-Fixed::ONE.0);
717        let _ = min / neg_one;
718    }
719
720    #[test]
721    fn fixed_abs_min_value() {
722        // Just don't panic with overflow; we use wrapping arithmetic to
723        // match FT.
724        assert_eq!(Fixed(i32::MIN).abs(), Fixed(i32::MIN));
725    }
726
727    #[test]
728    fn fixed_neg_min_value() {
729        // Just don't panic with overflow; we use wrapping arithmetic to
730        // match FT.
731        assert_eq!(-Fixed(i32::MIN), Fixed(i32::MIN));
732    }
733
734    #[test]
735    fn f48dot16_floats() {
736        assert_eq!(F48Dot16(0x0001_0000), F48Dot16::from_f64(1.0));
737        assert_eq!(F48Dot16(0x0000_0000), F48Dot16::from_f64(0.0));
738        assert_eq!(F48Dot16(0x0001_8000), F48Dot16::from_f64(1.5));
739        assert_eq!(F48Dot16(-0x0001_8000), F48Dot16::from_f64(-1.5));
740        assert_eq!(F48Dot16(0x0000_0001), F48Dot16::EPSILON);
741        // Values far outside the 16.16 range are representable.
742        assert_eq!(
743            F48Dot16((1i64 << 40) * 65536),
744            F48Dot16::from_f64((1u64 << 40) as f64)
745        );
746        assert_eq!(
747            F48Dot16::from_f64(1099511627776.5).to_f64(),
748            1099511627776.5
749        );
750    }
751
752    #[test]
753    fn f48dot16_round() {
754        assert_eq!(F48Dot16(0x0001_7FFF).round(), F48Dot16(0x0001_0000));
755        assert_eq!(F48Dot16(0x0001_8000).round(), F48Dot16(0x0002_0000));
756        assert_eq!(F48Dot16::from_f64(-1.5).round(), F48Dot16::from_f64(-1.0));
757    }
758
759    #[test]
760    fn f48dot16_to_int() {
761        assert_eq!(F48Dot16::from_f64(1.0).to_i64(), 1);
762        assert_eq!(F48Dot16::from_f64(1.5).to_i64(), 2);
763        assert_eq!(F48Dot16::from_f64(-1.5).to_i64(), -1);
764        assert_eq!(F48Dot16::from_f64(1099511627776.25).to_i64(), 1099511627776);
765    }
766
767    #[test]
768    fn f48dot16_from_int() {
769        assert_eq!(F48Dot16::from_i64(1000).to_bits(), 1000 << 16);
770        assert_eq!(F48Dot16::from_i64(1 << 40).to_bits(), 1 << 56);
771    }
772
773    /// Widening from 16.16 is exact over the whole range, and narrowing
774    /// returns exactly when the value fits.
775    #[test]
776    fn f48dot16_fixed_conversions() {
777        for bits in [0, 1, -1, 0x1234_5678, i32::MAX, i32::MIN] {
778            let fixed = Fixed(bits);
779            let wide = fixed.to_f48dot16();
780            assert_eq!(wide.to_bits(), bits as i64);
781            assert_eq!(wide.to_fixed(), fixed);
782        }
783        // Out of range narrows truncate, wrapping like the sibling
784        // conversions rather than saturating.
785        assert_eq!(F48Dot16(i32::MAX as i64 + 1).to_fixed(), Fixed(i32::MIN));
786        assert_eq!(F48Dot16(i32::MIN as i64 - 1).to_fixed(), Fixed(i32::MAX));
787    }
788
789    #[test]
790    fn f48dot16_mul_i32() {
791        assert_eq!(Fixed::from_f64(0.5).mul_i32(3), F48Dot16::from_f64(1.5));
792        assert_eq!(Fixed::ONE.mul_i32(-7), F48Dot16::from_i64(-7));
793        assert_eq!(Fixed::ZERO.mul_i32(i32::MAX), F48Dot16::ZERO);
794        // The extreme product fits without overflow: |i32::MIN| * |i32::MIN|
795        // is 2^62, inside i64.
796        assert_eq!(Fixed(i32::MIN).mul_i32(i32::MIN), F48Dot16(1i64 << 62));
797    }
798
799    /// The variation delta shape: raw deltas scaled and summed exactly,
800    /// then rounded once at the end.
801    #[test]
802    fn f48dot16_delta_accumulation() {
803        let deltas = [100i32, -250, 37];
804        let scalars = [
805            Fixed::from_f64(1.0),
806            Fixed::from_f64(0.5),
807            Fixed::from_f64(0.25),
808        ];
809        let mut accum = F48Dot16::ZERO;
810        for (delta, scalar) in deltas.iter().zip(&scalars) {
811            accum += scalar.mul_i32(*delta);
812        }
813        // 100 - 125 + 9.25 = -15.75, which rounds to the nearest integer.
814        assert_eq!(accum, F48Dot16::from_f64(-15.75));
815        assert_eq!(accum.to_i64(), -16);
816        assert_eq!(accum.round(), F48Dot16::from_f64(-16.0));
817    }
818
819    /// The delta application methods must agree exactly with the former
820    /// `FloatItemDeltaTarget` impls in read-fonts that they replaced, which
821    /// computed base + raw * (1 / quantum) through an f64 raw count.
822    #[test]
823    fn f48dot16_apply_delta() {
824        let raws = [0i64, 1, -1, 100, -32768, 65536, 1 << 40, -(1 << 40)];
825        for raw_bits in raws {
826            let delta = F48Dot16(raw_bits);
827            let raw = delta.to_f64();
828            // Fixed targets scale by 1/65536.
829            let base = Fixed::from_f64(1.5);
830            assert_eq!(
831                base.apply_delta(delta),
832                base.to_f32() + (raw * (1.0 / 65536.0)) as f32
833            );
834            // 2.14 targets scale by 1/16384.
835            let base = F2Dot14::from_f32(0.25);
836            assert_eq!(
837                base.apply_delta(delta),
838                base.to_f32() + (raw * (1.0 / 16384.0)) as f32
839            );
840        }
841        // Spot values: one quantum of delta moves a target by one quantum.
842        assert_eq!(
843            Fixed::ZERO.apply_delta(F48Dot16::from_i64(1)),
844            1.0 / 65536.0
845        );
846        assert_eq!(
847            F2Dot14::from_f32(0.0).apply_delta(F48Dot16::from_i64(1)),
848            1.0 / 16384.0
849        );
850        assert_eq!(
851            F2Dot14::from_f32(0.5).apply_delta(F48Dot16::from_f64(-0.5)),
852            0.5 - 0.5 / 16384.0
853        );
854    }
855
856    #[test]
857    fn f26dot6_muldiv() {
858        assert_eq!(
859            F26Dot6::from_f64(0.5) * F26Dot6::from_f64(2.0),
860            F26Dot6::from_f64(1.0)
861        );
862        assert_eq!(
863            F26Dot6::from_f64(0.5) * F26Dot6::from_f64(-2.4),
864            F26Dot6::from_f64(-1.2)
865        );
866        assert_eq!(F26Dot6::ONE * F26Dot6::ONE, F26Dot6::ONE);
867        assert_eq!(
868            F26Dot6::from_f64(0.5) / F26Dot6::from_f64(2.0),
869            F26Dot6::from_f64(0.25)
870        );
871        assert_eq!(
872            F26Dot6::from_f64(0.5) / F26Dot6::from_f64(-2.4),
873            F26Dot6::from_f64(-0.20833333333333334)
874        );
875        assert_eq!(
876            F26Dot6::from_f64(2.0) / F26Dot6::from_f64(3.0),
877            F26Dot6::from_f64(0.6666666666666666)
878        );
879        assert_eq!(F26Dot6::ONE / F26Dot6::ONE, F26Dot6::ONE);
880        assert_eq!(F26Dot6::ONE / F26Dot6::ZERO, F26Dot6(0x7FFFFFFF));
881        assert_eq!(-F26Dot6::ONE / F26Dot6::ZERO, F26Dot6(-0x7FFFFFFF));
882    }
883
884    #[cfg(feature = "std")]
885    mod display {
886        use super::*;
887
888        #[test]
889        fn f2dot14() {
890            let cases = [
891                (F2Dot14(9830), "0.6"),
892                (F2Dot14(-10139), "-0.61884"),
893                (F2Dot14::ONE, "1"),
894                (F2Dot14::NEG_ONE, "-1"),
895                (F2Dot14::ZERO, "0"),
896                (F2Dot14::MIN, "-2"),
897                (F2Dot14::MAX, "1.99994"),
898                (F2Dot14::EPSILON, "0.00006"),
899                (F2Dot14(-1), "-0.00006"),
900                (F2Dot14::from_f32(0.5), "0.5"),
901                (F2Dot14::from_f32(-0.25), "-0.25"),
902            ];
903            for (value, expected) in cases {
904                assert_eq!(value.to_string(), expected, "{:?}", value.to_bits());
905            }
906        }
907
908        #[test]
909        fn f4dot12_f6dot10() {
910            assert_eq!(F4Dot12::from_f32(0.6).to_string(), "0.6");
911            assert_eq!(F4Dot12::MIN.to_string(), "-8");
912            assert_eq!(F4Dot12::MAX.to_string(), "7.9998");
913            assert_eq!(F6Dot10::from_f32(-0.6).to_string(), "-0.6");
914            assert_eq!(F6Dot10::MIN.to_string(), "-32");
915            assert_eq!(F6Dot10::MAX.to_string(), "31.999");
916        }
917
918        #[test]
919        fn fixed() {
920            let cases = [
921                (Fixed::from_f64(0.6), "0.6"),
922                (Fixed::from_f64(-0.6), "-0.6"),
923                (Fixed::from_f64(-1.5), "-1.5"),
924                (Fixed::from_i32(1000), "1000"),
925                (Fixed::from_f64(32767.5), "32767.5"),
926                (Fixed::MAX, "32767.99998"),
927                (Fixed::MIN, "-32768"),
928                (Fixed::EPSILON, "0.00002"),
929                (Fixed(-1), "-0.00002"),
930            ];
931            for (value, expected) in cases {
932                assert_eq!(value.to_string(), expected, "{:?}", value.to_bits());
933            }
934        }
935
936        #[test]
937        fn f26dot6() {
938            let cases = [
939                (F26Dot6(1), "0.02"),
940                (F26Dot6(-3), "-0.05"),
941                (F26Dot6(32), "0.5"),
942                (F26Dot6(65), "1.02"),
943                (F26Dot6(-96), "-1.5"),
944                (F26Dot6(100 * 64 + 16), "100.25"),
945                (F26Dot6::from_i32(-7), "-7"),
946                (F26Dot6::MIN, "-33554432"),
947                (F26Dot6::MAX, "33554431.98"),
948            ];
949            for (value, expected) in cases {
950                assert_eq!(value.to_string(), expected, "{:?}", value.to_bits());
951            }
952        }
953
954        #[test]
955        fn f48dot16() {
956            let cases = [
957                (F48Dot16::from_f64(0.6), "0.6"),
958                (F48Dot16::from_i64(1 << 40), "1099511627776"),
959                (F48Dot16::from_f64(-1099511627776.5), "-1099511627776.5"),
960                (F48Dot16::MAX, "140737488355327.99998"),
961                (F48Dot16::MIN, "-140737488355328"),
962                (F48Dot16(i64::MIN + 1), "-140737488355327.99998"),
963            ];
964            for (value, expected) in cases {
965                assert_eq!(value.to_string(), expected, "{:?}", value.to_bits());
966            }
967        }
968
969        /// Checks that `text` parses back to `raw` and is as short as possible.
970        ///
971        /// A decimal with one fewer place that also round-trips would lie
972        /// within half a step of the value, and then so would one of the two
973        /// such decimals nearest it. `from_f64` returns `None` for inputs it
974        /// would saturate, since those don't round-trip in any real sense.
975        fn check_shortest(
976            raw: i64,
977            text: &str,
978            fract_bits: u32,
979            from_f64: impl Fn(f64) -> Option<i64>,
980        ) {
981            assert_ne!(text, "-0");
982            let parsed: f64 = text.parse().unwrap();
983            assert_eq!(from_f64(parsed), Some(raw), "{text} does not round-trip");
984            let places = text
985                .split_once('.')
986                .map_or(0, |(_, fract)| fract.len() as u32);
987            if places == 0 {
988                return;
989            }
990            let pow = 10i128.pow(places - 1);
991            let floor = (i128::from(raw) * pow).div_euclid(1 << fract_bits);
992            for shorter in [floor, floor + 1] {
993                let shorter = shorter as f64 / pow as f64;
994                assert_ne!(from_f64(shorter), Some(raw), "{text} could be {shorter}");
995            }
996        }
997
998        macro_rules! check_all {
999            ($fixed:ident, $raws:expr) => {
1000                let one = $fixed::ONE.to_bits() as f64;
1001                let min = ($fixed::MIN.to_bits() as f64 - 0.5) / one;
1002                let max = ($fixed::MAX.to_bits() as f64 + 0.5) / one;
1003                for raw in $raws {
1004                    check_shortest(
1005                        raw as i64,
1006                        &$fixed(raw).to_string(),
1007                        $fixed::FRACT_BITS as u32,
1008                        |x| (min < x && x < max).then(|| $fixed::from_f64(x).to_bits() as i64),
1009                    );
1010                }
1011            };
1012        }
1013
1014        #[test]
1015        fn shortest_all_f2dot14() {
1016            check_all!(F2Dot14, i16::MIN..=i16::MAX);
1017        }
1018
1019        #[test]
1020        fn shortest_all_f4dot12() {
1021            check_all!(F4Dot12, i16::MIN..=i16::MAX);
1022        }
1023
1024        #[test]
1025        fn shortest_all_f6dot10() {
1026            check_all!(F6Dot10, i16::MIN..=i16::MAX);
1027        }
1028
1029        fn sampled_i32() -> impl Iterator<Item = i32> {
1030            (i32::MIN..=i32::MIN + 2000)
1031                .chain(-200_000..=200_000)
1032                .chain((i32::MIN..=i32::MAX).step_by(65_521))
1033                .chain(i32::MAX - 2000..=i32::MAX)
1034        }
1035
1036        #[test]
1037        fn shortest_sampled_fixed() {
1038            check_all!(Fixed, sampled_i32());
1039        }
1040
1041        #[test]
1042        fn shortest_sampled_f26dot6() {
1043            check_all!(F26Dot6, sampled_i32());
1044        }
1045
1046        #[test]
1047        fn formatter_flags() {
1048            let value = F2Dot14(9830);
1049            assert_eq!(format!("{value:.2}"), "0.60");
1050            assert_eq!(format!("{value:.2?}"), "0.60");
1051            assert_eq!(format!("{value:>8}"), "     0.6");
1052            assert_eq!(format!("{value:8}"), "     0.6");
1053            assert_eq!(format!("{value:<8}|"), "0.6     |");
1054            assert_eq!(format!("{value:*^9}"), "***0.6***");
1055            assert_eq!(format!("{value:08}"), "000000.6");
1056            assert_eq!(format!("{value:+}"), "+0.6");
1057            assert_eq!(format!("{value:?}"), "0.6");
1058            // Where the shortest decimal is also what f64 prints, every flag
1059            // should agree with it.
1060            for (value, float) in [(F2Dot14::from_f32(-1.5), -1.5f64), (F2Dot14::ONE, 1.0)] {
1061                assert_eq!(format!("{value}"), format!("{float}"));
1062                assert_eq!(format!("{value:.3}"), format!("{float:.3}"));
1063                assert_eq!(format!("{value:>8}"), format!("{float:>8}"));
1064                assert_eq!(format!("{value:<8}"), format!("{float:<8}"));
1065                assert_eq!(format!("{value:08}"), format!("{float:08}"));
1066                assert_eq!(format!("{value:+09}"), format!("{float:+09}"));
1067            }
1068        }
1069    }
1070
1071    #[cfg(feature = "serde")]
1072    mod serde {
1073        use super::*;
1074
1075        macro_rules! roundtrip_one {
1076            ($fixed:ident) => {{
1077                let before = <$fixed>::ONE;
1078                let serialized = ::serde_json::to_string(&before).expect("should serialize");
1079                assert_eq!(&serialized, "1.0");
1080                let after = ::serde_json::from_str(&serialized).expect("should deserialize");
1081                assert_eq!(before, after);
1082            }};
1083        }
1084
1085        #[test]
1086        fn one_is_one_f2dot14() {
1087            roundtrip_one!(F2Dot14);
1088        }
1089
1090        #[test]
1091        fn one_is_one_f4dot12() {
1092            roundtrip_one!(F4Dot12);
1093        }
1094
1095        #[test]
1096        fn one_is_one_f6dot10() {
1097            roundtrip_one!(F6Dot10);
1098        }
1099
1100        #[test]
1101        fn one_is_one_fixed() {
1102            roundtrip_one!(Fixed);
1103        }
1104
1105        #[test]
1106        fn one_is_one_f26dot6() {
1107            roundtrip_one!(F26Dot6);
1108        }
1109
1110        macro_rules! roundtrip_all {
1111            ($fixed:ident, $ty:ty) => {
1112                for raw in <$ty>::MIN..=<$ty>::MAX {
1113                    let fixed = $fixed(raw);
1114                    let fixed_float = fixed.to_f64();
1115
1116                    let json_value = ::serde_json::to_value(&fixed).expect("should serialize");
1117                    let json_float = json_value
1118                        .as_f64()
1119                        .expect("serde didn't serialize the value to a float");
1120
1121                    // Normally directly comparing floats is flawed, but these
1122                    // should have been converted to float using the exact same
1123                    // method each, so I wouldn't expect them to be different
1124                    assert_eq!(
1125                        fixed_float,
1126                        json_float,
1127                        "failed on {raw} ({fixed_type}({raw:#X})): {json_float} != {fixed_float}",
1128                        fixed_type = ::std::stringify!($fixed),
1129                    );
1130                }
1131            };
1132        }
1133
1134        #[test]
1135        fn roundtrip_all_f2dot14() {
1136            roundtrip_all!(F2Dot14, i16);
1137        }
1138
1139        #[test]
1140        fn roundtrip_all_f4dot12() {
1141            roundtrip_all!(F4Dot12, i16);
1142        }
1143
1144        #[test]
1145        fn roundtrip_all_f6dot10() {
1146            roundtrip_all!(F6Dot10, i16);
1147        }
1148
1149        #[test]
1150        #[ignore = "enumerating all i32 values takes a while"]
1151        fn roundtrip_all_fixed() {
1152            roundtrip_all!(Fixed, i32);
1153        }
1154
1155        #[test]
1156        #[ignore = "enumerating all i32 values takes a while"]
1157        fn roundtrip_all_f26dot6() {
1158            roundtrip_all!(F26Dot6, i32);
1159        }
1160    }
1161}