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
use super::Parser;
use crate::parsers::{CommandArg, CommandArgParseError, ParseInput};

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Time {
    Ticks(f32),
    Seconds(f32),
    Days(f32),
}

impl CommandArg for Time {
    fn parse_arg(input: &mut ParseInput) -> Result<Self, CommandArgParseError> {
        input.skip_whitespace();
        let mut number_str = String::new();
        while let Some(c) = input.pop() {
            match c {
                't' => {
                    return Ok(Time::Ticks(number_str.parse::<f32>().map_err(|_| {
                        CommandArgParseError::InvalidArgument {
                            expected: "time".to_owned(),
                            got: "not a valid time".to_owned(),
                        }
                    })?));
                }
                's' => {
                    return Ok(Time::Seconds(number_str.parse::<f32>().map_err(|_| {
                        CommandArgParseError::InvalidArgument {
                            expected: "time".to_owned(),
                            got: "not a valid time".to_owned(),
                        }
                    })?));
                }
                'd' => {
                    return Ok(Time::Days(number_str.parse::<f32>().map_err(|_| {
                        CommandArgParseError::InvalidArgument {
                            expected: "time".to_owned(),
                            got: "not a valid time".to_owned(),
                        }
                    })?));
                }
                _ => {
                    number_str.push(c);
                }
            }
        }
        if !number_str.is_empty() {
            return Ok(Time::Ticks(number_str.parse::<f32>().map_err(|_| {
                CommandArgParseError::InvalidArgument {
                    expected: "time".to_owned(),
                    got: "not a valid time".to_owned(),
                }
            })?));
        }

        Err(CommandArgParseError::InvalidArgument {
            expected: "time".to_owned(),
            got: "not a valid time".to_owned(),
        })
    }

    fn display() -> Parser {
        Parser::Time
    }
}

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

    #[test]
    fn test_time() {
        let mut input = ParseInput::new("42.31t");
        let time = Time::parse_arg(&mut input).unwrap();
        assert_eq!(time, Time::Ticks(42.31));

        let mut input = ParseInput::new("42.31");
        let time = Time::parse_arg(&mut input).unwrap();
        assert_eq!(time, Time::Ticks(42.31));

        let mut input = ParseInput::new("1239.72s");
        let time = Time::parse_arg(&mut input).unwrap();
        assert_eq!(time, Time::Seconds(1239.72));

        let mut input = ParseInput::new("133.1d");
        let time = Time::parse_arg(&mut input).unwrap();
        assert_eq!(time, Time::Days(133.1));
    }
}