Skip to content

Commit bf2d6a7

Browse files
Implement IntoIterator for IMap and IArray via self-reference (#69)
1 parent d35c9e3 commit bf2d6a7

File tree

3 files changed

+85
-30
lines changed

3 files changed

+85
-30
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ derive = ["implicit-clone-derive"]
2727
implicit-clone-derive = { version = "0.1", optional = true, path = "./implicit-clone-derive" }
2828
indexmap = { version = "2", optional = true }
2929
serde = { version = "1", optional = true }
30+
ouroboros = "0.18"
3031

3132
[dev-dependencies]
3233
static_assertions = "1"

src/array.rs

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::fmt;
22

3+
use ouroboros::self_referencing;
4+
35
use super::Rc;
46
use crate::ImplicitClone;
57

@@ -110,47 +112,44 @@ impl<T: ImplicitClone + 'static, const N: usize> From<[T; N]> for IArray<T> {
110112
}
111113
}
112114

113-
/// An iterator over the cloned elements of an `IArray`.
114-
#[derive(Debug)]
115-
pub struct IArrayIntoIter<T: ImplicitClone + 'static> {
115+
#[self_referencing]
116+
struct IArrayIntoIterInternal<T: ImplicitClone + 'static> {
116117
array: IArray<T>,
117-
left: usize,
118-
right: usize,
118+
#[covariant]
119+
#[borrows(array)]
120+
iter: std::slice::Iter<'this, T>,
119121
}
120122

123+
/// An iterator over the cloned elements of an `IArray`.
124+
#[allow(missing_debug_implementations)]
125+
pub struct IArrayIntoIter<T: ImplicitClone + 'static>(IArrayIntoIterInternal<T>);
126+
121127
impl<T: ImplicitClone + 'static> IntoIterator for IArray<T> {
122128
type Item = T;
123129
type IntoIter = IArrayIntoIter<T>;
124130

125131
fn into_iter(self) -> <Self as IntoIterator>::IntoIter {
126-
IArrayIntoIter {
127-
left: 0,
128-
right: self.len(),
129-
array: self,
130-
}
132+
IArrayIntoIter(
133+
IArrayIntoIterInternalBuilder {
134+
array: self,
135+
iter_builder: |a| a.iter(),
136+
}
137+
.build(),
138+
)
131139
}
132140
}
133141

134142
impl<T: ImplicitClone + 'static> Iterator for IArrayIntoIter<T> {
135143
type Item = T;
136144

137145
fn next(&mut self) -> Option<Self::Item> {
138-
if self.left >= self.right {
139-
return None;
140-
}
141-
let item = &self.array[self.left];
142-
self.left += 1;
143-
Some(item.clone())
146+
self.0.with_iter_mut(|iter| iter.next().cloned())
144147
}
145148
}
146149

147150
impl<T: ImplicitClone + 'static> DoubleEndedIterator for IArrayIntoIter<T> {
148151
fn next_back(&mut self) -> Option<Self::Item> {
149-
if self.left >= self.right {
150-
return None;
151-
}
152-
self.right -= 1;
153-
Some(self.array[self.right].clone())
152+
self.0.with_iter_mut(|iter| iter.next_back().cloned())
154153
}
155154
}
156155

@@ -333,7 +332,7 @@ impl<T: ImplicitClone + 'static> IArray<T> {
333332
}
334333
}
335334

336-
impl<'a, T, U, const N: usize> PartialEq<&'a [U; N]> for IArray<T>
335+
impl<T, U, const N: usize> PartialEq<&[U; N]> for IArray<T>
337336
where
338337
T: PartialEq<U> + ImplicitClone,
339338
{
@@ -369,7 +368,7 @@ where
369368
}
370369
}
371370

