osu_file_parser/osu_file/osb/
mod.rs1pub mod error;
2pub mod types;
3
4use nom::multi::many0;
5
6use crate::parsers::square_section;
7
8use super::{Error, Events, Version, VersionedFromStr, VersionedToString};
9
10pub use error::*;
11pub use types::*;
12
13#[derive(Clone, Debug, Hash, PartialEq, Eq)]
14pub struct Osb {
15 pub variables: Option<Vec<Variable>>,
16 pub events: Option<Events>,
17}
18
19impl VersionedFromStr for Osb {
20 type Err = Error<ParseError>;
21
22 fn from_str(s: &str, version: Version) -> std::result::Result<Option<Self>, Self::Err> {
23 if version < 14 {
24 return Ok(None);
25 }
26
27 let pre_section_count = s
28 .lines()
29 .take_while(|s| {
30 let s = s.trim();
31 !s.trim().starts_with('[') && !s.trim().ends_with(']')
32 })
33 .count();
34
35 for (i, line) in s.lines().take(pre_section_count).enumerate() {
36 let line = line.trim();
37
38 if line.is_empty() {
39 continue;
40 }
41
42 if line.starts_with("//") {
43 continue;
44 }
45
46 return Err(Error::new(ParseError::UnexpectedLine, i));
47 }
48
49 let s = s
50 .lines()
51 .skip(pre_section_count)
52 .collect::<Vec<_>>()
53 .join("\n");
54
55 let (_, sections) = many0(square_section())(&s).unwrap();
58
59 let mut section_parsed = Vec::with_capacity(2);
60 let mut line_number = pre_section_count;
61
62 let (mut events, mut variables) = (None, None);
63
64 for (ws, section_name, ws2, section) in sections {
65 line_number += ws.lines().count();
66
67 if section_parsed.contains(§ion_name) {
68 return Err(Error::new(ParseError::DuplicateSections, line_number));
69 }
70
71 let section_name_line = line_number;
72 line_number += ws2.lines().count();
73
74 match section_name {
75 "Variables" => {
76 let mut vars = Vec::new();
77 for (i, line) in section.lines().enumerate() {
78 if line.trim().is_empty() {
79 continue;
80 }
81
82 let variable = Error::new_from_result_into(
83 Variable::from_str(line, version).map(|v| v.unwrap()),
84 line_number + i,
85 )?;
86
87 vars.push(variable);
88 }
89 variables = Some(vars);
90 }
91 "Events" => {
92 events = Error::processing_line(
93 Events::from_str_variables(
94 section,
95 version,
96 variables.as_ref().unwrap_or(&Vec::new()),
97 ),
98 line_number,
99 )?;
100 }
101 _ => return Err(Error::new(ParseError::UnknownSection, section_name_line)),
102 }
103
104 section_parsed.push(section_name);
105 line_number += section.lines().count().saturating_sub(1);
106 }
107
108 Ok(Some(Osb { events, variables }))
109 }
110}
111
112impl VersionedToString for Osb {
113 fn to_string(&self, version: Version) -> Option<String> {
114 if version < 14 {
115 None
116 } else {
117 let mut sections = Vec::new();
118
119 if let Some(variables) = &self.variables {
120 sections.push(format!(
121 "[Variables]\n{}",
122 variables
123 .iter()
124 .map(|v| v.to_string(version).unwrap())
125 .collect::<Vec<_>>()
126 .join("\n"),
127 ));
128 }
129 if let Some(events) = &self.events {
130 sections.push(format!(
132 "[Events]\n{}",
133 events
134 .to_string_variables(
135 version,
136 self.variables.as_ref().unwrap_or(&Vec::new()),
137 )
138 .unwrap()
139 ))
140 }
141
142 Some(sections.join("\n\n"))
143 }
144 }
145}