livesplit_core/run/parser/
splitty.rs1use crate::{platform::prelude::*, Run, Segment, Time, TimeSpan, TimingMethod};
4use alloc::borrow::Cow;
5use core::result::Result as StdResult;
6use serde::Deserialize;
7use serde_json::Error as JsonError;
8
9#[derive(Debug, snafu::Snafu)]
12#[snafu(context(suffix(false)))]
13pub enum Error {
14 Json {
16 #[cfg_attr(not(feature = "std"), snafu(source(false)))]
18 source: JsonError,
19 },
20}
21
22pub type Result<T> = StdResult<T, Error>;
24
25#[derive(Deserialize)]
26struct Splits<'a> {
27 #[serde(borrow)]
28 run_name: Cow<'a, str>,
29 start_delay: f64,
30 run_count: u32,
31 splits: Vec<Split<'a>>,
32 timer_type: u8,
33}
34
35#[derive(Deserialize)]
36struct Split<'a> {
37 #[serde(borrow)]
38 name: Cow<'a, str>,
39 pb_split: Option<f64>,
40 split_best: Option<f64>,
41}
42
43fn parse_time(milliseconds: Option<f64>, method: TimingMethod) -> Time {
44 let mut time = Time::new();
45
46 if let Some(milliseconds) = milliseconds {
47 time[method] = Some(TimeSpan::from_milliseconds(milliseconds));
48 }
49
50 time
51}
52
53pub fn parse(source: &str) -> Result<Run> {
55 let splits: Splits<'_> =
56 serde_json::from_str(source).map_err(|source| Error::Json { source })?;
57
58 let mut run = Run::new();
59
60 run.set_game_name(splits.run_name);
61 run.set_attempt_count(splits.run_count);
62 run.set_offset(TimeSpan::from_milliseconds(-splits.start_delay));
63
64 let method = if splits.timer_type == 0 {
65 TimingMethod::RealTime
66 } else {
67 TimingMethod::GameTime
68 };
69
70 run.segments_mut()
71 .extend(splits.splits.into_iter().map(|split| {
72 let mut segment = Segment::new(split.name);
73 segment.set_personal_best_split_time(parse_time(split.pb_split, method));
74 segment.set_best_segment_time(parse_time(split.split_best, method));
75
76 segment
77 }));
78
79 Ok(run)
80}