Skip to main content

ps_hash_core/encoding/
mod.rs

1//! The two textual representations of a [`Hash`](crate::Hash).
2//!
3//! Both encode the same [`HASH_SIZE_BIN`](crate::HASH_SIZE_BIN)-byte internal
4//! representation and differ only in alphabet:
5//!
6//! - [`crockford`] is the canonical form: case-insensitive, and free of the
7//!   ambiguous glyphs `I`, `L`, `O`, and `U`.
8//! - [`base64`] is the compact form, using the URL-safe alphabet.
9//!
10//! Their encoded lengths differ, which is what lets
11//! [`Hash::validate`](crate::Hash::validate) tell them apart by length alone.
12
13pub mod base64;
14pub mod crockford;
15
16#[cfg(test)]
17#[allow(clippy::expect_used)]
18mod tests {
19    use super::{base64, crockford};
20    use crate::{hash_inner, HASH_SIZE_BASE64, HASH_SIZE_BIN, HASH_SIZE_CROCKFORD};
21
22    #[test]
23    fn crockford_round_trips() {
24        let inner = hash_inner(b"crockford round trip").expect("hash_inner should work");
25
26        let encoded = crockford::encode(&inner);
27
28        assert_eq!(encoded.len(), HASH_SIZE_CROCKFORD);
29        assert_eq!(crockford::decode(&encoded), inner);
30    }
31
32    #[test]
33    fn base64_round_trips() {
34        let inner = hash_inner(b"base64 round trip").expect("hash_inner should work");
35
36        let encoded = base64::encode(&inner);
37
38        assert_eq!(encoded.len(), HASH_SIZE_BASE64);
39        assert_eq!(base64::decode(&encoded), inner);
40    }
41
42    #[test]
43    fn representations_differ_in_length() {
44        assert_ne!(HASH_SIZE_CROCKFORD, HASH_SIZE_BASE64);
45    }
46
47    #[test]
48    fn round_trips_over_the_whole_byte_range() {
49        for byte in 0..=u8::MAX {
50            let inner = [byte; HASH_SIZE_BIN];
51
52            assert_eq!(crockford::decode(&crockford::encode(&inner)), inner);
53            assert_eq!(base64::decode(&base64::encode(&inner)), inner);
54        }
55    }
56}