1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use actix_web::{
    dev::Payload, error::ErrorInternalServerError, FromRequest, HttpRequest,
};
use futures_util::future::{err, ok, Ready};
use runtime_injector::{Injector, Request};
use std::ops::Deref;

/// An injected request. Any request to the [`Injector`] can be injected by
/// wrapping it in this type and providing it as a parameter to your request
/// handler.
///
/// ## Example
///
/// ```no_run
/// use actix_web::{get, App, HttpResponse, HttpServer, Responder};
/// use runtime_injector_actix::{
///     constant, define_module, Injected, Injector, Svc,
/// };
///
/// #[actix_web::main]
/// async fn main() -> std::io::Result<()> {
///     let mut builder = Injector::builder();
///     builder.add_module(define_module! {
///         services = [constant(4i32)],
///     });
///
///     let injector = builder.build();
///     HttpServer::new(move || {
///         App::new().app_data(injector.clone()).service(index)
///     })
///     .bind(("127.0.0.1", 8080))?
///     .run()
///     .await
/// }
///
/// #[get("/")]
/// async fn index(my_service: Injected<Svc<i32>>) -> impl Responder {
///     HttpResponse::Ok().body(format!("injected value is {}", *my_service))
/// }
/// ```
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Injected<R: Request>(R);

impl<R: Request> Injected<R> {
    /// Converts an [`Injected<R>`] to its inner value.
    pub fn into_inner(value: Injected<R>) -> R {
        value.0
    }
}

impl<R: Request> Deref for Injected<R> {
    type Target = R;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<R: Request> FromRequest for Injected<R> {
    type Error = actix_web::Error;
    type Future = Ready<actix_web::Result<Self>>;
    type Config = ();

    fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future {
        let injector: &Injector = match req.app_data() {
            Some(app_data) => app_data,
            None => {
                return err(ErrorInternalServerError(
                    "no injector is present in app_data",
                ))
            }
        };

        let inner = match injector.get() {
            Ok(inner) => inner,
            Err(error) => return err(ErrorInternalServerError(error)),
        };

        ok(Injected(inner))
    }
}