Skip to main content

trueno/brick/patterns/
dual_waker_state.rs

1//! AWP-03: Dual-Waker Payload Backpressure
2
3/// Dual-waker state for async backpressure.
4///
5/// Tracks two wakers: one for the producer, one for the consumer.
6/// Enables efficient producer/consumer coordination.
7#[derive(Debug, Default)]
8pub struct DualWakerState {
9    /// Producer is waiting
10    producer_waiting: bool,
11    /// Consumer is waiting
12    consumer_waiting: bool,
13    /// Buffer fill level (0-100%)
14    fill_percent: u8,
15    /// High watermark for backpressure (%)
16    high_watermark: u8,
17    /// Low watermark for resume (%)
18    low_watermark: u8,
19}
20
21impl DualWakerState {
22    /// Create new state with watermarks.
23    pub fn new(low_watermark: u8, high_watermark: u8) -> Self {
24        Self {
25            producer_waiting: false,
26            consumer_waiting: false,
27            fill_percent: 0,
28            high_watermark: high_watermark.min(100),
29            low_watermark: low_watermark.min(high_watermark),
30        }
31    }
32
33    /// Update fill level and determine who should wake.
34    pub fn update_fill(&mut self, fill_percent: u8) -> WakeDecision {
35        let old_fill = self.fill_percent;
36        self.fill_percent = fill_percent.min(100);
37
38        // Crossed high watermark going up - pause producer
39        if old_fill < self.high_watermark && self.fill_percent >= self.high_watermark {
40            return WakeDecision::PauseProducer;
41        }
42
43        // Crossed low watermark going down - resume producer
44        if old_fill > self.low_watermark && self.fill_percent <= self.low_watermark {
45            return WakeDecision::WakeProducer;
46        }
47
48        // Data available - wake consumer if waiting
49        if self.fill_percent > 0 && self.consumer_waiting {
50            return WakeDecision::WakeConsumer;
51        }
52
53        WakeDecision::None
54    }
55
56    /// Producer is now waiting.
57    pub fn producer_wait(&mut self) {
58        self.producer_waiting = true;
59    }
60
61    /// Consumer is now waiting.
62    pub fn consumer_wait(&mut self) {
63        self.consumer_waiting = true;
64    }
65
66    /// Producer was woken.
67    pub fn producer_woke(&mut self) {
68        self.producer_waiting = false;
69    }
70
71    /// Consumer was woken.
72    pub fn consumer_woke(&mut self) {
73        self.consumer_waiting = false;
74    }
75
76    /// Check if producer should be allowed to produce.
77    #[must_use]
78    pub fn can_produce(&self) -> bool {
79        self.fill_percent < self.high_watermark
80    }
81
82    /// Check if consumer has data to consume.
83    #[must_use]
84    pub fn can_consume(&self) -> bool {
85        self.fill_percent > 0
86    }
87}
88
89/// Decision on which waker to invoke.
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91pub enum WakeDecision {
92    /// No action needed
93    None,
94    /// Wake the producer (buffer drained below low watermark)
95    WakeProducer,
96    /// Wake the consumer (data available)
97    WakeConsumer,
98    /// Pause the producer (buffer above high watermark)
99    PauseProducer,
100}