naia_shared/
wrapping_number.rs

1/// Returns whether or not a wrapping number is greater than another
2/// sequence_greater_than(2,1) will return true
3/// sequence_greater_than(1,2) will return false
4/// sequence_greater_than(1,1) will return false
5pub fn sequence_greater_than(s1: u16, s2: u16) -> bool {
6    ((s1 > s2) && (s1 - s2 <= 32768)) || ((s1 < s2) && (s2 - s1 > 32768))
7}
8
9/// Returns whether or not a wrapping number is greater than another
10/// sequence_less_than(1,2) will return true
11/// sequence_less_than(2,1) will return false
12/// sequence_less_than(1,1) will return false
13pub fn sequence_less_than(s1: u16, s2: u16) -> bool {
14    sequence_greater_than(s2, s1)
15}
16
17/// Retrieves the wrapping difference between 2 u16 values
18/// wrapping_diff(1,2) will return 1
19/// wrapping_diff(2,1) will return -1
20/// wrapping_diff(65535,0) will return 1
21/// wrapping_diff(0,65535) will return -1
22pub fn wrapping_diff(a: u16, b: u16) -> i16 {
23    const MAX: i32 = std::i16::MAX as i32;
24    const MIN: i32 = std::i16::MIN as i32;
25    const ADJUST: i32 = (std::u16::MAX as i32) + 1;
26
27    let a: i32 = i32::from(a);
28    let b: i32 = i32::from(b);
29
30    let mut result = b - a;
31    if (MIN..=MAX).contains(&result) {
32        result as i16
33    } else if b > a {
34        result = b - (a + ADJUST);
35        if (MIN..=MAX).contains(&result) {
36            result as i16
37        } else {
38            panic!("integer overflow, this shouldn't happen")
39        }
40    } else {
41        result = (b + ADJUST) - a;
42        if (MIN..=MAX).contains(&result) {
43            result as i16
44        } else {
45            panic!("integer overflow, this shouldn't happen")
46        }
47    }
48}
49
50#[cfg(test)]
51mod sequence_compare_tests {
52    use super::{sequence_greater_than, sequence_less_than};
53
54    #[test]
55    fn greater_is_greater() {
56        assert!(sequence_greater_than(2, 1));
57    }
58
59    #[test]
60    fn greater_is_not_equal() {
61        assert!(!sequence_greater_than(2, 2));
62    }
63
64    #[test]
65    fn greater_is_not_less() {
66        assert!(!sequence_greater_than(1, 2));
67    }
68
69    #[test]
70    fn less_is_less() {
71        assert!(sequence_less_than(1, 2));
72    }
73
74    #[test]
75    fn less_is_not_equal() {
76        assert!(!sequence_less_than(2, 2));
77    }
78
79    #[test]
80    fn less_is_not_greater() {
81        assert!(!sequence_less_than(2, 1));
82    }
83}
84
85#[cfg(test)]
86mod wrapping_diff_tests {
87    use super::wrapping_diff;
88
89    #[test]
90    fn simple() {
91        let a: u16 = 10;
92        let b: u16 = 12;
93
94        let result = wrapping_diff(a, b);
95
96        assert_eq!(result, 2);
97    }
98
99    #[test]
100    fn simple_backwards() {
101        let a: u16 = 10;
102        let b: u16 = 12;
103
104        let result = wrapping_diff(b, a);
105
106        assert_eq!(result, -2);
107    }
108
109    #[test]
110    fn max_wrap() {
111        let a: u16 = std::u16::MAX;
112        let b: u16 = a.wrapping_add(2);
113
114        let result = wrapping_diff(a, b);
115
116        assert_eq!(result, 2);
117    }
118
119    #[test]
120    fn min_wrap() {
121        let a: u16 = 0;
122        let b: u16 = a.wrapping_sub(2);
123
124        let result = wrapping_diff(a, b);
125
126        assert_eq!(result, -2);
127    }
128
129    #[test]
130    fn max_wrap_backwards() {
131        let a: u16 = std::u16::MAX;
132        let b: u16 = a.wrapping_add(2);
133
134        let result = wrapping_diff(b, a);
135
136        assert_eq!(result, -2);
137    }
138
139    #[test]
140    fn min_wrap_backwards() {
141        let a: u16 = 0;
142        let b: u16 = a.wrapping_sub(2);
143
144        let result = wrapping_diff(b, a);
145
146        assert_eq!(result, 2);
147    }
148
149    #[test]
150    fn medium_min_wrap() {
151        let diff: u16 = std::u16::MAX / 2;
152        let a: u16 = 0;
153        let b: u16 = a.wrapping_sub(diff);
154
155        let result = i32::from(wrapping_diff(a, b));
156
157        assert_eq!(result, -i32::from(diff));
158    }
159
160    #[test]
161    fn medium_min_wrap_backwards() {
162        let diff: u16 = std::u16::MAX / 2;
163        let a: u16 = 0;
164        let b: u16 = a.wrapping_sub(diff);
165
166        let result = i32::from(wrapping_diff(b, a));
167
168        assert_eq!(result, i32::from(diff));
169    }
170
171    #[test]
172    fn medium_max_wrap() {
173        let diff: u16 = std::u16::MAX / 2;
174        let a: u16 = std::u16::MAX;
175        let b: u16 = a.wrapping_add(diff);
176
177        let result = i32::from(wrapping_diff(a, b));
178
179        assert_eq!(result, i32::from(diff));
180    }
181
182    #[test]
183    fn medium_max_wrap_backwards() {
184        let diff: u16 = std::u16::MAX / 2;
185        let a: u16 = std::u16::MAX;
186        let b: u16 = a.wrapping_add(diff);
187
188        let result = i32::from(wrapping_diff(b, a));
189
190        assert_eq!(result, -i32::from(diff));
191    }
192}