Using std::io::Read implementation for RngCore

use rand_chacha; // 0.3.0
use rand_chacha::rand_core::SeedableRng;

fn main() {
    let mut rng = rand_chacha::ChaCha20Rng::from_entropy();
    let mut a = [0u8; 16];
    rng.read(&mut a[..]);
}

(Playground)

According to the docs, the rand_chacha::ChaCha20Rng implements RngCore, which should in turn provide an implementation of std::io::Read (at least since rand_core 0.6, which rand_chacha 0.3 should be using). However, I cannot manage to use this std::io::Read implementation. (Adding use std::io::Read; just gives an unused import warning). Am I missing something obvious here? Does it have something to do with the impl std::io::Read for dyn RngCore in rand/lib.rs at 30d2d98df5d09c524a30c8772fc7c8b203f5b70a · rust-random/rand · GitHub?
I haven't really seen that impl for dyn Trait syntax before.

Thanks in advance!

Yes, ìmpl Read for dyn RngCore is different from impl<R: RngCore> Read for R, which is maybe what you're thinking of. dyn RngCore is its own type that can have trait impls, and it's different from ChaCha20Rng or any other type that happens to implement RngCore.

It looks like you can use the RngCore::fill_bytes method to accomplish your goal here:

use rand_chacha; // 0.3.0
use rand_chacha::rand_core::{RngCore, SeedableRng};

fn main() {
    let mut rng = rand_chacha::ChaCha20Rng::from_entropy();
    let mut a = [0u8; 16];
    rng.fill_bytes(&mut a[..]);
}

If you really want to use the Read trait you see implemented, you could do something like
(&mut rng as &mut dyn RngCore).read(&mut a[..]);

I don't think there is much value in that exact usage, but it could be useful for something needing a Read generic bound, or if you want to use some of the other methods provided by the Read trait.

1 Like

Thanks, that's what I was looking for since I have a generic Read bound.

Is there any specific reason for the current impl Read for dyn RngCore implementation as opposed to impl<R: RngCore> Read for R that cole-miller mentioned?

I don't think the orphan rules allow writing a blanket impl in rand_core for a foreign trait like Read. And Read also already has a blanket impl in std, which could overlap with a second blanket impl in rand_core if that were allowed.

Ah, yes, that makes sense, forgot that the orphan rule applies here.

Thanks for the explanations!