Skip to main content

tower_http_cache_plus/cache/key/
common.rs

1use super::{super::weight::*, key::*};
2
3use {
4    http::{header::*, uri::*, *},
5    kutil::{http::*, std::immutable::*},
6    std::{collections::*, fmt, hash::*},
7};
8
9//
10// CommonCacheKey
11//
12
13/// [CacheKey] implementation designed for common use cases.
14#[derive(Clone, Debug, Eq, Hash, PartialEq)]
15pub struct CommonCacheKey {
16    /// Method.
17    pub method: Method,
18
19    /// Optional path.
20    pub path: Option<ImmutableString>,
21
22    /// Optional query (sorted by key).
23    pub query: Option<QueryMap>,
24
25    /// Optional scheme.
26    ///
27    /// Not set by default but reserved for custom use.
28    pub scheme: Option<Scheme>,
29
30    /// Optional host.
31    ///
32    /// Not set by default but reserved for custom use.
33    pub host: Option<ImmutableString>,
34
35    /// Optional port.
36    ///
37    /// Not set by default but reserved for custom use.
38    pub port: Option<u16>,
39
40    /// Optional media type.
41    ///
42    /// Not set by default but reserved for custom use.
43    pub media_type: Option<MediaType>,
44
45    /// Optional languages (sorted).
46    ///
47    /// Not set by default but reserved for custom use.
48    pub languages: Option<BTreeSet<Language>>,
49
50    /// Optional extensions (sorted by key).
51    ///
52    /// Not set by default but reserved for custom use.
53    pub extensions: Option<BTreeMap<ImmutableBytes, ImmutableBytes>>,
54}
55
56impl CommonCacheKey {
57    /// Constructor.
58    pub fn new(
59        method: Method,
60        path: Option<ImmutableString>,
61        query: Option<QueryMap>,
62        scheme: Option<Scheme>,
63        host: Option<ImmutableString>,
64        port: Option<u16>,
65        media_type: Option<MediaType>,
66        languages: Option<BTreeSet<Language>>,
67        extensions: Option<BTreeMap<ImmutableBytes, ImmutableBytes>>,
68    ) -> Self {
69        Self {
70            method,
71            scheme,
72            host,
73            port,
74            path,
75            query,
76            media_type,
77            languages,
78            extensions,
79        }
80    }
81}
82
83impl CacheKey for CommonCacheKey {
84    fn for_request(method: &Method, uri: &Uri, _headers: &HeaderMap) -> Self {
85        let (path, query) = uri
86            .path_and_query()
87            .map(|path_and_query| {
88                (
89                    Some(path_and_query.path().into()),
90                    path_and_query.decoded_query_map(),
91                )
92            })
93            .unwrap_or_default();
94
95        Self::new(
96            method.clone(),
97            path,
98            query,
99            None,
100            None,
101            None,
102            None,
103            None,
104            None,
105        )
106    }
107}
108
109impl CacheWeight for CommonCacheKey {
110    fn cache_weight(&self) -> usize {
111        const SELF_SIZE: usize = size_of::<CommonCacheKey>();
112
113        let mut size = SELF_SIZE;
114
115        if let Some(host) = &self.host {
116            size += host.len();
117        }
118
119        if let Some(path) = &self.path {
120            size += path.len();
121        }
122
123        if let Some(query) = &self.query {
124            for (k, v) in query {
125                size += k.len() + v.len();
126            }
127        }
128
129        if let Some(media_type) = &self.media_type {
130            size += media_type.cache_weight();
131        }
132
133        if let Some(languages) = &self.languages {
134            for language in languages {
135                size += language.cache_weight();
136            }
137        }
138
139        if let Some(extensions) = &self.extensions {
140            for (k, v) in extensions {
141                size += k.len() + v.len();
142            }
143        }
144
145        size
146    }
147}
148
149impl fmt::Display for CommonCacheKey {
150    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
151        let scheme = self
152            .scheme
153            .as_ref()
154            .map(|scheme| scheme.as_str())
155            .unwrap_or_default();
156        let host = self
157            .host
158            .as_ref()
159            .map(|host| AsRef::<str>::as_ref(host))
160            .unwrap_or_default();
161        let port = self.port.map(|port| port.to_string()).unwrap_or_default();
162        let path = self
163            .path
164            .as_ref()
165            .map(|path| AsRef::<str>::as_ref(path))
166            .unwrap_or_default();
167
168        let query = self
169            .query
170            .as_ref()
171            .map(|parameter| {
172                let mut string = String::default();
173                for (key, values) in parameter {
174                    for value in values {
175                        if !string.is_empty() {
176                            string += "&"
177                        }
178                        string += &format!("{}={}", key, value);
179                    }
180                }
181                string
182            })
183            .unwrap_or_default();
184
185        let media_type = self
186            .media_type
187            .as_ref()
188            .map(|media_type| media_type.to_string())
189            .unwrap_or_default();
190
191        let languages = self
192            .languages
193            .as_ref()
194            .map(|languages| {
195                let languages: Vec<_> = languages
196                    .iter()
197                    .map(|language| language.to_string())
198                    .collect();
199                languages.join(",")
200            })
201            .unwrap_or_default();
202
203        let extensions = self
204            .extensions
205            .as_ref()
206            .map(|extension| {
207                let mut string = String::default();
208                for (key, value) in extension {
209                    if !string.is_empty() {
210                        string += "&"
211                    }
212                    // We only display the length
213                    string += &format!("{}={}", key.len(), value.len());
214                }
215                string
216            })
217            .unwrap_or_default();
218
219        write!(
220            formatter,
221            "{}|{}|{}|{}|{}|{}|{}|{}|{}",
222            self.method, scheme, host, port, path, query, media_type, languages, extensions
223        )
224    }
225}