human_name/
word.rs

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{}