1
use std::{
2
    collections::{HashMap, HashSet},
3
    str::SplitWhitespace,
4
};
5

            
6
use crate::Request;
7

            
8
mod audio_output_devices;
9
mod client_to_client;
10
mod connection_settings;
11
mod controlling_playback;
12
mod mounts_and_neighbors;
13
mod music_database;
14
mod partition_commands;
15
mod playback_options;
16
mod querying_mpd_status;
17
mod queue;
18
mod reflection;
19
mod stickers;
20
mod stored_playlists;
21

            
22
pub use audio_output_devices::*;
23
pub use client_to_client::*;
24
pub use connection_settings::*;
25
pub use controlling_playback::*;
26
pub use mounts_and_neighbors::*;
27
pub use music_database::*;
28
pub use partition_commands::*;
29
pub use playback_options::*;
30
pub use querying_mpd_status::*;
31
pub use queue::*;
32
pub use reflection::*;
33
pub use stickers::*;
34
pub use stored_playlists::*;
35

            
36
pub trait Command {
37
    type Response;
38
    // The command name used within the protocol
39
    const COMMAND: &'static str;
40

            
41
    // TODO: `parse_request` should be using a more custom splitter, that can handle
42
    //       quoted strings and escape characters. This is what mpd uses to provide arguments
43
    //       with spaces and whatnot.
44

            
45
    // A function to parse the remaining parts of the command, split by whitespace
46
    fn parse_request(parts: SplitWhitespace<'_>) -> RequestParserResult<'_>;
47

            
48
    fn parse_raw_request(raw: &str) -> RequestParserResult<'_> {
49
        let (line, rest) = raw
50
            .split_once('\n')
51
            .ok_or(RequestParserError::UnexpectedEOF)?;
52
        let mut parts = line.split_whitespace();
53

            
54
        let command_name = parts
55
            .next()
56
            .ok_or(RequestParserError::SyntaxError(0, line.to_string()))?
57
            .trim();
58

            
59
        debug_assert!(command_name == Self::COMMAND);
60

            
61
        Self::parse_request(parts).map(|(req, _)| (req, rest))
62
    }
63

            
64
    fn parse_response(
65
        parts: ResponseAttributes<'_>,
66
    ) -> Result<Self::Response, ResponseParserError<'_>>;
67

            
68
3
    fn parse_raw_response(raw: &str) -> Result<Self::Response, ResponseParserError<'_>> {
69
3
        Self::parse_response(ResponseAttributes::new(raw)?)
70
3
    }
71
}
72

            
73
pub type RequestParserResult<'a> = Result<(Request, &'a str), RequestParserError>;
74

            
75
#[derive(Debug, Clone, PartialEq)]
76
pub enum RequestParserError {
77
    SyntaxError(u64, String),
78
    MissingCommandListEnd(u64),
79
    NestedCommandList(u64),
80
    UnexpectedCommandListEnd(u64),
81
    UnexpectedEOF,
82
    MissingNewline,
83
}
84

            
85
// TODO: should these be renamed to fit the mpd docs?
86
//       "Attribute" instead of "Property"?
87
#[derive(Debug, Clone, PartialEq)]
88
pub enum ResponseParserError<'a> {
89
    /// A property was expected to be present in the response, but was not found.
