Skip to main content

openhawk_core/
platform.rs

1// Platform detection and subsystem configuration
2// Requirements: 18.1, 18.3, 18.4
3
4#[derive(Debug, Clone, PartialEq)]
5pub enum Os {
6    Windows,
7    MacOs,
8    Linux,
9    Other(String),
10}
11
12#[derive(Debug, Clone, PartialEq)]
13pub enum Arch {
14    X86_64,
15    Arm64,
16    Other(String),
17}
18
19#[derive(Debug, Clone, PartialEq)]
20pub enum IpcMechanism {
21    UnixDomainSocket,
22    NamedPipe,
23}
24
25#[derive(Debug, Clone, PartialEq)]
26pub enum SnapshotStrategy {
27    ApfsReflink,
28    BtrfsCow,
29    FileCopyFallback,
30}
31
32#[derive(Debug, Clone)]
33pub struct PlatformConfig {
34    pub os: Os,
35    pub arch: Arch,
36    pub ipc: IpcMechanism,
37    pub snapshot_strategy: SnapshotStrategy,
38    pub keychain_available: bool,
39}
40
41impl PlatformConfig {
42    pub fn detect() -> Self {
43        let os = detect_os();
44        let arch = detect_arch();
45        let ipc = detect_ipc(&os);
46        let snapshot_strategy = detect_snapshot_strategy(&os);
47        let keychain_available = detect_keychain(&os);
48        PlatformConfig { os, arch, ipc, snapshot_strategy, keychain_available }
49    }
50}
51
52fn detect_os() -> Os {
53    #[cfg(target_os = "macos")]
54    return Os::MacOs;
55    #[cfg(target_os = "windows")]
56    return Os::Windows;
57    #[cfg(target_os = "linux")]
58    return Os::Linux;
59    #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
60    return Os::Other(std::env::consts::OS.to_string());
61}
62
63fn detect_arch() -> Arch {
64    #[cfg(target_arch = "x86_64")]
65    return Arch::X86_64;
66    #[cfg(target_arch = "aarch64")]
67    return Arch::Arm64;
68    #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
69    return Arch::Other(std::env::consts::ARCH.to_string());
70}
71
72pub fn detect_ipc(os: &Os) -> IpcMechanism {
73    match os {
74        Os::Windows => IpcMechanism::NamedPipe,
75        _ => IpcMechanism::UnixDomainSocket,
76    }
77}
78
79pub fn detect_snapshot_strategy(os: &Os) -> SnapshotStrategy {
80    match os {
81        Os::MacOs => SnapshotStrategy::ApfsReflink,
82        Os::Linux => SnapshotStrategy::BtrfsCow,
83        _ => SnapshotStrategy::FileCopyFallback,
84    }
85}
86
87pub fn detect_keychain(os: &Os) -> bool {
88    matches!(os, Os::MacOs | Os::Windows)
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn test_detect_returns_current_os() {
97        let config = PlatformConfig::detect();
98        #[cfg(target_os = "macos")]
99        assert_eq!(config.os, Os::MacOs);
100        #[cfg(target_os = "windows")]
101        assert_eq!(config.os, Os::Windows);
102        #[cfg(target_os = "linux")]
103        assert_eq!(config.os, Os::Linux);
104    }
105
106    #[test]
107    fn test_detect_returns_current_arch() {
108        let config = PlatformConfig::detect();
109        #[cfg(target_arch = "x86_64")]
110        assert_eq!(config.arch, Arch::X86_64);
111        #[cfg(target_arch = "aarch64")]
112        assert_eq!(config.arch, Arch::Arm64);
113    }
114
115    #[test]
116    fn test_macos_subsystem_config() {
117        let config = PlatformConfig {
118            os: Os::MacOs,
119            arch: Arch::Arm64,
120            ipc: detect_ipc(&Os::MacOs),
121            snapshot_strategy: detect_snapshot_strategy(&Os::MacOs),
122            keychain_available: detect_keychain(&Os::MacOs),
123        };
124        assert_eq!(config.ipc, IpcMechanism::UnixDomainSocket);
125        assert_eq!(config.snapshot_strategy, SnapshotStrategy::ApfsReflink);
126        assert!(config.keychain_available);
127    }
128
129    #[test]
130    fn test_windows_subsystem_config() {
131        let config = PlatformConfig {
132            os: Os::Windows,
133            arch: Arch::X86_64,
134            ipc: detect_ipc(&Os::Windows),
135            snapshot_strategy: detect_snapshot_strategy(&Os::Windows),
136            keychain_available: detect_keychain(&Os::Windows),
137        };
138        assert_eq!(config.ipc, IpcMechanism::NamedPipe);
139        assert_eq!(config.snapshot_strategy, SnapshotStrategy::FileCopyFallback);
140        assert!(config.keychain_available);
141    }
142
143    #[test]
144    fn test_linux_subsystem_config() {
145        let config = PlatformConfig {
146            os: Os::Linux,
147            arch: Arch::X86_64,
148            ipc: detect_ipc(&Os::Linux),
149            snapshot_strategy: detect_snapshot_strategy(&Os::Linux),
150            keychain_available: detect_keychain(&Os::Linux),
151        };
152        assert_eq!(config.ipc, IpcMechanism::UnixDomainSocket);
153        assert_eq!(config.snapshot_strategy, SnapshotStrategy::BtrfsCow);
154        assert!(!config.keychain_available);
155    }
156
157    #[test]
158    fn test_other_os_subsystem_config() {
159        let other = Os::Other("freebsd".to_string());
160        assert_eq!(detect_ipc(&other), IpcMechanism::UnixDomainSocket);
161        assert_eq!(detect_snapshot_strategy(&other), SnapshotStrategy::FileCopyFallback);
162        assert!(!detect_keychain(&other));
163    }
164
165    #[test]
166    fn test_detected_ipc_matches_os() {
167        let config = PlatformConfig::detect();
168        #[cfg(target_os = "windows")]
169        assert_eq!(config.ipc, IpcMechanism::NamedPipe);
170        #[cfg(not(target_os = "windows"))]
171        assert_eq!(config.ipc, IpcMechanism::UnixDomainSocket);
172    }
173
174    #[test]
175    fn test_detected_snapshot_strategy_matches_os() {
176        let config = PlatformConfig::detect();
177        #[cfg(target_os = "macos")]
178        assert_eq!(config.snapshot_strategy, SnapshotStrategy::ApfsReflink);
179        #[cfg(target_os = "linux")]
180        assert_eq!(config.snapshot_strategy, SnapshotStrategy::BtrfsCow);
181        #[cfg(target_os = "windows")]
182        assert_eq!(config.snapshot_strategy, SnapshotStrategy::FileCopyFallback);
183    }
184
185    #[test]
186    fn test_detected_keychain_matches_os() {
187        let config = PlatformConfig::detect();
188        #[cfg(any(target_os = "macos", target_os = "windows"))]
189        assert!(config.keychain_available);
190        #[cfg(target_os = "linux")]
191        assert!(!config.keychain_available);
192    }
193}