Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement TryFrom<Box<[T]>> for Box<[T; N]> #47245

Closed
wants to merge 8 commits into from

Conversation

nvzqz
Copy link
Contributor

@nvzqz nvzqz commented Jan 7, 2018

These changes serve to provide the same benefits as PR #44764 except for boxes, which refer to owned arrays allocated in the heap.

Should these changes be extended to other types like Arc<[T]> and Rc<[T]>?

r? @sfackler

This commit serves to provide the same benefits as PR rust-lang#44764 except for
boxes that refer to owned arrays allocated in the heap.
Copy link
Member

@kennytm kennytm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is commit 781574787ae169ba4fe87a71730a5a2b1638761b a mistake? Why is there a merge commit in this PR?

}

macro_rules! array_impls {
($($N:expr)+) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You forgot to add $(...)+ around the item.

[00:05:12]    Compiling alloc v0.0.0 (file:///checkout/src/liballoc)
[00:05:12] error: variable 'N' is still repeating at this depth
[00:05:12]    --> liballoc/boxed.rs:665:47
[00:05:12]     |
[00:05:12] 665 |         impl<T> TryFrom<Box<[T]>> for Box<[T; $N]> {
[00:05:12]     |                                               ^^
[00:05:12] 
[00:05:12] error: Could not compile `alloc`.

@kennytm kennytm added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jan 7, 2018
nvzqz added 2 commits January 7, 2018 14:58
The functions are very short and there may be relatively unreasonable
calling overhead if they're not inlined.
fn try_from(slice: Box<[T]>) -> Result<Box<[T; $N]>, TryFromSliceError<T>> {
if slice.len() == $N {
let ptr = Box::into_raw(slice) as *mut [T; $N];
unsafe { Ok(Box::from_raw(ptr)) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexcrichton is this a valid operation?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK yeah this should be safe, the destructor for Box<T> should deallocate with the size of T which in this case would be mem::size_of::<T>() * N

@alexcrichton alexcrichton added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 8, 2018
@sfackler sfackler added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Jan 10, 2018
@sfackler
Copy link
Member

Could you give some examples where you'd use these conversions?

@nvzqz
Copy link
Contributor Author

nvzqz commented Jan 10, 2018

Here a Redditor asked about how to go about making a heap-allocated table with a static size. I recommended using Vec and then converting that into a boxed slice. Because the size is known at compile-time, there's not much reason to keep the dynamic length.

Having const generics as well as a safe conversion interface such as this one would solve his problem without the need for unsafe. So while this conversion as-is wouldn't solve his problem, it in a way potentially solves half of it.

In my experience, LLVM seems to optimize further with arrays (&[T; N]) than just slices (&[T]). For people who want to make their code as fast as possible, they may want to reach for fixed-size arrays.

We currently have &[T] to &[T; N] conversions, I think it also makes sense to have the corresponding box conversions. Without this change, getting &[T; N] from Box<[T]> would require checking the length each time.

@sfackler
Copy link
Member

That post was asking about [T; 262144], though. Are these conversions worth it before const generics?

@carols10cents carols10cents added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 22, 2018
@carols10cents
Copy link
Member

Ping @nvzqz, looks like @sfackler has a further question for you?

@nvzqz
Copy link
Contributor Author

nvzqz commented Jan 22, 2018

@sfackler to me it makes sense to have these conversions when we already have &[T] to &[T; N] conversions. If these conversions don't get added now, I'll be submitting another similar PR once const generics are in nightly.

Currently, unsafe code is needed by libraries to make a statically sized box. If a statically-size slice is needed, multiple checks must be made for whether the box is the right size if authors choose to avoid unsafe.

@sfackler
Copy link
Member

Currently, unsafe code is needed by libraries to make a statically sized box.

??

let b: Box<[u64; 100]> = Box::new([0; 100]);

@nvzqz
Copy link
Contributor Author

nvzqz commented Jan 22, 2018

I should have elaborated. Your example is possible with trivial/primitive types that implement Copy. However, one may want to do something like this:

struct Entry {
    /* fields */
}

const NUM_ENTRIES: usize = 32;

lazy_static! {
    static ref TABLE: Box<[Entry; NUM_ENTRIES]> = {
        let mut table = Vec::<Entry>::with_capacity(NUM_ENTRIES);
        for i in 0..NUM_ENTRIES {
            table.push(Entry { /* ... */ });
        }
        table.into_boxed_slice().try_into().unwrap()
    };
}

By using the Vec to Box<[T]> conversion as well as these changes, this can be done without unsafe.

@sfackler
Copy link
Member

But how big is NUM_ENTRIES in practice? I'd expect it to almost always be larger than 32.

@nvzqz
Copy link
Contributor Author

nvzqz commented Jan 23, 2018

Well, generally, perhaps. Unless this is something that's polled, one can't really give a proper number. Alas, it is likely to be greater than 32.

@kennytm kennytm added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 31, 2018
@kennytm
Copy link
Member

kennytm commented Jan 31, 2018

Hi @sfackler @nvzqz, ping from triage.

Given the proper use case of this usually require N >> 32, I guess we should postpone this PR until const generics is implemented?

@pietroalbini
Copy link
Member

@sfackler @nvzqz ping from triage! What's the status of this PR?

@shepmaster
Copy link
Member

Since we haven't heard from @sfackler in a few weeks, I'm randomly reassigning from the @rust-lang/libs team...

r? @dtolnay

@rust-highfive rust-highfive assigned dtolnay and unassigned sfackler Feb 9, 2018
@dtolnay
Copy link
Member

dtolnay commented Feb 13, 2018

I would be inclined to accept this by analogy with #44764. If we decide that array stuff is not worth doing until const generics are available, let's roll back the &[T]⟶&[T; N] conversion impls.

@rfcbot fcp merge

@rfcbot rfcbot added the proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. label Feb 13, 2018
@rfcbot
Copy link
Collaborator

rfcbot commented Feb 13, 2018

Team member @dtolnay has proposed to merge this. The next step is review by the rest of the tagged teams:

No concerns currently listed.

Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@kennytm kennytm added S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 13, 2018
@dtolnay
Copy link
Member

dtolnay commented Feb 16, 2018

TryFrom is unstable so I am going to unilaterally accept these and we can consider more closely as a team when stabilizing TryFrom. Thanks @nvzqz!

@rfcbot fcp cancel

@rfcbot
Copy link
Collaborator

rfcbot commented Feb 16, 2018

@dtolnay proposal cancelled.

@rfcbot rfcbot removed the proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. label Feb 16, 2018
/// array fails.
#[unstable(feature = "try_from", issue = "33417")]
#[derive(Clone)]
pub struct TryFromSliceError<T>(Box<[T]>);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a brief example involving TryFromSliceError. See FromUtf8Error for examples of examples.

/// be made.
#[unstable(feature = "try_from", issue = "33417")]
#[inline]
pub fn into_boxed_slice(self) -> Box<[T]> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add an example showing a case in which this method is useful. The point of the example wouldn't be to show how to call this method (we can assume readers know how to call methods when they get to browsing TryFrom documentation) but to show why someone would want to call this method.

type Error = TryFromSliceError<T>;

#[inline]
fn try_from(slice: Box<[T]>) -> Result<Box<[T; $N]>, TryFromSliceError<T>> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a test so that we don't break this implementation later. Something similar to the test in #44764 should work.

@kennytm kennytm added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). labels Feb 16, 2018
@pietroalbini
Copy link
Member

Hi from the release team @nvzqz, there are a few comments from @dtolnay that needs to be addressed, can you fix them so this PR can be merged?

@pietroalbini
Copy link
Member

Thank you so much for this PR @nvzqz! Unfortunately, we haven't heard from you for more than two weeks, so I'm closing this PR to keep the queue tidy.

Please reopen it if you have time to address @dtolnay comments in the near future!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants