windows-ioring-sys 0.7.2

Memory-safe Rust over the Windows IoRing submission/completion ring, with the ring holding each in-flight buffer until its completion.
Documentation
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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
// Copyright (c) 2026 Mike Grier
//! Tests for [`RingContract`].
//!
//! Two halves, and the second matters as much as the first. The oracle must
//! catch each conservation failure it claims to catch -- and it must **not**
//! report a violation for a legal sequence, because an oracle that cries wolf
//! is one its reader learns to skip. The "does not fire" cases are therefore
//! written as deliberately as the "does fire" ones.

use super::{FINISHED_HISTORY, RingContract, Violation};

/// A complete, legal lifecycle: pushed, completed, claimed.
fn full_cycle(contract: &mut RingContract, user_data: usize) {
    contract.observe_push(user_data);
    contract.observe_completion(user_data);
}

#[test]
fn a_complete_lifecycle_is_quiescent() {
    let mut contract = RingContract::new();
    full_cycle(&mut contract, 1);
    full_cycle(&mut contract, 2);
    full_cycle(&mut contract, 3);
    assert_eq!(contract.check_quiescent(), Vec::new());
}

#[test]
fn nothing_at_all_is_quiescent() {
    // The degenerate case. A contract that reported a violation for a ring
    // nobody used would fail every test that does not touch the ring.
    let contract = RingContract::new();
    assert_eq!(contract.check_quiescent(), Vec::new());
}

#[test]
fn a_push_that_never_completes_is_reported() {
    // The rule `IoRing::run_down`'s termination depends on: every queued SQE
    // completes, so one that has not is either still in flight or lost.
    let mut contract = RingContract::new();
    full_cycle(&mut contract, 1);
    contract.observe_push(2);

    assert_eq!(
        contract.check_quiescent(),
        vec![Violation::Outstanding { user_data: 2 }]
    );
}

// Three tests stood here, and `D-74` retired all three with the model they
// described: an unclaimed completion reported as a leak, and two forms of
// *deliberate* leak that were accepted because they were stated. None of them
// can be written now -- there is no token to abandon, so no distinction
// between a stated leak and an unstated one, and `Violation::LeakedToken` is
// gone with the difference.
//
// What replaces them is the pair below. The settlement rule changed shape
// rather than disappearing: completion used to be *provisional*, corrected by
// a claim, and is now terminal. Both directions are asserted, because a test
// that only showed completion settling would pass just as well against an
// oracle that settled everything.

#[test]
fn a_completion_settles_its_operation() {
    // The replacement for the leak tests. A completion is terminal now: there
    // is no second report the caller must make, so observing one is the whole
    // story and quiescence follows.
    let mut contract = RingContract::new();
    contract.observe_push(7);
    contract.observe_completion(7);

    assert_eq!(contract.check_quiescent(), Vec::new());
}

#[test]
fn a_push_without_a_completion_is_still_outstanding() {
    // The other direction, and the reason the pair exists. Settling on
    // completion must not mean settling on anything: an operation that never
    // completed is the one thing quiescence is there to catch, and it is
    // reported as `Outstanding` rather than excused.
    let mut contract = RingContract::new();
    contract.observe_push(11);

    assert_eq!(
        contract.check_quiescent(),
        vec![Violation::Outstanding { user_data: 11 }]
    );
}

#[test]
fn a_second_completion_for_the_same_operation_is_reported() {
    // The "exactly" in "exactly one completion".
    let mut contract = RingContract::new();
    contract.observe_push(4);
    contract.observe_completion(4);
    contract.observe_completion(4);

    assert!(
        contract
            .violations()
            .contains(&Violation::DuplicateCompletion { user_data: 4 }),
        "a duplicate completion must be reported: {:?}",
        contract.violations()
    );
}

#[test]
fn a_completion_for_an_operation_never_pushed_is_reported() {
    let mut contract = RingContract::new();
    contract.observe_completion(0xDEAD);

    assert!(
        contract
            .violations()
            .contains(&Violation::UnexpectedCompletion { user_data: 0xDEAD }),
        "an unrecognised completion must be reported: {:?}",
        contract.violations()
    );
}

#[test]
fn a_completion_after_a_claim_is_a_duplicate_not_a_fresh_operation() {
    // Reusing a `user_data` that has already run its course must not look
    // like a new operation, or the ring could complete something twice and
    // the second one would pass as legitimate.
    let mut contract = RingContract::new();
    full_cycle(&mut contract, 5);
    contract.observe_completion(5);

    assert!(
        contract
            .violations()
            .contains(&Violation::DuplicateCompletion { user_data: 5 }),
        "a completion after a full cycle is a duplicate: {:?}",
        contract.violations()
    );
}

#[test]
fn a_busy_registered_buffer_is_reported_at_quiescence() {
    let mut contract = RingContract::new();
    contract.observe_buffer(0, 0);
    contract.observe_buffer(1, 2);

    assert_eq!(
        contract.check_quiescent(),
        vec![Violation::BufferStillInUse {
            index: 1,
            outstanding: 2
        }]
    );
}

