rust_lodash/utils/
type_conv.rs1use crate::utils::{LodashError, Result};
9
10pub trait ToKey {
12 fn to_key(&self) -> String;
14}
15
16impl ToKey for String {
17 fn to_key(&self) -> String {
18 self.clone()
19 }
20}
21
22impl ToKey for &str {
23 fn to_key(&self) -> String {
24 (*self).to_string()
25 }
26}
27
28impl ToKey for i32 {
29 fn to_key(&self) -> String {
30 (*self).to_string()
31 }
32}
33
34impl ToKey for i64 {
35 fn to_key(&self) -> String {
36 (*self).to_string()
37 }
38}
39
40impl ToKey for u32 {
41 fn to_key(&self) -> String {
42 (*self).to_string()
43 }
44}
45
46impl ToKey for u64 {
47 fn to_key(&self) -> String {
48 (*self).to_string()
49 }
50}
51
52impl ToKey for f32 {
53 fn to_key(&self) -> String {
54 (*self).to_string()
55 }
56}
57
58impl ToKey for f64 {
59 fn to_key(&self) -> String {
60 (*self).to_string()
61 }
62}
63
64impl ToKey for bool {
65 fn to_key(&self) -> String {
66 (*self).to_string()
67 }
68}
69
70pub trait Predicate<T> {
72 fn apply(&self, value: &T) -> bool;
74}
75
76impl<T, F> Predicate<T> for F
77where
78 F: Fn(&T) -> bool,
79{
80 fn apply(&self, value: &T) -> bool {
81 self(value)
82 }
83}
84
85pub trait Mapper<T, U> {
87 fn apply(&self, value: &T) -> U;
89}
90
91impl<T, U, F> Mapper<T, U> for F
92where
93 F: Fn(&T) -> U,
94{
95 fn apply(&self, value: &T) -> U {
96 self(value)
97 }
98}
99
100pub trait Reducer<T, U> {
102 fn apply(&self, acc: U, value: &T) -> U;
104}
105
106impl<T, U, F> Reducer<T, U> for F
107where
108 F: Fn(U, &T) -> U,
109{
110 fn apply(&self, acc: U, value: &T) -> U {
111 self(acc, value)
112 }
113}
114
115pub trait ToComparable {
117 type Output: PartialOrd;
119
120 fn to_comparable(&self) -> Self::Output;
122}
123
124impl ToComparable for i32 {
125 type Output = i32;
126
127 fn to_comparable(&self) -> Self::Output {
128 *self
129 }
130}
131
132impl ToComparable for i64 {
133 type Output = i64;
134
135 fn to_comparable(&self) -> Self::Output {
136 *self
137 }
138}
139
140impl ToComparable for u32 {
141 type Output = u32;
142
143 fn to_comparable(&self) -> Self::Output {
144 *self
145 }
146}
147
148impl ToComparable for u64 {
149 type Output = u64;
150
151 fn to_comparable(&self) -> Self::Output {
152 *self
153 }
154}
155
156impl ToComparable for f32 {
157 type Output = f32;
158
159 fn to_comparable(&self) -> Self::Output {
160 *self
161 }
162}
163
164impl ToComparable for f64 {
165 type Output = f64;
166
167 fn to_comparable(&self) -> Self::Output {
168 *self
169 }
170}
171
172impl ToComparable for String {
173 type Output = String;
174
175 fn to_comparable(&self) -> Self::Output {
176 self.clone()
177 }
178}
179
180impl ToComparable for &str {
181 type Output = String;
182
183 fn to_comparable(&self) -> Self::Output {
184 (*self).to_string()
185 }
186}
187
188pub trait SafeClone {
190 #[must_use]
192 fn safe_clone(&self) -> Self;
193}
194
195impl<T: Clone> SafeClone for T {
196 fn safe_clone(&self) -> Self {
197 self.clone()
198 }
199}
200
201pub trait ToHashKey {
203 fn to_hash_key(&self) -> u64;
205}
206
207impl ToHashKey for i32 {
208 fn to_hash_key(&self) -> u64 {
209 #[allow(clippy::cast_sign_loss)]
210 {
211 *self as u64
212 }
213 }
214}
215
216impl ToHashKey for i64 {
217 fn to_hash_key(&self) -> u64 {
218 #[allow(clippy::cast_sign_loss)]
219 {
220 *self as u64
221 }
222 }
223}
224
225impl ToHashKey for u32 {
226 fn to_hash_key(&self) -> u64 {
227 u64::from(*self)
228 }
229}
230
231impl ToHashKey for u64 {
232 fn to_hash_key(&self) -> u64 {
233 *self
234 }
235}
236
237impl ToHashKey for String {
238 fn to_hash_key(&self) -> u64 {
239 use std::collections::hash_map::DefaultHasher;
240 use std::hash::{Hash, Hasher};
241
242 let mut hasher = DefaultHasher::new();
243 self.hash(&mut hasher);
244 hasher.finish()
245 }
246}
247
248impl ToHashKey for &str {
249 fn to_hash_key(&self) -> u64 {
250 use std::collections::hash_map::DefaultHasher;
251 use std::hash::{Hash, Hasher};
252
253 let mut hasher = DefaultHasher::new();
254 self.hash(&mut hasher);
255 hasher.finish()
256 }
257}
258
259pub fn safe_convert<T, U>(value: T) -> Result<U>
266where
267 T: std::fmt::Display,
268 U: std::str::FromStr,
269 U::Err: std::fmt::Display,
270{
271 value.to_string().parse::<U>()
272 .map_err(|_e| LodashError::type_conversion(
273 std::any::type_name::<T>(),
274 std::any::type_name::<U>()
275 ))
276}
277
278pub fn to_string<T>(value: &T) -> String
280where
281 T: std::fmt::Display,
282{
283 value.to_string()
284}
285
286#[cfg(test)]
287mod tests {
288 use super::*;
289
290 #[test]
291 fn test_to_key() {
292 assert_eq!("hello".to_key(), "hello");
293 assert_eq!(42.to_key(), "42");
294 assert_eq!(true.to_key(), "true");
295 }
296
297 #[test]
298 fn test_predicate() {
299 let pred = |x: &i32| *x > 5;
300 assert!(Predicate::apply(&pred, &6));
301 assert!(!Predicate::apply(&pred, &4));
302 }
303
304 #[test]
305 fn test_mapper() {
306 let mapper = |x: &i32| x * 2;
307 assert_eq!(mapper.apply(&3), 6);
308 }
309
310 #[test]
311 fn test_reducer() {
312 let reducer = |acc: i32, x: &i32| acc + x;
313 assert_eq!(reducer.apply(5, &3), 8);
314 }
315
316 #[test]
317 fn test_to_comparable() {
318 assert_eq!(42.to_comparable(), 42);
319 assert_eq!("hello".to_comparable(), "hello");
320 }
321
322 #[test]
323 fn test_safe_clone() {
324 let original = vec![1, 2, 3];
325 let cloned = original.safe_clone();
326 assert_eq!(original, cloned);
327 }
328
329 #[test]
330 fn test_to_hash_key() {
331 let key1 = 42.to_hash_key();
332 let key2 = 42.to_hash_key();
333 assert_eq!(key1, key2);
334
335 let str_key1 = "hello".to_hash_key();
336 let str_key2 = "hello".to_hash_key();
337 assert_eq!(str_key1, str_key2);
338 }
339}