@@ -263,20 +263,32 @@ fn extract_term_set_query_fields(
263263 Ok ( visitor. term_dict_fields_to_warm_up )
264264}
265265
266+ /// Converts a `prefix` term into the equivalent term range.
267+ ///
268+ /// The resulting range is `[prefix, next_prefix)`, that is:
269+ /// - start bound: `Included(prefix)`
270+ /// - end bound: `Excluded(next lexicographic term after the prefix)`
271+ ///
272+ /// "abc" -> start: "abc", end: "abd" (excluded)
273+ /// "ab\xFF" -> start: "ab\xFF", end: "ac" (excluded)
274+ /// "\xFF\xFF" -> start: "\xFF\xFF", end: Unbounded
266275fn prefix_term_to_range ( prefix : Term ) -> ( Bound < Term > , Bound < Term > ) {
267- let mut end_bound = prefix. serialized_term ( ) . to_vec ( ) ;
268- while !end_bound. is_empty ( ) {
269- let last_byte = end_bound. last_mut ( ) . unwrap ( ) ;
276+ // Start from the given prefix and try to find the successor
277+ let mut end_bound = prefix. clone ( ) ;
278+ let mut end_bound_value_bytes = prefix. serialized_value_bytes ( ) . to_vec ( ) ;
279+ while !end_bound_value_bytes. is_empty ( ) {
280+ let last_byte = end_bound_value_bytes. last_mut ( ) . unwrap ( ) ;
270281 if * last_byte != u8:: MAX {
271282 * last_byte += 1 ;
272- return (
273- Bound :: Included ( prefix ) ,
274- Bound :: Excluded ( Term :: wrap ( end_bound) ) ,
275- ) ;
283+ // The last non-`u8::MAX` byte incremented
284+ // gives us the exclusive upper bound.
285+ end_bound. set_bytes ( & end_bound_value_bytes ) ;
286+ return ( Bound :: Included ( prefix ) , Bound :: Excluded ( end_bound ) ) ;
276287 }
277- end_bound. pop ( ) ;
288+ // pop u8::MAX byte and try next
289+ end_bound_value_bytes. pop ( ) ;
278290 }
279- // prefix is something like [255, 255, ..]
291+ // All bytes were `u8::MAX`: there is no successor, so the upper bound is unbounded.
280292 ( Bound :: Included ( prefix) , Bound :: Unbounded )
281293}
282294
0 commit comments