titan_core/
respond.rs

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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use std::convert::Infallible;

use titan_http::{body::Body, header, Response, ResponseBuilder, StatusCode};

/// A trait for types that can be converted into an HTTP response.
///
/// The `Respondable` trait is intended for types that can be transformed into a valid HTTP response.
/// Any type returned by a handler (or any function) that implements this trait can be converted into
/// a `Response<Body>`. This is typically used to ensure that different types can be unified into
/// a standard response format for HTTP APIs or services.
///
/// This method converts the implementing type into an HTTP response represented by a `Response<Body>`.
/// It allows various types (e.g., structs, enums, or other custom types) to be returned from a handler
/// and automatically converted into HTTP responses.
///
/// # Implementing `Respondable`
///
/// To implement the `Respondable` trait, you need to define how your custom type can be turned into
/// an HTTP response. This is commonly done by converting your type into a response body (e.g., a string,
/// JSON, or some binary data) and returning it wrapped in a `Response<Body>`.
///
/// # Example
///
/// ```
/// use titan_http::{body::Body, Response};
/// use titan_core::Respondable;
///
/// // Define a type that represents a response body.
/// pub struct MyResponse {
///     message: String,
/// }
///
/// // Implement `Respondable` for `MyResponse`.
/// impl Respondable for MyResponse {
///     fn respond(self) -> Response<Body> {
///         // Convert the struct into an HTTP response with the message in the body.
///         Response::new(Body::from(self.message))
///     }
/// }
///
/// // Now you can return `MyResponse` from a handler, and it will be automatically
/// // converted into an HTTP response.
/// ```
pub trait Respondable {
  fn respond(self) -> Response<Body>;
}

impl<T, E> Respondable for Result<T, E>
where
  T: Respondable,
  E: Respondable,
{
  fn respond(self) -> Response<Body> {
    match self {
      Ok(t) => t.respond(),
      Err(e) => e.respond(),
    }
  }
}

impl Respondable for Response<Body> {
  fn respond(self) -> Response<Body> {
    self
  }
}

impl Respondable for Infallible {
  fn respond(self) -> Response<Body> {
    panic!("Not fallible :(")
  }
}

impl Respondable for () {
  fn respond(self) -> Response<Body> {
    ResponseBuilder::new().status(204).body(Body::from(())).unwrap()
  }
}

impl<T> Respondable for (StatusCode, T)
where
  T: Respondable,
{
  fn respond(self) -> Response<Body> {
    let (status, body) = self;
    let mut res = body.respond();

    *res.status_mut() = status;
    res
  }
}

impl Respondable for titan_html::tags::html::Html {
  fn respond(self) -> Response<Body> {
    let str = titan_html::render(self);

    let response = ResponseBuilder::new().status(200);

    response
      .header(header::CONTENT_TYPE, "text/html")
      .body(Body::from(str))
      .unwrap()
  }
}

macro_rules! impl_respondable_for_int {
    ($($t:ty)*) => {
        $(
          impl Respondable for $t {
            fn respond(self) -> Response<Body> {
              let body = Body::from(self);

              let mut res = Response::new(body);
              let headers = res.headers_mut();

              headers.insert("content-type", "text/plain".parse().unwrap());

              res
            }
          }
        )*
    };
}

impl_respondable_for_int!(String &str i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 usize isize);