Skip to main content

botkit_core/
responder.rs

1use crate::response::Response;
2
3/// Trait for converting types into bot responses
4///
5/// Similar to skyzen's `Responder` trait, this allows handlers to
6/// return various types that get converted to responses.
7///
8/// # Example
9/// ```ignore
10/// // Return a string directly
11/// async fn ping() -> &'static str {
12///     "Pong!"
13/// }
14///
15/// // Return a formatted string
16/// async fn greet(user: User) -> String {
17///     format!("Hello, {}!", user.name)
18/// }
19///
20/// // Return Response for full control
21/// async fn buttons() -> Response {
22///     Response::text("Click a button:")
23///         .with_components(vec![...])
24/// }
25/// ```
26pub trait IntoResponse: Send {
27    /// Convert this type into a bot response
28    fn into_response(self) -> Response;
29}
30
31// String types
32impl IntoResponse for String {
33    fn into_response(self) -> Response {
34        Response::text(self)
35    }
36}
37
38impl IntoResponse for &'static str {
39    fn into_response(self) -> Response {
40        Response::text(self)
41    }
42}
43
44impl IntoResponse for std::borrow::Cow<'static, str> {
45    fn into_response(self) -> Response {
46        Response::text(self)
47    }
48}
49
50// Response passes through unchanged
51impl IntoResponse for Response {
52    fn into_response(self) -> Response {
53        self
54    }
55}
56
57// Unit type returns empty response
58impl IntoResponse for () {
59    fn into_response(self) -> Response {
60        Response::empty()
61    }
62}
63
64// Option<T> - None returns empty response
65impl<T: IntoResponse> IntoResponse for Option<T> {
66    fn into_response(self) -> Response {
67        match self {
68            Some(value) => value.into_response(),
69            None => Response::empty(),
70        }
71    }
72}
73
74// Result<T, E> - Ok returns T, Err returns error message
75impl<T: IntoResponse, E: std::fmt::Display + Send> IntoResponse for Result<T, E> {
76    fn into_response(self) -> Response {
77        match self {
78            Ok(value) => value.into_response(),
79            Err(e) => Response::text(format!("Error: {}", e)),
80        }
81    }
82}
83
84// File response
85impl IntoResponse for async_fs::File {
86    fn into_response(self) -> Response {
87        Response::file(self)
88    }
89}
90
91// File with caption (static str)
92impl IntoResponse for (async_fs::File, &'static str) {
93    fn into_response(self) -> Response {
94        Response::file(self.0).with_caption(self.1)
95    }
96}
97
98// File with caption (String)
99impl IntoResponse for (async_fs::File, String) {
100    fn into_response(self) -> Response {
101        Response::file(self.0).with_caption(self.1)
102    }
103}