Skip to main content

darwin_kperf/framework/
error.rs

1//! Error types for `kperfdata.framework` operations.
2
3use core::{error, ffi::c_int, fmt};
4
5use darwin_kperf_sys::kperfdata;
6
7/// Categorizes a `kpep_config_error_code` into a semantic variant.
8///
9/// The variants mirror the `KPEP_CONFIG_ERROR_*` constants from `kperfdata.framework`.
10/// [`Other`](FrameworkErrorKind::Other) captures any unrecognized code returned by a future OS
11/// revision.
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum FrameworkErrorKind {
14    /// The operation completed successfully (`KPEP_CONFIG_ERROR_NONE`, code 0).
15    None,
16    /// A required argument was null or otherwise invalid.
17    InvalidArgument,
18    /// Memory allocation failed inside the framework.
19    OutOfMemory,
20    /// An I/O error occurred while reading the PMC database plist.
21    Io,
22    /// A caller-supplied buffer was too small to receive the result.
23    BufferTooSmall,
24    /// The current CPU could not be identified in the PMC database.
25    CurrentSystemUnknown,
26    /// The path to the PMC database plist is invalid.
27    DatabasePathInvalid,
28    /// No PMC database plist was found for the requested CPU.
29    DatabaseNotFound,
30    /// The PMC database exists but targets an unsupported architecture.
31    DatabaseArchitectureUnsupported,
32    /// The PMC database version is not supported by this framework build.
33    DatabaseVersionUnsupported,
34    /// The PMC database plist is malformed or corrupt.
35    DatabaseCorrupt,
36    /// The requested event name was not found in the PMC database.
37    EventNotFound,
38    /// Two or more events conflict and cannot be measured simultaneously.
39    ConflictingEvents,
40    /// Counters must be force-acquired via `kpc_force_all_ctrs_set(1)` before configuring.
41    AllCountersMustBeForced,
42    /// The requested event exists in the database but is unavailable on this hardware.
43    EventUnavailable,
44    /// A POSIX error occurred; check `errno` for details.
45    CheckErrno,
46    /// An error code not covered by any known variant.
47    Other(c_int),
48}
49
50impl FrameworkErrorKind {
51    /// Maps a raw `kpep_config_error_code` to its corresponding variant.
52    const fn from_code(code: c_int) -> Self {
53        match code {
54            kperfdata::KPEP_CONFIG_ERROR_NONE => Self::None,
55            kperfdata::KPEP_CONFIG_ERROR_INVALID_ARGUMENT => Self::InvalidArgument,
56            kperfdata::KPEP_CONFIG_ERROR_OUT_OF_MEMORY => Self::OutOfMemory,
57            kperfdata::KPEP_CONFIG_ERROR_IO => Self::Io,
58            kperfdata::KPEP_CONFIG_ERROR_BUFFER_TOO_SMALL => Self::BufferTooSmall,
59            kperfdata::KPEP_CONFIG_ERROR_CUR_SYSTEM_UNKNOWN => Self::CurrentSystemUnknown,
60            kperfdata::KPEP_CONFIG_ERROR_DB_PATH_INVALID => Self::DatabasePathInvalid,
61            kperfdata::KPEP_CONFIG_ERROR_DB_NOT_FOUND => Self::DatabaseNotFound,
62            kperfdata::KPEP_CONFIG_ERROR_DB_ARCH_UNSUPPORTED => {
63                Self::DatabaseArchitectureUnsupported
64            }
65            kperfdata::KPEP_CONFIG_ERROR_DB_VERSION_UNSUPPORTED => Self::DatabaseVersionUnsupported,
66            kperfdata::KPEP_CONFIG_ERROR_DB_CORRUPT => Self::DatabaseCorrupt,
67            kperfdata::KPEP_CONFIG_ERROR_EVENT_NOT_FOUND => Self::EventNotFound,
68            kperfdata::KPEP_CONFIG_ERROR_CONFLICTING_EVENTS => Self::ConflictingEvents,
69            kperfdata::KPEP_CONFIG_ERROR_COUNTERS_NOT_FORCED => Self::AllCountersMustBeForced,
70            kperfdata::KPEP_CONFIG_ERROR_EVENT_UNAVAILABLE => Self::EventUnavailable,
71            kperfdata::KPEP_CONFIG_ERROR_ERRNO => Self::CheckErrno,
72            _ => Self::Other(code),
73        }
74    }
75
76    const fn as_str(self) -> &'static str {
77        match self {
78            Self::None => "success",
79            Self::InvalidArgument => "invalid argument",
80            Self::OutOfMemory => "out of memory",
81            Self::Io => "I/O error",
82            Self::BufferTooSmall => "buffer too small",
83            Self::CurrentSystemUnknown => "current system unknown",
84            Self::DatabasePathInvalid => "database path invalid",
85            Self::DatabaseNotFound => "database not found",
86            Self::DatabaseArchitectureUnsupported => "database architecture unsupported",
87            Self::DatabaseVersionUnsupported => "database version unsupported",
88            Self::DatabaseCorrupt => "database corrupt",
89            Self::EventNotFound => "event not found",
90            Self::ConflictingEvents => "conflicting events",
91            Self::AllCountersMustBeForced => "all counters must be forced",
92            Self::EventUnavailable => "event unavailable",
93            Self::CheckErrno => "check errno",
94            Self::Other(_) => "unknown error",
95        }
96    }
97}
98
99impl fmt::Display for FrameworkErrorKind {
100    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
101        fmt.write_str(self.as_str())
102    }
103}
104
105/// An error returned by a `kperfdata.framework` function.
106///
107/// Wraps the raw `c_int` error code together with its decoded [`FrameworkErrorKind`]. The original
108/// code is preserved so callers can inspect values that may not map to a known variant.
109pub struct FrameworkError {
110    code: c_int,
111    kind: FrameworkErrorKind,
112}
113
114impl FrameworkError {
115    /// Creates an `Error` from a raw `kpep_config_error_code`.
116    #[must_use]
117    pub const fn from_code(code: c_int) -> Self {
118        Self {
119            code,
120            kind: FrameworkErrorKind::from_code(code),
121        }
122    }
123
124    /// Returns the semantic category of this error.
125    #[must_use]
126    pub const fn kind(&self) -> FrameworkErrorKind {
127        self.kind
128    }
129}
130
131impl fmt::Debug for FrameworkError {
132    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
133        fmt.debug_struct("Error")
134            .field("kind", &self.kind)
135            .finish_non_exhaustive()
136    }
137}
138
139impl fmt::Display for FrameworkError {
140    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
141        write!(fmt, "kpep error {}: {}", self.code, self.kind)
142    }
143}
144
145impl error::Error for FrameworkError {}