@@ -174,6 +174,53 @@ pub trait TableTraverse<T: SingleKey, E: HotKvReadError>: KvTraverse<E> {
174174 fn read_prev ( & mut self ) -> Result < Option < KeyValue < T > > , E > {
175175 KvTraverse :: read_prev ( self ) ?. map ( T :: decode_kv_tuple) . transpose ( ) . map_err ( Into :: into)
176176 }
177+
178+ /// Iterate entries starting from a key while a predicate holds.
179+ ///
180+ /// Positions the cursor at `start_key` and calls `f` for each entry
181+ /// while `predicate` returns true.
182+ ///
183+ /// Returns `Ok(())` on successful completion, or the first error encountered.
184+ fn for_each_while < P , F > ( & mut self , start_key : & T :: Key , predicate : P , mut f : F ) -> Result < ( ) , E >
185+ where
186+ P : Fn ( & T :: Key , & T :: Value ) -> bool ,
187+ F : FnMut ( T :: Key , T :: Value ) -> Result < ( ) , E > ,
188+ {
189+ let Some ( ( k, v) ) = TableTraverse :: lower_bound ( self , start_key) ? else {
190+ return Ok ( ( ) ) ;
191+ } ;
192+
193+ if !predicate ( & k, & v) {
194+ return Ok ( ( ) ) ;
195+ }
196+
197+ f ( k, v) ?;
198+
199+ while let Some ( ( k, v) ) = TableTraverse :: read_next ( self ) ? {
200+ if !predicate ( & k, & v) {
201+ break ;
202+ }
203+ f ( k, v) ?;
204+ }
205+
206+ Ok ( ( ) )
207+ }
208+
209+ /// Collect entries from start_key while predicate holds.
210+ ///
211+ /// This is useful when you need to process entries after iteration completes
212+ /// or when the closure would need to borrow mutably from multiple sources.
213+ fn collect_while < P > ( & mut self , start_key : & T :: Key , predicate : P ) -> Result < Vec < KeyValue < T > > , E >
214+ where
215+ P : Fn ( & T :: Key , & T :: Value ) -> bool ,
216+ {
217+ let mut result = Vec :: new ( ) ;
218+ self . for_each_while ( start_key, predicate, |k, v| {
219+ result. push ( ( k, v) ) ;
220+ Ok ( ( ) )
221+ } ) ?;
222+ Ok ( result)
223+ }
177224}
178225
179226/// Blanket implementation of `TableTraverse` for any cursor that implements `KvTraverse`.
@@ -268,6 +315,94 @@ pub trait DualTableTraverse<T: DualKey, E: HotKvReadError>: DualKeyTraverse<E> {
268315
269316 /// Move to the PREVIOUS key2 entry for the CURRENT key1.
270317 fn previous_k2 ( & mut self ) -> Result < Option < DualKeyValue < T > > , E > ;
318+
319+ /// Iterate entries (crossing k1 boundaries) while a predicate holds.
320+ ///
321+ /// Positions the cursor at `(key1, start_k2)` and calls `f` for each entry
322+ /// while `predicate` returns true. Uses `read_next()` to cross k1 boundaries.
323+ ///
324+ /// Returns `Ok(())` on successful completion, or the first error encountered.
325+ fn for_each_while < P , F > (
326+ & mut self ,
327+ key1 : & T :: Key ,
328+ start_k2 : & T :: Key2 ,
329+ predicate : P ,
330+ mut f : F ,
331+ ) -> Result < ( ) , E >
332+ where
333+ P : Fn ( & T :: Key , & T :: Key2 , & T :: Value ) -> bool ,
334+ F : FnMut ( T :: Key , T :: Key2 , T :: Value ) -> Result < ( ) , E > ,
335+ {
336+ let Some ( ( k1, k2, v) ) = DualTableTraverse :: next_dual_above ( self , key1, start_k2) ? else {
337+ return Ok ( ( ) ) ;
338+ } ;
339+
340+ if !predicate ( & k1, & k2, & v) {
341+ return Ok ( ( ) ) ;
342+ }
343+
344+ f ( k1, k2, v) ?;
345+
346+ while let Some ( ( k1, k2, v) ) = DualTableTraverse :: read_next ( self ) ? {
347+ if !predicate ( & k1, & k2, & v) {
348+ break ;
349+ }
350+ f ( k1, k2, v) ?;
351+ }
352+
353+ Ok ( ( ) )
354+ }
355+
356+ /// Iterate entries within the same k1 while a predicate holds.
357+ ///
358+ /// Positions the cursor at `(key1, start_k2)` and calls `f` for each entry
359+ /// while `predicate` returns true. Uses `next_k2()` which stays within
360+ /// the same k1 value.
361+ ///
362+ /// Returns `Ok(())` on successful completion, or the first error encountered.
363+ fn for_each_while_k2 < P , F > (
364+ & mut self ,
365+ key1 : & T :: Key ,
366+ start_k2 : & T :: Key2 ,
367+ predicate : P ,
368+ f : F ,
369+ ) -> Result < ( ) , E >
370+ where
371+ P : Fn ( & T :: Key , & T :: Key2 , & T :: Value ) -> bool ,
372+ F : FnMut ( T :: Key , T :: Key2 , T :: Value ) -> Result < ( ) , E > ,
373+ {
374+ self . for_each_while ( key1, start_k2, |k, k2, v| key1 == k && predicate ( k, k2, v) , f)
375+ }
376+
377+ /// Iterate all k2 entries for a given k1, starting from `start_k2`.
378+ ///
379+ /// Calls `f` for each (k1, k2, v) tuple where k1 matches the provided key1
380+ /// and k2 >= start_k2. Stops when k1 changes or the table is exhausted.
381+ ///
382+ /// Returns `Ok(())` on successful completion, or the first error encountered.
383+ fn for_each_k2 < F > ( & mut self , key1 : & T :: Key , start_k2 : & T :: Key2 , f : F ) -> Result < ( ) , E >
384+ where
385+ T :: Key : PartialEq ,
386+ F : FnMut ( T :: Key , T :: Key2 , T :: Value ) -> Result < ( ) , E > ,
387+ {
388+ self . for_each_while_k2 ( key1, start_k2, |_, _, _| true , f)
389+ }
390+
391+ /// Collect all k2 entries for a given k1 into a Vec.
392+ ///
393+ /// This is useful when you need to process entries after iteration completes
394+ /// or when the closure would need to borrow mutably from multiple sources.
395+ fn collect_k2 ( & mut self , key1 : & T :: Key , start_k2 : & T :: Key2 ) -> Result < Vec < DualKeyValue < T > > , E >
396+ where
397+ T :: Key : PartialEq ,
398+ {
399+ let mut result = Vec :: new ( ) ;
400+ self . for_each_k2 ( key1, start_k2, |k1, k2, v| {
401+ result. push ( ( k1, k2, v) ) ;
402+ Ok ( ( ) )
403+ } ) ?;
404+ Ok ( result)
405+ }
271406}
272407
273408impl < C , T , E > DualTableTraverse < T , E > for C
@@ -393,6 +528,30 @@ where
393528 pub fn read_prev ( & mut self ) -> Result < Option < KeyValue < T > > , E > {
394529 TableTraverse :: < T , E > :: read_prev ( & mut self . inner )
395530 }
531+
532+ /// Iterate entries starting from a key while a predicate holds.
533+ ///
534+ /// Positions the cursor at `start_key` and calls `f` for each entry
535+ /// while `predicate` returns true.
536+ pub fn for_each_while < P , F > ( & mut self , start_key : & T :: Key , predicate : P , f : F ) -> Result < ( ) , E >
537+ where
538+ P : Fn ( & T :: Key , & T :: Value ) -> bool ,
539+ F : FnMut ( T :: Key , T :: Value ) -> Result < ( ) , E > ,
540+ {
541+ TableTraverse :: < T , E > :: for_each_while ( & mut self . inner , start_key, predicate, f)
542+ }
543+
544+ /// Collect entries from start_key while predicate holds.
545+ pub fn collect_while < P > (
546+ & mut self ,
547+ start_key : & T :: Key ,
548+ predicate : P ,
549+ ) -> Result < Vec < KeyValue < T > > , E >
550+ where
551+ P : Fn ( & T :: Key , & T :: Value ) -> bool ,
552+ {
553+ TableTraverse :: < T , E > :: collect_while ( & mut self . inner , start_key, predicate)
554+ }
396555}
397556
398557impl < C , T , E > TableCursor < C , T , E >
@@ -517,6 +676,67 @@ where
517676 pub fn read_prev ( & mut self ) -> Result < Option < DualKeyValue < T > > , E > {
518677 DualTableTraverse :: < T , E > :: read_prev ( & mut self . inner )
519678 }
679+
680+ /// Iterate all k2 entries for a given k1, starting from `start_k2`.
681+ ///
682+ /// Calls `f` for each (k1, k2, v) tuple where k1 matches the provided key1
683+ /// and k2 >= start_k2. Stops when k1 changes or the table is exhausted.
684+ pub fn for_each_k2 < F > ( & mut self , key1 : & T :: Key , start_k2 : & T :: Key2 , f : F ) -> Result < ( ) , E >
685+ where
686+ T :: Key : PartialEq ,
687+ F : FnMut ( T :: Key , T :: Key2 , T :: Value ) -> Result < ( ) , E > ,
688+ {
689+ DualTableTraverse :: < T , E > :: for_each_k2 ( & mut self . inner , key1, start_k2, f)
690+ }
691+
692+ /// Iterate entries within the same k1 while a predicate holds.
693+ ///
694+ /// Positions the cursor at `(key1, start_k2)` and calls `f` for each entry
695+ /// while `predicate` returns true. Uses `next_k2()` which stays within
696+ /// the same k1 value.
697+ pub fn for_each_while_k2 < P , F > (
698+ & mut self ,
699+ key1 : & T :: Key ,
700+ start_k2 : & T :: Key2 ,
701+ predicate : P ,
702+ f : F ,
703+ ) -> Result < ( ) , E >
704+ where
705+ P : Fn ( & T :: Key , & T :: Key2 , & T :: Value ) -> bool ,
706+ F : FnMut ( T :: Key , T :: Key2 , T :: Value ) -> Result < ( ) , E > ,
707+ {
708+ DualTableTraverse :: < T , E > :: for_each_while_k2 ( & mut self . inner , key1, start_k2, predicate, f)
709+ }
710+
711+ /// Iterate entries (crossing k1 boundaries) while a predicate holds.
712+ ///
713+ /// Positions the cursor at `(key1, start_k2)` and calls `f` for each entry
714+ /// while `predicate` returns true. Uses `read_next()` to cross k1 boundaries.
715+ pub fn for_each_while < P , F > (
716+ & mut self ,
717+ key1 : & T :: Key ,
718+ start_k2 : & T :: Key2 ,
719+ predicate : P ,
720+ f : F ,
721+ ) -> Result < ( ) , E >
722+ where
723+ P : Fn ( & T :: Key , & T :: Key2 , & T :: Value ) -> bool ,
724+ F : FnMut ( T :: Key , T :: Key2 , T :: Value ) -> Result < ( ) , E > ,
725+ {
726+ DualTableTraverse :: < T , E > :: for_each_while ( & mut self . inner , key1, start_k2, predicate, f)
727+ }
728+
729+ /// Collect all k2 entries for a given k1 into a Vec.
730+ pub fn collect_k2 (
731+ & mut self ,
732+ key1 : & T :: Key ,
733+ start_k2 : & T :: Key2 ,
734+ ) -> Result < Vec < DualKeyValue < T > > , E >
735+ where
736+ T :: Key : PartialEq ,
737+ {
738+ DualTableTraverse :: < T , E > :: collect_k2 ( & mut self . inner , key1, start_k2)
739+ }
520740}
521741
522742impl < C , T , E > DualTableCursor < C , T , E >
0 commit comments