#[test]
fn a_quiet_registered_buffer_is_not_reported() {
    let mut contract = RingContract::new();
    for index in 0..8 {
        contract.observe_buffer(index, 0);
    }
    assert_eq!(contract.check_quiescent(), Vec::new());
}

#[test]
fn a_buffer_reported_busy_then_quiet_is_not_reported() {
    // Counts are re-reported as they change; the latest observation wins.
    // Treating them as append-only would accuse every buffer that was ever
    // used.
    let mut contract = RingContract::new();
    contract.observe_buffer(3, 1);
    contract.observe_buffer(3, 0);
    assert_eq!(contract.check_quiescent(), Vec::new());
}

#[test]
fn violations_are_reported_in_a_stable_order() {
    // `HashMap` iteration order is unspecified, so without sorting the same
    // failure would print differently between runs and could not be diffed.
    let mut contract = RingContract::new();
    for user_data in [50_usize, 10, 30, 20, 40] {
        contract.observe_push(user_data);
    }

    let first = contract.check_quiescent();
    let second = contract.check_quiescent();
    assert_eq!(first, second, "repeated checks must agree");
    assert_eq!(
        first,
        vec![
            Violation::Outstanding { user_data: 10 },
            Violation::Outstanding { user_data: 20 },
            Violation::Outstanding { user_data: 30 },
            Violation::Outstanding { user_data: 40 },
            Violation::Outstanding { user_data: 50 },
        ]
    );
}

#[test]
fn every_violation_is_reported_rather_than_only_the_first() {
    // Several violations usually share one cause, and seeing only one invites
    // fixing a symptom.
    let mut contract = RingContract::new();
    contract.observe_push(1); // never completes
    contract.observe_push(2); // nor does this one
    contract.observe_buffer(0, 3); // still in use

    // Two *kinds* of violation, and more than one of the first kind. The
    // middle case used to be a completion that was never claimed, which
    // `D-74` made impossible -- so a second never-completing push replaces it
    // rather than the count being lowered, because "several" is what this
    // test is about.
    let violations = contract.check_quiescent();
    assert_eq!(violations.len(), 3, "got {violations:?}");
}

#[test]
fn assert_quiescent_names_every_violation() {
    let mut contract = RingContract::new();
    contract.observe_push(1);
    contract.observe_push(2);

    let panicked = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
        contract.assert_quiescent();
    }));
    let payload = panicked.expect_err("assert_quiescent must panic when the contract is broken");
    let message = payload
        .downcast_ref::<String>()
        .expect("a string panic payload");
    assert!(
        message.contains("0x1"),
        "should name operation 1: {message}"
    );
    assert!(
        message.contains("0x2"),
        "should name operation 2: {message}"
    );
}

#[test]
fn assert_quiescent_is_silent_when_the_contract_holds() {
    let mut contract = RingContract::new();
    full_cycle(&mut contract, 1);
    contract.assert_quiescent();
}

#[test]
fn a_tokenless_operation_is_complete_once_it_completes() {
    // `flush_raw` and `cancel_raw` return a bare `user_data` rather than a
    // token, because they own nothing a claim could hand back. Treating them
    // like token-carrying pushes would report a `LeakedToken` the caller
    // cannot possibly satisfy -- a violation that is not merely wrong but
    // unfixable, which is the worst kind an oracle can emit.
    //
    // Found by binding the real backpressure test in `submission_lifecycle.rs`
    // to this contract (M16.2), which pushes nothing but raw flushes.
    let mut contract = RingContract::new();
    contract.observe_push(1);
    contract.observe_completion(1);

    assert_eq!(contract.check_quiescent(), Vec::new());
}

#[test]
fn a_tokenless_operation_that_never_completes_is_still_reported() {
    // Owning no token does not excuse it from the one-SQE-one-completion rule.
    let mut contract = RingContract::new();
    contract.observe_push(2);

    assert_eq!(
        contract.check_quiescent(),
        vec![Violation::Outstanding { user_data: 2 }]
    );
}

#[test]
fn a_tokenless_operation_completing_twice_is_still_a_duplicate() {
    let mut contract = RingContract::new();
    contract.observe_push(3);
    contract.observe_completion(3);
    contract.observe_completion(3);

    assert!(
        contract
            .violations()
            .contains(&Violation::DuplicateCompletion { user_data: 3 }),
        "got {:?}",
        contract.violations()
    );
}

#[test]
fn a_push_that_was_rejected_is_simply_never_observed() {
    // The other half of the rule: a `Build*` that fails synchronously releases
    // its reservation and produces no completion, so it is un-counted rather
    // than uncompleted. Reporting it would manufacture an `Outstanding`
    // violation at teardown for an operation that never existed.
    //
    // Nothing in the API enforces this -- it is a rule about what a caller
    // reports -- so it is written down as a test to make the intent legible.
    let mut contract = RingContract::new();
    contract.observe_push(1);
    contract.observe_completion(1);
    // A second push was attempted here and rejected with queue-full. It is
    // deliberately not observed.
    assert_eq!(contract.check_quiescent(), Vec::new());
}

