tiny_skia_path/
floating_point.rs1use crate::scalar::Scalar;
8
9pub use strict_num::{FiniteF32, NonZeroPositiveF32, NormalizedF32};
10
11#[cfg(all(not(feature = "std"), feature = "no-std-float"))]
12use crate::NoStdFloat;
13
14pub(crate) const FLOAT_PI: f32 = 3.14159265;
15
16const MAX_I32_FITS_IN_F32: f32 = 2147483520.0;
17const MIN_I32_FITS_IN_F32: f32 = -MAX_I32_FITS_IN_F32;
18
19pub trait SaturateCast<T>: Sized {
22 fn saturate_from(n: T) -> Self;
24}
25
26impl SaturateCast<f32> for i32 {
27 fn saturate_from(mut x: f32) -> Self {
31 x = if x < MAX_I32_FITS_IN_F32 {
32 x
33 } else {
34 MAX_I32_FITS_IN_F32
35 };
36 x = if x > MIN_I32_FITS_IN_F32 {
37 x
38 } else {
39 MIN_I32_FITS_IN_F32
40 };
41 x as i32
42 }
43}
44
45impl SaturateCast<f64> for i32 {
46 fn saturate_from(mut x: f64) -> Self {
50 x = if x < i32::MAX as f64 {
51 x
52 } else {
53 i32::MAX as f64
54 };
55 x = if x > i32::MIN as f64 {
56 x
57 } else {
58 i32::MIN as f64
59 };
60 x as i32
61 }
62}
63
64#[allow(missing_docs)]
66pub trait SaturateRound<T>: SaturateCast<T> {
67 fn saturate_floor(n: T) -> Self;
68 fn saturate_ceil(n: T) -> Self;
69 fn saturate_round(n: T) -> Self;
70}
71
72impl SaturateRound<f32> for i32 {
73 fn saturate_floor(x: f32) -> Self {
74 Self::saturate_from(x.floor())
75 }
76
77 fn saturate_ceil(x: f32) -> Self {
78 Self::saturate_from(x.ceil())
79 }
80
81 fn saturate_round(x: f32) -> Self {
82 Self::saturate_from(x.floor() + 0.5)
83 }
84}
85
86pub(crate) fn f32_as_2s_compliment(x: f32) -> i32 {
91 sign_bit_to_2s_compliment(bytemuck::cast(x))
92}
93
94fn sign_bit_to_2s_compliment(mut x: i32) -> i32 {
98 if x < 0 {
99 x &= 0x7FFFFFFF;
100 x = -x;
101 }
102
103 x
104}
105
106#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Debug)]
108#[repr(transparent)]
109pub struct NormalizedF32Exclusive(FiniteF32);
110
111impl NormalizedF32Exclusive {
112 pub const ANY: Self = Self::HALF;
114
115 pub const HALF: Self = NormalizedF32Exclusive(unsafe { FiniteF32::new_unchecked(0.5) });
117
118 pub fn new(n: f32) -> Option<Self> {
120 if n > 0.0 && n < 1.0 {
121 FiniteF32::new(n).map(NormalizedF32Exclusive)
123 } else {
124 None
125 }
126 }
127
128 pub fn new_bounded(n: f32) -> Self {
132 let n = n.bound(f32::EPSILON, 1.0 - f32::EPSILON);
133 debug_assert!(n.is_finite());
135 NormalizedF32Exclusive(unsafe { FiniteF32::new_unchecked(n) })
136 }
137
138 pub fn get(self) -> f32 {
140 self.0.get()
141 }
142
143 pub fn to_normalized(self) -> NormalizedF32 {
145 unsafe { NormalizedF32::new_unchecked(self.0.get()) }
147 }
148}