Associate type with trait

I need to associate some type with trait. This is not about "trait associated types", I need to associate type with trait itself, not it's implementations. And traits may be external, not defined in my code.

Right now I use following approach:

use bla_bla::SomeExternalTrait;

trait HaveAssociatedType {
  type AssociatedType: Default;
}

impl HaveAssociatedType for &'static dyn SomeExternalTrait {
  type AssociatedType = u32;
}

fn use_associated_type<T: ?Sized>() -> <&'static T as HaveAssociatedType>::AssociatedType
    where &'static T: HaveAssociatedType
{
    <&'static T as HaveAssociatedType>::AssociatedType::default()
}

fn main() {
   println!("{:?}", use_associated_type::<dyn SomeExternalTrait>());
}

The problem is that it only works for object-safe traits. Is there any way to make it work for all traits?

Maybe you could tell us more about the reasons why you need this?

The trait object type in Rust isn’t particularly tightly coupled to the trait itself. Sure dyn SomeExternalTrait does implement SomeExternalTrait, and shares its name, but – as your use-case demonstrates – you’ll need to call out the type dyn SomeExternalTrait manually, and the connection to SomeExternalTrait will likely only be convention, in particular if you aren’t actually working with trait objects of that type in your use-case. Which seems to be the case, otherwise you wouldn’t ask about non-object-safe traits.

You could come up with various other conventions. You for instance could define marker types like struct MarkerForSomeExternalTrait; and implement HaveAssociatedType for those. Just yet another convention of calling out a type that has a similar name as the trait to make the connection.

I use it in my mockers library to get mock instance for specified trait, like this:

#[mocked]
trait A {}

#[test]
fn test {
  let scenario = Scenario::new();
  let (mock, handle) = scenario.create_mock_for::<dyn A>();
}

Behind the scene, {TraitName}Mock struct is created, so actually you can use

scenario.create_mock::<AMock>();

But I don't like implicit names, i.e. when you grep your source for AMock, you'll find nothing, so I research two possibilities (non-exclusive):

  1. Make mock name required: #[mocked(mock_name=AMock)]
  2. Make create_mock_for to work for all traits, so you don't have to name mock explicitly.