Skip to main content

alux_http/
status.rs

1//! States what a response answers with, and what a failure means to a caller.
2
3use core::convert::Infallible;
4use std::io::{Error as IoError, ErrorKind};
5
6/// Names the status a response is answered with.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub struct HttpStatus(u16);
9
10impl HttpStatus {
11    /// Answers that the request succeeded.
12    pub const OK: Self = Self(200);
13    /// Answers that the request succeeded and states no body.
14    pub const NO_CONTENT: Self = Self(204);
15    /// Answers that what was asked for is at another location.
16    pub const SEE_OTHER: Self = Self(303);
17    /// Answers that the request could not be read.
18    pub const BAD_REQUEST: Self = Self(400);
19    /// Answers that the caller is known and not allowed.
20    pub const FORBIDDEN: Self = Self(403);
21    /// Answers that nothing is at this location.
22    pub const NOT_FOUND: Self = Self(404);
23    /// Answers that something is at this location, but not under this method.
24    pub const METHOD_NOT_ALLOWED: Self = Self(405);
25    /// Answers that the service failed for a reason the caller cannot act on.
26    pub const INTERNAL: Self = Self(500);
27
28    /// Returns the status this code names.
29    pub const fn new(code: u16) -> Self {
30        Self(code)
31    }
32
33    /// Returns the code this status is written as on the wire.
34    pub const fn code(self) -> u16 {
35        self.0
36    }
37
38    /// Returns whether this status names a successful answer.
39    pub const fn is_success(self) -> bool {
40        200 <= self.0 && self.0 < 300
41    }
42}
43
44/// States what one failure means to a caller.
45///
46/// A handler that can fail returns a `Result`, and its endpoint answers with what the failure means
47/// rather than with the failure itself. That meaning is HTTP vocabulary rather than domain
48/// vocabulary, which is why a domain states its failures and this states how they are answered.
49pub trait HttpErrorAlg {
50    /// Every status this failure can be answered with.
51    ///
52    /// An interpretation that runs asks a failure what it means and is given one status. An
53    /// interpretation that only reads a program has no failure to ask, so what an endpoint can
54    /// answer with has to be stated by the type rather than by a value.
55    const HTTP_STATUSES: &'static [HttpStatus];
56
57    /// Returns the status this failure is answered with.
58    fn http_status(&self) -> HttpStatus;
59
60    /// Returns the message this failure is answered with.
61    fn http_message(&self) -> String;
62}
63
64impl HttpErrorAlg for Infallible {
65    const HTTP_STATUSES: &'static [HttpStatus] = &[];
66
67    fn http_status(&self) -> HttpStatus {
68        match *self {}
69    }
70
71    fn http_message(&self) -> String {
72        match *self {}
73    }
74}
75
76impl HttpErrorAlg for IoError {
77    const HTTP_STATUSES: &'static [HttpStatus] = &[HttpStatus::NOT_FOUND, HttpStatus::FORBIDDEN, HttpStatus::INTERNAL];
78
79    fn http_status(&self) -> HttpStatus {
80        match self.kind() {
81            ErrorKind::NotFound => HttpStatus::NOT_FOUND,
82            ErrorKind::PermissionDenied => HttpStatus::FORBIDDEN,
83            _ => HttpStatus::INTERNAL,
84        }
85    }
86
87    fn http_message(&self) -> String {
88        self.to_string()
89    }
90}