1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4/// A Fixed point, represented with the T underlying type, and shifted by so many bits
5#[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 /// Create a fixed point from an integer value
19 #[inline(always)]
20 pub fn from_integer(value: T) -> Self {
21 Self(value << SHIFT)
22 }
23
24 /// Get the integer part of the fixed point value
25 #[inline(always)]
26 pub fn truncate(self) -> T {
27 self.0 >> SHIFT
28 }
29
30 /// Return the fractional part of the fixed point value
31 #[inline(always)]
32 pub fn fract(self) -> u8
33 where
34 T: num_traits::AsPrimitive<u8>,
35 {
36 if SHIFT < 8 {
37 (self.0 >> (SHIFT - 8)).as_()
38 } else {
39 (self.0 << (8 - SHIFT)).as_()
40 }
41 }
42
43 #[inline(always)]
44 pub fn from_fixed<
45 T2: core::ops::Shl<usize, Output = T2> + core::ops::Shr<usize, Output = T2> + Into<T>,
46 const SHIFT2: usize,
47 >(
48 value: Fixed<T2, SHIFT2>,
49 ) -> Self {
50 if SHIFT > SHIFT2 {
51 let s: T = value.0.into();
52 Self(s << (SHIFT - SHIFT2))
53 } else {
54 Self((value.0 >> (SHIFT2 - SHIFT)).into())
55 }
56 }
57 #[inline(always)]
58 pub fn try_from_fixed<
59 T2: core::ops::Shl<usize, Output = T2> + core::ops::Shr<usize, Output = T2> + TryInto<T>,
60 const SHIFT2: usize,
61 >(
62 value: Fixed<T2, SHIFT2>,
63 ) -> Result<Self, T2::Error> {
64 Ok(if SHIFT > SHIFT2 {
65 let s: T = value.0.try_into()?;
66 Self(s << (SHIFT - SHIFT2))
67 } else {
68 Self((value.0 >> (SHIFT2 - SHIFT)).try_into()?)
69 })
70 }
71
72 #[inline(always)]
73 pub fn from_fraction(numerator: T, denominator: T) -> Self {
74 Self((numerator << SHIFT) / denominator)
75 }
76
77 #[inline(always)]
78 pub(crate) fn from_f32(value: f32) -> Option<Self>
79 where
80 T: num_traits::FromPrimitive,
81 {
82 Some(Self(T::from_f32(value * (1 << SHIFT) as f32)?))
83 }
84}
85
86impl<T: core::ops::Add<Output = T>, const SHIFT: usize> core::ops::Add for Fixed<T, SHIFT> {
87 type Output = Self;
88 #[inline(always)]
89 fn add(self, rhs: Self) -> Self::Output {
90 Self(self.0.add(rhs.0))
91 }
92}
93
94impl<T: core::ops::Sub<Output = T>, const SHIFT: usize> core::ops::Sub for Fixed<T, SHIFT> {
95 type Output = Self;
96 #[inline(always)]
97 fn sub(self, rhs: Self) -> Self::Output {
98 Self(self.0.sub(rhs.0))
99 }
100}
101
102impl<T: core::ops::AddAssign, const SHIFT: usize> core::ops::AddAssign for Fixed<T, SHIFT> {
103 #[inline(always)]
104 fn add_assign(&mut self, rhs: Self) {
105 self.0.add_assign(rhs.0)
106 }
107}
108
109impl<T: core::ops::SubAssign, const SHIFT: usize> core::ops::SubAssign for Fixed<T, SHIFT> {
110 #[inline(always)]
111 fn sub_assign(&mut self, rhs: Self) {
112 self.0.sub_assign(rhs.0)
113 }
114}
115
116impl<T: core::ops::Mul<Output = T>, const SHIFT: usize> core::ops::Mul<T> for Fixed<T, SHIFT> {
117 type Output = Self;
118 #[inline(always)]
119 fn mul(self, rhs: T) -> Self::Output {
120 Self(self.0.mul(rhs))
121 }
122}
123
124impl<T: core::ops::Mul<Output = T>, const SHIFT: usize> core::ops::Mul<Fixed<T, SHIFT>>
125 for Fixed<T, SHIFT>
126where
127 T: TryFrom<i64> + Into<i64>,
128 <T as TryFrom<i64>>::Error: core::fmt::Debug,
129{
130 type Output = Self;
131 fn mul(self, rhs: Fixed<T, SHIFT>) -> Self::Output {
132 let lhs_i64: i64 = self.0.into();
133 let rhs_i64: i64 = rhs.0.into();
134 Self(T::try_from((lhs_i64 * rhs_i64) >> SHIFT).expect(msg:"attempt to multiply with overflow"))
135 }
136}
137
138impl<T: core::ops::Neg<Output = T>, const SHIFT: usize> core::ops::Neg for Fixed<T, SHIFT> {
139 type Output = Self;
140 #[inline(always)]
141 fn neg(self) -> Self::Output {
142 Self(-self.0)
143 }
144}
145
146impl<T: core::ops::Div<Output = T>, const SHIFT: usize> core::ops::Div for Fixed<T, SHIFT> {
147 type Output = T;
148 #[inline(always)]
149 fn div(self, rhs: Self) -> Self::Output {
150 self.0 / rhs.0
151 }
152}
153
154impl<T: core::ops::Rem<Output = T>, const SHIFT: usize> core::ops::Rem for Fixed<T, SHIFT> {
155 type Output = Self;
156 #[inline(always)]
157 fn rem(self, rhs: Self) -> Self::Output {
158 Self(self.0 % rhs.0)
159 }
160}
161
162impl<T: core::ops::Div<Output = T>, const SHIFT: usize> core::ops::Div<T> for Fixed<T, SHIFT> {
163 type Output = Self;
164 #[inline(always)]
165 fn div(self, rhs: T) -> Self::Output {
166 Self(self.0 / rhs)
167 }
168}
169