Skip to main content

vexil_store/
detect.rs

1/// Auto-detected file format.
2#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3pub enum FileFormat {
4    /// `.vxb` — binary data file
5    Vxb,
6    /// `.vxc` — binary compiled schema file
7    Vxc,
8    /// `.vxbp` — binary data pack file
9    Vxbp,
10    /// `.vxcp` — binary compiled schema pack file
11    Vxcp,
12    /// `.vx` with `namespace` keyword — Vexil schema source
13    VexilSchema,
14    /// `.vx` with `@schema` directive — Vexil data file
15    VxData,
16    /// Unknown format
17    Unknown,
18}
19
20/// Detect file format from the first bytes of a file.
21pub fn detect_format(data: &[u8]) -> FileFormat {
22    if data.len() >= 4 {
23        match &data[0..4] {
24            b"VXB\0" => return FileFormat::Vxb,
25            b"VXC\0" => return FileFormat::Vxc,
26            b"VXBP" => return FileFormat::Vxbp,
27            b"VXCP" => return FileFormat::Vxcp,
28            _ => {}
29        }
30    }
31
32    // Text detection: scan for first non-whitespace, non-comment token
33    if let Ok(text) = std::str::from_utf8(data) {
34        for line in text.lines() {
35            let trimmed = line.trim();
36            if trimmed.is_empty() || trimmed.starts_with('#') || trimmed.starts_with("//") {
37                continue;
38            }
39            if trimmed.starts_with("namespace") {
40                return FileFormat::VexilSchema;
41            }
42            if trimmed.starts_with("@schema") {
43                return FileFormat::VxData;
44            }
45            // First real token found, not a known marker
46            break;
47        }
48    }
49
50    FileFormat::Unknown
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn detect_vxb() {
59        assert_eq!(detect_format(b"VXB\0\x01\x00"), FileFormat::Vxb);
60    }
61
62    #[test]
63    fn detect_vxc() {
64        assert_eq!(detect_format(b"VXC\0\x01\x00"), FileFormat::Vxc);
65    }
66
67    #[test]
68    fn detect_vxbp() {
69        assert_eq!(detect_format(b"VXBP\x01\x00"), FileFormat::Vxbp);
70    }
71
72    #[test]
73    fn detect_vxcp() {
74        assert_eq!(detect_format(b"VXCP\x01\x00"), FileFormat::Vxcp);
75    }
76
77    #[test]
78    fn detect_vexil_schema() {
79        let text = b"namespace test.simple\nmessage Foo { x @0 : u32 }";
80        assert_eq!(detect_format(text), FileFormat::VexilSchema);
81    }
82
83    #[test]
84    fn detect_vx_data() {
85        let text = b"@schema \"test.simple\"\nFoo { x: 1 }";
86        assert_eq!(detect_format(text), FileFormat::VxData);
87    }
88
89    #[test]
90    fn detect_vexil_schema_with_comments() {
91        let text = b"// This is a schema\n# another comment\nnamespace foo.bar";
92        assert_eq!(detect_format(text), FileFormat::VexilSchema);
93    }
94
95    #[test]
96    fn detect_unknown() {
97        assert_eq!(detect_format(b"garbage"), FileFormat::Unknown);
98    }
99}