Does converting a String into a PathBuf allocate new buffer?

I want to reuse String buffer as PathBuf. For this I use From trait conversion. If I open the source code, I'll see:

impl From<String> for PathBuf {
    /// Converts a `String` into a `PathBuf`
    ///
    /// This conversion does not allocate or copy memory.
    #[inline]
    fn from(s: String) -> PathBuf {
        PathBuf::from(OsString::from(s))
    }
}

As you can see from the comment: "This conversion does not allocate or copy memory". But is it? If I open String to OsString convertion, then it will be:

impl From<String> for OsString {
    /// Converts a [`String`] into a [`OsString`].
    ///
    /// The conversion copies the data, and includes an allocation on the heap.
    #[inline]
    fn from(s: String) -> OsString {
        OsString { inner: Buf::from_string(s) }
    }
}

The comment reads: "The conversion copies the data, and includes an allocation on the heap". As far as I understand, OS specific code follows deeper. In the end, can I rely on the lack of allocation on all OSs (at least on Windows, Linux, MacOS)? Anyway, isn't the documentation conflicting?

1 Like

Looking further into the implementation, it seems like it does not allocate a new buffer, at least in its current implementation.

I suppose that the documentation is wrong here, since the conversion from PathBuf to OsString also claims to “not allocate or copy memory”. It doesn’t make sense to be able to convert String->PathBuf->OsString cheaply but not String->OsString directly.

Converting a String into PathBuf or OsString won't allocate. They are both wrappers around a byte array and OsString has less restrictions than String. Converting back to a String may fail or else need to be lossy.

However calling OS functions (e.g. File::open) will always allocate. On Unix a PathBuf will be converted to a null terminated c-string. On Windows it will be converted to UTF-16.

3 Likes

Here is the relevant piece of code:

impl Buf {
    pub fn from_string(s: String) -> Buf {
        Buf { inner: s.into_bytes() }
    }

    ...
}

So it indeed seems not to allocate.

Indeed, being "cheaply inter-convertible with Rust strings" is the documented behaviour.

So one of these documentation lines comes from

and the others from

The former asks for double-checking the claims about allocation, and it doesn’t look like this double-checking (if it even happened) was all that thorough, whereas the latter had some good discussion on allocations. I guess we should fix the documentation.

1 Like