1#![forbid(unsafe_code)]
3#![deny(
4 missing_copy_implementations,
5 rustdoc::missing_crate_level_docs,
6 missing_debug_implementations,
7 missing_docs,
8 nonstandard_style,
9 unused_qualifications
10)]
11
12#[cfg(test)]
13#[doc = include_str!("../README.md")]
14mod readme {}
15
16use std::borrow::Cow;
17use trillium::{Conn, Handler, KnownHeaderName::Location, Status};
18
19#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
23pub enum RedirectStatus {
24 MultipleChoices,
26 MovedPermanently,
28 #[default]
30 Found,
31 SeeOther,
33 TemporaryRedirect,
35 PermanentRedirect,
37}
38
39impl From<RedirectStatus> for Status {
40 fn from(value: RedirectStatus) -> Self {
41 match value {
42 RedirectStatus::MultipleChoices => Status::MultipleChoice,
43 RedirectStatus::MovedPermanently => Status::MovedPermanently,
44 RedirectStatus::Found => Status::Found,
45 RedirectStatus::SeeOther => Status::SeeOther,
46 RedirectStatus::TemporaryRedirect => Status::TemporaryRedirect,
47 RedirectStatus::PermanentRedirect => Status::PermanentRedirect,
48 }
49 }
50}
51
52#[derive(Clone, Debug)]
54pub struct Redirect {
55 to: Cow<'static, str>,
56 status: RedirectStatus,
57}
58
59impl Redirect {
60 pub fn to(to: impl Into<Cow<'static, str>>) -> Self {
62 Self {
63 to: to.into(),
64 status: RedirectStatus::default(),
65 }
66 }
67
68 pub fn with_redirect_status(mut self, status: RedirectStatus) -> Self {
70 self.status = status;
71 self
72 }
73}
74
75pub fn redirect(to: impl Into<Cow<'static, str>>) -> Redirect {
77 Redirect::to(to)
78}
79
80impl Handler for Redirect {
81 async fn run(&self, conn: Conn) -> Conn {
82 conn.redirect_as(self.to.clone(), self.status)
83 }
84}
85
86pub trait RedirectConnExt {
88 fn redirect(self, to: impl Into<Cow<'static, str>>) -> Self;
90 fn redirect_as(self, to: impl Into<Cow<'static, str>>, status: RedirectStatus) -> Self;
92}
93
94impl RedirectConnExt for Conn {
95 fn redirect(self, to: impl Into<Cow<'static, str>>) -> Self {
96 self.redirect_as(to, RedirectStatus::default())
97 }
98
99 fn redirect_as(self, to: impl Into<Cow<'static, str>>, status: RedirectStatus) -> Self {
100 self.with_status(status)
101 .with_response_header(Location, to.into())
102 .halt()
103 }
104}