1use crate::error::ConfigError;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct ConfigEntry<'a> {
13 key: &'a str,
14 value: Option<&'a str>,
18}
19
20impl<'a> ConfigEntry<'a> {
21 pub fn new(key: &'a str, value: Option<&'a str>) -> Result<Self, ConfigError> {
31 Self::validate_key(key)?;
32 Ok(ConfigEntry { key, value })
33 }
34
35 pub fn flag(key: &'a str) -> Result<Self, ConfigError> {
44 Self::new(key, None)
45 }
46
47 pub fn with_value(key: &'a str, value: &'a str) -> Result<Self, ConfigError> {
57 Self::new(key, Some(value))
58 }
59
60 pub fn key(&self) -> &'a str {
65 self.key
66 }
67
68 pub fn value(&self) -> Option<&'a str> {
75 self.value
76 }
77
78 pub fn is_flag(&self) -> bool {
83 self.value.is_none()
84 }
85
86 pub fn from_str(s: &'a str) -> Result<Self, ConfigError> {
95 if s.is_empty() {
96 return Err(ConfigError::InvalidKey);
97 }
98
99 if s.as_bytes()[0] == b'=' {
100 return Err(ConfigError::KeyStartsWithEquals);
101 }
102
103 if let Some(eq_pos) = s.bytes().position(|b| b == b'=') {
105 let key = &s[..eq_pos];
106 let value = &s[eq_pos + 1..];
107 Self::validate_key(key)?;
108 Ok(ConfigEntry {
109 key,
110 value: Some(value),
111 })
112 } else {
113 Self::validate_key(s)?;
114 Ok(ConfigEntry { key: s, value: None })
115 }
116 }
117
118 fn validate_key(key: &str) -> Result<(), ConfigError> {
127 if key.is_empty() {
128 return Err(ConfigError::InvalidKey);
129 }
130
131 let mut has_non_whitespace = false;
132
133 for &byte in key.as_bytes() {
135 if byte < 0x20 || byte > 0x7E || byte == b'=' {
136 return Err(ConfigError::InvalidKey);
137 }
138 if byte != b' ' && byte != b'\t' {
139 has_non_whitespace = true;
140 }
141 }
142
143 if !has_non_whitespace {
144 return Err(ConfigError::InvalidKey);
145 }
146
147 Ok(())
148 }
149
150 pub fn write_to(&self, buf: &mut [u8]) -> Result<usize, ConfigError> {
159 let key_bytes = self.key.as_bytes();
160 let needed = match self.value {
161 None => key_bytes.len(),
162 Some(v) => key_bytes.len() + 1 + v.len(), };
164
165 if buf.len() < needed {
166 return Err(ConfigError::BufferTooSmall);
167 }
168
169 let mut pos = 0;
170 buf[pos..pos + key_bytes.len()].copy_from_slice(key_bytes);
171 pos += key_bytes.len();
172
173 if let Some(val) = self.value {
174 buf[pos] = b'=';
175 pos += 1;
176 let val_bytes = val.as_bytes();
177 buf[pos..pos + val_bytes.len()].copy_from_slice(val_bytes);
178 pos += val_bytes.len();
179 }
180
181 Ok(pos)
182 }
183
184 pub fn wire_size(&self) -> usize {
189 match self.value {
190 None => self.key.len(),
191 Some(v) => self.key.len() + 1 + v.len(),
192 }
193 }
194}
195
196pub struct ConfigEntryIter<'a> {
204 data: &'a [u8],
205 pos: usize,
206}
207
208impl<'a> ConfigEntryIter<'a> {
209 pub fn new(data: &'a [u8]) -> Self {
217 ConfigEntryIter { data, pos: 0 }
218 }
219}
220
221impl<'a> Iterator for ConfigEntryIter<'a> {
222 type Item = Result<ConfigEntry<'a>, ConfigError>;
223
224 fn next(&mut self) -> Option<Self::Item> {
225 if self.pos >= self.data.len() {
227 return Some(Err(ConfigError::UnexpectedEnd));
228 }
229
230 let length = self.data[self.pos] as usize;
231 self.pos += 1;
232
233 if length == 0 {
235 return None;
236 }
237
238 if self.pos + length > self.data.len() {
240 return Some(Err(ConfigError::LengthOverflow));
241 }
242
243 let string_bytes = &self.data[self.pos..self.pos + length];
245 let string = match core::str::from_utf8(string_bytes) {
246 Ok(s) => s,
247 Err(_) => return Some(Err(ConfigError::InvalidUtf8)),
248 };
249
250 self.pos += length;
251 Some(ConfigEntry::from_str(string))
252 }
253}
254
255pub struct ConfigurationOption;
270
271impl ConfigurationOption {
272 pub fn parse<'a>(data: &'a [u8]) -> ConfigEntryIter<'a> {
297 ConfigEntryIter::new(data)
298 }
299
300 pub fn serialize<'a, I>(entries: I, buf: &mut [u8]) -> Result<usize, ConfigError>
324 where
325 I: IntoIterator<Item = ConfigEntry<'a>>,
326 {
327 let mut pos = 0;
328
329 for entry in entries {
330 let entry_size = entry.wire_size();
331
332 if entry_size > 255 {
334 return Err(ConfigError::BufferTooSmall);
335 }
336
337 if pos + 1 + entry_size > buf.len() {
339 return Err(ConfigError::BufferTooSmall);
340 }
341
342 buf[pos] = entry_size as u8;
344 pos += 1;
345
346 let written = entry.write_to(&mut buf[pos..])?;
348 pos += written;
349 }
350
351 if pos >= buf.len() {
353 return Err(ConfigError::BufferTooSmall);
354 }
355 buf[pos] = 0x00;
356 pos += 1;
357
358 Ok(pos)
359 }
360
361 pub fn wire_size<'a, I>(entries: I) -> usize
363 where
364 I: IntoIterator<Item = ConfigEntry<'a>>,
365 {
366 let mut size = 1; for entry in entries {
368 size += 1; size += entry.wire_size();
370 }
371 size
372 }
373}
374
375#[cfg(test)]
376mod tests {
377 use super::*;
378
379 #[test]
380 fn test_config_entry_flag() {
381 let entry = ConfigEntry::flag("debug").unwrap();
382 assert_eq!(entry.key(), "debug");
383 assert_eq!(entry.value(), None);
384 assert!(entry.is_flag());
385 assert_eq!(entry.wire_size(), 5);
386 }
387
388 #[test]
389 fn test_config_entry_with_value() {
390 let entry = ConfigEntry::with_value("key", "value").unwrap();
391 assert_eq!(entry.key(), "key");
392 assert_eq!(entry.value(), Some("value"));
393 assert!(!entry.is_flag());
394 assert_eq!(entry.wire_size(), 9); }
396
397 #[test]
398 fn test_config_entry_empty_value() {
399 let entry = ConfigEntry::with_value("timeout", "").unwrap();
400 assert_eq!(entry.key(), "timeout");
401 assert_eq!(entry.value(), Some(""));
402 assert!(!entry.is_flag());
403 }
404
405 #[test]
406 fn test_config_entry_from_str() {
407 let entry = ConfigEntry::from_str("multicast=true").unwrap();
408 assert_eq!(entry.key(), "multicast");
409 assert_eq!(entry.value(), Some("true"));
410
411 let entry = ConfigEntry::from_str("priority").unwrap();
412 assert_eq!(entry.key(), "priority");
413 assert_eq!(entry.value(), None);
414
415 let entry = ConfigEntry::from_str("timeout=").unwrap();
416 assert_eq!(entry.key(), "timeout");
417 assert_eq!(entry.value(), Some(""));
418 }
419
420 #[test]
421 fn test_config_entry_validation() {
422 assert_eq!(ConfigEntry::flag(""), Err(ConfigError::InvalidKey));
424
425 assert_eq!(ConfigEntry::flag(" "), Err(ConfigError::InvalidKey));
427
428 assert_eq!(
430 ConfigEntry::from_str("=invalid"),
431 Err(ConfigError::KeyStartsWithEquals)
432 );
433
434 assert_eq!(ConfigEntry::flag("key="), Err(ConfigError::InvalidKey));
436
437 assert_eq!(ConfigEntry::flag("key\x01"), Err(ConfigError::InvalidKey));
439 assert_eq!(ConfigEntry::flag("key\x7F"), Err(ConfigError::InvalidKey));
440
441 assert!(ConfigEntry::flag("valid").is_ok());
443 assert!(ConfigEntry::flag("valid-key_123").is_ok());
444 assert!(ConfigEntry::flag("a b c").is_ok());
445 }
446
447 #[test]
448 fn test_config_serialize_deserialize() {
449 let entries = [
451 ConfigEntry::with_value("multicast", "true").unwrap(),
452 ConfigEntry::flag("priority").unwrap(),
453 ConfigEntry::with_value("timeout", "").unwrap(),
454 ConfigEntry::flag("debug").unwrap(),
455 ];
456
457 let mut buf = [0u8; 256];
459 let size = ConfigurationOption::serialize(entries.iter().copied(), &mut buf).unwrap();
460
461 let expected = [
463 0x0E, b'm', b'u', b'l', b't', b'i', b'c', b'a', b's', b't', b'=', b't', b'r', b'u', b'e',
464 0x08, b'p', b'r', b'i', b'o', b'r', b'i', b't', b'y',
465 0x08, b't', b'i', b'm', b'e', b'o', b'u', b't', b'=',
466 0x05, b'd', b'e', b'b', b'u', b'g',
467 0x00,
468 ];
469
470 assert_eq!(&buf[..size], &expected);
471
472 let parsed: Vec<_> = ConfigurationOption::parse(&buf[..size])
474 .collect::<Result<Vec<_>, _>>()
475 .unwrap();
476
477 assert_eq!(parsed.len(), 4);
478 assert_eq!(parsed[0].key(), "multicast");
479 assert_eq!(parsed[0].value(), Some("true"));
480 assert_eq!(parsed[1].key(), "priority");
481 assert_eq!(parsed[1].value(), None);
482 assert_eq!(parsed[2].key(), "timeout");
483 assert_eq!(parsed[2].value(), Some(""));
484 assert_eq!(parsed[3].key(), "debug");
485 assert_eq!(parsed[3].value(), None);
486 }
487
488 #[test]
489 fn test_config_wire_size() {
490 let entries = [
491 ConfigEntry::with_value("a", "b").unwrap(),
492 ConfigEntry::flag("c").unwrap(),
493 ];
494
495 let size = ConfigurationOption::wire_size(entries.iter().copied());
496 assert_eq!(size, 7);
498
499 let mut buf = [0u8; 256];
500 let written = ConfigurationOption::serialize(entries.iter().copied(), &mut buf).unwrap();
501 assert_eq!(written, size);
502 }
503
504 #[test]
505 fn test_config_parse_errors() {
506 let data = [0x03, b'k', b'e', b'y'];
508 let mut iter = ConfigurationOption::parse(&data);
509 assert_eq!(iter.next(), Some(Ok(ConfigEntry::flag("key").unwrap())));
510 assert_eq!(iter.next(), Some(Err(ConfigError::UnexpectedEnd)));
511
512 let data = [0x0A, b'k', b'e', b'y'];
514 let mut iter = ConfigurationOption::parse(&data);
515 assert_eq!(iter.next(), Some(Err(ConfigError::LengthOverflow)));
516
517 let data = [0x03, 0xFF, 0xFE, 0xFD, 0x00];
519 let mut iter = ConfigurationOption::parse(&data);
520 assert_eq!(iter.next(), Some(Err(ConfigError::InvalidUtf8)));
521 }
522
523 #[test]
524 fn test_config_buffer_too_small() {
525 let entries = [ConfigEntry::with_value("key", "value").unwrap()];
526 let mut buf = [0u8; 5]; assert_eq!(
528 ConfigurationOption::serialize(entries.iter().copied(), &mut buf),
529 Err(ConfigError::BufferTooSmall)
530 );
531 }
532
533 #[test]
534 fn test_config_empty() {
535 let entries: [ConfigEntry; 0] = [];
536 let mut buf = [0u8; 256];
537 let size = ConfigurationOption::serialize(entries.iter().copied(), &mut buf).unwrap();
538 assert_eq!(size, 1); assert_eq!(buf[0], 0x00);
540
541 let parsed: Vec<_> = ConfigurationOption::parse(&buf[..size])
542 .collect::<Result<Vec<_>, _>>()
543 .unwrap();
544 assert_eq!(parsed.len(), 0);
545 }
546
547 #[test]
548 fn test_config_duplicate_keys() {
549 let entries = [
550 ConfigEntry::with_value("key", "value1").unwrap(),
551 ConfigEntry::with_value("key", "value2").unwrap(),
552 ConfigEntry::flag("key").unwrap(),
553 ];
554
555 let mut buf = [0u8; 256];
556 let size = ConfigurationOption::serialize(entries.iter().copied(), &mut buf).unwrap();
557
558 let parsed: Vec<_> = ConfigurationOption::parse(&buf[..size])
559 .collect::<Result<Vec<_>, _>>()
560 .unwrap();
561
562 assert_eq!(parsed.len(), 3);
563 assert_eq!(parsed[0].key(), "key");
564 assert_eq!(parsed[0].value(), Some("value1"));
565 assert_eq!(parsed[1].key(), "key");
566 assert_eq!(parsed[1].value(), Some("value2"));
567 assert_eq!(parsed[2].key(), "key");
568 assert_eq!(parsed[2].value(), None);
569 }
570}