Crates.io | iterate-trait |
lib.rs | iterate-trait |
version | 1.0.1 |
source | src |
created_at | 2024-11-25 12:35:40.748983 |
updated_at | 2024-11-25 14:18:20.162548 |
description | Experiment with methods on IntoIterator |
homepage | |
repository | https://github.com/yoshuawuyts/iterate-trait |
max_upload_size | |
id | 1460275 |
size | 31,414 |
This project asks the question: what if we used IntoIterator
everywhere
instead of Iterator
? This becomes relevant for generator blocks, which
themselves may contain !Send
items, but that doesn't mean that the type
returned by gen {}
needs to be !Send
too. This crate follows Swift's
example, making it so all operations happen on a base builder type - which
has one final operation that converts it into an actual iterable.
The other reason is that in bounds we already always use IntoIterator
. For
example the collect
method takes A: IntoIterator
, not A: Iterator
. In
function bounds there is rarely a reason to use Iterator
directly; typically the
only reason we don't is because it's more effort to type.
Iterator
's limitationsHere's a practical case people are bound to hit when writing generator
blocks, which can't be fixed unless generator returns IntoIterator
:
// A gen block that holds some `!Send` type across a yield point
let iter = gen {
let items = my_data.lock(); // ← `MutexGuard: !Send`
for item in items {
yield item;
}
};
// ## Option 1
let iter = gen { ... }; // 1. Desugars to `impl Iterator + !Send`
thread::spawn(move || { // 2. ❌ Can't move `!Send` type across threads
for item in iter { ... }
}).unwrap();
// ## Option 2
let iter = gen { ... }; // 1. Desugars to `impl IntoIterator + Send`
thread::spawn(move || { // 2. ✅ Move `Send` type across threads
for item in iter { ... } // 3. Obtain `impl Iterator + !Send`
}).unwrap();
This crate essentially reframes IntoIterator
into the main interface for
iteration. However the name IntoIterator
suggests it is a mere supplement
to some other Iterator
trait. Iterator
also has another quirk: it's a
trait that's named after a noun, rather than a verb. Think of Read
,
Write
, Send
- these are all verbs.
The closest prior art for this in the stdlib I could find was the Hash
/
Hasher
pair. The main trait Hash
is the subject of the hashing, with
Hasher
containing all the hash state. This makes Hasher
very similar to
Iterator
, and hints the better name for IntoIterator
might in fact be Iterate
.
This just leaves us with what to do about FromIterator
, which currently
exists as a dual to IntoIterator
. But interestingly it also exists as a
dual to Extend
,
where rather than creating a new container it can be used to extend an
existing collection. This is also used in the unstable collect_into
method.
It's for this reason that we've renamed FromIterator
to Collect
. All
together this changes the names to:
IntoIterator
→ Iterate
Iterator
→ Iterator
FromIterator
→ Collect
$ cargo add iterate-trait
This crate uses #![deny(unsafe_code)]
to ensure everything is implemented in
100% Safe Rust.
Want to join us? Check out our "Contributing" guide and take a look at some of these issues: