rosu_map/section/colors/
decode.rs1use std::{num::ParseIntError, str::FromStr};
2
3use crate::{
4 decode::{DecodeBeatmap, DecodeState},
5 section::UnknownKeyError,
6 util::{KeyValue, ParseNumberError, StrExt},
7 Beatmap,
8};
9
10use super::{Color, CustomColor};
11
12#[derive(Clone, Debug, Default, PartialEq, Eq)]
14pub struct Colors {
15 pub custom_combo_colors: Vec<Color>,
16 pub custom_colors: Vec<CustomColor>,
17}
18
19impl From<Colors> for Beatmap {
20 fn from(colors: Colors) -> Self {
21 Self {
22 custom_combo_colors: colors.custom_combo_colors,
23 custom_colors: colors.custom_colors,
24 ..Self::default()
25 }
26 }
27}
28
29impl Colors {
30 pub const DEFAULT_COMBO_COLORS: [Color; 4] = [
31 Color([255, 192, 0, 255]),
32 Color([0, 202, 0, 255]),
33 Color([18, 124, 255, 255]),
34 Color([242, 24, 57, 255]),
35 ];
36}
37
38#[derive(Clone, Debug, PartialEq, Eq)]
40pub enum ColorsKey {
41 Combo,
42 Name(String),
43}
44
45impl FromStr for ColorsKey {
46 type Err = UnknownKeyError;
47
48 fn from_str(s: &str) -> Result<Self, Self::Err> {
49 if s.starts_with("Combo") {
50 Ok(Self::Combo)
51 } else {
52 Ok(Self::Name(s.to_owned()))
53 }
54 }
55}
56
57thiserror! {
58 #[derive(Debug)]
60 pub enum ParseColorsError {
61 #[error("color specified in incorrect format (should be R,G,B or R,G,B,A)")]
62 IncorrectColor,
63 #[error("failed to parse number")]
64 Number(#[source] ParseNumberError),
65 }
66}
67
68impl From<ParseIntError> for ParseColorsError {
69 fn from(err: ParseIntError) -> Self {
70 Self::Number(ParseNumberError::InvalidInteger(err))
71 }
72}
73
74pub type ColorsState = Colors;
76
77impl DecodeState for ColorsState {
78 fn create(_version: i32) -> Self {
79 Self::default()
80 }
81}
82
83impl DecodeBeatmap for Colors {
84 type Error = ParseColorsError;
85 type State = ColorsState;
86
87 fn parse_general(_: &mut Self::State, _: &str) -> Result<(), Self::Error> {
88 Ok(())
89 }
90
91 fn parse_editor(_: &mut Self::State, _: &str) -> Result<(), Self::Error> {
92 Ok(())
93 }
94
95 fn parse_metadata(_: &mut Self::State, _: &str) -> Result<(), Self::Error> {
96 Ok(())
97 }
98
99 fn parse_difficulty(_: &mut Self::State, _: &str) -> Result<(), Self::Error> {
100 Ok(())
101 }
102
103 fn parse_events(_: &mut Self::State, _: &str) -> Result<(), Self::Error> {
104 Ok(())
105 }
106
107 fn parse_timing_points(_: &mut Self::State, _: &str) -> Result<(), Self::Error> {
108 Ok(())
109 }
110
111 fn parse_colors(state: &mut Self::State, line: &str) -> Result<(), Self::Error> {
112 let Ok(KeyValue { key, value }) = KeyValue::parse(line.trim_comment()) else {
113 return Ok(());
114 };
115
116 let color: Color = value.parse()?;
117
118 match key {
119 ColorsKey::Combo => state.custom_combo_colors.push(color),
120 ColorsKey::Name(name) => {
121 match state.custom_colors.iter_mut().find(|c| c.name == name) {
122 Some(old) => old.color = color,
123 None => state.custom_colors.push(CustomColor { name, color }),
124 }
125 }
126 }
127
128 Ok(())
129 }
130
131 fn parse_hit_objects(_: &mut Self::State, _: &str) -> Result<(), Self::Error> {
132 Ok(())
133 }
134
135 fn parse_variables(_: &mut Self::State, _: &str) -> Result<(), Self::Error> {
136 Ok(())
137 }
138
139 fn parse_catch_the_beat(_: &mut Self::State, _: &str) -> Result<(), Self::Error> {
140 Ok(())
141 }
142
143 fn parse_mania(_: &mut Self::State, _: &str) -> Result<(), Self::Error> {
144 Ok(())
145 }
146}