1use std::{fmt, iter, ops::Index, slice};
2
3#[derive(Clone, Copy, Debug)]
5pub struct Input<'a> {
6 raw: &'a str,
7 lines: &'a [&'a str],
8}
9
10impl<'a> Input<'a> {
11 pub(crate) fn new(raw: &'a str, lines: &'a [&'a str]) -> Self {
12 Self { raw, lines }
13 }
14
15 #[inline(always)]
17 pub fn raw(self) -> &'a str {
18 self.raw
19 }
20
21 #[inline(always)]
25 pub fn lines(self) -> Lines<'a> {
26 self.into_iter()
27 }
28
29 #[inline(always)]
31 pub fn as_lines(self) -> &'a [&'a str] {
32 self.lines
33 }
34
35 #[inline(always)]
37 #[allow(clippy::len_without_is_empty)] pub fn len(self) -> usize {
39 self.lines.len()
40 }
41}
42
43#[derive(Clone)]
45pub struct Lines<'a> {
46 inner: slice::Iter<'a, &'a str>,
47}
48
49impl<'a> Iterator for Lines<'a> {
50 type Item = &'a str;
51
52 #[inline]
53 fn next(&mut self) -> Option<Self::Item> {
54 self.inner.next().copied()
55 }
56}
57
58impl<'a> DoubleEndedIterator for Lines<'a> {
59 fn next_back(&mut self) -> Option<Self::Item> {
60 self.inner.next_back().copied()
61 }
62}
63
64impl<'a> ExactSizeIterator for Lines<'a> {
65 fn len(&self) -> usize {
66 self.inner.len()
67 }
68}
69
70impl<'a> iter::FusedIterator for Lines<'a> {}
71
72impl<'a> IntoIterator for Input<'a> {
73 type Item = &'a str;
74 type IntoIter = Lines<'a>;
75
76 #[inline]
77 fn into_iter(self) -> Self::IntoIter {
78 Lines {
79 inner: self.lines.iter(),
80 }
81 }
82}
83
84impl<'a, T> Index<T> for Input<'a>
85where
86 [&'a str]: Index<T>,
87{
88 type Output = <[&'a str] as Index<T>>::Output;
89
90 #[inline]
91 #[track_caller]
92 fn index(&self, index: T) -> &Self::Output {
93 &self.lines[index]
94 }
95}
96
97impl<'a> fmt::Display for Input<'a> {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 <str as fmt::Display>::fmt(self.raw, f)
100 }
101}