@@ -58,38 +58,56 @@ where
5858 G : crate :: SizedGenerator < ' a , Output = T > ,
5959 G :: Error : ' a ,
6060 {
61- // If we are at context cap, search by_size for templates <= budget and
62- // return a random choice. If we are not at context cap, call
63- // generator with the budget and then store the result
64- // for future use in `by_size`.
61+ self . fetch_mut ( rng, budget) . map ( |template| & * template)
62+ }
63+
64+ /// Return a mutable reference to an item from the pool.
65+ ///
66+ /// Callers that model cumulative protocol state update this stored template
67+ /// so later selections of the same template retain their prior values.
68+ pub ( crate ) fn fetch_mut < ' a , R > (
69+ & ' a mut self ,
70+ rng : & mut R ,
71+ budget : & mut usize ,
72+ ) -> Result < & ' a mut T , PoolError < G :: Error > >
73+ where
74+ R : Rng + ?Sized ,
75+ G : crate :: SizedGenerator < ' a , Output = T > ,
76+ G :: Error : ' a ,
77+ {
78+ // If we are at context cap, search by_size for templates within the
79+ // budget. Otherwise, generate and store one additional template before
80+ // selecting a random eligible template.
6581 //
6682 // Size search is in the interval (0, budget].
67-
6883 let upper = * budget;
6984
7085 // Generate new instances until either context_cap is hit or the
71- // remaining space drops below our lookup interval .
86+ // remaining storage budget is exhausted .
7287 if self . len < self . context_cap && self . consumed_bytes < self . max_available_bytes {
7388 let mut limit = * budget;
7489 if let Ok ( item) = self . generator . generate ( rng, & mut limit) {
75- let sz = item. encoded_len ( ) ;
76- self . by_size . entry ( sz ) . or_default ( ) . push ( item) ;
90+ let size = item. encoded_len ( ) ;
91+ self . by_size . entry ( size ) . or_default ( ) . push ( item) ;
7792 self . len += 1 ;
78- self . consumed_bytes = self . consumed_bytes . saturating_add ( sz) ;
79- } else {
80- // Generation failed. It's possible there's an existing
81- // template that fits the budget.
93+ self . consumed_bytes = self . consumed_bytes . saturating_add ( size) ;
8294 }
8395 }
96+ // A generation failure does not prevent selecting an existing template
97+ // that fits the requested budget.
8498
85- let ( choice_sz , choices ) = self
99+ let choice_size = * self
86100 . by_size
87101 . range ( ..=upper)
102+ . map ( |( size, _) | size)
88103 . choose ( rng)
89104 . ok_or ( PoolError :: EmptyChoice ) ?;
90-
91- let choice = choices. choose ( rng) . ok_or ( PoolError :: EmptyChoice ) ?;
92- * budget = budget. saturating_sub ( * choice_sz) ;
105+ let choices = self
106+ . by_size
107+ . get_mut ( & choice_size)
108+ . ok_or ( PoolError :: EmptyChoice ) ?;
109+ let choice = choices. choose_mut ( rng) . ok_or ( PoolError :: EmptyChoice ) ?;
110+ * budget = budget. saturating_sub ( choice_size) ;
93111
94112 Ok ( choice)
95113 }
0 commit comments