summaryrefslogtreecommitdiffstats
path: root/src/client_identifier.rs
blob: f0f5356d9cae156d07cc2966a90cf8e34d63728e (plain)
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//
//   This Source Code Form is subject to the terms of the Mozilla Public
//   License, v. 2.0. If a copy of the MPL was not distributed with this
//   file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

pub enum ClientIdentifier {
    MinimalRequired(MinimalRequiredClientIdentifier),
    PotentiallyServerProvided,
    PotentiallyAccepted(PotentiallyAcceptedClientIdentifier),
}

impl ClientIdentifier {
    pub fn new_minimal_required(
        s: impl Into<String>,
    ) -> Result<ClientIdentifier, ClientIdentifierError> {
        const ALLOWED_CHARS: &str =
            "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        let s = s.into();

        let disallowed_chars = s
            .chars()
            .filter(|c| !ALLOWED_CHARS.chars().any(|allowed| allowed == *c))
            .collect::<Vec<char>>();

        if !disallowed_chars.is_empty() {
            return Err(ClientIdentifierError::MinimalNotAllowedChar(
                disallowed_chars,
            ));
        }

        if s.len() > 23 {
            return Err(ClientIdentifierError::MinimalTooLong(s.len()));
        }

        Ok(ClientIdentifier::MinimalRequired(
            MinimalRequiredClientIdentifier(s),
        ))
    }

    pub fn new_potentially_server_provided() -> ClientIdentifier {
        ClientIdentifier::PotentiallyServerProvided
    }

    pub fn new_potetially_accepted(
        s: impl Into<String>,
    ) -> Result<ClientIdentifier, ClientIdentifierError> {
        let s = s.into();
        if s.is_empty() {
            return Err(ClientIdentifierError::Zero);
        }
        crate::string::MqttString::try_from(s)
            .map(PotentiallyAcceptedClientIdentifier)
            .map(ClientIdentifier::PotentiallyAccepted)
            .map_err(ClientIdentifierError::from)
    }

    pub fn as_str(&self) -> &str {
        todo!()
    }
}

pub struct MinimalRequiredClientIdentifier(String);
pub struct PotentiallyAcceptedClientIdentifier(crate::string::MqttString);

#[derive(Debug, thiserror::Error)]
pub enum ClientIdentifierError {
    // I am ugly
    #[error("Minimal client identifier contains disallowed characters: {}", .0.iter().copied().map(String::from).collect::<Vec<_>>().join(", "))]
    MinimalNotAllowedChar(Vec<char>),

    #[error("Minimal client identifier contains more characters than allowed: {}", .0)]
    MinimalTooLong(usize),

    #[error("Client identifier is not allowed to be empty")]
    Zero,

    #[error(transparent)]
    String(#[from] crate::string::MqttStringError),
}