Skip to main content

incular_platform/
operation.rs

1//! Portable native-operation identity, completion, and errors.
2
3use crate::WindowId;
4
5/// Stable identity for one result-bearing native request.
6///
7/// IDs are allocated by the runtime command bridge and are never native
8/// command IDs or handles.
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
10pub struct NativeRequestId(u64);
11
12impl NativeRequestId {
13    #[must_use]
14    pub const fn new(value: u64) -> Self {
15        Self(value)
16    }
17
18    #[must_use]
19    pub const fn get(self) -> u64 {
20        self.0
21    }
22}
23
24/// Stable category for a failure at the native platform boundary.
25#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
26pub enum PlatformOperationErrorKind {
27    Unsupported,
28    Unavailable,
29    RejectedByPlatform,
30    InvalidState,
31    StaleResource,
32    NativeFailure,
33}
34
35/// Backend-neutral native operation failure.
36///
37/// `context` is diagnostic text only. Public code must branch on [`Self::kind`]
38/// rather than parsing platform error strings.
39#[derive(Clone, Debug, PartialEq, Eq, Hash, thiserror::Error)]
40#[error("{}", describe_operation_error(.kind, .context.as_deref()))]
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
89fn describe_operation_error(kind: &PlatformOperationErrorKind, context: Option<&str>) -> String {
90    let category = match kind {
91        PlatformOperationErrorKind::Unsupported => "operation is unsupported",
92        PlatformOperationErrorKind::Unavailable => "platform service is unavailable",
93        PlatformOperationErrorKind::RejectedByPlatform => "operation was rejected by the platform",
94        PlatformOperationErrorKind::InvalidState => "operation is invalid in the current state",
95        PlatformOperationErrorKind::StaleResource => "target resource is stale",
96        PlatformOperationErrorKind::NativeFailure => "native operation failed",
97    };
98    match context {
99        Some(context) => format!("{category}: {context}"),
100        None => category.to_owned(),
101    }
102}
103
104pub type PlatformOperationResult = Result<(), PlatformOperationError>;
105
106/// One native backend completion routed back to the runtime.
107#[derive(Clone, Debug, PartialEq, Eq)]
108pub struct NativeOperationCompletion {
109    pub window_id: WindowId,
110    pub request_id: NativeRequestId,
111    pub result: PlatformOperationResult,
112}
113
114impl NativeOperationCompletion {
115    #[must_use]
116    pub const fn new(
117        window_id: WindowId,
118        request_id: NativeRequestId,
119        result: PlatformOperationResult,
120    ) -> Self {
121        Self {
122            window_id,
123            request_id,
124            result,
125        }
126    }
127}