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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
//! Provides the [`TypedMap`] type, a hash map that allows to store key-value pair of type any type (K, V) such that
//! K implements [`TypedMapKey`] and [`TypedMapKey::Value`] is V.
//!
//! ```
//! use typedmap::{TypedMap, TypedMapKey};
//!
//! // Define key types
//! #[derive(Debug, PartialEq, Eq, Hash)]
//! struct Dog { name: String }
//! #[derive(Debug, PartialEq, Eq, Hash)]
//! struct Cat { name: String }
//!
//! struct Bark { volume: u32 }
//! struct Mew { pitch: f32 }
//!
//! // Define value type for key types
//! impl TypedMapKey for Dog {
//! type Value = Bark;
//! }
//! impl TypedMapKey for Cat {
//! type Value = Mew;
//! }
//! // Create a new empty map
//! let mut animal_sounds: TypedMap = TypedMap::new();
//! // Insert data
//! animal_sounds.insert(Dog { name: "Spiky".into() }, Bark { volume: 80 });
//! animal_sounds.insert(Cat { name: "Spot".into() }, Mew { pitch: 12000.0 });
//!
//! // Get for Dog key get value of type Bark.
//! let spiky_volume = animal_sounds.get(&Dog { name: "Spiky".into() }).unwrap().volume;
//! assert_eq!(spiky_volume, 80);
//! ```
//!
//! One can have multiple implementation
//! of [`TypedMapKey`] for a given type K by specifying `Marker` parameter.
//! For example, in a web service one may keep endpoint configuration
//! and endpoint serivce in two hashmaps.
//! ```
//! struct Configs;
//! struct Services;
//!
//! use typedmap::{TypedMap, TypedMapKey};
//!
//! #[derive(Debug, PartialEq, Eq, Hash)]
//! struct EndpointGet(String);
//! #[derive(Debug, PartialEq, Eq, Hash)]
//! struct EndpointPost(usize);
//!
//! struct EndpointGetConfig(String);
//! struct EndpointPostConfig(usize);
//!
//! struct EndpointGetService {}
//! struct EndpointPostService {}
//!
//! impl TypedMapKey<Configs> for EndpointGet {
//! type Value = EndpointGetConfig;
//! }
//!
//! impl TypedMapKey<Configs> for EndpointPost {
//! type Value = EndpointPostConfig;
//! }
//!
//! impl TypedMapKey<Services> for EndpointGet {
//! type Value = EndpointGetService;
//! }
//!
//! impl TypedMapKey<Services> for EndpointPost {
//! type Value = EndpointPostService;
//! }
//!
//! let mut configs: TypedMap<Configs> = TypedMap::new();
//! let mut services: TypedMap<Services> = TypedMap::new();
//!
//! configs.insert(EndpointGet("test".to_owned()), EndpointGetConfig("config".to_owned()));
//! configs.insert(EndpointPost(10), EndpointPostConfig(20));
//!
//! services.insert(EndpointGet("test".to_owned()), EndpointGetService {});
//! services.insert(EndpointPost(10), EndpointPostService {});
//! ```
//!
//! If `dashmap` feature is enabled, also a dashmap-backed [`TypedDashMap`] is available which allows to
//! perform hashmap operations concurrently.
//! ```
//! struct Configs;
//! struct Serivces;
//!
//! #[cfg(feature = "dashmap")]
//! use typedmap::{TypedDashMap, TypedMapKey};
//! #[cfg(feature = "dashmap")]
//! let mut configs: TypedDashMap<Configs> = TypedDashMap::new();
//! ```
//!
//! By default
//! [`TypedMap`] accepts keys and values that implement [Any](std::any::Any) trait (and of course [`TypedMapKey`] trait),
//! while [`TypedDashMap`] requires that keys and values meet `std::any::Any + Send + Sync` bounds.
//! However, both [`TypedMap`] and [`TypedDashMap`] can be parametrized with two type parameters: key bounds (`KB`) and value bounds (`VB`).
//! This mechanism allows to restrict what kind of keys and values can be stored in the hashmap. This crate provides four kind of bounds:
//! * [AnyBounds](bounds::AnyBounds) - represents `Any` bounds (used by default in [`TypedMap`]),
//! * [SyncAnyBounds](bounds::SyncAnyBounds) - represents `Any + Sync + Send` bounds (used by default in [`TypedDashMap`]),
//! * [CloneBounds](clone::CloneBounds) (if `clone` feature is enabled) - represents `Clone + Any` bounds - allows to restrict keys/values to clonable types,
//! * [SyncCloneBounds](clone::SyncCloneBounds) (if `clone` feature is enabled) - represents `Clone + Any + Send + Sync` bounds.
//!
//! These bounds can be specified in the type signature separately for keys and values, e.g.
//!
//! It is possible to define own bounds using [Bounds](bounds::Bounds) and [HasBounds](bounds::HasBounds) traits to add custom restrictions to values.
//! For example, you may want to enforce that each value implements a custom `Component` trait.
//! This can be done with a few lines of code using [impl_custom_bounds](crate::impl_custom_bounds) or [impl_custom_bounds_with_key_container](crate::impl_custom_bounds_with_key_container)
//! and [impl_dyn_trait_wrapper](crate::impl_dyn_trait_wrapper) macros.
//!
//! See [`bounds`] for a full example of implementation of bounds.
extern crate core;
pub use crate;
pub use crateTypedDashMap;
pub use crate;