Skip to content

ACP: Proper const Deref methods #624

@clarfonthey

Description

@clarfonthey

Proposal

Problem statement

Right now, each "slice-like" method in the standard library has its own, dedicated methods to bypass Deref and DerefMut, which are named appropriately based upon the collection:

  • Vec::as_slice and Vec::as_mut_slice
  • String::as_str and String::as_mut_str

However, for CString, OsString, and PathBuf, there is an inconsistency where only the immutable versions of these methods are offered, and they are not usable in const context. However, OsString and PathBuf both implement DerefMut, allowing mutable access via the trait:

  • CString::as_c_str
  • OsString::as_os_str
  • PathBuf::as_path

Motivating examples or use cases

All of these methods are useful for avoiding "deref closures" and type-ambiguous as_ref calls, instead directly stating what type they return:

let x = String::new().as_ref(); // ambiguous
let x = Some(String::new()).map(AsRef::as_ref); // ambiguous
let x = Some(String::new()).map(String::as_str); // unambiguous

While it's questionable whether in-place editing of these string-like types is useful, it still can be done on mostly-ASCII text, and in particular, there are the methods str::make_ascii_lowercase and str::make_ascii_uppercase which could similarly be applied to CString, OsString, and PathBuf.

Additionally, in code for tools like serde, it's desirable to edit buffers in-place to, for example, replace escaped characters in-place, and additional bytes can be overwritten with placeholder bytes to keep the result still valid UTF-8. Even for CString this is possible, and the addition of an &mut CStr could be desirable to still indicate that it's valid to write to the buffer, but UB to write a NUL byte to it, instead of simply passing &mut [u8] which does not convey this.

Solution sketch

Add the following methods:

  • CString::as_mut_c_str
  • OsString::as_mut_os_str
  • PathBuf::as_mut_path

And also allow those, plus the following methods, to be used in const context:

  • CString::as_c_str
  • OsString::as_os_str
  • PathBuf::as_path

And additionally, add a DerefMut and associated AsMut<CStr> and BorrowMut<CStr> implementations for CString and CStr.

Alternatives

These methods are desirable to also forward in the Deref and DerefMut implementations of these methods, to make the code more clear. So, they will likely exist regardless, just as private methods or trait impls.

Links and related work

Since this was mostly just marking methods as const-unstable, I already filed a tracking issue here: rust-lang/rust#144288

But, this does include new methods technically, so, it should have an ACP. If the ACP is not accepted, the new methods will be removed, but presumably that tracking issue will still apply to making some methods const-unstable.

What happens now?

This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.

Possible responses

The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):

  • We think this problem seems worth solving, and the standard library might be the right place to solve it.
  • We think that this probably doesn't belong in the standard library.

Second, if there's a concrete solution:

  • We think this specific solution looks roughly right, approved, you or someone else should implement this. (Further review will still happen on the subsequent implementation PR.)
  • We're not sure this is the right solution, and the alternatives or other materials don't give us enough information to be sure about that. Here are some questions we have that aren't answered, or rough ideas about alternatives we'd want to see discussed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions