base36/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//! Base36 encoder/decoder.

use num_bigint::{BigUint, ParseBigIntError};
use num_traits::Num;

const RADIX: u32 = 36;

/// Error during [`decode`](fn.decode.html).
pub type DecodeError = ParseBigIntError;

/// Decodes a Base36 string into a byte array.
///
/// Returns [`DecodeError`](type.DecodeError.html) if the string is not Base36.
pub fn decode(s: &str) -> Result<Vec<u8>, DecodeError> {
    Ok(BigUint::from_str_radix(s, RADIX)?.to_bytes_be())
}

/// Encodes a byte array into a Base36 string (lowercase).
pub fn encode(buf: &[u8]) -> String {
    BigUint::from_bytes_be(buf).to_str_radix(RADIX)
}

#[cfg(test)]
mod tests {
    use super::*;

    const HELLO_WORLD: &[u8] = b"Hello, World!";
    const HELLO_WORLD_BASE36: &str = "fg3h7vqw7een6jwwnzmp";
    const HELLO_WORLD_BASE36_MIXED: &str = "fG3h7vQw7eEn6JwwnZmP";

    #[test]
    fn test_decode() {
        assert_eq!(decode(&HELLO_WORLD_BASE36).unwrap(), HELLO_WORLD);
    }

    #[test]
    fn test_decode_mixed() {
        assert_eq!(decode(&HELLO_WORLD_BASE36_MIXED).unwrap(), HELLO_WORLD);
    }

    #[test]
    fn test_decode_empty() {
        assert!(decode("").is_err());
    }

    #[test]
    fn test_decode_null() {
        assert_eq!(decode("0").unwrap(), b"\0");
    }

    #[test]
    fn test_encode() {
        assert_eq!(encode(HELLO_WORLD), HELLO_WORLD_BASE36);
    }

    #[test]
    fn test_encode_empty() {
        assert_eq!(encode(b""), "0");
    }

    #[test]
    fn test_encode_null() {
        assert_eq!(encode(b"\0"), "0");
    }
}