commands: use new error variants for a few more commands
All checks were successful
Build and test / build (push) Successful in 1m9s
Build and test / check (push) Successful in 1m23s
Build and test / test (push) Successful in 1m39s
Build and test / docs (push) Successful in 1m21s

This commit is contained in:
2025-12-08 17:30:47 +09:00
parent 02ba7f2684
commit 624b232d0e
27 changed files with 352 additions and 86 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

@@ -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

@@ -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 = 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

@@ -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

@@ -55,7 +55,7 @@ impl CommandRequest for SearchPlaylistRequest {
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