typed_headers/impls/
token68.rs

1use std::error::Error;
2use std::fmt;
3use std::str::FromStr;
4
5/// A base68 value as defined in [RFC7235].
6///
7/// [RFC7235]: https://tools.ietf.org/html/rfc7235#section-2.1
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct Token68(pub(crate) String);
10
11impl Token68 {
12    /// Constructs a new base68 value.
13    #[inline]
14    pub fn new(s: &str) -> Result<Token68, InvalidToken68> {
15        let trimmed = s.trim_end_matches('=');
16
17        if trimmed.is_empty() {
18            return Err(InvalidToken68(()));
19        }
20
21        let ok = trimmed.as_bytes().iter().all(|b| match b {
22            b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' | b'-' | b'.' | b'_' | b'~' | b'+' | b'/' => {
23                true
24            }
25            _ => false,
26        });
27
28        if ok {
29            Ok(Token68(s.to_string()))
30        } else {
31            Err(InvalidToken68(()))
32        }
33    }
34
35    /// Returns the string the value as a string.
36    #[inline]
37    pub fn as_str(&self) -> &str {
38        &self.0
39    }
40}
41
42impl fmt::Display for Token68 {
43    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
44        fmt.write_str(self.as_str())
45    }
46}
47
48impl FromStr for Token68 {
49    type Err = InvalidToken68;
50
51    #[inline]
52    fn from_str(s: &str) -> Result<Token68, InvalidToken68> {
53        Token68::new(s)
54    }
55}
56
57#[derive(Debug)]
58pub struct InvalidToken68(());
59
60impl fmt::Display for InvalidToken68 {
61    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
62        fmt.write_str("invalid base68")
63    }
64}
65
66impl Error for InvalidToken68 {
67    fn description(&self) -> &str {
68        "invalid base68"
69    }
70}