commands: use new error variants for a few more commands

This commit is contained in:
2025-12-08 17:30:47 +09:00
parent f6a0489539
commit b1bbd4ebb1
30 changed files with 413 additions and 102 deletions

View File

@@ -612,10 +612,17 @@ pub enum RequestParserError {
found: u32,
},
#[error("A keyword argument was provided without a value: {keyword}")]
#[error("Keyword argument {keyword} at position {argument_index} is missing its value")]
MissingKeywordValue {
/// The unexpected keyword that was found
keyword: String,
keyword: &'static str,
/// The index of the argument that was missing it's value
///
/// Note that in the case of keyworded arguments, such as
/// `group <groupname>`, `sort <sorting>`, etc., these are
/// counted as a single argument despite being two tokens.
argument_index: u32,
},
#[error("A command list was expected to be closed, but the end was not found")]

View File

@@ -52,7 +52,12 @@ impl CommandRequest for CountRequest {
};
let group = if let Some("group") = parts.next() {
let group = parts.next().ok_or(Self::missing_arguments_error(1))?;
let group = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
argument_index: 1,
keyword: "group",
})?;
Some(
group

View File

@@ -57,23 +57,44 @@ impl CommandRequest for FindRequest {
None => return Err(Self::missing_arguments_error(0)),
};
let mut argument_index_counter = 0;
let mut sort_or_window = parts.next();
let mut sort = None;
if let Some("sort") = sort_or_window {
let s = parts.next().ok_or(Self::missing_arguments_error(1))?;
argument_index_counter += 1;
let s = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "sort",
argument_index: argument_index_counter,
})?;
sort = Some(
s.parse()
.map_err(|_| RequestParserError::SyntaxError(0, s.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "Sort".to_string(),
raw_input: s.to_string(),
})?,
);
sort_or_window = parts.next();
}
let mut window = None;
if let Some("window") = sort_or_window {
let w = parts.next().ok_or(Self::missing_arguments_error(2))?;
argument_index_counter += 1;
let w = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "window",
argument_index: argument_index_counter,
})?;
window = Some(
w.parse()
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "WindowRange".to_string(),
raw_input: w.to_string(),
})?,
);
}

View File

@@ -61,16 +61,23 @@ impl CommandRequest for FindAddRequest {
None => return Err(Self::missing_arguments_error(0)),
};
let mut argument_index_counter = 0;
let mut sort_or_window_or_position = parts.next();
let mut sort = None;
if let Some("sort") = sort_or_window_or_position {
let s = parts.next().ok_or(Self::missing_arguments_error(1))?;
argument_index_counter += 1;
let s = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "sort",
argument_index: argument_index_counter,
})?;
sort = Some(
s.parse()
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 1,
argument_index: argument_index_counter,
expected_type: "Sort".to_string(),
raw_input: s.to_owned(),
raw_input: s.to_string(),
})?,
);
sort_or_window_or_position = parts.next();
@@ -78,13 +85,19 @@ impl CommandRequest for FindAddRequest {
let mut window = None;
if let Some("window") = sort_or_window_or_position {
let w = parts.next().ok_or(Self::missing_arguments_error(2))?;
argument_index_counter += 1;
let w = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "window",
argument_index: argument_index_counter,
})?;
window = Some(
w.parse()
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 2,
argument_index: argument_index_counter,
expected_type: "WindowRange".to_string(),
raw_input: w.to_owned(),
raw_input: w.to_string(),
})?,
);
sort_or_window_or_position = parts.next();
@@ -92,13 +105,19 @@ impl CommandRequest for FindAddRequest {
let mut position = None;
if let Some("position") = sort_or_window_or_position {
let p = parts.next().ok_or(Self::missing_arguments_error(3))?;
argument_index_counter += 1;
let p = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "position",
argument_index: argument_index_counter,
})?;
position = Some(
p.parse()
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 3,
argument_index: argument_index_counter,
expected_type: "SongPosition".to_string(),
raw_input: p.to_owned(),
raw_input: p.to_string(),
})?,
);
}

View File

