swf_fixed/
lib.rs

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        // TODO: Checked cast
23        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}