Skip to main content

dds_bridge/solver/
system_info.rs

1//! DDS library version, build, and threading metadata
2
3use dds_bridge_sys as sys;
4use semver::Version;
5
6use core::ffi::{CStr, c_char};
7use core::fmt;
8
9/// OS platform reported by the DDS library
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum Platform {
12    /// Microsoft Windows
13    Windows,
14    /// Cygwin (Windows POSIX layer)
15    Cygwin,
16    /// Linux
17    Linux,
18    /// Apple (macOS / iOS)
19    Apple,
20    /// Unknown or unrecognized platform
21    Unknown(i32),
22}
23
24/// C++ compiler used to build the DDS library
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26pub enum Compiler {
27    /// Microsoft Visual C++
28    MSVC,
29    /// MinGW
30    MinGW,
31    /// GNU g++
32    GCC,
33    /// Clang
34    Clang,
35    /// Unknown or unrecognized compiler
36    Unknown(i32),
37}
38
39/// Threading model used by the DDS library
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
41pub enum Threading {
42    /// No threading
43    None,
44    /// Windows native threads
45    Windows,
46    /// OpenMP
47    OpenMP,
48    /// Grand Central Dispatch (Apple)
49    GCD,
50    /// Boost.Thread
51    Boost,
52    /// C++ standard library threads (`std::thread`)
53    STL,
54    /// Intel Threading Building Blocks
55    TBB,
56    /// Unknown or experimental threading model
57    Unknown(i32),
58}
59
60/// Information about the DDS library and how it was built
61///
62/// Returned by [`Solver::system_info`](super::Solver::system_info).  Exposes
63/// the version, hardware configuration (cores, threads, pointer width), and
64/// compile-time choices (OS, compiler, threading model) that DDS was built
65/// with.
66#[derive(Debug, Clone, Copy)]
67pub struct SystemInfo(pub(super) sys::DDSInfo);
68
69impl SystemInfo {
70    /// DDS version
71    #[must_use]
72    pub const fn version(&self) -> Version {
73        #[allow(clippy::cast_sign_loss)]
74        Version::new(
75            self.0.major as u64,
76            self.0.minor as u64,
77            self.0.patch as u64,
78        )
79    }
80
81    /// OS platform DDS was built for
82    #[must_use]
83    pub const fn platform(&self) -> Platform {
84        match self.0.system {
85            1 => Platform::Windows,
86            2 => Platform::Cygwin,
87            3 => Platform::Linux,
88            4 => Platform::Apple,
89            n => Platform::Unknown(n),
90        }
91    }
92
93    /// Pointer size in bits (32 or 64)
94    #[must_use]
95    pub const fn num_bits(&self) -> u32 {
96        #[allow(clippy::cast_sign_loss)]
97        return self.0.numBits as u32;
98    }
99
100    /// C++ compiler DDS was built with
101    #[must_use]
102    pub const fn compiler(&self) -> Compiler {
103        match self.0.compiler {
104            1 => Compiler::MSVC,
105            2 => Compiler::MinGW,
106            3 => Compiler::GCC,
107            4 => Compiler::Clang,
108            n => Compiler::Unknown(n),
109        }
110    }
111
112    /// Threading model DDS was built with
113    ///
114    /// Currently, [`dds_bridge_sys`] only supports [`Threading::STL`] for
115    /// maximum compatibility, minimum code size, and competitive performance.
116    /// Other variants may be activated in the future for specialized use cases
117    /// or platforms.
118    #[must_use]
119    pub const fn threading(&self) -> Threading {
120        match self.0.threading {
121            0 => Threading::None,
122            1 => Threading::Windows,
123            2 => Threading::OpenMP,
124            3 => Threading::GCD,
125            4 => Threading::Boost,
126            5 => Threading::STL,
127            6 => Threading::TBB,
128            n => Threading::Unknown(n),
129        }
130    }
131
132    /// Number of CPU cores detected by DDS
133    #[must_use]
134    pub const fn num_cores(&self) -> usize {
135        #[allow(clippy::cast_sign_loss)]
136        return self.0.numCores as usize;
137    }
138
139    /// Number of threads configured in the DDS thread pool
140    #[must_use]
141    pub const fn num_threads(&self) -> usize {
142        #[allow(clippy::cast_sign_loss)]
143        return self.0.noOfThreads as usize;
144    }
145
146    /// Memory-size description for each thread slot
147    ///
148    /// A string such as `"0 S, 16 L"` where `L` denotes a large transposition
149    /// table and `S` a small one.
150    #[must_use]
151    pub const fn thread_sizes(&self) -> &str {
152        // SAFETY: [DDS fills `threadSizes` with a null-terminated ASCII string.](https://github.com/dds-bridge/dds/blob/d2bc4c2c703941664fc1d73e69caa5233cdeac18/src/System.cpp#L756)
153        unsafe { c_chars_to_str(&self.0.threadSizes) }
154    }
155
156    /// Human-readable summary of the full DDS system configuration
157    #[must_use]
158    pub const fn system_string(&self) -> &str {
159        // SAFETY: [DDS fills `systemString` with a null-terminated ASCII string.](https://github.com/dds-bridge/dds/blob/d2bc4c2c703941664fc1d73e69caa5233cdeac18/src/System.cpp#L773)
160        unsafe { c_chars_to_str(&self.0.systemString) }
161    }
162}
163
164const unsafe fn c_chars_to_str(bytes: &[c_char]) -> &str {
165    unsafe { core::str::from_utf8_unchecked(CStr::from_ptr(bytes.as_ptr()).to_bytes()) }
166}
167
168impl fmt::Display for SystemInfo {
169    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170        f.write_str(self.system_string())
171    }
172}