pub fn shuffle_bounded(input: u64, feedback: u64, size: u64, min: u64) -> u64Expand description
Map input into [min, min + size), visiting every value of that
range exactly once per cycle.
The LFSR cannot produce zero, so the range is worked 1-based and
denormalized on the way out. A register that steps past size
is rejected and stepped again, which is what makes a range that is
not a power of two come out whole.
§Degenerate pairs
Three pairs describe no permutation, and all three answer min, the
range’s floor: the empty range below, a feedback that walks the
register to zero, and one that cycles without ever landing in range.
Each is reachable with the node’s own defaults or with the arbitrary
constants a fuzzer supplies, so each is answered in bounded time
rather than trapped. The result is always inside [min, min + size),
or min when that interval is empty.
size == 0 is the empty range [min, min), which has no value to
permute onto, and it is reachable without being asked for: the
node’s size defaults to zero, so shuffle(x) and
shuffle(x, feedback) both land here. It answers min, the range’s
own floor, as hash_range answers 0 for the same degenerate
bound. Left unanswered it is not merely undefined but a trap:
input % size divides by zero, and were that defined the rejection
loop could never terminate, since the register starts at 1 and the
exit condition wants register <= 0.