windows_ioring_sys/ring/kind.rs
1// Copyright (c) 2026 Mike Grier
2//! What a ring may be asked to carry: [`Open`] or [`Owned`] (`M41.1`,
3//! [D-91](../../DESIGN-NOTES.md#d-91)).
4//!
5//! Every operation a safe push queues is an *owned* operation: the ring holds what it needs, and
6//! the pop that observes its completion hands that back. A handful of calls queue an operation
7//! the ring holds **nothing** for -- the registrations, the `_raw` flush and cancel, and
8//! [`IoRing::push_raw`](super::IoRing::push_raw) -- and their completions arrive from a pop with
9//! no payload and no sidecar. That is a legitimate outcome for a caller who chose it, and a
10//! branch every other caller has to write and cannot reach.
11//!
12//! A ring is therefore typed by whether it can have such an operation in flight. An [`Open`] ring
13//! can, and is what every constructor makes. An [`Owned`] ring cannot: the calls that queue one do
14//! not exist for it, and a pop never hands back an absent entry. The one way from the first to the
15//! second is [`IoRing::into_owned`](super::IoRing::into_owned), which consumes the ring and refuses
16//! while any such operation is in flight; there is no way back, so the property is not one a
17//! later caller can undo.
18
19use std::io;
20
21use crate::ring::Completion;
22
23/// A ring that may have an operation in flight that the ring holds nothing for: the kind every
24/// constructor makes. All of the ring's calls exist for it.
25///
26/// Uninhabited: it only ever appears as a type argument.
27#[derive(Debug, Clone, Copy)]
28pub enum Open {}
29
30/// A ring none of whose in-flight operations can be one the ring holds nothing for, reached from
31/// an [`Open`] ring by [`IoRing::into_owned`](super::IoRing::into_owned). The calls that queue such
32/// an operation do not exist for it, and a pop returns what the ring held, without the case of
33/// there being nothing.
34///
35/// Uninhabited: it only ever appears as a type argument.
36#[derive(Debug, Clone, Copy)]
37pub enum Owned {}
38
39mod sealed {
40 pub trait Sealed {}
41 impl Sealed for super::Open {}
42 impl Sealed for super::Owned {}
43}
44
45/// What a ring's kind decides: the shape a pop returns it in. Implemented by [`Open`] and
46/// [`Owned`] only.
47pub trait RingKind: sealed::Sealed {
48 /// What a pop returns: the completion, and what the ring held for it.
49 type Popped<T, X>;
50
51 /// Shape a popped completion and what the ring held for it.
52 ///
53 /// # Errors
54 ///
55 /// Only when the kind promises the ring holds something for every completion and it did not,
56 /// during an unwind, where a panic would abort.
57 #[doc(hidden)]
58 fn shape<T, X>(
59 completion: Completion,
60 held: Option<(Option<T>, X)>,
61 ) -> io::Result<Self::Popped<T, X>>;
62}
63
64/// The kinds that may queue an operation the ring holds nothing for: [`Open`]. A method with this
65/// bound is one an [`Owned`] ring does not have.
66///
67/// The registrations and the `_raw` flush and cancel do not build for an [`Owned`] ring:
68///
69/// ```compile_fail,E0277
70/// use windows_ioring_sys::{Batch, IoRing, Owned};
71///
72/// fn register(ring: &mut IoRing<Vec<u8>, (), Owned>) {
73/// let _ = Batch::new(ring).register_buffers(vec![vec![0_u8; 8]]);
74/// }
75/// ```
76///
77/// ```compile_fail,E0277
78/// use windows_ioring_sys::{Batch, FlushCoverage, FlushMode, IoRing, Owned};
79///
80/// fn flush(ring: &mut IoRing<(), (), Owned>, file: std::os::windows::io::RawHandle) {
81/// // SAFETY: not reached; this is a compile failure.
82/// let _ = unsafe {
83/// Batch::new(ring).flush_raw(file, FlushCoverage::Unordered, FlushMode::Default)
84/// };
85/// }
86/// ```
87///
88/// ```compile_fail,E0277
89/// use windows_ioring_sys::{IoRing, Owned};
90///
91/// fn push(ring: &mut IoRing<(), (), Owned>) {
92/// // SAFETY: not reached; this is a compile failure.
93/// let _ = unsafe { ring.push_raw(|_, _| 0) };
94/// }
95/// ```
96///
97/// And no constructor makes one, nor is there a way back to [`Open`]:
98///
99/// ```compile_fail,E0308
100/// use windows_ioring_sys::{IoRing, Owned};
101///
102/// let _ring: IoRing<(), (), Owned> = IoRing::new(8, 8).unwrap();
103/// ```
104///
105/// ```compile_fail,E0599
106/// use windows_ioring_sys::{IoRing, Owned};
107///
108/// fn reopen(ring: IoRing<(), (), Owned>) {
109/// let _ = ring.into_open();
110/// }
111/// ```
112///
113/// Over an [`Open`] ring the same calls build:
114///
115/// ```no_run
116/// use windows_ioring_sys::{Batch, IoRing};
117///
118/// # fn main() -> std::io::Result<()> {
119/// let mut ring = IoRing::<Vec<u8>>::with_inventory(8, 8)?;
120/// let _pending = Batch::new(&mut ring).register_buffers(vec![vec![0_u8; 8]]);
121/// # Ok(())
122/// # }
123/// ```
124pub trait AllowsRaw: RingKind {}
125
126impl RingKind for Open {
127 /// The outer `Option` is whether the ring held anything for the completion; the inner is
128 /// whether what it held included a buffer.
129 type Popped<T, X> = (Completion, Option<(Option<T>, X)>);
130
131 fn shape<T, X>(
132 completion: Completion,
133 held: Option<(Option<T>, X)>,
134 ) -> io::Result<Self::Popped<T, X>> {
135 Ok((completion, held))
136 }
137}
138
139impl AllowsRaw for Open {}
140
141impl RingKind for Owned {
142 /// The buffer, if the operation had one, and the sidecar: the ring held an entry for every
143 /// completion, so there is no case of it holding none.
144 type Popped<T, X> = (Completion, Option<T>, X);
145
146 fn shape<T, X>(
147 completion: Completion,
148 held: Option<(Option<T>, X)>,
149 ) -> io::Result<Self::Popped<T, X>> {
150 match held {
151 Some((payload, extra)) => Ok((completion, payload, extra)),
152 // Nothing can queue an operation this ring holds nothing for, and `into_owned`
153 // refused while one was in flight, so this is a defect in the ring or in a caller
154 // that reached its internals -- as a completion for an identity not in flight is
155 // (D-79). An unwind is the exception: a second panic there aborts, so it is an error.
156 None if std::thread::panicking() => Err(io::Error::other(
157 "an owned ring held nothing for a completion, while unwinding",
158 )),
159 None => panic!(
160 "an owned ring held nothing for the completion of operation {}: nothing can \
161 queue an operation it does not hold, so the ring's bookkeeping is inconsistent \
162 (D-91)",
163 completion.user_data()
164 ),
165 }
166 }
167}