statsd_parser/parser/
mod.rs1use std::{error,fmt};
2use std::num::ParseFloatError;
3use std::vec::Vec;
4use std::collections::BTreeMap;
5
6
7pub mod metric_parser;
8pub mod service_check_parser;
9
10#[derive(Debug,PartialEq)]
11pub enum ParseError {
12 EmptyInput,
14 IncompleteInput,
16 NoName,
18 ValueNotFloat,
20 SampleRateNotFloat,
22 UnknownMetricType,
24}
25
26impl fmt::Display for ParseError {
27 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28 match *self {
29 ParseError::EmptyInput => write!(f, "Empty input"),
30 ParseError::IncompleteInput => write!(f, "Incomplete input"),
31 ParseError::NoName => write!(f, "No name in input"),
32 ParseError::ValueNotFloat => write!(f, "Value is not a float"),
33 ParseError::SampleRateNotFloat => write!(f, "Sample rate is not a float"),
34 ParseError::UnknownMetricType => write!(f, "Unknown metric type")
35 }
36 }
37}
38
39impl error::Error for ParseError {
40 fn description(&self) -> &str {
42 "description() is deprecated; use Display"
43 }
44}
45
46#[derive(Debug,PartialEq)]
47pub struct Parser {
48 chars: Vec<char>,
49 len: usize,
50 pos: usize
51}
52
53impl Parser {
54 pub fn new(buf: String) -> Parser {
56 let chars: Vec<char> = buf.chars().collect();
57 let len = chars.len();
58 Parser {
59 chars: chars,
60 len: len,
61 pos: 0
62 }
63 }
64
65 fn take_until(&mut self, to_match: Vec<char>) -> String {
68 let mut chars = Vec::new();
69 loop {
70 if self.pos >= self.len {
71 break
72 }
73 let current_char = self.chars[self.pos];
74 self.pos += 1;
75 if to_match.contains(¤t_char) {
76 break
77 } else {
78 chars.push(current_char);
79 }
80 }
81 chars.into_iter().collect()
82 }
83
84 fn take_float_until(&mut self, to_match: Vec<char>) -> Result<f64, ParseFloatError> {
87 let string = self.take_until(to_match);
88 string.parse()
89 }
90
91 fn peek(&mut self) -> Option<char> {
93 if self.pos == self.len {
94 None
95 } else {
96 Some(self.chars[self.pos])
97 }
98 }
99
100 fn last(&mut self) -> Option<char> {
102 if self.pos == 0 {
103 None
104 } else {
105 Some(self.chars[self.pos - 1 ])
106 }
107 }
108
109 fn skip(&mut self) {
111 self.pos += 1;
112 }
113
114 fn parse_tags(&mut self) -> BTreeMap<String, String> {
115 let mut tags = BTreeMap::new();
116
117 self.skip(); loop {
123 if Some('|') == self.last() {
125 break
126 }
127
128 let tag = self.take_until(vec![',', '|']);
130 if tag.is_empty() {
131 break
132 }
133
134 let mut split= tag.split(":");
137 match split.next() {
138 Some(key) => {
139 let parts: Vec<&str> = split.collect();
140 tags.insert(key.to_owned(), parts.join(":"))
141 },
142 None => break
143 };
144 }
145
146 tags
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use std::collections::BTreeMap;
153
154 use super::Parser;
155
156 #[test]
157 fn test_take_until() {
158 let mut parser = Parser::new("this is a string".to_string());
159
160 assert_eq!(parser.take_until(vec![' ']), "this");
162
163 assert_eq!(parser.pos, 5);
165
166 assert_eq!(parser.take_until(vec!['.']), "is a string");
168
169 assert_eq!(parser.pos, 16);
171 }
172
173 #[test]
174 fn test_take_float_until() {
175 let mut parser = Parser::new("10.01|number|string".to_string());
176
177 assert_eq!(parser.take_float_until(vec!['|']), Ok(10.01));
179
180 assert_eq!(parser.pos, 6);
182
183 assert!(parser.take_float_until(vec!['|']).is_err());
185
186 assert_eq!(parser.pos, 13);
188 }
189
190 #[test]
191 fn test_peek() {
192 let mut parser = Parser::new("this is a string".to_string());
193 parser.pos = 10;
194
195 assert_eq!(parser.peek(), Some('s'));
197
198 assert_eq!(parser.pos, 10);
200
201 parser.pos = 16;
202
203 assert_eq!(parser.peek(), None);
205 }
206
207 #[test]
208 fn test_last() {
209 let mut parser = Parser::new("abcdef".to_string());
210 parser.pos = 0;
211
212 assert_eq!(parser.last(), None);
214
215 assert_eq!(parser.pos, 0);
217
218 parser.pos = 3;
219
220 assert_eq!(parser.last(), Some('c'));
222 }
223
224 #[test]
225 fn test_skip() {
226 let mut parser = Parser::new("foo#bar".to_string());
227 parser.pos = 3;
228 parser.skip();
229
230 assert_eq!(parser.pos, 4);
232 }
233
234 #[test]
235 fn test_parse_tags() {
236 let mut parser = Parser::new("#hostname:frontend1,redis_instance:10.0.0.16:6379,namespace:web".to_string());
237
238 let mut tags = BTreeMap::new();
239 tags.insert("hostname".to_string(), "frontend1".to_string());
240 tags.insert("redis_instance".to_string(), "10.0.0.16:6379".to_string());
241 tags.insert("namespace".to_string(), "web".to_string());
242
243 assert_eq!(parser.parse_tags(), tags);
245 }
246}