Skip to content

ACP: Move ToOwned and Cow to core. #519

Closed as not planned
Closed as not planned

Description

@bjoernager

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

  1. kennytm commented on Jan 5, 2025

    @kennytm
    Member

    This exists:

    impl ToOwned for str {
        type Owned = String;
    }

    If you put the impl in core, you can't name String.

    While if you put it in alloc there would be orphanage problem (E0117) (not sure if making ToOwned #[fundamental] would allow it).

  2. bjoernager commented on Jan 5, 2025

    @bjoernager
    Author

    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).

  3. pitaj commented on Jan 5, 2025

    @pitaj

    Previous discussion in #76

  4. pitaj commented on Jan 5, 2025

    @pitaj

    Notably, CoW stands for "copy on write" (technically a clone). What we'd probably want in core is actually a "owned or reference" type.

  5. joshtriplett commented on Jan 7, 2025

    @joshtriplett
    Member

    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 str and impl<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.

  6. cvengler commented on Jan 3, 2026

    @cvengler

    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 str and impl ToOwned for [T]. Also see #76 for details.

    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 core with the compiler patch applied: cvengler/rust@943fc34

    Let me know what you think :)

  7. added
    I-libs-nominatedIndicates that an issue has been nominated for discussion during a team meeting.
    on Jan 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    I-libs-nominatedIndicates that an issue has been nominated for discussion during a team meeting.api-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