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
//! Provides the parser for Splitty splits files.

use crate::{Run, Segment, Time, TimeSpan, TimingMethod};
use serde_json::de::from_reader;
use serde_json::Error as JsonError;
use std::io::Read;
use std::result::Result as StdResult;

quick_error! {
    /// The Error type for splits files that couldn't be parsed by the Splitty
    /// Parser.
    #[derive(Debug)]
    pub enum Error {
        /// Failed to parse JSON.
        Json(err: JsonError) {
            from()
        }
    }
}

/// The Result type for the Splitty Parser.
pub type Result<T> = StdResult<T, Error>;

#[derive(Deserialize)]
struct Splits {
    run_name: String,
    start_delay: f64,
    run_count: u32,
    splits: Vec<Split>,
    timer_type: u8,
}

#[derive(Deserialize)]
struct Split {
    name: String,
    pb_split: Option<f64>,
    split_best: Option<f64>,
}

fn parse_time(milliseconds: Option<f64>, method: TimingMethod) -> Time {
    let mut time = Time::new();

    if let Some(milliseconds) = milliseconds {
        time[method] = Some(TimeSpan::from_milliseconds(milliseconds));
    }

    time
}

/// Attempts to parse a Splitty splits file.
pub fn parse<R: Read>(source: R) -> Result<Run> {
    let splits: Splits = from_reader(source)?;

    let mut run = Run::new();

    run.set_game_name(splits.run_name);
    run.set_attempt_count(splits.run_count);
    run.set_offset(TimeSpan::from_milliseconds(-splits.start_delay));

    let method = if splits.timer_type == 0 {
        TimingMethod::RealTime
    } else {
        TimingMethod::GameTime
    };

    for split in splits.splits {
        let mut segment = Segment::new(split.name);
        segment.set_personal_best_split_time(parse_time(split.pb_split, method));
        segment.set_best_segment_time(parse_time(split.split_best, method));

        run.push_segment(segment);
    }

    Ok(run)
}