chart_file_parser/
chart.rs

1use std::fmt::Display;
2
3use nom::{
4    bytes::complete::take_until,
5    character::complete::{multispace0, multispace1},
6    combinator::all_consuming,
7    multi::separated_list1,
8    IResult,
9};
10
11use crate::{events::Events, song::Song, sync_track::SyncTrack, track::Track};
12
13#[derive(Debug, PartialEq, Eq)]
14pub struct Chart<'a> {
15    song: Song<'a>,
16    synctrack: SyncTrack,
17    global_events: Events<'a>,
18    tracks: Vec<Track<'a>>,
19}
20
21impl<'a> Chart<'a> {
22    #[must_use]
23    pub(crate) fn new(
24        song: Song<'a>,
25        synctrack: SyncTrack,
26        global_events: Events<'a>,
27        tracks: Vec<Track<'a>>,
28    ) -> Self {
29        Self {
30            song,
31            synctrack,
32            global_events,
33            tracks,
34        }
35    }
36
37    /// Multiply all timestamps and durations by the given factor. If two events have a 1-tick difference, this difference is preserved.
38    pub fn multiply(&mut self, factor: u32) {
39        self.song.multiply(factor);
40        self.synctrack.multiply(factor);
41        self.global_events.multiply(factor);
42        for item in &mut self.tracks {
43            item.multiply(factor);
44        }
45    }
46
47    /// Parse the .chart
48    ///
49    /// # Errors
50    ///
51    /// This function will return an error if the given string does not
52    /// represent a valid .chart file.
53    pub fn parse(input: &str) -> IResult<&str, Chart> {
54        let (input, _) = take_until("[")(input)?;
55        let (input, song) = Song::parse(input)?;
56        let (input, _) = multispace0(input)?;
57        let (input, synctrack) = SyncTrack::parse(input)?;
58        let (input, _) = multispace0(input)?;
59        let (input, global_events) = Events::parse(input)?;
60        let (input, _) = multispace0(input)?;
61        let (input, tracks) = separated_list1(multispace1, Track::parse)(input)?;
62        let (input, _) = all_consuming(multispace0)(input)?;
63        Ok((input, Chart::new(song, synctrack, global_events, tracks)))
64    }
65}
66
67impl<'a> Display for Chart<'a> {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        write!(
70            f,
71            "{}\n{}\n{}\n{}",
72            self.song,
73            self.synctrack,
74            self.global_events,
75            self.tracks.iter().map(Track::to_string).collect::<String>()
76        )
77    }
78}