dbc_rs/version/
version.rs1use crate::{
2 Parser,
3 error::{ParseError, ParseResult, lang},
4};
5
6#[derive(Debug, Clone, PartialEq, Eq, Hash)]
7pub struct Version<'a> {
8 version: &'a str,
9}
10
11impl<'a> Version<'a> {
12 pub(crate) fn new(version: &'a str) -> Self {
13 Self { version }
15 }
16
17 #[must_use = "parse result should be checked"]
18 pub(crate) fn parse<'b: 'a>(parser: &mut Parser<'b>) -> ParseResult<Self> {
19 use crate::VERSION;
20 if parser.expect(VERSION.as_bytes()).is_ok() {
23 parser
25 .skip_whitespace()?
26 .expect(b"\"")
27 .map_err(|_| ParseError::Expected("Expected opening quote after VERSION"))?;
28 } else {
29 if parser.is_at_start() && !parser.starts_with(VERSION.as_bytes()) {
33 return Err(ParseError::Expected("Expected 'VERSION' keyword"));
35 }
36 let _ = parser.skip_whitespace().ok(); parser
41 .expect(b"\"")
42 .map_err(|_| ParseError::Expected("Expected opening quote after VERSION"))?;
43 }
44
45 const MAX_VERSION_LENGTH: u16 = 255;
49 let version_bytes = parser.take_until_quote(false, MAX_VERSION_LENGTH)?;
50
51 let version_str = core::str::from_utf8(version_bytes)
53 .map_err(|_| ParseError::Version(lang::VERSION_INVALID))?;
54
55 Ok(Version::new(version_str))
57 }
58
59 pub fn as_str(&self) -> &'a str {
60 self.version
61 }
62
63 #[must_use]
64 #[cfg(feature = "alloc")]
65 pub fn to_dbc_string(&self) -> String {
66 use crate::VERSION;
67 if self.version.is_empty() {
68 format!("{} \"\"", VERSION)
69 } else {
70 format!("{} \"{}\"", VERSION, self.version)
71 }
72 }
73}
74
75impl<'a> core::fmt::Display for Version<'a> {
77 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
78 write!(f, "{}", self.version)
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::Version;
85 use crate::Parser;
86 use crate::error::ParseError;
87
88 #[test]
89 fn test_read_version() {
90 let line = b"VERSION \"1.0\"";
91 let mut parser = Parser::new(line).unwrap();
92 let version = Version::parse(&mut parser).unwrap();
93 #[cfg(feature = "alloc")]
94 assert_eq!(version.to_string(), "1.0");
95 #[cfg(not(feature = "alloc"))]
96 assert_eq!(version.as_str(), "1.0");
97 #[cfg(not(feature = "alloc"))]
98 assert_eq!(version.as_str(), "1.0");
99 }
100
101 #[test]
102 fn test_read_version_invalid() {
103 let line = b"VERSION 1.0";
104 let mut parser = Parser::new(line).unwrap();
105 let version = Version::parse(&mut parser).unwrap_err();
106 match version {
108 ParseError::Expected(_) => {
109 }
111 _ => panic!("Expected Expected error, got {:?}", version),
112 }
113 }
114
115 #[test]
116 fn test_version_parse_empty() {
117 let line = b"";
118 let result = Parser::new(line);
119 assert!(result.is_err());
120 match result.unwrap_err() {
121 ParseError::UnexpectedEof => {
122 }
124 _ => panic!("Expected UnexpectedEof"),
125 }
126 }
127
128 #[test]
129 fn test_version_parse_no_version_prefix() {
130 let line = b"\"1.0\"";
131 let mut parser = Parser::new(line).unwrap();
132 let result = Version::parse(&mut parser);
133 assert!(result.is_err());
134 match result.unwrap_err() {
135 ParseError::Expected(_) => {
136 }
138 _ => panic!("Expected Expected error"),
139 }
140 }
141
142 #[test]
143 fn test_version_parse_no_quotes() {
144 let line = b"VERSION 1.0";
145 let mut parser = Parser::new(line).unwrap();
146 let result = Version::parse(&mut parser);
147 assert!(result.is_err());
148 match result.unwrap_err() {
149 ParseError::Expected(_) => {
150 }
152 _ => panic!("Expected Expected error"),
153 }
154 }
155
156 #[test]
157 fn test_version_parse_major_only() {
158 let line = b"VERSION \"1\"";
159 let mut parser = Parser::new(line).unwrap();
160 let result = Version::parse(&mut parser);
161 assert!(result.is_ok());
162 let version = result.unwrap();
163 #[cfg(feature = "alloc")]
164 assert_eq!(version.to_string(), "1");
165 #[cfg(not(feature = "alloc"))]
166 assert_eq!(version.as_str(), "1");
167 }
168
169 #[test]
170 fn test_version_parse_full_version() {
171 let line = b"VERSION \"1.2.3\"";
172 let mut parser = Parser::new(line).unwrap();
173 let result = Version::parse(&mut parser);
174 assert!(result.is_ok());
175 let version = result.unwrap();
176 #[cfg(feature = "std")]
177 assert_eq!(version.to_string(), "1.2.3");
178 #[cfg(not(feature = "alloc"))]
179 assert_eq!(version.as_str(), "1.2.3");
180 }
181
182 #[test]
183 fn test_version_parse_with_whitespace() {
184 let line = b"VERSION \"1.0\"";
185 let mut parser = Parser::new(line).unwrap();
186 let result = Version::parse(&mut parser);
187 assert!(result.is_ok());
188 let version = result.unwrap();
189 #[cfg(feature = "std")]
190 assert_eq!(version.to_string(), "1.0");
191 #[cfg(not(feature = "alloc"))]
192 assert_eq!(version.as_str(), "1.0");
193 }
194
195 #[test]
196 fn test_version_parse_empty_quotes() {
197 let line = b"VERSION \"\"";
198 let mut parser = Parser::new(line).unwrap();
199 let version = Version::parse(&mut parser).unwrap();
200 #[cfg(feature = "std")]
201 assert_eq!(version.to_string(), "");
202 #[cfg(not(feature = "alloc"))]
203 assert_eq!(version.as_str(), "");
204 }
205
206 #[test]
207 fn test_version_parse_missing_closing_quote() {
208 let line = b"VERSION \"1.0";
209 let mut parser = Parser::new(line).unwrap();
210 let result = Version::parse(&mut parser);
211 assert!(result.is_err());
212 match result.unwrap_err() {
213 ParseError::UnexpectedEof => {
214 }
216 _ => panic!("Expected UnexpectedEof"),
217 }
218 }
219
220 #[test]
221 fn test_version_parse_missing_opening_quote() {
222 let line = b"VERSION 1.0\"";
223 let mut parser = Parser::new(line).unwrap();
224 let result = Version::parse(&mut parser);
225 assert!(result.is_err());
226 match result.unwrap_err() {
227 ParseError::Expected(_) => {
228 }
230 _ => panic!("Expected Expected error"),
231 }
232 }
233
234 #[test]
235 #[cfg(feature = "alloc")]
236 fn test_version_to_dbc_string() {
237 let line1 = b"VERSION \"1\"";
238 let mut parser1 = Parser::new(line1).unwrap();
239 let v1 = Version::parse(&mut parser1).unwrap();
240 assert_eq!(v1.to_dbc_string(), "VERSION \"1\"");
241
242 let line2 = b"VERSION \"1.0\"";
243 let mut parser2 = Parser::new(line2).unwrap();
244 let v2 = Version::parse(&mut parser2).unwrap();
245 assert_eq!(v2.to_dbc_string(), "VERSION \"1.0\"");
246
247 let line3 = b"VERSION \"2.3.4\"";
248 let mut parser3 = Parser::new(line3).unwrap();
249 let v3 = Version::parse(&mut parser3).unwrap();
250 assert_eq!(v3.to_dbc_string(), "VERSION \"2.3.4\"");
251 }
252
253 #[test]
254 #[cfg(feature = "alloc")]
255 fn test_version_empty_round_trip() {
256 let line = b"VERSION \"\"";
257 let mut parser = Parser::new(line).unwrap();
258 let version = Version::parse(&mut parser).unwrap();
259 assert_eq!(version.to_dbc_string(), "VERSION \"\"");
260 }
261
262 #[test]
263 fn test_version_with_special_chars() {
264 let line = b"VERSION \"1.0-beta\"";
265 let mut parser = Parser::new(line).unwrap();
266 let version = Version::parse(&mut parser).unwrap();
267 #[cfg(feature = "std")]
268 assert_eq!(version.to_string(), "1.0-beta");
269 #[cfg(not(feature = "alloc"))]
270 assert_eq!(version.as_str(), "1.0-beta");
271 }
272}