Skip to main content

clawless_core/event/process/
run_id.rs

1//! The identity of one run of an external program
2
3use std::fmt::{self, Display};
4use std::sync::atomic::{AtomicU64, Ordering};
5
6/// The source of the identities that [`RunId::next`] hands out
7///
8/// The counter is a single static, so every identity is unique within the
9/// process regardless of which [`Process`] handed it out. A counter per handle
10/// would repeat itself as soon as a command cloned its context.
11///
12/// [`Process`]: crate::process::Process
13static NEXT_RUN_ID: AtomicU64 = AtomicU64::new(0);
14
15/// The identity of one run of an external program
16///
17/// A command can run several programs at the same time, and the lines of those
18/// programs then reach the presenter interleaved. Every [`ProcessEvent`]
19/// carries this value so that a consumer can put a line back with the run that
20/// produced it, group the output of one program, and know when that program
21/// ended.
22///
23/// The identity is Clawless's own, and it counts runs. It is not the
24/// [`ProcessId`] that the operating system assigns, which names the program
25/// while it runs and which the operating system reuses afterwards. A run has an
26/// identity before the program starts and keeps it after the program ended,
27/// which is what an event stream needs.
28///
29/// [`ProcessId`]: crate::process::ProcessId
30///
31/// # Examples
32///
33/// ```
34/// use clawless_core::event::process::RunId;
35///
36/// let first = RunId::next();
37/// let second = RunId::next();
38///
39/// assert_ne!(first, second);
40/// ```
41///
42/// [`ProcessEvent`]: super::ProcessEvent
43// r[impl process.event.correlation]
44#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
45pub struct RunId(u64);
46
47impl RunId {
48    /// Returns an identity that no earlier call returned
49    ///
50    /// [`Process::run`] calls this once per run, so a command that runs a
51    /// program does not need it. A test that stands in for a run builds its
52    /// events with identities from here.
53    ///
54    /// The counter wraps after `2^64` runs. An application that started a
55    /// program every nanosecond would reach that point after more than five
56    /// hundred years, so the wrap is not a case that callers handle.
57    ///
58    /// # Examples
59    ///
60    /// ```
61    /// use clawless_core::event::process::RunId;
62    ///
63    /// let id = RunId::next();
64    ///
65    /// assert_eq!(id, id);
66    /// ```
67    ///
68    /// [`Process::run`]: crate::process::Process::run
69    // r[impl process.event.correlation.unique]
70    pub fn next() -> Self {
71        Self(NEXT_RUN_ID.fetch_add(1, Ordering::Relaxed))
72    }
73
74    /// Returns the identity as a number
75    ///
76    /// A consumer that keys a map or a widget by the run reads the number here.
77    ///
78    /// # Examples
79    ///
80    /// ```
81    /// use clawless_core::event::process::RunId;
82    ///
83    /// let id = RunId::next();
84    ///
85    /// assert_eq!(id.get(), id.get());
86    /// ```
87    pub fn get(&self) -> u64 {
88        self.0
89    }
90}
91
92/// Shows the identity for a reader
93///
94/// The text is the number alone, so that a log line can name the run without
95/// the punctuation that [`Debug`] adds.
96impl Display for RunId {
97    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
98        Display::fmt(&self.0, formatter)
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    // An assertion in a test panics by design. A `# Panics` section on every test
105    // would repeat that and give the reader no information.
106    #![allow(clippy::missing_panics_doc)]
107
108    use super::*;
109
110    #[test]
111    fn display_returns_the_number() {
112        let id = RunId::next();
113
114        let text = id.to_string();
115
116        assert_eq!(text, id.get().to_string());
117    }
118
119    // r[verify process.event.correlation]
120    // r[verify process.event.correlation.unique]
121    #[test]
122    fn next_returns_a_new_identity_every_time() {
123        let first = RunId::next();
124        let second = RunId::next();
125
126        assert_ne!(first, second);
127    }
128
129    #[test]
130    fn trait_send() {
131        fn assert_send<T: Send>() {}
132        assert_send::<RunId>();
133    }
134
135    #[test]
136    fn trait_sync() {
137        fn assert_sync<T: Sync>() {}
138        assert_sync::<RunId>();
139    }
140
141    #[test]
142    fn trait_unpin() {
143        fn assert_unpin<T: Unpin>() {}
144        assert_unpin::<RunId>();
145    }
146}