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}