lightyear_utils/
wrapping_id.rs1pub trait WrappedId {
3 fn rem(&self, total: usize) -> usize;
6}
7
8pub use paste::paste;
9
10#[macro_export]
21macro_rules! wrapping_id {
22 ($struct_name:ident) => {
23 use lightyear_utils::wrapping_id::paste;
24 paste! {
25 mod [<$struct_name:lower _module>] {
26 use serde::{Deserialize, Serialize};
27 use core::ops::{Add, AddAssign, Deref, Sub};
28 use core::cmp::Ordering;
29 use bevy_reflect::Reflect;
30 use lightyear_serde::{SerializationError, reader::{Reader, ReadInteger}, writer::WriteInteger, ToBytes};
31 use lightyear_utils::wrapping_id::{wrapping_diff, WrappedId};
32
33 #[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, Hash, PartialEq, Default, Reflect
35 )]
36 pub struct $struct_name(pub u16);
37
38 impl ToBytes for $struct_name {
39 fn bytes_len(&self) -> usize {
40 2
41 }
42
43 fn to_bytes(&self, buffer: &mut impl WriteInteger) -> Result<(), SerializationError> {
44 Ok(buffer.write_u16(self.0)?)
45 }
46
47 fn from_bytes(buffer: &mut Reader) -> Result<Self, SerializationError>
48 where
49 Self: Sized,
50 {
51 Ok(Self(buffer.read_u16()?))
52 }
53 }
54
55 impl WrappedId for $struct_name {
56 fn rem(&self, total: usize) -> usize {
57 (self.0 as usize) % total
58 }
59 }
60
61 impl Deref for $struct_name {
63 type Target = u16;
64 fn deref(&self) -> &Self::Target {
65 &self.0
66 }
67 }
68
69 impl Ord for $struct_name {
70 fn cmp(&self, other: &Self) -> Ordering {
71 match wrapping_diff(self.0, other.0) {
72 0 => Ordering::Equal,
73 x if x > 0 => Ordering::Less,
74 x if x < 0 => Ordering::Greater,
75 _ => unreachable!(),
76 }
77 }
78 }
79
80 impl PartialOrd for $struct_name {
81 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
82 Some(self.cmp(other))
83 }
84 }
85
86 impl Sub for $struct_name {
87 type Output = i16;
88
89 fn sub(self, rhs: Self) -> Self::Output {
90 wrapping_diff(rhs.0, self.0)
91 }
92 }
93
94 impl Sub<u16> for $struct_name {
95 type Output = Self;
96
97 fn sub(self, rhs: u16) -> Self::Output {
98 Self(self.0.wrapping_sub(rhs))
101 }
102 }
103
104
105 impl Add for $struct_name {
106 type Output = Self;
107
108 fn add(self, rhs: Self) -> Self::Output {
109 Self(self.0.wrapping_add(rhs.0))
110 }
111 }
112
113 impl AddAssign<u16> for $struct_name {
114 fn add_assign(&mut self, rhs: u16) {
115 self.0 = self.0.wrapping_add(rhs);
116 }
117 }
118 impl Add<i16> for $struct_name {
127 type Output = Self;
128
129 fn add(self, rhs: i16) -> Self::Output {
130 Self(self.0.wrapping_add_signed(rhs))
131 }
132 }
133 }
134 pub use [<$struct_name:lower _module>]::$struct_name;
135 }
136 };
137}
138
139pub fn wrapping_diff(a: u16, b: u16) -> i16 {
154 b.wrapping_sub(a) as i16
155}
156
157#[cfg(test)]
158mod wrapping_diff_tests {
159 use super::wrapping_diff;
160
161 #[test]
162 fn simple() {
163 let a: u16 = 10;
164 let b: u16 = 12;
165
166 let result = wrapping_diff(a, b);
167
168 assert_eq!(result, 2);
169 }
170
171 #[test]
172 fn simple_backwards() {
173 let a: u16 = 10;
174 let b: u16 = 12;
175
176 let result = wrapping_diff(b, a);
177
178 assert_eq!(result, -2);
179 }
180
181 #[test]
182 fn max_wrap() {
183 let a: u16 = u16::MAX;
184 let b: u16 = a.wrapping_add(2);
185
186 let result = wrapping_diff(a, b);
187
188 assert_eq!(result, 2);
189 }
190
191 #[test]
192 fn min_wrap() {
193 let a: u16 = 0;
194 let b: u16 = a.wrapping_sub(2);
195
196 let result = wrapping_diff(a, b);
197
198 assert_eq!(result, -2);
199 }
200
201 #[test]
202 fn max_wrap_backwards() {
203 let a: u16 = u16::MAX;
204 let b: u16 = a.wrapping_add(2);
205
206 let result = wrapping_diff(b, a);
207
208 assert_eq!(result, -2);
209 }
210
211 #[test]
212 fn min_wrap_backwards() {
213 let a: u16 = 0;
214 let b: u16 = a.wrapping_sub(2);
215
216 let result = wrapping_diff(b, a);
217
218 assert_eq!(result, 2);
219 }
220
221 #[test]
222 fn medium_min_wrap() {
223 let diff: u16 = u16::MAX / 2;
224 let a: u16 = 0;
225 let b: u16 = a.wrapping_sub(diff);
226
227 let result = i32::from(wrapping_diff(a, b));
228
229 assert_eq!(result, -i32::from(diff));
230 }
231
232 #[test]
233 fn medium_min_wrap_backwards() {
234 let diff: u16 = u16::MAX / 2;
235 let a: u16 = 0;
236 let b: u16 = a.wrapping_sub(diff);
237
238 let result = i32::from(wrapping_diff(b, a));
239
240 assert_eq!(result, i32::from(diff));
241 }
242
243 #[test]
244 fn medium_max_wrap() {
245 let diff: u16 = u16::MAX / 2;
246 let a: u16 = u16::MAX;
247 let b: u16 = a.wrapping_add(diff);
248
249 let result = i32::from(wrapping_diff(a, b));
250
251 assert_eq!(result, i32::from(diff));
252 }
253
254 #[test]
255 fn medium_max_wrap_backwards() {
256 let diff: u16 = u16::MAX / 2;
257 let a: u16 = u16::MAX;
258 let b: u16 = a.wrapping_add(diff);
259
260 let result = i32::from(wrapping_diff(b, a));
261
262 assert_eq!(result, -i32::from(diff));
263 }
264}