dbc_rs/
parse_options.rs

1/// Options for configuring DBC parsing behavior.
2///
3/// # Examples
4///
5/// ```rust,no_run
6/// use dbc_rs::{Dbc, ParseOptions};
7///
8/// let dbc_content = r#"VERSION "1.0"
9///
10/// BU_: ECM
11///
12/// BO_ 256 Test : 8 ECM
13///  SG_ Signal1 : 0|8@1+ (1,0) [0|255] ""
14/// "#;
15///
16/// // Use lenient mode to allow signals that extend beyond message boundaries
17/// let options = ParseOptions::lenient();
18/// let dbc = Dbc::parse_with_options(dbc_content, options)?;
19/// # Ok::<(), dbc_rs::Error>(())
20/// ```
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct ParseOptions {
23    /// If `true`, signals that extend beyond message boundaries will cause a parse error.
24    /// If `false`, such signals will be allowed (lenient mode).
25    ///
26    /// Default: `true` (strict mode)
27    ///
28    /// # Note
29    ///
30    /// Many real-world DBC files have signals that technically extend beyond message
31    /// boundaries but are still valid in practice. Setting this to `false` allows
32    /// parsing such files.
33    pub strict_boundary_check: bool,
34}
35
36impl Default for ParseOptions {
37    fn default() -> Self {
38        Self {
39            strict_boundary_check: true,
40        }
41    }
42}
43
44impl ParseOptions {
45    /// Creates a new `ParseOptions` with default settings (strict mode).
46    #[must_use]
47    pub const fn new() -> Self {
48        Self {
49            strict_boundary_check: true,
50        }
51    }
52
53    /// Creates a new `ParseOptions` with lenient boundary checking enabled.
54    ///
55    /// This allows signals that extend beyond message boundaries, which is useful
56    /// for parsing real-world DBC files that may have technically invalid but
57    /// commonly used signal definitions.
58    #[must_use]
59    pub const fn lenient() -> Self {
60        Self {
61            strict_boundary_check: false,
62        }
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::ParseOptions;
69
70    // Tests that work in all configurations
71    #[test]
72    fn test_parse_options_default() {
73        let options = ParseOptions::default();
74        assert!(options.strict_boundary_check);
75    }
76
77    #[test]
78    fn test_parse_options_new() {
79        let options = ParseOptions::new();
80        assert!(options.strict_boundary_check);
81    }
82
83    #[test]
84    fn test_parse_options_lenient() {
85        let options = ParseOptions::lenient();
86        assert!(!options.strict_boundary_check);
87    }
88
89    #[test]
90    fn test_parse_options_equality() {
91        let default1 = ParseOptions::default();
92        let default2 = ParseOptions::new();
93        assert_eq!(default1, default2);
94
95        let lenient1 = ParseOptions::lenient();
96        let lenient2 = ParseOptions::lenient();
97        assert_eq!(lenient1, lenient2);
98
99        assert_ne!(default1, lenient1);
100    }
101
102    #[test]
103    fn test_parse_options_clone() {
104        let original = ParseOptions::lenient();
105        let cloned = original;
106        assert_eq!(original, cloned);
107        assert!(!cloned.strict_boundary_check);
108    }
109
110    #[test]
111    fn test_parse_options_copy() {
112        let options = ParseOptions::new();
113        let copied = options; // Copy, not move
114        assert_eq!(options, copied); // Original still valid
115        assert!(options.strict_boundary_check);
116    }
117
118    // Tests that require alloc or kernel (for format! macro)
119    #[cfg(any(feature = "alloc", feature = "kernel"))]
120    mod tests_with_format {
121        use super::*;
122        #[cfg(any(feature = "alloc", feature = "kernel"))]
123        use alloc::format;
124
125        #[test]
126        fn test_parse_options_debug() {
127            let options = ParseOptions::default();
128            let debug_str = format!("{:?}", options);
129            assert!(debug_str.contains("ParseOptions"));
130        }
131    }
132}