i_slint_renderer_software/
fixed.rs1#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
6pub struct Fixed<T, const SHIFT: usize>(pub T);
7
8impl<
9 T: Copy
10 + core::ops::Shl<usize, Output = T>
11 + core::ops::Shr<usize, Output = T>
12 + core::ops::Div<Output = T>
13 + core::ops::Add<Output = T>
14 + core::ops::Rem<Output = T>,
15 const SHIFT: usize,
16> Fixed<T, SHIFT>
17{
18 #[inline(always)]
20 pub fn from_integer(value: T) -> Self {
21 Self(value << SHIFT)
22 }
23
24 #[inline(always)]
26 pub fn truncate(self) -> T {
27 self.0 >> SHIFT
28 }
29
30 #[inline(always)]
32 pub fn fract(self) -> u8
33 where
34 T: num_traits::AsPrimitive<u8>,
35 {
36 if SHIFT < 8 { (self.0 >> (SHIFT - 8)).as_() } else { (self.0 << (8 - SHIFT)).as_() }
37 }
38
39 #[inline(always)]
40 pub fn from_fixed<
41 T2: core::ops::Shl<usize, Output = T2> + core::ops::Shr<usize, Output = T2> + Into<T>,
42 const SHIFT2: usize,
43 >(
44 value: Fixed<T2, SHIFT2>,
45 ) -> Self {
46 if SHIFT > SHIFT2 {
47 let s: T = value.0.into();
48 Self(s << (SHIFT - SHIFT2))
49 } else {
50 Self((value.0 >> (SHIFT2 - SHIFT)).into())
51 }
52 }
53 #[inline(always)]
54 pub fn try_from_fixed<
55 T2: core::ops::Shl<usize, Output = T2> + core::ops::Shr<usize, Output = T2> + TryInto<T>,
56 const SHIFT2: usize,
57 >(
58 value: Fixed<T2, SHIFT2>,
59 ) -> Result<Self, T2::Error> {
60 Ok(if SHIFT > SHIFT2 {
61 let s: T = value.0.try_into()?;
62 Self(s << (SHIFT - SHIFT2))
63 } else {
64 Self((value.0 >> (SHIFT2 - SHIFT)).try_into()?)
65 })
66 }
67
68 #[inline(always)]
69 pub fn from_fraction(numerator: T, denominator: T) -> Self {
70 Self((numerator << SHIFT) / denominator)
71 }
72
73 #[inline(always)]
74 pub(crate) fn from_f32(value: f32) -> Option<Self>
75 where
76 T: num_traits::FromPrimitive,
77 {
78 Some(Self(T::from_f32(value * (1 << SHIFT) as f32)?))
79 }
80}
81
82impl<T: core::ops::Add<Output = T>, const SHIFT: usize> core::ops::Add for Fixed<T, SHIFT> {
83 type Output = Self;
84 #[inline(always)]
85 fn add(self, rhs: Self) -> Self::Output {
86 Self(self.0.add(rhs.0))
87 }
88}
89
90impl<T: core::ops::Sub<Output = T>, const SHIFT: usize> core::ops::Sub for Fixed<T, SHIFT> {
91 type Output = Self;
92 #[inline(always)]
93 fn sub(self, rhs: Self) -> Self::Output {
94 Self(self.0.sub(rhs.0))
95 }
96}
97
98impl<T: core::ops::AddAssign, const SHIFT: usize> core::ops::AddAssign for Fixed<T, SHIFT> {
99 #[inline(always)]
100 fn add_assign(&mut self, rhs: Self) {
101 self.0.add_assign(rhs.0)
102 }
103}
104
105impl<T: core::ops::SubAssign, const SHIFT: usize> core::ops::SubAssign for Fixed<T, SHIFT> {
106 #[inline(always)]
107 fn sub_assign(&mut self, rhs: Self) {
108 self.0.sub_assign(rhs.0)
109 }
110}
111
112impl<T: core::ops::Mul<Output = T>, const SHIFT: usize> core::ops::Mul<T> for Fixed<T, SHIFT> {
113 type Output = Self;
114 #[inline(always)]
115 fn mul(self, rhs: T) -> Self::Output {
116 Self(self.0.mul(rhs))
117 }
118}
119
120impl<T: core::ops::Mul<Output = T>, const SHIFT: usize> core::ops::Mul<Fixed<T, SHIFT>>
121 for Fixed<T, SHIFT>
122where
123 T: TryFrom<i64> + Into<i64>,
124 <T as TryFrom<i64>>::Error: core::fmt::Debug,
125{
126 type Output = Self;
127 fn mul(self, rhs: Fixed<T, SHIFT>) -> Self::Output {
128 let lhs_i64: i64 = self.0.into();
129 let rhs_i64: i64 = rhs.0.into();
130 Self(T::try_from((lhs_i64 * rhs_i64) >> SHIFT).expect("attempt to multiply with overflow"))
131 }
132}
133
134impl<T: core::ops::Neg<Output = T>, const SHIFT: usize> core::ops::Neg for Fixed<T, SHIFT> {
135 type Output = Self;
136 #[inline(always)]
137 fn neg(self) -> Self::Output {
138 Self(-self.0)
139 }
140}
141
142impl<T: core::ops::Div<Output = T>, const SHIFT: usize> core::ops::Div for Fixed<T, SHIFT> {
143 type Output = T;
144 #[inline(always)]
145 fn div(self, rhs: Self) -> Self::Output {
146 self.0 / rhs.0
147 }
148}
149
150impl<T: core::ops::Rem<Output = T>, const SHIFT: usize> core::ops::Rem for Fixed<T, SHIFT> {
151 type Output = Self;
152 #[inline(always)]
153 fn rem(self, rhs: Self) -> Self::Output {
154 Self(self.0 % rhs.0)
155 }
156}
157
158impl<T: core::ops::Div<Output = T>, const SHIFT: usize> core::ops::Div<T> for Fixed<T, SHIFT> {
159 type Output = Self;
160 #[inline(always)]
161 fn div(self, rhs: T) -> Self::Output {
162 Self(self.0 / rhs)
163 }
164}