From c657200615116d93f97069130b76a39d8a4c8d59 Mon Sep 17 00:00:00 2001 From: Sven Stegemann Date: Tue, 16 Jul 2019 04:56:54 +0200 Subject: [PATCH 1/6] Implemented DoubleEndedIterator for EnumIter. --- strum_macros/src/enum_iter.rs | 30 ++++++++++++++++++++++++++---- strum_tests/tests/enum_iter.rs | 15 +++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/strum_macros/src/enum_iter.rs b/strum_macros/src/enum_iter.rs index 51c4744c..ab00b070 100644 --- a/strum_macros/src/enum_iter.rs +++ b/strum_macros/src/enum_iter.rs @@ -62,14 +62,24 @@ pub fn enum_iter_inner(ast: &syn::DeriveInput) -> TokenStream { #[allow(missing_docs)] #vis struct #iter_name #ty_generics { idx: usize, + back_idx: usize, marker: ::std::marker::PhantomData #phantom_data, } + impl #impl_generics #iter_name #ty_generics #where_clause { + fn get(&self, idx: usize) -> Option<#name #ty_generics> { + match idx { + #(#arms),* + } + } + } + impl #impl_generics ::strum::IntoEnumIterator for #name #ty_generics #where_clause { type Iterator = #iter_name #ty_generics; fn iter() -> #iter_name #ty_generics { #iter_name { - idx:0, + idx: 0, + back_idx: 0, marker: ::std::marker::PhantomData, } } @@ -79,9 +89,7 @@ pub fn enum_iter_inner(ast: &syn::DeriveInput) -> TokenStream { type Item = #name #ty_generics; fn next(&mut self) -> Option<#name #ty_generics> { - let output = match self.idx { - #(#arms),* - }; + let output = self.get(self.idx); self.idx += 1; output @@ -99,10 +107,24 @@ pub fn enum_iter_inner(ast: &syn::DeriveInput) -> TokenStream { } } + impl #impl_generics DoubleEndedIterator for #iter_name #ty_generics #where_clause { + fn next_back(&mut self) -> Option<#name #ty_generics> { + if self.back_idx >= #variant_count { + return None + } + + let output = self.get(#variant_count - self.back_idx - 1); + + self.back_idx += 1; + output + } + } + impl #impl_generics Clone for #iter_name #ty_generics #where_clause { fn clone(&self) -> #iter_name #ty_generics { #iter_name { idx: self.idx, + back_idx: self.back_idx, marker: self.marker.clone(), } } diff --git a/strum_tests/tests/enum_iter.rs b/strum_tests/tests/enum_iter.rs index e3cffa58..4ba64bab 100644 --- a/strum_tests/tests/enum_iter.rs +++ b/strum_tests/tests/enum_iter.rs @@ -100,3 +100,18 @@ fn cycle_test() { ]; assert_eq!(expected, results); } + +#[test] +fn reverse_test() { + let results = Week::iter().rev().collect::>(); + let expected = vec![ + Week::Saturday, + Week::Friday, + Week::Thursday, + Week::Wednesday, + Week::Tuesday, + Week::Monday, + Week::Sunday, + ]; + assert_eq!(expected, results); +} From c1791966d1c2d9a71651a3b5c1887bc6dd5799a7 Mon Sep 17 00:00:00 2001 From: Sven Stegemann Date: Tue, 23 Jul 2019 12:29:16 +0200 Subject: [PATCH 2/6] Fixed overlapping behaviour of next and next_back. --- strum_macros/src/enum_iter.rs | 6 +++++- strum_tests/tests/enum_iter.rs | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/strum_macros/src/enum_iter.rs b/strum_macros/src/enum_iter.rs index ab00b070..a2a13e69 100644 --- a/strum_macros/src/enum_iter.rs +++ b/strum_macros/src/enum_iter.rs @@ -89,6 +89,10 @@ pub fn enum_iter_inner(ast: &syn::DeriveInput) -> TokenStream { type Item = #name #ty_generics; fn next(&mut self) -> Option<#name #ty_generics> { + if self.idx + self.back_idx >= #variant_count { + return None + } + let output = self.get(self.idx); self.idx += 1; @@ -109,7 +113,7 @@ pub fn enum_iter_inner(ast: &syn::DeriveInput) -> TokenStream { impl #impl_generics DoubleEndedIterator for #iter_name #ty_generics #where_clause { fn next_back(&mut self) -> Option<#name #ty_generics> { - if self.back_idx >= #variant_count { + if self.idx + self.back_idx >= #variant_count { return None } diff --git a/strum_tests/tests/enum_iter.rs b/strum_tests/tests/enum_iter.rs index 4ba64bab..2ebb4354 100644 --- a/strum_tests/tests/enum_iter.rs +++ b/strum_tests/tests/enum_iter.rs @@ -103,6 +103,21 @@ fn cycle_test() { #[test] fn reverse_test() { + let mut iter = Week::iter(); + + assert_eq!(Some(Week::Sunday), iter.next()); + assert_eq!(Some(Week::Saturday), iter.next_back()); + assert_eq!(Some(Week::Friday), iter.next_back()); + assert_eq!(Some(Week::Monday), iter.next()); + assert_eq!(Some(Week::Tuesday), iter.next()); + assert_eq!(Some(Week::Wednesday), iter.next()); + assert_eq!(Some(Week::Thursday), iter.next_back()); + assert_eq!(None, iter.next()); + assert_eq!(None, iter.next_back()); +} + +#[test] +fn take_from_both_sides_test() { let results = Week::iter().rev().collect::>(); let expected = vec![ Week::Saturday, From ff584125c49919d4559e16d5c569667c94315005 Mon Sep 17 00:00:00 2001 From: Sven Stegemann Date: Tue, 23 Jul 2019 12:53:49 +0200 Subject: [PATCH 3/6] Changed names of tests I accidentally swapped. --- strum_tests/tests/enum_iter.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/strum_tests/tests/enum_iter.rs b/strum_tests/tests/enum_iter.rs index 2ebb4354..a907df97 100644 --- a/strum_tests/tests/enum_iter.rs +++ b/strum_tests/tests/enum_iter.rs @@ -103,21 +103,6 @@ fn cycle_test() { #[test] fn reverse_test() { - let mut iter = Week::iter(); - - assert_eq!(Some(Week::Sunday), iter.next()); - assert_eq!(Some(Week::Saturday), iter.next_back()); - assert_eq!(Some(Week::Friday), iter.next_back()); - assert_eq!(Some(Week::Monday), iter.next()); - assert_eq!(Some(Week::Tuesday), iter.next()); - assert_eq!(Some(Week::Wednesday), iter.next()); - assert_eq!(Some(Week::Thursday), iter.next_back()); - assert_eq!(None, iter.next()); - assert_eq!(None, iter.next_back()); -} - -#[test] -fn take_from_both_sides_test() { let results = Week::iter().rev().collect::>(); let expected = vec![ Week::Saturday, @@ -130,3 +115,18 @@ fn take_from_both_sides_test() { ]; assert_eq!(expected, results); } + +#[test] +fn take_from_both_sides_test() { + let mut iter = Week::iter(); + + assert_eq!(Some(Week::Sunday), iter.next()); + assert_eq!(Some(Week::Saturday), iter.next_back()); + assert_eq!(Some(Week::Friday), iter.next_back()); + assert_eq!(Some(Week::Monday), iter.next()); + assert_eq!(Some(Week::Tuesday), iter.next()); + assert_eq!(Some(Week::Wednesday), iter.next()); + assert_eq!(Some(Week::Thursday), iter.next_back()); + assert_eq!(None, iter.next()); + assert_eq!(None, iter.next_back()); +} \ No newline at end of file From 4c08bcf138c0ad159407f64bda12a147eca20509 Mon Sep 17 00:00:00 2001 From: Sven Stegemann Date: Fri, 13 Dec 2019 21:36:18 +0100 Subject: [PATCH 4/6] Fixed size_hint() for EnumIter. --- strum_macros/src/enum_iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strum_macros/src/enum_iter.rs b/strum_macros/src/enum_iter.rs index a2a13e69..f04dbc2b 100644 --- a/strum_macros/src/enum_iter.rs +++ b/strum_macros/src/enum_iter.rs @@ -100,7 +100,7 @@ pub fn enum_iter_inner(ast: &syn::DeriveInput) -> TokenStream { } fn size_hint(&self) -> (usize, Option) { - let t = #variant_count - self.idx; + let t = #variant_count - self.idx - self.back_idx; (t, Some(t)) } } From dbc7a257b8cbe4aa98a38a7556fc3fb1fc398649 Mon Sep 17 00:00:00 2001 From: Sven Stegemann Date: Fri, 13 Dec 2019 21:39:21 +0100 Subject: [PATCH 5/6] Implemented more efficient version of nth() for EnumIter. --- strum_macros/src/enum_iter.rs | 38 ++++++++++++++++++++-------------- strum_tests/tests/enum_iter.rs | 27 ++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/strum_macros/src/enum_iter.rs b/strum_macros/src/enum_iter.rs index f04dbc2b..9db83e05 100644 --- a/strum_macros/src/enum_iter.rs +++ b/strum_macros/src/enum_iter.rs @@ -88,21 +88,24 @@ pub fn enum_iter_inner(ast: &syn::DeriveInput) -> TokenStream { impl #impl_generics Iterator for #iter_name #ty_generics #where_clause { type Item = #name #ty_generics; - fn next(&mut self) -> Option<#name #ty_generics> { - if self.idx + self.back_idx >= #variant_count { - return None - } - - let output = self.get(self.idx); - - self.idx += 1; - output + fn next(&mut self) -> Option { + self.nth(0) } fn size_hint(&self) -> (usize, Option) { let t = #variant_count - self.idx - self.back_idx; (t, Some(t)) } + + fn nth(&mut self, n: usize) -> Option { + self.idx += n + 1; + + if self.idx + self.back_idx > #variant_count { + None + } else { + self.get(self.idx - 1) + } + } } impl #impl_generics ExactSizeIterator for #iter_name #ty_generics #where_clause { @@ -112,15 +115,18 @@ pub fn enum_iter_inner(ast: &syn::DeriveInput) -> TokenStream { } impl #impl_generics DoubleEndedIterator for #iter_name #ty_generics #where_clause { - fn next_back(&mut self) -> Option<#name #ty_generics> { - if self.idx + self.back_idx >= #variant_count { - return None - } + fn next_back(&mut self) -> Option { + self.nth_back(0) + } - let output = self.get(#variant_count - self.back_idx - 1); + fn nth_back(&mut self, n: usize) -> Option { + self.back_idx += n + 1; - self.back_idx += 1; - output + if self.idx + self.back_idx > #variant_count { + None + } else { + self.get(#variant_count - self.back_idx) + } } } diff --git a/strum_tests/tests/enum_iter.rs b/strum_tests/tests/enum_iter.rs index a907df97..2ff9d10f 100644 --- a/strum_tests/tests/enum_iter.rs +++ b/strum_tests/tests/enum_iter.rs @@ -65,6 +65,21 @@ fn len_test() { assert_eq!(0, i.len()); } +#[test] +fn double_ended_len_test() { + let mut i = Complicated::<(), ()>::iter(); + assert_eq!(3, i.len()); + i.next_back(); + + assert_eq!(2, i.len()); + i.next(); + + assert_eq!(1, i.len()); + i.next_back(); + + assert_eq!(0, i.len()); +} + #[test] fn clone_test() { let mut i = Week::iter(); @@ -129,4 +144,16 @@ fn take_from_both_sides_test() { assert_eq!(Some(Week::Thursday), iter.next_back()); assert_eq!(None, iter.next()); assert_eq!(None, iter.next_back()); +} + +#[test] +fn take_nth_test() { + let mut iter = Week::iter(); + + assert_eq!(Some(Week::Tuesday), iter.nth(2)); + assert_eq!(Some(Week::Saturday), iter.nth_back(0)); + assert_eq!(Some(Week::Thursday), iter.nth_back(1)); + assert_eq!(None, iter.nth(1)); + assert_eq!(None, iter.next()); + assert_eq!(None, iter.next_back()); } \ No newline at end of file From 4636bec52560297e67cc5dd63aa726cc57a822da Mon Sep 17 00:00:00 2001 From: Sven Stegemann Date: Fri, 13 Dec 2019 22:39:54 +0100 Subject: [PATCH 6/6] Added another test of `next` and `next_back`, where the last call is to `next`. --- strum_tests/tests/enum_iter.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/strum_tests/tests/enum_iter.rs b/strum_tests/tests/enum_iter.rs index fcdecf1f..6e1975e0 100644 --- a/strum_tests/tests/enum_iter.rs +++ b/strum_tests/tests/enum_iter.rs @@ -149,6 +149,21 @@ fn take_from_both_sides_test() { assert_eq!(None, iter.next_back()); } +#[test] +fn take_from_both_sides_test2() { + let mut iter = Week::iter(); + + assert_eq!(Some(Week::Sunday), iter.next()); + assert_eq!(Some(Week::Saturday), iter.next_back()); + assert_eq!(Some(Week::Friday), iter.next_back()); + assert_eq!(Some(Week::Monday), iter.next()); + assert_eq!(Some(Week::Tuesday), iter.next()); + assert_eq!(Some(Week::Wednesday), iter.next()); + assert_eq!(Some(Week::Thursday), iter.next()); + assert_eq!(None, iter.next_back()); + assert_eq!(None, iter.next()); +} + #[test] fn take_nth_test() { let mut iter = Week::iter();