@@ -70,10 +70,12 @@ impl CommandRequest for ListRequest {
let mut next = parts.next();
let mut argument_index_counter = 0;
if let Some(f) = next
&& f != "group"
&& f != "window"
{
argument_index_counter += 1;
let parsed_filter =
Filter::parse(f).map_err(|_| RequestParserError::SyntaxError(1, f.to_owned()))?;
filter = Some(parsed_filter);
@@ -83,7 +85,13 @@ impl CommandRequest for ListRequest {
while let Some(g) = next
&& g == "group"
{
let group = parts.next().ok_or(Self::missing_arguments_error(2))?;
argument_index_counter += 1;
let group = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "group",
argument_index: argument_index_counter,
})?;
let parsed_group =
group
.parse()
@@ -99,7 +107,12 @@ impl CommandRequest for ListRequest {
if let Some(w) = next
&& w == "window"
{
let window_str = parts.next().ok_or(Self::missing_arguments_error(3))?;
let window_str = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "window",
argument_index: argument_index_counter,
})?;
let parsed_window =
window_str
.parse()

View File

@@ -57,23 +57,44 @@ impl CommandRequest for SearchRequest {
None => return Err(Self::missing_arguments_error(0)),
};
let mut argument_index_counter = 0;
let mut sort_or_window = parts.next();
let mut sort = None;
if let Some("sort") = sort_or_window {
let s = parts.next().ok_or(Self::missing_arguments_error(1))?;
argument_index_counter += 1;
let s = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "sort",
argument_index: argument_index_counter,
})?;
sort = Some(
s.parse()
.map_err(|_| RequestParserError::SyntaxError(0, s.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "Sort".to_string(),
raw_input: s.to_string(),
})?,
);
sort_or_window = parts.next();
}
let mut window = None;
if let Some("window") = sort_or_window {
let w = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
argument_index_counter += 1;
let w = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "window",
argument_index: argument_index_counter,
})?;
window = Some(
w.parse()
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "WindowRange".to_string(),
raw_input: w.to_string(),
})?,
);
}

View File

@@ -61,33 +61,64 @@ impl CommandRequest for SearchAddRequest {
None => return Err(Self::missing_arguments_error(0)),
};
let mut argument_index_counter = 0;
let mut sort_or_window_or_position = parts.next();
let mut sort = None;
if let Some("sort") = sort_or_window_or_position {
let s = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
argument_index_counter += 1;
let s = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "sort",
argument_index: argument_index_counter,
})?;
sort = Some(
s.parse()
.map_err(|_| RequestParserError::SyntaxError(0, s.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "Sort".to_string(),
raw_input: s.to_string(),
})?,
);
sort_or_window_or_position = parts.next();
}
let mut window = None;
if let Some("window") = sort_or_window_or_position {
let w = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
argument_index_counter += 1;
let w = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "window",
argument_index: argument_index_counter,
})?;
window = Some(
w.parse()
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "WindowRange".to_string(),
raw_input: w.to_string(),
})?,
);
sort_or_window_or_position = parts.next();
}
let mut position = None;
if let Some("position") = sort_or_window_or_position {
let p = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
argument_index_counter += 1;
let p = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "position",
argument_index: argument_index_counter,
})?;
position = Some(
p.parse()
.map_err(|_| RequestParserError::SyntaxError(0, p.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "SongPosition".to_string(),
raw_input: p.to_string(),
})?,
);
}

View File

@@ -66,43 +66,74 @@ impl CommandRequest for SearchAddPlRequest {
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let playlist_name = parts
.next()
.ok_or(RequestParserError::UnexpectedEOF)?
.ok_or(Self::missing_arguments_error(0))?
.to_string();
let filter = match parts.next() {
Some(f) => {
Filter::parse(f).map_err(|_| RequestParserError::SyntaxError(1, f.to_owned()))?
}
None => return Err(RequestParserError::UnexpectedEOF),
None => return Err(Self::missing_arguments_error(1)),
};
let mut argument_index_counter = 1;
let mut sort_or_window_or_position = parts.next();
let mut sort = None;
if let Some("sort") = sort_or_window_or_position {
let s = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
argument_index_counter += 1;
let s = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "sort",
argument_index: argument_index_counter,
})?;
sort = Some(
s.parse()
.map_err(|_| RequestParserError::SyntaxError(0, s.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "Sort".to_string(),
raw_input: s.to_string(),
})?,
);
sort_or_window_or_position = parts.next();
}
let mut window = None;
if let Some("window") = sort_or_window_or_position {
let w = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
argument_index_counter += 1;
let w = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "window",
argument_index: argument_index_counter,
})?;
window = Some(
w.parse()
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "WindowRange".to_string(),
raw_input: w.to_string(),
})?,
);
sort_or_window_or_position = parts.next();
}
let mut position = None;
if let Some("position") = sort_or_window_or_position {
let p = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
argument_index_counter += 1;
let p = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "position",
argument_index: argument_index_counter,
})?;
position = Some(
p.parse()
.map_err(|_| RequestParserError::SyntaxError(0, p.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "SongPosition".to_string(),
raw_input: p.to_string(),
})?,
);
}

