Specialization of `impl ToString for Box<str>`?

Currently, Box<str> can be converted into String via ToString trait. However, compiler can't remove formatter call even in release mode. Consider:

// lib.rs
pub fn just_trait(s: Box<str>) -> String {
    s.to_string()
}

pub fn unsafely(s: Box<str>) -> String {
    let len = s.len();
    let ptr = Box::into_raw(s);

    unsafe { String::from_raw_parts(ptr as *mut u8, len, len) }
}

(note: I have checked whether unsafely contains UB. It seems unlikely according to miri)

I think it can be solved by adding specialized implementation of ToString for Box<str> with unsafely body.

I’m not quite sure of how the discussion of the unsafely function is relevant all that much. It seems correctly implemented, probably; but also, you can just call the existing into_string method.[1]

Of course this doesn’t affect the main point of yours ^^


  1. Incidentally, .into() should work the same, but it seems like the From<Box<str>> for String implementation isn’t inlined properly!? Are we missing an #[inline] on that one?? ↩︎

2 Likes

you can just call the existing into_string method.

I didn't know that... It's surprising because I thought impl str contains members that can be used in no-alloc environment; both Box and String does not satisfy it.

Another relevant detail: ToString provides a &self -> String conversion. So copying the string cannot be avoided at all, because you’d only get a &Box<str> reference; of course, the use of formatting machinery probably still can.

5 Likes

I thought the trait takes ownership. But there is still unnecessary format codegen from non-owned equivalent (<&str as ToString>::to_string). In general formatter is slow (not benchmarked: I'll add the result later) and I want to avoid it.

Box<str> is overall clunky, so this is probably an oversight that can be fixed (at least as a copy from &str without extra steps).

4 Likes

If the standard library wasn’t split between core and alloc, then ToString wouldn’t need to exist and a to_string method could be part of Display, which could be overridden without the need for any specialization. Display for Box<T> could just call the to_string method from Display for T, so Box<str> would be properly optimized as desired. But alas, Display lives in core and String & ToString live in alloc.

I feel there’s some kind of language design opportunity that could make this possible despite of the split.

And/or clever library design. E.g. this thread earlier this year tried finding a library solution:

1 Like