use std::fmt::Display;
use crate::{
IntoResponse, Response,
http::{StatusCode, header},
};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Redirect {
status: StatusCode,
uri: String,
}
impl Redirect {
pub fn permanent(uri: impl Display) -> Self {
Self {
status: StatusCode::PERMANENT_REDIRECT,
uri: uri.to_string(),
}
}
pub fn moved_permanent(uri: impl Display) -> Self {
Self {
status: StatusCode::MOVED_PERMANENTLY,
uri: uri.to_string(),
}
}
pub fn see_other(uri: impl Display) -> Self {
Self {
status: StatusCode::SEE_OTHER,
uri: uri.to_string(),
}
}
pub fn temporary(uri: impl Display) -> Self {
Self {
status: StatusCode::TEMPORARY_REDIRECT,
uri: uri.to_string(),
}
}
}
impl IntoResponse for Redirect {
fn into_response(self) -> Response {
self.status
.with_header(header::LOCATION, self.uri)
.into_response()
}
}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! test_redirect {
($fn:ident, $status:ident) => {
#[test]
fn $fn() {
let resp = Redirect::$fn("https://example.com/").into_response();
assert_eq!(resp.status(), StatusCode::$status);
assert_eq!(
resp.headers()
.get(header::LOCATION)
.and_then(|value| value.to_str().ok()),
Some("https://example.com/")
);
}
};
}
test_redirect!(permanent, PERMANENT_REDIRECT);
test_redirect!(moved_permanent, MOVED_PERMANENTLY);
test_redirect!(see_other, SEE_OTHER);
test_redirect!(temporary, TEMPORARY_REDIRECT);
}