View File

@@ -54,11 +54,20 @@ impl CommandRequest for SearchCountRequest {
};
let group = if let Some("group") = parts.next() {
let group = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let group = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "group",
argument_index: 1,
})?;
Some(
group
.parse()
.map_err(|_| RequestParserError::SyntaxError(1, group.to_owned()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 1,
expected_type: "Group".to_string(),
raw_input: group.to_string(),
})?,
)
} else {
None

View File

@@ -35,15 +35,24 @@ impl CommandRequest for MoveRequest {
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let from_or_range = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let from_or_range = from_or_range
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, from_or_range.to_string()))?;
let from_or_range = parts.next().ok_or(Self::missing_arguments_error(0))?;
let from_or_range =
from_or_range
.parse()
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 0,
expected_type: "OneOrRange".to_string(),
raw_input: from_or_range.to_string(),
})?;
let to = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let to = parts.next().ok_or(Self::missing_arguments_error(1))?;
let to = to
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, to.to_string()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 1,
expected_type: "AbsoluteRelativeSongPosition".to_string(),
raw_input: to.to_string(),
})?;
Self::throw_if_too_many_arguments(parts)?;

View File

@@ -35,15 +35,23 @@ impl CommandRequest for MoveIdRequest {
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let id = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let id = parts.next().ok_or(Self::missing_arguments_error(0))?;
let id = id
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, id.to_string()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 0,
expected_type: "SongId".to_string(),
raw_input: id.to_string(),
})?;
let to = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let to = parts.next().ok_or(Self::missing_arguments_error(1))?;
let to = to
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, to.to_string()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 1,
expected_type: "AbsoluteRelativeSongPosition".to_string(),
raw_input: to.to_string(),
})?;
Self::throw_if_too_many_arguments(parts)?;

View File

@@ -58,23 +58,44 @@ impl CommandRequest for PlaylistFindRequest {
None => return Err(Self::missing_arguments_error(0)),
};
let mut argument_index_counter = 0;
let mut sort_or_window = parts.next();
let mut sort = None;
if let Some("sort") = sort_or_window {
let s = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
argument_index_counter += 1;
let s = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "sort",
argument_index: argument_index_counter,
})?;
sort = Some(
s.parse()
.map_err(|_| RequestParserError::SyntaxError(0, s.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "Sort".to_string(),
raw_input: s.to_string(),
})?,
);
sort_or_window = parts.next();
}
let mut window = None;
if let Some("window") = sort_or_window {
let w = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
argument_index_counter += 1;
let w = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "window",
argument_index: argument_index_counter,
})?;
window = Some(
w.parse()
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "WindowRange".to_string(),
raw_input: w.to_string(),
})?,
);
}

View File

@@ -57,23 +57,44 @@ impl CommandRequest for PlaylistSearchRequest {
None => return Err(Self::missing_arguments_error(0)),
};
let mut argument_index_counter = 0;
let mut sort_or_window = parts.next();
let mut sort = None;
if let Some("sort") = sort_or_window {
let s = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
argument_index_counter += 1;
let s = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "sort",
argument_index: argument_index_counter,
})?;
sort = Some(
s.parse()
.map_err(|_| RequestParserError::SyntaxError(0, s.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "Sort".to_string(),
raw_input: s.to_string(),
})?,
);
sort_or_window = parts.next();
}
let mut window = None;
if let Some("window") = sort_or_window {
let w = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
argument_index_counter += 1;
let w = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "window",
argument_index: argument_index_counter,
})?;
window = Some(
w.parse()
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "WindowRange".to_string(),
raw_input: w.to_string(),
})?,
);
}

View File

@@ -41,16 +41,24 @@ impl CommandRequest for PlChangesRequest {
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let version = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let version = parts.next().ok_or(Self::missing_arguments_error(0))?;
let version = version
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, version.to_string()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 0,
expected_type: "PlaylistVersion".to_string(),
raw_input: version.to_string(),
})?;
let window = parts
.next()
.map(|w| {
w.parse()
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 1,
expected_type: "WindowRange".to_string(),
raw_input: w.to_string(),
})
})
.transpose()?;

