]> git.lizzy.rs Git - rust.git/blob - src/test/run-pass/impl-trait/example-calendar.rs
Rollup merge of #35558 - lukehinds:master, r=nikomatsakis
[rust.git] / src / test / run-pass / impl-trait / example-calendar.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![feature(conservative_impl_trait, fn_traits, step_trait, unboxed_closures)]
12
13 //! Derived from: <https://raw.githubusercontent.com/quickfur/dcal/master/dcal.d>.
14 //!
15 //! Originally converted to Rust by [Daniel Keep](https://github.com/DanielKeep).
16
17 use std::fmt::Write;
18 use std::mem;
19
20 /// Date representation.
21 #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
22 struct NaiveDate(i32, u32, u32);
23
24 impl NaiveDate {
25     pub fn from_ymd(y: i32, m: u32, d: u32) -> NaiveDate {
26         assert!(1 <= m && m <= 12, "m = {:?}", m);
27         assert!(1 <= d && d <= NaiveDate(y, m, 1).days_in_month(), "d = {:?}", d);
28         NaiveDate(y, m, d)
29     }
30
31     pub fn year(&self) -> i32 {
32         self.0
33     }
34
35     pub fn month(&self) -> u32 {
36         self.1
37     }
38
39     pub fn day(&self) -> u32 {
40         self.2
41     }
42
43     pub fn succ(&self) -> NaiveDate {
44         let (mut y, mut m, mut d, n) = (
45             self.year(), self.month(), self.day()+1, self.days_in_month());
46         if d > n {
47             d = 1;
48             m += 1;
49         }
50         if m > 12 {
51             m = 1;
52             y += 1;
53         }
54         NaiveDate::from_ymd(y, m, d)
55     }
56
57     pub fn weekday(&self) -> Weekday {
58         use Weekday::*;
59
60         // 0 = Sunday
61         let year = self.year();
62         let dow_jan_1 = (year*365 + ((year-1) / 4) - ((year-1) / 100) + ((year-1) / 400)) % 7;
63         let dow = (dow_jan_1 + (self.day_of_year() as i32 - 1)) % 7;
64         [Sun, Mon, Tue, Wed, Thu, Fri, Sat][dow as usize]
65     }
66
67     pub fn isoweekdate(&self) -> (i32, u32, Weekday) {
68         let first_dow_mon_0 = self.year_first_day_of_week().num_days_from_monday();
69
70         // Work out this date's DOtY and week number, not including year adjustment.
71         let doy_0 = self.day_of_year() - 1;
72         let mut week_mon_0: i32 = ((first_dow_mon_0 + doy_0) / 7) as i32;
73
74         if self.first_week_in_prev_year() {
75             week_mon_0 -= 1;
76         }
77
78         let weeks_in_year = self.last_week_number();
79
80         // Work out the final result.
81         // If the week is -1 or >= weeks_in_year, we will need to adjust the year.
82         let year = self.year();
83         let wd = self.weekday();
84
85         if week_mon_0 < 0 {
86             (year - 1, NaiveDate::from_ymd(year - 1, 1, 1).last_week_number(), wd)
87         } else if week_mon_0 >= weeks_in_year as i32 {
88             (year + 1, (week_mon_0 + 1 - weeks_in_year as i32) as u32, wd)
89         } else {
90             (year, (week_mon_0 + 1) as u32, wd)
91         }
92     }
93
94     fn first_week_in_prev_year(&self) -> bool {
95         let first_dow_mon_0 = self.year_first_day_of_week().num_days_from_monday();
96
97         // Any day in the year *before* the first Monday of that year
98         // is considered to be in the last week of the previous year,
99         // assuming the first week has *less* than four days in it.
100         // Adjust the week appropriately.
101         ((7 - first_dow_mon_0) % 7) < 4
102     }
103
104     fn year_first_day_of_week(&self) -> Weekday {
105         NaiveDate::from_ymd(self.year(), 1, 1).weekday()
106     }
107
108     fn weeks_in_year(&self) -> u32 {
109         let days_in_last_week = self.year_first_day_of_week().num_days_from_monday() + 1;
110         if days_in_last_week >= 4 { 53 } else { 52 }
111     }
112
113     fn last_week_number(&self) -> u32 {
114         let wiy = self.weeks_in_year();
115         if self.first_week_in_prev_year() { wiy - 1 } else { wiy }
116     }
117
118     fn day_of_year(&self) -> u32 {
119         (1..self.1).map(|m| NaiveDate::from_ymd(self.year(), m, 1).days_in_month())
120             .fold(0, |a,b| a+b) + self.day()
121     }
122
123     fn is_leap_year(&self) -> bool {
124         let year = self.year();
125         if year % 4 != 0 {
126             return false
127         } else if year % 100 != 0 {
128             return true
129         } else if year % 400 != 0 {
130             return false
131         } else {
132             return true
133         }
134     }
135
136     fn days_in_month(&self) -> u32 {
137         match self.month() {
138             /* Jan */ 1 => 31,
139             /* Feb */ 2 => if self.is_leap_year() { 29 } else { 28 },
140             /* Mar */ 3 => 31,
141             /* Apr */ 4 => 30,
142             /* May */ 5 => 31,
143             /* Jun */ 6 => 30,
144             /* Jul */ 7 => 31,
145             /* Aug */ 8 => 31,
146             /* Sep */ 9 => 30,
147             /* Oct */ 10 => 31,
148             /* Nov */ 11 => 30,
149             /* Dec */ 12 => 31,
150             _ => unreachable!()
151         }
152     }
153 }
154
155 impl<'a, 'b> std::ops::Add<&'b NaiveDate> for &'a NaiveDate {
156     type Output = NaiveDate;
157
158     fn add(self, other: &'b NaiveDate) -> NaiveDate {
159         assert_eq!(*other, NaiveDate(0, 0, 1));
160         self.succ()
161     }
162 }
163
164 impl std::iter::Step for NaiveDate {
165     fn step(&self, by: &Self) -> Option<Self> {
166         Some(self + by)
167     }
168
169     fn steps_between(_: &Self, _: &Self, _: &Self) -> Option<usize> {
170         unimplemented!()
171     }
172
173     fn steps_between_by_one(_: &Self, _: &Self) -> Option<usize> {
174         unimplemented!()
175     }
176
177     fn is_negative(&self) -> bool {
178         false
179     }
180
181     fn replace_one(&mut self) -> Self {
182         mem::replace(self, NaiveDate(0, 0, 1))
183     }
184
185     fn replace_zero(&mut self) -> Self {
186         mem::replace(self, NaiveDate(0, 0, 0))
187     }
188
189     fn add_one(&self) -> Self {
190         self.succ()
191     }
192
193     fn sub_one(&self) -> Self {
194         unimplemented!()
195     }
196 }
197
198 #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
199 pub enum Weekday {
200     Mon,
201     Tue,
202     Wed,
203     Thu,
204     Fri,
205     Sat,
206     Sun,
207 }
208
209 impl Weekday {
210     pub fn num_days_from_monday(&self) -> u32 {
211         use Weekday::*;
212         match *self {
213             Mon => 0,
214             Tue => 1,
215             Wed => 2,
216             Thu => 3,
217             Fri => 4,
218             Sat => 5,
219             Sun => 6,
220         }
221     }
222
223     pub fn num_days_from_sunday(&self) -> u32 {
224         use Weekday::*;
225         match *self {
226             Sun => 0,
227             Mon => 1,
228             Tue => 2,
229             Wed => 3,
230             Thu => 4,
231             Fri => 5,
232             Sat => 6,
233         }
234     }
235 }
236
237 /// Wrapper for zero-sized closures.
238 // HACK(eddyb) Only needed because closures can't implement Copy.
239 struct Fn0<F>(std::marker::PhantomData<F>);
240
241 impl<F> Copy for Fn0<F> {}
242 impl<F> Clone for Fn0<F> {
243     fn clone(&self) -> Self { *self }
244 }
245
246 impl<F: FnOnce<A>, A> FnOnce<A> for Fn0<F> {
247     type Output = F::Output;
248
249     extern "rust-call" fn call_once(self, args: A) -> Self::Output {
250         let f = unsafe { std::mem::uninitialized::<F>() };
251         f.call_once(args)
252     }
253 }
254
255 impl<F: FnMut<A>, A> FnMut<A> for Fn0<F> {
256     extern "rust-call" fn call_mut(&mut self, args: A) -> Self::Output {
257         let mut f = unsafe { std::mem::uninitialized::<F>() };
258         f.call_mut(args)
259     }
260 }
261
262 trait AsFn0<A>: Sized {
263     fn copyable(self) -> Fn0<Self>;
264 }
265
266 impl<F: FnMut<A>, A> AsFn0<A> for F {
267     fn copyable(self) -> Fn0<Self> {
268         assert_eq!(std::mem::size_of::<F>(), 0);
269         Fn0(std::marker::PhantomData)
270     }
271 }
272
273 /// GroupBy implementation.
274 struct GroupBy<It: Iterator, F> {
275     it: std::iter::Peekable<It>,
276     f: F,
277 }
278
279 impl<It, F> Clone for GroupBy<It, F>
280 where It: Iterator + Clone, It::Item: Clone, F: Clone {
281     fn clone(&self) -> GroupBy<It, F> {
282         GroupBy {
283             it: self.it.clone(),
284             f: self.f.clone()
285         }
286     }
287 }
288
289 impl<'a, G, It: 'a, F: 'a> Iterator for GroupBy<It, F>
290 where It: Iterator + Clone,
291       It::Item: Clone,
292       F: Clone + FnMut(&It::Item) -> G,
293       G: Eq + Clone
294 {
295     type Item = (G, InGroup<std::iter::Peekable<It>, F, G>);
296
297     fn next(&mut self) -> Option<Self::Item> {
298         self.it.peek().map(&mut self.f).map(|key| {
299             let start = self.it.clone();
300             while let Some(k) = self.it.peek().map(&mut self.f) {
301                 if key != k {
302                     break;
303                 }
304                 self.it.next();
305             }
306
307             (key.clone(), InGroup {
308                 it: start,
309                 f: self.f.clone(),
310                 g: key
311             })
312         })
313     }
314 }
315
316 #[derive(Copy, Clone)]
317 struct InGroup<It, F, G> {
318     it: It,
319     f: F,
320     g: G
321 }
322
323 impl<It: Iterator, F: FnMut(&It::Item) -> G, G: Eq> Iterator for InGroup<It, F, G> {
324     type Item = It::Item;
325
326     fn next(&mut self) -> Option<It::Item> {
327         self.it.next().and_then(|x| {
328             if (self.f)(&x) == self.g { Some(x) } else { None }
329         })
330     }
331 }
332
333 trait IteratorExt: Iterator + Sized {
334     fn group_by<G, F>(self, f: F) -> GroupBy<Self, Fn0<F>>
335     where F: FnMut(&Self::Item) -> G,
336           G: Eq
337     {
338         GroupBy {
339             it: self.peekable(),
340             f: f.copyable(),
341         }
342     }
343
344     fn join(mut self, sep: &str) -> String
345     where Self::Item: std::fmt::Display {
346         let mut s = String::new();
347         if let Some(e) = self.next() {
348             write!(s, "{}", e);
349             for e in self {
350                 s.push_str(sep);
351                 write!(s, "{}", e);
352             }
353         }
354         s
355     }
356
357     // HACK(eddyb) Only needed because `impl Trait` can't be
358     // used with trait methods: `.foo()` becomes `.__(foo)`.
359     fn __<F, R>(self, f: F) -> R
360     where F: FnOnce(Self) -> R {
361         f(self)
362     }
363 }
364
365 impl<It> IteratorExt for It where It: Iterator {}
366
367 ///
368 /// Generates an iterator that yields exactly n spaces.
369 ///
370 fn spaces(n: usize) -> std::iter::Take<std::iter::Repeat<char>> {
371     std::iter::repeat(' ').take(n)
372 }
373
374 fn test_spaces() {
375     assert_eq!(spaces(0).collect::<String>(), "");
376     assert_eq!(spaces(10).collect::<String>(), "          ")
377 }
378
379 ///
380 /// Returns an iterator of dates in a given year.
381 ///
382 fn dates_in_year(year: i32) -> impl Iterator<Item=NaiveDate>+Clone {
383     InGroup {
384         it: NaiveDate::from_ymd(year, 1, 1)..,
385         f: (|d: &NaiveDate| d.year()).copyable(),
386         g: year
387     }
388 }
389
390 fn test_dates_in_year() {
391     {
392         let mut dates = dates_in_year(2013);
393         assert_eq!(dates.next(), Some(NaiveDate::from_ymd(2013, 1, 1)));
394
395         // Check increment
396         assert_eq!(dates.next(), Some(NaiveDate::from_ymd(2013, 1, 2)));
397
398         // Check monthly rollover
399         for _ in 3..31 {
400             assert!(dates.next() != None);
401         }
402
403         assert_eq!(dates.next(), Some(NaiveDate::from_ymd(2013, 1, 31)));
404         assert_eq!(dates.next(), Some(NaiveDate::from_ymd(2013, 2, 1)));
405     }
406
407     {
408         // Check length of year
409         let mut dates = dates_in_year(2013);
410         for _ in 0..365 {
411             assert!(dates.next() != None);
412         }
413         assert_eq!(dates.next(), None);
414     }
415
416     {
417         // Check length of leap year
418         let mut dates = dates_in_year(1984);
419         for _ in 0..366 {
420             assert!(dates.next() != None);
421         }
422         assert_eq!(dates.next(), None);
423     }
424 }
425
426 ///
427 /// Convenience trait for verifying that a given type iterates over
428 /// `NaiveDate`s.
429 ///
430 trait DateIterator: Iterator<Item=NaiveDate> + Clone {}
431 impl<It> DateIterator for It where It: Iterator<Item=NaiveDate> + Clone {}
432
433 fn test_group_by() {
434     let input = [
435         [1, 1],
436         [1, 1],
437         [1, 2],
438         [2, 2],
439         [2, 3],
440         [2, 3],
441         [3, 3]
442     ];
443
444     let by_x = input.iter().cloned().group_by(|a| a[0]);
445     let expected_1: &[&[[i32; 2]]] = &[
446         &[[1, 1], [1, 1], [1, 2]],
447         &[[2, 2], [2, 3], [2, 3]],
448         &[[3, 3]]
449     ];
450     for ((_, a), b) in by_x.zip(expected_1.iter().cloned()) {
451         assert_eq!(&a.collect::<Vec<_>>()[..], b);
452     }
453
454     let by_y = input.iter().cloned().group_by(|a| a[1]);
455     let expected_2: &[&[[i32; 2]]] = &[
456         &[[1, 1], [1, 1]],
457         &[[1, 2], [2, 2]],
458         &[[2, 3], [2, 3], [3, 3]]
459     ];
460     for ((_, a), b) in by_y.zip(expected_2.iter().cloned()) {
461         assert_eq!(&a.collect::<Vec<_>>()[..], b);
462     }
463 }
464
465 ///
466 /// Groups an iterator of dates by month.
467 ///
468 fn by_month<It>(it: It)
469                 ->  impl Iterator<Item=(u32, impl Iterator<Item=NaiveDate> + Clone)> + Clone
470 where It: Iterator<Item=NaiveDate> + Clone {
471     it.group_by(|d| d.month())
472 }
473
474 fn test_by_month() {
475     let mut months = dates_in_year(2013).__(by_month);
476     for (month, (_, mut date)) in (1..13).zip(&mut months) {
477         assert_eq!(date.nth(0).unwrap(), NaiveDate::from_ymd(2013, month, 1));
478     }
479     assert!(months.next().is_none());
480 }
481
482 ///
483 /// Groups an iterator of dates by week.
484 ///
485 fn by_week<It>(it: It)
486                -> impl Iterator<Item=(u32, impl DateIterator)> + Clone
487 where It: DateIterator {
488     // We go forward one day because `isoweekdate` considers the week to start on a Monday.
489     it.group_by(|d| d.succ().isoweekdate().1)
490 }
491
492 fn test_isoweekdate() {
493     fn weeks_uniq(year: i32) -> Vec<((i32, u32), u32)> {
494         let mut weeks = dates_in_year(year).map(|d| d.isoweekdate())
495             .map(|(y,w,_)| (y,w));
496         let mut result = vec![];
497         let mut accum = (weeks.next().unwrap(), 1);
498         for yw in weeks {
499             if accum.0 == yw {
500                 accum.1 += 1;
501             } else {
502                 result.push(accum);
503                 accum = (yw, 1);
504             }
505         }
506         result.push(accum);
507         result
508     }
509
510     let wu_1984 = weeks_uniq(1984);
511     assert_eq!(&wu_1984[..2], &[((1983, 52), 1), ((1984, 1), 7)]);
512     assert_eq!(&wu_1984[wu_1984.len()-2..], &[((1984, 52), 7), ((1985, 1), 1)]);
513
514     let wu_2013 = weeks_uniq(2013);
515     assert_eq!(&wu_2013[..2], &[((2013, 1), 6), ((2013, 2), 7)]);
516     assert_eq!(&wu_2013[wu_2013.len()-2..], &[((2013, 52), 7), ((2014, 1), 2)]);
517
518     let wu_2015 = weeks_uniq(2015);
519     assert_eq!(&wu_2015[..2], &[((2015, 1), 4), ((2015, 2), 7)]);
520     assert_eq!(&wu_2015[wu_2015.len()-2..], &[((2015, 52), 7), ((2015, 53), 4)]);
521 }
522
523 fn test_by_week() {
524     let mut weeks = dates_in_year(2013).__(by_week);
525     assert_eq!(
526         &*weeks.next().unwrap().1.collect::<Vec<_>>(),
527         &[
528             NaiveDate::from_ymd(2013, 1, 1),
529             NaiveDate::from_ymd(2013, 1, 2),
530             NaiveDate::from_ymd(2013, 1, 3),
531             NaiveDate::from_ymd(2013, 1, 4),
532             NaiveDate::from_ymd(2013, 1, 5),
533         ]
534     );
535     assert_eq!(
536         &*weeks.next().unwrap().1.collect::<Vec<_>>(),
537         &[
538             NaiveDate::from_ymd(2013, 1, 6),
539             NaiveDate::from_ymd(2013, 1, 7),
540             NaiveDate::from_ymd(2013, 1, 8),
541             NaiveDate::from_ymd(2013, 1, 9),
542             NaiveDate::from_ymd(2013, 1, 10),
543             NaiveDate::from_ymd(2013, 1, 11),
544             NaiveDate::from_ymd(2013, 1, 12),
545         ]
546     );
547     assert_eq!(weeks.next().unwrap().1.nth(0).unwrap(), NaiveDate::from_ymd(2013, 1, 13));
548 }
549
550 /// The number of columns per day in the formatted output.
551 const COLS_PER_DAY: u32 = 3;
552
553 /// The number of columns per week in the formatted output.
554 const COLS_PER_WEEK: u32 = 7 * COLS_PER_DAY;
555
556 ///
557 /// Formats an iterator of weeks into an iterator of strings.
558 ///
559 fn format_weeks<It>(it: It) -> impl Iterator<Item=String>
560 where It: Iterator, It::Item: DateIterator {
561     it.map(|week| {
562         let mut buf = String::with_capacity((COLS_PER_DAY * COLS_PER_WEEK + 2) as usize);
563
564         // Format each day into its own cell and append to target string.
565         let mut last_day = 0;
566         let mut first = true;
567         for d in week {
568             last_day = d.weekday().num_days_from_sunday();
569
570             // Insert enough filler to align the first day with its respective day-of-week.
571             if first {
572                 buf.extend(spaces((COLS_PER_DAY * last_day) as usize));
573                 first = false;
574             }
575
576             write!(buf, " {:>2}", d.day());
577         }
578
579         // Insert more filler at the end to fill up the remainder of the week,
580         // if its a short week (e.g. at the end of the month).
581         buf.extend(spaces((COLS_PER_DAY * (6 - last_day)) as usize));
582         buf
583     })
584 }
585
586 fn test_format_weeks() {
587     let jan_2013 = dates_in_year(2013)
588         .__(by_month).next() // pick January 2013 for testing purposes
589         // NOTE: This `map` is because `next` returns an `Option<_>`.
590         .map(|(_, month)|
591             month.__(by_week)
592                  .map(|(_, weeks)| weeks)
593                  .__(format_weeks)
594                  .join("\n"));
595
596     assert_eq!(
597         jan_2013.as_ref().map(|s| &**s),
598         Some("        1  2  3  4  5\n\
599            \x20 6  7  8  9 10 11 12\n\
600            \x2013 14 15 16 17 18 19\n\
601            \x2020 21 22 23 24 25 26\n\
602            \x2027 28 29 30 31      ")
603     );
604 }
605
606 ///
607 /// Formats the name of a month, centered on COLS_PER_WEEK.
608 ///
609 fn month_title(month: u32) -> String {
610     const MONTH_NAMES: &'static [&'static str] = &[
611         "January", "February", "March", "April", "May", "June",
612         "July", "August", "September", "October", "November", "December"
613     ];
614     assert_eq!(MONTH_NAMES.len(), 12);
615
616     // Determine how many spaces before and after the month name
617     // we need to center it over the formatted weeks in the month.
618     let name = MONTH_NAMES[(month - 1) as usize];
619     assert!(name.len() < COLS_PER_WEEK as usize);
620     let before = (COLS_PER_WEEK as usize - name.len()) / 2;
621     let after = COLS_PER_WEEK as usize - name.len() - before;
622
623     // NOTE: Being slightly more verbose to avoid extra allocations.
624     let mut result = String::with_capacity(COLS_PER_WEEK as usize);
625     result.extend(spaces(before));
626     result.push_str(name);
627     result.extend(spaces(after));
628     result
629 }
630
631 fn test_month_title() {
632     assert_eq!(month_title(1).len(), COLS_PER_WEEK as usize);
633 }
634
635 ///
636 /// Formats a month.
637 ///
638 fn format_month<It: DateIterator>(it: It) -> impl Iterator<Item=String> {
639     let mut month_days = it.peekable();
640     let title = month_title(month_days.peek().unwrap().month());
641
642     Some(title).into_iter()
643         .chain(month_days.__(by_week)
644             .map(|(_, week)| week)
645             .__(format_weeks))
646 }
647
648 fn test_format_month() {
649     let month_fmt = dates_in_year(2013)
650         .__(by_month).next() // Pick January as a test case
651         .map(|(_, days)| days.into_iter()
652             .__(format_month)
653             .join("\n"));
654
655     assert_eq!(
656         month_fmt.as_ref().map(|s| &**s),
657         Some("       January       \n\
658            \x20       1  2  3  4  5\n\
659            \x20 6  7  8  9 10 11 12\n\
660            \x2013 14 15 16 17 18 19\n\
661            \x2020 21 22 23 24 25 26\n\
662            \x2027 28 29 30 31      ")
663     );
664 }
665
666
667 ///
668 /// Formats an iterator of months.
669 ///
670 fn format_months<It>(it: It) -> impl Iterator<Item=impl Iterator<Item=String>>
671 where It: Iterator, It::Item: DateIterator {
672     it.map(format_month)
673 }
674
675 ///
676 /// Takes an iterator of iterators of strings; the sub-iterators are consumed
677 /// in lock-step, with their elements joined together.
678 ///
679 trait PasteBlocks: Iterator + Sized
680 where Self::Item: Iterator<Item=String> {
681     fn paste_blocks(self, sep_width: usize) -> PasteBlocksIter<Self::Item> {
682         PasteBlocksIter {
683             iters: self.collect(),
684             cache: vec![],
685             col_widths: None,
686             sep_width: sep_width,
687         }
688     }
689 }
690
691 impl<It> PasteBlocks for It where It: Iterator, It::Item: Iterator<Item=String> {}
692
693 struct PasteBlocksIter<StrIt>
694 where StrIt: Iterator<Item=String> {
695     iters: Vec<StrIt>,
696     cache: Vec<Option<String>>,
697     col_widths: Option<Vec<usize>>,
698     sep_width: usize,
699 }
700
701 impl<StrIt> Iterator for PasteBlocksIter<StrIt>
702 where StrIt: Iterator<Item=String> {
703     type Item = String;
704
705     fn next(&mut self) -> Option<String> {
706         self.cache.clear();
707
708         // `cache` is now the next line from each iterator.
709         self.cache.extend(self.iters.iter_mut().map(|it| it.next()));
710
711         // If every line in `cache` is `None`, we have nothing further to do.
712         if self.cache.iter().all(|e| e.is_none()) { return None }
713
714         // Get the column widths if we haven't already.
715         let col_widths = match self.col_widths {
716             Some(ref v) => &**v,
717             None => {
718                 self.col_widths = Some(self.cache.iter()
719                     .map(|ms| ms.as_ref().map(|s| s.len()).unwrap_or(0))
720                     .collect());
721                 &**self.col_widths.as_ref().unwrap()
722             }
723         };
724
725         // Fill in any `None`s with spaces.
726         let mut parts = col_widths.iter().cloned().zip(self.cache.iter_mut())
727             .map(|(w,ms)| ms.take().unwrap_or_else(|| spaces(w).collect()));
728
729         // Join them all together.
730         let first = parts.next().unwrap_or(String::new());
731         let sep_width = self.sep_width;
732         Some(parts.fold(first, |mut accum, next| {
733             accum.extend(spaces(sep_width));
734             accum.push_str(&next);
735             accum
736         }))
737     }
738 }
739
740 fn test_paste_blocks() {
741     let row = dates_in_year(2013)
742         .__(by_month).map(|(_, days)| days)
743         .take(3)
744         .__(format_months)
745         .paste_blocks(1)
746         .join("\n");
747     assert_eq!(
748         &*row,
749         "       January              February                March        \n\
750       \x20       1  2  3  4  5                  1  2                  1  2\n\
751       \x20 6  7  8  9 10 11 12   3  4  5  6  7  8  9   3  4  5  6  7  8  9\n\
752       \x2013 14 15 16 17 18 19  10 11 12 13 14 15 16  10 11 12 13 14 15 16\n\
753       \x2020 21 22 23 24 25 26  17 18 19 20 21 22 23  17 18 19 20 21 22 23\n\
754       \x2027 28 29 30 31        24 25 26 27 28        24 25 26 27 28 29 30\n\
755       \x20                                            31                  "
756     );
757 }
758
759 ///
760 /// Produces an iterator that yields `n` elements at a time.
761 ///
762 trait Chunks: Iterator + Sized {
763     fn chunks(self, n: usize) -> ChunksIter<Self> {
764         assert!(n > 0);
765         ChunksIter {
766             it: self,
767             n: n,
768         }
769     }
770 }
771
772 impl<It> Chunks for It where It: Iterator {}
773
774 struct ChunksIter<It>
775 where It: Iterator {
776     it: It,
777     n: usize,
778 }
779
780 // NOTE: `chunks` in Rust is more-or-less impossible without overhead of some kind.
781 // Aliasing rules mean you need to add dynamic borrow checking, and the design of
782 // `Iterator` means that you need to have the iterator's state kept in an allocation
783 // that is jointly owned by the iterator itself and the sub-iterator.
784 // As such, I've chosen to cop-out and just heap-allocate each chunk.
785
786 impl<It> Iterator for ChunksIter<It>
787 where It: Iterator {
788     type Item = Vec<It::Item>;
789
790     fn next(&mut self) -> Option<Vec<It::Item>> {
791         let first = match self.it.next() {
792             Some(e) => e,
793             None => return None
794         };
795
796         let mut result = Vec::with_capacity(self.n);
797         result.push(first);
798
799         Some((&mut self.it).take(self.n-1)
800             .fold(result, |mut acc, next| { acc.push(next); acc }))
801     }
802 }
803
804 fn test_chunks() {
805     let r = &[1, 2, 3, 4, 5, 6, 7];
806     let c = r.iter().cloned().chunks(3).collect::<Vec<_>>();
807     assert_eq!(&*c, &[vec![1, 2, 3], vec![4, 5, 6], vec![7]]);
808 }
809
810 ///
811 /// Formats a year.
812 ///
813 fn format_year(year: i32, months_per_row: usize) -> String {
814     const COL_SPACING: usize = 1;
815
816     // Start by generating all dates for the given year.
817     dates_in_year(year)
818
819         // Group them by month and throw away month number.
820         .__(by_month).map(|(_, days)| days)
821
822         // Group the months into horizontal rows.
823         .chunks(months_per_row)
824
825         // Format each row
826         .map(|r| r.into_iter()
827             // By formatting each month
828             .__(format_months)
829
830             // Horizontally pasting each respective month's lines together.
831             .paste_blocks(COL_SPACING)
832             .join("\n")
833         )
834
835         // Insert a blank line between each row
836         .join("\n\n")
837 }
838
839 fn test_format_year() {
840     const MONTHS_PER_ROW: usize = 3;
841
842     macro_rules! assert_eq_cal {
843         ($lhs:expr, $rhs:expr) => {
844             if $lhs != $rhs {
845                 println!("got:\n```\n{}\n```\n", $lhs.replace(" ", "."));
846                 println!("expected:\n```\n{}\n```", $rhs.replace(" ", "."));
847                 panic!("calendars didn't match!");
848             }
849         }
850     }
851
852     assert_eq_cal!(&format_year(1984, MONTHS_PER_ROW), "\
853 \x20      January              February                March        \n\
854 \x20 1  2  3  4  5  6  7            1  2  3  4               1  2  3\n\
855 \x20 8  9 10 11 12 13 14   5  6  7  8  9 10 11   4  5  6  7  8  9 10\n\
856 \x2015 16 17 18 19 20 21  12 13 14 15 16 17 18  11 12 13 14 15 16 17\n\
857 \x2022 23 24 25 26 27 28  19 20 21 22 23 24 25  18 19 20 21 22 23 24\n\
858 \x2029 30 31              26 27 28 29           25 26 27 28 29 30 31\n\
859 \n\
860 \x20       April                  May                  June         \n\
861 \x20 1  2  3  4  5  6  7         1  2  3  4  5                  1  2\n\
862 \x20 8  9 10 11 12 13 14   6  7  8  9 10 11 12   3  4  5  6  7  8  9\n\
863 \x2015 16 17 18 19 20 21  13 14 15 16 17 18 19  10 11 12 13 14 15 16\n\
864 \x2022 23 24 25 26 27 28  20 21 22 23 24 25 26  17 18 19 20 21 22 23\n\
865 \x2029 30                 27 28 29 30 31        24 25 26 27 28 29 30\n\
866 \n\
867 \x20       July                 August               September      \n\
868 \x20 1  2  3  4  5  6  7            1  2  3  4                     1\n\
869 \x20 8  9 10 11 12 13 14   5  6  7  8  9 10 11   2  3  4  5  6  7  8\n\
870 \x2015 16 17 18 19 20 21  12 13 14 15 16 17 18   9 10 11 12 13 14 15\n\
871 \x2022 23 24 25 26 27 28  19 20 21 22 23 24 25  16 17 18 19 20 21 22\n\
872 \x2029 30 31              26 27 28 29 30 31     23 24 25 26 27 28 29\n\
873 \x20                                            30                  \n\
874 \n\
875 \x20      October              November              December       \n\
876 \x20    1  2  3  4  5  6               1  2  3                     1\n\
877 \x20 7  8  9 10 11 12 13   4  5  6  7  8  9 10   2  3  4  5  6  7  8\n\
878 \x2014 15 16 17 18 19 20  11 12 13 14 15 16 17   9 10 11 12 13 14 15\n\
879 \x2021 22 23 24 25 26 27  18 19 20 21 22 23 24  16 17 18 19 20 21 22\n\
880 \x2028 29 30 31           25 26 27 28 29 30     23 24 25 26 27 28 29\n\
881 \x20                                            30 31               ");
882
883     assert_eq_cal!(&format_year(2015, MONTHS_PER_ROW), "\
884 \x20      January              February                March        \n\
885 \x20             1  2  3   1  2  3  4  5  6  7   1  2  3  4  5  6  7\n\
886 \x20 4  5  6  7  8  9 10   8  9 10 11 12 13 14   8  9 10 11 12 13 14\n\
887 \x2011 12 13 14 15 16 17  15 16 17 18 19 20 21  15 16 17 18 19 20 21\n\
888 \x2018 19 20 21 22 23 24  22 23 24 25 26 27 28  22 23 24 25 26 27 28\n\
889 \x2025 26 27 28 29 30 31                        29 30 31            \n\
890 \n\
891 \x20       April                  May                  June         \n\
892 \x20          1  2  3  4                  1  2      1  2  3  4  5  6\n\
893 \x20 5  6  7  8  9 10 11   3  4  5  6  7  8  9   7  8  9 10 11 12 13\n\
894 \x2012 13 14 15 16 17 18  10 11 12 13 14 15 16  14 15 16 17 18 19 20\n\
895 \x2019 20 21 22 23 24 25  17 18 19 20 21 22 23  21 22 23 24 25 26 27\n\
896 \x2026 27 28 29 30        24 25 26 27 28 29 30  28 29 30            \n\
897 \x20                      31                                        \n\
898 \n\
899 \x20       July                 August               September      \n\
900 \x20          1  2  3  4                     1         1  2  3  4  5\n\
901 \x20 5  6  7  8  9 10 11   2  3  4  5  6  7  8   6  7  8  9 10 11 12\n\
902 \x2012 13 14 15 16 17 18   9 10 11 12 13 14 15  13 14 15 16 17 18 19\n\
903 \x2019 20 21 22 23 24 25  16 17 18 19 20 21 22  20 21 22 23 24 25 26\n\
904 \x2026 27 28 29 30 31     23 24 25 26 27 28 29  27 28 29 30         \n\
905 \x20                      30 31                                     \n\
906 \n\
907 \x20      October              November              December       \n\
908 \x20             1  2  3   1  2  3  4  5  6  7         1  2  3  4  5\n\
909 \x20 4  5  6  7  8  9 10   8  9 10 11 12 13 14   6  7  8  9 10 11 12\n\
910 \x2011 12 13 14 15 16 17  15 16 17 18 19 20 21  13 14 15 16 17 18 19\n\
911 \x2018 19 20 21 22 23 24  22 23 24 25 26 27 28  20 21 22 23 24 25 26\n\
912 \x2025 26 27 28 29 30 31  29 30                 27 28 29 30 31      ");
913 }
914
915 fn main() {
916     // Run tests.
917     test_spaces();
918     test_dates_in_year();
919     test_group_by();
920     test_by_month();
921     test_isoweekdate();
922     test_by_week();
923     test_format_weeks();
924     test_month_title();
925     test_format_month();
926     test_paste_blocks();
927     test_chunks();
928     test_format_year();
929 }