id30/
id30_parse.rs

1// Copyright 2024 Magnus Hovland Hoff.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/license/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::fmt;
10
11use crate::Id30;
12
13/// `Id30Parse` represents the successful result of parsing an id30 string:
14///  - an [`Id30`] value, `id30`
15///  - a boolean, `is_canonical`, which is `true` iff the parsed string was in
16///    canonical encoding
17///
18/// When accepting id30 as input, non-canonical encodings should preferably
19/// redirect the user to a canonical encoding of the input. For example, when
20/// id30 is used in URLs, the server should respond with a redirect when the
21/// id30 is not canonical. Parsing the given input as `Id30Parse` yields the
22/// information necessary to implement this.
23///
24/// ```
25/// # fn main() -> Result<(), id30::ParseError> {
26/// let parse: id30::Id30Parse = "78ddpa".parse()?;
27/// assert_eq!(u32::from(parse.id30), 243709642);
28/// assert!(parse.is_canonical);
29/// assert_eq!(&parse.id30.to_string(), "78ddpa");
30///
31/// let parse: id30::Id30Parse = "78DDPA".parse()?;
32/// assert_eq!(u32::from(parse.id30), 243709642);
33/// assert!(!parse.is_canonical);
34/// assert_eq!(&parse.id30.to_string(), "78ddpa");
35/// # Ok(())}
36/// ```
37#[derive(Debug, PartialEq, Eq)]
38pub struct Id30Parse {
39    #[allow(missing_docs)]
40    pub id30: Id30,
41
42    #[allow(missing_docs)]
43    pub is_canonical: bool,
44}
45
46/// The given string was not a valid `id30`
47#[derive(Debug, Copy, Clone, PartialEq, Eq)]
48pub enum ParseError {
49    /// The given string did not have length 6
50    InvalidLength,
51
52    /// The given string contained invalid characters, see the [crate] root
53    /// for documentation of the alphabet
54    InvalidCharacters,
55}
56
57impl fmt::Display for ParseError {
58    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
59        match self {
60            ParseError::InvalidLength => "invalid length for Id30".fmt(fmt),
61            ParseError::InvalidCharacters => "one or more invalid characters in string".fmt(fmt),
62        }
63    }
64}
65
66impl std::error::Error for ParseError {}