double_int/lib.rs
1//! The double-int format represents an integer that can be stored in an IEEE 754 double-precision
2//! number without loss of precision.
3//!
4//! This crate has been designed for use with OpenAPI tooling that wish to support integer-based
5//! `format: double-int` fields. [See docs in the OpenAPI format registry.][reg_double_int]
6//!
7//! # Examples
8//!
9//! ```
10//! # use double_int::DoubleInt;
11//! #[derive(Debug, serde::Deserialize)]
12//! struct Config {
13//! count: DoubleInt,
14//! }
15//!
16//! let config = toml::from_str::<Config>(r#"
17//! count = 42
18//! "#).unwrap();
19//! assert_eq!(config.count, 42);
20//!
21//! let config = toml::from_str::<Config>(r#"
22//! count = -42
23//! "#).unwrap();
24//! assert_eq!(config.count, -42);
25//!
26//! // count is outside the bounds of a double-int (> 2^53 in this case)
27//! // (this would usually be accepted by an i64)
28//! let config = toml::from_str::<Config>(r#"
29//! count = 36028797018963968
30//! "#).unwrap_err();
31//! ```
32//!
33//! [reg_double_int]: https://spec.openapis.org/registry/format/double-int
34
35#![no_std]
36#![deny(rust_2018_idioms, nonstandard_style, future_incompatible)]
37#![cfg_attr(docsrs, feature(doc_auto_cfg))]
38
39use serde_core::{de, Deserialize, Deserializer, Serialize, Serializer};
40
41/// Type that only deserializes from the `true` boolean value.
42///
43/// # Examples
44///
45/// ```
46/// assert_eq!(
47/// serde_json::from_str::<double_int::DoubleInt>("42").unwrap(),
48/// 42,
49/// );
50///
51/// serde_json::from_str::<double_int::DoubleInt>("4.2").unwrap_err();
52/// serde_json::from_str::<double_int::DoubleInt>("36028797018963968").unwrap_err();
53/// ```
54#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
55pub struct DoubleInt(i64);
56
57impl DoubleInt {
58 const MIN: i128 = -(2_i128.pow(53)) + 1;
59 const MAX: i128 = 2_i128.pow(53) - 1;
60 const UMAX: u128 = 2_u128.pow(53) - 1;
61
62 /// Returns value as a standard type.
63 pub const fn as_i64(self) -> i64 {
64 self.0
65 }
66}
67
68macro_rules! from_impl {
69 ($ty:ty) => {
70 impl From<$ty> for DoubleInt {
71 fn from(val: $ty) -> Self {
72 Self(val as i64)
73 }
74 }
75 };
76}
77
78from_impl!(u8);
79from_impl!(u16);
80from_impl!(u32);
81from_impl!(i8);
82from_impl!(i16);
83from_impl!(i32);
84
85macro_rules! infallible_eq_impls {
86 ($ty:ty) => {
87 impl PartialEq<$ty> for DoubleInt {
88 fn eq(&self, val: &$ty) -> bool {
89 self.0 == *val as i64
90 }
91 }
92 };
93}
94
95infallible_eq_impls!(u8);
96infallible_eq_impls!(u16);
97infallible_eq_impls!(u32);
98infallible_eq_impls!(i8);
99infallible_eq_impls!(i16);
100infallible_eq_impls!(i32);
101
102impl PartialEq<u64> for DoubleInt {
103 fn eq(&self, val: &u64) -> bool {
104 match *val as u128 {
105 // self cannot be larger than UMAX so val is not equal
106 DoubleInt::UMAX.. => false,
107
108 // all remaining u64s would be representable by i64
109 // just cast and check equality
110 _ => self.0 == *val as i64,
111 }
112 }
113}
114
115impl PartialEq<u128> for DoubleInt {
116 fn eq(&self, val: &u128) -> bool {
117 match val {
118 // self cannot be larger than UMAX so val is not equal
119 DoubleInt::UMAX.. => false,
120
121 // all remaining u64s would be representable by i64
122 // just cast and check equality
123 _ => self.0 == *val as i64,
124 }
125 }
126}
127
128impl PartialEq<i64> for DoubleInt {
129 fn eq(&self, val: &i64) -> bool {
130 self.0 == *val
131 }
132}
133
134impl PartialEq<i128> for DoubleInt {
135 fn eq(&self, val: &i128) -> bool {
136 match val {
137 // self cannot be larger than UMAX so val is not equal
138 DoubleInt::MAX.. => false,
139
140 // all remaining u64s would be representable by i64
141 // just cast and check equality
142 _ => self.0 == *val as i64,
143 }
144 }
145}
146
147impl<'de> Deserialize<'de> for DoubleInt {
148 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
149 match i64::deserialize(deserializer) {
150 Err(err) => Err(err),
151
152 Ok(val) if (val as i128) < DoubleInt::MIN => Err(de::Error::invalid_value(
153 de::Unexpected::Signed(val),
154 &"integer larger than -9007199254740991 / -(2^53) + 1",
155 )),
156
157 Ok(val) if (val as i128) > DoubleInt::MAX => Err(de::Error::invalid_value(
158 de::Unexpected::Signed(val),
159 &"integer smaller than 9007199254740991 / (2^53) - 1",
160 )),
161
162 Ok(val) => Ok(DoubleInt(val)),
163 }
164 }
165}
166
167impl Serialize for DoubleInt {
168 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
169 serializer.serialize_i64(self.0)
170 }
171}
172
173// #[cfg(test)]
174// mod tests {
175// use super::*;
176
177// #[derive(Debug, Deserialize, PartialEq)]
178// struct Tru {
179// foo: DoubleInt,
180// }
181
182// #[test]
183// fn de_true() {
184// assert_eq!(
185// Tru { foo: DoubleInt },
186// serde_json::from_str::<Tru>(r#"{"foo": true}"#).unwrap(),
187// );
188
189// serde_json::from_str::<Tru>(r#"{"foo": false}"#).unwrap_err();
190// serde_json::from_str::<Tru>(r#"{"foo": 42}"#).unwrap_err();
191// }
192
193// #[derive(Debug, Deserialize, PartialEq)]
194// struct Fal {
195// foo: False,
196// }
197
198// #[test]
199// fn de_false() {
200// assert_eq!(
201// Fal { foo: False },
202// serde_json::from_str::<Fal>(r#"{"foo": false}"#).unwrap(),
203// );
204
205// serde_json::from_str::<Fal>(r#"{"foo": true}"#).unwrap_err();
206// serde_json::from_str::<Fal>(r#"{"foo": 42}"#).unwrap_err();
207// }
208
209// #[test]
210// fn ser() {
211// assert_eq!("true", serde_json::to_string(&DoubleInt).unwrap());
212// assert_eq!("false", serde_json::to_string(&False).unwrap());
213// }
214
215// #[test]
216// fn as_bool() {
217// assert!(DoubleInt.as_bool());
218// assert!(!False.as_bool());
219// }
220
221// #[test]
222// fn from() {
223// assert!(bool::from(DoubleInt));
224// assert!(!bool::from(False));
225// }
226
227// #[test]
228// fn eq() {
229// assert_eq!(DoubleInt, DoubleInt);
230// assert_eq!(DoubleInt, true);
231// assert_eq!(true, DoubleInt);
232// assert_eq!(False, False);
233// assert_eq!(False, false);
234// assert_eq!(false, False);
235
236// assert_ne!(DoubleInt, False);
237// assert_ne!(DoubleInt, false);
238// assert_ne!(False, DoubleInt);
239// assert_ne!(false, DoubleInt);
240
241// assert_ne!(False, DoubleInt);
242// assert_ne!(False, true);
243// assert_ne!(DoubleInt, False);
244// assert_ne!(true, False);
245// }
246
247// #[test]
248// fn formatting() {
249// let _ = format_args!("{:?}", DoubleInt);
250// let _ = format_args!("{:?}", False);
251// }
252
253// #[test]
254// fn other_implementations() {
255// #![allow(clippy::default_constructed_unit_structs)]
256
257// assert_eq!(DoubleInt.clone(), DoubleInt);
258// assert_eq!(False.clone(), False);
259
260// assert_eq!(DoubleInt::default(), DoubleInt);
261// assert_eq!(False::default(), False);
262// }
263// }