1#![cfg_attr(not(any(test, feature = "std")), no_std)]
28
29pub use macros::fixed;
31
32use core::{convert, fmt::Display, ops, str::FromStr};
33#[cfg(all(feature = "serde", not(any(test, feature = "std"))))]
34use num_traits::float::FloatCore;
35use num_traits::pow::Pow;
36
37#[derive(Copy, Clone, Default, Debug, PartialEq, PartialOrd)]
38pub struct FixedPoint<T, const D: u8>(pub T);
39
40impl<T, const D: u8> FixedPoint<T, D> {
41 pub fn decimal_length(self) -> u8 {
42 D
43 }
44
45 pub fn exp(self) -> usize {
46 10_usize.pow(D as u32)
47 }
48}
49
50pub trait Number {
51 fn ten() -> Self;
52 fn zero() -> Self;
53}
54
55macro_rules! impl_number {
56 ($($types:ty),+) => {
57 $(
58 impl Number for $types {
59 fn ten() -> Self {
60 10
61 }
62
63 fn zero() -> Self {
64 0
65 }
66 }
67 )+
68 };
69}
70
71impl_number!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize);
72
73impl<T, const D: u8> FixedPoint<T, D>
74where
75 T: Number + Pow<u8, Output = T> + ops::Mul<Output = T> + ops::Add<Output = T>,
76{
77 pub fn new(number: T, decimal: u8) -> Self {
78 Self(number * T::ten().pow(D - decimal))
79 }
80}
81
82impl<T, const D: u8> FixedPoint<T, D>
83where
84 T: Copy + Number + Pow<u32, Output = T> + ops::Div<Output = T> + ops::Rem<Output = T>,
85{
86 pub fn integer(&self) -> T {
87 self.0 / (T::ten()).pow(D as u32)
88 }
89
90 pub fn decimal(&self) -> T {
91 self.0 % (T::ten()).pow(D as u32)
92 }
93}
94
95impl<T: ops::Div<Output = T>, const D: u8> ops::Div<T> for FixedPoint<T, D> {
96 type Output = Self;
97
98 fn div(self, div: T) -> Self {
99 Self(self.0 / div)
100 }
101}
102
103impl<T: Copy + Into<i32>, const D: u8> Into<f32> for FixedPoint<T, D> {
104 fn into(self) -> f32 {
105 let value: i32 = self.0.into();
106 value as f32 / self.exp() as f32
107 }
108}
109
110impl<T: convert::TryFrom<isize>, const D: u8> FromStr for FixedPoint<T, D> {
111 type Err = ();
112
113 fn from_str(string: &str) -> Result<Self, Self::Err> {
114 let negative = string.chars().next().map(|c| c == '-').unwrap_or(false);
115 let mut splitted = string.split('.');
116 let mut integer = splitted
117 .next()
118 .ok_or(())?
119 .parse::<isize>()
120 .map_err(|_| ())?;
121 integer *= (10 as isize).pow(D as u32);
122 let field = match splitted.next() {
123 Some(s) => s,
124 None => return T::try_from(integer).map(|v| Self(v)).map_err(|_| ()),
125 };
126 let decimal_length = core::cmp::min(field.len(), 255) as u8;
127 let mut decimal = field.parse::<isize>().map_err(|_| ())?;
128 if integer < 0 || negative {
129 decimal = -decimal
130 }
131 if D >= decimal_length {
132 decimal *= (10 as isize).pow((D - decimal_length) as u32);
133 } else {
134 decimal /= (10 as isize).pow((decimal_length - D) as u32);
135 }
136 T::try_from(integer + decimal)
137 .map(|v| Self(v))
138 .map_err(|_| ())
139 }
140}
141
142impl<T, const D: u8> Display for FixedPoint<T, D>
143where
144 T: Copy
145 + Display
146 + Into<i32>
147 + PartialEq
148 + Number
149 + PartialOrd
150 + Pow<u32, Output = T>
151 + ops::Div<Output = T>
152 + ops::Rem<Output = T>,
153{
154 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
155 let mut decimal = self.decimal().into().abs();
156 if D == 0 || decimal == 0 {
157 return write!(f, "{}.0", self.integer());
158 }
159 let mut length = D;
160 while decimal % 10 == 0 {
161 decimal = decimal / 10;
162 length -= 1;
163 }
164 let integer = self.integer();
165 if integer == T::zero() && self.0 < T::zero() {
166 write!(f, "-0.{:0length$}", decimal, length = length as usize)
167 } else {
168 write!(
169 f,
170 "{}.{:0length$}",
171 integer,
172 decimal,
173 length = length as usize
174 )
175 }
176 }
177}
178
179#[cfg(feature = "serde")]
180impl<T: Copy + Into<i32>, const D: u8> serde::Serialize for FixedPoint<T, D> {
181 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
182 serializer.serialize_f32((*self).into())
183 }
184}
185
186#[cfg(feature = "serde")]
187impl<'a, T: convert::TryFrom<isize>, const D: u8> serde::Deserialize<'a> for FixedPoint<T, D> {
188 fn deserialize<DE: serde::Deserializer<'a>>(deserializer: DE) -> Result<Self, DE::Error> {
189 let float = <f32>::deserialize(deserializer)?;
190 let v = (float * 10f32.powi(D as i32)) as isize;
191 T::try_from(v)
192 .map(|v| Self(v))
193 .map_err(|_| <DE::Error as serde::de::Error>::custom("Not fixed-point"))
194 }
195}