Add array_chunks - #1023
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1023 +/- ##
==========================================
- Coverage 94.38% 93.91% -0.48%
==========================================
Files 48 53 +5
Lines 6665 6707 +42
==========================================
+ Hits 6291 6299 +8
- Misses 374 408 +34 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Re the MSRV failure, I'm not sure what the idiomatic way is to trigger a PME on 1.63 based on |
You can do it like this: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=233fb2f6ca3df52d15e3df96b8c4cb61 |
| /// Effectively assert!(N > 0) post-monomorphization | ||
| fn assert_positive<const N: usize>() { | ||
| trait StaticAssert<const N: usize> { | ||
| const ASSERT: bool; | ||
| } | ||
|
|
||
| impl<const N: usize> StaticAssert<N> for () { | ||
| const ASSERT: bool = { | ||
| assert!(N > 0); | ||
| true | ||
| }; | ||
| } | ||
|
|
||
| assert!(<() as StaticAssert<N>>::ASSERT); | ||
| } |
There was a problem hiding this comment.
Rust doesn't provide stacktraces for monomorphization errors, so folks will only see that an error occured in assert_positive — and not the code that actually required the assertion.
Define this as a macro and call that instead.
There was a problem hiding this comment.
Is the change in db21b2f what you meant?
| /// assert_eq!(Some([]), it.next()); | ||
| /// ``` | ||
| #[cfg(feature = "use_alloc")] | ||
| fn arrays<const N: usize>(self) -> Arrays<Self, N> |
There was a problem hiding this comment.
IMO array_chunks is the better name, since it differentiates it from array_windows.
There was a problem hiding this comment.
To add context, I was trying to avoid triggering the unstable-name-collisions lint, because of rust-lang/rust#100450. Should I change it back to array_chunks?
| pub struct Arrays<I: Iterator, const N: usize> { | ||
| iter: I, | ||
| partial: Vec<I::Item>, | ||
| } |
There was a problem hiding this comment.
It strikes me as a code smell that N doesn't appear in the definition here. Shouldn't partial be an ArrayBuilder<T, N>?
There was a problem hiding this comment.
Making it ArrayBuilder<T, N> a priori makes sense, but I had trouble with the bounds for the impl Clone in that case. Note that MaybeUninit<T>: Clone requires T: Copy.
Maybe it could also be array::IntoIter<T, N> or a hypothetical ArrayBuilder::IntoIter<T, N> (this is close to what the unstable Iterator::ArrayChunks does) but I think the unsafe code for that would need to be more careful.
The state you need to keep track of doesn't really depend on N (except partial.len() <= N but this is sort of incidental). However Arrays needs to have N as a parameter for Arrays::Item to be well-defined.
Suggestions?
There was a problem hiding this comment.
Yes, should be ArrayBuilder, because this brings it closer to no_alloc.
Maybe this array builder could also be re-used in next.
Can you remember/share the exact problem?
There was a problem hiding this comment.
@phimuemue If it holds an ArrayBuilder<T> then it won't be Clone without T : Copy. But we should have Arrays<I, N>: Clone when I: Clone and I::Item : Clone.
There was a problem hiding this comment.
Ok. Then, let's implement it without partial/remaining for now.
(Because if we extend our ArrayBuilder further and further, we land at (a less tested version of) ArrayVec.)
|
what are the thoughts about having an array_chunks which can fill the partially filled last item by fetching from a filler that the caller provides? I think it would be a very useful API in case people always want a certain length chunks |
|
im curious why you didnt want to just copy the previous stdlib implementation? you can simply implement this on top of a manual |
|
@bend-n Do you mean There's also a nightly version of this in std: Iterator::array_chunks. If you're asking about the implementation there, I don't think the code in this PR is that different, just trying to reuse things already in the crate. But TBF I haven't looked at either that implementation or this PR closely in a while. |
|
oh, my bad. i forgot that iterator::array_chunks was still unstable and assumed this was with regards to slice array chunks for some reason. you could still copy the implementation of iterator::array_chunks, though? |
If you go through the source, |
|
If it turns out to be too complicated, maybe go without |
Iterator::array_chunks exists on nightly and it's better to avoid the name collision especially if and when that's stabilized
|
@phimuemue I've removed |
| /// let it = (1..7).arrays::<3>(); | ||
| /// itertools::assert_equal(it, vec![[1, 2, 3], [4, 5, 6]]); | ||
| /// | ||
| /// // you can also specify the complete type |
There was a problem hiding this comment.
Let's not encourage people to spell iterator types
There was a problem hiding this comment.
Note that such an example is included in the docs for tuple_windows(), tuples(), tuple_combinations() and array_combinations(). Should I still remove this or keep it for consistency?
|
|
||
| /// Return an iterator that groups the items in arrays of const generic size `N`. | ||
| /// | ||
| /// `N == 0` is a compile-time (but post-monomorphization) error. |
There was a problem hiding this comment.
Is it really important for users that it is post-monomorphization?
There was a problem hiding this comment.
It won't be caught by cargo check, for example, which seems relevant to users.
|
@jswrenn regarding naming: what's our policy? IMHO, the best name is array_chunks, and I would use it and deprecate our function once it's also available in std. |
Added an implementation of
arraysthat just repeatedly callsnext_array(). Currently theN = 0produces a post-monomorphization error, see the discussion in #1012.The
remainder()feature is not implemented, based on the discussion below, since this seems to require either:use_alloc, orClone, orarrayvec.