Yeah, my use cases are a combination of burntsushi's and dbaupp's answers.
1. As dbaupp said, there are some convenience methods which don't actually depend on a buffer being any kind of string, and would be just as useful for an &[u8] containing true binary data, or even arbitrary &[T] - yet currently are only implemented for &str. For example, find(), for finding the index of a substring/subsequence.
If that was all I wanted, though, I wouldn't be talking about wanting a separate type. So:
2. As burntsushi said, sometimes you have strings that ought to be UTF-8, but might be invalid. If they're invalid, I don't care about displaying the string correctly, but I still want to be able to round-trip between the source (perhaps an on-disk binary format, perhaps FFI with C/C++) and the native Rust representation, without crashing or doing a lossy conversion.
3. A similar use case is strings that could have any representation… that is a superset of ASCII. For example, this is typically a guarantee for locale character encodings on Unix systems - that is, if you want to properly handle legacy locales rather than just assuming UTF-8 (which reduces to the previous case). It also applies to legacy "text-based" formats and network protocols such as IRC. For some use cases, you'd need to actually know what character encoding is in use and convert between it and Unicode. But for many uses, you only need to locate, replace, split, or join based on known ASCII delimiters. And since the environment locale setting is not necessarily reliable (or in the case of network protocols, isn't meaningful at all), if you can do what you need with that alone, you should. For example, in the case of IRC, a low-level protocol implementation would ideally use byte strings for everything, and outsource the decision of how to decode messages to the client. It's not good enough to make the encoding a configurable setting: even if, say, the client wants to interpret all strings as UTF-8, if someone creates a chat channel whose name is invalid UTF-8, the client should still be able to ask the low-level implementation to join the channel, send messages to it, etc., which requires echoing its name back to the server.
This isn't actually all that different from the pure binary use case, since locating, replacing, splitting, and joining is also useful for arbitrary binary data. Unlike the "possibly invalid UTF-8" use case, you don't want any normal code paths to try to interpret the data as UTF-8. However, it would still be useful if the Debug impl did so.