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
74#[cfg(feature = "serde")]
75impl serde::Serialize for U64Id {
76 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
77 where
78 S: serde::Serializer,
79 {
80 serializer.serialize_str(&format!("{:x}", self.0))
82 }
83}
84
85#[cfg(feature = "serde")]
86impl<'de> serde::Deserialize<'de> for U64Id {
87 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
88 where
89 D: serde::Deserializer<'de>,
90 {
91 struct AssetIdVisitor;
92 impl<'de> serde::de::Visitor<'de> for AssetIdVisitor {
93 type Value = u64;
94
95 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
96 formatter.write_str("a hex-encoded integer between 0 and 2^64 - 1")
97 }
98
99 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
100 where
101 E: serde::de::Error,
102 {
103 u64::from_str_radix(v, 16).map_err(|_| {
104 serde::de::Error::invalid_value(serde::de::Unexpected::Str(v), &self)
105 })
106 }
107
108 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
110 where
111 E: serde::de::Error,
112 {
113 u64::from_str_radix(&v.to_string(), 16).map_err(|_| {
114 serde::de::Error::invalid_value(serde::de::Unexpected::Unsigned(v), &self)
115 })
116 }
117
118 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
120 where
121 E: serde::de::Error,
122 {
123 u64::from_str_radix(&v.to_string(), 16).map_err(|_| {
124 serde::de::Error::invalid_value(serde::de::Unexpected::Signed(v), &self)
125 })
126 }
127 }
128
129 if deserializer.is_human_readable() {
130 deserializer.deserialize_any(AssetIdVisitor).map(U64Id)
131 } else {
132 deserializer.deserialize_str(AssetIdVisitor).map(U64Id)
133 }
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn null_tests() {
143 let asset = U64Id::NULL;
144 assert!(asset.is_null());
145 }
146
147 #[cfg(feature = "serde")]
148 #[test]
149 fn basic_serde() {
150 assert_eq!(
151 serde_json::from_str::<U64Id>("12345").unwrap(),
152 U64Id(74565)
153 );
154
155 assert_eq!(
156 serde_json::from_str::<U64Id>("\"a12b345\"").unwrap(),
157 U64Id(168997701)
158 );
159 }
160
161 #[cfg(feature = "serde")]
162 #[test]
163 fn serde_cycle() {
164 let input = "\"123454321\"";
165 let output = serde_json::from_str::<U64Id>(input).unwrap();
166 let input_again = serde_json::to_string(&output).unwrap();
167
168 assert_eq!(input, input_again);
169 }
170
171 #[cfg(feature = "serde")]
172 #[test]
173 fn serde_cycle_around() {
174 let input = U64Id(12345321);
175 let output = serde_json::to_string::<U64Id>(&input).unwrap();
176 let input_again = serde_json::from_str(&output).unwrap();
177
178 assert_eq!(input, input_again);
179 }
180}