View File

@@ -41,16 +41,24 @@ impl CommandRequest for PlChangesPosIdRequest {
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let version = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let version = parts.next().ok_or(Self::missing_arguments_error(0))?;
let version = version
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, version.to_string()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 0,
expected_type: "PlaylistVersion".to_string(),
raw_input: version.to_string(),
})?;
let window = parts
.next()
.map(|w| {
w.parse()
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 1,
expected_type: "WindowRange".to_string(),
raw_input: w.to_string(),
})
})
.transpose()?;

View File

@@ -35,15 +35,23 @@ impl CommandRequest for PrioRequest {
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let prio = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let prio = parts.next().ok_or(Self::missing_arguments_error(0))?;
let prio = prio
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, prio.to_string()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 0,
expected_type: "Priority".to_string(),
raw_input: prio.to_string(),
})?;
let window = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let window = parts.next().ok_or(Self::missing_arguments_error(1))?;
let window = window
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, window.to_string()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 1,
expected_type: "WindowRange".to_string(),
raw_input: window.to_string(),
})?;
Self::throw_if_too_many_arguments(parts)?;

View File

@@ -42,12 +42,17 @@ impl CommandRequest for PrioIdRequest {
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let prio = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let prio = parts.next().ok_or(Self::missing_arguments_error(0))?;
let prio = prio
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, prio.to_string()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 0,
expected_type: "Priority".to_string(),
raw_input: prio.to_string(),
})?;
let songids = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
// TODO: determine how to count arguments here...
let songids = parts.next().ok_or(Self::missing_arguments_error(1))?;
let songids = songids
.split(',')
.map(|s| {

View File

@@ -38,15 +38,24 @@ impl CommandRequest for RangeIdRequest {
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let songid = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songid = parts.next().ok_or(Self::missing_arguments_error(0))?;
let songid = songid
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, songid.to_string()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 0,
expected_type: "SongId".to_string(),
raw_input: songid.to_string(),
})?;
let time_interval = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let time_interval = time_interval
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, time_interval.to_string()))?;
let time_interval = parts.next().ok_or(Self::missing_arguments_error(1))?;
let time_interval =
time_interval
.parse()
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 1,
expected_type: "TimeInterval".to_string(),
raw_input: time_interval.to_string(),
})?;
Self::throw_if_too_many_arguments(parts)?;

View File

@@ -35,15 +35,23 @@ impl CommandRequest for SwapRequest {
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let songpos1 = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songpos1 = parts.next().ok_or(Self::missing_arguments_error(0))?;
let songpos1 = songpos1
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, songpos1.to_string()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 0,
expected_type: "SongPosition".to_string(),
raw_input: songpos1.to_string(),
})?;
let songpos2 = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songpos2 = parts.next().ok_or(Self::missing_arguments_error(1))?;
let songpos2 = songpos2
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, songpos2.to_string()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 1,
expected_type: "SongPosition".to_string(),
raw_input: songpos2.to_string(),
})?;
Self::throw_if_too_many_arguments(parts)?;

View File

@@ -35,15 +35,23 @@ impl CommandRequest for SwapIdRequest {
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let songid1 = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songid1 = parts.next().ok_or(Self::missing_arguments_error(0))?;
let songid1 = songid1
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, songid1.to_string()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 0,
expected_type: "SongId".to_string(),
raw_input: songid1.to_string(),
})?;
let songid2 = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songid2 = parts.next().ok_or(Self::missing_arguments_error(1))?;
let songid2 = songid2
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, songid2.to_string()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 1,
expected_type: "SongId".to_string(),
raw_input: songid2.to_string(),
})?;
Self::throw_if_too_many_arguments(parts)?;

View File

@@ -77,10 +77,14 @@ impl CommandRequest for StickerDecRequest {
raw_input: name.to_string(),
})?;
let value = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let value = parts.next().ok_or(Self::missing_arguments_error(3))?;
let value = value
.parse()
.map_err(|_| RequestParserError::SyntaxError(1, value.to_owned()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 3,
expected_type: "usize".to_string(),
raw_input: value.to_string(),
})?;
Self::throw_if_too_many_arguments(parts)?;

View File

