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
101
102
103
104
105
106
107
108
109
110
111
use bevy_derive::Deref;
use valence_server::protocol::packets::play::command_tree_s2c::StringArg;

use super::Parser;
use crate::parsers::{CommandArg, CommandArgParseError, ParseInput};

impl CommandArg for String {
    fn parse_arg(input: &mut ParseInput) -> Result<Self, CommandArgParseError> {
        input.skip_whitespace();
        Ok(input.pop_word().to_owned())
    }

    fn display() -> Parser {
        Parser::String(StringArg::SingleWord)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Default, Deref)]
pub struct GreedyString(pub String);

impl CommandArg for GreedyString {
    fn parse_arg(input: &mut ParseInput) -> Result<Self, CommandArgParseError> {
        input.skip_whitespace();
        Ok(GreedyString(
            match input.pop_all() {
                Some(s) => s,
                None => return Err(CommandArgParseError::InvalidArgLength),
            }
            .to_owned(),
        ))
    }

    fn display() -> Parser {
        Parser::String(StringArg::GreedyPhrase)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Default, Deref)]
pub struct QuotableString(pub String);

impl CommandArg for QuotableString {
    fn parse_arg(input: &mut ParseInput) -> Result<Self, CommandArgParseError> {
        input.skip_whitespace();
        match input.peek() {
            Some('"') => {
                input.pop();
                let mut s = String::new();
                let mut escaped = false;
                while let Some(c) = input.pop() {
                    if escaped {
                        s.push(c);
                        escaped = false;
                    } else if c == '\\' {
                        escaped = true;
                    } else if c == '"' {
                        return Ok(QuotableString(s));
                    } else {
                        s.push(c);
                    }
                }
                Err(CommandArgParseError::InvalidArgLength)
            }
            Some(_) => Ok(QuotableString(String::parse_arg(input)?)),
            None => Err(CommandArgParseError::InvalidArgLength),
        }
    }

    fn display() -> Parser {
        Parser::String(StringArg::QuotablePhrase)
    }
}

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

    #[test]
    fn test_quotable_string() {
        let mut input = ParseInput::new("\"hello world\"");
        assert_eq!(
            "hello world",
            QuotableString::parse_arg(&mut input).unwrap().0
        );
        assert!(input.is_done());

        let mut input = ParseInput::new("\"hello w\"orld");
        assert_eq!("hello w", QuotableString::parse_arg(&mut input).unwrap().0);
        assert!(!input.is_done());

        let mut input = ParseInput::new("hello world\"");
        assert_eq!("hello", QuotableString::parse_arg(&mut input).unwrap().0);
        assert!(!input.is_done());
    }

    #[test]
    fn test_greedy_string() {
        let mut input = ParseInput::new("hello world");
        assert_eq!(
            "hello world",
            GreedyString::parse_arg(&mut input).unwrap().0
        );
        assert!(input.is_done());
    }
    #[test]
    fn test_string() {
        let mut input = ParseInput::new("hello world");
        assert_eq!("hello", String::parse_arg(&mut input).unwrap());
        assert_eq!("world", String::parse_arg(&mut input).unwrap());
        assert!(input.is_done());
    }
}