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
125
126
127
128
129
130
131
132
133
use pest::error::Error as PestError;
use pest::Parser;
use pest_derive::Parser;
use serde_json::json;
use std::collections::HashMap;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum WeatherParserError {
#[error("Parsing error: {0}")]
ParsingError(#[from] Box<PestError<Rule>>),
#[error("Invalid input format: {0}")]
InvalidInput(String),
}
#[derive(Parser)]
#[grammar = "./grammar.pest"]
pub struct WeatherParser;
pub fn parse_input(input: &str) -> Result<HashMap<String, serde_json::Value>, WeatherParserError> {
let mut weather_data = HashMap::new();
if let Ok(mut parsed) = WeatherParser::parse(Rule::string_collection, input) {
if let Some(collection) = parsed.next() {
let strings: Vec<_> = collection
.into_inner()
.map(|pair| pair.as_str().trim())
.collect();
let rules = [
Rule::condition,
Rule::temperature,
Rule::humidity,
Rule::wind,
Rule::precipitation,
Rule::visibility,
Rule::cloud_cover,
Rule::pressure,
Rule::uv_index,
Rule::air_quality,
Rule::sunrise,
Rule::sunset,
Rule::cloud_types,
];
for (i, string) in strings.iter().enumerate() {
if i < rules.len() {
if let Some(record) = WeatherParser::parse(rules[i], string)
.map_err(|e| WeatherParserError::ParsingError(Box::new(e)))?
.next()
{
match rules[i] {
Rule::wind => {
let mut wind_data = HashMap::new();
for inner in record.into_inner() {
match inner.as_rule() {
Rule::direction => {
wind_data.insert(
"Direction",
inner.as_str().trim().to_string(),
);
}
Rule::float | Rule::integer => {
wind_data
.insert("Speed", inner.as_str().trim().to_string());
}
_ => {}
}
}
weather_data.insert("Wind".to_string(), json!(wind_data));
}
Rule::precipitation => {
let mut precipitation_data = HashMap::new();
for inner in record.into_inner() {
match inner.as_rule() {
Rule::precipitation_type => {
precipitation_data
.insert("Type", inner.as_str().trim().to_string());
}
Rule::float | Rule::integer => {
precipitation_data.insert(
"Amount",
inner.as_str().trim().to_string(),
);
}
_ => {}
}
}
weather_data
.insert("Precipitation".to_string(), json!(precipitation_data));
}
Rule::cloud_types => {
let cloud_types: Vec<String> = record
.into_inner()
.map(|inner| inner.as_str().trim().to_string())
.collect();
weather_data.insert("Cloud Types".to_string(), json!(cloud_types));
}
_ => {
let key = match rules[i] {
Rule::condition => "Condition",
Rule::temperature => "Temperature",
Rule::humidity => "Humidity",
Rule::visibility => "Visibility",
Rule::cloud_cover => "Cloud Cover",
Rule::pressure => "Pressure",
Rule::uv_index => "UV Index",
Rule::air_quality => "Air Quality",
Rule::sunrise => "Sunrise",
Rule::sunset => "Sunset",
Rule::cloud_types => "Cloud Types",
_ => "Unknown",
};
weather_data.insert(
key.to_string(),
json!(record.as_str().trim().to_string()),
);
}
}
}
}
}
}
}
if weather_data.is_empty() {
Err(WeatherParserError::InvalidInput(
"No matching rule found".to_string(),
))
} else {
Ok(weather_data)
}
}