key_list/
lib.rs

1//! A minimalistic crate to help you quickly
2//! get substrings of text between 2 characters
3//! inside a string.
4#![warn(missing_docs)]
5
6
7/// The list itself
8pub struct KeyList<'a> {
9    input: &'a str,
10    start: char,
11    end: char
12}
13
14
15impl<'a> KeyList<'a> {
16    /// Creates a new iterable list of keys
17    ///
18    /// # Example
19    /// ```
20    /// # use crate::key_list::KeyList;
21    ///
22    /// let list = KeyList::new("<a> <b> <c>", '<', '>');
23    /// ```
24    pub fn new(input: &'a str, start: char, end: char) -> Self {
25        Self {
26            input,
27            start,
28            end
29        }
30    }
31}
32
33
34impl<'a> Iterator for KeyList<'a> {
35    type Item = &'a str;
36
37    fn next(&mut self) -> Option<Self::Item> {
38        let mut key = None;
39
40        if let Some(i) = self.input.find(self.start) {
41            self.input = &self.input[i..];
42            let mut first = true;
43
44            let rest = self.input.char_indices()
45                .take_while(|(_, c)| {
46                    if first {
47                        first = false;
48                        return true;
49                    }
50
51                    *c != self.end
52                })
53                .last()
54                .map(|(idx, c)| idx + c.len_utf8())
55                .unwrap_or_default();
56
57            // +1 to get the end symbol that's excluded
58            key = Some(&self.input[..(rest + 1)]);
59            self.input = &self.input[(rest + 1)..];
60        }
61
62        key
63    }
64}
65
66
67
68
69
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn find_keys() {
77        let input = "<black> <red> one two <three>";
78        let key_count = KeyList::new(input, '<', '>').count();
79
80        assert_eq!(key_count, 3);
81    }
82
83    #[test]
84    fn different_start() {
85        let input = "<A/ <B> one two <C/";
86        let key_count = KeyList::new(input, '<', '/').count();
87
88        assert_eq!(key_count, 2);
89    }
90
91    #[test]
92    fn different_character() {
93        let input = "/A/ /B/ one two /C/";
94        let key_count = KeyList::new(input, '/', '/').count();
95
96        assert_eq!(key_count, 3);
97    }
98}