1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
///Simple split of string into arguments
pub struct Split<'a> {
    string: &'a str,
}

impl<'a> Split<'a> {
    ///Creates new instance
    pub const fn from_str(string: &'a str) -> Self {
        Self {
            string
        }
    }

    #[inline(always)]
    ///Retrieves next argument
    pub fn next_arg(&mut self) -> Option<&str> {
        self.next()
    }
}

impl<'a> Iterator for Split<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        self.string = self.string.trim_start();

        if self.string.is_empty() {
            return None;
        }

        let (end_char, from) = match self.string.get(0..=0) {
            Some("'") => ('\'', 1),
            Some("\"") => ('"', 1),
            _ => (' ', 0),
        };

        match self.string[from..].find(end_char) {
            Some(end_idx) => {
                let end_idx = end_idx + from;
                let result = &self.string[from..end_idx];
                self.string = &self.string[end_idx+1..];
                Some(result.trim_start())
            },
            None => {
                let result = &self.string[from..];
                self.string = "";
                Some(result.trim())
            }
        }

    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_simple_args() {
        let mut split = Split::from_str("ロリ が 好き");
        assert_eq!(Some("ロリ"), split.next_arg());
        assert_eq!(Some("が"), split.next_arg());
        assert_eq!(Some("好き"), split.next_arg());
        assert_eq!(None, split.next_arg());
    }

    #[test]
    fn test_quoted_args() {
        let mut split = Split::from_str("ロリ  'が が'  好き");
        assert_eq!(Some("ロリ"), split.next_arg());
        assert_eq!(Some("が が"), split.next_arg());
        assert_eq!(Some("好き"), split.next_arg());
        assert_eq!(None, split.next_arg());
    }

    #[test]
    fn test_single_quoted_args() {
        let mut split = Split::from_str("'ロリ が 好き'");
        assert_eq!(Some("ロリ が 好き"), split.next_arg());
        assert_eq!(None, split.next_arg());
    }

    #[test]
    fn test_wrong_quoted_args() {
        let mut split = Split::from_str("foo 'bar test\" baz");
        assert_eq!(Some("foo"), split.next_arg());
        assert_eq!(Some("bar test\" baz"), split.next_arg());
        assert_eq!(None, split.next_arg());
    }

    #[test]
    fn test_several_quoted_args() {
        let mut split = Split::from_str("foo 'bar test' \"baz buzz\"");
        assert_eq!(Some("foo"), split.next_arg());
        assert_eq!(Some("bar test"), split.next_arg());
        assert_eq!(Some("baz buzz"), split.next_arg());
        assert_eq!(None, split.next_arg());

    }
}