We have next_if and some other methods for conditional iteration over Peekable. The problem is that these methods are not really composable. Usually it is easier to use peek, do something with the peeked value and then do .next().unwrap(). This unwrap feels unnecessary and never fails if the value is already peeked and known to be there. Hence the following idea.
I propose to add a method for Peekable<I> with the following signature (the names here are temporary, of course):
Calling the first method is equivalent to peek()ing.
The second one equivalent to next(), but there is no unnecessary Option now.
I think the described interface cannot be implemented without using Peekable's internals or unsafe. Here is an implementation sketch with unsafe: Compiler Explorer. There is also an implementation of "merge iterator" using the proposed interface.
There's Peekable::next_if_map which acts similarly, but your API can do a few things it can't (although it isn't very good at doing the "map" part of that API). It reminds me of the difference between the normal map APIs and the entry-based APIs.
Note that if your API offers enough over next_if_map to be worth adding as a stable API, it should probably have a Peeked::get_mut (which allows changing the value in the peek slot): I can't think of any reason not to add it and it would be consistent with the other APIs.
While next_if_map is indeed useful, I couldn't come up with an implementation of next() for MergeIter (see the attached compiler explorer link) without a single unwrap. At least nothing straightforward comes to my mind.
You can implement this without unwrap by comparing the Options a.peek() and b.peek() to decide which of the iterators to return the value of next() from. (Note that you will need to use a comparison that sorts Some before None and low Some before high Some, which I don't think is built-in in Option, but it is easy enough to implement.) This avoids unwrapping because all you're doing is deciding which iterator to iterate on, and if you're taking a value from an empty iterator it is because both are exhausted, so you can return the None you get directly.
I'm not sure whether or not this technique generalises, but it is at least pretty good for iterator adaptors (and might generate simpler code than you get with Peeked).