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