How to define non-auto trait bounds for associated types?

Greetings!

I'm trying to implement a seedable and serializable random number generator for my game. The seed type should be kept generic if possible, but when trying to define trait bounds for it, the compiler disagrees.

Note: This is running nightly-2019-07-19

#[derive(Clone, Debug)]
pub struct GameRng<T> {
    inner: T,
}


impl<T: Rng + 'static> GameRng<T> {
    pub fn new(inner: T) -> GameRng<T> {
        GameRng { inner }
    }
}

impl<T: SeedableRng + Rng + 'static> SeedableRng for GameRng<T> {
    type Seed = dyn Default + Sized + AsMut<[u8]>;

    fn from_seed(seed: S) -> GameRng<T> {
        GameRng::new(SeedableRng::from_seed(seed))
    }
}

The above code yields the following error message:

error[E0225]: only auto traits can be used as additional traits in a trait object
  --> src/util/game_rng.rs:44:31
   |
44 |     type Seed = dyn Default + Sized + AsMut<[u8]>;
   |                     -------   ^^^^^
   |                     |         |
   |                     |         additional non-auto trait
   |                     |         trait alias used in trait object type (additional use)
   |                     first non-auto trait
   |                     trait alias used in trait object type (first use)

I understand one possible workaround is to define a custom seed type that implements Default and AsMut, but any rng that we substitute T with should have an associated seed type already. Is there a way to refer to that?

Yeah, sure:

impl<T: SeedableRng + Rng + 'static> SeedableRng for GameRng<T> {
    type Seed = <T as SeedableRng>::Seed;
    //...
}

Although do note that your previous attempt at using a trait object is odd, because it's illogical to enforce a trait object to be dyn Sized, it doesn't mean anything because the very nature of a trait object is being unsized because it doesn't have a defined backing struct.

Thank you very much, talk about not seeing the forest for the trees. The syntax seems very obvious now.

it's illogical to enforce a trait object to be dyn Sized , it doesn't mean anything because the very nature of a trait object is being unsized because it doesn't have a defined backing struct .

I thought this is used to enforce that the implementing type has a known size at compile time. But yeah that doesn't make much sense for a trait object.

1 Like

Also to note is that you cannot coerce an unsized object into another unsized object of a different type. For example I cannot go from &[T] to &dyn Index<usize, Output = T>