3

How can I achieve the following (pseudo Rust) with stable Rust?

pub fn read<T: Read>(stream: T) {
    let stream = if T implements BufRead {
        stream
    } else {
        BufReader::new(stream)
    };

    // Work with `stream`
}

I know about impl specialization, however I want to achieve the same thing with stable Rust.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
torkleyy
  • 1,137
  • 9
  • 26

2 Answers2

4

You don't. The entire reason that the RFC exists is because it wasn't possible before!

As "proof", consider str::to_string. Before specialization existed, str::to_string used the exact same mechanism as all the other implementors of ToString, which meant that it had to build up and use the formatting infrastructure. This is relatively expensive and benchmarks actively showed the difference between str::to_string and str::to_owned or String::from. After specialization was enabled, the Rust compiler used it for str::to_string, and the benchmarks improved.

If the Rust compiler couldn't specialize before specialization, it's highly unlikely that other code could find some way to work around it in a generic manner.


For your specific case, I agree that you should just accept something implementing BufRead (fn read<T: BufRead>(stream: T)).

Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
4

In terms of pure Rust, with difficulty:

  • Stable does not have specialization
  • Rust does not have down-casting

That being said, there are alternatives such as the query_interfaces crate which promote principled down-casting.

In essence, you want to let the caller tell you whether BufRead is implemented for the stream in question. query_interfaces or a dedicated purpose solution can be created to ship "optional" v-pointers.

However, I would simply require BufRead to be implement by stream. The caller can always wrap their stream with BufRead::new if they need.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722