win_numa_sys/lib.rs
1// Copyright (c) 2026 Mike Grier
2//! Memory-safe Rust over the Windows NUMA APIs.
3//!
4//! Windows provides some NUMA concepts; this crate builds library notions on
5//! top of them. Whether a client uses them is up to the client.
6//!
7//! # What is here
8//!
9//! - [`NumaNode`] -- a node number, as Windows numbers them.
10//! - [`NumaBuffer`] -- an owned allocation made with `VirtualAllocExNuma` and
11//! released with `VirtualFree`, so a buffer can be placed on a chosen node
12//! rather than wherever the default allocator lands it.
13//! - [`highest_numa_node`] and [`volume_numa_node`] -- the two questions
14//! Windows will answer about nodes, wrapped so a caller can find a node to
15//! pass without writing the FFI themselves.
16//!
17//! [`NumaBuffer`] implements `io-buffers`' `IoBuf` and `IoBufMut`, so it can be
18//! handed to a ring as it is. This crate defines no buffer trait of its own.
19//!
20//! # What is not here, and will not be
21//!
22//! **Any opinion about which node anything should use.** This crate reports
23//! what Windows says and allocates where it is told. It does not map a file to
24//! a node, does not shard anything, and does not choose a node on a caller's
25//! behalf. Those are workload decisions, and a consumer on hardware this
26//! workspace has never seen is better placed to take them.
27//!
28//! The `-sys` suffix is that promise, and it is the repository's meaning of the
29//! suffix rather than a convention borrowed from elsewhere: thin over Win32,
30//! memory-safe, adding no policy.
31//!
32//! # A node argument is a preference, not an instruction
33//!
34//! The underlying parameter says so in its own name -- `nndPreferred`. A
35//! successful allocation is therefore **not** evidence that the pages landed on
36//! the node that was asked for, and code that needs to know must observe rather
37//! than assume. Two measured facts about that, both from this workspace:
38//!
39//! - Committed pages are demand-zero, so until something writes to them no
40//! physical page has been drawn from the preferred node at all. A caller
41//! measuring placement must fault the pages in first.
42//! - An *invalid* node is refused, and `u32::MAX` is not a test of that: it is
43//! the API's own no-preference sentinel, accepted by design. A measurement
44//! that asks for `u32::MAX` and sees it succeed has measured the sentinel,
45//! not a range check. [`NumaBuffer`]'s tests use `u32::MAX - 1`.
46//!
47//! Observing where pages actually landed needs `QueryWorkingSetEx`, which lives
48//! in `windows-placement-probe` today and is a candidate to move here; see that
49//! crate's `peer_index_cache`.
50
51#![cfg(windows)]
52#![deny(missing_docs)]
53
54mod buffer;
55mod io_buf;
56mod node;
57
58pub use buffer::NumaBuffer;
59pub use node::{NumaNode, highest_numa_node, volume_numa_node};