1use core::fmt;
2
3#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
15#[repr(transparent)]
16pub struct U64Id(pub u64);
17
18impl U64Id {
19 pub const NULL: U64Id = U64Id(u64::MAX);
22
23 pub const VALID_RANGE: core::ops::Range<u64> = 0..(u64::MAX - 128);
29
30 #[cfg(feature = "rand")]
35 pub fn new() -> Self {
36 use rand::Rng;
37
38 Self(rand::rng().random_range(Self::VALID_RANGE))
39 }
40
41 pub const fn is_null(self) -> bool {
43 self.0 == u64::MAX
44 }
45}
46
47#[cfg(feature = "rand")]
48impl Default for U64Id {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54impl fmt::Display for U64Id {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 write!(f, "{:x}", self.0)
57 }
58}
59impl fmt::LowerHex for U64Id {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 let val = self.0;
62
63 fmt::LowerHex::fmt(&val, f)
64 }
65}
66impl fmt::UpperHex for U64Id {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 let val = self.0;
69
70 fmt::UpperHex::fmt(&val, f)
71 }
72}
73
74impl std::str::FromStr for U64Id {
75 type Err = std::num::ParseIntError;
76
77 fn from_str(s: &str) -> Result<Self, Self::Err> {
78 u64::from_str_radix(s, 16).map(Self)
79 }
80}
81
82#[cfg(feature = "serde")]
83impl serde::Serialize for U64Id {
84 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
85 where
86 S: serde::Serializer,
87 {
88 serializer.serialize_str(&format!("{:x}", self.0))
90 }
91}
92
93#[cfg(feature = "serde")]
94impl<'de> serde::Deserialize<'de> for U64Id {
95 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
96 where
97 D: serde::Deserializer<'de>,
98 {
99 struct AssetIdVisitor;
100 impl<'de> serde::de::Visitor<'de> for AssetIdVisitor {
101 type Value = u64;
102
103 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
104 formatter.write_str("a hex-encoded integer between 0 and 2^64 - 1")
105 }
106
107 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
108 where
109 E: serde::de::Error,
110 {
111 u64::from_str_radix(v, 16).map_err(|_| {
112 serde::de::Error::invalid_value(serde::de::Unexpected::Str(v), &self)
113 })
114 }
115
116 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
118 where
119 E: serde::de::Error,
120 {
121 u64::from_str_radix(&v.to_string(), 16).map_err(|_| {
122 serde::de::Error::invalid_value(serde::de::Unexpected::Unsigned(v), &self)
123 })
124 }
125
126 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
128 where
129 E: serde::de::Error,
130 {
131 u64::from_str_radix(&v.to_string(), 16).map_err(|_| {
132 serde::de::Error::invalid_value(serde::de::Unexpected::Signed(v), &self)
133 })
134 }
135 }
136
137 if deserializer.is_human_readable() {
138 deserializer.deserialize_any(AssetIdVisitor).map(U64Id)
139 } else {
140 deserializer.deserialize_str(AssetIdVisitor).map(U64Id)
141 }
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 #[test]
150 fn null_tests() {
151 let asset = U64Id::NULL;
152 assert!(asset.is_null());
153 }
154
155 #[cfg(feature = "serde")]
156 #[test]
157 fn basic_serde() {
158 assert_eq!(
159 serde_json::from_str::<U64Id>("12345").unwrap(),
160 U64Id(74565)
161 );
162
163 assert_eq!(
164 serde_json::from_str::<U64Id>("\"a12b345\"").unwrap(),
165 U64Id(168997701)
166 );
167 }
168
169 #[cfg(feature = "serde")]
170 #[test]
171 fn serde_cycle() {
172 let input = "\"123454321\"";
173 let output = serde_json::from_str::<U64Id>(input).unwrap();
174 let input_again = serde_json::to_string(&output).unwrap();
175
176 assert_eq!(input, input_again);
177 }
178
179 #[cfg(feature = "serde")]
180 #[test]
181 fn serde_cycle_around() {
182 let input = U64Id(12345321);
183 let output = serde_json::to_string::<U64Id>(&input).unwrap();
184 let input_again = serde_json::from_str(&output).unwrap();
185
186 assert_eq!(input, input_again);
187 }
188}