skip parsed line if expected field not present

This commit is contained in:
MaxOhn
2023-02-09 07:08:35 +01:00
parent 6c36065ea1
commit d15f3313d9
2 changed files with 48 additions and 101 deletions
-4
View File
@@ -19,8 +19,6 @@ pub enum ParseError {
InvalidDecimalNumber,
/// Failed to parse game mode.
InvalidMode,
/// Expected an additional field.
MissingField(&'static str),
/// Failed to recognized specified type for hitobjects.
UnknownHitObjectKind,
}
@@ -36,7 +34,6 @@ impl fmt::Display for ParseError {
Self::InvalidCurvePoints => f.write_str("invalid curve point"),
Self::InvalidDecimalNumber => f.write_str("invalid float number"),
Self::InvalidMode => f.write_str("invalid mode"),
Self::MissingField(field) => write!(f, "missing field `{field}`"),
Self::UnknownHitObjectKind => f.write_str("unsupported hitobject kind"),
}
}
@@ -51,7 +48,6 @@ impl StdError for ParseError {
Self::InvalidCurvePoints => None,
Self::InvalidDecimalNumber => None,
Self::InvalidMode => None,
Self::MissingField(_) => None,
Self::UnknownHitObjectKind => None,
}
}
+48 -97
View File
@@ -33,16 +33,6 @@ use crate::{
util::{SortedVec, TandemSorter},
};
trait OptionExt<T> {
fn next_field(self, field: &'static str) -> Result<T, ParseError>;
}
impl<T> OptionExt<T> for Option<T> {
fn next_field(self, field: &'static str) -> Result<T, ParseError> {
self.ok_or(ParseError::MissingField(field))
}
}
trait InRange: Sized + Copy + Neg<Output = Self> + PartialOrd + FromStr {
const LIMIT: Self;
@@ -239,15 +229,8 @@ macro_rules! parse_events_body {
// We're only interested in breaks
if let Some(b'2') = split.next().and_then(|value| value.bytes().next()) {
let start_time = split
.next()
.next_field("break start")
.map(f64::parse_in_range)?;
let end_time = split
.next()
.next_field("break end")
.map(f64::parse_in_range)?;
let start_time = split.next().and_then(f64::parse_in_range);
let end_time = split.next().and_then(f64::parse_in_range);
if let (Some(start_time), Some(end_time)) = (start_time, end_time) {
$self.breaks.push(Break {
@@ -279,13 +262,7 @@ macro_rules! parse_timingpoints_body {
let line = $reader.get_line()?;
let mut split = line.split(',');
let time_opt = split
.next()
.next_field("timing point time")
.map(str::trim)
.map(f64::parse_in_range)?;
let time = match time_opt {
let time = match split.next().map(str::trim).and_then(f64::parse_in_range) {
Some(time) => time,
None => continue,
};
@@ -293,11 +270,10 @@ macro_rules! parse_timingpoints_body {
// * beatLength is allowed to be NaN to handle an edge case in which
// * some beatmaps use NaN slider velocity to disable slider tick
// * generation (see LegacyDifficultyControlPoint).
let beat_len: f64 = split.next().next_field("beat len")?.trim().parse()?;
if !(beat_len.is_in_range() || beat_len.is_nan()) {
continue;
}
let beat_len = match split.next().map(str::trim).map(str::parse::<f64>) {
Some(Ok(beat_len)) if beat_len.is_in_range() || beat_len.is_nan() => beat_len,
_ => continue,
};
let mut timing_change = true;
let mut kiai = false;
@@ -428,14 +404,12 @@ macro_rules! parse_hitobjects_body {
let x = split
.next()
.next_field("x pos")
.map(|s| f32::parse_in_custom_range(s, MAX_COORDINATE_VALUE as f32))?
.and_then(|s| f32::parse_in_custom_range(s, MAX_COORDINATE_VALUE as f32))
.map(|x| x as i32 as f32);
let y = split
.next()
.next_field("y pos")
.map(|s| f32::parse_in_custom_range(s, MAX_COORDINATE_VALUE as f32))?
.and_then(|s| f32::parse_in_custom_range(s, MAX_COORDINATE_VALUE as f32))
.map(|x| x as i32 as f32);
let pos = if let (Some(x), Some(y)) = (x, y) {
@@ -444,13 +418,7 @@ macro_rules! parse_hitobjects_body {
continue 'next_line;
};
let time_opt = split
.next()
.next_field("hitobject time")
.map(str::trim)
.map(f64::parse_in_range)?;
let time = match time_opt {
let time = match split.next().map(str::trim).and_then(f64::parse_in_range) {
Some(time) => time,
None => continue 'next_line,
};
@@ -459,64 +427,47 @@ macro_rules! parse_hitobjects_body {
unsorted = true;
}
let kind: u8 = match split.next().next_field("hitobject kind")?.parse() {
Ok(kind) => kind,
Err(_) => continue 'next_line,
let kind = match split.next().map(str::parse::<u8>) {
Some(Ok(kind)) => kind,
_ => continue 'next_line,
};
let mut sound: u8 = match split.next().next_field("sound")?.parse() {
Ok(sound) => sound,
Err(_) => continue 'next_line,
let mut sound = match split.next().map(str::parse::<u8>) {
Some(Ok(sound)) => sound,
_ => continue 'next_line,
};
#[derive(Debug)]
enum Status {
Ok(bool),
Skip,
Err(ParseError),
}
fn has_custom_sound_file(bank_info: Option<&str>) -> Status {
fn has_custom_sound_file(bank_info: Option<&str>) -> Option<bool> {
let mut split = match bank_info {
Some(s) if !s.is_empty() => s.split(':'),
_ => return Status::Ok(false),
_ => return Some(false),
};
split.next().and_then(i32::parse_in_range)?;
split.next().and_then(i32::parse_in_range)?;
match split.next().map(i32::parse_in_range) {
Some(Some(_)) => {}
Some(None) => return Status::Skip,
None => return Status::Err(ParseError::MissingField("normal set")),
None => return Some(false),
Some(None) => return None,
}
match split.next().map(i32::parse_in_range) {
Some(Some(_)) => {}
Some(None) => return Status::Skip,
None => return Status::Err(ParseError::MissingField("additional set")),
}
match split.next().map(i32::parse_in_range) {
Some(Some(_)) => {}
None => return Status::Ok(false),
Some(None) => return Status::Skip,
}
match split.next().map(i32::parse_in_range) {
Some(Some(_)) => {}
None => return Status::Ok(false),
Some(None) => return Status::Skip,
None => return Some(false),
Some(None) => return None,
}
let filename = split.next().filter(|filename| !filename.is_empty());
Status::Ok(filename.is_some())
Some(filename.is_some())
}
let kind = if kind & Self::CIRCLE_FLAG > 0 {
match has_custom_sound_file(split.next()) {
Status::Ok(false) => {}
Status::Ok(true) => sound = 0,
Status::Skip => continue 'next_line,
Status::Err(err) => return Err(err),
Some(false) => {}
Some(true) => sound = 0,
None => continue 'next_line,
}
$self.n_circles += 1;
@@ -528,13 +479,16 @@ macro_rules! parse_hitobjects_body {
// Control Points: [1, 94872] | Median=3 | Mean=2.9984
let mut control_points = Vec::with_capacity(3);
let control_point_iter = split.next().next_field("control points")?.split('|');
let control_point_iter = match split.next() {
Some(s) => s.split('|'),
None => continue 'next_line,
};
let repeats = match split.next().next_field("repeats")?.parse::<usize>() {
let repeats = match split.next().map(str::parse::<usize>) {
// * osu-stable treated the first span of the slider
// * as a repeat, but no repeats are happening
Ok(repeats @ 0..=9000) => repeats.saturating_sub(1),
Ok(_) | Err(_) => continue 'next_line,
Some(Ok(repeats @ 0..=9000)) => repeats.saturating_sub(1),
_ => continue 'next_line,
};
let mut start_idx = 0;
@@ -622,10 +576,9 @@ macro_rules! parse_hitobjects_body {
// Note: Edge sets are currently not considered, seems to be fine though.
match has_custom_sound_file(split.nth(1)) {
Status::Ok(false) => {}
Status::Ok(true) => sound = 0,
Status::Skip => continue 'next_line,
Status::Err(err) => return Err(err),
Some(false) => {}
Some(true) => sound = 0,
None => continue 'next_line,
}
HitObjectKind::Slider {
@@ -638,16 +591,15 @@ macro_rules! parse_hitobjects_body {
} else if kind & Self::SPINNER_FLAG > 0 {
$self.n_spinners += 1;
let end_time = match split.next().next_field("spinner endtime")?.parse::<f64>() {
Ok(end_time) => end_time.max(time),
Err(_) => continue 'next_line,
let end_time = match split.next().map(str::parse::<f64>) {
Some(Ok(end_time)) => end_time.max(time),
_ => continue 'next_line,
};
match has_custom_sound_file(split.next()) {
Status::Ok(false) => {}
Status::Ok(true) => sound = 0,
Status::Skip => continue 'next_line,
Status::Err(err) => return Err(err),
Some(false) => {}
Some(true) => sound = 0,
None => continue 'next_line,
}
HitObjectKind::Spinner { end_time }
@@ -662,10 +614,9 @@ macro_rules! parse_hitobjects_body {
};
match has_custom_sound_file(Some(tail)) {
Status::Ok(false) => {}
Status::Ok(true) => sound = 0,
Status::Skip => continue 'next_line,
Status::Err(err) => return Err(err),
Some(false) => {}
Some(true) => sound = 0,
None => continue 'next_line,
}
parsed