If you are willing to use const generics in any capacity, my crate staticvec has several examples of doing exactly this kind of thing that you might find useful as a reference.
Thanks for the review! I had forgotten about Ordering::*, thanks for that.
I don't follow your last comment, however. What's a ZST? As for the calculation, how is it different?
A ZST is a Zero-Sized Type, such as struct Foo;, struct Foo {}, enum Foo { OneVariant }, PhantomData<_>, [_; 0], or anything recursively made of ZSTs exclusively.
Since an instance of a ZST is zero-sized, it is perfectly possible to have arrays / slices made of a ZST with a gigantic number of elements, such as usize::MAX elements.
In that case, if the element we are looking for is on the right half of such a gigantic array, the expression (start + stop) / 2overflows usize when computing start + stop; then...
either this panic!s when overflow-checks are enabled (enabled by default on debug; disabled by default on release)
or it leads to a logic bug.
To see how, let's imagine that usize is u8 (to use smaller numbers). Then usize::MAX == 255 and if we go over it we "wrap around" as if 256 were 0 (one can imagine a clock having 256 hours).
Then if the first comparison yields Less, we have start = 127 and stop = 255, and when computing mid, instead of mid = start + (stop - start) / 2 = 191, we get: mid = (start + stop) / 2 = (127 + 255) / 2 = 126 / 2 = 63
since 1_u8 + 255_u8 = 0_u8
It's not very practical to find a ZST though, since there's only one possible value, empty. A vector of ZSTs is basically just a glorified counter for its length.
That's a good point. I guess a binary search over ZSTs can always just return the first item? Given that Ord requires Eq which requires a == a, it seems like all instances of a ZST must be equal.