@@ -231,6 +231,116 @@ impl CongestionController for CongestionControlImplementation {
231231 }
232232}
233233
234+ /// A concrete congestion controller, dispatching across all combinations of
235+ /// algorithm and slow-start strategy.
236+ ///
237+ /// This enum avoids the heap allocation and vtable indirection of `Box<dyn CongestionController>`
238+ /// on the per-packet hot path.
239+ #[ derive( Debug , strum:: Display ) ]
240+ pub enum CongestionControlImplementation {
241+ #[ strum( to_string = "{0}" ) ]
242+ ClassicNewReno ( ClassicCongestionController < ClassicSlowStart , NewReno > ) ,
243+ #[ strum( to_string = "{0}" ) ]
244+ HyStartNewReno ( ClassicCongestionController < HyStart , NewReno > ) ,
245+ #[ strum( to_string = "{0}" ) ]
246+ ClassicCubic ( ClassicCongestionController < ClassicSlowStart , Cubic > ) ,
247+ #[ strum( to_string = "{0}" ) ]
248+ HyStartCubic ( ClassicCongestionController < HyStart , Cubic > ) ,
249+ }
250+
251+ macro_rules! dispatch {
252+ ( $self: ident . $method: ident $args: tt) => {
253+ neqo_common:: dispatch!(
254+ [ ClassicNewReno , HyStartNewReno , ClassicCubic , HyStartCubic ]
255+ $self . $method $args
256+ )
257+ } ;
258+ }
259+
260+ impl CongestionController for CongestionControlImplementation {
261+ fn set_qlog ( & mut self , qlog : Qlog ) {
262+ dispatch ! ( self . set_qlog( qlog) ) ;
263+ }
264+
265+ fn cwnd ( & self ) -> usize {
266+ dispatch ! ( self . cwnd( ) )
267+ }
268+
269+ fn bytes_in_flight ( & self ) -> usize {
270+ dispatch ! ( self . bytes_in_flight( ) )
271+ }
272+
273+ fn cwnd_avail ( & self ) -> usize {
274+ dispatch ! ( self . cwnd_avail( ) )
275+ }
276+
277+ fn cwnd_min ( & self ) -> usize {
278+ dispatch ! ( self . cwnd_min( ) )
279+ }
280+
281+ fn pmtud ( & self ) -> & Pmtud {
282+ dispatch ! ( self . pmtud( ) )
283+ }
284+
285+ fn pmtud_mut ( & mut self ) -> & mut Pmtud {
286+ dispatch ! ( self . pmtud_mut( ) )
287+ }
288+
289+ fn on_packets_acked (
290+ & mut self ,
291+ acked_pkts : & [ sent:: Packet ] ,
292+ rtt_est : & RttEstimate ,
293+ now : Instant ,
294+ cc_stats : & mut CongestionControlStats ,
295+ ) {
296+ dispatch ! ( self . on_packets_acked( acked_pkts, rtt_est, now, cc_stats) ) ;
297+ }
298+
299+ fn on_packets_lost (
300+ & mut self ,
301+ first_rtt_sample_time : Option < Instant > ,
302+ prev_largest_acked_sent : Option < Instant > ,
303+ pto : Duration ,
304+ lost_packets : & [ sent:: Packet ] ,
305+ now : Instant ,
306+ cc_stats : & mut CongestionControlStats ,
307+ ) -> bool {
308+ dispatch ! ( self . on_packets_lost(
309+ first_rtt_sample_time,
310+ prev_largest_acked_sent,
311+ pto,
312+ lost_packets,
313+ now,
314+ cc_stats,
315+ ) )
316+ }
317+
318+ fn on_ecn_ce_received (
319+ & mut self ,
320+ largest_acked_pkt : & sent:: Packet ,
321+ now : Instant ,
322+ cc_stats : & mut CongestionControlStats ,
323+ ) -> bool {
324+ dispatch ! ( self . on_ecn_ce_received( largest_acked_pkt, now, cc_stats) )
325+ }
326+
327+ fn recovery_packet ( & self ) -> bool {
328+ dispatch ! ( self . recovery_packet( ) )
329+ }
330+
331+ fn discard ( & mut self , pkt : & sent:: Packet , now : Instant ) {
332+ dispatch ! ( self . discard( pkt, now) ) ;
333+ }
334+
335+ fn on_packet_sent ( & mut self , pkt : & sent:: Packet , now : Instant ) {
336+ dispatch ! ( self . on_packet_sent( pkt, now) ) ;
337+ }
338+
339+ fn discard_in_flight ( & mut self , now : Instant ) {
340+ dispatch ! ( self . discard_in_flight( now) ) ;
341+ }
342+ }
343+
234344#[ cfg( test) ]
235345#[ cfg_attr( coverage_nightly, coverage( off) ) ]
236346mod tests;
0 commit comments