Skip to main content

incular_platform/
operation.rs

1//! Portable native-operation identity, completion, and errors.
2
3use crate::WindowId;
4use std::fmt;
5
6/// Stable identity for one result-bearing native request.
7///
8/// IDs are allocated by the runtime command bridge and are never native
9/// command IDs or handles.
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
11pub struct NativeRequestId(u64);
12
13impl NativeRequestId {
14    #[must_use]
15    pub const fn new(value: u64) -> Self {
16        Self(value)
17    }
18
19    #[must_use]
20    pub const fn get(self) -> u64 {
21        self.0
22    }
23}
24
25/// Stable category for a failure at the native platform boundary.
26#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
27pub enum PlatformOperationErrorKind {
28    Unsupported,
29    Unavailable,
30    RejectedByPlatform,
31    InvalidState,
32    StaleResource,
33    NativeFailure,
34}
35
36/// Backend-neutral native operation failure.
37///
38/// `context` is diagnostic text only. Public code must branch on [`Self::kind`]
39/// rather than parsing platform error strings.
40#[derive(Clone, Debug, PartialEq, Eq, Hash)]
41pub struct PlatformOperationError {
42    kind: PlatformOperationErrorKind,
43    context: Option<String>,
44}
45
46impl PlatformOperationError {
47    #[must_use]
48    pub const fn new(kind: PlatformOperationErrorKind) -> Self {
49        Self {
50            kind,
51            context: None,
52        }
53    }
54
55    #[must_use]
56    pub fn with_context(kind: PlatformOperationErrorKind, context: impl Into<String>) -> Self {
57        Self {
58            kind,
59            context: Some(context.into()),
60        }
61    }
62
63    #[must_use]
64    pub const fn unsupported() -> Self {
65        Self::new(PlatformOperationErrorKind::Unsupported)
66    }
67
68    #[must_use]
69    pub const fn unavailable() -> Self {
70        Self::new(PlatformOperationErrorKind::Unavailable)
71    }
72
73    #[must_use]
74    pub const fn stale_resource() -> Self {
75        Self::new(PlatformOperationErrorKind::StaleResource)
76    }
77
78    #[must_use]
79    pub const fn kind(&self) -> PlatformOperationErrorKind {
80        self.kind
81    }
82
83    #[must_use]
84    pub fn context(&self) -> Option<&str> {
85        self.context.as_deref()
86    }
87}
88
89impl fmt::Display for PlatformOperationError {
90    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
91        let category = match self.kind {
92            PlatformOperationErrorKind::Unsupported => "operation is unsupported",
93            PlatformOperationErrorKind::Unavailable => "platform service is unavailable",
94            PlatformOperationErrorKind::RejectedByPlatform => {
95                "operation was rejected by the platform"
96            }
97            PlatformOperationErrorKind::InvalidState => "operation is invalid in the current state",
98            PlatformOperationErrorKind::StaleResource => "target resource is stale",
99            PlatformOperationErrorKind::NativeFailure => "native operation failed",
100        };
101        match &self.context {
102            Some(context) => write!(formatter, "{category}: {context}"),
103            None => formatter.write_str(category),
104        }
105    }
106}
107
108impl std::error::Error for PlatformOperationError {}
109
110pub type PlatformOperationResult = Result<(), PlatformOperationError>;
111
112/// One native backend completion routed back to the runtime.
113#[derive(Clone, Debug, PartialEq, Eq)]
114pub struct NativeOperationCompletion {
115    pub window_id: WindowId,
116    pub request_id: NativeRequestId,
117    pub result: PlatformOperationResult,
118}
119
120impl NativeOperationCompletion {
121    #[must_use]
122    pub const fn new(
123        window_id: WindowId,
124        request_id: NativeRequestId,
125        result: PlatformOperationResult,
126    ) -> Self {
127        Self {
128            window_id,
129            request_id,
130            result,
131        }
132    }
133}