use std::{fmt::Debug, collections::HashMap, any::{TypeId, Any}};
use hyper::{Version, Body, Method, header::{HeaderName, HeaderValue}, Uri};
use routefinder::Captures;
#[derive(Debug)]
pub struct Context {
pub req: crate::Request<Body>,
ctx: HashMap<TypeId, Box<dyn Any + Send>>,
pub params: Vec<Captures<'static, 'static>>,
}
impl Context {
pub(crate) fn new(
req: crate::Request<Body>,
params: Vec<Captures<'static, 'static>>,
) -> Self {
Self {
req,
ctx: HashMap::new(),
params,
}
}
#[must_use]
pub fn method(&self) -> &Method {
self.req.method()
}
#[must_use]
pub fn uri(&self) -> &Uri {
self.req.uri()
}
#[must_use]
pub fn version(&self) -> Version {
self.req.version()
}
#[must_use]
pub fn host(&self) -> Option<&str> {
self.req.uri().host()
}
#[must_use]
pub fn header(
&self,
key: impl Into<HeaderName>,
) -> Option<&HeaderValue> {
self.req.headers().get(key.into())
}
pub fn header_mut(&mut self, name: impl Into<HeaderName>) -> Option<&mut HeaderValue> {
self.req.headers_mut().get_mut(name.into())
}
pub fn insert_header(
&mut self,
name: impl Into<HeaderName>,
value: impl Into<HeaderValue>,
) -> Option<HeaderValue> {
self.req.headers_mut().insert(name.into(), value.into())
}
pub fn remove_header(&mut self, name: impl Into<HeaderName>) -> Option<HeaderValue> {
self.req.headers_mut().remove(name.into())
}
#[must_use]
pub fn try_borrow<T: 'static>(&self) -> Option<&T> {
self.ctx.get(&TypeId::of::<T>()).and_then(|v| v.downcast_ref::<T>())
}
#[must_use]
pub fn borrow<T: 'static>(&self) -> &T {
self.try_borrow().unwrap_or_else(|| {
panic!("Context value `{}` does not exist", std::any::type_name::<T>())
})
}
#[must_use]
pub fn try_borrow_mut<T: 'static>(&mut self) -> Option<&mut T> {
self.ctx.get_mut(&TypeId::of::<T>()).and_then(|v| v.downcast_mut::<T>())
}
#[must_use]
pub fn borrow_mut<T: 'static>(&mut self) -> &mut T {
match self.try_borrow_mut() {
Some(v) => v,
None => panic!("Context value `{}` does not exist", std::any::type_name::<T>()),
}
}
#[must_use]
pub fn try_take<T: 'static>(&mut self) -> Option<T> {
self.ctx.remove(&TypeId::of::<T>()).and_then(|v| v.downcast::<T>().map(|v| *v).ok())
}
#[must_use]
pub fn take<T: 'static>(&mut self) -> T {
match self.try_take() {
Some(v) => v,
None => panic!("Context value `{}` does not exist", std::any::type_name::<T>()),
}
}
pub fn insert<T: Send + 'static>(&mut self, value: T) -> Option<T> {
self.ctx.insert(TypeId::of::<T>(), Box::new(value)).map(|v| *v.downcast::<T>().unwrap())
}
pub fn param(&self, key: &str) -> crate::Result<&str> {
self.params
.iter()
.rev()
.find_map(|captures| captures.get(key))
.ok_or_else(|| anyhow::anyhow!("Param \"{}\" not found", key.to_string()).into())
}
pub fn wildcard(&self) -> Option<&str> {
self.params
.iter()
.rev()
.find_map(|captures| captures.wildcard())
}
}
impl AsRef<crate::Request<Body>> for Context {
fn as_ref(&self) -> &crate::Request<Body> {
&self.req
}
}
impl AsMut<crate::Request<Body>> for Context {
fn as_mut(&mut self) -> &mut crate::Request<Body> {
&mut self.req
}
}