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