colmac/lib.rs
1//! Macros to work with `std::collections` that are mostly straight-forward syntactic sugars.
2pub use std::collections::HashMap;
3pub use std::collections::HashSet;
4
5/// Counts the number of `args` passed to this macro invocation.
6///
7/// Returns the count as `usize`.
8///
9/// # Examples
10///
11/// ```
12/// #[macro_use] extern crate colmac;
13///
14/// assert_eq!(0, count_args!());
15/// assert_eq!(1, count_args!("one"));
16/// assert_eq!(3, count_args!("one", "two", "three"));
17/// ```
18#[macro_export]
19macro_rules! count_args {
20 // base cases
21 () => {
22 0usize
23 };
24 ( $arg:expr ) => {
25 1usize
26 };
27 // recurse
28 ( $arg:expr, $( $rest:expr ),* ) => {
29 1usize + count_args!( $( $rest ),* )
30 };
31}
32
33/// Sugar for `String::new` and `String::from`.
34///
35/// # Examples
36///
37/// ```
38/// #[macro_use] extern crate colmac;
39///
40/// // create an empty string
41/// assert_eq!(String::new(), string!());
42///
43/// // syntactically identical
44/// assert_eq!(String::from("abc"), string!("abc"));
45/// ```
46#[macro_export]
47macro_rules! string {
48 () => {
49 String::new()
50 };
51 ( $arg:expr ) => {
52 String::from($arg)
53 };
54}
55
56/// Concatenate multiple sliceable structs like `Vec` or `String`.
57///
58/// Does not mutate the input structs.
59///
60/// ```
61/// #[macro_use] extern crate colmac;
62///
63/// let a = vec![1, 2];
64/// let b = vec![3, 4];
65/// let c = vec![5, 6];
66///
67/// assert_eq!(concat_vec![a, b], vec![1, 2, 3, 4]);
68/// assert_eq!(concat_vec![a, c, b], vec![1, 2, 5, 6, 3, 4]);
69/// ```
70#[macro_export]
71macro_rules! concat_vec {
72 ( $( $sliceable:expr ),* ) => {{
73 [
74 $(
75 &$sliceable[..],
76 )*
77 ].concat()
78 }};
79}
80
81/// Just like `vec!`, but for `std::collections::HashMap`.
82///
83/// This macro uses `count_args!` to preallocate the exact amount of memory
84/// needed, so it's more efficient than simply iteratively inserting.
85///
86/// ```
87/// #[macro_use] extern crate colmac;
88///
89/// use std::collections::HashMap;
90///
91/// // create an empty one
92/// let empty: HashMap<u64, u64> = hashmap![];
93/// assert_eq!(0, empty.len());
94///
95/// // literal initialization
96/// let mut map_a = HashMap::new();
97/// map_a.insert("a", 123);
98/// map_a.insert("b", 456);
99///
100/// let map_b = hashmap!["a" => 123, "b" => 456];
101/// assert_eq!(map_a, map_b);
102/// ```
103#[macro_export]
104macro_rules! hashmap {
105 () => {
106 HashMap::new()
107 };
108 ( $( $key:expr => $value:expr ),* ) => {{
109 let size = count_args!( $( $key ),* );
110 let mut map = HashMap::with_capacity(size);
111 $(
112 map.insert($key, $value);
113 )*
114 map
115 }};
116}
117
118/// Just like `vec!`, but for `std::collections::HashSet`.
119///
120/// This macro uses `count_args!` to preallocate the exact amount of memory
121/// needed, so it's more efficient than simply iteratively inserting.
122///
123/// ```
124/// #[macro_use] extern crate colmac;
125///
126/// use std::collections::HashSet;
127///
128/// // create an empty one
129/// let empty: HashSet<u64> = hashset![];
130/// assert_eq!(0, empty.len());
131///
132/// // literal initialization
133/// let mut set_a = HashSet::new();
134/// set_a.insert(123);
135/// set_a.insert(456);
136///
137/// let set_b = hashset!(123, 456);
138/// assert_eq!(set_a, set_b);
139/// ```
140#[macro_export]
141macro_rules! hashset {
142 () => {
143 HashSet::new()
144 };
145 ( $( $elem:expr ),* ) => {{
146 let size = count_args!( $($elem),* );
147 let mut set = HashSet::with_capacity(size);
148 $(
149 set.insert($elem);
150 )*
151 set
152 }};
153}
154
155/// Sorts the input collection that impl's the trait `std::ops::IndexMut`.
156///
157/// There are two ways to invoke this macro:
158/// 1. with one argument, a mutable collection
159/// 1. uses [`slice::sort_unstable`](https://doc.rust-lang.org/std/primitive.slice.html#method.sort_unstable) to sort
160/// 1. with two arguments, a mutable collection followed by a closure
161/// 1. passes the closure to [`slice::sort_unstable_by`](https://doc.rust-lang.org/std/primitive.slice.html#method.sort_unstable_by) to sort
162///
163/// # Examples
164///
165/// ```
166/// #[macro_use] extern crate colmac;
167/// use std::cmp::Ordering::{Equal, Greater, Less};
168///
169/// // sort without a custom closure
170/// let mut v1 = vec![2, 4, -1];
171/// sort!(v1);
172/// assert_eq!(vec![-1, 2, 4], v1);
173///
174/// // sort with; sort in reverse order
175/// let mut v2 = vec![2, 4, -1];
176/// sort!(v2, |a, b| match a.cmp(b) {
177/// Less => Greater,
178/// Greater => Less,
179/// Equal => Equal,
180/// });
181/// assert_eq!(vec![4, 2, -1], v2);
182/// ```
183#[macro_export]
184macro_rules! sort {
185 ( $collection:expr ) => {
186 (&mut $collection[..]).sort_unstable();
187 };
188 ( $collection:expr, $compare_fn:expr ) => {
189 (&mut $collection[..]).sort_unstable_by($compare_fn);
190 };
191}
192
193/// Creates a sorted `Vec` with cloned elements of the input collection, leaving the original
194/// collection untouched.
195///
196/// The input collection should support `.iter()` method that returns an `Iterator` over its
197/// elemnts.
198///
199/// There are two ways to invoke this macro:
200/// 1. with one argument, a mutable collection
201/// 1. uses [`slice::sort_unstable`](https://doc.rust-lang.org/std/primitive.slice.html#method.sort_unstable) to sort
202/// 1. with two arguments, a mutable collection followed by a closure
203/// 1. passes the closure to [`slice::sort_unstable_by`](https://doc.rust-lang.org/std/primitive.slice.html#method.sort_unstable_by) to sort
204///
205/// # Examples
206///
207/// ```
208/// #[macro_use] extern crate colmac;
209/// use std::cmp::Ordering::{Equal, Greater, Less};
210///
211/// // sort without a custom closure
212/// let v1 = vec![2, 4, -1];
213/// let v1_sorted = sorted!(v1);
214/// assert_eq!(vec![2, 4, -1], v1); // v1 is not modified
215/// assert_eq!(vec![-1, 2, 4], v1_sorted);
216///
217/// // sort with; sort in reverse order
218/// let v2 = vec![2, 4, -1];
219/// let v2_sorted = sorted!(v2, |a, b| match a.cmp(b) {
220/// Less => Greater,
221/// Greater => Less,
222/// Equal => Equal,
223/// });
224/// assert_eq!(vec![2, 4, -1], v2); // v2 is not modified
225/// assert_eq!(vec![4, 2, -1], v2_sorted);
226/// ```
227#[macro_export]
228macro_rules! sorted {
229 ( $collection:expr ) => {{
230 let mut clones: Vec<_> = $collection.iter().cloned().collect();
231 sort!(clones);
232 clones
233 }};
234 ( $collection:expr, $compare_fn:expr ) => {{
235 let mut clones: Vec<_> = $collection.iter().cloned().collect();
236 sort!(clones, $compare_fn);
237 clones
238 }};
239}
240
241/// Creates a sorted `Vec<f64>` from the input.
242///
243/// This is a syntactic sugar for calling `sorted!` with the closure
244/// `|a, b| a.partial_cmp(b).unwrap()`.
245///
246/// # Examples
247///
248/// ```
249/// #[macro_use] extern crate colmac;
250/// # use std::cmp::Ordering::{Equal, Greater, Less};
251///
252/// // sort some collection that impl's `IntoIterator`
253/// let vec = vec![2.0, 4.0, -1.0];
254///
255/// let sorted_vec = sorted_f64!(vec);
256/// let expected = vec![-1.0, 2.0, 4.0];
257///
258/// assert_eq!(expected, sorted_vec);
259/// ```
260#[macro_export]
261macro_rules! sorted_f64 {
262 ( $collection:expr ) => {
263 sorted!($collection, |a, b| a.partial_cmp(b).unwrap())
264 };
265}
266
267#[cfg(test)]
268mod tests {
269 use super::*;
270 use std::cmp::Ordering::{Equal, Greater, Less};
271
272 mod count_args {
273 use super::*;
274
275 #[test]
276 fn zero() {
277 let expected = 0;
278 let result = count_args!();
279 assert_eq!(expected, result);
280 }
281 #[test]
282 fn one() {
283 let expected = 1;
284 let result = count_args!(10);
285 assert_eq!(expected, result);
286 }
287 #[test]
288 fn many() {
289 let expected = 4;
290 let result = count_args!(10, 20, 30, 40);
291 assert_eq!(expected, result);
292 }
293 }
294
295 mod concat_vec {
296 #[test]
297 fn one() {
298 let a = vec![1, 2];
299
300 let expected = vec![1, 2];
301 let result = concat_vec![a];
302 assert_eq!(expected, result);
303 }
304
305 #[test]
306 fn two() {
307 let a = vec![1, 2];
308 let b = vec![3, 4];
309
310 let expected = vec![1, 2, 3, 4];
311 let result = concat_vec![a, b];
312 assert_eq!(expected, result);
313 }
314
315 #[test]
316 fn many() {
317 let a = vec![1, 2];
318 let b = vec![3, 4];
319 let c = vec![5, 6];
320
321 let expected = vec![1, 2, 5, 6, 3, 4];
322 let result = concat_vec![a, c, b];
323 assert_eq!(expected, result);
324 }
325 }
326
327 mod hashmap {
328 use super::*;
329
330 #[test]
331 fn zero() {
332 let expected: HashMap<usize, usize> = HashMap::new();
333 let result: HashMap<usize, usize> = hashmap!();
334 assert_eq!(expected, result);
335 }
336 #[test]
337 fn one() {
338 let key = "abcde";
339 let expected: HashMap<String, usize> =
340 [(string!(key), 3usize)].iter().cloned().collect();
341 let result: HashMap<String, usize> = hashmap!(string!(key) => 3usize);
342 assert_eq!(expected, result);
343 }
344 #[test]
345 fn many() {
346 let expected: HashMap<String, usize> = vec![
347 (string!("a"), 10usize),
348 (string!("ab"), 20usize),
349 (string!("abc"), 30usize),
350 ]
351 .into_iter()
352 .collect();
353 let result = hashmap!(
354 string!("a") => 10usize,
355 string!("ab") => 20usize,
356 string!("abc") => 30usize
357 );
358 assert_eq!(expected, result);
359 }
360 }
361
362 mod hashset {
363 use super::*;
364
365 #[test]
366 fn zero() {
367 let expected: HashSet<usize> = HashSet::new();
368 let result: HashSet<usize> = hashset!();
369 assert_eq!(expected, result);
370 }
371 #[test]
372 fn one() {
373 let name = string!("Jack");
374 let expected: HashSet<String> = vec![&name].into_iter().cloned().collect();
375 let result: HashSet<String> = hashset!(name);
376 assert_eq!(expected, result);
377 }
378 #[test]
379 fn many() {
380 let expected: HashSet<&str> = vec!["a", "b", "c"].into_iter().collect();
381 let result: HashSet<&str> = hashset!("a", "b", "c");
382 assert_eq!(expected, result);
383 }
384 }
385
386 mod sort {
387 use super::*;
388
389 #[test]
390 fn vec() {
391 let expected = vec![-14, -1, 0, 2, 3, 4, 8];
392
393 let mut v = vec![4, 2, 3, -1, -14, 0, 8];
394 sort!(v);
395 assert_eq!(expected, v);
396 }
397 #[test]
398 fn array() {
399 let expected = vec![-14, -1, 0, 2, 3, 4, 8];
400
401 let mut v = [4, 2, 3, -1, -14, 0, 8];
402 sort!(v);
403 assert_eq!(expected, v);
404 }
405 #[test]
406 fn vec_reverse_sort() {
407 let expected = vec![8, 4, 3, 2, 0, -1, -14];
408
409 let mut v = vec![4, 2, 3, -1, -14, 0, 8];
410 sort!(v, |a, b| match a.cmp(b) {
411 Less => Greater,
412 Greater => Less,
413 Equal => Equal,
414 });
415 assert_eq!(expected, v);
416 }
417 }
418
419 mod sorted {
420 use super::*;
421
422 #[test]
423 fn vec() {
424 let expected = vec![-14, -1, 0, 2, 3, 4, 8];
425
426 let v = vec![4, 2, 3, -1, -14, 0, 8];
427 let result = sorted!(v);
428 assert_eq!(expected, result);
429 assert_eq!(vec![-14, -1, 0, 2, 3, 4, 8], expected); // unmodified
430 }
431 #[test]
432 fn hashset() {
433 let expected = vec![-14, -1, 0, 2, 3, 4, 8];
434
435 let v = hashset![4, 2, 3, -1, -14, 0, 8];
436 let result = sorted!(v);
437 assert_eq!(expected, result);
438 }
439 #[test]
440 fn array() {
441 let expected = vec![-14, -1, 0, 2, 3, 4, 8];
442
443 let v = [4, 2, 3, -1, -14, 0, 8];
444 let result = sorted!(v);
445 assert_eq!(expected, result);
446 }
447 #[test]
448 fn vec_reverse_sort() {
449 let expected = vec![8, 4, 3, 2, 0, -1, -14];
450
451 let v = vec![4, 2, 3, -1, -14, 0, 8];
452 let result = sorted!(v, |a, b| match a.cmp(b) {
453 Less => Greater,
454 Greater => Less,
455 Equal => Equal,
456 });
457 assert_eq!(expected, result);
458 assert_eq!(vec![8, 4, 3, 2, 0, -1, -14], expected); // unmodified
459 }
460 }
461
462 mod sorted_f64 {
463 use super::*;
464
465 #[test]
466 fn vec() {
467 let expected = vec![-14.0, -1.0, 0.0, 2.0, 3.0, 4.0, 8.0];
468
469 let v = vec![4.0, 2.0, 3.0, -1.0, -14.0, 0.0, 8.0];
470 let result = sorted_f64!(v);
471 assert_eq!(expected, result);
472 }
473 #[test]
474 fn array() {
475 let expected = vec![-14.0, -1.0, 0.0, 2.0, 3.0, 4.0, 8.0];
476
477 let v = [4.0, 2.0, 3.0, -1.0, -14.0, 0.0, 8.0];
478 let result = sorted_f64!(v);
479 assert_eq!(expected, result);
480 }
481 }
482}