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> =
67 State::from_request_parts(parts, state).await.map_err(|_| {
68 HttpException::internal_server_error("Container state not available")
69 .with_optional_request_id(request_id.clone())
70 })?;
71 let container = scoped_container.unwrap_or(root_container);
72
73 Self::from(&container).map_err(|err| {
74 HttpException::internal_server_error(format!(
75 "Failed to resolve dependency `{}`: {}",
76 std::any::type_name::<T>(),
77 err
78 ))
79 .with_optional_request_id(request_id)
80 })
81 }
82}
83
84impl<T> AsRef<T> for Inject<T> {
85 fn as_ref(&self) -> &T {
86 &self.0
87 }
88}