ACP: Move ToOwned and Cow to core. #519
Description
Proposal
Problem statement
The standard library's alloc crate defines the ToOwned trait and the Cow type in the borrow module. This module is closely tied to Rust's ownership model, and the core crate also defines some facilities in this module (i.e. the Borrow and BorrowMut traits).
Whilst both ToOwned and Cow are usually used in conjunction with the alloc crate's dynamically-allocated types (such as String and Vec), they do not intrinsically need to be coupled with these types.
The issue with having these items in alloc is that it renders it impossible for crates to implement ToOwned for their own types (without, of course, importing either alloc or std). This is despite the fact that it is theoretically possible to define this trait without using any other facilities from alloc or std (the ownership model, at least, exists no matter the combination of crates used).
Motivating examples or use cases
Third-party crates that define their own sense of borrowed vs. owned types would naturally want to implement ToOwned for the borrowed types. But this currently requires importing either of the alloc or std crates, which may not necessarily be wanted (especially if the crate uses the no_std attribute).
Solution sketch
Move the definitions of ToOwned and Cow into core:
// core::borrow;
pub trait ToOwned {
type Owned: Borrow<Self>;
fn to_owned(&self) -> Self::Owned;
fn clone_into(&self, target: &mut Self::Owned);
}
pub enum Cow<'a, B>
where
B: ToOwned + ?Sized + 'a
{
Borrowed(&'a B),
Owned(B::Owned),
}
impl<'a, B> Cow<'a, B> {
pub fn to_mut(&mut self) -> &mut B::Owned;
pub fn into_owned(self) -> B::Owned;
}
// Remaining implementations for `Cow`...As the Cow type is very closely related to ToOwned, I do not see any reason for keeping it separated should ToOwned be moved to core.
Alternatives
Third-party crates could define their own ToOwned or Cow. But this would be completely redundant as the standard items already exist, albeit in an incompatible context.
Activity
kennytm commentedon Jan 5, 2025
This exists:
If you put the
implincore, you can't nameString.While if you put it in
allocthere would be orphanage problem (E0117) (not sure if makingToOwned#[fundamental]would allow it).bjoernager commentedon Jan 5, 2025
I believe it should be possible for the standard library to extend its own traits, even if this would happen across crate boundaries (granted those boundaries are between its own crates).
We already do have some exceptions to this rule with regard to primitive types, so I cannot see why we (technically) couldn't do this as well. But I guess that makes this more a philosophical question rather than a technical one (i.e. is this a core design choice of Rust – even for the standard library – or do we have some wiggle room for changes).
pitaj commentedon Jan 5, 2025
Previous discussion in #76
pitaj commentedon Jan 5, 2025
Notably,
CoWstands for "copy on write" (technically a clone). What we'd probably want in core is actually a "owned or reference" type.joshtriplett commentedon Jan 7, 2025
We discussed this in today's @rust-lang/libs-api meeting. We don't have any objections in principle. However, there are some serious implementation issues with this, regarding
impl ToOwned for strandimpl<T> ToOwned for [T]. Also see #76 for details.Solving this would require solving those issues, including the ways this would interact with potential future use of specialization. If you can come up with a solution for that (which probably involves an RFC given the complexity of this), we'd be happy to consider that RFC.
Allow incoherent trait implementations
Allow incoherent trait implementations
cvengler commentedon Jan 3, 2026
I'm currently interested in picking this up again, although I probably may be underestimating the complexity here. 🫠
I did a related PR with rust-lang/rust#150652 that would allow for incoherent trait impls.
I also did a quick WIP that "proves" one may move it to
corewith the compiler patch applied: cvengler/rust@943fc34Let me know what you think :)