aboutsummaryrefslogtreecommitdiff
path: root/src/framework/standard/args.rs
blob: 020ce6dd88a337d05492c21d7cf2e3987cb20635 (plain) (blame)
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
112
113
114
115
116
117
118
119
120
121
122
123
124
use vec_shift::Shift;
use std::str::FromStr;
use std::error::Error as StdError;
use utils::parse_quotes;

/// Defines how an operation on an `Args` method failed.
#[derive(Debug)]
pub enum Error {
    /// "END-OF-STRING", more precisely, there isn't anything to parse anymore.
    Eos,
    /// A parsing operation failed; the error in it can be of any returned from the `FromStr` trait.
    Parse(Box<StdError>),
}

type Result<T> = ::std::result::Result<T, Error>;

#[derive(Debug, Clone)]
pub struct Args {
    delimiter: String,
    delimiter_split: Vec<String>,
}

impl Args {
    pub fn new(message: &str, delimiter: &str) -> Self {
        Args {
            delimiter: delimiter.to_string(),
            delimiter_split: message.split(delimiter).map(|s| s.to_string()).collect(),
        }
    }
    
    /// Removes the first element, parses it to a specific type if necessary, returns. 
    pub fn single<T: FromStr>(&mut self) -> Result<T> where T::Err: StdError + 'static {
        if self.delimiter_split.is_empty() {
           return Err(Error::Eos); 
        }
        
        self.delimiter_split.shift()
            .ok_or(Error::Eos)?
            .parse::<T>()
            .map_err(|e| Error::Parse(Box::new(e)))
    }
    
    /// Like [`single`], but doesn't remove the element.
    ///
    /// [`single`]: #method.single
    pub fn single_n<T: FromStr>(&mut self) -> Result<T> where T::Err: StdError + 'static {
        if self.delimiter_split.is_empty() {
           return Err(Error::Eos); 
        }
        
        self.delimiter_split.get(0)
            .ok_or(Error::Eos)?
            .parse::<T>()
            .map_err(|e| Error::Parse(Box::new(e)))
    }
    
    /// Skips if there's a first element, but also returns it.
    pub fn skip(&mut self) -> Option<String> {
        self.delimiter_split.shift()
    }
    
    /// Like [`skip`], but allows for multiple at once.
    ///
    /// [`skip`]: #method.skip
    pub fn skip_for(&mut self, i: u32) -> Option<Vec<String>> {
        let mut vec = Vec::with_capacity(i as usize);
        
        for _ in 0..i {
            vec.push(match self.delimiter_split.shift() {
                Some(x) => x,
                None => return None,
            });
        }
        
        Some(vec)
    }
    
    /// Like [`single`], but takes quotes into account.
    ///
    /// [`single`]: #method.single
    pub fn single_quoted<T: FromStr>(&mut self) -> Result<T> where T::Err: StdError + 'static  {
        parse_quotes(&self.delimiter_split.shift().ok_or(Error::Eos)?).remove(0).parse::<T>().map_err(|e| Error::Parse(Box::new(e)))
    }
    
    /// Like [`single_quoted`], but doesn't remove the element.
    ///
    /// [`single_quoted`]: #method.single_quoted
    pub fn single_quoted_n<T: FromStr>(&mut self) -> Result<T> where T::Err: StdError + 'static  {
        parse_quotes(&self.delimiter_split.get(0).ok_or(Error::Eos)?).remove(0).parse::<T>().map_err(|e| Error::Parse(Box::new(e)))
    }
    
    /// Like [`list`], but takes quotes into account.
    ///
    /// [`list`]: #method.list
    pub fn multiple_quoted<T: FromStr>(self) -> Result<Vec<T>> where T::Err: StdError + 'static  {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }
        
        parse_quotes(&self.delimiter_split.join(&self.delimiter)).into_iter().map(|s| s.parse::<T>().map_err(|e| Error::Parse(Box::new(e)))).collect()
    }
    
    /// Empty outs the internal vector while parsing (if necessary) and returning them
    pub fn list<T: FromStr>(self) -> Result<Vec<T>> where T::Err: StdError + 'static  {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }
        
        self.delimiter_split.into_iter().map(|s| s.parse::<T>().map_err(|e| Error::Parse(Box::new(e)))).collect()
    }
    
    /// This method is just `internal_vector.join(delimiter)`
    pub fn full(&self) -> String {
        self.delimiter_split.join(&self.delimiter)
    }
}

impl ::std::ops::Deref for Args {
    type Target = [String];

    fn deref(&self) -> &Self::Target {
        &self.delimiter_split
    }
}