s2n_quic_core/transmission/
interest.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::transmission::Constraint;
5
6#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
7pub enum Interest {
8    None,
9    NewData,
10    LostData,
11    Forced,
12}
13
14impl Default for Interest {
15    #[inline]
16    fn default() -> Self {
17        Self::None
18    }
19}
20
21impl Interest {
22    #[inline]
23    pub fn can_transmit(self, limit: Constraint) -> bool {
24        match (self, limit) {
25            // nothing can be transmitted when we're at amplification limits
26            (_, Constraint::AmplificationLimited) => false,
27
28            // a component wants to try to recover so ignore limits
29            (Interest::Forced, _) => true,
30
31            // transmit lost data when we're either not limited, probing, or we want to do a fast
32            // retransmission to try to recover
33            (Interest::LostData, _) => limit.can_retransmit(),
34
35            // new data may only be transmitted when we're not limited or probing
36            (Interest::NewData, _) => limit.can_transmit(),
37
38            // nothing is interested in transmitting anything
39            (Interest::None, _) => false,
40        }
41    }
42
43    #[inline]
44    pub fn is_none(self) -> bool {
45        matches!(self, Interest::None)
46    }
47
48    #[inline]
49    pub fn merge_with<F: FnOnce(&mut Self) -> Result>(&mut self, f: F) -> Result {
50        f(self)
51    }
52}
53
54pub trait Provider {
55    fn transmission_interest<Q: Query>(&self, query: &mut Q) -> Result;
56
57    #[inline]
58    fn get_transmission_interest(&self) -> Interest {
59        let mut interest = Interest::None;
60        let _ = self.transmission_interest(&mut interest);
61        interest
62    }
63
64    #[inline]
65    fn has_transmission_interest(&self) -> bool {
66        let mut query = HasTransmissionInterestQuery;
67        self.transmission_interest(&mut query).is_err()
68    }
69
70    #[inline]
71    fn can_transmit(&self, mut constraint: Constraint) -> bool {
72        self.transmission_interest(&mut constraint).is_err()
73    }
74}
75
76pub trait Query {
77    fn on_interest(&mut self, interest: Interest) -> Result;
78
79    #[inline]
80    fn on_new_data(&mut self) -> Result {
81        self.on_interest(Interest::NewData)
82    }
83
84    #[inline]
85    fn on_lost_data(&mut self) -> Result {
86        self.on_interest(Interest::LostData)
87    }
88
89    #[inline]
90    fn on_forced(&mut self) -> Result {
91        self.on_interest(Interest::Forced)
92    }
93}
94
95impl Query for Interest {
96    #[inline]
97    fn on_interest(&mut self, interest: Interest) -> Result {
98        match (*self, interest) {
99            // we don't need to keep querying if we're already at the max interest
100            (Interest::Forced, _) | (_, Interest::Forced) => {
101                *self = Interest::Forced;
102                return Err(QueryBreak);
103            }
104            (Interest::LostData, _) | (_, Interest::LostData) => *self = Interest::LostData,
105            (Interest::NewData, _) | (_, Interest::NewData) => *self = Interest::NewData,
106            (Interest::None, _) => {}
107        }
108
109        Ok(())
110    }
111}
112
113impl Query for Constraint {
114    #[inline]
115    fn on_interest(&mut self, interest: Interest) -> Result {
116        // If we can transmit with the given constraint bail since we now have an answer
117        if interest.can_transmit(*self) {
118            return Err(QueryBreak);
119        }
120
121        Ok(())
122    }
123}
124
125pub struct HasTransmissionInterestQuery;
126
127impl Query for HasTransmissionInterestQuery {
128    #[inline]
129    fn on_interest(&mut self, interest: Interest) -> Result {
130        if interest.is_none() {
131            Ok(())
132        } else {
133            // If we've got anything other than `None` then bail since we now have an answer
134            Err(QueryBreak)
135        }
136    }
137
138    // any calls to interest should bail the query
139    #[inline]
140    fn on_new_data(&mut self) -> Result {
141        Err(QueryBreak)
142    }
143
144    #[inline]
145    fn on_lost_data(&mut self) -> Result {
146        Err(QueryBreak)
147    }
148
149    #[inline]
150    fn on_forced(&mut self) -> Result {
151        Err(QueryBreak)
152    }
153}
154
155#[cfg(feature = "std")]
156pub struct Debugger;
157
158#[cfg(feature = "std")]
159impl Query for Debugger {
160    #[inline]
161    #[track_caller]
162    fn on_interest(&mut self, interest: Interest) -> Result {
163        eprintln!("  {} - {:?}", core::panic::Location::caller(), interest);
164        Ok(())
165    }
166
167    #[inline]
168    #[track_caller]
169    fn on_new_data(&mut self) -> Result {
170        eprintln!(
171            "  {} - {:?}",
172            core::panic::Location::caller(),
173            Interest::NewData
174        );
175        Ok(())
176    }
177
178    #[inline]
179    #[track_caller]
180    fn on_lost_data(&mut self) -> Result {
181        eprintln!(
182            "  {} - {:?}",
183            core::panic::Location::caller(),
184            Interest::LostData
185        );
186        Ok(())
187    }
188
189    #[inline]
190    #[track_caller]
191    fn on_forced(&mut self) -> Result {
192        eprintln!(
193            "  {} - {:?}",
194            core::panic::Location::caller(),
195            Interest::Forced
196        );
197        Ok(())
198    }
199}
200
201pub struct QueryBreak;
202
203pub type Result<T = (), E = QueryBreak> = core::result::Result<T, E>;
204
205#[cfg(test)]
206mod test {
207    use crate::transmission::{
208        interest::Query,
209        Constraint,
210        Constraint::*,
211        Interest::{None, *},
212    };
213
214    #[test]
215    fn ordering_test() {
216        assert!(None < NewData);
217        assert!(NewData < LostData);
218        assert!(LostData < Forced);
219    }
220
221    #[test]
222    fn interest_query_test() {
223        let levels = [None, NewData, LostData, Forced];
224        for a in levels.iter().copied() {
225            for b in levels.iter().copied() {
226                let mut query = a;
227                let result = query.on_interest(b);
228
229                assert_eq!(query, a.max(b));
230                assert_eq!(matches!(a, Forced) || matches!(b, Forced), result.is_err());
231            }
232        }
233    }
234
235    #[test]
236    fn can_transmit() {
237        // Amplification Limited
238        assert!(!None.can_transmit(AmplificationLimited));
239        assert!(!NewData.can_transmit(AmplificationLimited));
240        assert!(!LostData.can_transmit(AmplificationLimited));
241        assert!(!Forced.can_transmit(AmplificationLimited));
242
243        // Congestion Limited
244        assert!(!None.can_transmit(CongestionLimited));
245        assert!(!NewData.can_transmit(CongestionLimited));
246        assert!(!LostData.can_transmit(CongestionLimited));
247        assert!(Forced.can_transmit(CongestionLimited));
248
249        // Retransmission Only
250        assert!(!None.can_transmit(RetransmissionOnly));
251        assert!(!NewData.can_transmit(RetransmissionOnly));
252        assert!(LostData.can_transmit(RetransmissionOnly));
253        assert!(Forced.can_transmit(RetransmissionOnly));
254
255        // No Constraint
256        assert!(!None.can_transmit(Constraint::None));
257        assert!(NewData.can_transmit(Constraint::None));
258        assert!(LostData.can_transmit(Constraint::None));
259        assert!(Forced.can_transmit(Constraint::None));
260    }
261}