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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//! affix middleware is used to add any data to depot.

use std::any::TypeId;

use salvo_core::handler;
use salvo_core::prelude::*;

trait Affix {
    fn attach(&self, depot: &mut Depot);
}

#[derive(Default)]
struct AffixCell<V> {
    key: String,
    value: V,
}
impl<T> Affix for AffixCell<T>
where
    T: Send + Sync + Clone + 'static,
{
    fn attach(&self, depot: &mut Depot) {
        depot.insert(self.key.clone(), self.value.clone());
    }
}

/// Inject a value into depot.
#[inline]
pub fn inject<V: Send + Sync + Clone + 'static>(value: V) -> AffixList {
    insert(format!("{:?}", TypeId::of::<V>()), value)
}

/// Insert a key-value pair into depot.
#[inline]
pub fn insert<K, V>(key: K, value: V) -> AffixList
where
    K: Into<String>,
    V: Send + Sync + Clone + 'static,
{
    AffixList::new().insert(key, value)
}

/// AffixList is used to add any data to depot.
#[derive(Default)]
pub struct AffixList(Vec<Box<dyn Affix + Send + Sync + 'static>>);

#[handler]
impl AffixList {
    /// Create an empty affix list.
    pub fn new() -> AffixList {
        AffixList(Vec::new())
    }
    /// Inject a value into depot.
    pub fn inject<V: Send + Sync + Clone + 'static>(self, value: V) -> Self {
        self.insert(format!("{:?}", TypeId::of::<V>()), value)
    }

    /// Insert a key-value pair into depot.
    pub fn insert<K, V>(mut self, key: K, value: V) -> Self
    where
        K: Into<String>,
        V: Send + Sync + Clone + 'static,
    {
        let cell = AffixCell { key: key.into(), value };
        self.0.push(Box::new(cell));
        self
    }
    async fn handle(&self, depot: &mut Depot) {
        for cell in &self.0 {
            cell.attach(depot);
        }
    }
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;

    use salvo_core::prelude::*;
    use salvo_core::test::{ResponseExt, TestClient};

    use super::*;
    
    struct User {
        name: String,
    }
    #[handler]
    async fn hello(depot: &mut Depot) -> String {
        format!(
            "{}:{}",
            depot.obtain::<Arc<User>>().map(|u| u.name.clone()).unwrap_or_default(),
            depot.get::<&str>("data1").copied().unwrap_or_default()
        )
    }
    #[tokio::test]
    async fn test_affix() {
        let user = User {
            name: "salvo".to_string(),
        };
        let router = Router::with_hoop(inject(Arc::new(user)).insert("data1", "powerful")).handle(hello);
        let content = TestClient::get("http://127.0.0.1:5800/")
            .send(router)
            .await
            .take_string()
            .await;
        assert_eq!(content.unwrap(), "salvo:powerful");
    }
}