rmux_sdk/events/
render.rs1use std::time::Duration;
4
5use crate::{Pane, PaneLagNotice, PaneOutputChunk, PaneOutputStream, PaneSnapshot, Result};
6
7const DEFAULT_RENDER_DEBOUNCE: Duration = Duration::from_millis(16);
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct RenderUpdate {
12 snapshot: PaneSnapshot,
13 lag: Option<PaneLagNotice>,
14}
15
16impl RenderUpdate {
17 #[must_use]
19 pub const fn snapshot(&self) -> &PaneSnapshot {
20 &self.snapshot
21 }
22
23 #[must_use]
26 pub const fn lag(&self) -> Option<&PaneLagNotice> {
27 self.lag.as_ref()
28 }
29
30 #[must_use]
32 pub fn into_snapshot(self) -> PaneSnapshot {
33 self.snapshot
34 }
35}
36
37pub struct PaneRenderStream {
45 pane: Pane,
46 output: PaneOutputStream,
47 debounce: Duration,
48 last_revision: Option<u64>,
49 pending_lag: Option<PaneLagNotice>,
50}
51
52impl PaneRenderStream {
53 pub(crate) async fn open(pane: Pane) -> Result<Self> {
54 let output = pane.output_stream().await?;
55 let baseline = pane.snapshot().await?;
56 Ok(Self {
57 pane,
58 output,
59 debounce: DEFAULT_RENDER_DEBOUNCE,
60 last_revision: Some(baseline.revision),
61 pending_lag: None,
62 })
63 }
64
65 #[must_use]
67 pub const fn with_debounce(mut self, debounce: Duration) -> Self {
68 self.debounce = debounce;
69 self
70 }
71
72 pub async fn next(&mut self) -> Result<Option<RenderUpdate>> {
75 loop {
76 let Some(chunk) = self.output.next().await? else {
77 return Ok(None);
78 };
79 if let PaneOutputChunk::Lag(lag) = chunk {
80 self.pending_lag = Some(lag);
81 }
82
83 if !self.debounce.is_zero() {
84 tokio::time::sleep(self.debounce).await;
85 }
86
87 let snapshot = self.pane.snapshot().await?;
88 if self.last_revision == Some(snapshot.revision) {
89 continue;
90 }
91 self.last_revision = Some(snapshot.revision);
92 return Ok(Some(RenderUpdate {
93 snapshot,
94 lag: self.pending_lag.take(),
95 }));
96 }
97 }
98}
99
100impl std::fmt::Debug for PaneRenderStream {
101 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 formatter
103 .debug_struct("PaneRenderStream")
104 .field("pane", &self.pane)
105 .field("debounce", &self.debounce)
106 .field("last_revision", &self.last_revision)
107 .field("pending_lag", &self.pending_lag)
108 .finish_non_exhaustive()
109 }
110}