typedmap/
clone.rs

1//! Provides struct for `Clone` bounds.
2use std::any::Any;
3
4use dyn_clone::DynClone;
5
6use crate::bounds::{Bounds, ContainerWithHash};
7use crate::{impl_custom_bounds_with_key_container, TypedMap};
8
9/// Basically dyn trait object for cloneable types
10pub trait CloneAny: DynClone + Any {
11    fn as_any(&self) -> &dyn Any;
12    fn as_mut_any(&mut self) -> &mut dyn Any;
13    fn as_any_box(self: Box<Self>) -> Box<dyn Any>;
14}
15
16dyn_clone::clone_trait_object!(CloneAny);
17
18impl<T: Clone + Any> CloneAny for T {
19    fn as_any(&self) -> &dyn Any {
20        self
21    }
22
23    fn as_mut_any(&mut self) -> &mut dyn Any {
24        self
25    }
26
27    fn as_any_box(self: Box<Self>) -> Box<dyn Any> {
28        self
29    }
30}
31
32/// Clones dyn CloneAny type.
33pub fn clone_box<T: ?Sized + CloneAny>(t: &T) -> Box<T> {
34    dyn_clone::clone_box(t)
35}
36
37/// CloneBounds is used to bound keys or values stored in hashmap to cloneable types.
38/// ```rust
39/// use std::sync::Arc;
40/// use typedmap::{TypedMap, TypedMapKey};
41/// use typedmap::clone::{clone_box, CloneBounds};
42/// let mut map: TypedMap::<(), CloneBounds, CloneBounds, _> = TypedMap::default();
43///
44/// #[derive(PartialEq, Eq, Hash, Debug)]
45/// struct Key;
46///
47/// #[derive(Clone, Eq, PartialEq, Hash, Debug)]
48/// struct CloneKey;
49///
50/// impl TypedMapKey for Key {
51///     type Value = u32;
52/// }
53///
54/// impl TypedMapKey for CloneKey {
55///     type Value = u32;
56/// }
57///
58/// map.insert(CloneKey, 32);
59/// // Won't compile, because Key is not Clone
60/// // map.insert(Key, 32);
61///
62/// for elem in map.iter() {
63///     let cloned = clone_box(elem.key_container_ref());
64///     let key = *cloned.as_any_box().downcast::<CloneKey>().unwrap();
65///     assert_eq!(key, CloneKey);
66///
67///     let cloned = clone_box(elem.value_container_ref());
68///     let value = *cloned.as_any_box().downcast::<u32>().unwrap();
69///     assert_eq!(value, 32);
70/// }
71/// ```
72///
73pub struct CloneBounds;
74
75pub trait ContainerWithHashAndClone<B: Bounds>: ContainerWithHash<B> + CloneAny {}
76
77impl<B: Bounds, K: ContainerWithHash<B> + CloneAny + 'static> ContainerWithHashAndClone<B> for K {}
78
79/// Bounds for Cloneable keys or values which are Send & Sync
80pub struct SyncCloneBounds;
81impl_custom_bounds_with_key_container!(
82    CloneBounds,
83    CloneAny,
84    dyn ContainerWithHashAndClone<CloneBounds>,
85    CloneAny
86);
87impl_custom_bounds_with_key_container!(
88    SyncCloneBounds,
89    CloneAny,
90    dyn ContainerWithHashAndClone<SyncCloneBounds> + Send + Sync,
91    CloneAny, + Send + Sync
92);
93
94impl<M, KB: 'static + Bounds, VB: 'static + Bounds> Clone for TypedMap<M, KB, VB>
95where
96    KB::KeyContainer: CloneAny,
97    VB::Container: CloneAny,
98{
99    fn clone(&self) -> Self {
100        self.iter().map(|pair| pair.to_owned()).collect()
101    }
102}
103
104#[cfg(feature = "dashmap")]
105impl<M, KB: 'static + Bounds, VB: 'static + Bounds> Clone for crate::TypedDashMap<M, KB, VB>
106where
107    KB::KeyContainer: CloneAny,
108    VB::Container: CloneAny,
109{
110    fn clone(&self) -> Self {
111        self.iter().map(|pair| pair.to_owned()).collect()
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use crate::clone::{CloneBounds, SyncCloneBounds};
118
119    use crate::TypedMap;
120    use crate::TypedMapKey;
121
122    struct Marker;
123
124    impl TypedMapKey<Marker> for String {
125        type Value = String;
126    }
127
128    #[test]
129    fn test_clone_typed_map() {
130        let mut map: TypedMap<Marker, CloneBounds, SyncCloneBounds> = TypedMap::new_with_bounds();
131        map.insert("String".to_owned(), "Value".to_owned());
132
133        let map2 = map.clone();
134        assert_eq!(map2.get(&"String".to_owned()), Some(&"Value".to_owned()))
135    }
136
137    #[cfg(feature = "dashmap")]
138    #[test]
139    fn test_clone() {
140        use crate::clone::SyncCloneBounds;
141        use crate::TypedDashMap;
142        let state: TypedDashMap<Marker, SyncCloneBounds, SyncCloneBounds> =
143            TypedDashMap::new_with_bounds();
144        state.insert("Key".to_owned(), "Value".to_owned());
145
146        let cloned = state.clone();
147        assert_eq!(
148            state.get(&"Key".to_owned()).unwrap().value(),
149            cloned.get(&"Key".to_owned()).unwrap().value()
150        );
151    }
152}