Skip to main content

cadvm_core/
format.rs

1//! Supported CAD file formats.
2
3use std::path::Path;
4
5use serde::{Deserialize, Serialize};
6
7/// CAD formats tracked by cadvm.
8///
9/// STEP/STP are B-Rep (boundary representation) formats and support the full
10/// geometric diff. STL/OBJ are triangle-mesh formats: they are versioned with
11/// lightweight metadata, and get a mesh-based (not B-Rep) geometric diff.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "lowercase")]
14pub enum CadFormat {
15    Step,
16    Stp,
17    Stl,
18    Obj,
19}
20
21impl CadFormat {
22    /// Detect the format from a path's extension, if it is a tracked format.
23    pub fn from_path(path: &Path) -> Option<CadFormat> {
24        let ext = path.extension()?.to_str()?.to_ascii_lowercase();
25        match ext.as_str() {
26            "step" => Some(CadFormat::Step),
27            "stp" => Some(CadFormat::Stp),
28            "stl" => Some(CadFormat::Stl),
29            "obj" => Some(CadFormat::Obj),
30            _ => None,
31        }
32    }
33
34    /// Lowercase extension (without the dot) for this format.
35    pub fn extension(self) -> &'static str {
36        match self {
37            CadFormat::Step => "step",
38            CadFormat::Stp => "stp",
39            CadFormat::Stl => "stl",
40            CadFormat::Obj => "obj",
41        }
42    }
43
44    /// Whether this is a B-Rep format (STEP/STP) — full geometric diff applies.
45    pub fn is_brep(self) -> bool {
46        matches!(self, CadFormat::Step | CadFormat::Stp)
47    }
48
49    /// Whether this is a triangle-mesh format (STL/OBJ).
50    pub fn is_mesh(self) -> bool {
51        matches!(self, CadFormat::Stl | CadFormat::Obj)
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58    use std::path::PathBuf;
59
60    #[test]
61    fn detects_tracked_formats_case_insensitively() {
62        assert_eq!(
63            CadFormat::from_path(&PathBuf::from("a.step")),
64            Some(CadFormat::Step)
65        );
66        assert_eq!(
67            CadFormat::from_path(&PathBuf::from("a.STP")),
68            Some(CadFormat::Stp)
69        );
70        assert_eq!(
71            CadFormat::from_path(&PathBuf::from("m.STL")),
72            Some(CadFormat::Stl)
73        );
74        assert_eq!(
75            CadFormat::from_path(&PathBuf::from("m.obj")),
76            Some(CadFormat::Obj)
77        );
78        assert_eq!(CadFormat::from_path(&PathBuf::from("a.iges")), None);
79        assert_eq!(CadFormat::from_path(&PathBuf::from("noext")), None);
80    }
81
82    #[test]
83    fn brep_vs_mesh() {
84        assert!(CadFormat::Step.is_brep() && !CadFormat::Step.is_mesh());
85        assert!(CadFormat::Stl.is_mesh() && !CadFormat::Stl.is_brep());
86    }
87}