Skip to main content

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;