Better way to handle implementing trait for generics?

I'm working on a new crate: GitHub - SUPERCILEX/io-adapters: Adapters to convert between different writable APIs.

And I'm wondering if there's a better interface than this:

pub trait WriteExtension<T> {
    type Adapter<'a>
    where
        Self: 'a;

    fn write_adapter(&mut self) -> Self::Adapter<'_>;
}

impl<W: io::Write> WriteExtension<Struct1<W>> for W {
    type Adapter<'a> = Struct1<&'a mut W> where W: 'a;

    fn write_adapter(&mut self) -> Struct1<&mut W>
}

impl<H: Hasher> WriteExtension<Struct2<H>> for H {
    type Adapter<'a> = Struct2<&'a mut H> where H: 'a;

    fn write_adapter(&mut self) -> Struct2<&mut H>
}

Originally I tried to just make WriteExtension generic, but the output of write_adapter needs to access the lifetime of self, so I'm pretty sure that doesn't work. Next, I tried using only associated types, but the issue there is that my two WriteExtension impls conflict. So finally I added back a generic that I don't use in the trait just so I can get the trait resolver to play nice.

Is there not a simpler way to do this?

You could make them different traits, since the implementations do different things anyway (return an io::Writer, or return a fmt::Writer). In a sense you've already done that by turning your trait into a "trait constructor" by adding the parameter.

If you do this, you don't need the GAT and you can optionally give them different names if you find it's ambiguous a lot.

pub trait WriteExtension {
    fn write_adapter(&mut self) -> Struct1<&mut Self>;
}

pub trait HashExtension {
    fn write_adapter(&mut self) -> Struct2<&mut Self>;
}

If you keep the generic version you might supply some meaningfully named marker structs.

pub struct IoToFmt;
impl<W: io::Write> WriteExtension<IoToFmt> for W { /* ... */ }

pub struct HashToIo;
impl<H: Hasher> WriteExtension<HashToIo> for H { /* ... */ }

They sort of name the outputs of your trait constructor.

I see, thanks for the help! I decided to go the clear trait constructor output names route as I'd like users to be able to import a single trait and get all the adapters.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.