Converting from generic unsized parameter to trait object

Is it not possible to have generic function taking ?Sized to create a trait object?

use std::io::Write;

fn only_unsized(_: &mut dyn Write) {}

fn allow_unsized<W: Write + ?Sized>(w: &mut W) {
//    only_unsized(w);
//    only_unsized(w.by_ref());
    only_unsized(&mut *w);
}

Playground

I'm getting an error telling me to remove the ?Sized bound, but I'd really like to keep it. I want the generic function to accept either a concrete sized type (and make trait objects where needed), or take something that is already a dyn reference.

fn test() {
    allow_unsized(&mut vec![0u8] as &mut dyn Write);
    allow_unsized(&mut vec![0u8] as &mut Vec<u8>);
}

Ok, I've found this:

fn allow_unsized<W: Write + ?Sized>(mut w: &mut W) {
    only_unsized(&mut w);
}

I'm afraid this has has one more level of indirection than I'd like, but at least it compiles.

I think I've tried that combo before, but didn't notice Rust was pointlessly wanting the fake do-nothing talisman of mut w too.

Someone could implement Write for an unsized type besides dyn Write, e.g.

struct MaybeUnsized<T: ?Sized> {
    t: T,
}

impl Write for MaybeUnsized<[u8]> {
    fn write(&mut self, _: &[u8]) -> Result<usize, std::io::Error> { todo!() }
    fn flush(&mut self) -> Result<(), std::io::Error> { todo!() }
}

A &mut MaybeUnsized consists of a length and a pointer, and can't be coerced to a &mut dyn Write consisting of a vtable and a pointer, as the length would be discarded (and sizes stored in vtables are static).

Your work-around works because you're now doing unsizing coercion on a &mut &mut Write + ?Sized and not a &mut Write + ?Sized (and Write is implemented for &mut Write + ?Sized). I.e. you got rid of the deref. The mut w is required to take the outer &mut reference to w.

You could avoid the extra indirection by using a trait. But only unsized types you explicitly implement will be directly usable. On the other hand, a &mut &mut UnsizedWriter will work with the blanket implementation (including via method call on a &mut UnsizedWriter).

5 Likes

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.