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}