waddling_errors_hash/
base62.rs1#[cfg(not(feature = "std"))]
13extern crate alloc;
14
15#[cfg(feature = "std")]
16use std::string::String;
17
18#[cfg(not(feature = "std"))]
19use alloc::string::String;
20
21const BASE62_CHARS: &[u8] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
23const BASE: u64 = 62;
24
25pub fn to_base62(bytes: &[u8]) -> String {
41 let mut num: u64 = 0;
44 let byte_count = bytes.len().min(5);
45
46 for &byte in bytes.iter().take(byte_count) {
47 num = (num << 8) | (byte as u64);
48 }
49
50 for _ in byte_count..5 {
52 num <<= 8;
53 }
54
55 let mut result_chars = [0u8; 5];
57 let mut n = num;
58
59 for i in (0..5).rev() {
60 result_chars[i] = BASE62_CHARS[(n % BASE) as usize];
61 n /= BASE;
62 }
63
64 String::from_utf8(result_chars.to_vec()).expect("base62 encoding produces valid UTF-8")
66}
67
68pub fn u64_to_base62(value: u64) -> String {
81 let bytes = [
82 (value >> 32) as u8,
83 (value >> 24) as u8,
84 (value >> 16) as u8,
85 (value >> 8) as u8,
86 value as u8,
87 ];
88 to_base62(&bytes)
89}
90
91pub fn seed_to_u64(seed: &str) -> u64 {
106 let seed_bytes = seed.as_bytes();
113 let mut padded = [0u8; 8];
114 let len = seed_bytes.len().min(8);
115 padded[..len].copy_from_slice(&seed_bytes[..len]);
116 u64::from_le_bytes(padded)
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn test_to_base62_length() {
125 let bytes = [0x12, 0x34, 0x56, 0x78, 0x9A];
126 let result = to_base62(&bytes);
127 assert_eq!(result.len(), 5, "Result should be exactly 5 characters");
128 }
129
130 #[test]
131 fn test_to_base62_alphanumeric() {
132 let bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
133 let result = to_base62(&bytes);
134 assert!(
135 result.chars().all(|c| c.is_ascii_alphanumeric()),
136 "Result should be alphanumeric only"
137 );
138 }
139
140 #[test]
141 fn test_to_base62_deterministic() {
142 let bytes = [0x12, 0x34, 0x56, 0x78, 0x9A];
143 let result1 = to_base62(&bytes);
144 let result2 = to_base62(&bytes);
145 assert_eq!(result1, result2, "Should be deterministic");
146 }
147
148 #[test]
149 fn test_to_base62_different_inputs() {
150 let bytes1 = [0x12, 0x34, 0x56, 0x78, 0x9A];
151 let bytes2 = [0x12, 0x34, 0x56, 0x78, 0x9B];
152 let result1 = to_base62(&bytes1);
153 let result2 = to_base62(&bytes2);
154 assert_ne!(
155 result1, result2,
156 "Different inputs should produce different outputs"
157 );
158 }
159
160 #[test]
161 fn test_to_base62_short_input() {
162 let bytes = [0x12];
163 let result = to_base62(&bytes);
164 assert_eq!(result.len(), 5, "Should pad to 5 characters");
165 }
166
167 #[test]
168 fn test_to_base62_empty_input() {
169 let bytes = [];
170 let result = to_base62(&bytes);
171 assert_eq!(result.len(), 5, "Should pad to 5 characters");
172 }
173
174 #[test]
175 fn test_u64_to_base62() {
176 let value = 123456789u64;
177 let result = u64_to_base62(value);
178 assert_eq!(result.len(), 5);
179 assert!(result.chars().all(|c| c.is_ascii_alphanumeric()));
180 }
181
182 #[test]
183 fn test_u64_to_base62_deterministic() {
184 let value = 987654321u64;
185 let result1 = u64_to_base62(value);
186 let result2 = u64_to_base62(value);
187 assert_eq!(result1, result2);
188 }
189
190 #[test]
191 fn test_seed_to_u64_deterministic() {
192 let seed = "wdp-v1";
193 let result1 = seed_to_u64(seed);
194 let result2 = seed_to_u64(seed);
195 assert_eq!(result1, result2, "Should be deterministic");
196 }
197
198 #[test]
199 fn test_seed_to_u64_wdp_conformant() {
200 let seed = "wdp-v1";
203 let result = seed_to_u64(seed);
204 assert_eq!(
205 result, 0x000031762D706477,
206 "WDP seed should match spec value"
207 );
208 }
209
210 #[test]
211 fn test_seed_to_u64_different_seeds() {
212 let seed1 = "wdp-v1";
213 let seed2 = "Different";
214 let result1 = seed_to_u64(seed1);
215 let result2 = seed_to_u64(seed2);
216 assert_ne!(
217 result1, result2,
218 "Different seeds should produce different values"
219 );
220 }
221
222 #[test]
223 fn test_seed_to_u64_empty() {
224 let seed = "";
226 let result = seed_to_u64(seed);
227 assert_eq!(result, 0, "Empty seed produces zero");
228 }
229}