Method that accepts different values that all implement same trait

FWIW, and this is kind of what erased-serde will end up doing, anyways, you can offer a dyn-safe "frontend" for the crate.

  1. Your objective:

  2. From there, the key function is https://docs.rs/rmp-serde/0.15.4/rmp_serde/encode/fn.write_named.html:

    fn write_named<W: ?Sized, T: ?Sized>(
        wr: &mut W, 
        val: &T
    ) -> Result<(), Error> 
    where
        W: Write,
        T: Serialize, // <- we target this trait, so this shall be Self
    

    becoming the trait's method (val -> self, T -> Self):

    //                  frontend trait
    //                  vvvvvvvvvvvvv
    impl<T : Serialize> RmpWriteNamed for T {
        fn write_named<W: ?Sized>(
            self: &Self
            wr: &mut W, 
        ) -> Result<(), Error> 
        where
            W: Write,
        {
            …
        }
    }
    
  3. Our objective now is to make it object-safe: it currently isn't yet since remains that
    &mut impl ?Sized + Write generic parameter. But at this point, it's easy: just replace it with a &mut dyn Write parameter:

    fn write_named (
        self: &Self,
        wr: &mut dyn Write,
    ) -> Result<(), Error>
    

Hence,

The solution

trait RmpWriteNamed {
    fn write_named (
        self: &Self,
        wr: &mut dyn Write,
    ) -> Result<(), Error>
    ;
}

impl<T : Serialize> RmpWriteNamed for T {
    fn write_named (
        self: &Self,
        wr: &mut dyn Write,
    ) -> Result<(), Error>
    {
        ::rmp_serde::encode::write_named(wr, self)
    }
}

And now you can use dyn RmpWriteNamed and its .write_named(writer) method :slightly_smiling_face:

1 Like