use super::Run;
use crate::types::TimeType;
use serde::Deserialize;
#[derive(Deserialize, Clone, Copy, Default)]
enum TimeTypeV1 {
Skipped(u128),
Time(u128),
#[default]
None,
}
impl TimeTypeV1 {
fn val(&self) -> u128 {
match self {
&Self::Skipped(t) => t,
&Self::Time(t) => t,
Self::None => 0,
}
}
}
impl From<TimeTypeV1> for TimeType {
fn from(tm: TimeTypeV1) -> TimeType {
if let TimeTypeV1::Time(t) = tm {
TimeType::Time(t as i128)
} else {
TimeType::None
}
}
}
#[derive(Deserialize, Clone, Copy, Default, PartialEq)]
enum TimeTypeV2 {
Time(i128),
Skipped,
#[default]
None,
}
impl TimeTypeV2 {
pub fn val(&self) -> i128 {
if let &TimeTypeV2::Time(t) = self {
t
} else {
0
}
}
}
impl From<TimeTypeV2> for TimeType {
fn from(tm: TimeTypeV2) -> TimeType {
if let TimeTypeV2::Time(t) = tm {
TimeType::Time(t)
} else {
TimeType::None
}
}
}
#[derive(Deserialize)]
pub struct RunV1 {
game_title: String,
category: String,
offset: Option<u128>,
splits: Vec<String>,
pb_times: Vec<u128>,
gold_times: Vec<u128>,
}
#[derive(Deserialize)]
pub struct RunV2 {
game_title: String,
category: String,
offset: TimeTypeV1,
splits: Vec<String>,
pb_times: Vec<TimeTypeV1>,
gold_times: Vec<TimeTypeV1>,
sum_times: Vec<(u128, TimeTypeV1)>,
}
#[derive(Deserialize)]
pub struct RunV3 {
game_title: String,
category: String,
ingame_time: bool,
offset: TimeTypeV2,
segment_names: Vec<String>,
pb_segments: Vec<TimeTypeV2>,
gold_segments: Vec<TimeTypeV2>,
sum_segments: Vec<(usize, TimeTypeV2)>,
}
#[derive(Deserialize)]
pub struct RunV4 {
game_title: String,
category: String,
ingame_time: bool,
offset: TimeTypeV2,
segment_names: Vec<String>,
rta_pb_segments: Vec<TimeTypeV2>,
igt_pb_segments: Vec<TimeTypeV2>,
rta_gold_segments: Vec<TimeTypeV2>,
igt_gold_segments: Vec<TimeTypeV2>,
rta_sum_segments: Vec<(usize, TimeTypeV2)>,
igt_sum_segments: Vec<(usize, TimeTypeV2)>,
}
impl From<RunV1> for Run {
fn from(old: RunV1) -> Run {
let mut r = Run::default();
r.game_title = old.game_title;
r.category = old.category;
r.offset = old
.offset
.map_or(TimeType::None, |t| TimeType::Time(-(t as i128)));
r.segment_names = old.splits;
r.rta_pb_splits = old
.pb_times
.iter()
.scan(TimeType::None, |acc, &time| {
if time != 0 {
*acc += (time as i128).into();
Some(*acc)
} else {
Some(TimeType::None)
}
})
.collect();
r.igt_pb_splits = r.rta_pb_splits.clone();
r.rta_gold_segments = old.gold_times.iter().map(|&t| (t as i128).into()).collect();
r.igt_gold_segments = r.rta_gold_segments.clone();
r.rta_sum_segments = vec![(0, TimeType::None); r.segment_names.len()];
r.igt_sum_segments = r.rta_sum_segments.clone();
r
}
}
impl From<RunV2> for Run {
fn from(old: RunV2) -> Run {
let pb_splits: Vec<_> = old
.pb_times
.iter()
.scan(0, |acc, time| match time {
TimeTypeV1::Skipped(t) => {
*acc += t;
Some(TimeType::None)
}
TimeTypeV1::Time(t) => {
*acc += t;
Some(TimeType::Time(*acc as i128))
}
TimeTypeV1::None => Some(TimeType::Time(*acc as i128)),
})
.collect();
let gold_segments: Vec<_> = old.gold_times.iter().map(|&gold| gold.into()).collect();
let sum_segments: Vec<_> = old
.sum_times
.iter()
.map(|&(n, t)| (n as usize, t.into()))
.collect();
Run {
game_title: old.game_title,
category: old.category,
offset: TimeType::from(-(old.offset.val() as i128)),
segment_names: old.splits,
rta_pb_splits: pb_splits.clone(),
igt_pb_splits: pb_splits,
rta_gold_segments: gold_segments.clone(),
igt_gold_segments: gold_segments,
rta_sum_segments: sum_segments.clone(),
igt_sum_segments: sum_segments,
..Default::default()
}
}
}
fn seg_to_split_v2((sum, has_gap): &mut (TimeType, bool), time: &TimeTypeV2) -> Option<TimeType> {
*sum += TimeType::from(time.val());
if *time == TimeTypeV2::None {
*has_gap = true;
}
if *has_gap || *time == TimeTypeV2::Skipped {
Some(TimeType::None)
} else {
Some(*sum)
}
}
impl From<RunV3> for Run {
fn from(old: RunV3) -> Run {
let mut r = Run {
game_title: old.game_title,
category: old.category,
ingame_time: old.ingame_time,
offset: old.offset.into(),
segment_names: old.segment_names,
..Default::default()
};
let pb_splits: Vec<_> = old
.pb_segments
.iter()
.scan((TimeType::None, false), seg_to_split_v2)
.collect();
r.rta_pb_splits = pb_splits.clone();
r.rta_gold_segments = old.gold_segments.iter().map(|&t| t.into()).collect();
r.rta_sum_segments = old
.sum_segments
.iter()
.map(|&(n, t)| (n, t.into()))
.collect();
if old.ingame_time {
r.igt_pb_splits = pb_splits;
r.igt_gold_segments = old.gold_segments.iter().map(|&t| t.into()).collect();
r.igt_sum_segments = old
.sum_segments
.iter()
.map(|&(n, t)| (n, t.into()))
.collect();
}
r
}
}
impl From<RunV4> for Run {
fn from(old: RunV4) -> Run {
let mut r = Run {
game_title: old.game_title,
category: old.category,
ingame_time: old.ingame_time,
offset: old.offset.into(),
segment_names: old.segment_names,
rta_gold_segments: old.rta_gold_segments.iter().map(|&t| t.into()).collect(),
igt_gold_segments: old.igt_gold_segments.iter().map(|&t| t.into()).collect(),
rta_sum_segments: old
.rta_sum_segments
.iter()
.map(|&(n, t)| (n, t.into()))
.collect(),
igt_sum_segments: old
.igt_sum_segments
.iter()
.map(|&(n, t)| (n, t.into()))
.collect(),
..Default::default()
};
let rta_pb_splits: Vec<_> = old
.rta_pb_segments
.iter()
.scan((TimeType::None, false), seg_to_split_v2)
.collect();
let igt_pb_splits: Vec<_> = old
.igt_pb_segments
.iter()
.scan((TimeType::None, false), seg_to_split_v2)
.collect();
r.rta_pb_splits = rta_pb_splits;
r.igt_pb_splits = igt_pb_splits;
r
}
}