How to construct DST?

How to construct this struct:

struct S {
   x: dyn Debug
}

It looks so difficult to construct, then what is the use case of this grammar ?

1 Like

It's not only difficult but impossible as of right now. The only way to construct a custom dynamically sized type is via unsizing coercion. From the nomicon:

Currently the only properly supported way to create a custom DST is by making your type generic and performing an unsizing coercion:

struct MySuperSliceable<T: ?Sized> {
   info: u32,
   data: T,
}

fn main() {
    let sized: MySuperSliceable<[u8; 8]> = MySuperSliceable {
        info: 17,
        data: [0; 8],
    };

    let dynamic: &MySuperSliceable<[u8]> = &sized;

    // prints: "17 [0, 0, 0, 0, 0, 0, 0, 0]"
    println!("{} {:?}", dynamic.info, &dynamic.data);
}

(Yes, custom DSTs are a largely half-baked feature for now.)

1 Like

Not impossible. With an added #[repr(C)] or #[repr(transparent)], it is possible to construct S using unsafe code, and then after that construction it can be used normally.

use std::fmt::Debug;

#[derive(Debug)]
#[repr(transparent)]
struct S {
   x: dyn Debug
}

fn main() {
    let d: Box<dyn Debug> = Box::new("hi");
    let s: Box<S> = unsafe { Box::from_raw(Box::into_raw(d) as *mut S) };
    println!("{s:?}");
}

S as written is only a "newtype" of dyn Debug, and there aren’t a whole lot of specific uses by itself for that (though I can think of one — have the wrapper implement Debug in a way that modifies the formatting, like forcing alternate mode) but in the context of some application’s generic code it might have a particular use.

More useful, but even harder to construct, custom DSTs are those that have more fields than just the unsized tail field. These can allow using a single indirection where two would otherwise be required (one for the whole struct and one for the boxed DST field).

Broadly: there are some uses for the custom DST feature today, and if we someday figure out how to provide easy construction, there will be more.

3 Likes