conjure_object/
safe_long.rs1use serde::{de, ser};
17use std::convert::{TryFrom, TryInto};
18use std::error::Error;
19use std::fmt;
20use std::num::{ParseIntError, TryFromIntError};
21use std::ops::Deref;
22use std::str::FromStr;
23
24#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
34pub struct SafeLong(i64);
35
36impl SafeLong {
37 #[inline]
39 pub fn min_value() -> SafeLong {
40 SafeLong(-(1 << 53) + 1)
41 }
42
43 #[inline]
45 pub fn max_value() -> SafeLong {
46 SafeLong((1 << 53) - 1)
47 }
48
49 #[inline]
53 pub fn new(value: i64) -> Result<SafeLong, BoundsError> {
54 if value >= *SafeLong::min_value() && value <= *SafeLong::max_value() {
55 Ok(SafeLong(value))
56 } else {
57 Err(BoundsError(()))
58 }
59 }
60}
61
62impl Deref for SafeLong {
63 type Target = i64;
64
65 #[inline]
66 fn deref(&self) -> &i64 {
67 &self.0
68 }
69}
70
71impl fmt::Display for SafeLong {
72 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
73 fmt::Display::fmt(&self.0, fmt)
74 }
75}
76
77impl FromStr for SafeLong {
78 type Err = ParseError;
79
80 #[inline]
81 fn from_str(s: &str) -> Result<SafeLong, ParseError> {
82 let n = s
83 .parse()
84 .map_err(|e| ParseError(ParseErrorInner::Parse(e)))?;
85
86 SafeLong::new(n).map_err(|e| ParseError(ParseErrorInner::Bounds(e)))
87 }
88}
89
90impl ser::Serialize for SafeLong {
91 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
92 where
93 S: ser::Serializer,
94 {
95 s.serialize_i64(self.0)
96 }
97}
98
99impl<'de> de::Deserialize<'de> for SafeLong {
100 fn deserialize<D>(d: D) -> Result<SafeLong, D::Error>
101 where
102 D: de::Deserializer<'de>,
103 {
104 let value = i64::deserialize(d)?;
105 SafeLong::new(value)
106 .map_err(|_| de::Error::invalid_value(de::Unexpected::Signed(value), &"a safe long"))
107 }
108}
109
110macro_rules! impl_from {
111 ($($t:ty),*) => {
112 $(
113 impl From<$t> for SafeLong {
114 #[inline]
115 fn from(n: $t) -> SafeLong {
116 SafeLong(i64::from(n))
117 }
118 }
119 )*
120 }
121}
122
123impl_from!(u8, i8, u16, i16, u32, i32);
124
125macro_rules! impl_into {
126 ($($t:ty),*) => {
127 $(
128 impl From<SafeLong> for $t {
129 #[inline]
130 fn from(n: SafeLong) -> $t {
131 n.0.into()
132 }
133 }
134 )*
135 }
136}
137
138impl_into!(i64, i128);
139
140macro_rules! impl_try_from {
141 ($($t:ty),*) => {
142 $(
143 impl TryFrom<$t> for SafeLong {
144 type Error = BoundsError;
145
146 #[inline]
147 fn try_from(n: $t) -> Result<SafeLong, BoundsError> {
148 i64::try_from(n)
149 .map_err(|_| BoundsError(()))
150 .and_then(SafeLong::new)
151 }
152 }
153 )*
154 }
155}
156
157impl_try_from!(u64, i64, u128, i128, usize, isize);
158
159macro_rules! impl_try_into {
160 ($($t:ty),*) => {
161 $(
162 impl TryFrom<SafeLong> for $t {
163 type Error = TryFromIntError;
164
165 #[inline]
166 fn try_from(n: SafeLong) -> Result<$t, TryFromIntError> {
167 n.0.try_into()
168 }
169 }
170 )*
171 };
172}
173
174impl_try_into!(u8, i8, u16, i16, u32, i32, u64, u128, usize, isize);
175
176#[derive(Debug, Clone)]
178pub struct BoundsError(());
179
180impl fmt::Display for BoundsError {
181 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
182 fmt.write_str("value was out of bounds of a safe long")
183 }
184}
185
186impl Error for BoundsError {}
187
188#[derive(Debug, Clone)]
189enum ParseErrorInner {
190 Parse(ParseIntError),
191 Bounds(BoundsError),
192}
193
194#[derive(Debug, Clone)]
196pub struct ParseError(ParseErrorInner);
197
198impl fmt::Display for ParseError {
199 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
200 match &self.0 {
201 ParseErrorInner::Parse(e) => fmt::Display::fmt(e, fmt),
202 ParseErrorInner::Bounds(e) => fmt::Display::fmt(e, fmt),
203 }
204 }
205}
206
207impl Error for ParseError {}