1use jiff::Zoned;
5use serde::{Deserialize, Serialize};
6use std::cmp::Ordering;
7use std::fmt;
8use std::sync::atomic::AtomicU32;
9use std::sync::atomic::Ordering::Relaxed;
10use tokio::sync::mpsc::UnboundedReceiver;
11
12static ID: AtomicU32 = AtomicU32::new(1);
13
14pub struct Stdio {
15 pub(crate) buffer: Vec<StdioMessage>,
16 receiver: UnboundedReceiver<StdioMessage>,
17}
18
19impl Stdio {
20 pub(crate) fn new(receiver: UnboundedReceiver<StdioMessage>) -> Self {
21 Self { buffer: Vec::new(), receiver }
22 }
23
24 pub(crate) fn flush(&mut self) {
25 while let Ok(message) = self.receiver.try_recv() {
26 self.buffer.push(message);
27 }
28 }
29}
30
31#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
32#[serde(rename_all = "camelCase")]
33pub struct StdioMessage {
34 id: u32,
35 content: String,
36 time: Zoned,
37}
38
39impl StdioMessage {
40 pub(crate) fn new(content: String) -> Self {
41 Self {
42 id: ID.fetch_add(1, Relaxed),
43 content,
44 time: Zoned::now(),
45 }
46 }
47}
48
49impl PartialOrd for StdioMessage {
50 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
51 Some(self.cmp(other))
52 }
53}
54
55impl Ord for StdioMessage {
56 fn cmp(&self, other: &Self) -> Ordering {
57 self
58 .time
59 .cmp(&other.time)
60 .then_with(|| self.id.cmp(&other.id))
61 }
62}
63
64impl fmt::Display for StdioMessage {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 write!(f, "{}", self.content)
67 }
68}