windows_thread_ambient_sys/captured.rs
1// Copyright (c) Mike Grier.
2
3//! The three-state value every capturable aspect carries.
4
5/// What a capture produced for one aspect.
6///
7/// # Why this is not `Option`
8///
9/// *Not captured* and *captured, and the thread had none* are different facts
10/// with the same observable outcome, and only one of them is a decision.
11///
12/// Take impersonation. If the aspect was left out of the capture set, the worker
13/// runs under the process identity. If it was captured and the calling thread
14/// had no token, the worker also runs under the process identity. A caller
15/// reading back an `Option::None` cannot tell which happened -- so an omission
16/// becomes indistinguishable from a deliberate statement about what the work
17/// should run as, and nobody can later reconstruct which one it was.
18///
19/// The shape is uniform across aspects even where [`Absent`](Self::Absent) is
20/// unreachable, because a per-aspect shape would make every consumer remember
21/// which aspects can be absent.
22///
23/// # Example
24///
25/// ```
26/// use windows_thread_ambient_sys::Captured;
27///
28/// let omitted: Captured<u32> = Captured::NotCaptured;
29/// let asked_and_empty: Captured<u32> = Captured::Absent;
30///
31/// // Both yield nothing, which is what `Option` would collapse them to...
32/// assert_eq!(omitted.present(), None);
33/// assert_eq!(asked_and_empty.present(), None);
34///
35/// // ...but only one of them is a decision, and that stays recoverable.
36/// assert!(!omitted.was_captured());
37/// assert!(asked_and_empty.was_captured());
38/// ```
39#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
40pub enum Captured<T> {
41 /// The aspect was not in the capture set, so nothing was read and the
42 /// target thread's own value is left alone.
43 NotCaptured,
44 /// The aspect was captured, and the calling thread had no value for it.
45 Absent,
46 /// The aspect was captured.
47 Present(T),
48}
49
50impl<T> Captured<T> {
51 /// Whether capture was attempted at all.
52 ///
53 /// True for both [`Absent`](Self::Absent) and [`Present`](Self::Present):
54 /// the question is whether the caller asked, not what the answer was.
55 #[must_use]
56 pub const fn was_captured(&self) -> bool {
57 !matches!(self, Self::NotCaptured)
58 }
59
60 /// The captured value, if there is one.
61 #[must_use]
62 pub const fn present(&self) -> Option<&T> {
63 match self {
64 Self::Present(value) => Some(value),
65 Self::NotCaptured | Self::Absent => None,
66 }
67 }
68
69 /// Borrow the contents.
70 #[must_use]
71 pub const fn as_ref(&self) -> Captured<&T> {
72 match self {
73 Self::NotCaptured => Captured::NotCaptured,
74 Self::Absent => Captured::Absent,
75 Self::Present(value) => Captured::Present(value),
76 }
77 }
78
79 /// Transform a present value, preserving which of the other two states it
80 /// was otherwise.
81 #[must_use]
82 pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Captured<U> {
83 match self {
84 Self::NotCaptured => Captured::NotCaptured,
85 Self::Absent => Captured::Absent,
86 Self::Present(value) => Captured::Present(f(value)),
87 }
88 }
89}
90
91#[cfg(test)]
92mod tests;