use crate::codec::Decoder;
use crate::error::RoxResult;
use crate::model::{Metadata, Note, RoxChart, TimingPoint};
use super::parser;
use super::types::QuaChart;
pub struct QuaDecoder;
impl QuaDecoder {
#[must_use]
pub fn from_qua(qua: &QuaChart) -> RoxChart {
let key_count = qua.mode.key_count();
let mut chart = RoxChart::new(key_count);
chart.metadata = Metadata {
title: qua.title.clone(),
artist: qua.artist.clone(),
creator: qua.creator.clone(),
difficulty_name: qua.difficulty_name.clone(),
audio_file: qua.audio_file.clone(),
background_file: qua.background_file.clone(),
preview_time_us: i64::from(qua.preview_time) * 1000,
source: qua.source.clone(),
tags: qua
.tags
.as_ref()
.map(|t| t.split(',').map(|s| s.trim().to_string()).collect())
.unwrap_or_default(),
..Default::default()
};
for tp in &qua.timing_points {
#[allow(clippy::cast_possible_truncation)]
let time_us = (tp.start_time * 1000.0) as i64;
let mut timing = TimingPoint::bpm(time_us, tp.bpm);
timing.signature = tp
.signature
.as_ref()
.map_or(4, super::types::TimeSignature::beats);
chart.timing_points.push(timing);
}
for sv in &qua.slider_velocities {
#[allow(clippy::cast_possible_truncation)]
let time_us = (sv.start_time * 1000.0) as i64;
#[allow(clippy::cast_possible_truncation)]
let multiplier = sv.multiplier as f32;
chart
.timing_points
.push(TimingPoint::sv(time_us, multiplier));
}
chart.timing_points.sort_by_key(|tp| tp.time_us);
for ho in &qua.hit_objects {
#[allow(clippy::cast_possible_truncation)]
let time_us = (ho.start_time * 1000.0) as i64;
let column = ho.lane.saturating_sub(1);
let note = if let Some(end_time) = ho.end_time {
#[allow(clippy::cast_possible_truncation)]
let end_us = (end_time * 1000.0) as i64;
let duration_us = end_us - time_us;
Note::hold(time_us, duration_us, column)
} else {
Note::tap(time_us, column)
};
chart.notes.push(note);
}
chart.notes.sort_by_key(|n| n.time_us);
chart
}
}
impl Decoder for QuaDecoder {
fn decode(data: &[u8]) -> RoxResult<RoxChart> {
let qua = parser::parse(data)?;
Ok(Self::from_qua(&qua))
}
}