From 9f23083b6ba6b60132787f75c6c42828abff4d53 Mon Sep 17 00:00:00 2001 From: CheaterCodes Date: Sat, 15 Aug 2026 16:41:52 +0200 Subject: [PATCH 1/7] own_ref RFC initial commit --- text/0000-owning-references.md | 707 +++++++++++++++++++++++++++++++++ 1 file changed, 707 insertions(+) create mode 100644 text/0000-owning-references.md diff --git a/text/0000-owning-references.md b/text/0000-owning-references.md new file mode 100644 index 00000000000..1a609632a61 --- /dev/null +++ b/text/0000-owning-references.md @@ -0,0 +1,707 @@ +- Feature Name: `own_ref` +- Start Date: 2026-07-22 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + +## Summary +[summary]: #summary + +Introduce owning references `&own` into the language, which allows passing ownership of the pointee without moving its value. +Owning references can be moved out of (including partial moves), and drop their pointee when dropped. + + +## Motivation +[motivation]: #motivation + +Owning references (`&own`, sometimes called `&move`) come up every so often in discussions around Rust. +Their primary purpose is to allow passing owned values behind an indirection, but agnostic of the backing allocation. +There have been multiple attempts at bringing them to the Rust language in the past, each of which has been **postponed**. + +

A brief history of &own/&move

+ +This is a short list of Rust related resources that inspired us in certain aspects of this RFC, provided in chronological order. + +#### [RFC #965](https://github.com/rust-lang/rfcs/pull/965) Add `&own T` + +Already back in 2015, this RFC proposed owning references. +It shares some of the motivations with this RFC: +- Provide an allocation-agnostic owned reference type. +- Pass ownership of values while avoiding (large) copies. +- Pass ownership of unsized types (slices and trait objects). + +It was **postponed** after some comments by @nikomatsakis: +- It is *too soon* for a new pointer type, especially for teaching Rust. +- Many use cases can be discussed using library types and custom allocators. + +#### [Issue #998](https://github.com/rust-lang/rfcs/issues/998) Owned references to contents in an earlier stack frame (`&own`, `&move`, etc) + +Niko also opened this issue afterwards, presumably to keep an eye on this topic. +It occasionally received comments, and is still open today. + +#### [RFC #1617](https://github.com/rust-lang/rfcs/pull/1617) Add an owning "borrowed" pointer type `&move` + +Just one year later, another short RFC proposed owning references with minor differences: +- It calls the reference `&move` to reuse the existing keyword. +- Add a simple (but incomplete) `DerefMove` trait. + +Once again, it was **postponed** until more design bandwidth is available. +Primary concerns were that "owned borrowing" would be confusing, as well as some syntactic discussions. +Niko then mentions he wanted to re-open the RFC to allow further discussions, but by then another RFC already appeared: + + +#### [RFC #1646](https://github.com/rust-lang/rfcs/pull/1646) &move, DerefMove, DerefPure and box patterns + +Less than a month after the previous RFC was closed, this new one was opened. +It touches once again on some of the same topics, but also proposes a "pure" version of `DerefMove` to allow pattern matching. + +Once more, this RFC was **postponed** a year later, since it was a "good idea at a bad time". +Niko once again left an [elaborate comment](https://github.com/rust-lang/rfcs/pull/1646#issuecomment-279123028): +- Concerns about a steeper learning curve. +- Simpler solutions exist, specifically for unsized types. + - I believe this is talking about `unsized_rvalues`, but the provided link is dead. +- More elaborate problems exist, such as out-pointers, and should possibly be considered at the same time. + +#### [URLO Thread](https://users.rust-lang.org/t/aside-some-ramblings-about-move-references) Aside – some ramblings about `&move` references + +In mid 2021, Yandros provided a sketch of owning references, based on their own experience implementing the `stackbox` crate. +This topic also already mentions how `unsized_fn_params` are effectively implicit owning references. + +#### [IRLO Thread](https://internals.rust-lang.org/t/a-sketch-for-move-semantics) A sketch for `&move` semantics + +In mid 2023, another thread appeared discussing owning references. +This time, the interaction of `Pin` and `&own` was also discussed. +In another [lengthy comment](https://internals.rust-lang.org/t/a-sketch-for-move-semantics/18632/20), Yandros once again dives into the details of how a library solution is not sufficient, how this could replace `unsized_fn_params`, and how pinning is too much to handle. + +#### [Zulip Thread](https://rust-lang.zulipchat.com/#narrow/channel/549962-t-lang.2Fmove-trait/topic/Leak.2C.20Forget.2C.20and.20.26own) Leak Forget and `&own` + +This thread discussed how `Forget` would interact with `&own`. While this is not directly related to the contents of this RFC, it is the reason why I (the RFC author) decided to tackle this topic: +There seems to be some sort of community consensus how an owning reference would work, even though we neither have it in the language nor a formal design for it. + +While further discussion (including [pre-RFC discussion](https://rust-lang.zulipchat.com/#narrow/channel/213817-t-lang/topic/.60.26own.60.20appetite.3F.20.28and.20Pre-RFC.20I.20guess.29/with/615156849)) revealed that not all details are easy, we believe that the learning curve is not that high, but that owning references may even be very intuitive. + +--- + +
+ +A number of things have changed since the last proposals: +- After over 10 years of Rust, it is no longer "too soon" to add another fundamental reference type. +- The `unsized_rvalues` RFC has been merged, and demonstrated the challenges with handling unsized values implictly. +- We have prior art in external crates, which show that pure library implementations are not sufficient. +- Non-movable types have become important in Rust (`async`-like self-referential types) + +As such, this RFC introduces owning references `&own` to allow passing ownership of both **unsized and immovable types**, as well as an **explicit optimization**, in a **allocation agnostic** way. +At the same time, we try to choose the **most intuitive** behavior for owning references where possible. + + +### Passing ownership of large objects + +When writing a function that takes ownership of some `LargeStruct`, idiomatic Rust suggests passing by value: + +```rust +fn consume_by_value(x: LargeStruct) { } +``` + +However, this may cause our `LargeStruct` to be copied to/from the stack, depending on compiler optimizations. +If we want to guarantee that such a copy does not happen, we are forced to use indirection, and instead pass a pointer to the struct itself. +The idiomatic safe way to do this would be via `Box`: + +```rust +fn consume_by_box(x: Box) { } +``` + +This avoids unnecessary copies when passing through functions, but requires putting `LargeStruct` into the heap up front. +This may be undesirable in some cases, e.g. when the value is already part of a different heap allocation (e.g., a `Vec`), or even impossible in others (e.g., if `alloc` is unavailable). + +Using an owning reference, we can pass ownership of our value, while ensuring that the compiler will not perform additional copies: + +```rust +fn consume_by_ref(x: &own LargeStruct) { } +``` + + +

Example: Statically fused Iterators

