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