Skip to content

Commit 398d3ee

Browse files
authored
Rollup merge of #71421 - elichai:2020-04-boxed-slice, r=sfackler
Add a function to turn Box<T> into Box<[T]> Hi, I think this is very useful, as currently it's not possible in safe rust to do this without re-allocating. an alternative implementation of the same function can be: ```rust pub fn into_boxed_slice<T>(boxed: Box<T>) -> Box<[T]> { unsafe { let slice = slice::from_raw_parts_mut(Box::into_raw(boxed), 1); Box::from_raw(slice) } } ``` The only thing that makes me a little uncomfortable is this line : > The alignment of array types is greater or equal to the alignment of its element type from https://rust-lang.github.io/unsafe-code-guidelines/layout/arrays-and-slices.html But then I see: > The alignment of &T, &mut T, *const T and *mut T are the same, and are at least the word size. > The alignment of &[T] is the word size. from https://rust-lang.github.io/unsafe-code-guidelines/layout/pointers.html#representation So I do believe this is valid(FWIW it also passes in miri https://play.rust-lang.org/?gist=c002b99364ee6b29862aeb3565a91c19)
2 parents 7f3b3df + 0228ca0 commit 398d3ee

4 files changed

+79
-0
lines changed

src/liballoc/boxed.rs

+10
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,16 @@ impl<T> Box<T> {
239239
pub fn pin(x: T) -> Pin<Box<T>> {
240240
(box x).into()
241241
}
242+
243+
/// Converts a `Box<T>` into a `Box<[T]>`
244+
///
245+
/// This conversion does not allocate on the heap and happens in place.
246+
///
247+
#[unstable(feature = "box_into_boxed_slice", issue = "71582")]
248+
pub fn into_boxed_slice(boxed: Box<T>) -> Box<[T]> {
249+
// *mut T and *mut [T; 1] have the same size and alignment
250+
unsafe { Box::from_raw(Box::into_raw(boxed) as *mut [T; 1] as *mut [T]) }
251+
}
242252
}
243253

244254
impl<T> Box<[T]> {
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// ignore-tidy-linelength
2+
#![feature(box_into_boxed_slice)]
3+
4+
use std::boxed::Box;
5+
use std::fmt::Debug;
6+
fn main() {
7+
let boxed_slice = Box::new([1,2,3]) as Box<[u8]>;
8+
let _ = Box::into_boxed_slice(boxed_slice);
9+
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
10+
//~^^ ERROR the size for values of type `[u8]` cannot be known at compilation time
11+
let boxed_trait: Box<dyn Debug> = Box::new(5u8);
12+
let _ = Box::into_boxed_slice(boxed_trait);
13+
//~^ ERROR the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time
14+
//~^^ ERROR the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
2+
--> $DIR/box-into-boxed-slice-fail.rs:8:35
3+
|
4+
LL | let _ = Box::into_boxed_slice(boxed_slice);
5+
| ^^^^^^^^^^^ doesn't have a size known at compile-time
6+
|
7+
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
8+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
9+
= note: required by `std::boxed::Box::<T>::into_boxed_slice`
10+
11+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
12+
--> $DIR/box-into-boxed-slice-fail.rs:8:13
13+
|
14+
LL | let _ = Box::into_boxed_slice(boxed_slice);
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
16+
|
17+
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
18+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
19+
= note: slice and array elements must have `Sized` type
20+
21+
error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time
22+
--> $DIR/box-into-boxed-slice-fail.rs:12:35
23+
|
24+
LL | let _ = Box::into_boxed_slice(boxed_trait);
25+
| ^^^^^^^^^^^ doesn't have a size known at compile-time
26+
|
27+
= help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug`
28+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
29+
= note: required by `std::boxed::Box::<T>::into_boxed_slice`
30+
31+
error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time
32+
--> $DIR/box-into-boxed-slice-fail.rs:12:13
33+
|
34+
LL | let _ = Box::into_boxed_slice(boxed_trait);
35+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
36+
|
37+
= help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug`
38+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
39+
= note: slice and array elements must have `Sized` type
40+
41+
error: aborting due to 4 previous errors
42+
43+
For more information about this error, try `rustc --explain E0277`.

src/test/ui/box-into-boxed-slice.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// run-pass
2+
#![feature(box_into_boxed_slice)]
3+
4+
use std::boxed::Box;
5+
fn main() {
6+
assert_eq!(Box::into_boxed_slice(Box::new(5u8)), Box::new([5u8]) as Box<[u8]>);
7+
assert_eq!(Box::into_boxed_slice(Box::new([25u8])), Box::new([[25u8]]) as Box<[[u8; 1]]>);
8+
let a: Box<[Box<[u8; 1]>]> = Box::into_boxed_slice(Box::new(Box::new([5u8])));
9+
let b: Box<[Box<[u8; 1]>]> = Box::new([Box::new([5u8])]);
10+
assert_eq!(a, b);
11+
}

0 commit comments

Comments
 (0)