+ +One possible application of this is the `Iterator` trait, which is currently defined like this: + +```rust +pub trait Iterator { + type Item; + + fn next(&mut self) -> Option; +} +``` + +This definition leaves it unclear what should happen, if an iterator is run past its end. +Iterators should return `None` to indicate their end. +If they are advanced after that, they may return arbitrary values or panic. + +An alternative design could use `&own` references to statically guarantee that an iterator may not be polled past its end, without passing the (possibly large) iterator by value: + +```rust +pub trait Iterator { + type Item; + + fn next(&own self) -> Option<(&own Self, Self::Item)>; +} +``` + +> This RFC doesn't propose that we make this change, but uses it as an interesting example application for `&own`. + +
+ +### Consuming unsized types + +In some cases we don't just want indirection, we *need* it. +In current safe Rust, this primarily comes up with unsized types such as trait objects and slices. +As an example, the following code fails to compile: + +```rust +// error[E0277]: the size for values of type `(dyn FnOnce() + 'static)` cannot be known at compilation time +fn consume_by_value(x: dyn FnOnce()) { + x() +} +``` + +Again, the solution is to use a `Box`, costing a heap allocation. +Alternatively, we could use an owning reference, which provides similar capabilities to a `Box`, but without the heap allocation: + +```rust +fn consume_by_ref(x: &own dyn FnOnce()) { + x() +} +``` + +

Example: Owned slices

