extendable_assets/asset/
id.rs1use rand::Rng;
2use rand::RngExt;
3use rand::distr::{Distribution, StandardUniform};
4
5use xxhash_rust::const_xxh3::const_custom_default_secret;
6use xxhash_rust::xxh3::xxh3_64_with_secret;
7
8use std::hash::Hash;
9
10#[derive(Default, Clone, Copy)]
11#[derive(PartialEq, PartialOrd, Ord, Eq)]
12#[derive(serde::Deserialize, serde::Serialize)]
13#[serde(transparent)]
14#[repr(transparent)]
15pub struct AssetId(u64);
16
17impl Hash for AssetId {
18 #[inline]
19 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
20 state.write_u64(self.0)
21 }
22}
23
24impl From<&str> for AssetId {
34 fn from(value: &str) -> Self {
35 let value: String = value
36 .chars()
37 .map(|c| {
38 match c {
39 'A'..='Z' | 'a'..='z' | '0'..='9' | '-' | '_' | '.' | '~' => c.to_string(),
41 '/' => c.to_string(),
43 _ => {
45 let mut buf = [0; 4];
46 let encoded = c.encode_utf8(&mut buf);
47 let mut strs = encoded.bytes().map(|b| format!("%{:02X}", b));
48 if c.is_ascii() {
49 strs.next_back().unwrap()
50 } else {
51 strs.collect::<String>()
52 }
53 }
54 }
55 })
56 .collect();
57 const SECRET: [u8; 192] = const_custom_default_secret(1111);
58 xxh3_64_with_secret(value.as_bytes(), &SECRET).into()
59 }
60}
61
62impl From<AssetId> for u64 {
63 #[inline]
64 fn from(value: AssetId) -> Self {
65 value.0
66 }
67}
68impl From<u64> for AssetId {
69 #[inline]
70 fn from(value: u64) -> Self {
71 Self(value)
72 }
73}
74
75impl std::fmt::Debug for AssetId {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 struct HexWrapper(u64);
78 impl std::fmt::Debug for HexWrapper {
79 #[inline]
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 f.write_fmt(format_args!("0x{:#x}", self.0))
82 }
83 }
84 f.debug_tuple("AssetId").field(&HexWrapper(self.0)).finish()
85 }
86}
87
88impl Distribution<AssetId> for StandardUniform {
89 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> AssetId {
90 AssetId(rng.random())
91 }
92}
93
94#[cfg(test)]
95mod test {
96 use super::*;
97 use serde_test::{Token, assert_tokens};
98
99 #[test]
100 fn asset_id_serde() {
101 let id: AssetId = rand::rng().random();
102 let id_value: u64 = id.into();
103 assert_tokens(&id, &[Token::U64(id_value)]);
104 }
105}