1use std::{ops::Deref, sync::Arc};
2
3use anyhow::Result;
4use axum::{
5 extract::{FromRequestParts, State},
6 http::request::Parts,
7};
8
9use crate::{framework_log_event, Container, HttpException};
10
11pub struct Inject<T>(Arc<T>);
20
21impl<T> Inject<T>
22where
23 T: Send + Sync + 'static,
24{
25 pub fn from(container: &Container) -> Result<Self> {
29 framework_log_event(
30 "dependency_injected",
31 &[("type", std::any::type_name::<T>().to_string())],
32 );
33 let inner = container.resolve::<T>()?;
34 Ok(Self(inner))
35 }
36
37 pub fn into_inner(self) -> Arc<T> {
38 self.0
39 }
40}
41
42impl<T> Deref for Inject<T> {
43 type Target = T;
44
45 fn deref(&self) -> &Self::Target {
46 &self.0
47 }
48}
49
50impl<T> FromRequestParts<Container> for Inject<T>
55where
56 T: Send + Sync + 'static,
57{
58 type Rejection = HttpException;
59
60 async fn from_request_parts(
61 parts: &mut Parts,
62 state: &Container,
63 ) -> Result<Self, Self::Rejection> {
64 let request_id = crate::request::request_id_from_extensions(&parts.extensions);
65 let scoped_container = parts.extensions.get::<Container>().cloned();
66 let State(root_container): State<Container> = State::from_request_parts(parts, state)
67 .await
68 .map_err(|_| {
69 HttpException::internal_server_error("Container state not available")
70 .with_optional_request_id(request_id.clone())
71 })?;
72 let container = scoped_container.unwrap_or(root_container);
73
74 Self::from(&container).map_err(|err| {
75 HttpException::internal_server_error(format!(
76 "Failed to resolve dependency `{}`: {}",
77 std::any::type_name::<T>(),
78 err
79 ))
80 .with_optional_request_id(request_id)
81 })
82 }
83}
84
85impl<T> AsRef<T> for Inject<T> {
86 fn as_ref(&self) -> &T {
87 &self.0
88 }
89}