metainfo/
lib.rs

1mod convert;
2mod faststr_map;
3mod kv;
4mod type_map;
5
6use std::{fmt, sync::Arc};
7
8use ahash::AHashMap;
9use convert::{Converter, HttpConverter, RpcConverter};
10use faststr::FastStr;
11pub use faststr_map::FastStrMap;
12use kv::Node;
13use paste::paste;
14pub use type_map::TypeMap;
15
16pub mod backward;
17pub mod forward;
18pub use backward::Backward;
19pub use forward::Forward;
20
21#[cfg(feature = "task_local")]
22tokio::task_local! {
23    pub static METAINFO: std::cell::RefCell<MetaInfo>;
24}
25
26/// Framework should all obey these prefixes.
27
28pub const RPC_PREFIX_PERSISTENT: &str = "RPC_PERSIST_";
29pub const RPC_PREFIX_TRANSIENT: &str = "RPC_TRANSIT_";
30pub const RPC_PREFIX_BACKWARD: &str = "RPC_BACKWARD_";
31pub const HTTP_PREFIX_PERSISTENT: &str = "rpc-persist-";
32pub const HTTP_PREFIX_TRANSIENT: &str = "rpc-transit-";
33pub const HTTP_PREFIX_BACKWARD: &str = "rpc-backward-";
34
35const DEFAULT_MAP_SIZE: usize = 10;
36
37/// `MetaInfo` is used to passthrough information between components and even client-server.
38///
39/// It supports two types of info: typed map and string k-v.
40///
41/// It is designed to be tree-like, which means you can share a `MetaInfo` with multiple children.
42///
43/// Note: only the current scope is mutable.
44///
45/// Examples:
46/// ```rust
47/// use metainfo::MetaInfo;
48///
49/// fn test() {
50///     let mut m1 = MetaInfo::new();
51///     m1.insert::<i8>(2);
52///     assert_eq!(*m1.get::<i8>().unwrap(), 2);
53///
54///     let (mut m1, mut m2) = m1.derive();
55///     assert_eq!(*m2.get::<i8>().unwrap(), 2);
56///
57///     m2.insert::<i8>(4);
58///     assert_eq!(*m2.get::<i8>().unwrap(), 4);
59///
60///     m2.remove::<i8>();
61///     assert_eq!(*m2.get::<i8>().unwrap(), 2);
62/// }
63/// ```
64#[derive(Default)]
65pub struct MetaInfo {
66    /// Parent is read-only, if we can't find the specified key in the current,
67    /// we search it in the parent scope.
68    parent: Option<Arc<MetaInfo>>,
69    tmap: Option<TypeMap>,
70    smap: Option<AHashMap<FastStr, FastStr>>, // for str k-v
71    faststr_tmap: Option<FastStrMap>,         // for newtype wrapper of FastStr
72
73    /// for information transport through client and server.
74    /// e.g. RPC
75    forward_node: Option<kv::Node>,
76    backward_node: Option<kv::Node>,
77}
78
79impl MetaInfo {
80    /// Creates an empty `MetaInfo`.
81    #[inline]
82    pub fn new() -> MetaInfo {
83        Default::default()
84    }
85
86    /// Creates an `MetaInfo` with the parent given.
87    ///
88    /// When the info is not found in the current scope, `MetaInfo` will try to get from parent.
89    ///
90    /// [`derive`] is more efficient than this. It is recommended to use [`derive`] instead of this.
91    #[inline]
92    pub fn from(parent: Arc<MetaInfo>) -> MetaInfo {
93        let forward_node = parent.forward_node.clone();
94        let backward_node = parent.backward_node.clone();
95        MetaInfo {
96            parent: Some(parent),
97            tmap: None,
98            smap: None,
99            faststr_tmap: None,
100
101            forward_node,
102            backward_node,
103        }
104    }
105
106    /// Derives the current [`MetaInfo`], returns two new equivalent `Metainfo`s.
107    ///
108    /// When the info is not found in the current scope, `MetaInfo` will try to get from parent.
109    ///
110    /// This is the recommended way.
111    #[inline]
112    pub fn derive(mut self) -> (MetaInfo, MetaInfo) {
113        if self.tmap.is_none() && self.smap.is_none() && self.faststr_tmap.is_none() {
114            // we can use the same parent as self to make the tree small
115            let new = MetaInfo {
116                parent: self.parent.clone(),
117                tmap: None,
118                smap: None,
119                faststr_tmap: None,
120                forward_node: self.forward_node.clone(),
121                backward_node: self.backward_node.clone(),
122            };
123            (self, new)
124        } else {
125            let forward_node = self.forward_node.take();
126            let backward_node = self.backward_node.take();
127            let mi = Arc::new(self);
128            (
129                MetaInfo::from_node(mi.clone(), forward_node.clone(), backward_node.clone()),
130                MetaInfo::from_node(mi, forward_node, backward_node),
131            )
132        }
133    }
134
135    /// Creates an `MetaInfo` with the parent and node given.
136    fn from_node(
137        parent: Arc<MetaInfo>,
138        forward_node: Option<kv::Node>,
139        backward_node: Option<kv::Node>,
140    ) -> MetaInfo {
141        MetaInfo {
142            parent: Some(parent),
143            tmap: None,
144            smap: None,
145            faststr_tmap: None,
146
147            forward_node,
148            backward_node,
149        }
150    }
151
152    /// Insert a type into this `MetaInfo`.
153    #[inline]
154    pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) {
155        self.tmap
156            .get_or_insert_with(|| TypeMap::with_capacity(DEFAULT_MAP_SIZE))
157            .insert(val);
158    }
159
160    /// Insert a faststr newtype into this `MetaInfo`.
161    #[inline]
162    pub fn insert_faststr<T: Send + Sync + 'static>(&mut self, val: FastStr) {
163        self.faststr_tmap
164            .get_or_insert_with(|| FastStrMap::with_capacity(DEFAULT_MAP_SIZE))
165            .insert::<T>(val);
166    }
167
168    /// Insert a string k-v into this `MetaInfo`.
169    #[inline]
170    pub fn insert_string(&mut self, key: FastStr, val: FastStr) {
171        self.smap
172            .get_or_insert_with(|| AHashMap::with_capacity(DEFAULT_MAP_SIZE))
173            .insert(key, val);
174    }
175
176    /// Check if `MetaInfo` contains entry
177    #[inline]
178    pub fn contains<T: 'static>(&self) -> bool {
179        if self
180            .tmap
181            .as_ref()
182            .map(|tmap| tmap.contains::<T>())
183            .unwrap_or(false)
184        {
185            return true;
186        }
187        self.parent
188            .as_ref()
189            .map(|parent| parent.as_ref().contains::<T>())
190            .unwrap_or(false)
191    }
192
193    /// Check if `MetaInfo` contains the given Faststr newtype
194    #[inline]
195    pub fn contains_faststr<T: 'static>(&self) -> bool {
196        if self
197            .faststr_tmap
198            .as_ref()
199            .map(|faststr_tmap| faststr_tmap.contains::<T>())
200            .unwrap_or(false)
201        {
202            return true;
203        }
204        self.parent
205            .as_ref()
206            .map(|parent| parent.as_ref().contains_faststr::<T>())
207            .unwrap_or(false)
208    }
209
210    /// Check if `MetaInfo` contains the given string k-v
211    #[inline]
212    pub fn contains_string<K: AsRef<str>>(&self, key: K) -> bool {
213        if self
214            .smap
215            .as_ref()
216            .map(|smap| smap.contains_key(key.as_ref()))
217            .unwrap_or(false)
218        {
219            return true;
220        }
221        self.parent
222            .as_ref()
223            .map(|parent| parent.as_ref().contains_string(key))
224            .unwrap_or(false)
225    }
226
227    /// Get a reference to a type previously inserted on this `MetaInfo`.
228    #[inline]
229    pub fn get<T: 'static>(&self) -> Option<&T> {
230        self.tmap.as_ref().and_then(|tmap| tmap.get()).or_else(|| {
231            self.parent
232                .as_ref()
233                .and_then(|parent| parent.as_ref().get::<T>())
234        })
235    }
236
237    /// Remove a type from this `MetaInfo` and return it.
238    /// Can only remove the type in the current scope.
239    #[inline]
240    pub fn remove<T: 'static>(&mut self) -> Option<T> {
241        self.tmap.as_mut().and_then(|tmap| tmap.remove::<T>())
242    }
243
244    /// Get a reference to a faststr newtype previously inserted on this `MetaInfo`.
245    #[inline]
246    pub fn get_faststr<T: 'static>(&self) -> Option<&FastStr> {
247        self.faststr_tmap
248            .as_ref()
249            .and_then(|faststr_tmap: &FastStrMap| faststr_tmap.get::<T>())
250            .or_else(|| {
251                self.parent
252                    .as_ref()
253                    .and_then(|parent| parent.as_ref().get_faststr::<T>())
254            })
255    }
256
257    /// Remove a faststr newtype from this `MetaInfo` and return it.
258    /// Can only remove the type in the current scope.
259    #[inline]
260    pub fn remove_faststr<T: 'static>(&mut self) -> Option<FastStr> {
261        self.faststr_tmap
262            .as_mut()
263            .and_then(|faststr_tmap| faststr_tmap.remove::<T>())
264    }
265
266    /// Get a reference to a string k-v previously inserted on this `MetaInfo`.
267    #[inline]
268    pub fn get_string<K: AsRef<str>>(&self, key: K) -> Option<&FastStr> {
269        self.smap
270            .as_ref()
271            .and_then(|smap| smap.get(key.as_ref()))
272            .or_else(|| {
273                self.parent
274                    .as_ref()
275                    .and_then(|parent| parent.as_ref().get_string(key))
276            })
277    }
278
279    /// Remove a string k-v from this `MetaInfo` and return it.
280    /// Can only remove the type in the current scope.
281    #[inline]
282    pub fn remove_string<K: AsRef<str>>(&mut self, key: K) -> Option<FastStr> {
283        self.smap
284            .as_mut()
285            .and_then(|smap| smap.remove(key.as_ref()))
286    }
287
288    /// Clear the `MetaInfo` of all inserted MetaInfo.
289    /// This will not clear the parent.
290    #[inline]
291    pub fn clear(&mut self) {
292        self.parent = None;
293        if let Some(tmap) = self.tmap.as_mut() {
294            tmap.clear()
295        }
296        if let Some(smap) = self.smap.as_mut() {
297            smap.clear()
298        }
299        if let Some(faststr_tmap) = self.faststr_tmap.as_mut() {
300            faststr_tmap.clear()
301        }
302        if let Some(forward_node) = self.forward_node.as_mut() {
303            forward_node.clear()
304        }
305        if let Some(backward_node) = self.backward_node.as_mut() {
306            backward_node.clear()
307        }
308    }
309
310    /// Extends self with the items from another `MetaInfo`.
311    /// Only extend the items in the current scope.
312    #[inline]
313    pub fn extend(&mut self, other: MetaInfo) {
314        if let Some(tmap) = other.tmap {
315            self.tmap
316                .get_or_insert_with(|| TypeMap::with_capacity(DEFAULT_MAP_SIZE))
317                .extend(tmap);
318        }
319
320        if let Some(smap) = other.smap {
321            self.smap
322                .get_or_insert_with(|| AHashMap::with_capacity(DEFAULT_MAP_SIZE))
323                .extend(smap);
324        }
325
326        if let Some(faststr_tmap) = other.faststr_tmap {
327            self.faststr_tmap
328                .get_or_insert_with(|| FastStrMap::with_capacity(DEFAULT_MAP_SIZE))
329                .extend(faststr_tmap);
330        }
331
332        if let Some(node) = other.forward_node {
333            if self.forward_node.is_none() {
334                self.forward_node = Some(node);
335            } else {
336                self.forward_node.as_mut().unwrap().extend(node);
337            }
338        }
339
340        if let Some(node) = other.backward_node {
341            if self.backward_node.is_none() {
342                self.backward_node = Some(node);
343            } else {
344                self.backward_node.as_mut().unwrap().extend(node);
345            }
346        }
347    }
348
349    fn ensure_forward_node(&mut self) {
350        if self.forward_node.is_none() {
351            self.forward_node = Some(Node::default())
352        }
353    }
354
355    fn ensure_backward_node(&mut self) {
356        if self.backward_node.is_none() {
357            self.backward_node = Some(Node::default())
358        }
359    }
360}
361
362macro_rules! get_impl {
363    ($name:ident,$node:ident,$func_name:ident) => {
364        paste! {
365            #[inline]
366            fn [<get_ $name>]<K: AsRef<str>>(&self, key: K) -> Option<FastStr> {
367                match self.[<$node _node>].as_ref() {
368                    Some(node) => node.[<get_ $func_name>](key),
369                    None => None,
370                }
371            }
372        }
373    };
374}
375
376macro_rules! set_impl {
377    ($name:ident,$node:ident,$func_name:ident) => {
378        paste! {
379            #[inline]
380            fn [<set_ $name>]<K: Into<FastStr>, V: Into<FastStr>>(
381                &mut self,
382                key: K,
383                value: V,
384            ) {
385                self.[<ensure_ $node _node>]();
386                self.[<$node _node>]
387                    .as_mut()
388                    .unwrap()
389                    .[<set_ $func_name>](key, value)
390            }
391        }
392    };
393}
394
395macro_rules! del_impl {
396    ($name:ident,$node:ident,$func_name:ident) => {
397        paste! {
398            #[inline]
399            fn [<del_ $name>]<K: AsRef<str>>(&mut self, key: K) -> Option<FastStr> {
400                if let Some(node) = self.[<$node _node>].as_mut() {
401                    node.[<del_ $func_name>](key)
402                } else {
403                    None
404                }
405            }
406        }
407    };
408}
409
410impl forward::Forward for MetaInfo {
411    get_impl!(persistent, forward, persistent);
412    get_impl!(transient, forward, transient);
413    get_impl!(upstream, forward, stale);
414
415    set_impl!(persistent, forward, persistent);
416    set_impl!(transient, forward, transient);
417    set_impl!(upstream, forward, stale);
418
419    del_impl!(persistent, forward, persistent);
420    del_impl!(transient, forward, transient);
421    del_impl!(upstream, forward, stale);
422
423    #[inline]
424    fn get_all_persistents(&self) -> Option<&AHashMap<FastStr, FastStr>> {
425        match self.forward_node.as_ref() {
426            Some(node) => node.get_all_persistents(),
427            None => None,
428        }
429    }
430
431    #[inline]
432    fn get_all_transients(&self) -> Option<&AHashMap<FastStr, FastStr>> {
433        match self.forward_node.as_ref() {
434            Some(node) => node.get_all_transients(),
435            None => None,
436        }
437    }
438
439    #[inline]
440    fn get_all_upstreams(&self) -> Option<&AHashMap<FastStr, FastStr>> {
441        match self.forward_node.as_ref() {
442            Some(node) => node.get_all_stales(),
443            None => None,
444        }
445    }
446
447    #[inline]
448    fn get_all_persistents_and_transients_with_rpc_prefix(
449        &self,
450    ) -> Option<AHashMap<FastStr, FastStr>> {
451        self.get_all_persistents_and_transients_with_prefix(RpcConverter)
452    }
453
454    #[inline]
455    fn get_all_persistents_and_transients_with_http_prefix(
456        &self,
457    ) -> Option<AHashMap<FastStr, FastStr>> {
458        self.get_all_persistents_and_transients_with_prefix(HttpConverter)
459    }
460
461    #[inline]
462    fn iter_persistents_and_transients_with_rpc_prefix(
463        &self,
464    ) -> impl Iterator<Item = (FastStr, &FastStr)> {
465        self.iter_all_persistents_and_transients_with_prefix(RpcConverter)
466    }
467
468    #[inline]
469    fn iter_persistents_and_transients_with_http_prefix(
470        &self,
471    ) -> impl Iterator<Item = (FastStr, &FastStr)> {
472        self.iter_all_persistents_and_transients_with_prefix(HttpConverter)
473    }
474
475    #[inline]
476    fn strip_rpc_prefix_and_set_persistent<K: AsRef<str>, V: Into<FastStr>>(
477        &mut self,
478        key: K,
479        value: V,
480    ) {
481        let key = key.as_ref();
482        if let Some(key) = RpcConverter.remove_persistent_prefix(key) {
483            self.set_persistent(key, value);
484        }
485    }
486
487    #[inline]
488    fn strip_rpc_prefix_and_set_upstream<K: AsRef<str>, V: Into<FastStr>>(
489        &mut self,
490        key: K,
491        value: V,
492    ) {
493        let key = key.as_ref();
494        if let Some(key) = RpcConverter.remove_transient_prefix(key) {
495            self.set_upstream(key, value);
496        }
497    }
498
499    #[inline]
500    fn strip_http_prefix_and_set_persistent<K: AsRef<str>, V: Into<FastStr>>(
501        &mut self,
502        key: K,
503        value: V,
504    ) {
505        let key = key.as_ref();
506        if let Some(key) = HttpConverter.remove_persistent_prefix(key) {
507            self.set_persistent(key, value);
508        }
509    }
510
511    #[inline]
512    fn strip_http_prefix_and_set_upstream<K: AsRef<str>, V: Into<FastStr>>(
513        &mut self,
514        key: K,
515        value: V,
516    ) {
517        let key = key.as_ref();
518        if let Some(key) = HttpConverter.remove_transient_prefix(key) {
519            self.set_upstream(key, value);
520        }
521    }
522}
523
524impl backward::Backward for MetaInfo {
525    get_impl!(backward_transient, backward, transient);
526    get_impl!(backward_downstream, backward, stale);
527
528    set_impl!(backward_transient, backward, transient);
529    set_impl!(backward_downstream, backward, stale);
530
531    del_impl!(backward_transient, backward, transient);
532    del_impl!(backward_downstream, backward, stale);
533
534    fn get_all_backward_transients(&self) -> Option<&AHashMap<FastStr, FastStr>> {
535        match self.backward_node.as_ref() {
536            Some(node) => node.get_all_transients(),
537            None => None,
538        }
539    }
540
541    fn get_all_backward_downstreams(&self) -> Option<&AHashMap<FastStr, FastStr>> {
542        match self.backward_node.as_ref() {
543            Some(node) => node.get_all_stales(),
544            None => None,
545        }
546    }
547
548    fn get_all_backward_transients_with_rpc_prefix(&self) -> Option<AHashMap<FastStr, FastStr>> {
549        self.get_all_backword_transients_with_prefix(RpcConverter)
550    }
551
552    fn get_all_backward_transients_with_http_prefix(&self) -> Option<AHashMap<FastStr, FastStr>> {
553        self.get_all_backword_transients_with_prefix(HttpConverter)
554    }
555
556    fn iter_backward_transients_with_rpc_prefix(
557        &self,
558    ) -> impl Iterator<Item = (FastStr, &FastStr)> {
559        self.iter_all_backword_transients_with_prefix(RpcConverter)
560    }
561
562    fn iter_backward_transients_with_http_prefix(
563        &self,
564    ) -> impl Iterator<Item = (FastStr, &FastStr)> {
565        self.iter_all_backword_transients_with_prefix(HttpConverter)
566    }
567
568    fn strip_rpc_prefix_and_set_backward_downstream<K: AsRef<str>, V: Into<FastStr>>(
569        &mut self,
570        key: K,
571        value: V,
572    ) {
573        let key = key.as_ref();
574        if let Some(key) = RpcConverter.remove_backward_prefix(key) {
575            self.set_backward_downstream(key, value);
576        }
577    }
578
579    fn strip_http_prefix_and_set_backward_downstream<K: AsRef<str>, V: Into<FastStr>>(
580        &mut self,
581        key: K,
582        value: V,
583    ) {
584        let key = key.as_ref();
585        if let Some(key) = HttpConverter.remove_backward_prefix(key) {
586            self.set_backward_downstream(key, value);
587        }
588    }
589}
590
591impl MetaInfo {
592    #[inline]
593    fn get_all_persistents_and_transients_with_prefix<C>(
594        &self,
595        converter: C,
596    ) -> Option<AHashMap<FastStr, FastStr>>
597    where
598        C: Converter,
599    {
600        match self.forward_node.as_ref() {
601            Some(node) => {
602                let persistents = node.get_all_persistents();
603                let transients = node.get_all_transients();
604                let new_cap = persistents.map(|p| p.len()).unwrap_or(0)
605                    + transients.map(|t| t.len()).unwrap_or(0);
606                if new_cap == 0 {
607                    return None;
608                }
609                let mut map = AHashMap::with_capacity(new_cap);
610                if let Some(persistents) = persistents {
611                    map.extend(
612                        persistents
613                            .iter()
614                            .map(|(k, v)| (converter.add_persistent_prefix(k), v.clone())),
615                    );
616                }
617                if let Some(transients) = transients {
618                    map.extend(
619                        transients
620                            .iter()
621                            .map(|(k, v)| (converter.add_transient_prefix(k), v.clone())),
622                    );
623                }
624                Some(map)
625            }
626            None => None,
627        }
628    }
629
630    #[inline]
631    fn iter_all_persistents_and_transients_with_prefix<C>(
632        &self,
633        converter: C,
634    ) -> impl Iterator<Item = (FastStr, &FastStr)>
635    where
636        C: Converter + Copy + 'static,
637    {
638        self.forward_node
639            .as_ref()
640            .into_iter()
641            .flat_map(move |node| {
642                let persistents = node.get_all_persistents().into_iter().flat_map(move |p| {
643                    p.into_iter()
644                        .map(move |(k, v)| (converter.add_persistent_prefix(k), v))
645                });
646                let transients = node.get_all_transients().into_iter().flat_map(move |t| {
647                    t.into_iter()
648                        .map(move |(k, v)| (converter.add_transient_prefix(k), v))
649                });
650                persistents.chain(transients)
651            })
652    }
653
654    #[inline]
655    fn get_all_backword_transients_with_prefix<C>(
656        &self,
657        converter: C,
658    ) -> Option<AHashMap<FastStr, FastStr>>
659    where
660        C: Converter,
661    {
662        match self.backward_node.as_ref() {
663            Some(node) => {
664                if let Some(t) = node.get_all_transients() {
665                    let new_cap = t.len();
666                    if new_cap == 0 {
667                        return None;
668                    }
669                    let mut map = AHashMap::with_capacity(new_cap);
670                    map.extend(
671                        t.iter()
672                            .map(|(k, v)| (converter.add_transient_prefix(k), v.clone())),
673                    );
674                    Some(map)
675                } else {
676                    None
677                }
678            }
679            None => None,
680        }
681    }
682
683    #[inline]
684    fn iter_all_backword_transients_with_prefix<C>(
685        &self,
686        converter: C,
687    ) -> impl Iterator<Item = (FastStr, &FastStr)>
688    where
689        C: Converter + 'static,
690    {
691        self.backward_node
692            .as_ref()
693            .into_iter()
694            .flat_map(|node| {
695                node.get_all_transients()
696                    .into_iter()
697                    .flat_map(|t| t.into_iter())
698            })
699            .map(move |(k, v)| (converter.add_transient_prefix(k), v))
700    }
701}
702
703impl fmt::Debug for MetaInfo {
704    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
705        f.debug_struct("MetaInfo").finish()
706    }
707}
708
709#[cfg(test)]
710mod tests {
711    use super::*;
712
713    #[test]
714    fn test_remove() {
715        let mut map = MetaInfo::new();
716
717        map.insert::<i8>(123);
718        assert!(map.get::<i8>().is_some());
719
720        map.remove::<i8>();
721        assert!(map.get::<i8>().is_none());
722
723        map.insert::<i8>(123);
724
725        let mut m2 = MetaInfo::from(Arc::new(map));
726
727        m2.remove::<i8>();
728        assert!(m2.get::<i8>().is_some());
729    }
730
731    #[test]
732    fn test_clear() {
733        let mut map = MetaInfo::new();
734
735        map.insert::<i8>(8);
736        map.insert::<i16>(16);
737        map.insert::<i32>(32);
738
739        assert!(map.contains::<i8>());
740        assert!(map.contains::<i16>());
741        assert!(map.contains::<i32>());
742
743        map.clear();
744
745        assert!(!map.contains::<i8>());
746        assert!(!map.contains::<i16>());
747        assert!(!map.contains::<i32>());
748
749        map.insert::<i8>(10);
750        assert_eq!(*map.get::<i8>().unwrap(), 10);
751    }
752
753    #[test]
754    fn test_integers() {
755        let mut map = MetaInfo::new();
756
757        map.insert::<i8>(8);
758        map.insert::<i16>(16);
759        map.insert::<i32>(32);
760        map.insert::<i64>(64);
761        map.insert::<i128>(128);
762        map.insert::<u8>(8);
763        map.insert::<u16>(16);
764        map.insert::<u32>(32);
765        map.insert::<u64>(64);
766        map.insert::<u128>(128);
767        assert!(map.get::<i8>().is_some());
768        assert!(map.get::<i16>().is_some());
769        assert!(map.get::<i32>().is_some());
770        assert!(map.get::<i64>().is_some());
771        assert!(map.get::<i128>().is_some());
772        assert!(map.get::<u8>().is_some());
773        assert!(map.get::<u16>().is_some());
774        assert!(map.get::<u32>().is_some());
775        assert!(map.get::<u64>().is_some());
776        assert!(map.get::<u128>().is_some());
777
778        let m2 = MetaInfo::from(Arc::new(map));
779        assert!(m2.get::<i8>().is_some());
780        assert!(m2.get::<i16>().is_some());
781        assert!(m2.get::<i32>().is_some());
782        assert!(m2.get::<i64>().is_some());
783        assert!(m2.get::<i128>().is_some());
784        assert!(m2.get::<u8>().is_some());
785        assert!(m2.get::<u16>().is_some());
786        assert!(m2.get::<u32>().is_some());
787        assert!(m2.get::<u64>().is_some());
788        assert!(m2.get::<u128>().is_some());
789    }
790
791    #[test]
792    fn test_composition() {
793        struct Magi<T>(pub T);
794
795        struct Madoka {
796            pub god: bool,
797        }
798
799        struct Homura {
800            pub attempts: usize,
801        }
802
803        struct Mami {
804            pub guns: usize,
805        }
806
807        let mut map = MetaInfo::new();
808
809        map.insert(Magi(Madoka { god: false }));
810        map.insert(Magi(Homura { attempts: 0 }));
811        map.insert(Magi(Mami { guns: 999 }));
812
813        assert!(!map.get::<Magi<Madoka>>().unwrap().0.god);
814        assert_eq!(0, map.get::<Magi<Homura>>().unwrap().0.attempts);
815        assert_eq!(999, map.get::<Magi<Mami>>().unwrap().0.guns);
816    }
817
818    #[test]
819    fn test_metainfo() {
820        #[derive(Debug, PartialEq)]
821        struct MyType(i32);
822
823        let mut metainfo = MetaInfo::new();
824
825        metainfo.insert(5i32);
826        metainfo.insert(MyType(10));
827
828        assert_eq!(metainfo.get(), Some(&5i32));
829
830        assert_eq!(metainfo.remove::<i32>(), Some(5i32));
831        assert!(metainfo.get::<i32>().is_none());
832
833        assert_eq!(metainfo.get::<bool>(), None);
834        assert_eq!(metainfo.get(), Some(&MyType(10)));
835    }
836
837    #[test]
838    fn test_extend() {
839        #[derive(Debug, PartialEq)]
840        struct MyType(i32);
841
842        let mut metainfo = MetaInfo::new();
843
844        metainfo.insert(5i32);
845        metainfo.insert(MyType(10));
846
847        let mut other = MetaInfo::new();
848
849        other.insert(15i32);
850        other.insert(20u8);
851
852        metainfo.extend(other);
853
854        assert_eq!(metainfo.get(), Some(&15i32));
855
856        assert_eq!(metainfo.remove::<i32>(), Some(15i32));
857        assert!(metainfo.get::<i32>().is_none());
858
859        assert_eq!(metainfo.get::<bool>(), None);
860        assert_eq!(metainfo.get(), Some(&MyType(10)));
861
862        assert_eq!(metainfo.get(), Some(&20u8));
863    }
864
865    #[test]
866    fn rpc_forward_test() {
867        let mut metainfo = MetaInfo::new();
868        metainfo.strip_rpc_prefix_and_set_persistent("RPC_PERSIST_TEST_KEY", "PERSIST");
869        metainfo.strip_rpc_prefix_and_set_upstream("RPC_TRANSIT_TEST_KEY", "TRANSIT");
870        assert_eq!(metainfo.get_persistent("TEST_KEY").unwrap(), "PERSIST");
871        assert_eq!(metainfo.get_upstream("TEST_KEY").unwrap(), "TRANSIT");
872        let map = metainfo
873            .get_all_persistents_and_transients_with_rpc_prefix()
874            .unwrap();
875        assert_eq!(map.get("RPC_PERSIST_TEST_KEY").unwrap(), "PERSIST");
876        // The `RPC_TRANSIT_TEST_KEY` is inserted into `upstream` and we cannot get it from
877        // `transients`.
878    }
879
880    #[test]
881    fn http_forward_test() {
882        let mut metainfo = MetaInfo::new();
883        metainfo.strip_http_prefix_and_set_persistent("rpc-persist-test-key", "persist");
884        metainfo.strip_http_prefix_and_set_upstream("rpc-transit-test-key", "transit");
885        assert_eq!(metainfo.get_persistent("TEST_KEY").unwrap(), "persist");
886        assert_eq!(metainfo.get_upstream("TEST_KEY").unwrap(), "transit");
887        let map = metainfo
888            .get_all_persistents_and_transients_with_http_prefix()
889            .unwrap();
890        assert_eq!(map.get("rpc-persist-test-key").unwrap(), "persist");
891        let iter = metainfo.iter_all_persistents_and_transients_with_prefix(HttpConverter);
892        assert_eq!(iter.count(), 1);
893        metainfo.set_persistent("test_key2", "test_value2");
894        let iter = metainfo.iter_all_persistents_and_transients_with_prefix(HttpConverter);
895        assert_eq!(iter.count(), 2);
896        // The `RPC_TRANSIT_TEST_KEY` is inserted into `upstream` and we cannot get it from
897        // `transients`.
898    }
899}