use std::{
any::{Any, TypeId},
collections::HashMap,
fmt::Debug,
};
use hyper::{Body};
use routefinder::Captures;
#[derive(Debug)]
pub struct Context {
state: HashMap<TypeId, Box<dyn Any + Send + Sync + 'static>>,
pub params: Vec<Captures<'static, 'static>>,
}
impl Context {
pub(crate) fn new(req: crate::Request<Body>, params: Vec<Captures<'static, 'static>>) -> Self {
let mut ctx = Self {
state: HashMap::new(),
params,
};
let (
hyper::http::request::Parts {
method,
uri,
version,
headers,
extensions,
..
},
body,
) = req.into_parts();
ctx.insert(method);
ctx.insert(uri);
ctx.insert(version);
ctx.insert(headers);
ctx.insert(body);
ctx.insert(extensions);
ctx
}
#[must_use]
pub fn try_borrow<T: 'static>(&self) -> Option<&T> {
self.state
.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.state
.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.state
.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 + Sync + 'static>(&mut self, value: T) -> Option<T> {
self.state
.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())
}
}