1use std::{fmt, num::ParseIntError};
2
3#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
5pub struct Integer {
6 value: i128,
7}
8
9impl Integer {
10 pub fn as_signed(self) -> Option<i64> {
12 if self.value >= i128::from(i64::min_value()) && self.value <= i128::from(i64::max_value())
13 {
14 Some(self.value as i64)
15 } else {
16 None
17 }
18 }
19
20 pub fn as_unsigned(self) -> Option<u64> {
22 if self.value >= 0 && self.value <= i128::from(u64::max_value()) {
23 Some(self.value as u64)
24 } else {
25 None
26 }
27 }
28
29 pub(crate) fn from_str(s: &str) -> Result<Self, ParseIntError> {
30 if s.starts_with("0x") {
31 let s = s.trim_start_matches("0x");
35 u64::from_str_radix(s, 16).map(Into::into)
36 } else {
37 Ok(match s.parse::<i64>() {
40 Ok(v) => v.into(),
41 Err(_) => s.parse::<u64>()?.into(),
42 })
43 }
44 }
45}
46
47impl fmt::Debug for Integer {
48 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49 self.value.fmt(f)
50 }
51}
52
53impl fmt::Display for Integer {
54 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55 self.value.fmt(f)
56 }
57}
58
59impl From<i64> for Integer {
60 fn from(value: i64) -> Integer {
61 Integer {
62 value: value.into(),
63 }
64 }
65}
66
67impl From<i32> for Integer {
68 fn from(value: i32) -> Integer {
69 Integer {
70 value: value.into(),
71 }
72 }
73}
74
75impl From<i16> for Integer {
76 fn from(value: i16) -> Integer {
77 Integer {
78 value: value.into(),
79 }
80 }
81}
82
83impl From<i8> for Integer {
84 fn from(value: i8) -> Integer {
85 Integer {
86 value: value.into(),
87 }
88 }
89}
90
91impl From<u64> for Integer {
92 fn from(value: u64) -> Integer {
93 Integer {
94 value: value.into(),
95 }
96 }
97}
98
99impl From<u32> for Integer {
100 fn from(value: u32) -> Integer {
101 Integer {
102 value: value.into(),
103 }
104 }
105}
106
107impl From<u16> for Integer {
108 fn from(value: u16) -> Integer {
109 Integer {
110 value: value.into(),
111 }
112 }
113}
114
115impl From<u8> for Integer {
116 fn from(value: u8) -> Integer {
117 Integer {
118 value: value.into(),
119 }
120 }
121}
122
123#[cfg(feature = "serde")]
124pub mod serde_impls {
125 use serde::{
126 de::{Deserialize, Deserializer, Error, Visitor},
127 ser::{Serialize, Serializer},
128 };
129 use std::fmt;
130
131 use crate::Integer;
132
133 impl Serialize for Integer {
134 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
135 where
136 S: Serializer,
137 {
138 if let Some(v) = self.as_unsigned() {
139 serializer.serialize_u64(v)
140 } else if let Some(v) = self.as_signed() {
141 serializer.serialize_i64(v)
142 } else {
143 unreachable!();
144 }
145 }
146 }
147
148 struct IntegerVisitor;
149
150 impl<'de> Visitor<'de> for IntegerVisitor {
151 type Value = Integer;
152
153 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
154 formatter.write_str("a plist integer")
155 }
156
157 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
158 where
159 E: Error,
160 {
161 Ok(Integer::from(v))
162 }
163
164 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
165 where
166 E: Error,
167 {
168 Ok(Integer::from(v))
169 }
170 }
171
172 impl<'de> Deserialize<'de> for Integer {
173 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
174 where
175 D: Deserializer<'de>,
176 {
177 deserializer.deserialize_any(IntegerVisitor)
178 }
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::Integer;
185
186 #[test]
187 fn from_str_limits() {
188 assert_eq!(Integer::from_str("-1"), Ok((-1).into()));
189 assert_eq!(Integer::from_str("0"), Ok(0.into()));
190 assert_eq!(Integer::from_str("1"), Ok(1.into()));
191 assert_eq!(
192 Integer::from_str("-9223372036854775808"),
193 Ok((-9223372036854775808i64).into())
194 );
195 assert!(Integer::from_str("-9223372036854775809").is_err());
196 assert_eq!(
197 Integer::from_str("18446744073709551615"),
198 Ok(18446744073709551615u64.into())
199 );
200 assert!(Integer::from_str("18446744073709551616").is_err());
201 }
202}