1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
//! [`SurfaceTarget`] — the one sanctioned platform leak in the engine.
//!
//! # Why this lives in `crcbl-core`
//!
//! The windowing rules in `docs/notes/backends.md` describe `SurfaceTarget` as
//! "the *single* sanctioned platform leak": the shell produces it, a HAL backend consumes it,
//! and nothing in between is allowed to look inside. That makes it **shared
//! vocabulary between two crates that must not depend on each other**:
//!
//! ```text
//! crcbl-core (SurfaceTarget lives here)
//! ^ ^
//! | |
//! crcbl-shell crcbl-hal
//! ^
//! |
//! crcbl-vk / crcbl-webgpu / …
//! ```
//!
//! * `crcbl-shell` must not depend on `crcbl-hal` — a windowing library that
//! needs a graphics HAL to compile has the dependency backwards, and
//! `HeadlessShell` would drag a backend seam into CI-only builds.
//! * `crcbl-hal` must not depend on `crcbl-shell` — backends are used offscreen
//! (`crcbl screenshot`, golden-image e2e) with no window anywhere in the
//! process, and `crcbl-shell` will grow real platform code that a headless
//! render test has no business linking.
//!
//! Both already depend on `crcbl-core`, so putting the type here is the only
//! placement that does not create a cycle or a spurious dependency. It costs
//! `crcbl-core` nothing: the type is a plain enum of integers and raw pointers
//! with no methods that touch them.
//!
//! # Safety model
//!
//! Constructing a `SurfaceTarget` is **safe**. Nothing here dereferences a
//! pointer, and a wrong value is inert until a backend uses it. The obligation
//! sits at the single point that can act on it — `crcbl-hal`'s
//! `Instance::create_surface`, which is `unsafe` and documents the full
//! contract (handles are live objects of the stated kind, and they outlive the
//! surface created from them).
//!
//! This mirrors `raw-window-handle` 0.6 and `wgpu::Instance::create_surface_unsafe`,
//! and it means this module — the one place platform pointers enter the engine
//! — contains no `unsafe` at all.
//!
//! # Thread safety
//!
//! `SurfaceTarget` is deliberately **not** `Send`/`Sync` (it holds
//! [`NonNull`]). Several of these handles are thread-affine in ways we cannot
//! promise away — a Win32 `HWND` belongs to the thread that pumps its message
//! queue, and an `NSView`/`CAMetalLayer` is main-thread-only on macOS. The
//! practical consequence is the one every engine already lives with: create the
//! HAL surface on the thread that owns the window. `raw-window-handle` reached
//! the same conclusion in 0.6 after shipping the unsound `Send` version.
use c_void;
use NonNull;
/// A window's native presentation handles, in the form a HAL backend needs to
/// create a surface.
///
/// Produced by `crcbl-shell`, destructured *only* by HAL backends. Engine code,
/// samples and the editor pass it through opaquely; a `#[cfg]` on a platform in
/// a consumer crate is a regression.
///
/// # Exhaustiveness
///
/// This enum is intentionally **not** `#[non_exhaustive]`. Adding a platform
/// should break every backend's `match` loudly at compile time — the whole
/// engine is one workspace, and a silently-ignored new platform is exactly the
/// failure this type exists to prevent.
///
/// # Variants and their producers
///
/// | Variant | Shell backend | Vulkan entry point |
/// | --- | --- | --- |
/// | [`Wayland`](Self::Wayland) | Wayland (P0) | `vkCreateWaylandSurfaceKHR` |
/// | [`Xcb`](Self::Xcb) | X11 (P0) | `vkCreateXcbSurfaceKHR` |
/// | [`Web`](Self::Web) | canvas (P5) | — (WebGPU `GPUCanvasContext`) |
/// | [`Win32`](Self::Win32) | Win32 (P14) | `vkCreateWin32SurfaceKHR` |
/// | [`AppKit`](Self::AppKit) | AppKit (P14) | `vkCreateMetalSurfaceEXT` |
/// | [`Offscreen`](Self::Offscreen) | `HeadlessShell` | — (image ring, no WSI) |
///
/// Xlib is absent on purpose: topic 15 links `libxcb`, not `libX11`, so no
/// shell backend can produce an `Xlib` target and a variant nobody constructs
/// is a variant every backend still has to handle.