windows_ioring_sys/capability.rs
1// Copyright (c) 2026 Mike Grier
2//! Capability query and version negotiation (M1.3, D-6).
3
4use std::io;
5
6use windows_sys::Win32::Storage::FileSystem::{
7 IORING_CAPABILITIES, IORING_FEATURE_SET_COMPLETION_EVENT, IORING_FEATURE_UM_EMULATION,
8 IORING_VERSION_1, IORING_VERSION_2, IORING_VERSION_3, QueryIoRingCapabilities,
9};
10
11use crate::error::check;
12
13/// An `IORING_VERSION` value.
14///
15/// Wraps the raw value rather than a closed Rust enum, because the running
16/// system can report a version this crate does not yet name: a spike found
17/// `QueryIoRingCapabilities` reporting `MaxVersion = 400` on a machine current
18/// as of this writing, while `windows-sys` 0.61.2 only names up to
19/// [`RingVersion::V3`] (`IORING_VERSION_3 = 300`). Hardcoding the highest
20/// named version as a hard ceiling would silently cap this crate the moment
21/// a newer system shipped, rather than only until the next `windows-sys`
22/// bump.
23#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub struct RingVersion(i32);
25
26impl RingVersion {
27 /// `IORING_VERSION_1`.
28 pub const V1: RingVersion = RingVersion(IORING_VERSION_1);
29 /// `IORING_VERSION_2`.
30 pub const V2: RingVersion = RingVersion(IORING_VERSION_2);
31 /// `IORING_VERSION_3`.
32 pub const V3: RingVersion = RingVersion(IORING_VERSION_3);
33
34 /// The highest version this crate can name. [`IoRing::new`](crate::IoRing::new)
35 /// negotiates down to `min(HIGHEST_KNOWN, capabilities()?.max_version)`
36 /// rather than assuming this is what the running system supports.
37 pub const HIGHEST_KNOWN: RingVersion = Self::V3;
38
39 /// Wrap a raw `IORING_VERSION` value, for example one reported by
40 /// [`Capabilities::max_version`] that this crate does not name.
41 #[must_use]
42 pub fn from_raw(value: i32) -> Self {
43 Self(value)
44 }
45
46 /// The raw `IORING_VERSION` value.
47 #[must_use]
48 pub fn raw(self) -> i32 {
49 self.0
50 }
51}
52
53/// What the running system's `IoRing` implementation supports, queried
54/// without creating a ring.
55#[derive(Clone, Copy, Debug, PartialEq, Eq)]
56pub struct Capabilities {
57 /// The highest `IORING_VERSION` the system supports.
58 pub max_version: RingVersion,
59 /// The largest submission queue a ring can request.
60 pub max_submission_queue_size: u32,
61 /// The largest completion queue a ring can request.
62 pub max_completion_queue_size: u32,
63 /// Whether `SetIoRingCompletionEvent` is available. Both
64 /// [`crate::IoRing::completion_event`] and the thread-pool delivery path
65 /// built on it refuse to construct without this.
66 pub supports_completion_event: bool,
67 /// Whether the ring is emulated in user mode rather than backed by the
68 /// kernel. A consumer reaching for this crate to maximize throughput
69 /// needs to know when they are getting an emulation with no kernel
70 /// benefit, so this is surfaced rather than hidden.
71 pub is_emulated: bool,
72}
73
74/// Query the running system's `IoRing` capabilities.
75///
76/// Needs no ring: `QueryIoRingCapabilities` is a free-standing query, so a
77/// consumer can decide whether to use this crate at all before creating
78/// anything.
79///
80/// # Errors
81///
82/// Returns any error from `QueryIoRingCapabilities`.
83pub fn capabilities() -> io::Result<Capabilities> {
84 let mut raw = IORING_CAPABILITIES::default();
85 // SAFETY: `raw` is a valid, appropriately sized out-pointer; the call
86 // needs no ring.
87 let hr = unsafe { QueryIoRingCapabilities(&raw mut raw) };
88 check(hr)?;
89 Ok(decode(&raw))
90}
91
92/// Turn a raw `IORING_CAPABILITIES` into this crate's shape.
93///
94/// Split out of [`capabilities`] so the flag decoding can be exercised with
95/// values the running system does not report (M18.7). `QueryIoRingCapabilities`
96/// reports whatever the host supports and nothing can vary it, so while this
97/// lived inside the query it was unreachable from any test -- M18.3's mutation
98/// run found all four of its bit operations surviving, including the one
99/// deciding `supports_completion_event`, which gates every completion-event
100/// path in the crate ([D-20](../DESIGN-NOTES.md#d-20)) and which
101/// [#47](https://github.com/MikeGrier/windows-threadpool-sys/issues/47) lived
102/// downstream of.
103///
104/// Pure, and takes the raw struct by reference: no syscall, no global state, so
105/// a test can hand it any flag combination including ones no Windows build
106/// produces.
107fn decode(raw: &IORING_CAPABILITIES) -> Capabilities {
108 Capabilities {
109 max_version: RingVersion(raw.MaxVersion),
110 max_submission_queue_size: raw.MaxSubmissionQueueSize,
111 max_completion_queue_size: raw.MaxCompletionQueueSize,
112 // Each flag is tested on its own bit: a mask that happens to carry
113 // other feature bits must not change either answer.
114 supports_completion_event: raw.FeatureFlags & IORING_FEATURE_SET_COMPLETION_EVENT != 0,
115 is_emulated: raw.FeatureFlags & IORING_FEATURE_UM_EMULATION != 0,
116 }
117}
118
119#[cfg(test)]
120mod tests;