1#[cfg(feature = "serde")]
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3
4macro_rules! fixed_point_impl {
5 ($name:ident, $int_bits:expr, $frac_bits:expr, $epsilons_type:ty, $value_type:ty) => {
6 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
7 pub struct $name {
8 pub epsilons: $epsilons_type,
9 }
10
11 impl $name {
12 pub const ZERO: Self = Self { epsilons: 0 };
13 pub const ONE: Self = Self {
14 epsilons: 1 << $frac_bits,
15 };
16
17 pub const fn from_epsilons(epsilons: $epsilons_type) -> $name {
18 $name { epsilons: epsilons }
19 }
20
21 pub fn from_value(value: $value_type) -> $name {
22 let epsilons: $epsilons_type = (value * ((1 << $frac_bits) as $value_type)) as $epsilons_type;
24 $name { epsilons: epsilons }
25 }
26 }
27
28 impl From<$name> for $value_type {
29 fn from(fixed: $name) -> $value_type {
30 (fixed.epsilons as $value_type) / ((1 << $frac_bits) as $value_type)
31 }
32 }
33
34 impl ::std::ops::Add<$name> for $name {
35 type Output = $name;
36
37 fn add(self, rhs: $name) -> $name {
38 &self + &rhs
39 }
40 }
41
42 impl<'a, 'b> ::std::ops::Add<&'b $name> for &'a $name {
43 type Output = $name;
44
45 fn add(self, rhs: &'b $name) -> $name {
46 $name {
47 epsilons: self.epsilons + rhs.epsilons,
48 }
49 }
50 }
51
52 impl ::std::ops::AddAssign<$name> for $name {
53 fn add_assign(&mut self, rhs: $name) -> () {
54 self.add_assign(&rhs)
55 }
56 }
57
58 impl<'a> ::std::ops::AddAssign<&'a $name> for $name {
59 fn add_assign(&mut self, rhs: &'a $name) -> () {
60 self.epsilons.add_assign(rhs.epsilons)
61 }
62 }
63
64 #[cfg(feature = "serde")]
65 impl Serialize for $name {
66 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
67 where
68 S: Serializer,
69 {
70 self.epsilons.serialize(serializer)
71 }
72 }
73
74 #[cfg(feature = "serde")]
75 impl<'a> Deserialize<'a> for $name {
76 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
77 where
78 D: Deserializer<'a>,
79 {
80 Ok($name::from_epsilons(<$epsilons_type>::deserialize(deserializer)?))
81 }
82 }
83 };
84}
85
86fixed_point_impl!(Sfixed8P8, 8, 8, i16, f32);
87fixed_point_impl!(Sfixed16P16, 16, 16, i32, f64);
88fixed_point_impl!(Ufixed8P8, 8, 8, u16, f32);
89fixed_point_impl!(Ufixed16P16, 16, 16, u32, f64);
90
91#[cfg(test)]
92mod tests {
93 #[cfg(feature = "serde")]
94 use serde_json;
95
96 use crate::{Sfixed16P16, Sfixed8P8, Ufixed16P16, Ufixed8P8};
97
98 #[test]
99 fn test_eq() {
100 assert_eq!(Sfixed16P16::from_epsilons(3), Sfixed16P16::from_epsilons(3));
101 }
102
103 #[test]
104 fn test_default() {
105 const DEFAULT_SFIXED16P16: Sfixed16P16 = Sfixed16P16::from_epsilons(0);
106 const DEFAULT_SFIXED8P8: Sfixed8P8 = Sfixed8P8::from_epsilons(0);
107 const DEFAULT_UFIXED16P16: Ufixed16P16 = Ufixed16P16::from_epsilons(0);
108 const DEFAULT_UFIXED8P8: Ufixed8P8 = Ufixed8P8::from_epsilons(0);
109 assert_eq!(Sfixed16P16::default(), DEFAULT_SFIXED16P16);
110 assert_eq!(Sfixed8P8::default(), DEFAULT_SFIXED8P8);
111 assert_eq!(Ufixed16P16::default(), DEFAULT_UFIXED16P16);
112 assert_eq!(Ufixed8P8::default(), DEFAULT_UFIXED8P8);
113 }
114
115 #[test]
116 fn test_zero() {
117 assert_eq!(Sfixed16P16::ZERO, Sfixed16P16::from_epsilons(0));
118 assert_eq!(Sfixed8P8::ZERO, Sfixed8P8::from_epsilons(0));
119 assert_eq!(Ufixed16P16::ZERO, Ufixed16P16::from_epsilons(0));
120 assert_eq!(Ufixed8P8::ZERO, Ufixed8P8::from_epsilons(0));
121 }
122
123 #[test]
124 fn test_one() {
125 assert_eq!(Sfixed16P16::ONE, Sfixed16P16::from_epsilons(65536));
126 assert_eq!(Sfixed8P8::ONE, Sfixed8P8::from_epsilons(256));
127 assert_eq!(Ufixed16P16::ONE, Ufixed16P16::from_epsilons(65536));
128 assert_eq!(Ufixed8P8::ONE, Ufixed8P8::from_epsilons(256));
129 }
130
131 #[test]
132 #[cfg(feature = "serde")]
133 fn test_json_serde_serialization() {
134 assert_eq!(serde_json::to_string(&Sfixed16P16::from_epsilons(3)).unwrap(), "3");
135 }
136
137 #[test]
138 #[cfg(feature = "serde")]
139 fn test_json_serde_deserialization() {
140 assert_eq!(
141 serde_json::from_str::<Sfixed16P16>("0").unwrap(),
142 Sfixed16P16::from_epsilons(0)
143 );
144 assert_eq!(
145 serde_json::from_str::<Sfixed16P16>("3").unwrap(),
146 Sfixed16P16::from_epsilons(3)
147 );
148 assert_eq!(
149 serde_json::from_str::<Sfixed16P16>("65536").unwrap(),
150 Sfixed16P16::from_epsilons(65_536)
151 );
152 assert_eq!(
153 serde_json::from_str::<Sfixed16P16>("2147483647").unwrap(),
154 Sfixed16P16::from_epsilons(2_147_483_647)
155 );
156 assert_eq!(
157 serde_json::from_str::<Sfixed16P16>("-2147483648").unwrap(),
158 Sfixed16P16::from_epsilons(-2_147_483_648)
159 );
160 }
161
162 #[test]
163 fn test_ufixed8p8() {
164 assert_eq!(Ufixed8P8::from_value(24f32).epsilons, 6144);
165 }
166
167 #[test]
168 fn test_ufixed8p8_value() {
169 assert_eq!(
170 f32::from(Ufixed8P8::from_value(24f32)).to_ne_bytes(),
171 24f32.to_ne_bytes()
172 );
173 assert_eq!(
174 f32::from(Ufixed8P8::from_value(255f32)).to_ne_bytes(),
175 255f32.to_ne_bytes()
176 );
177 }
178
179 #[test]
180 fn test_sfixed8p8_value() {
181 assert_eq!(
182 f32::from(Sfixed8P8::from_value(-24f32)).to_ne_bytes(),
183 (-24f32).to_ne_bytes()
184 );
185 }
186
187 #[test]
188 fn test_ufixed16p16_value() {
189 assert_eq!(
190 f64::from(Ufixed16P16::from_value(1000f64)).to_ne_bytes(),
191 1000f64.to_ne_bytes()
192 );
193 }
194
195 #[test]
196 fn test_add_ufixed8p8() {
197 assert_eq!(
198 Ufixed8P8::from_value(0f32) + Ufixed8P8::from_value(0f32),
199 Ufixed8P8::from_value(0f32)
200 );
201 assert_eq!(
202 Ufixed8P8::from_value(0f32) + Ufixed8P8::from_value(1f32),
203 Ufixed8P8::from_value(1f32)
204 );
205 assert_eq!(
206 Ufixed8P8::from_value(1f32) + Ufixed8P8::from_value(0f32),
207 Ufixed8P8::from_value(1f32)
208 );
209 assert_eq!(
210 Ufixed8P8::from_value(1f32) + Ufixed8P8::from_value(1f32),
211 Ufixed8P8::from_value(2f32)
212 );
213 assert_eq!(
214 Ufixed8P8::from_value(0.5f32) + Ufixed8P8::from_value(0.5f32),
215 Ufixed8P8::from_value(1f32)
216 );
217 }
218
219 #[test]
220 fn test_add_ufixed8p8_ref() {
221 assert_eq!(
222 Ufixed8P8::from_value(0f32) + Ufixed8P8::from_value(0f32),
223 Ufixed8P8::from_value(0f32)
224 );
225 assert_eq!(
226 Ufixed8P8::from_value(0f32) + Ufixed8P8::from_value(1f32),
227 Ufixed8P8::from_value(1f32)
228 );
229 assert_eq!(
230 Ufixed8P8::from_value(1f32) + Ufixed8P8::from_value(0f32),
231 Ufixed8P8::from_value(1f32)
232 );
233 assert_eq!(
234 Ufixed8P8::from_value(1f32) + Ufixed8P8::from_value(1f32),
235 Ufixed8P8::from_value(2f32)
236 );
237 assert_eq!(
238 Ufixed8P8::from_value(0.5f32) + Ufixed8P8::from_value(0.5f32),
239 Ufixed8P8::from_value(1f32)
240 );
241 }
242}