From 3adc4f3f13e704717bc54d549260ddc9b560acfb Mon Sep 17 00:00:00 2001 From: Finn Bear Date: Sun, 18 Sep 2022 15:19:30 -0700 Subject: [PATCH 1/4] String::leak RFC text. --- text/0000-string-leak.md | 71 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 text/0000-string-leak.md diff --git a/text/0000-string-leak.md b/text/0000-string-leak.md new file mode 100644 index 00000000000..436c74af192 --- /dev/null +++ b/text/0000-string-leak.md @@ -0,0 +1,71 @@ +- Feature Name: string_leak +- Start Date: (2022-09-18) +- 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 + +Add `String::leak` analogous to [`Vec::leak`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.leak). + +# Motivation +[motivation]: #motivation + +The existing alternative of `Box::leak(string.into_boxed_str())` may reallocate the string, which is presumably why +[`Vec::leak`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.leak) exists. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +`String::leak` works exactly like [`Vec::::leak`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.leak) except that +it preserves the guarantee that the bytes are valid `utf8`. + +For example, the following code leaks a `String` without reallocation. ```rust +let string = String::with_capacity(1000); +string.push_str("Hello world!"); +let leaked: &'static mut str = string.leak(); +println!("{}", leaked); +``` + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +```rust +impl String { + pub fn leak(self) -> &'static mut str { + let me = s.into_bytes().leak(); + // Safety: Bytes from a [`String`] are valid utf8. + unsafe { std::str::from_utf8_unchecked_mut(me) } + } +} +``` + +# Drawbacks +[drawbacks]: #drawbacks + +`String` API has added complexity. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +- This design is the best because it is analogous to the existing [`Vec::leak`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.leak). +- I couldn't think of any other designs to get the same effect. +- The impact of not doing this is that those who want the same effect will be forced to use `unsafe` to avoid reallocation or pay the performance and code size penalty for reallocation. + +# Prior art +[prior-art]: #prior-art + +As previously emphasized, this change is an extension of [`Vec::leak`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.leak). + +Right now, [StackOverflow answers](https://stackoverflow.com/a/30527289) suggest using +`Box::leak(string.into_boxed_str())`, which shrinks the string to fit, possibly causing unnecessary reallocation. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +N/A + +# Future possibilities +[future-possibilities]: #future-possibilities + +I couldn't think of any. From db55c611f9f62dc83bc67cc19a555be78a421aba Mon Sep 17 00:00:00 2001 From: Finn Bear Date: Sun, 18 Sep 2022 15:21:13 -0700 Subject: [PATCH 2/4] Edits. --- text/0000-string-leak.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/text/0000-string-leak.md b/text/0000-string-leak.md index 436c74af192..99353237a88 100644 --- a/text/0000-string-leak.md +++ b/text/0000-string-leak.md @@ -20,7 +20,8 @@ The existing alternative of `Box::leak(string.into_boxed_str())` may reallocate `String::leak` works exactly like [`Vec::::leak`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.leak) except that it preserves the guarantee that the bytes are valid `utf8`. -For example, the following code leaks a `String` without reallocation. ```rust +For example, the following code leaks a `String` without reallocation. +```rust let string = String::with_capacity(1000); string.push_str("Hello world!"); let leaked: &'static mut str = string.leak(); @@ -33,7 +34,7 @@ println!("{}", leaked); ```rust impl String { pub fn leak(self) -> &'static mut str { - let me = s.into_bytes().leak(); + let me = self.into_bytes().leak(); // Safety: Bytes from a [`String`] are valid utf8. unsafe { std::str::from_utf8_unchecked_mut(me) } } From 70a55eb4c40ddd18d94ed82631bdd468df6d42a5 Mon Sep 17 00:00:00 2001 From: Finn Bear Date: Sun, 18 Sep 2022 15:24:34 -0700 Subject: [PATCH 3/4] Add RFC number. --- text/{0000-string-leak.md => 3317-string-leak.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename text/{0000-string-leak.md => 3317-string-leak.md} (96%) diff --git a/text/0000-string-leak.md b/text/3317-string-leak.md similarity index 96% rename from text/0000-string-leak.md rename to text/3317-string-leak.md index 99353237a88..0a955f82f02 100644 --- a/text/0000-string-leak.md +++ b/text/3317-string-leak.md @@ -1,6 +1,6 @@ - Feature Name: string_leak - Start Date: (2022-09-18) -- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- RFC PR: [rust-lang/rfcs#3317](https://github.com/rust-lang/rfcs/pull/3317) - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) # Summary From 37389c57035a5f967e1e1ee0600ee38d65bb0f44 Mon Sep 17 00:00:00 2001 From: Finn Bear Date: Sun, 18 Sep 2022 15:28:08 -0700 Subject: [PATCH 4/4] Lifetime. --- text/3317-string-leak.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/3317-string-leak.md b/text/3317-string-leak.md index 0a955f82f02..176385b64b4 100644 --- a/text/3317-string-leak.md +++ b/text/3317-string-leak.md @@ -33,13 +33,14 @@ println!("{}", leaked); ```rust impl String { - pub fn leak(self) -> &'static mut str { + pub fn leak<'a>(self) -> &'a mut str { let me = self.into_bytes().leak(); // Safety: Bytes from a [`String`] are valid utf8. unsafe { std::str::from_utf8_unchecked_mut(me) } } } ``` +*note: It may be necessary to bound the allocator's lifetime. # Drawbacks [drawbacks]: #drawbacks