+ +Probably the most commonly used unsized types are slices `[T]`. +Since they cannot be pased by value, they are always passed with indirection. +We use `&[T]` for read-only slices, `&mut T` for mutable slices. +Slices are well built into the language and support some convenient features, such as slice pattern matching. +Currently, there exists no way to use slice pattern matching for owned values. +Boxed slices `Box<[T]>` are often used to fill this gap, but they cannot be used in slice patterns. + +```rust +fn foo(boxed: Box<[String]>) { + match *boxed { + // error[E0277]: the size for values of type `[String]` cannot be known at compilation time + [first, rest @ ..] => { }, + _ => { } + } +} +``` + +This code fails, because we cannot provide a useful type for `rest`. +While `first` could in theory move out the first string by value (it doesn't today), +`rest` would be an unsized local. +We cannot split the box into two boxes, as it would be unclear which value is responsible for freeing the backing allocation. + +Owning slices `&own [T]` don't suffer from this problem, since they are only responsible for freeing their values, not the backing allocation. +It is not problematic to split an owning slice in two, so most known slice operations can be applied to owned values as well. + + +```rust +fn foo(owned: &own [String]) { + match owned { + [first, rest @ ..] => { }, + _ => { } + } +} + +> Even without pattern matching, a `<[T]>::split_at_owned(&own self, usize) -> (&own [T], &own [T])` supports this behavior in a way that neither `Box` nor `Vec` can. + +``` +
+ +

Example: Owned self in trait methods

+ +A very useful application of this is to make traits which take `self` arguments `dyn`-compatible. +As a real-world example, let us look at a slightly simplified version of the `FnOnce` trait: + +```rs +pub trait FnOnce { + /// The returned type after the call operator is used. + type Output; + + /// Performs the call operation. + fn call_once(self, args: Args) -> Self::Output; +} + +// Call a boxed and type erased closure +fn call_func(func: Box) { + // error[E0161]: cannot move a value of type `dyn FnOnce()` + (*func).call_once(()); +} +``` + +This code fails, because we cannot pass an unsized value to a function. +However, we could change the trait method to take an `&own self` instead, which is dyn-compatible: + +```rs +pub trait FnOnce { + /// The returned type after the call operator is used. + type Output; + + /// Performs the call operation. + fn call_once(&own self, args: Args) -> Self::Output; +} + +// Call a boxed and type erased closure +fn call_func(func: Box) { + // With auto-deref, this could be func.call_once(()) + (&own *func).call_once(()); +} +``` + +> For more discussion on `FnOnce`, see [below](#Change-FnOnce-to-use-ampown-and-remove-unsized_fn_params). + +
+ +### Consuming immovable types + +Rust does not *currently* have immovable types. +The closest we have is `Pin`, which additionally enforces the drop guarantee, which we cannot provide with `&own` (see [drawbacks](#Pinning)). +However, in a possible future where Rust splits immovability from the drop guarantee, `&own` would play a central role in passing ownership of immobile types. + +> The "Immobile types and guaranteed destructors" project goal[^move-trait] is (among other options) considering a combination of `T: !Move + !Forget` to replace `Pin`. + +## Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +An *owning reference* type is written `&own T` or `&'a own T` for any type `T`. +Owning references behave like mutable references, except that they own the value behind the reference, which means that: +- It is possible to move out of an `&own T`. +- Dropping an `&own T` drops the inner `T`. + +Owning references should be used when we want to transfer ownership and either do not want to or can not move the value. +For example, you might want to write a function that prints a list of values. +For efficiency, we will use a homogenous list of trait objects. +Note that this function accepts a list of trait objects, but does not require putting them on the heap! +Additionally, we can consume both the slice and its elements, which is not possible with other reference types. + +```rust +fn print_all(producers: &own [&own dyn FnOnce() -> String]) { + for producer in producers { + println!("Got value: {}", producer()); + } +} + +let hello = String::from("Hello"); +print_all(&own [ + &own || hello, + &own || "World".to_string(), + &own || format!("{}", 42), +]); +``` + +## Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +### Owned reference type + +The reference type syntax is extended to allow the contextual keyword `own` instead of `mut`: + +```grammar,types +ReferenceType -> `&` Lifetime? (`mut` | own`)? TypeNoBounds +``` + +In this position, `own` may also appear as an identifier at the beginning of `TypeNoBounds`. +To resolve this conflict, `own` is always parsed as the keyword in this position. +If the developer intends to reference a type which begins with the `own` identifier, they must wrap it in parentheses. + +### Owned borrow expression + +The syntax of borrow expressions is extended in the same way. +Similarly to the owned reference type expression, if `Expression` begins with an the identifier `own`, it must be wrapped in parentheses. + +```grammar,expressions +BorrowExpression -> + (`&`|`&&`) Expression + | (`&`|`&&`) `mut` Expression + | (`&`|`&&`) `own` Expression + | (`&`|`&&`) `raw` `const` Expression + | (`&`|`&&`) `raw` `mut` Expression +``` + +When using the borrow expression `&own Expression` on a place expression with type `T`, the expression produces an owning reference of type `&own T` in the same fashion as existing reference types. +The place must be an *owned place* and is considered exclusively borrowed for the lifetime of the created owning references, as well as considered "moved out" once the lifetime expires. + +The following expressions can be owned place expression contexts: + +* Variables which are not currently borrowed. +* Temporary values. + * This must perform lifetime extension. +* Fields: this evaluates the subexpression in an owned place expression context. +* Dereference of a `*mut T` pointer. +* Dereference of a place, or field of a place, with type `Box`. +* Dereference of a place, or field of a place, with type `&own T`. + +When using the borrow expression on a value expression, the behavior is analogous to that of other borrow expressions. + +### Properties + +The type `&'a own T` behaves similar like other references, except it owns the value of the pointee: + +- It is **covariant** in both `'a` and `T`. +- It is an **exclusive** borrow. +- It may be reborrowed as a shared or mutable reference. +- It must be aligned, non-null, point to a valid `T`, and be "dereferencable". +- When dereferenced, it produces an *owned* place (instead of a mutable one), which may be (partially) moved out of (like `Box`). +- When dropped, it also drops its pointee (but does not free the allocation). + +## Drawbacks +[drawbacks]: #drawbacks + +### Pinning + +This simple approach to owning references cannot support pinning. +A `Pin<&'a own T>` is unsound, since forgetting the reference violates the drop guarantee (unless `'a: 'static`). +This may be confusing to users, since they often only consider the immovability guarantee of `Pin`. +Unfortunately, the [alternative](#Alternative-Add-remote-drop-flags-to-support-pinning) is more complex, and we believe that it is not worth it. + +### Some easy APIs are actually hard + +As Rust users, we are used to APIs of the form `fn into_foo(&own Self) -> &own Foo`. +However, these APIs are often difficult or impossible to write. +For example, we cannot write a function `Box::into_inner(&own self) -> &own T` without leaking the allocation. +In general, we cannot write such an API if `Self` requires droping (and the dropping involves the returned value). +This is the same problem as providing a `DerefOwn` trait ([see below](#Introduce-DerefOwn)). + +### Teaching + +Many Rust resources teach that Rust has two kinds of references: Shared and mutable. +With owning references, we would add a third one to the mix. +One challenge here is, that owning references are not borrows like the other two: +After a borrow expires, you can keep using the original value. +But with owning references, once the borrow expires, the original value is gone. + +On the one hand, we believe that we do not need to bother Rust beginners with owning references. +[The Rust Book](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html), adresses the current primary alternative `Box` only in chapter 15, and owning references would be considered similar advanced usage. +However, we would still need to adjust teaching to mention a third reference type, to be explained later. + +### Documentation + +Besides implementing this, documentation changes would be a big churn. +While we believe that the behavior of `&own` is mostly intuitive, +many places in Rust documentation would need to be adjusted to account for a third reference type, which does not share the behavior of the others (e.g., does something when dropped). + +Additionally, many places in Rust use `Box` as the canonical "owned pointer", which in some cases would need adjustment. +For example, the [`std` docs](https://doc.rust-lang.org/std/#containers-and-collections) call `Box<[T]>` an "owned slice", which would be confusing in the presence of `&own [T]`. + +## Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +The proposed design of `&own` references is kept as simple as possible. +It tries to be an intuitive addition to the Rust programming language, where most existing programmers would understand what it does without having to read the reference. + +This design intentionally omits some additional complexities mentioned in drawbacks and alternatives, in favor or a straightforward design. + +### Alternative: Do nothing + +This is the current situation, and Rust users found a number of ways to work around the lack of owning references. +Primarily, users will use `Box` if they can and it isn't performance critical. +If boxing is not available (too expensive, or no heap present), alternatives include using a `&mut Option` to pass runtime-checked ownership of `T`, or use a crate like [stackbox](https://docs.rs/stackbox/latest/stackbox/struct.StackBox.html). + +However, as stated by [the `stackbox` maintaner themselves](https://internals.rust-lang.org/t/a-sketch-for-move-semantics/18632/19), there are some ergonimic challenges with a library implementation: + +- Creating a stack box is cumbersome. +- Especially lifetime extension is missing. +- `&own self` receivers are not (currently) possible. +- It is non-straightforward to write functions are "allocation-agnostic", i.e., work with both `Box` and `StackBox`. + +### Alternative: Syntax options + +While many prior discussions use the `&own` notation, other options are available: + +- `&move` has been used in the past, indicating the "movement of ownership". + - We believe that this syntax isn't as clear in the implied semantics. + - This could re-use the existing `move` keyword + - However, there is ambiguity with closures: `&move || { }` +- `&ref(own)` does not require a contextual keyword + - This allows for more reference types to be added in the future + - Doubles the amount of typing and adds visual clutter +- `Own<'_, T>` could use normal type syntax, avoiding additional parsing complexity. + - This would visually more closely resemble `Box` rather than other reference types + - This would likely need a macro to perform (re-)borrowing + +### Alternative: Wait for custom references + +As part of the "field projections" project goal[^field-projections], we aim to support custom reference types in the compiler. +Supporting an `Own<'_, T>` reference type with the same semantics as described in this RFC should become possible via a library type. + +This is likely the best alternative, since it in principle can provide everything a specialized owning reference can. +However, we believe that `&own` is fundamental enough to deserve custom syntax, even with custom references. +Additionally, most of the work that goes into owning references would need to happen even if we waited for fully custom references. + +### Alternative: Model as `Box>` + +Semantically, `&own` is identical to `Box>`, where `NoOp<'a>` is a zero-sized `Allocator`, which cannot perform allocations and does nothing on deallocations. +A type alias could be used to name this type `Own<'a, T>`. +With this alternative, a macro would be used to create an owning reference to a place, such as `own!(place)` instead of `&own place`. + +On the upside, this would allow functions accepting an allocator-generic `Box` would to also accept an `Own`. +However, there are a number of downsides to this approach: + +- The `Box` API is too general. + For example, it would mean that `Own<'a, T>: Clone` if `T: Clone`. However, calling this method would have to panic with the `Noop` allocator. +- There might be subtle differences in the types that are currently unknown. + For example, we might want different aliasing rules for the types. +- `Box` is (currently) not available in `no_std` (unless `alloc` is enabled), so APIs compatible with `no_std` cannot take `Box` as an argument. + We might be able to change this, but it seems non-trivial. + +Additionally, it might just be *too weird*. +By its own docs: +> `Box`, casually referred to as a ‘box’, provides the simplest form of +heap allocation in Rust. +> Boxes provide ownership for this allocation, and +drop their contents when they go out of scope. + +A `Box>` is neither a heap allocation, nor does it provide opwnership for its allocation. + +### Alternative: Add remote drop flags to support pinning + +Unfortunately, `Pin<&own T>` is unsound with regards to the drop guarantee. +This is because forgetting `Pin<&own T>` avoids running the drop implementation of `T`, but we have no control over the backing memory or the reference. + +If we'd want to fix this design to allow for pinning, we would have to change `&own` to track and possibly modify the drop flags of its allocation. +In this scenario, `Pin<&own T>` would behave similarly to an `Pin<&mut Option>`, which is already expressable today. + +While this could be an interesting design approach, we believe that remote drop flags would make the language design much more complicated. +Instead, we proposed this much simpler design, even if that forbids pinning. + +> See the [`own-ref` crate](https://docs.rs/own-ref/0.1.0-alpha/own_ref/pin/index.html), which allows adding drop-flags via a generic on the reference, and how that helps with pinning. + +> See [future possibilities](#Interactions-with-Move-and-Forget) for how the `Move` and `Forget` traits could avoid the need for pinning and use the current design of `&own`. + +### Alternative: Explore design space of additional reference types + +This RFC proposes a single new reference type, `&own`. +There may be additional reference types we may want to add in the future, such as `&pin`, `&uninit`, `&out`, or `&init`. +It may be advantageous to increase the scope of this RFC to include other references, to avoid short-sighted desicions in this design space. + +Besides the complexity in the language, we believe that major point of contention is the syntax space. +Contextual keywords, as suggested here with `&own` work well, but might become annoying when there are too many. + +We could consider changing the syntax to avoid the need for contextual keywords, e.g. `&ref(own) T`, although this significantly increases syntactic load on the reader. + +## Prior art +[prior-art]: #prior-art + +### The `stackbox` and `own_ref` crates + +These crates provide library types that emulate `&own`. +The `stackbox` crate frames itself as a stack-allocated box. +The creation of a `StackBox` is somewhat cumbersome. + +The `own_ref` is essentially an updated version of `stackbox`, which additionally allows pinning via a optional built-in drop flag. +It improves reference creation, but still lacks ergonomic features. + +In particular, no library can currently emulate moving out of field. + +### The `bumpalo` crate and its `Box` type + +The [`bumpalo` crate](https://docs.rs/bumpalo/latest/bumpalo/) provides bump allocation via the `Bump` arena. +The `Bump::alloc(&self, val: T) -> &mut T` method allocates a `T` in the arena, and returns a mutable reference to it. +Since the arena does not keep track of the types of all of its allocations, it cannot drop `T`, and the mutable reference does not allow dropping the value either (without unsafe code). + +As a solution, it provides its own `Box` type, which drops its pointee when dropped. +This `Box` is effectively the same as `&own`, except for missing ergonimics. + +> Note that `bumpalo:box:Box` provides a pinning API, which is an known to be unsound. + +## Unresolved questions +[unresolved-questions]: #unresolved-questions + +### Does `&'a own T` need to be covariant in `'a`? + +While it is undisputed that it is *possible* to enable this property, there are concerns about its usefulness. +If it is not necessary to be covariant, we could alternatively be invariant in `'a`. +This could allow us, for example, to use `&own` as an initialization prove for certain in-place-init proposals. + +### Should is be allowed to borrow through pointers? + +The unsafe operation `&own *ptr` would allow effectively casting the pointer to an owning reference. +This is allowed with other references, so it seems reaonable to allow this here too. +However, this operation additionally causes a deferred drop of the pointee as a side-effect. + +As an alternative, we could disallow this behavior (for now), and instead introduce some more explicitly named function `unsafe fn assume_owned<'a, T>'(ptr: *mut T) -> &own T`. + +### How does `&own place` work if `place: Copy`? + +As per the design, taking an owning reference to a place means that the place may be mutated and will be considered moved out of. +This results in some possibly unexpected interactions. +Currently it is not possible in rust to move out of a place which is `Copy`, since we will always just copy the value instead. +So this behavior is consistent, but might be surprising (and new in the Rust language): + +```rs +let x = 5u32; +{ + let owned = &own x; + *owned += 2; +} +assert_eq!(x, 5); // Error: Use of moved value +``` + +If we consider the place not moved out, the referee may be modified after the borrow ends (the assert would fail at runtime), which would indicate that we require a `mut` binding. +```rs +let mut x = 5u32; +{ + let owned = &own x; + *owned += 2; +} +assert_eq!(x, 5); // Assertion failed; 7 != 5 +``` + +The final option is to use the "trivial copy" property of `Copy` types, and simply restore the value after the borrow. + +```rs +let x = 5u32; +{ + let temp = x; // Compiler generated + let owned = &own x; + *owned += 2; + x = temp; // Compiler generated +} +assert_eq!(x, 5); // Now the assertion passes +``` + +We suggest the first option, one of the others could also be added later. + +## Future possibilities +[future-possibilities]: #future-possibilities + +### Add an owned raw pointer `*own T` + +Analogous to mutable and shared raw pointers, we could add an owned raw pointer. +Currently, when needing an owned raw pointer, the general choice is `*const T`, since it is covariant in `T`. +An `*own T` would then be a mix of a `*mut T`, which allows mutable borrows, and a `*const T`, which is covariant. + +This again places strain on the syntax space, since a contextual keyword may not work in this position. + +### Pattern matching with an owning binding mode + +Analog to other reference types, we could introduce a new binding mode `own`. +As an example, this enables an ergonomic way to recursively consume a slice: + +```rust +fn consume_slice(elements: &own [T]) { + match *elements { + [entry, ref own rest @ ..] => { + consume_entry(entry); + consume_slice(elements); + }, + [] => { } + } +} +``` + +Syntactically, this is slightly more challenging since a contextual keyword is more tricky in this position (compred to, e.g., `ref(own)`). + +### Introduce `DerefOwn` (see [#997](https://github.com/rust-lang/rfcs/issues/997)) + +Given the simple design of the `Deref` and `DerefMut` traits, it seems obvious to add another trait which produces a value. +However, the obvious design for `DerefMove` using values does not support unsized types, such as slices: + +```rs +trait DerefMove: Deref { + fn deref_own(self) -> Self::Target; +} + +fn foo(func: Box) { + // error[E0161]: cannot move a value of type `dyn FnOnce()` + (*func)(); +} + +``` + +With owning references, we could provide a `DerefOwn` trait to allow working with owned unsized types behind an indirection: +```rs +trait DerefOwn: Deref { + fn deref_own(&own self) -> &own Self::Target; +} + +fn foo(func: Box) { + // Could just be `func()` with auto-deref + (&own *func)(); +} +``` + +However, implementing such a trait is difficult, since it is unclear when the "shell" of a type (e.g., the allocation of `Box`) will be freed. +Therefore, the design of such a trait is left for a future RFC, especially since it may involve additional missing Rust features (e.g., self-referential types); + +There is ongoing work in the "field projections" project goal[^field-projections] that attempts to allow equivalent behavior via a more generic `DerefPlace`. + +### Interactions with `Move` and `Forget` + +The "Immobile types and guaranteed destructors" project goal aims to introduce the `Move` and `Forget` traits in order to supersede pinning. + +A type `T: !Move` cannot be moved by value. +However, due to the indirection, `&own T: Move` regardless of `T`. +This makes `&own` essential for transfering ownership of immovable types. + +A type `T: !Forget` must be dropped before its backing allocation may be reused. +This trivially makes `&own T: !Forget`, since forgetting the reference is equivalent to forgetting the value. +However, we would additionally require that `&own T: !Leak`, since leaking the reference would allow reusing the backing allocation without ever dropping `T`. + +#### Statically-fused futures + +Without `Pin`, the future trait could then mirror the `Iterator` trait mentioned earlier: + +```rust +pub enum Poll<'a, F: Future> { + Ready(F::Output), + Pending(&'a own F), +} + +pub trait Future { + type Output; + + // Required method + fn poll(self: &own Self, cx: &mut Context<'_>) -> Poll<'_, Self>; +} +``` + +In this design, `poll` consumes the future, and returns it again if further polling is required. +With this design, futures are able to produce their final output by moving out of their internal state; +It is statically guaranteed that they cannot be polled again. + +Self-referential futures `F: !Move` prevent using `Self` directly, but `&own Self` preserves the ownership-passing semantics while being movable due to the indirection. + +### Change `FnOnce` to use `&own`, replacing `unsized_fn_params` + +In order to implement `Box: FnOnce()`, Rust currently uses the internal and unstable `unsized_fn_params` feature. +If it was possible to migrate the `FnOnce` trait to use `&own self` instead of `self`, we could remove the `unsized_fn_params` feature, or at least not rely on it and provide similar capabilities to user code. + +Luckily, the trait method is not stable, so we could change its signature. +However, there are additional concerns regarding compiler internal details, like closure to fn-pointer casts. + +Additionally, there exist many other trait methods today that would benefit from changing their signature from `self` to `&own self`. +However, this transition is semver breaking. +It could be interesting to find a general migration path here for existing code. + +## Appendix: Some possibly interesting APIs enabled by `&own` + +```rust +// Divide an owned slice into two. +// Note that is impossible with both `Vec` and `Box`, without creating an allocation. +<[T]>::split_at_owned(&own self, usize) -> (&own [T], &own [T]) { ... } + +// Pop a value off a vec without copying it. +// Useful if the elements are very large or immovable. +Vec::pop_own(&mut self) -> &own T { ... } + +// Extract an owning slice from the `Vec`, without dropping the allocation. +// This way the allocation can be reused, and the slice processed further +// via pattern amtching or slice methods (e.g., splitting). +Vec::take_all(&mut self) -> &own [T] { ... } + +// Allows the return value of `Vec::drain` to be converted to an owned slice. +// This way, we can support by-value slice patterns on any subslice of `Vec`. +// Also note that we can reuse the backing allocation, even though we consume the elements. +// `vec.drain().as_owned()` is similar to `vec.take_all()` (with temporary lifetime extension) +Drain<'a, T, A>::as_owned(&mut self) -> &own [T] { ... } +``` + + +[^field-projections]: https://rust-lang.github.io/rust-project-goals/2026/field-projections.html + +[^move-trait]: https://rust-lang.github.io/rust-project-goals/2026/move-trait.html \ No newline at end of file From b6335767fd67c2afbc311eaa9da8aaf17ef6ba3d Mon Sep 17 00:00:00 2001 From: CheaterCodes <49926638+CheaterCodes@users.noreply.github.com> Date: Mon, 17 Aug 2026 08:44:27 +0200 Subject: [PATCH 2/7] Update 0000-owning-references.md Fixed formatting and some typos --- text/0000-owning-references.md | 38 ++++++++++++++++------------------ 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/text/0000-owning-references.md b/text/0000-owning-references.md index 1a609632a61..e74e15533d3 100644 --- a/text/0000-owning-references.md +++ b/text/0000-owning-references.md @@ -174,8 +174,8 @@ fn consume_by_ref(x: &own dyn FnOnce()) {

Example: Owned slices

Probably the most commonly used unsized types are slices `[T]`. -Since they cannot be pased by value, they are always passed with indirection. -We use `&[T]` for read-only slices, `&mut T` for mutable slices. +Since they cannot be passed by value, they are always passed with indirection. +We use `&[T]` for read-only slices, `&mut [T]` for mutable slices. Slices are well built into the language and support some convenient features, such as slice pattern matching. Currently, there exists no way to use slice pattern matching for owned values. Boxed slices `Box<[T]>` are often used to fill this gap, but they cannot be used in slice patterns. @@ -206,10 +206,10 @@ fn foo(owned: &own [String]) { _ => { } } } +``` > Even without pattern matching, a `<[T]>::split_at_owned(&own self, usize) -> (&own [T], &own [T])` supports this behavior in a way that neither `Box` nor `Vec` can. -```

Example: Owned self in trait methods

@@ -274,7 +274,7 @@ Owning references behave like mutable references, except that they own the value Owning references should be used when we want to transfer ownership and either do not want to or can not move the value. For example, you might want to write a function that prints a list of values. -For efficiency, we will use a homogenous list of trait objects. +For efficiency, we will use a homogeneous list of trait objects. Note that this function accepts a list of trait objects, but does not require putting them on the heap! Additionally, we can consume both the slice and its elements, which is not possible with other reference types. @@ -330,7 +330,7 @@ The following expressions can be owned place expression contexts: * Variables which are not currently borrowed. * Temporary values. * This must perform lifetime extension. -* Fields: this evaluates the subexpression in an owned place expression context. +* Fields: this evaluates the sub-expression in an owned place expression context. * Dereference of a `*mut T` pointer. * Dereference of a place, or field of a place, with type `Box`. * Dereference of a place, or field of a place, with type `&own T`. @@ -363,7 +363,7 @@ Unfortunately, the [alternative](#Alternative-Add-remote-drop-flags-to-support-p As Rust users, we are used to APIs of the form `fn into_foo(&own Self) -> &own Foo`. However, these APIs are often difficult or impossible to write. For example, we cannot write a function `Box::into_inner(&own self) -> &own T` without leaking the allocation. -In general, we cannot write such an API if `Self` requires droping (and the dropping involves the returned value). +In general, we cannot write such an API if `Self` requires dropping (and the dropping involves the returned value). This is the same problem as providing a `DerefOwn` trait ([see below](#Introduce-DerefOwn)). ### Teaching @@ -375,7 +375,7 @@ After a borrow expires, you can keep using the original value. But with owning references, once the borrow expires, the original value is gone. On the one hand, we believe that we do not need to bother Rust beginners with owning references. -[The Rust Book](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html), adresses the current primary alternative `Box` only in chapter 15, and owning references would be considered similar advanced usage. +[The Rust Book](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html), addresses the current primary alternative `Box` only in chapter 15, and owning references would be considered similar advanced usage. However, we would still need to adjust teaching to mention a third reference type, to be explained later. ### Documentation @@ -401,7 +401,7 @@ This is the current situation, and Rust users found a number of ways to work aro Primarily, users will use `Box` if they can and it isn't performance critical. If boxing is not available (too expensive, or no heap present), alternatives include using a `&mut Option` to pass runtime-checked ownership of `T`, or use a crate like [stackbox](https://docs.rs/stackbox/latest/stackbox/struct.StackBox.html). -However, as stated by [the `stackbox` maintaner themselves](https://internals.rust-lang.org/t/a-sketch-for-move-semantics/18632/19), there are some ergonimic challenges with a library implementation: +However, as stated by [the `stackbox` maintaner themselves](https://internals.rust-lang.org/t/a-sketch-for-move-semantics/18632/19), there are some ergonomic challenges with a library implementation: - Creating a stack box is cumbersome. - Especially lifetime extension is missing. @@ -450,12 +450,10 @@ However, there are a number of downsides to this approach: Additionally, it might just be *too weird*. By its own docs: -> `Box`, casually referred to as a ‘box’, provides the simplest form of -heap allocation in Rust. -> Boxes provide ownership for this allocation, and -drop their contents when they go out of scope. +> `Box`, casually referred to as a ‘box’, provides the simplest form of heap allocation in Rust. +> Boxes provide ownership for this allocation, and drop their contents when they go out of scope. -A `Box>` is neither a heap allocation, nor does it provide opwnership for its allocation. +A `Box>` is neither a heap allocation, nor does it provide ownership for its allocation. ### Alternative: Add remote drop flags to support pinning @@ -463,7 +461,7 @@ Unfortunately, `Pin<&own T>` is unsound with regards to the drop guarantee. This is because forgetting `Pin<&own T>` avoids running the drop implementation of `T`, but we have no control over the backing memory or the reference. If we'd want to fix this design to allow for pinning, we would have to change `&own` to track and possibly modify the drop flags of its allocation. -In this scenario, `Pin<&own T>` would behave similarly to an `Pin<&mut Option>`, which is already expressable today. +In this scenario, `Pin<&own T>` would behave similarly to an `Pin<&mut Option>`, which is already expressible today. While this could be an interesting design approach, we believe that remote drop flags would make the language design much more complicated. Instead, we proposed this much simpler design, even if that forbids pinning. @@ -476,7 +474,7 @@ Instead, we proposed this much simpler design, even if that forbids pinning. This RFC proposes a single new reference type, `&own`. There may be additional reference types we may want to add in the future, such as `&pin`, `&uninit`, `&out`, or `&init`. -It may be advantageous to increase the scope of this RFC to include other references, to avoid short-sighted desicions in this design space. +It may be advantageous to increase the scope of this RFC to include other references, to avoid short-sighted decisions in this design space. Besides the complexity in the language, we believe that major point of contention is the syntax space. Contextual keywords, as suggested here with `&own` work well, but might become annoying when there are too many. @@ -504,7 +502,7 @@ The `Bump::alloc(&self, val: T) -> &mut T` method allocates a `T` in the aren Since the arena does not keep track of the types of all of its allocations, it cannot drop `T`, and the mutable reference does not allow dropping the value either (without unsafe code). As a solution, it provides its own `Box` type, which drops its pointee when dropped. -This `Box` is effectively the same as `&own`, except for missing ergonimics. +This `Box` is effectively the same as `&own`, except for missing ergonomics. > Note that `bumpalo:box:Box` provides a pinning API, which is an known to be unsound. @@ -520,7 +518,7 @@ This could allow us, for example, to use `&own` as an initialization prove for c ### Should is be allowed to borrow through pointers? The unsafe operation `&own *ptr` would allow effectively casting the pointer to an owning reference. -This is allowed with other references, so it seems reaonable to allow this here too. +This is allowed with other references, so it seems reasonable to allow this here too. However, this operation additionally causes a deferred drop of the pointee as a side-effect. As an alternative, we could disallow this behavior (for now), and instead introduce some more explicitly named function `unsafe fn assume_owned<'a, T>'(ptr: *mut T) -> &own T`. @@ -594,7 +592,7 @@ fn consume_slice(elements: &own [T]) { } ``` -Syntactically, this is slightly more challenging since a contextual keyword is more tricky in this position (compred to, e.g., `ref(own)`). +Syntactically, this is slightly more challenging since a contextual keyword is more tricky in this position (compared to, e.g., `ref(own)`). ### Introduce `DerefOwn` (see [#997](https://github.com/rust-lang/rfcs/issues/997)) @@ -636,7 +634,7 @@ The "Immobile types and guaranteed destructors" project goal aims to introduce t A type `T: !Move` cannot be moved by value. However, due to the indirection, `&own T: Move` regardless of `T`. -This makes `&own` essential for transfering ownership of immovable types. +This makes `&own` essential for transferring ownership of immovable types. A type `T: !Forget` must be dropped before its backing allocation may be reused. This trivially makes `&own T: !Forget`, since forgetting the reference is equivalent to forgetting the value. @@ -704,4 +702,4 @@ Drain<'a, T, A>::as_owned(&mut self) -> &own [T] { ... } [^field-projections]: https://rust-lang.github.io/rust-project-goals/2026/field-projections.html -[^move-trait]: https://rust-lang.github.io/rust-project-goals/2026/move-trait.html \ No newline at end of file +[^move-trait]: https://rust-lang.github.io/rust-project-goals/2026/move-trait.html From 9139c15d35b9ac8c95302aeb03809721879f588c Mon Sep 17 00:00:00 2001 From: CheaterCodes <49926638+CheaterCodes@users.noreply.github.com> Date: Mon, 17 Aug 2026 10:40:57 +0200 Subject: [PATCH 3/7] Update RFC PR link --- text/0000-owning-references.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-owning-references.md b/text/0000-owning-references.md index e74e15533d3..378a4a31d06 100644 --- a/text/0000-owning-references.md +++ b/text/0000-owning-references.md @@ -1,6 +1,6 @@ - Feature Name: `own_ref` - Start Date: 2026-07-22 -- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/4000) - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) ## Summary From 900ca456bd22fad7e53b46a8ab6cd65fed7e8cd5 Mon Sep 17 00:00:00 2001 From: CheaterCodes <49926638+CheaterCodes@users.noreply.github.com> Date: Mon, 17 Aug 2026 10:41:29 +0200 Subject: [PATCH 4/7] Rename file to match PR number --- text/{0000-owning-references.md => 4000-owning-references.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename text/{0000-owning-references.md => 4000-owning-references.md} (100%) diff --git a/text/0000-owning-references.md b/text/4000-owning-references.md similarity index 100% rename from text/0000-owning-references.md rename to text/4000-owning-references.md From 869196b613570f81fb3837b5a96c30097576e649 Mon Sep 17 00:00:00 2001 From: CheaterCodes <49926638+CheaterCodes@users.noreply.github.com> Date: Mon, 17 Aug 2026 10:42:14 +0200 Subject: [PATCH 5/7] Fix RFC PR link render --- text/4000-owning-references.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/4000-owning-references.md b/text/4000-owning-references.md index 378a4a31d06..d72f3bb2ca1 100644 --- a/text/4000-owning-references.md +++ b/text/4000-owning-references.md @@ -1,6 +1,6 @@ - Feature Name: `own_ref` - Start Date: 2026-07-22 -- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/4000) +- RFC PR: [rust-lang/rfcs#4000](https://github.com/rust-lang/rfcs/pull/4000) - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) ## Summary From 62515859291c19ba30fcd170495a8ae1bdb8dcb7 Mon Sep 17 00:00:00 2001 From: CheaterCodes <49926638+CheaterCodes@users.noreply.github.com> Date: Thu, 20 Aug 2026 15:57:49 +0200 Subject: [PATCH 6/7] Apply suggestions from code review Co-authored-by: Daniel Henry-Mantilla --- text/4000-owning-references.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/text/4000-owning-references.md b/text/4000-owning-references.md index d72f3bb2ca1..63058b32487 100644 --- a/text/4000-owning-references.md +++ b/text/4000-owning-references.md @@ -413,7 +413,7 @@ However, as stated by [the `stackbox` maintaner themselves](https://internals.ru While many prior discussions use the `&own` notation, other options are available: - `&move` has been used in the past, indicating the "movement of ownership". - - We believe that this syntax isn't as clear in the implied semantics. + - We believe that this syntax isn't as clear in the implied semantics, as reference types, including this one, do very much not move the referee when they are themselves moved. - This could re-use the existing `move` keyword - However, there is ambiguity with closures: `&move || { }` - `&ref(own)` does not require a contextual keyword @@ -513,15 +513,15 @@ This `Box` is effectively the same as `&own`, except for missing ergonomics. While it is undisputed that it is *possible* to enable this property, there are concerns about its usefulness. If it is not necessary to be covariant, we could alternatively be invariant in `'a`. -This could allow us, for example, to use `&own` as an initialization prove for certain in-place-init proposals. +This could allow us, for example, to use `&own` as an initialization proof for certain in-place-init proposals. -### Should is be allowed to borrow through pointers? +### Should it be allowed to borrow through pointers? The unsafe operation `&own *ptr` would allow effectively casting the pointer to an owning reference. This is allowed with other references, so it seems reasonable to allow this here too. However, this operation additionally causes a deferred drop of the pointee as a side-effect. -As an alternative, we could disallow this behavior (for now), and instead introduce some more explicitly named function `unsafe fn assume_owned<'a, T>'(ptr: *mut T) -> &own T`. +As an alternative, we could disallow this behavior (for now), and instead introduce some more explicitly named function `unsafe fn assume_owned<'a, T>(ptr: *mut T) -> &own T`. ### How does `&own place` work if `place: Copy`? @@ -689,7 +689,7 @@ Vec::pop_own(&mut self) -> &own T { ... } // Extract an owning slice from the `Vec`, without dropping the allocation. // This way the allocation can be reused, and the slice processed further -// via pattern amtching or slice methods (e.g., splitting). +// via pattern matching or slice methods (e.g., splitting). Vec::take_all(&mut self) -> &own [T] { ... } // Allows the return value of `Vec::drain` to be converted to an owned slice. From 5185e67400019651d08e625975f570d6e5c1051b Mon Sep 17 00:00:00 2001 From: CheaterCodes <49926638+CheaterCodes@users.noreply.github.com> Date: Fri, 21 Aug 2026 12:59:59 +0200 Subject: [PATCH 7/7] Incorporated some feedback --- text/4000-owning-references.md | 78 ++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/text/4000-owning-references.md b/text/4000-owning-references.md index 63058b32487..565a7336f24 100644 --- a/text/4000-owning-references.md +++ b/text/4000-owning-references.md @@ -269,7 +269,7 @@ However, in a possible future where Rust splits immovability from the drop guara An *owning reference* type is written `&own T` or `&'a own T` for any type `T`. Owning references behave like mutable references, except that they own the value behind the reference, which means that: -- It is possible to move out of an `&own T`. +- It is possible to move out of an `&own T` (including partial moves). - Dropping an `&own T` drops the inner `T`. Owning references should be used when we want to transfer ownership and either do not want to or can not move the value. @@ -293,6 +293,20 @@ print_all(&own [ ]); ``` +Due to thier owning nature, in some cases a `&own T` behaves more like a `Box` than a `&mut T`. +For example, in order to mutate value inside an owned reference, the reference itself must be mutable: +```rust +let value = 42; +// We can move out of an immutable place with an owning borrow. +let own_ref = &own value; +// ERROR: We cannot mutate the value of a non-mutable owned reference +// *own_ref += 20; +// But we can move out of it +let mut own_ref = &own *own_ref; +// With a mutable binding, we may mutate the value +*own_ref += 5; +``` + ## Reference-level explanation [reference-level-explanation]: #reference-level-explanation @@ -343,7 +357,7 @@ The type `&'a own T` behaves similar like other references, except it owns the v - It is **covariant** in both `'a` and `T`. - It is an **exclusive** borrow. -- It may be reborrowed as a shared or mutable reference. +- It may be borrowed as a shared or mutable reference via the `Deref` and `DerefMut` traits. - It must be aligned, non-null, point to a valid `T`, and be "dereferencable". - When dereferenced, it produces an *owned* place (instead of a mutable one), which may be (partially) moved out of (like `Box`). - When dropped, it also drops its pointee (but does not free the allocation). @@ -356,7 +370,7 @@ The type `&'a own T` behaves similar like other references, except it owns the v This simple approach to owning references cannot support pinning. A `Pin<&'a own T>` is unsound, since forgetting the reference violates the drop guarantee (unless `'a: 'static`). This may be confusing to users, since they often only consider the immovability guarantee of `Pin`. -Unfortunately, the [alternative](#Alternative-Add-remote-drop-flags-to-support-pinning) is more complex, and we believe that it is not worth it. +Unfortunately, the [alternative](#Alternative-Add-remote-drop-flags-to-support-pinning) is more complex, and we believe that it is not worth it, since it makes owning references more expensive and complicated than their syntax would suggest. ### Some easy APIs are actually hard @@ -408,6 +422,9 @@ However, as stated by [the `stackbox` maintaner themselves](https://internals.ru - `&own self` receivers are not (currently) possible. - It is non-straightforward to write functions are "allocation-agnostic", i.e., work with both `Box` and `StackBox`. +Additionally, a library type cannot directly benefit from compiler optimizations such as `noalias` and `dereferencable`. +This can't currently be done soundly with a `Box`, since `noalias` does not work with custom allocators. + ### Alternative: Syntax options While many prior discussions use the `&own` notation, other options are available: @@ -421,7 +438,7 @@ While many prior discussions use the `&own` notation, other options are availabl - Doubles the amount of typing and adds visual clutter - `Own<'_, T>` could use normal type syntax, avoiding additional parsing complexity. - This would visually more closely resemble `Box` rather than other reference types - - This would likely need a macro to perform (re-)borrowing + - It is unclear how the borrow syntax would work in this case ### Alternative: Wait for custom references @@ -442,7 +459,8 @@ On the upside, this would allow functions accepting an allocator-generic `Box` w However, there are a number of downsides to this approach: - The `Box` API is too general. - For example, it would mean that `Own<'a, T>: Clone` if `T: Clone`. However, calling this method would have to panic with the `Noop` allocator. + For example, `Box::allocator` would have to return the `Noop` allocator, which cannot allocate memory and therefore will have to panic on most methods. + This would be a hazard for allocator agnostic code. - There might be subtle differences in the types that are currently unknown. For example, we might want different aliasing rules for the types. - `Box` is (currently) not available in `no_std` (unless `alloc` is enabled), so APIs compatible with `no_std` cannot take `Box` as an argument. @@ -457,13 +475,14 @@ A `Box>` is neither a heap allocation, nor does it provide ownership ### Alternative: Add remote drop flags to support pinning -Unfortunately, `Pin<&own T>` is unsound with regards to the drop guarantee. +Unfortunately, `Pin<&'a own T>` is unsound with regards to the drop guarantee (unless `'a: 'static`). This is because forgetting `Pin<&own T>` avoids running the drop implementation of `T`, but we have no control over the backing memory or the reference. If we'd want to fix this design to allow for pinning, we would have to change `&own` to track and possibly modify the drop flags of its allocation. In this scenario, `Pin<&own T>` would behave similarly to an `Pin<&mut Option>`, which is already expressible today. While this could be an interesting design approach, we believe that remote drop flags would make the language design much more complicated. +Additionally, it would come at a non-zero runtime overhead one would not expect from fundamental reference types. Instead, we proposed this much simpler design, even if that forbids pinning. > See the [`own-ref` crate](https://docs.rs/own-ref/0.1.0-alpha/own_ref/pin/index.html), which allows adding drop-flags via a generic on the reference, and how that helps with pinning. @@ -511,9 +530,13 @@ This `Box` is effectively the same as `&own`, except for missing ergonomics. ### Does `&'a own T` need to be covariant in `'a`? -While it is undisputed that it is *possible* to enable this property, there are concerns about its usefulness. -If it is not necessary to be covariant, we could alternatively be invariant in `'a`. -This could allow us, for example, to use `&own` as an initialization proof for certain in-place-init proposals. +While it is undisputed that covariance is a useful and ergonomic property, it is not truly necessary. +An invariant lifetime may allow to, e.g., use `&own` as a initialization proof for certain in-place-init proposals. + +However, it is unclear whether such an invariant `&own` is sufficient or necessary as an initialization proof. +Lifetime branding requires additional care to avoid duplicating or transferring the brand, and in some scenarios a zero-sized proof may be preferable. + +If we in the future decide to attach a branding to owning references, we could introduce a second lifetime in a backwards compatible way, e.g., `&'a own<'brand> T`, or provide a separate branded type, e.g., `Init<'a, 'brand, T>(&'a own T, PhantomBranded<'brand>)`. ### Should it be allowed to borrow through pointers? @@ -533,7 +556,7 @@ So this behavior is consistent, but might be surprising (and new in the Rust lan ```rs let x = 5u32; { - let owned = &own x; + let mut owned = &own x; *owned += 2; } assert_eq!(x, 5); // Error: Use of moved value @@ -543,26 +566,23 @@ If we consider the place not moved out, the referee may be modified after the bo ```rs let mut x = 5u32; { - let owned = &own x; + let mut owned = &own x; *owned += 2; } assert_eq!(x, 5); // Assertion failed; 7 != 5 ``` -The final option is to use the "trivial copy" property of `Copy` types, and simply restore the value after the borrow. - +However, if we want to avoid moving out of a `Copy` place, we can borrow a (lifetime extended) temporary instead: ```rs let x = 5u32; { - let temp = x; // Compiler generated - let owned = &own x; + let mut owned = &own { x }; *owned += 2; - x = temp; // Compiler generated } assert_eq!(x, 5); // Now the assertion passes ``` -We suggest the first option, one of the others could also be added later. +We suggest that an owning borrow should move out of a place, regardless of its type, since it is likely the simpler implementation, and strinctly more powerful. ## Future possibilities [future-possibilities]: #future-possibilities @@ -581,13 +601,10 @@ Analog to other reference types, we could introduce a new binding mode `own`. As an example, this enables an ergonomic way to recursively consume a slice: ```rust -fn consume_slice(elements: &own [T]) { - match *elements { - [entry, ref own rest @ ..] => { - consume_entry(entry); - consume_slice(elements); - }, - [] => { } +fn consume_slice(mut elements: &own [T]) { + while let [head, ref own tail @ ..] = *elements { + consume_entry(head); + elements = tail; } } ``` @@ -624,9 +641,12 @@ fn foo(func: Box) { ``` However, implementing such a trait is difficult, since it is unclear when the "shell" of a type (e.g., the allocation of `Box`) will be freed. -Therefore, the design of such a trait is left for a future RFC, especially since it may involve additional missing Rust features (e.g., self-referential types); +Therefore, the design of such a trait is left for a future RFC, especially since it may involve additional missing Rust features (e.g., self-referential types). +Some relevant prior discussion during the lead-up for this RFC can be found on Zulip: +[#t-lang > `&own` tangent: `DerefOwned` musings](https://rust-lang.zulipchat.com/#narrow/channel/213817-t-lang/topic/.60.26own.60.20tangent.3A.20.60DerefOwned.60.20musings/near/614756248) -There is ongoing work in the "field projections" project goal[^field-projections] that attempts to allow equivalent behavior via a more generic `DerefPlace`. + +There is also ongoing work in the "field projections" project goal[^field-projections] that attempts to allow equivalent behavior via a more generic `DerefPlace`. ### Interactions with `Move` and `Forget` @@ -638,7 +658,7 @@ This makes `&own` essential for transferring ownership of immovable types. A type `T: !Forget` must be dropped before its backing allocation may be reused. This trivially makes `&own T: !Forget`, since forgetting the reference is equivalent to forgetting the value. -However, we would additionally require that `&own T: !Leak`, since leaking the reference would allow reusing the backing allocation without ever dropping `T`. +However, we would additionally require that `&'a own T: !Leak` (unless `'a: 'static`), since leaking the reference would allow reusing the backing allocation without ever dropping `T`. #### Statically-fused futures @@ -697,6 +717,10 @@ Vec::take_all(&mut self) -> &own [T] { ... } // Also note that we can reuse the backing allocation, even though we consume the elements. // `vec.drain().as_owned()` is similar to `vec.take_all()` (with temporary lifetime extension) Drain<'a, T, A>::as_owned(&mut self) -> &own [T] { ... } + +// Convert an owned reference `usize` into a `NonZeroUsize`, returning the original reference in case of a failure. +// This is a toy example for how APIs can "change" the type of their target. +NonZeroUsize::try_from_own(value: &own usize) -> Result<&own Self, &own usize> ```