Skip to content

Tracking Issue for Iterator::next_chunk #98326

Open

Description

@rossmacarthur

View all comments

Feature gate: #![feature(iter_next_chunk)]

This is a tracking issue for the .next_chunk() and .next_chunk_back() method on iterators which allows you to advance the iterator N elements and return an array [T; N]

Public API

use core::array;

trait Iterator {
    type Item;
    
    fn next_chunk<const N: usize>(&mut self) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>>
    where
        Self: Sized;
}

trait DoubleEndedIterator {
    fn next_chunk_back<const N: usize>(&mut self) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>>
    where
        Self: Sized;
}

Steps / History

Unresolved Questions

  • Naming: other options include next_array() or next_array_chunk().
  • How should we handle N = 0?

Activity

  1. pitaj commented on May 25, 2023

    @pitaj
    Contributor

    I can see that maybe being the case down the line unless we add something like const if or const match. But currently they just panic when N=0 so one can just put a simple if N == 0 { return Ok([]); } at the top which will easily get optimized out.

    Edit: actually the above does NOT work and would need some kind of const if as well. I'll need to think about this.

    It's possible to achieve a similar thing via specialization but it's not ideal.

  2. frewsxcv commented on Jun 19, 2023

    @frewsxcv
    Contributor

    @rust-lang/libs Is there anything blocking a stabilization pull request? I'm happy to open that

  3. Andlon commented on May 18, 2024

    @Andlon

    I think for the name next_chunk it's slightly unfortunate that a "chunk" in this context is an array and not a slice, like slice.chunks(). This seems inconsistent and a clear potential source of confusion. next_array_chunk or similar removes any such ambiguities, and should be preferred, in my opinion.

    If things are otherwise blocked on the handling of N == 0, would it be possible to delay this decision by panicking (at compile time?) for now, and then possibly allow it in the future? My understanding is that the case N == 0 is an edge case that would only come up in some unusual situations involving generics, and it seems unfortunate for such an edge case to delay stabilization for the common use cases of this method.

  4. the8472 commented on May 18, 2024

    @the8472
    Member

    I think for the name next_chunk it's slightly unfortunate that a "chunk" in this context is an array and not a slice, like slice.chunks(). This seems inconsistent and a clear potential source of confusion. next_array_chunk or similar removes any such ambiguities, and should be preferred, in my opinion.

    Whether a chunk is a slice or an array already is not consistent. E.g. slices already have as_chunks that returns a reference to arrays. I don't see much of a chance for confusion because -> [Self::Item] signatures are not possible and -> &[Self::Item] signatures would be neither practical nor useful to implement.

    If things are otherwise blocked on the handling of N == 0, would it be possible to delay this decision by panicking (at compile time?) for now, and then possibly allow it in the future?

    That would block the option of adding a where N > 0 bound once that's possible

  5. Andlon commented on May 18, 2024

    @Andlon

    Whether a chunk is a slice or an array already is not consistent. E.g. slices already have as_chunks that returns a reference to arrays. I don't see much of a chance for confusion because -> [Self::Item] signatures are not possible and -> &[Self::Item] signatures would be neither practical nor useful to implement.

    Fair point, though I don't think any of these methods have been stabilized, unless I'm mistaken. as_chunks would probably also be better as as_array_chunks, for the same reason.

    Actually, upon reviewing this post I see that last_chunk was recently made available in 1.77. Unfortunate. Oh well. In that case, you are correct, and that it's already unfortunately inconsistent.

    In any case, the confusion I point to has to do with readability. By using clear and distinct naming, you do not have to stop and think through a logical argument like the one you suggest when scanning over the code.

    I just don't see any downside in using a few more characters to avoid the ambiguity. But I also don't think we need to bikeshed this further.

    That would block the option of adding a where N > 0 bound once that's possible

    Thanks for pointing this out, that's what I was missing.

  6. betelgeuse commented on Jun 16, 2024

    @betelgeuse
    Contributor

    Before making this stable it would be useful to improve the documentation so that it provides an example with a loop. Now the examples have fixed amount of calls to next_chunk. I would think the more common use case is when not operating on a known input.

    https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.next_chunk

  7. added 2 commits that reference this issue on Jun 26, 2024
  8. added a commit that references this issue on Jun 26, 2024
  9. jmevel commented on Dec 8, 2024

    @jmevel

    Hi guys,

    Just wondering if any of you also experienced some stack overflow errors using this feature?
    I'm trying to use it (inside a Tokio task) but whenever I try to get a chunk of 475 or more element I get a stack overflow error. This is fine up to 474 elements.

    I'm iterating over huge CSV files using the csv crate. I wanted to simplify a bit my code which was calling next() on my iterator and executing some code every 10_000 elements but I think I'll have to stick to my existing working code for now.

    Just wanted to know if anyone else also stumbled on this issue?

    Thanks

  10. SuperSamus commented on Dec 23, 2024

    @SuperSamus

    The generated assembly is pretty bad.
    Godbolt

    Benchmarking on my PC, the one that doesn't use next_chunk is almost 3 times as fast.

    EDIT: Still an issue on 20/08/2026.

  11. the8472 commented on Dec 23, 2024

    @the8472
    Member

    The generated assembly is pretty bad. For some reason, the hot loop contains multiple checks that seem unnecessary.
    Godbolt

    That's using the default implementation which uses the internal array::iter_next_chunk, which I thought would be better optimized than that... CC @scottmcm didn't we have a trustedlen version of that at some point?
    We can obviously do much better for slices.

    I'm iterating over huge CSV files using the csv crate. I wanted to simplify a bit my code which was calling next() on my iterator and executing some code every 10_000 elements but I think I'll have to stick to my existing working code for now.

    Arrays are usually stack-allocated if you don't box them. So using deep call chains with huge array arguments will lead to stack overflows unless most of the moves get optimized away. We'd need placement by return or changing the next_chunk signature to pass maybeuninit slice references, which would make this a lower-level method.

  12. simonsso commented on Aug 27, 2025

    @simonsso

    The use of Result return type seems a bit out of place since the Err is not a regular Error as one could expect. I think it would make more sense to return an enum with the states Chunk([u8;32]) and Remainder(iter) instead

  13. max-heller commented on Nov 1, 2025

    @max-heller
    Contributor

    The use of Result return type seems a bit out of place since the Err is not a regular Error as one could expect. I think it would make more sense to return an enum with the states Chunk([u8;32]) and Remainder(iter) instead

    The Result-based signature feels similar to slice::binary_search() -> Result<usize, usize> and slice::contains() -> bool

  14. added 4 commits that reference this issue on Nov 26, 2025
  15. added a commit that references this issue on Nov 27, 2025
  16. scottmcm commented on Dec 1, 2025

    @scottmcm
    Member

    (Commenting after the meeting that discussed #100450 (comment) )

    I suspect the fundamental problem here is that returning -> Option<[T; N]> (or result, or whatever that's not just the array or just a pointer) is rough from an ABI perspective. Something wanting a [T; N] will have space for that somewhere, but Option<[T; N]> is almost always bigger than that (particularly for the common cases of Option<[u8; N]>), and both end up with Memory ABIs, so they're returned via out pointer. But that means that next_chunk().unwrap() gets space for [T; N], but then needs to stack-allocate space for Option<[T; N]>, get the optional chunk into there, then copy the array into the return place. (That's part of how #107634 made map better.)

    Fixing that would mean, I think, an API like

    trait Iterator {
        fn fill_slice<'a>(buffer: &'a mut [MaybeUninit<Self::Item>]) -> slice::Dropper<'a, Self::Item>;
    }

    Where you can DerefMut<Target = [T]> the slice::Dropper<'_, T>, it drops the elements on drop, it's up to you to check how many were actually filled, etc. That way the return type is always the same size (it's just a wrapper on slice::IterMut) and ScalarPair so you don't have the ABI problems.

    (Maybe also an array::Dropper so we could have fn fill_array(…) -> Result<array::Dropper<T, N>, slice::Dropper<T>>; for unwrapping or something. Dunno. Or something smart where the array version can unsize into the slice version, or something.)

    That said, it really wants a promise that the returned dropper's pointers would be into the passed buffer, which would normally mean it'd need to be on an unsafe trait which is annoying for iterators since one would want this to always exist.

    Maybe there's a way that fill_slice and fill_array would just be final fn, and there's other things that people can optionally implement that we'd call to populate the slice? Feels like anything that can do it materially faster is something with at least a helpful size_hint lower bound (since otherwise it'd need to go one-by-one and the default impl will be fine) so maybe there's a different version that can request the tristate: fill the whole thing, do nothing, or say you don't have enough size information to know. Then we just call that repeatedly -- which in practice on things like slice::Iterator is always exactly once.

  17. Amanieu commented on Dec 2, 2025

    @Amanieu
    Member

    Fundamentally the way to solve such issues is to change the way Result and Option are returned in the ABI. Specifically we want to have 2 separate return places, one for the "main" result (Ok/Some) and one for the rest of the enum. When the main result is returned via an out pointer, this allows the result to be directly placed into its final location. This along with the current work on MIR move optimization should allow these to optimize optimally.

    I would much prefer this kind of ABI-level solution over making the API more complicated because of low-level implementation details.

  18. hanna-kruppe commented on Dec 24, 2025

    @hanna-kruppe
    Contributor

    The other alternative here is to piggy-back on some future language feature for in-place initialization, which also has to address fallibility somehow. The downside of transparently making the current API lower to "out-ptr for Some/Ok payload" ABI is that it also fails transparently: whenever move elimination doesn't fire for any reason, or a pointer to an entire Result<[T; N], _> is required, codegen will be just as inefficient as today, without any clue at the source level.

    In contrast, most in-place-init proposals have some explicit opt-in at the call site that guarantees no extra moves or temporaries. That's necessary for soundness in some use cases, but it's also useful for types (here: array lengths) large enough to overflow the stack. The downside is that there's some extra annotation burden, which may be a bad trade-off for an API that's partly about convenience. But depending on which (if any) approach is adopted, maybe the common case is succinct enough to be attractive for this API, too.

  19. added a commit that references this issue on Jan 20, 2026
  20. added 2 commits that reference this issue on Apr 18, 2026
  21. added a commit that references this issue on Apr 18, 2026
  22. asder8215 commented on May 19, 2026

    @asder8215
    Contributor

    Are we able to add DoubleEndedIterator::next_chunk_back underneath this tracking issue? The person who made the ACP for this method and the original PR had it marked under #![feature(iter_next_chunk)] feature gated. I picked up the PR here to get it over the finish line due to inactivity.

  23. added a commit that references this issue on Jul 1, 2026
  24. added a commit that references this issue on Jul 1, 2026
  25. added a commit that references this issue on Jul 1, 2026
  26. added a commit that references this issue on Jul 2, 2026
  27. aapoalas commented on Jul 3, 2026

    @aapoalas
    Contributor

    Added .next_chunk_back() to the tracking issue.

  28. asder8215 commented on Jul 3, 2026

    @asder8215
    Contributor

    @aapoalas to note, .next_chunk_back() should be underneath the DoubleEndedIterator trait not Iterator trait.

  29. giang299 commented on Jul 11, 2026

    @giang299
    • Naming: other options include next_array() or next_array_chunk().

    IT MUST BE next_chunk()
    next_chunk is amz naming. we already have a Vec::chunks(),..etc before, it's universal.

  30. added
    T-libsRelevant to the library team, which will review and decide on the PR/issue.
    and removed
    T-libs-api[DEPRECATED; DO NOT USE]
    on Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-autovectorizationArea: Autovectorization, which can impact perf or code sizeC-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions