1use std::{
2 hash::{Hash, Hasher},
3 num::TryFromIntError,
4};
5
6#[cfg(any(test, feature = "testing"))]
7use proptest::prelude::*;
8#[cfg(any(test, feature = "testing"))]
9use proptest_derive::Arbitrary;
10
11mod signed;
12mod unsigned;
13
14pub use self::{signed::SignedIntValue, unsigned::UnsignedIntValue};
15
16#[cfg_attr(any(test, feature = "testing"), derive(Arbitrary))]
18#[derive(Copy, Clone)]
19pub enum IntValue {
20 Signed(SignedIntValue),
22 Unsigned(UnsignedIntValue),
24}
25
26impl IntValue {
27 pub fn is_signed(&self) -> bool {
29 match self {
30 Self::Signed(_) => true,
31 Self::Unsigned(_) => false,
32 }
33 }
34}
35
36impl Default for IntValue {
37 fn default() -> Self {
38 Self::Unsigned(Default::default())
39 }
40}
41
42macro_rules! impl_int_value_from {
43 ($t:ty => $v:ident) => {
44 impl From<$t> for IntValue {
45 fn from(value: $t) -> Self {
46 Self::$v(value.into())
47 }
48 }
49 };
50}
51
52impl_int_value_from!(i8 => Signed);
53impl_int_value_from!(i16 => Signed);
54impl_int_value_from!(i32 => Signed);
55impl_int_value_from!(i64 => Signed);
56
57impl_int_value_from!(u8 => Unsigned);
58impl_int_value_from!(u16 => Unsigned);
59impl_int_value_from!(u32 => Unsigned);
60impl_int_value_from!(u64 => Unsigned);
61
62macro_rules! impl_int_value_from_size {
63 ($t:ty) => {
64 impl From<$t> for IntValue {
65 fn from(value: $t) -> Self {
66 match <$t>::BITS {
67 8 => Self::from(value as u8),
68 16 => Self::from(value as u16),
69 32 => Self::from(value as u32),
70 64 => Self::from(value as u64),
71 _ => unimplemented!(),
72 }
73 }
74 }
75 };
76}
77
78impl_int_value_from_size!(isize);
79impl_int_value_from_size!(usize);
80
81impl PartialEq for IntValue {
82 fn eq(&self, other: &Self) -> bool {
83 match (self, other) {
84 (Self::Signed(lhs), Self::Signed(rhs)) => lhs == rhs,
85 (Self::Signed(lhs), Self::Unsigned(rhs)) => {
86 let lhs = lhs.canonicalized();
87 let rhs = rhs.canonicalized();
88
89 if lhs.is_negative() {
90 false
91 } else {
92 (lhs as u64) == rhs
93 }
94 }
95 (Self::Unsigned(lhs), Self::Signed(rhs)) => {
96 let lhs = lhs.canonicalized();
97 let rhs = rhs.canonicalized();
98
99 if rhs.is_negative() {
100 false
101 } else {
102 lhs == (rhs as u64)
103 }
104 }
105 (Self::Unsigned(lhs), Self::Unsigned(rhs)) => lhs == rhs,
106 }
107 }
108}
109
110impl PartialOrd for IntValue {
111 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
112 Some(self.cmp(other))
113 }
114}
115
116impl Eq for IntValue {}
117
118impl Ord for IntValue {
119 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
120 match (self, other) {
121 (Self::Unsigned(lhs), Self::Unsigned(rhs)) => lhs.cmp(rhs),
122 (Self::Signed(lhs), Self::Signed(rhs)) => lhs.cmp(rhs),
123 (Self::Unsigned(lhs), Self::Signed(rhs)) => {
124 let lhs = lhs.canonicalized();
125 let rhs = rhs.canonicalized();
126 if rhs.is_negative() {
127 std::cmp::Ordering::Greater
128 } else {
129 lhs.cmp(&(rhs as u64))
130 }
131 }
132 (Self::Signed(lhs), Self::Unsigned(rhs)) => {
133 let lhs = lhs.canonicalized();
134 let rhs = rhs.canonicalized();
135 if lhs.is_negative() {
136 std::cmp::Ordering::Less
137 } else {
138 (lhs as u64).cmp(&rhs)
139 }
140 }
141 }
142 }
143}
144
145impl Hash for IntValue {
146 fn hash<H: Hasher>(&self, state: &mut H) {
147 match *self {
148 Self::Unsigned(value) => {
149 let value = value.canonicalized();
150 value.to_ne_bytes().hash(state)
151 }
152 Self::Signed(value) => {
153 let value = value.canonicalized();
154 if value.is_negative() {
155 value.to_ne_bytes().hash(state)
156 } else {
157 (value as u64).to_ne_bytes().hash(state)
158 }
159 }
160 }
161 }
162}
163
164impl std::fmt::Debug for IntValue {
165 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166 match self {
167 Self::Signed(value) => std::fmt::Debug::fmt(&value, f),
168 Self::Unsigned(value) => std::fmt::Debug::fmt(&value, f),
169 }
170 }
171}
172
173impl std::fmt::Display for IntValue {
174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175 match self {
176 Self::Signed(value) => std::fmt::Display::fmt(value, f),
177 Self::Unsigned(value) => std::fmt::Display::fmt(value, f),
178 }
179 }
180}
181
182#[cfg(feature = "serde")]
183impl serde::Serialize for IntValue {
184 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
185 where
186 S: serde::Serializer,
187 {
188 match self {
189 Self::Signed(value) => value.serialize(serializer),
190 Self::Unsigned(value) => value.serialize(serializer),
191 }
192 }
193}
194
195#[cfg(feature = "serde")]
196impl<'de> serde::Deserialize<'de> for IntValue {
197 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
198 where
199 D: serde::Deserializer<'de>,
200 {
201 struct ValueVisitor;
202
203 impl serde::de::Visitor<'_> for ValueVisitor {
204 type Value = IntValue;
205
206 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
207 formatter.write_str("integer value")
208 }
209
210 #[inline]
211 fn visit_i8<E>(self, value: i8) -> Result<Self::Value, E> {
212 Ok(value.into())
213 }
214
215 #[inline]
216 fn visit_i16<E>(self, value: i16) -> Result<Self::Value, E> {
217 Ok(value.into())
218 }
219
220 #[inline]
221 fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E> {
222 Ok(value.into())
223 }
224
225 #[inline]
226 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> {
227 Ok(value.into())
228 }
229
230 #[inline]
231 fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E> {
232 Ok(value.into())
233 }
234
235 #[inline]
236 fn visit_u16<E>(self, value: u16) -> Result<Self::Value, E> {
237 Ok(value.into())
238 }
239
240 #[inline]
241 fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E> {
242 Ok(value.into())
243 }
244
245 #[inline]
246 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
247 Ok(value.into())
248 }
249 }
250
251 deserializer.deserialize_any(ValueVisitor)
252 }
253}
254
255impl IntValue {
256 pub fn to_signed(self) -> Result<SignedIntValue, TryFromIntError> {
258 match self {
259 IntValue::Signed(signed) => Ok(signed),
260 IntValue::Unsigned(unsigned) => unsigned.to_signed(),
261 }
262 }
263
264 pub fn to_unsigned(self) -> Result<UnsignedIntValue, TryFromIntError> {
266 match self {
267 IntValue::Signed(signed) => signed.to_unsigned(),
268 IntValue::Unsigned(unsigned) => Ok(unsigned),
269 }
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use std::{cmp::Ordering, hash::RandomState};
276
277 use proptest::prelude::*;
278 use test_log::test;
279
280 use crate::{
281 config::EncoderConfig,
282 decoder::Decoder,
283 encoder::Encoder,
284 io::{SliceReader, VecWriter},
285 value::Value,
286 };
287
288 use super::*;
289
290 proptest! {
291 #[test]
292 fn eq(signed in i8::MIN..=i8::MAX, unsigned in u8::MIN..=u8::MAX) {
293 let signed_values = [
294 IntValue::from(signed),
295 IntValue::from(signed as i16),
296 IntValue::from(signed as i32),
297 IntValue::from(signed as i64),
298 ];
299
300 let unsigned_values = [
301 IntValue::from(unsigned),
302 IntValue::from(unsigned as u16),
303 IntValue::from(unsigned as u32),
304 IntValue::from(unsigned as u64),
305 ];
306
307 for lhs_value in &signed_values {
309 for rhs_value in &signed_values {
310 prop_assert_eq!(lhs_value, rhs_value);
311 prop_assert_eq!(rhs_value, lhs_value);
312 }
313 }
314
315 for lhs_value in &unsigned_values {
317 for rhs_value in &unsigned_values {
318 prop_assert_eq!(lhs_value, rhs_value);
319 prop_assert_eq!(rhs_value, lhs_value);
320 }
321 }
322
323 for lhs_value in &signed_values {
325 for rhs_value in &unsigned_values {
326 if u8::try_from(signed) == Ok(unsigned) {
327 prop_assert_eq!(lhs_value, rhs_value);
328 prop_assert_eq!(rhs_value, lhs_value);
329 } else {
330 prop_assert_ne!(lhs_value, rhs_value);
331 prop_assert_ne!(rhs_value, lhs_value);
332 }
333 }
334 }
335 }
336
337 #[test]
338 fn ord(signed in i8::MIN..=i8::MAX, unsigned in u8::MIN..=u8::MAX) {
339 let signed_values = [
340 IntValue::from(signed),
341 IntValue::from(signed as i16),
342 IntValue::from(signed as i32),
343 IntValue::from(signed as i64),
344 ];
345
346 let unsigned_values = [
347 IntValue::from(unsigned),
348 IntValue::from(unsigned as u16),
349 IntValue::from(unsigned as u32),
350 IntValue::from(unsigned as u64),
351 ];
352
353 for lhs_value in &signed_values {
355 for rhs_value in &signed_values {
356 let value_ordering = lhs_value.cmp(rhs_value);
357 prop_assert_eq!(value_ordering, Ordering::Equal);
358 }
359 }
360
361 for lhs_value in &unsigned_values {
363 for rhs_value in &unsigned_values {
364 let value_ordering = lhs_value.cmp(rhs_value);
365 prop_assert_eq!(value_ordering, Ordering::Equal);
366 }
367 }
368
369 for lhs_value in &signed_values {
371 for rhs_value in &unsigned_values {
372 let value_ordering = lhs_value.cmp(rhs_value);
373
374 if let Ok(positive) = u8::try_from(signed) {
375 let int_ordering = positive.cmp(&unsigned);
376 prop_assert_eq!(value_ordering, int_ordering);
377 } else {
378 prop_assert_eq!(value_ordering, Ordering::Less);
379 }
380 }
381 }
382 }
383
384 #[test]
385 fn hash(signed in i8::MIN..=i8::MAX, unsigned in u8::MIN..=u8::MAX) {
386 use std::hash::BuildHasher as _;
387
388 let signed_values = [
389 IntValue::from(signed),
390 IntValue::from(signed as i16),
391 IntValue::from(signed as i32),
392 IntValue::from(signed as i64),
393 ];
394
395 let unsigned_values = [
396 IntValue::from(unsigned),
397 IntValue::from(unsigned as u16),
398 IntValue::from(unsigned as u32),
399 IntValue::from(unsigned as u64),
400 ];
401
402 for lhs_value in &signed_values {
404 for rhs_value in &signed_values {
405 let build_hasher = RandomState::new();
406 let lhs_hash = build_hasher.hash_one(lhs_value);
407 let rhs_hash = build_hasher.hash_one(rhs_value);
408 prop_assert_eq!(lhs_hash, rhs_hash);
409 }
410 }
411
412 for lhs_value in &unsigned_values {
414 for rhs_value in &unsigned_values {
415 let build_hasher = RandomState::new();
416 let lhs_hash = build_hasher.hash_one(lhs_value);
417 let rhs_hash = build_hasher.hash_one(rhs_value);
418 prop_assert_eq!(lhs_hash, rhs_hash);
419 }
420 }
421 }
422 }
423
424 #[test]
425 fn display() {
426 assert_eq!(format!("{}", IntValue::from(42_u8)), "42");
427 assert_eq!(format!("{}", IntValue::from(42_u16)), "42");
428 assert_eq!(format!("{}", IntValue::from(42_u32)), "42");
429 assert_eq!(format!("{}", IntValue::from(42_u64)), "42");
430
431 assert_eq!(format!("{}", IntValue::from(42_i8)), "42");
432 assert_eq!(format!("{}", IntValue::from(42_i16)), "42");
433 assert_eq!(format!("{}", IntValue::from(42_i32)), "42");
434 assert_eq!(format!("{}", IntValue::from(42_i64)), "42");
435 }
436
437 #[test]
438 fn debug() {
439 assert_eq!(format!("{:?}", IntValue::from(42_u8)), "42");
440 assert_eq!(format!("{:?}", IntValue::from(42_u16)), "42");
441 assert_eq!(format!("{:?}", IntValue::from(42_u32)), "42");
442 assert_eq!(format!("{:?}", IntValue::from(42_u64)), "42");
443
444 assert_eq!(format!("{:?}", IntValue::from(42_i8)), "42");
445 assert_eq!(format!("{:?}", IntValue::from(42_i16)), "42");
446 assert_eq!(format!("{:?}", IntValue::from(42_i32)), "42");
447 assert_eq!(format!("{:?}", IntValue::from(42_i64)), "42");
448
449 assert_eq!(format!("{:#?}", IntValue::from(42_u8)), "42_u8");
450 assert_eq!(format!("{:#?}", IntValue::from(42_u16)), "42_u16");
451 assert_eq!(format!("{:#?}", IntValue::from(42_u32)), "42_u32");
452 assert_eq!(format!("{:#?}", IntValue::from(42_u64)), "42_u64");
453
454 assert_eq!(format!("{:#?}", IntValue::from(42_i8)), "42_i8");
455 assert_eq!(format!("{:#?}", IntValue::from(42_i16)), "42_i16");
456 assert_eq!(format!("{:#?}", IntValue::from(42_i32)), "42_i32");
457 assert_eq!(format!("{:#?}", IntValue::from(42_i64)), "42_i64");
458 }
459
460 proptest! {
461 #[test]
462 fn encode_decode_roundtrip(value in IntValue::arbitrary(), config in EncoderConfig::arbitrary()) {
463 let mut encoded: Vec<u8> = Vec::new();
464 let writer = VecWriter::new(&mut encoded);
465 let mut encoder = Encoder::new(writer, config);
466 encoder.encode_int_value(&value).unwrap();
467
468 prop_assert!(encoded.len() <= 1 + 8);
469
470 let reader = SliceReader::new(&encoded);
471 let mut decoder = Decoder::from_reader(reader);
472 let decoded = decoder.decode_int_value().unwrap();
473 prop_assert_eq!(&decoded, &value);
474
475 let reader = SliceReader::new(&encoded);
476 let mut decoder = Decoder::from_reader(reader);
477 let decoded = decoder.decode_value().unwrap();
478 let Value::Int(decoded) = decoded else {
479 panic!("expected int value");
480 };
481 prop_assert_eq!(&decoded, &value);
482 }
483 }
484}