claudiofsr_lib/
macros.rs

1pub mod svec {
2    #![macro_use]
3    #[macro_export]
4    /**
5    Create a `Vec<String>` from `Vec<&str>`.
6
7    Example:
8    ```
9        use claudiofsr_lib::svec;
10
11        let v1: Vec<String> = svec![
12            "this",
13            "that",
14            "the other", // with or without a comma at the end
15        ];
16        let result1 = vec![
17            String::from("this"),
18            String::from("that"),
19            String::from("the other"),
20        ];
21
22        let v2 = svec![ "a", "1", "abc", "", "foobar"];
23        let result2 = vec![
24            "a",
25            "1",
26            "abc",
27            "",
28            "foobar",
29        ].iter().map(ToString::to_string).collect::<Vec<String>>();
30
31        assert_eq!(v1, result1);
32        assert_eq!(v2, result2);
33    ```
34    <https://doc.rust-lang.org/book/ch19-06-macros.html>
35
36    <https://doc.rust-lang.org/std/macro.vec.html>
37    */
38    macro_rules! svec {
39        ( $($x:expr_2021),+ $(,)?) => {
40            {
41                Vec::from([$(String::from($x)),*])
42            }
43        };
44    }
45
46    #[cfg(test)]
47    mod tests {
48        #[test]
49        fn macro_svec_works() {
50            let v = dbg!(svec!["this", "that", "the other", "123"]);
51            let x: Vec<String> = v;
52            assert_eq!(
53                x,
54                [
55                    String::from("this"),
56                    String::from("that"),
57                    String::from("the other"),
58                    String::from("123"),
59                ]
60            );
61        }
62    }
63}
64
65pub mod match_cast {
66    #![macro_use]
67    #[macro_export]
68    /**
69    Match through different types.
70
71    Example:
72    ```
73        use std::any::Any;
74        use chrono::NaiveDate;
75        use claudiofsr_lib::match_cast;
76
77        let opt_u8: Option<u8> = None;
78        let opt_u32: Option<u32> = Some(5);
79        let float64: f64 = 32.00870000;
80        let string: String = String::from("foo bar baz");
81        let opt_naivedate: Option<NaiveDate> = NaiveDate::from_ymd_opt(2015, 3, 14);
82
83        // With std::any::Any it is possible to obtain a vector with different types:
84        let values: Vec<&dyn Any> = vec![
85            &opt_u8,
86            &opt_u32,
87            &float64,
88            &string,
89            &opt_naivedate,
90        ];
91
92        // Get lengths of all items in the vector.
93        let lengths: Vec<usize> = values
94            .into_iter()
95            .map(|value| {
96                let opt_value_len: Option<usize> = match_cast!( value {
97                    val as Option<u8> => {
98                        val.as_ref().map(|s| s.to_string().chars().count())
99                    },
100                    val as Option<u32> => {
101                        val.as_ref().map(|s| s.to_string().chars().count())
102                    },
103                    val as f64 => {
104                        Some(val.to_string().chars().count())
105                    },
106                    val as String => {
107                        Some(val.chars().count())
108                    },
109                    val as Option<NaiveDate> => {
110                        // eprintln!("val: {val:?}"); // Some(2015-03-14)
111                        val.as_ref().map(|date| date.to_string().chars().count())
112                    }
113                });
114
115                opt_value_len.unwrap_or(0)
116            })
117            .collect();
118
119        assert_eq!(
120            lengths,
121            [0, 1, 7, 11, 10]
122        );
123    ```
124
125    Font: <https://github.com/therustmonk/match_cast/blob/master/src/lib.rs>
126    */
127    macro_rules! match_cast {
128        ($any:ident { $( $bind:ident as $patt:ty => $body:block $(,)? )+ }) => {{
129            let downcast = || {
130                $(
131                if let Some($bind) = $any.downcast_ref::<$patt>() {
132                    return $body;
133                }
134                )+
135                None
136            };
137            downcast()
138        }};
139    }
140
141    #[cfg(test)]
142    mod tests {
143        use chrono::NaiveDate;
144        use std::any::Any;
145
146        #[test]
147        fn macro_match_cast_works() {
148            let opt_u8: Option<u8> = None;
149            let opt_u32: Option<u32> = Some(5);
150            let opt_i64: Option<i64> = Some(83);
151            let opt_f32: Option<f32> = Some(5.78);
152            let float64: f64 = 32.00870000;
153            let string: String = String::from("foo bar baz");
154            let strings: Vec<String> = svec!["a", "ab", "abc"];
155            let opt_naivedate: Option<NaiveDate> = NaiveDate::from_ymd_opt(2015, 3, 14);
156            let naivedate: NaiveDate = NaiveDate::from_ymd_opt(2015, 3, 14).expect("date");
157
158            // Vector with different types
159            let values: Vec<&dyn Any> = vec![
160                &opt_u8,
161                &opt_u32,
162                &opt_i64,
163                &opt_f32,
164                &float64,
165                &string,
166                &strings,
167                &opt_naivedate,
168                &naivedate,
169            ];
170
171            // Get lengths of all items in the vector.
172            let lengths: Vec<usize> = values
173                .into_iter()
174                .map(|value| {
175                    let opt_value_len: Option<usize> = match_cast!( value {
176
177                        val as Option<u8> => {
178                            val.as_ref().map(|s| s.to_string().chars().count())
179                        },
180                        val as Option<u16> => {
181                            val.as_ref().map(|s| s.to_string().chars().count())
182                        },
183                        val as Option<u32> => {
184                            val.as_ref().map(|s| s.to_string().chars().count())
185                        },
186                        val as Option<u64> => {
187                            val.as_ref().map(|s| s.to_string().chars().count())
188                        },
189                        val as Option<u128> => {
190                            val.as_ref().map(|s| s.to_string().chars().count())
191                        },
192                        val as Option<usize> => {
193                            val.as_ref().map(|s| s.to_string().chars().count())
194                        },
195
196                        val as Option<i8> => {
197                            val.as_ref().map(|s| s.to_string().chars().count())
198                        },
199                        val as Option<i16> => {
200                            val.as_ref().map(|s| s.to_string().chars().count())
201                        },
202                        val as Option<i32> => {
203                            val.as_ref().map(|s| s.to_string().chars().count())
204                        },
205                        val as Option<i64> => {
206                            val.as_ref().map(|s| s.to_string().chars().count())
207                        },
208                        val as Option<i128> => {
209                            val.as_ref().map(|s| s.to_string().chars().count())
210                        },
211                        val as Option<isize> => {
212                            val.as_ref().map(|s| s.to_string().chars().count())
213                        },
214
215                        val as Option<f32> => {
216                            val.as_ref().map(|s| s.to_string().chars().count())
217                        },
218                        val as Option<f64> => {
219                            val.as_ref().map(|s| s.to_string().chars().count())
220                        },
221
222                        val as f32 => {
223                            Some(val.to_string().chars().count())
224                        },
225                        val as f64 => {
226                            Some(val.to_string().chars().count())
227                        },
228
229                        val as String => {
230                            Some(val.chars().count())
231                        },
232                        val as Option<String> => {
233                            val.as_ref().map(|s| s.chars().count())
234                        },
235                        val as Vec<String> => {
236                            Some(val.iter().map(|s| s.chars().count()).sum())
237                        },
238
239                        val as NaiveDate => {
240                            Some(val.to_string().chars().count())
241                        },
242                        val as Option<NaiveDate> => {
243                            // eprintln!("val: {val:?}"); // Some(2015-03-14)
244                            val.as_ref().map(|date| date.to_string().chars().count())
245                        }
246                    });
247
248                    opt_value_len.unwrap_or(0)
249                })
250                .collect();
251
252            assert_eq!(lengths, [0, 1, 2, 4, 7, 11, 6, 10, 10]);
253        }
254    }
255}