mnk_vmf/types/
versioninfo.rs1use chumsky::Parser as ChumskyParser;
2
3use crate::parser::{
4 close_block, key_value_numeric, open_block, InternalParser, Parser, TokenError, TokenSource,
5};
6
7#[derive(Clone, Debug)]
9pub struct VersionInfo {
10 pub editor_version: u32,
11 pub editor_build: u32,
12 pub map_version: u16,
13 pub format_version: u16,
14 pub prefab: u32,
15}
16
17impl VersionInfo {
18 pub fn new(
20 version: u32,
21 build: u32,
22 map_version: u16,
23 format_version: u16,
24 prefab: u32,
25 ) -> VersionInfo {
26 Self {
27 editor_version: version,
28 editor_build: build,
29 map_version,
30 format_version,
31 prefab,
32 }
33 }
34}
35
36impl Parser<'_> for VersionInfo {}
38
39impl<'src> InternalParser<'src> for VersionInfo {
54 fn parser<I>() -> impl ChumskyParser<'src, I, Self, TokenError<'src>>
55 where
56 I: TokenSource<'src>,
57 {
58 open_block("versioninfo")
59 .ignored()
60 .then(key_value_numeric::<u32, I>("editorversion"))
61 .then(key_value_numeric::<u32, I>("editorbuild"))
62 .then(key_value_numeric::<u16, I>("mapversion"))
63 .then(key_value_numeric::<u16, I>("formatversion"))
64 .then(key_value_numeric::<u32, I>("prefab"))
65 .map(|(((((_, vi), eb), mv), fv), pf)| VersionInfo::new(vi, eb, mv, fv, pf))
66 .then_ignore(close_block())
67 .boxed()
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use crate::util::lex;
74
75 use super::*;
76 use chumsky::Parser;
77
78 #[test]
79 fn test_version_info_parser() {
80 let input = lex(r#"versioninfo
82 {
83 "editorversion" "400"
84 "editorbuild" "6157"
85 "mapversion" "16"
86 "formatversion" "100"
87 "prefab" "0"
88 }"#);
89
90 let result = VersionInfo::parser().parse(input);
91 assert!(
92 !result.has_errors(),
93 "Parser failed with error: {:?}",
94 result.errors().collect::<Vec<_>>()
95 );
96
97 let version_info = result.unwrap();
98 assert_eq!(version_info.editor_version, 400);
99 assert_eq!(version_info.editor_build, 6157);
100 assert_eq!(version_info.map_version, 16);
101 assert_eq!(version_info.format_version, 100);
102 assert_eq!(version_info.prefab, 0);
103
104 let compact_input = lex(
106 r#"versioninfo{"editorversion""500""editorbuild""7000""mapversion""20""formatversion""110""prefab""1"}"#,
107 );
108 let compact_result = VersionInfo::parser().parse(compact_input);
109 assert!(
110 !compact_result.has_errors(),
111 "Compact parser failed with error: {:?}",
112 compact_result.errors().collect::<Vec<_>>()
113 );
114
115 let missing_field = lex(r#"versioninfo
117 {
118 "editorversion" "400"
119 "editorbuild" "6157"
120 "mapversion" "16"
121 "prefab" "0"
122 }"#); let missing_result = VersionInfo::parser().parse(missing_field);
125 assert!(
126 missing_result.has_errors(),
127 "Parser should fail on missing field"
128 );
129
130 let invalid_format = lex(r#"versioninfo
132 {
133 "editorversion" "400"
134 "editorbuild" "invalid"
135 "mapversion" "16"
136 "formatversion" "100"
137 "prefab" "0"
138 }"#);
139
140 let invalid_result = VersionInfo::parser().parse(invalid_format);
141 assert!(
142 invalid_result.has_errors(),
143 "Parser should fail on invalid number format"
144 );
145 }
146}