rust-iterator-impl skill
Use when writing a custom iterator or making a type iterable, to implement Iterator, IntoIterator, FromIterator, Extend, size_hint, ExactSizeIterator, or DoubleEndedIterator. Triggers on a for loop or collect that rejects a container, a lending iterator and E0207, an ExactSizeIterator len panic, an unconditional_recursion warning in into_iter, E0658 on impl Trait in an associated IntoIter type, enumerate().rev() needing ExactSizeIterator, and iter::from_fn in place of a nightly gen block. Not for calling-side combinator style (rust-code-style) or iteration speed (rust-hot-path).
- GitHub stars
- 7
- Files
- 5
- Last commit
- Nov 13, 2026
- License
- BSD-3-Clause
- Allowed tools
- —
What does the rust-iterator-impl skill do?
rust-iterator-impl uses when writing a custom iterator or making a type iterable, to implement Iterator, IntoIterator, FromIterator, Extend, size_hint, ExactSizeIterator, or DoubleEndedIterator. Triggers on a for loop or collect that rejects a container, a lending iterator and E0207, an ExactSizeIterator len panic, an unconditional_recursion warning in into_iter, E0658 on impl Trait in an associated IntoIter type, enumerate().rev() needing ExactSizeIterator, and iter::from_fn in place of a nightly gen block. Not for calling-side combinator style (rust-code-style) or iteration speed (rust-hot-path).
How to install the rust-iterator-impl skill
Each command copies the skill folder into the client's skills directory. Restart the client or start a new session to load it.Install the rust-iterator-impl skill in Plugin
/plugin marketplace add po4yka/rust-skills /plugin install rust-skills@rust-skills
Install the rust-iterator-impl skill in Claude Code
~/.claude/skills/rust-iterator-impl/SKILL.md
$ npx degit po4yka/rust-skills/skills/rust-iterator-impl ~/.claude/skills/rust-iterator-implInstall the rust-iterator-impl skill in Claude Code (project)
.claude/skills/rust-iterator-impl/SKILL.md
$ npx degit po4yka/rust-skills/skills/rust-iterator-impl .claude/skills/rust-iterator-implInstall the rust-iterator-impl skill in Codex
~/.agents/skills/rust-iterator-impl/SKILL.md
$ npx degit po4yka/rust-skills/skills/rust-iterator-impl ~/.agents/skills/rust-iterator-implInstall the rust-iterator-impl skill in Gemini CLI
~/.gemini/skills/rust-iterator-impl/SKILL.md
$ npx degit po4yka/rust-skills/skills/rust-iterator-impl ~/.gemini/skills/rust-iterator-implInstall the rust-iterator-impl skill in Claude.ai
npx degit po4yka/rust-skills/skills/rust-iterator-impl rust-iterator-impl && zip -r rust-iterator-impl.zip rust-iterator-impl # claude.ai → Customize → Skills → + → Create skill → Upload a skill → rust-iterator-impl.zip
SKILL.md
View on GitHubRust iterator impl
Every error text and number below comes from rustc 1.98.1, edition 2024, on aarch64-apple-darwin.
Route the symptom to a section
| Symptom or task | Section |
|---|---|
error[E0277]: &Bag is not an iterator on for v in &bag, or E0658 on type IntoIter = impl .. |
The three IntoIterator impls |
warning: function cannot return without recursing, then has overflowed its stack |
Never call self.into_iter() in the impl |
error[E0277]: a value of type X cannot be built from an iterator |
A collection newtype needs four impls |
error[E0207]: the lifetime parameter 'a is not constrained |
Iterator cannot borrow from itself |
A panic inside core/src/iter/traits/exact_size.rs |
size_hint is a contract |
error[E0277]: ... ExactSizeIterator is not satisfied, pointing at .rev() |
Adapter order |
error[E0658]: gen blocks are experimental, or E0432 on std::ops::Generator |
Stateful generators |
| The impls are correct, and iteration is slow | the rust-hot-path skill; for a known length, with_capacity plus extend |
Verify
Set these lint levels once ([lints.*] in a single-package manifest):
[workspace.lints.rust]
unconditional_recursion = "deny"
[workspace.lints.clippy]
iter_without_into_iter = "warn"
into_iter_without_iter = "warn"
While you iterate, run cargo test --locked -p <crate>. Before commit, run
cargo clippy --locked --workspace --all-targets -- -D warnings. The rust-lints skill, when installed,
owns the full [workspace.lints.clippy] tables and the workspace gate.
| Check | Catches |
|---|---|
unconditional_recursion = "deny" |
An into_iter body that calls itself directly |
clippy::iter_without_into_iter, clippy::into_iter_without_iter (pedantic, allow by default) |
An exported iter or iter_mut without its IntoIterator for &T or &mut T, and the reverse |
clippy::should_implement_trait (style, warn by default) |
An inherent fn next or fn into_iter on an exported type |
A test that calls next() once, then asserts size_hint() and len() |
A wrapper that drops size_hint, and an off-by-one after partial use |
A test on (index, element) pairs |
A swap of enumerate().rev() and rev().enumerate() |
A test that alternates next and next_back to the end |
A next_back that yields one element twice or skips one |
A green lint run proves little. The clippy lints skip a type that is not exported, and no lint
sees a missing IntoIterator for T, FromIterator, or Extend, a wrong size_hint, or
recursion through a second function. The tests and the review checklist
cover those.
Review checklist
The change is done when the Verify commands pass and a reading confirms each item. Each has its home in the section named after it.
IntoIteratorforT,&T, and, with mutable element access,&mut Ton every container aforloop iterates;FromIteratorandExtendon a collection newtype.- No inherent
fn into_iterorfn next; nointo_iterbody that reachesself.into_iter(), directly or through a helper. - A
Derefonly to[T]orstr. - A forwarded or computed
size_hinton every wrapper, and an exact one under everyExactSizeIteratorimpl. - No
enumerate().rev()afterfilter,flat_map,take_while,chars, orchain. - No raw pointer or
RefCell::as_ptrescape from E0207. - No nightly
genblock.
The three IntoIterator impls
The for loop and every I: IntoIterator bound resolve through the trait, so a container that
offers only an inherent fn iter(&self) fails with error[E0277]: &Bag is not an iterator.
Rewriting the call site to b.iter() hides the defect. Write all three impls once, on the
container: &'a C, &'a mut C, and C. Read references/impl-examples.md
when you write the impls: it has a run-tested container with all three, a forwarding wrapper
iterator, and the inherent iter and iter_mut they delegate to.
Rules:
- Do not add an inherent
fn into_iter;clippy::should_implement_traitasks you to delete it. - Keep the inherent
iteranditer_mut. The borrowing trait impls delegate to them. - A newtype that yields exactly the inner iterator's items forwards
size_hintand each trait of the inner iterator:DoubleEndedIterator,ExactSizeIterator,FusedIterator,Clone. Forwarding onlynextreports(0, None):collectloses the capacity hint andlen()panics. - A wrapper that drops, adds, or merges items computes its own
size_hint, and claimsExactSizeIteratoronly when that hint is exact. - Give
IntoItera named public type when the caller may store it. A std type such asstd::slice::Iter<'a, u32>in apubsignature ties the API to it forever. type IntoIter = impl Iterator<Item = T>;fails on stable with E0658 (issue 63063). Name the std type, write a wrapper, or useBox<dyn Iterator<Item = T> + 'a>(one allocation and a dynamic call per item). A non-capturing closure coerces to afnpointer, sostd::iter::Map<std::slice::Iter<'a, T>, fn(&'a T) -> U>is nameable.
Never call self.into_iter() in the impl
A body fn into_iter(self) -> Self::IntoIter { self.into_iter() } compiles and links, warns
only with unconditional_recursion, and aborts at run time with a stack overflow. It usually
works when written, because an inherent fn into_iter(self) shadows the trait method; delete
that inherent method, as clippy::should_implement_trait asks, and the same body calls itself.
Read references/diagnostics.md when you need
the code and the exact warning and abort text.
The unconditional_recursion = "deny" level in Verify turns the warning into a build
error. Without that level, search for the shape:
rg -nU 'fn into_iter\(self\) -> [^{]*\{\s*self\.into_iter' --type rust. Keep -U: rustfmt splits the
body across lines.
A collection newtype needs four impls
Deref does not supply IntoIterator, FromIterator, or Extend: method-call syntax follows a
deref; trait resolution does not. A Deref<Target = Vec<T>> newtype still fails for v in w,
collect, an I: IntoIterator argument, w.into_iter() (E0507), and w.extend(..) (E0596;
DerefMut fixes only that one). Read
references/diagnostics.md when
you need the exact error for each call site.
Read references/impl-examples.md
when you write them: it has a run-tested newtype with the four impls and a Deref<Target = [T]>.
Deref<Target = [T]> costs the caller nothing and keeps the growth API private (b.push(4) is
E0599). Do not add DerefMut to get mutation back; add one named inherent method for each
mutation the type really offers.
Iterator cannot borrow from itself
Item cannot name the lifetime of &mut self, so an iterator that owns its buffer cannot yield
references into it. rustc gives E0207, then lifetime may not live long enough; the help line
misleads, and no attribute, bound, or PhantomData field fixes it. Pick one of three options:
- Borrow the data:
struct Frames<'a> { data: &'a [u8], pos: usize }withtype Item = &'a [u8]. - Yield a guard that owns its borrow, such as
Ref<'a, T>from a borrowed&'a [RefCell<T>]. - Drop the
Iteratorimpl for an inherentfn next_frame(&mut self) -> Option<&[u8]>, used withwhile let. Do not name itnext:clippy::should_implement_traitflags it.
Read references/lending-iterators.md when you implement one: it has a tested example of each
option, the full E0207 output, and a lending trait with a generic associated type.
Never escape the lifetime through a raw pointer or RefCell::as_ptr. That is unsound: the
yielded reference outlives the tracked borrow, so a caller can hold it across a push that
reallocates. Change the API. A clean cargo +nightly miri test --locked run proves nothing
here; Miri reports the defect only when a test interleaves the reference with a write.
size_hint is a contract
The default size_hint is (0, None). Two consequences.
collect falls back to the growth ladder (500 unhinted items land in capacity 512 on
1.99.1). For a known output length, use with_capacity plus extend.
ExactSizeIterator panics at run time. impl ExactSizeIterator for X {} compiles with no
size_hint override, and the default len() then panics inside
core/src/iter/traits/exact_size.rs.
Override size_hint before you implement ExactSizeIterator. Implement DoubleEndedIterator as
well when the sequence has a defined end, because .rev() and .enumerate().rev() both need
it. Read references/impl-examples.md
when you write the impls: it has a run-tested iterator with both.
Rules for the two traits:
- Implement
ExactSizeIteratoronly when the count is known before iteration and fitsusize; a filtered or input-driven source does not qualify. next_backyields the same elements asnext, from the other end, and the two must not hand out one element twice where they meet.- The
size_hintlower bound is a promise, not a guess: an over-large one reserves memory that never fills.
Adapter order: enumerate().rev() needs ExactSizeIterator
Enumerate<I> implements DoubleEndedIterator only when I: DoubleEndedIterator + ExactSizeIterator. An adapter that loses the exact length breaks a later .rev(), and the
E0277 blames .rev(), not the adapter. A follow-on E0599 goes away with it.
Swapping to rev().enumerate() compiles and renumbers from 0 at the tail, where
enumerate().rev() keeps the forward index. The elements are the same, so assert on the
(index, element) pairs.
Read references/adapters-and-generators.md when you need to know which adapter keeps the exact
length, or want the full error and the three orderings side by side.
Stateful generators: use iter::from_fn
Coroutines and gen blocks are still nightly on 1.99.1 (E0658, and E0554 for
#![feature(coroutines)]). Pinning rust-toolchain.toml to nightly for one iterator pins the
whole workspace. use std::ops::Generator; gives E0432 on every channel.
std::iter::from_fn is the stable shape. A move closure owns the state, and the function
returns impl Iterator. No allocation, no Pin, no Box<dyn>.
FromFn is never DoubleEndedIterator or ExactSizeIterator. Read
references/adapters-and-generators.md when you write a from_fn generator, port an old
Generator snippet, or need successors, repeat_with, or the FromFn cost table.
Related skills
When installed, rust-compiler-errors covers E0277, E0507, and E0596 beyond the shapes here.
Files in this skill
5rust-iterator-impl skill questions
How do I install the rust-iterator-impl skill in Claude Code?
Run npx degit po4yka/rust-skills/skills/rust-iterator-impl ~/.claude/skills/rust-iterator-impl. Claude Code loads skills from ~/.claude/skills (all projects) or .claude/skills (one project) and uses a skill when its description matches the task.
Which clients can use the rust-iterator-impl skill?
Any client that reads the Agent Skills format: Claude Code, Codex, Gemini CLI and claude.ai (upload as a ZIP). Scripts in the skill run only where the client allows code execution.