use crate::response::Response;
#[cfg(not(target_arch = "wasm32"))]
pub trait IntoResponseBounds: Send {}
#[cfg(not(target_arch = "wasm32"))]
impl<T: Send + ?Sized> IntoResponseBounds for T {}
#[cfg(target_arch = "wasm32")]
pub trait IntoResponseBounds {}
#[cfg(target_arch = "wasm32")]
impl<T: ?Sized> IntoResponseBounds for T {}
pub trait IntoResponse: IntoResponseBounds {
fn into_response(self) -> Response;
}
impl IntoResponse for String {
fn into_response(self) -> Response {
Response::text(self)
}
}
impl IntoResponse for &'static str {
fn into_response(self) -> Response {
Response::text(self)
}
}
impl IntoResponse for std::borrow::Cow<'static, str> {
fn into_response(self) -> Response {
Response::text(self)
}
}
impl IntoResponse for Response {
fn into_response(self) -> Response {
self
}
}
impl IntoResponse for () {
fn into_response(self) -> Response {
Response::empty()
}
}
impl<T: IntoResponse> IntoResponse for Option<T> {
fn into_response(self) -> Response {
match self {
Some(value) => value.into_response(),
None => Response::empty(),
}
}
}
impl<T, E> IntoResponse for Result<T, E>
where
T: IntoResponse,
E: std::fmt::Display + IntoResponseBounds,
{
fn into_response(self) -> Response {
match self {
Ok(value) => value.into_response(),
Err(e) => Response::text(format!("Error: {e}")),
}
}
}
impl IntoResponse for async_fs::File {
fn into_response(self) -> Response {
Response::file(self)
}
}
impl IntoResponse for std::path::PathBuf {
fn into_response(self) -> Response {
Response::path(self)
}
}
macro_rules! impl_captioned_file {
($ty:ty) => {
impl<C: Into<String> + IntoResponseBounds> IntoResponse for ($ty, C) {
fn into_response(self) -> Response {
let (file, caption) = self;
file.into_response().with_caption(caption)
}
}
};
}
impl_captioned_file!(async_fs::File);
impl_captioned_file!(std::path::PathBuf);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn strings_become_text_responses() {
assert_eq!("hi".into_response().content(), Some("hi"));
assert_eq!(String::from("hi").into_response().content(), Some("hi"));
assert_eq!(
std::borrow::Cow::Borrowed("hi").into_response().content(),
Some("hi")
);
}
#[test]
fn unit_and_none_are_empty() {
assert!(().into_response().is_empty());
assert!(Option::<String>::None.into_response().is_empty());
assert_eq!(Some("hi").into_response().content(), Some("hi"));
}
#[test]
fn errors_render_their_display() {
let result: Result<&str, std::fmt::Error> = Err(std::fmt::Error);
assert_eq!(
result.into_response().content(),
Some("Error: an error occurred when formatting an argument")
);
}
#[test]
fn ok_passes_the_inner_value_through() {
let result: Result<&str, std::fmt::Error> = Ok("fine");
assert_eq!(result.into_response().content(), Some("fine"));
}
#[test]
fn captions_attach_to_file_responses() {
let mut response = (std::path::PathBuf::from("/tmp/a.txt"), "caption").into_response();
let file = response.take_file().unwrap();
assert_eq!(file.caption.as_deref(), Some("caption"));
assert_eq!(file.filename.as_deref(), Some("a.txt"));
}
}