rust_lodash/utils/
type_conv.rs

1/*!
2Type conversion utilities for Lodash-RS.
3
4This module provides type conversion traits and utilities for handling
5different data types in a type-safe manner.
6*/
7
8use crate::utils::{LodashError, Result};
9
10/// Trait for types that can be converted to a key for grouping operations.
11pub trait ToKey {
12    /// Convert the value to a key.
13    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
70/// Trait for types that can be used as predicate functions.
71pub trait Predicate<T> {
72    /// Apply the predicate to the given value.
73    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
85/// Trait for types that can be used as mapper functions.
86pub trait Mapper<T, U> {
87    /// Apply the mapper to the given value.
88    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
100/// Trait for types that can be used as reducer functions.
101pub trait Reducer<T, U> {
102    /// Apply the reducer to the accumulator and value.
103    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
115/// Trait for types that can be converted to a comparable value for sorting.
116pub trait ToComparable {
117    /// Convert to a comparable value.
118    type Output: PartialOrd;
119    
120    /// Convert the value to a comparable type.
121    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
188/// Trait for types that can be safely cloned for collection operations.
189pub trait SafeClone {
190    /// Safely clone the value.
191    #[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
201/// Trait for types that can be converted to a hash key.
202pub trait ToHashKey {
203    /// Convert to a hash key.
204    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
259/// Utility function to safely convert between types.
260/// Safely convert a value from one type to another.
261/// 
262/// # Errors
263/// 
264/// Returns a `LodashError` if the conversion fails.
265pub 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
278/// Utility function to convert a value to a string representation.
279pub 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}