1use crate::SmallVec;
2use std::borrow::Cow;
3use std::convert::TryInto;
4use std::ops::Range;
5
6#[derive(Clone, Copy, Debug)]
7pub struct Location {
8 start: u16,
9 end: u16,
10}
11
12impl Location {
13 #[inline]
14 pub fn range(&self) -> Range<usize> {
15 Range {
16 start: self.start.into(),
17 end: self.end.into(),
18 }
19 }
20
21 #[inline]
22 pub fn new(range: Range<usize>) -> Option<Self> {
23 let start = range.start.try_into().ok()?;
24 let end = range.end.try_into().ok()?;
25 Some(Self { start, end })
26 }
27}
28
29pub struct Words<'a, I>
30where
31 I: Iterator<Item = Location>,
32{
33 text: &'a str,
34 locations: I,
35}
36
37impl<'a, I> Words<'a, I>
38where
39 I: Iterator<Item = Location>,
40{
41 #[inline]
42 pub fn new(text: &'a str, locations: I) -> Words<'a, I> {
43 Words { text, locations }
44 }
45}
46
47impl<'a, I> Words<'a, I>
48where
49 I: Iterator<Item = Location> + ExactSizeIterator,
50{
51 pub fn join(mut self) -> Cow<'a, str> {
52 match self.len() {
53 0 => Cow::Borrowed(""),
54 1 => Cow::Borrowed(self.next().unwrap()),
55 _ => Cow::Owned(self.collect::<SmallVec<[&str; 4]>>().join(" ")),
56 }
57 }
58}
59
60impl<'a, I> Iterator for Words<'a, I>
61where
62 I: Iterator<Item = Location>,
63{
64 type Item = &'a str;
65
66 #[inline]
67 fn next(&mut self) -> Option<&'a str> {
68 self.locations.next().map(|loc| &self.text[loc.range()])
69 }
70
71 #[inline]
72 fn fold<B, F>(self, init: B, mut f: F) -> B
73 where
74 F: FnMut(B, Self::Item) -> B,
75 {
76 let Self { locations, text } = self;
77 locations.fold(init, |acc, loc| {
78 let item = &text[loc.range()];
79 f(acc, item)
80 })
81 }
82
83 #[inline]
84 fn size_hint(&self) -> (usize, Option<usize>) {
85 self.locations.size_hint()
86 }
87}
88
89impl<'a, I> DoubleEndedIterator for Words<'a, I>
90where
91 I: Iterator<Item = Location> + DoubleEndedIterator,
92{
93 #[inline]
94 fn next_back(&mut self) -> Option<&'a str> {
95 self.locations
96 .next_back()
97 .map(|loc| &self.text[loc.range()])
98 }
99}
100
101impl<'a, I> ExactSizeIterator for Words<'a, I> where I: Iterator<Item = Location> + ExactSizeIterator
102{}