win_durable_ioring/windows_backend/file_target.rs
1// Copyright (c) 2026 Mike Grier
2//! [`Win32FileTarget`]: a target backed by a Win32 file, a raw volume or a whole disk (DI-D-48,
3//! DI-D-50, DI-D-60, DI-D-61, DI-D-62).
4
5use win_shared_os_owned_handle::SharedHandle;
6
7use super::opened_disk::OpenedDisk;
8use super::opened_file::{Buffering, OpenedFile};
9use super::opened_volume::OpenedVolume;
10use durable_ioring::FlushDomain;
11use durable_ioring::{Capabilities, Geometry, IoTarget, WarrantyClass};
12
13/// A target backed by a Win32 file, a raw volume or a whole disk this crate opened, held as a
14/// `SharedHandle` -- an owning form, never a raw handle (DI-D-4).
15///
16/// It is made from an [`OpenedFile`], an [`OpenedVolume`] or an [`OpenedDisk`] and from nothing else, and takes its
17/// warranty class, its alignment and its capabilities from how that was opened, not from a
18/// declaration (DI-D-60): one opened cached is [`WarrantyClass::BestEffort`], and one opened
19/// [`Unbuffered`](super::Unbuffered) is [`WarrantyClass::SharedDevice`], needs a sector's alignment,
20/// and offers per-write write-through. [`WarrantyClass::Complete`] is never one's: it needs
21/// knowledge of what else writes the device, which a volume's lock does not give (DI-D-61).
22///
23/// A volume's flush domains are found from its disks. A file's are what it cannot know, so they are
24/// declared with [`with_domains`](Self::with_domains); declaring them on a volume adds to the ones
25/// found, and never removes one.
26#[derive(Clone, Debug)]
27pub struct Win32FileTarget {
28 handle: SharedHandle,
29 /// What the backing found for itself: a volume's disks.
30 found: Vec<FlushDomain>,
31 /// What the consumer declared.
32 declared: Vec<FlushDomain>,
33 /// Both, each once: what the target reports.
34 domains: Vec<FlushDomain>,
35 warranty: WarrantyClass,
36 geometry: Geometry,
37 capabilities: Capabilities,
38}
39
40impl Win32FileTarget {
41 /// The target `file` makes, claiming what its open mode allows and no more.
42 #[must_use]
43 pub fn new<B: Buffering>(file: OpenedFile<B>) -> Self {
44 Self {
45 geometry: file.geometry(),
46 handle: file.handle().clone(),
47 found: Vec::new(),
48 declared: Vec::new(),
49 domains: Vec::new(),
50 warranty: B::WARRANTY,
51 capabilities: B::CAPABILITIES,
52 }
53 }
54
55 /// The target `volume` makes: its sector's alignment, the flush domains of the disks it sits
56 /// on, and what its open mode allows and no more.
57 #[must_use]
58 pub fn from_volume<B: Buffering>(volume: OpenedVolume<B>) -> Self {
59 let found = volume.flush_domains();
60 Self {
61 geometry: volume.geometry(),
62 handle: volume.handle().clone(),
63 domains: found.clone(),
64 found,
65 declared: Vec::new(),
66 warranty: B::WARRANTY,
67 capabilities: B::CAPABILITIES,
68 }
69 }
70
71 /// The target `disk` makes: its sector's alignment, the disk itself as its flush domain, and
72 /// what its open mode allows and no more.
73 #[must_use]
74 pub fn from_disk<B: Buffering>(disk: OpenedDisk<B>) -> Self {
75 let found = vec![disk.flush_domain()];
76 Self {
77 geometry: disk.geometry(),
78 handle: disk.handle().clone(),
79 domains: found.clone(),
80 found,
81 declared: Vec::new(),
82 warranty: B::WARRANTY,
83 capabilities: B::CAPABILITIES,
84 }
85 }
86
87 /// Declare every flush domain its writes depend on, beyond any the backing found for itself.
88 /// Declaring again replaces what was declared before, and never what the backing found.
89 #[must_use]
90 pub fn with_domains(mut self, domains: impl IntoIterator<Item = FlushDomain>) -> Self {
91 self.declared = domains.into_iter().collect();
92 self.domains = self.found.clone();
93 for domain in &self.declared {
94 if !self.domains.contains(domain) {
95 self.domains.push(domain.clone());
96 }
97 }
98 self
99 }
100
101 /// The file's handle.
102 #[must_use]
103 pub fn handle(&self) -> &SharedHandle {
104 &self.handle
105 }
106
107 /// State a class a file's open mode cannot give, to test what the backend does with each.
108 #[cfg(test)]
109 #[must_use]
110 pub(crate) fn declared(
111 mut self,
112 warranty: WarrantyClass,
113 geometry: Geometry,
114 capabilities: Capabilities,
115 ) -> Self {
116 self.warranty = warranty;
117 self.geometry = geometry;
118 self.capabilities = capabilities;
119 self
120 }
121}
122
123impl IoTarget for Win32FileTarget {
124 fn flush_domains(&self) -> &[FlushDomain] {
125 &self.domains
126 }
127
128 fn warranty(&self) -> WarrantyClass {
129 self.warranty
130 }
131
132 fn geometry(&self) -> Geometry {
133 self.geometry
134 }
135
136 fn capabilities(&self) -> Capabilities {
137 self.capabilities
138 }
139}