#[test]
fn busy_registered_buffers_are_reported_in_index_order() {
    // `check_quiescent` sorts its busy buffers so a failure reads the same way
    // twice -- `HashMap` iteration order is deliberately unspecified. M18.3
    // showed the sort's match arm could be deleted without any test noticing,
    // because the only test with a busy buffer had exactly one of them, and one
    // element is sorted whatever the key says.
    // Enough of them that an unsorted report is implausible rather than merely
    // unlikely: deleting the sort key leaves every entry comparing equal, and
    // `sort_by_key` is stable, so the output becomes `HashMap` iteration order.
    // With three entries that lands sorted one time in six -- which is exactly
    // what happened on the first attempt at this test, and the mutant survived.
    const BUSY: u32 = 8;

    let mut contract = RingContract::new();
    contract.observe_buffer(99, 0); // quiet, and highest -- must not appear
    for index in (0..BUSY).rev() {
        contract.observe_buffer(index, (index + 1) as usize);
    }

    let reported = contract.check_quiescent();
    let expected: Vec<_> = (0..BUSY)
        .map(|index| Violation::BufferStillInUse {
            index,
            outstanding: (index + 1) as usize,
        })
        .collect();

    assert_eq!(
        reported, expected,
        "busy buffers must be reported by ascending index, and the quiet one omitted"
    );
}

// ---------------------------------------------------------------------------
// M28.2: what the oracle costs to run.
//
// The three tests below are the only ones here that assert about *memory*
// rather than about violations, and they exist because the defect M28.2 fixed
// was invisible to every other test in this file: a claimed operation was kept
// forever, and a suite that runs a handful of operations cannot tell that from
// one that keeps none.
// ---------------------------------------------------------------------------

/// A finished operation stops being tracked at all.
///
/// The direct statement of the fix. Before `M28.2` a claim rewrote the entry
/// to `Completed` and left it in the map, so this assertion would have found
/// three.
#[test]
fn a_finished_operation_stops_being_tracked() {
    let mut contract = RingContract::new();
    full_cycle(&mut contract, 1);
    full_cycle(&mut contract, 2);
    full_cycle(&mut contract, 3);

    assert!(
        contract.operations.is_empty(),
        "a claimed operation must leave the tracking map, found: {:?}",
        contract.operations
    );
    // And the fix must not have been bought by weakening the oracle.
    assert_eq!(contract.check_quiescent(), Vec::new());
}

/// Tracking follows concurrency, not uptime.
///
/// The property a long-running consumer actually needs, and the one the old
/// shape broke. Ten thousand sequential operations are *one* operation's worth
/// of concurrency, so nothing should accumulate -- while the history stays
/// capped whatever the count.
#[test]
fn the_tracking_map_follows_concurrency_not_uptime() {
    let mut contract = RingContract::new();
    let cycles = FINISHED_HISTORY * 4;
    for user_data in 0..cycles {
        full_cycle(&mut contract, user_data);
    }

    assert!(
        contract.operations.is_empty(),
        "{cycles} sequential operations left {} tracked",
        contract.operations.len()
    );
    assert!(
        contract.finished.len() <= FINISHED_HISTORY,
        "the history must stay capped at {FINISHED_HISTORY}, found {}",
        contract.finished.len()
    );
    assert_eq!(
        contract.finished.len(),
        contract.finished_set.len(),
        "the queue and its membership index must stay in step, or eviction \
         leaks entries out of one and not the other"
    );
    assert_eq!(contract.check_quiescent(), Vec::new());
}

/// The bound's price, asserted rather than only documented.
///
/// A duplicate inside the window is named precisely; one that has fallen out
/// of it is still **reported**, under the weaker name. Both halves matter: the
/// first is what the window is for, and the second is the honest statement
/// that nothing is silently missed past it.
#[test]
fn a_duplicate_is_named_precisely_within_the_window_and_still_reported_beyond_it() {
    let mut contract = RingContract::new();

    // `oldest` is pushed out of the history by the cycles that follow it.
    let oldest = 0_usize;
    full_cycle(&mut contract, oldest);
    for user_data in 1..=FINISHED_HISTORY {
        full_cycle(&mut contract, user_data);
    }
    let recent = FINISHED_HISTORY;

    contract.observe_completion(recent);
    assert!(
        contract
            .violations()
            .contains(&Violation::DuplicateCompletion { user_data: recent }),
        "a duplicate still inside the window is a duplicate: {:?}",
        contract.violations()
    );

    contract.observe_completion(oldest);
    assert!(
        contract
            .violations()
            .contains(&Violation::UnexpectedCompletion { user_data: oldest }),
        "a duplicate that has fallen out of the window is still reported, \
         under the weaker name: {:?}",
        contract.violations()
    );
}