ferroui_base/rendering/composition/transport/
batch.rs1use super::BatchStreamData;
2use std::sync::atomic::{AtomicI64, Ordering};
3use std::sync::{Arc, Condvar, Mutex};
4use std::time::Duration;
5
6static NEXT_SEQUENCE_ID: AtomicI64 = AtomicI64::new(1);
7
8type Continuation = Box<dyn FnOnce() + Send>;
9
10#[derive(Default)]
13pub struct BatchCompletion {
14 state: Mutex<CompletionState>,
15 completed: Condvar,
16}
17
18#[derive(Default)]
19struct CompletionState {
20 completed: bool,
21 continuations: Vec<Continuation>,
22}
23
24impl BatchCompletion {
25 pub fn is_completed(&self) -> bool {
27 self.state.lock().unwrap_or_else(|e| e.into_inner()).completed
28 }
29
30 pub fn on_completed(&self, continuation: impl FnOnce() + Send + 'static) {
34 {
35 let mut state = self.state.lock().unwrap_or_else(|e| e.into_inner());
36 if !state.completed {
37 state.continuations.push(Box::new(continuation));
38 return;
39 }
40 }
41 continuation();
42 }
43
44 pub fn wait(&self) {
47 let mut state = self.state.lock().unwrap_or_else(|e| e.into_inner());
48 while !state.completed {
49 state = self.completed.wait(state).unwrap_or_else(|e| e.into_inner());
50 }
51 }
52
53 pub(crate) fn try_set(&self) {
54 let continuations = {
55 let mut state = self.state.lock().unwrap_or_else(|e| e.into_inner());
56 if state.completed {
57 return;
58 }
59 state.completed = true;
60 std::mem::take(&mut state.continuations)
61 };
62 self.completed.notify_all();
63 for continuation in continuations {
64 continuation();
65 }
66 }
67}
68
69pub struct CompositionBatch {
73 sequence_id: i64,
74 processed: BatchCompletion,
75 rendered: BatchCompletion,
76}
77
78impl CompositionBatch {
79 pub(crate) fn new() -> Arc<CompositionBatch> {
80 Arc::new(CompositionBatch {
81 sequence_id: NEXT_SEQUENCE_ID.fetch_add(1, Ordering::SeqCst) + 1,
82 processed: BatchCompletion::default(),
83 rendered: BatchCompletion::default(),
84 })
85 }
86
87 pub fn sequence_id(&self) -> i64 {
89 self.sequence_id
90 }
91
92 pub fn processed(&self) -> &BatchCompletion {
100 &self.processed
101 }
102
103 pub fn rendered(&self) -> &BatchCompletion {
109 &self.rendered
110 }
111
112 pub(crate) fn notify_processed(&self) {
113 self.processed.try_set();
114 }
115
116 pub(crate) fn notify_rendered(&self) {
117 self.rendered.try_set();
118 }
119}
120
121pub struct CommittedBatch {
127 pub(crate) batch: Arc<CompositionBatch>,
128 pub(crate) changes: BatchStreamData,
129 pub(crate) committed_at: Duration,
130}
131
132const _: fn() = || {
135 fn sent<T: Send>() {}
136 sent::<CommittedBatch>();
137};