Skip to main content

kynos_openapi/model/response/
status.rs

1//! The keys of a Responses Object: exact status codes and the five wildcards.
2
3use std::{fmt, str::FromStr};
4
5/// The key of an entry in a [`Responses`](crate::model::response::Responses)
6/// map.
7///
8/// Either an exact status code or one of the five permitted wildcards. No other
9/// wildcard form is legal.
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
11pub enum StatusPattern {
12    /// An exact status code, such as `404`.
13    Code(u16),
14    /// Every informational response, written `1XX`.
15    Informational,
16    /// Every successful response, written `2XX`.
17    Success,
18    /// Every redirection response, written `3XX`.
19    Redirection,
20    /// Every client error response, written `4XX`.
21    ClientError,
22    /// Every server error response, written `5XX`.
23    ServerError,
24}
25
26impl StatusPattern {
27    /// Whether `code` is covered by this pattern.
28    #[must_use]
29    pub fn matches(self, code: u16) -> bool {
30        match self {
31            Self::Code(exact) => exact == code,
32            Self::Informational => (100..200).contains(&code),
33            Self::Success => (200..300).contains(&code),
34            Self::Redirection => (300..400).contains(&code),
35            Self::ClientError => (400..500).contains(&code),
36            Self::ServerError => (500..600).contains(&code),
37        }
38    }
39
40    /// Whether this pattern is a wildcard rather than an exact code.
41    #[must_use]
42    pub fn is_range(self) -> bool {
43        !matches!(self, Self::Code(_))
44    }
45}
46
47impl fmt::Display for StatusPattern {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        match self {
50            Self::Code(code) => write!(f, "{code}"),
51            Self::Informational => f.write_str("1XX"),
52            Self::Success => f.write_str("2XX"),
53            Self::Redirection => f.write_str("3XX"),
54            Self::ClientError => f.write_str("4XX"),
55            Self::ServerError => f.write_str("5XX"),
56        }
57    }
58}
59
60/// The error returned when a string is not a legal
61/// [`Responses`](crate::model::response::Responses) key.
62#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
63#[error(
64    "`{0}` is not a valid response key: expected a status code such as `404`, \
65     or one of `1XX`, `2XX`, `3XX`, `4XX`, `5XX`"
66)]
67pub struct InvalidStatusPattern(pub String);
68
69impl FromStr for StatusPattern {
70    type Err = InvalidStatusPattern;
71
72    fn from_str(value: &str) -> Result<Self, Self::Err> {
73        match value {
74            "1XX" => Ok(Self::Informational),
75            "2XX" => Ok(Self::Success),
76            "3XX" => Ok(Self::Redirection),
77            "4XX" => Ok(Self::ClientError),
78            "5XX" => Ok(Self::ServerError),
79            _ => value
80                .parse::<u16>()
81                .ok()
82                .filter(|code| (100..600).contains(code))
83                .map(Self::Code)
84                .ok_or_else(|| InvalidStatusPattern(value.to_owned())),
85        }
86    }
87}