Skip to content

Commit dad9814

Browse files
committed
Auto merge of #41258 - clarcharr:str_box_extras, r=Kimundi
More methods for str boxes. (reduce Box<[u8]> ↔ Box<str> transmutes) This is a follow-up to #41096 that adds safer methods for converting between `Box<str>` and `Box<[u8]>`. They're gated under a different feature from the `&mut str` methods because they may be too niche to include in public APIs, although having them internally helps reduce the number of transmutes the standard library uses. What's added: * `From<Box<str>> for Box<[u8]>` * `<Box<str>>::into_boxed_bytes` (just calls `Into::into`) * `alloc::str` (new module) * `from_boxed_utf8` and `from_boxed_utf8_unchecked`, defined in `alloc:str`, exported in `collections::str` * exports `from_utf8_mut` in `collections::str` (missed from previous PR)
2 parents 4512424 + c66c6e9 commit dad9814

File tree

8 files changed

+60
-8
lines changed

8 files changed

+60
-8
lines changed

src/doc/unstable-book/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@
202202
- [str_checked_slicing](library-features/str-checked-slicing.md)
203203
- [str_escape](library-features/str-escape.md)
204204
- [str_internals](library-features/str-internals.md)
205+
- [str_box_extras](library-features/str-box-extras.md)
205206
- [str_mut_extras](library-features/str-mut-extras.md)
206207
- [test](library-features/test.md)
207208
- [thread_id](library-features/thread-id.md)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# `str_box_extras`
2+
3+
The tracking issue for this feature is: [#str_box_extras]
4+
5+
[#str_box_extras]: https://github.com/rust-lang/rust/issues/41119
6+
7+
------------------------
8+
9+

src/liballoc/boxed.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ use core::ops::{CoerceUnsized, Deref, DerefMut};
6868
use core::ops::{BoxPlace, Boxed, InPlace, Place, Placer};
6969
use core::ptr::{self, Unique};
7070
use core::convert::From;
71+
use str::from_boxed_utf8_unchecked;
7172

7273
/// A value that represents the heap. This is the default place that the `box`
7374
/// keyword allocates into when no place is supplied.
@@ -320,8 +321,7 @@ impl<T> Default for Box<[T]> {
320321
#[stable(feature = "default_box_extra", since = "1.17.0")]
321322
impl Default for Box<str> {
322323
fn default() -> Box<str> {
323-
let default: Box<[u8]> = Default::default();
324-
unsafe { mem::transmute(default) }
324+
unsafe { from_boxed_utf8_unchecked(Default::default()) }
325325
}
326326
}
327327

@@ -366,7 +366,7 @@ impl Clone for Box<str> {
366366
let buf = RawVec::with_capacity(len);
367367
unsafe {
368368
ptr::copy_nonoverlapping(self.as_ptr(), buf.ptr(), len);
369-
mem::transmute(buf.into_box()) // bytes to str ~magic
369+
from_boxed_utf8_unchecked(buf.into_box())
370370
}
371371
}
372372
}
@@ -441,8 +441,16 @@ impl<'a, T: Copy> From<&'a [T]> for Box<[T]> {
441441
#[stable(feature = "box_from_slice", since = "1.17.0")]
442442
impl<'a> From<&'a str> for Box<str> {
443443
fn from(s: &'a str) -> Box<str> {
444-
let boxed: Box<[u8]> = Box::from(s.as_bytes());
445-
unsafe { mem::transmute(boxed) }
444+
unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) }
445+
}
446+
}
447+
448+
#[stable(feature = "boxed_str_conv", since = "1.18.0")]
449+
impl From<Box<str>> for Box<[u8]> {
450+
fn from(s: Box<str>) -> Self {
451+
unsafe {
452+
mem::transmute(s)
453+
}
446454
}
447455
}
448456

src/liballoc/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ mod boxed_test;
129129
pub mod arc;
130130
pub mod rc;
131131
pub mod raw_vec;
132+
#[unstable(feature = "str_box_extras", issue = "41119")]
133+
pub mod str;
132134
pub mod oom;
133135

134136
pub use oom::oom;

src/liballoc/str.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Methods for dealing with boxed strings.
12+
use core::mem;
13+
14+
use boxed::Box;
15+
16+
/// Converts a boxed slice of bytes to a boxed string slice without checking
17+
/// that the string contains valid UTF-8.
18+
#[unstable(feature = "str_box_extras", issue = "41119")]
19+
pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
20+
mem::transmute(v)
21+
}

src/libcollections/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#![feature(specialization)]
6161
#![feature(staged_api)]
6262
#![feature(str_internals)]
63+
#![feature(str_box_extras)]
6364
#![feature(str_mut_extras)]
6465
#![feature(trusted_len)]
6566
#![feature(unicode)]

src/libcollections/str.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,17 @@ pub use core::str::{Matches, RMatches};
7070
#[stable(feature = "rust1", since = "1.0.0")]
7171
pub use core::str::{MatchIndices, RMatchIndices};
7272
#[stable(feature = "rust1", since = "1.0.0")]
73-
pub use core::str::{from_utf8, Chars, CharIndices, Bytes};
73+
pub use core::str::{from_utf8, from_utf8_mut, Chars, CharIndices, Bytes};
7474
#[stable(feature = "rust1", since = "1.0.0")]
7575
pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError};
76+
#[unstable(feature = "str_box_extras", issue = "41119")]
77+
pub use alloc::str::from_boxed_utf8_unchecked;
7678
#[stable(feature = "rust1", since = "1.0.0")]
7779
pub use std_unicode::str::SplitWhitespace;
7880
#[stable(feature = "rust1", since = "1.0.0")]
7981
pub use core::str::pattern;
8082

83+
8184
#[unstable(feature = "slice_concat_ext",
8285
reason = "trait should not have to exist",
8386
issue = "27747")]
@@ -1715,6 +1718,12 @@ impl str {
17151718
core_str::StrExt::parse(self)
17161719
}
17171720

1721+
/// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating.
1722+
#[unstable(feature = "str_box_extras", issue = "41119")]
1723+
pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]> {
1724+
self.into()
1725+
}
1726+
17181727
/// Replaces all matches of a pattern with another string.
17191728
///
17201729
/// `replace` creates a new [`String`], and copies the data from this string slice into it.

src/libcollections/string.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,11 @@
5656
5757
#![stable(feature = "rust1", since = "1.0.0")]
5858

59+
use alloc::str as alloc_str;
60+
5961
use core::fmt;
6062
use core::hash;
6163
use core::iter::{FromIterator, FusedIterator};
62-
use core::mem;
6364
use core::ops::{self, Add, AddAssign, Index, IndexMut};
6465
use core::ptr;
6566
use core::str as core_str;
@@ -1463,7 +1464,7 @@ impl String {
14631464
#[stable(feature = "box_str", since = "1.4.0")]
14641465
pub fn into_boxed_str(self) -> Box<str> {
14651466
let slice = self.vec.into_boxed_slice();
1466-
unsafe { mem::transmute::<Box<[u8]>, Box<str>>(slice) }
1467+
unsafe { alloc_str::from_boxed_utf8_unchecked(slice) }
14671468
}
14681469
}
14691470

0 commit comments

Comments
 (0)