mnk_vmf/types/
visgroup.rs1use chumsky::{prelude::recursive, IterParser, Parser as ChumskyParser};
2
3use crate::{
4 parser::{
5 any_quoted_string, close_block, number, open_block, quoted_string, InternalParser,
6 TokenError, TokenSource,
7 },
8 types::Color,
9 Parser,
10};
11
12#[derive(Debug, Clone, PartialEq)]
15pub struct VisGroup<'a> {
16 name: &'a str,
18
19 visgroupid: u32,
21
22 color: Color,
24
25 children: Vec<VisGroup<'a>>,
27}
28
29impl<'a> VisGroup<'a> {
30 pub fn new(
32 name: &'a str,
33 visgroupid: u32,
34 color: Color,
35 children: Vec<VisGroup<'a>>,
36 ) -> VisGroup<'a> {
37 VisGroup {
38 name,
39 visgroupid,
40 color,
41 children,
42 }
43 }
44}
45
46#[derive(Debug, Clone, PartialEq)]
47pub struct VisGroups<'a>(Vec<VisGroup<'a>>);
48
49impl<'a> VisGroups<'a> {
50 pub fn new(visgroups: Vec<VisGroup<'a>>) -> VisGroups<'a> {
51 Self(visgroups)
52 }
53}
54
55impl<'src> Parser<'src> for VisGroups<'src> {}
57
58impl<'src> InternalParser<'src> for VisGroups<'src> {
87 fn parser<I>() -> impl ChumskyParser<'src, I, Self, TokenError<'src>>
88 where
89 I: TokenSource<'src>,
90 {
91 open_block("visgroups")
92 .ignore_then(VisGroup::parser::<I>().repeated().collect())
93 .then_ignore(close_block())
94 .map(VisGroups::new)
95 }
96}
97
98impl<'src> Parser<'src> for VisGroup<'src> {}
100
101impl<'src> InternalParser<'src> for VisGroup<'src> {
116 fn parser<I>() -> impl ChumskyParser<'src, I, Self, TokenError<'src>>
117 where
118 I: TokenSource<'src>,
119 {
120 recursive(|vis_group| {
121 open_block("visgroup")
122 .boxed()
123 .ignore_then(
124 quoted_string("name")
125 .boxed()
126 .ignore_then(any_quoted_string().boxed())
127 .then_ignore(quoted_string("visgroupid").boxed())
128 .then(number::<u32, I>().boxed())
129 .then(Color::parser::<I>().boxed())
130 .then(vis_group.repeated().collect().boxed()),
131 )
132 .then_ignore(close_block().boxed())
133 .map(|(((name, id), color), children)| VisGroup::new(name, id, color, children))
134 })
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use crate::{parser::util::lex, Parser};
142
143 #[test]
144 fn test_single_visgroup() {
145 let input = lex(r#"
146 visgroup {
147 "name" "Tree_1"
148 "visgroupid" "5"
149 "color" "65 45 0"
150 }
151 "#);
152
153 let parsed = VisGroup::parse(input).unwrap();
154 assert_eq!(parsed.name, "Tree_1");
155 assert_eq!(parsed.visgroupid, 5);
156 assert_eq!(parsed.color.r, 65);
157 assert_eq!(parsed.color.g, 45);
158 assert_eq!(parsed.color.b, 0);
159 assert!(parsed.children.is_empty());
160 }
161
162 #[test]
163 fn test_nested_visgroup() {
164 let input = lex(r#"
165 visgroup {
166 "name" "Parent"
167 "visgroupid" "1"
168 "color" "10 20 30"
169 visgroup {
170 "name" "Child"
171 "visgroupid" "2"
172 "color" "100 100 100"
173 }
174 }
175 "#);
176
177 let parsed = VisGroup::parse(input).unwrap();
178 assert_eq!(parsed.name, "Parent");
179 assert_eq!(parsed.children.len(), 1);
180 assert_eq!(parsed.children[0].name, "Child");
181 assert_eq!(parsed.children[0].color.r, 100);
182 }
183
184 #[test]
185 fn test_visgroups_block() {
186 let input = lex(r#"
187 visgroups {
188 visgroup {
189 "name" "One"
190 "visgroupid" "11"
191 "color" "11 22 33"
192 }
193 visgroup {
194 "name" "Two"
195 "visgroupid" "12"
196 "color" "44 55 66"
197 }
198 }
199 "#);
200
201 let parsed = VisGroups::parse(input).unwrap();
202 assert_eq!(parsed.0.len(), 2);
203 assert_eq!(parsed.0[0].name, "One");
204 assert_eq!(parsed.0[1].name, "Two");
205 }
206
207 #[test]
208 fn test_empty_visgroups() {
209 let input = lex(r#"
210 visgroups {
211 }
212 "#);
213
214 let parsed = VisGroups::parse(input).unwrap();
215 assert_eq!(parsed.0.len(), 0);
216 }
217}