@@ -95,23 +95,44 @@ impl CommandRequest for StickerFindRequest {
raw_input: name.to_string(),
})?;
let mut argument_index_counter = 2;
let mut sort_or_window = parts.next();
let mut sort = None;
if let Some("sort") = sort_or_window {
let s = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
argument_index_counter += 1;
let s = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "sort",
argument_index: argument_index_counter,
})?;
sort = Some(
s.parse()
.map_err(|_| RequestParserError::SyntaxError(0, s.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "Sort".to_string(),
raw_input: s.to_string(),
})?,
);
sort_or_window = parts.next();
}
let mut window = None;
if let Some("window") = sort_or_window {
let w = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
argument_index_counter += 1;
let w = parts
.next()
.ok_or(RequestParserError::MissingKeywordValue {
keyword: "window",
argument_index: argument_index_counter,
})?;
window = Some(
w.parse()
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))?,
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: argument_index_counter,
expected_type: "WindowRange".to_string(),
raw_input: w.to_string(),
})?,
);
}

View File

@@ -77,10 +77,14 @@ impl CommandRequest for StickerIncRequest {
raw_input: name.to_string(),
})?;
let value = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let value = parts.next().ok_or(Self::missing_arguments_error(3))?;
let value = value
.parse()
.map_err(|_| RequestParserError::SyntaxError(1, value.to_owned()))?;
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 3,
expected_type: "usize".to_string(),
raw_input: value.to_string(),
})?;
Self::throw_if_too_many_arguments(parts)?;

View File

@@ -77,7 +77,7 @@ impl CommandRequest for StickerSetRequest {
raw_input: name.to_string(),
})?;
let value = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let value = parts.next().ok_or(Self::missing_arguments_error(3))?;
Self::throw_if_too_many_arguments(parts)?;

View File

@@ -45,7 +45,7 @@ impl CommandRequest for ListPlaylistRequest {
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let name = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let name = parts.next().ok_or(Self::missing_arguments_error(0))?;
let name = name
.parse::<PlaylistName>()
.map_err(|_| RequestParserError::SyntaxError(0, name.to_owned()))?;

View File

@@ -41,7 +41,7 @@ impl CommandRequest for ListPlaylistInfoRequest {
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let name = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let name = parts.next().ok_or(Self::missing_arguments_error(0))?;
let name = name
.parse::<PlaylistName>()
.map_err(|_| RequestParserError::SyntaxError(0, name.to_owned()))?;

View File

@@ -67,7 +67,11 @@ impl CommandRequest for PlaylistAddRequest {
.next()
.map(|s| {
s.parse()
.map_err(|_| RequestParserError::SyntaxError(0, s.to_owned()))
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 2,
expected_type: "SongPosition".to_string(),
raw_input: s.to_string(),
})
})
.transpose()?;

View File

@@ -51,7 +51,7 @@ impl CommandRequest for PlaylistDeleteRequest {
.to_string();
// TODO: this can be a range, according to docs
let position = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let position = parts.next().ok_or(Self::missing_arguments_error(1))?;
let position = position
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, position.to_string()))?;

View File

@@ -59,7 +59,7 @@ impl CommandRequest for PlaylistMoveRequest {
.to_string();
let mut from = None;
let from_or_range_or_to = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let from_or_range_or_to = parts.next().ok_or(Self::missing_arguments_error(1))?;
let to = parts.next();

View File

@@ -47,22 +47,30 @@ impl CommandRequest for SearchPlaylistRequest {
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let name = parts.next().ok_or(Self::missing_arguments_error(0))?;
let name = name
.parse::<PlaylistName>()
.map_err(|_| RequestParserError::SyntaxError(0, name.to_owned()))?;
let name =
name.parse::<PlaylistName>()
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 0,
expected_type: "PlaylistName".to_string(),
raw_input: name.to_string(),
})?;
let filter = match parts.next() {
Some(f) => {
Filter::parse(f).map_err(|_| RequestParserError::SyntaxError(1, f.to_owned()))?
}
None => return Err(RequestParserError::UnexpectedEOF),
None => return Err(Self::missing_arguments_error(1)),
};
let range = parts
.next()
.map(|s| {
s.parse()
.map_err(|_| RequestParserError::SyntaxError(0, s.to_owned()))
.map_err(|_| RequestParserError::SubtypeParserError {
argument_index: 0,
expected_type: "WindowRange".to_string(),
raw_input: s.to_string(),
})
})
.transpose()?;