372-
impl<'a, T, U> PartialEq<&'a [U]> for IArray<T>
371+
impl<T, U> PartialEq<&[U]> for IArray<T>
373372
where
374373
T: PartialEq<U> + ImplicitClone,
375374
{
@@ -490,7 +489,7 @@ mod test_array {
490489
}
491490

492491
#[test]
493-
fn into_iter() {
492+
fn iterators() {
494493
let array = IArray::Static(&[1, 2, 3]);
495494
assert_eq!(array.iter().next().unwrap(), &1);
496495
assert_eq!(array.into_iter().next().unwrap(), 1);

src/map.rs

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use indexmap::map::Iter as MapIter;
22
use indexmap::map::Keys as MapKeys;
33
use indexmap::map::Values as MapValues;
44
use indexmap::IndexMap as Map;
5+
use ouroboros::self_referencing;
56
use std::borrow::Borrow;
67
use std::fmt;
78
use std::hash::Hash;
@@ -308,8 +309,8 @@ impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone +
308309
}
309310
}
310311

311-
impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>
312-
DoubleEndedIterator for IMapIter<'a, K, V>
312+
impl<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>
313+
DoubleEndedIterator for IMapIter<'_, K, V>
313314
{
314315
fn next_back(&mut self) -> Option<Self::Item> {
315316
match self {
@@ -319,6 +320,51 @@ impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone +
319320
}
320321
}
321322

323+
#[self_referencing]
324+
struct IMapIntoIterInternal<
325+
K: Eq + Hash + ImplicitClone + 'static,
326+
V: PartialEq + ImplicitClone + 'static,
327+
> {
328+
map: IMap<K, V>,
329+
#[covariant]
330+
#[borrows(map)]
331+
iter: IMapIter<'this, K, V>,
332+
}
333+
334+
#[allow(missing_docs, missing_debug_implementations)]
335+
pub struct IMapIntoIter<
336+
K: Eq + Hash + ImplicitClone + 'static,
337+
V: PartialEq + ImplicitClone + 'static,
338+
>(IMapIntoIterInternal<K, V>);
339+
340+
impl<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static> IntoIterator
341+
for IMap<K, V>
342+
{
343+
type Item = (K, V);
344+
type IntoIter = IMapIntoIter<K, V>;
345+
346+
fn into_iter(self) -> Self::IntoIter {
347+
IMapIntoIter(
348+
IMapIntoIterInternalBuilder {
349+
map: self,
350+
iter_builder: |a| a.iter(),
351+
}
352+
.build(),
353+
)
354+
}
355+
}
356+
357+
impl<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static> Iterator
358+
for IMapIntoIter<K, V>
359+
{
360+
type Item = (K, V);
361+
362+
fn next(&mut self) -> Option<Self::Item> {
363+
self.0
364+
.with_iter_mut(|iter| iter.next().map(|(k, v)| (k.clone(), v.clone())))
365+
}
366+
}
367+
322368
#[allow(missing_docs, missing_debug_implementations)]
323369
pub enum IMapKeys<'a, K, V> {
324370
Slice(std::slice::Iter<'a, (K, V)>),
@@ -338,8 +384,8 @@ impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone +
338384
}
339385
}
340386

341-
impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>
342-
DoubleEndedIterator for IMapKeys<'a, K, V>
387+
impl<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>
388+
DoubleEndedIterator for IMapKeys<'_, K, V>
343389
{
344390
fn next_back(&mut self) -> Option<Self::Item> {
345391
match self {
@@ -368,8 +414,8 @@ impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone +
368414
}
369415
}
370416

371-
impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>
372-
DoubleEndedIterator for IMapValues<'a, K, V>
417+
impl<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>
418+
DoubleEndedIterator for IMapValues<'_, K, V>
373419
{
374420
fn next_back(&mut self) -> Option<Self::Item> {
375421
match self {
@@ -472,4 +518,13 @@ mod test_map {
472518
let x: IMap<u32, u32> = IMap::Static(&[]);
473519
let _out = IMap::from(&x);
474520
}
521+
522+
#[test]
523+
fn iterators() {
524+
let map = IMap::Static(&[(1, 10), (2, 20), (3, 30)]);
525+
assert_eq!(map.iter().next().unwrap(), (&1, &10));
526+
assert_eq!(map.keys().next().unwrap(), &1);
527+
assert_eq!(map.values().next().unwrap(), &10);
528+
assert_eq!(map.into_iter().next().unwrap(), (1, 10));
529+
}
475530
}

0 commit comments

Comments
 (0)