90
    MissingProperty(&'a str),
91

            
92
    // TODO: change name to UnexpectedPropertyEncoding
93
    /// An expected property was found in the response, but its encoding was not as expected. (e.g. binary instead of text)
94
    UnexpectedPropertyType(&'a str, &'a str),
95

            
96
    /// A property was found in the response that was not expected.
97
    UnexpectedProperty(&'a str),
98

            
99
    /// The property value is parsable, but the value is invalid or nonsensical.
100
    InvalidProperty(&'a str, &'a str),
101

            
102
    /// Could not parse the response due to a syntax error.
103
    SyntaxError(u64, &'a str),
104

            
105
    /// Response ended early, while more properties were expected.
106
    UnexpectedEOF,
107
    // MissingNewline,
108
}
109

            
110
pub type GenericResponseResult<'a> = Result<GenericResponse<'a>, &'a str>;
111

            
112
pub type GenericResponse<'a> = HashMap<&'a str, GenericResponseValue<'a>>;
113

            
114
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
115
pub enum GenericResponseValue<'a> {
116
    Text(&'a str),
117
    Binary(&'a [u8]),
118
    // Many(Vec<GenericResponseValue<'a>>),
119
}
120

            
121
#[derive(Debug, Clone, PartialEq)]
122
pub struct ResponseAttributes<'a>(Vec<(&'a str, GenericResponseValue<'a>)>);
123

            
124
impl<'a> ResponseAttributes<'a> {
125
3
    pub fn new(raw: &'a str) -> Result<Self, ResponseParserError<'a>> {
126
3
        let mut parts = Vec::new();
127
3
        let mut lines = raw.lines();
128
        loop {
129
29
            let line = lines.next().ok_or(ResponseParserError::UnexpectedEOF)?;
130
29
            if line.is_empty() {
131
                println!("Warning: empty line in response");
132
                continue;
133
29
            }
134
29

            
135
29
            if line == "OK" {
136
3
                break;
137
26
            }
138
26

            
139
26
            let mut keyval = line.splitn(2, ": ");
140
26
            let key = keyval
141
26
                .next()
142
26
                .ok_or(ResponseParserError::SyntaxError(0, line))?;
143

            
144
            // TODO: handle binary data, also verify binarylimit
145
26
            let value = keyval
146
26
                .next()
147
26
                .ok_or(ResponseParserError::SyntaxError(0, line))?;
148

            
149
26
            parts.push((key, GenericResponseValue::Text(value)));
150
        }
151

            
152
3
        Ok(parts.into())
153
3
    }
154

            
155
    // pub fn get<'a>(&self, key: &str) -> Option<&GenericResponseValue<'a>> {
156
    //     self.0.iter().find_map(|(k, v)| if k == &key { Some(v) } else { None })
157
    // }
158
}
159

            
160
impl ResponseAttributes<'_> {
161
    pub fn is_empty(&self) -> bool {
162
        self.0.is_empty()
163
    }
164
}
165

            
166
impl<'a> From<HashMap<&'a str, GenericResponseValue<'a>>> for ResponseAttributes<'a> {
167
    fn from(map: HashMap<&'a str, GenericResponseValue<'a>>) -> Self {
168
        Self(map.into_iter().collect())
169
    }
170
}
171

            
172
impl<'a> From<ResponseAttributes<'a>> for HashMap<&'a str, GenericResponseValue<'a>> {
173
1
    fn from(val: ResponseAttributes<'a>) -> Self {
174
1
        debug_assert!({
175
            let mut uniq = HashSet::new();
176
            val.0.iter().all(move |x| uniq.insert(*x))
177
        });
178

            
179
1
        val.0.into_iter().collect()
180
1
    }
181
}
182

            
183
impl<'a> From<ResponseAttributes<'a>> for Vec<(&'a str, GenericResponseValue<'a>)> {
184
2
    fn from(val: ResponseAttributes<'a>) -> Self {
185
2
        val.0
186
2
    }
187
}
188

            
189
impl<'a> From<Vec<(&'a str, GenericResponseValue<'a>)>> for ResponseAttributes<'a> {
190
3
    fn from(val: Vec<(&'a str, GenericResponseValue<'a>)>) -> Self {
191
3
        Self(val)
192
3
    }
193
}
194

            
195
// TODO: There should probably be a helper that lets you extract and verify one, two or maybe
196
//       three properties without having to allocate a hashmap to get a nice API. We can retrieve
197
//       the properties by name with a loop on the inner vec.
198

            
199
/*******************/
200
/* Parsing Helpers */
201
/*******************/
202

            
203
macro_rules! _expect_property_type {
204
    ($property:expr, $name:expr, $variant:ident) => {
205
        match $property {
206
            Some(crate::commands::GenericResponseValue::$variant(value)) => Some(value),
207
            Some(value) => {
208
                let actual_type = match value {
209
                    crate::commands::GenericResponseValue::Text(_) => "Text",
210
                    crate::commands::GenericResponseValue::Binary(_) => "Binary",
211
                };
212
                return Err(
213
                    crate::commands::ResponseParserError::UnexpectedPropertyType(
214
                        $name,
215
                        actual_type,
216
                    ),
217
                );
218
            }
219
            None => None,
220
        }
221
    };
222
}
223

            
224
macro_rules! _parse_optional_property_type {
225
    ($name:expr, $property:expr) => {
226
        $property
227
14
            .map(|value| {
228
14
                value.parse().map_err(|_| {
229
                    crate::commands::ResponseParserError::InvalidProperty($name, value)
230
14
                })
231
14
            })
232
            .transpose()?
233
    };
234
}
235

            
236
macro_rules! _unwrap_optional_property_type {
237
    ($name:expr, $property:expr) => {
238
        match $property {
239
            Some(value) => value,
240
            None => return Err(crate::commands::ResponseParserError::MissingProperty($name)),
241
        }
242
    };
243
}
244

            
245
macro_rules! expect_optional_property_type {
246
    ($property:expr, $name:expr, $variant:ident) => {
247
        crate::commands::_expect_property_type!($property, $name, $variant)
248
    };
249
}
250

            
251
macro_rules! expect_property_type {
252
    ($property:expr, $name:expr, $variant:ident) => {{
253
        let prop = crate::commands::_expect_property_type!($property, $name, $variant);
254
        crate::commands::_unwrap_optional_property_type!($name, prop)
255
    }};
256
}
257

            
258
macro_rules! get_optional_property {
259
    ($parts:expr, $name:literal, $variant:ident) => {
260
1
        crate::commands::_expect_property_type!({ $parts.get($name).map(|v| *v) }, $name, $variant)
261
    };
262
}
263

            
264
macro_rules! get_property {
265
    ($parts:expr, $name:literal, $variant:ident) => {{
266
        let prop = crate::commands::_expect_property_type!(
267
4
            { $parts.get($name).map(|v| *v) },
268
            $name,
269
            $variant
270
        );
271
        crate::commands::_unwrap_optional_property_type!($name, prop)
272
    }};
273
}
274

            
275
macro_rules! get_and_parse_optional_property {
276
    ($parts:ident, $name:literal, $variant:ident) => {{
277
        let prop = crate::commands::_expect_property_type!(
278
9
            { $parts.get($name).map(|v| *v) },
279
            $name,
280
            $variant
281
        );
282
        crate::commands::_parse_optional_property_type!($name, prop)
283
    }};
284
}
285

            
286
macro_rules! get_and_parse_property {
287
    ($parts:ident, $name:literal, $variant:ident) => {{
288
        let prop = crate::commands::_expect_property_type!(
289
5
            { $parts.get($name).map(|v| *v) },
290
            $name,
291
            $variant
292
        );
293
        let prop = crate::commands::_parse_optional_property_type!($name, prop);
294
        crate::commands::_unwrap_optional_property_type!($name, prop)
295
    }};
296
}
297

            
298
macro_rules! get_next_optional_property {
299
    ($parts:ident, $variant:ident) => {
300
        match $parts.next() {
301
            Some((name, value)) => {
302
                crate::commands::_expect_property_type!({ Some(value) }, name, $variant)
303
                    .map(|value| (name, value))
304
            }
305
            None => None,
306
        }
307
    };
308
}
309

            
310
macro_rules! get_next_property {
311
    ($parts:ident, $variant:ident) => {
312
        match $parts.next() {
313
            Some((name, value)) => (
314
                name,
315
                crate::commands::_expect_property_type!({ Some(value) }, name, $variant).unwrap(),
316
            ),
317
            None => return Err(crate::commands::ResponseParserError::UnexpectedEOF),
318
        }
319
    };
320
}
321

            
322
macro_rules! get_next_and_parse_optional_property {
323
    ($parts:ident, $variant:ident) => {
324
        match $parts.next() {
325
            Some((name, value)) => {
326
                let prop = crate::commands::_expect_property_type!({ Some(value) }, name, $variant);
327
                prop.map(|value| {
328
                    (
329
                        name,
330
                        crate::commands::_parse_optional_property_type!(name, value),
331
                    )
332
                })
333
            }
334
            None => None,
335
        }
336
    };
337
}
338

            
339
macro_rules! get_next_and_parse_property {
340
    ($parts:ident, $variant:ident) => {
341
        match $parts.next() {
342
            Some((name, value)) => {
343
                let prop = crate::commands::_expect_property_type!({ Some(value) }, name, $variant);
344
                let prop = crate::commands::_parse_optional_property_type!(name, prop);
345
                (
346
                    name,
347
                    crate::commands::_unwrap_optional_property_type!(name, prop),
348
                )
349
            }
350
            None => return Err(crate::commands::ResponseParserError::UnexpectedEOF),
351
        }
352
    };
353
}
354

            
355
pub(crate) use _expect_property_type;
356
pub(crate) use _parse_optional_property_type;
357
pub(crate) use _unwrap_optional_property_type;
358
pub(crate) use expect_property_type;
359
// pub(crate) use expect_optional_property_type;
360
pub(crate) use get_and_parse_optional_property;
361
pub(crate) use get_and_parse_property;
362
// pub(crate) use get_next_and_parse_optional_property;
363
pub(crate) use get_next_and_parse_property;
364
// pub(crate) use get_next_optional_property;
365
pub(crate) use get_next_property;
366
pub(crate) use get_optional_property;
367
pub(crate) use get_property;
368

            
369
#[cfg(test)]
370
mod tests {
371
    use super::*;
372

            
373
    #[test]
374
    #[cfg(debug_assertions)]
375
    fn test_valid_hashmap_uniqueness_assert() {
376
        let valid_maplike_attrs: ResponseAttributes = vec![
377
            ("a", GenericResponseValue::Text("1")),
378
            ("A", GenericResponseValue::Text("2")),
379
            ("A ", GenericResponseValue::Text("3")),
380
            ("b", GenericResponseValue::Text("4")),
381
        ]
382
        .into();
383

            
384
        let map: HashMap<_, _> = valid_maplike_attrs.into();
385
        assert_eq!(map.len(), 4);
386
    }
387

            
388
    #[test]
389
    #[cfg(debug_assertions)]
390
    #[should_panic]
391
    fn test_invalid_hashmap_uniqueness_assert() {
392
        let invalid_maplike_attrs: ResponseAttributes = vec![
393
            ("a", GenericResponseValue::Text("1")),
394
            ("b", GenericResponseValue::Text("2")),
395
            ("c", GenericResponseValue::Text("3")),
396
            ("a", GenericResponseValue::Text("4")),
397
        ]
398
        .into();
399

            
400
        let map: HashMap<_, _> = invalid_maplike_attrs.into();
401
        assert_eq!(map.len(), 4);
402
    }
403
}