Skip to content

Commit

Permalink
Auto merge of #61515 - shepmaster:boxed-slice-to-array, r=cramertj
Browse files Browse the repository at this point in the history
Add implementations for converting boxed slices into boxed arrays

This mirrors the implementations of reference slices into arrays.

# Discussion

- [x] Should we use const generics? ([probably not](#61515 (comment)))
- [ ] [What's the safety rationale here](#61515 (comment))?
- [ ] [Should the errors return the original object](#61515 (comment))?

# Remaining

- [ ] Implement `Error`
- [ ] Create a tracking issue
  • Loading branch information
bors committed Aug 5, 2019
2 parents c471519 + 32324d2 commit 09a245b
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 6 deletions.
19 changes: 18 additions & 1 deletion src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,10 @@
#![stable(feature = "rust1", since = "1.0.0")]

use core::any::Any;
use core::array::LengthAtMost32;
use core::borrow;
use core::cmp::Ordering;
use core::convert::From;
use core::convert::{From, TryFrom};
use core::fmt;
use core::future::Future;
use core::hash::{Hash, Hasher};
Expand Down Expand Up @@ -612,6 +613,22 @@ impl From<Box<str>> for Box<[u8]> {
}
}

#[unstable(feature = "boxed_slice_try_from", issue = "0")]
impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]>
where
[T; N]: LengthAtMost32,
{
type Error = Box<[T]>;

fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> {
if boxed_slice.len() == N {
Ok(unsafe { Box::from_raw(Box::into_raw(boxed_slice) as *mut [T; N]) })
} else {
Err(boxed_slice)
}
}
}

impl Box<dyn Any> {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
2 changes: 1 addition & 1 deletion src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@
#![feature(box_syntax)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![cfg_attr(not(bootstrap), feature(const_in_array_repeat_expressions))]
#![feature(const_generic_impls_guard)]
#![feature(const_generics)]
#![cfg_attr(not(bootstrap), feature(const_in_array_repeat_expressions))]
#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
#![feature(dropck_eyepatch)]
Expand Down
19 changes: 18 additions & 1 deletion src/liballoc/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ use crate::boxed::Box;
use std::boxed::Box;

use core::any::Any;
use core::array::LengthAtMost32;
use core::borrow;
use core::cell::Cell;
use core::cmp::Ordering;
Expand All @@ -245,7 +246,7 @@ use core::ops::{Deref, Receiver, CoerceUnsized, DispatchFromDyn};
use core::pin::Pin;
use core::ptr::{self, NonNull};
use core::slice::{self, from_raw_parts_mut};
use core::convert::From;
use core::convert::{From, TryFrom};
use core::usize;

use crate::alloc::{Global, Alloc, Layout, box_free, handle_alloc_error};
Expand Down Expand Up @@ -1257,6 +1258,22 @@ impl<T> From<Vec<T>> for Rc<[T]> {
}
}

#[unstable(feature = "boxed_slice_try_from", issue = "0")]
impl<T, const N: usize> TryFrom<Rc<[T]>> for Rc<[T; N]>
where
[T; N]: LengthAtMost32,
{
type Error = Rc<[T]>;

fn try_from(boxed_slice: Rc<[T]>) -> Result<Self, Self::Error> {
if boxed_slice.len() == N {
Ok(unsafe { Rc::from_raw(Rc::into_raw(boxed_slice) as *mut [T; N]) })
} else {
Err(boxed_slice)
}
}
}

#[stable(feature = "shared_from_iter", since = "1.37.0")]
impl<T> iter::FromIterator<T> for Rc<[T]> {
/// Takes each element in the `Iterator` and collects it into an `Rc<[T]>`.
Expand Down
14 changes: 13 additions & 1 deletion src/liballoc/rc/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::option::Option::{self, None, Some};
use std::result::Result::{Err, Ok};
use std::mem::drop;
use std::clone::Clone;
use std::convert::From;
use std::convert::{From, TryInto};

#[test]
fn test_clone() {
Expand Down Expand Up @@ -425,3 +425,15 @@ fn test_downcast() {
assert!(r2str.is_ok());
assert_eq!(r2str.unwrap(), Rc::new("abc"));
}

#[test]
fn test_array_from_slice() {
let v = vec![1, 2, 3];
let r: Rc<[u32]> = Rc::from(v);

let a: Result<Rc<[u32; 3]>, _> = r.clone().try_into();
assert!(a.is_ok());

let a: Result<Rc<[u32; 2]>, _> = r.clone().try_into();
assert!(a.is_err());
}
19 changes: 18 additions & 1 deletion src/liballoc/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//! [arc]: struct.Arc.html

use core::any::Any;
use core::array::LengthAtMost32;
use core::sync::atomic;
use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
use core::borrow;
Expand All @@ -21,7 +22,7 @@ use core::ptr::{self, NonNull};
use core::marker::{Unpin, Unsize, PhantomData};
use core::hash::{Hash, Hasher};
use core::{isize, usize};
use core::convert::From;
use core::convert::{From, TryFrom};
use core::slice::{self, from_raw_parts_mut};

use crate::alloc::{Global, Alloc, Layout, box_free, handle_alloc_error};
Expand Down Expand Up @@ -1826,6 +1827,22 @@ impl<T> From<Vec<T>> for Arc<[T]> {
}
}

#[unstable(feature = "boxed_slice_try_from", issue = "0")]
impl<T, const N: usize> TryFrom<Arc<[T]>> for Arc<[T; N]>
where
[T; N]: LengthAtMost32,
{
type Error = Arc<[T]>;

fn try_from(boxed_slice: Arc<[T]>) -> Result<Self, Self::Error> {
if boxed_slice.len() == N {
Ok(unsafe { Arc::from_raw(Arc::into_raw(boxed_slice) as *mut [T; N]) })
} else {
Err(boxed_slice)
}
}
}

#[stable(feature = "shared_from_iter", since = "1.37.0")]
impl<T> iter::FromIterator<T> for Arc<[T]> {
/// Takes each element in the `Iterator` and collects it into an `Arc<[T]>`.
Expand Down
14 changes: 13 additions & 1 deletion src/liballoc/sync/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::option::Option::{self, None, Some};
use std::sync::atomic::{self, Ordering::{Acquire, SeqCst}};
use std::thread;
use std::sync::Mutex;
use std::convert::From;
use std::convert::{From, TryInto};

use crate::vec::Vec;

Expand Down Expand Up @@ -478,3 +478,15 @@ fn test_downcast() {
assert!(r2str.is_ok());
assert_eq!(r2str.unwrap(), Arc::new("abc"));
}

#[test]
fn test_array_from_slice() {
let v = vec![1, 2, 3];
let r: Arc<[u32]> = Arc::from(v);

let a: Result<Arc<[u32; 3]>, _> = r.clone().try_into();
assert!(a.is_ok());

let a: Result<Arc<[u32; 2]>, _> = r.clone().try_into();
assert!(a.is_err());
}
13 changes: 13 additions & 0 deletions src/liballoc/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Test for `boxed` mod.

use core::any::Any;
use core::convert::TryInto;
use core::ops::Deref;
use core::result::Result::{Err, Ok};
use core::clone::Clone;
Expand Down Expand Up @@ -138,3 +139,15 @@ fn boxed_slice_from_iter() {
assert_eq!(boxed.len(), 100);
assert_eq!(boxed[7], 7);
}

#[test]
fn test_array_from_slice() {
let v = vec![1, 2, 3];
let r: Box<[u32]> = v.into_boxed_slice();

let a: Result<Box<[u32; 3]>, _> = r.clone().try_into();
assert!(a.is_ok());

let a: Result<Box<[u32; 2]>, _> = r.clone().try_into();
assert!(a.is_err());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// ignore-tidy-linelength

use std::{convert::TryFrom, rc::Rc, sync::Arc};

pub fn no_box() {
let boxed_slice = Box::new([0; 33]) as Box<[i32]>;
let boxed_array = <Box<[i32; 33]>>::try_from(boxed_slice);
//~^ ERROR the trait bound `std::boxed::Box<[i32; 33]>: std::convert::From<std::boxed::Box<[i32]>>` is not satisfied
//~^^ ERROR the trait bound `std::boxed::Box<[i32; 33]>: std::convert::TryFrom<std::boxed::Box<[i32]>>` is not satisfied
}

pub fn no_rc() {
let boxed_slice = Rc::new([0; 33]) as Rc<[i32]>;
let boxed_array = <Rc<[i32; 33]>>::try_from(boxed_slice);
//~^ ERROR the trait bound `std::rc::Rc<[i32; 33]>: std::convert::From<std::rc::Rc<[i32]>>` is not satisfied
//~^^ ERROR the trait bound `std::rc::Rc<[i32; 33]>: std::convert::TryFrom<std::rc::Rc<[i32]>>` is not satisfied
}

pub fn no_arc() {
let boxed_slice = Arc::new([0; 33]) as Arc<[i32]>;
let boxed_array = <Arc<[i32; 33]>>::try_from(boxed_slice);
//~^ ERROR the trait bound `std::sync::Arc<[i32; 33]>: std::convert::From<std::sync::Arc<[i32]>>` is not satisfied
//~^^ ERROR the trait bound `std::sync::Arc<[i32; 33]>: std::convert::TryFrom<std::sync::Arc<[i32]>>` is not satisfied
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
error[E0277]: the trait bound `std::boxed::Box<[i32; 33]>: std::convert::From<std::boxed::Box<[i32]>>` is not satisfied
--> $DIR/alloc-types-no-impls-length-33.rs:7:23
|
LL | let boxed_array = <Box<[i32; 33]>>::try_from(boxed_slice);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<std::boxed::Box<[i32]>>` is not implemented for `std::boxed::Box<[i32; 33]>`
|
= help: the following implementations were found:
<std::boxed::Box<(dyn std::error::Error + 'a)> as std::convert::From<E>>
<std::boxed::Box<(dyn std::error::Error + 'static)> as std::convert::From<&str>>
<std::boxed::Box<(dyn std::error::Error + 'static)> as std::convert::From<std::borrow::Cow<'a, str>>>
<std::boxed::Box<(dyn std::error::Error + 'static)> as std::convert::From<std::string::String>>
and 16 others
= note: required because of the requirements on the impl of `std::convert::Into<std::boxed::Box<[i32; 33]>>` for `std::boxed::Box<[i32]>`
= note: required because of the requirements on the impl of `std::convert::TryFrom<std::boxed::Box<[i32]>>` for `std::boxed::Box<[i32; 33]>`

error[E0277]: the trait bound `std::boxed::Box<[i32; 33]>: std::convert::TryFrom<std::boxed::Box<[i32]>>` is not satisfied
--> $DIR/alloc-types-no-impls-length-33.rs:7:23
|
LL | let boxed_array = <Box<[i32; 33]>>::try_from(boxed_slice);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom<std::boxed::Box<[i32]>>` is not implemented for `std::boxed::Box<[i32; 33]>`
|
= help: the following implementations were found:
<std::boxed::Box<[T; _]> as std::convert::TryFrom<std::boxed::Box<[T]>>>

error[E0277]: the trait bound `std::rc::Rc<[i32; 33]>: std::convert::From<std::rc::Rc<[i32]>>` is not satisfied
--> $DIR/alloc-types-no-impls-length-33.rs:14:23
|
LL | let boxed_array = <Rc<[i32; 33]>>::try_from(boxed_slice);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<std::rc::Rc<[i32]>>` is not implemented for `std::rc::Rc<[i32; 33]>`
|
= help: the following implementations were found:
<std::rc::Rc<T> as std::convert::From<T>>
<std::rc::Rc<T> as std::convert::From<std::boxed::Box<T>>>
<std::rc::Rc<[T]> as std::convert::From<&[T]>>
<std::rc::Rc<[T]> as std::convert::From<std::vec::Vec<T>>>
and 8 others
= note: required because of the requirements on the impl of `std::convert::Into<std::rc::Rc<[i32; 33]>>` for `std::rc::Rc<[i32]>`
= note: required because of the requirements on the impl of `std::convert::TryFrom<std::rc::Rc<[i32]>>` for `std::rc::Rc<[i32; 33]>`

error[E0277]: the trait bound `std::rc::Rc<[i32; 33]>: std::convert::TryFrom<std::rc::Rc<[i32]>>` is not satisfied
--> $DIR/alloc-types-no-impls-length-33.rs:14:23
|
LL | let boxed_array = <Rc<[i32; 33]>>::try_from(boxed_slice);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom<std::rc::Rc<[i32]>>` is not implemented for `std::rc::Rc<[i32; 33]>`
|
= help: the following implementations were found:
<std::rc::Rc<[T; _]> as std::convert::TryFrom<std::rc::Rc<[T]>>>

error[E0277]: the trait bound `std::sync::Arc<[i32; 33]>: std::convert::From<std::sync::Arc<[i32]>>` is not satisfied
--> $DIR/alloc-types-no-impls-length-33.rs:21:23
|
LL | let boxed_array = <Arc<[i32; 33]>>::try_from(boxed_slice);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<std::sync::Arc<[i32]>>` is not implemented for `std::sync::Arc<[i32; 33]>`
|
= help: the following implementations were found:
<std::sync::Arc<T> as std::convert::From<T>>
<std::sync::Arc<T> as std::convert::From<std::boxed::Box<T>>>
<std::sync::Arc<[T]> as std::convert::From<&[T]>>
<std::sync::Arc<[T]> as std::convert::From<std::vec::Vec<T>>>
and 8 others
= note: required because of the requirements on the impl of `std::convert::Into<std::sync::Arc<[i32; 33]>>` for `std::sync::Arc<[i32]>`
= note: required because of the requirements on the impl of `std::convert::TryFrom<std::sync::Arc<[i32]>>` for `std::sync::Arc<[i32; 33]>`

error[E0277]: the trait bound `std::sync::Arc<[i32; 33]>: std::convert::TryFrom<std::sync::Arc<[i32]>>` is not satisfied
--> $DIR/alloc-types-no-impls-length-33.rs:21:23
|
LL | let boxed_array = <Arc<[i32; 33]>>::try_from(boxed_slice);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom<std::sync::Arc<[i32]>>` is not implemented for `std::sync::Arc<[i32; 33]>`
|
= help: the following implementations were found:
<std::sync::Arc<[T; _]> as std::convert::TryFrom<std::sync::Arc<[T]>>>

error: aborting due to 6 previous errors

For more information about this error, try `rustc --explain E0277`.

0 comments on commit 09a245b

Please sign in to comment.