Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support arbitrary containers by IntoIterator blanket impl #230

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 14 additions & 62 deletions src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,8 @@ impl BitOr<HasIterator> for HasIterator {
/// whichever impl happens to be applicable. Calling that method repeatedly on
/// the returned value should be idempotent.
pub mod ext {
use super::RepInterp;
use super::{HasIterator as HasIter, ThereIsNoIteratorInRepetition as DoesNotHaveIter};
use crate::ToTokens;
use core::slice;
use std::collections::btree_set::{self, BTreeSet};

/// Extension trait providing the `quote_into_iter` method on iterators.
pub trait RepIteratorExt: Iterator + Sized {
Expand All @@ -60,6 +57,16 @@ pub mod ext {

impl<T: Iterator> RepIteratorExt for T {}

/// Extension trait providing the `quote_into_iter` method on containers
/// implementing IntoIterator.
pub trait RepIntoIteratorExt: IntoIterator + Copy + Sized {
fn quote_into_iter(self) -> (Self::IntoIter, HasIter) {
(self.into_iter(), HasIter)
}
}

impl<T: IntoIterator + Copy> RepIntoIteratorExt for T {}

/// Extension trait providing the `quote_into_iter` method for
/// non-iterable types. These types interpolate the same value in each
/// iteration of the repetition.
Expand All @@ -77,62 +84,6 @@ pub mod ext {
}

impl<T: ToTokens + ?Sized> RepToTokensExt for T {}

/// Extension trait providing the `quote_into_iter` method for types that
/// can be referenced as an iterator.
pub trait RepAsIteratorExt<'q> {
type Iter: Iterator;

fn quote_into_iter(&'q self) -> (Self::Iter, HasIter);
}

impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a T {
type Iter = T::Iter;

fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
<T as RepAsIteratorExt>::quote_into_iter(*self)
}
}

impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a mut T {
type Iter = T::Iter;

fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
<T as RepAsIteratorExt>::quote_into_iter(*self)
}
}

impl<'q, T: 'q> RepAsIteratorExt<'q> for [T] {
type Iter = slice::Iter<'q, T>;

fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
(self.iter(), HasIter)
}
}

impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec<T> {
type Iter = slice::Iter<'q, T>;

fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
(self.iter(), HasIter)
}
}

impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet<T> {
type Iter = btree_set::Iter<'q, T>;

fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
(self.iter(), HasIter)
}
}

impl<'q, T: RepAsIteratorExt<'q>> RepAsIteratorExt<'q> for RepInterp<T> {
type Iter = T::Iter;

fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
self.0.quote_into_iter()
}
}
}

// Helper type used within interpolations to allow for repeated binding names.
Expand All @@ -150,11 +101,12 @@ impl<T> RepInterp<T> {
}
}

impl<T: Iterator> Iterator for RepInterp<T> {
impl<T: IntoIterator> IntoIterator for RepInterp<T> {
type Item = T::Item;
type IntoIter = T::IntoIter;

fn next(&mut self) -> Option<Self::Item> {
self.0.next()
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}

Expand Down
86 changes: 54 additions & 32 deletions tests/ui/not-repeatable.stderr
Original file line number Diff line number Diff line change
@@ -1,35 +1,57 @@
error[E0599]: the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not satisfied
--> tests/ui/not-repeatable.rs:7:9
|
3 | struct Ipv4Addr;
| ---------------
| |
| method `quote_into_iter` not found for this struct
| doesn't satisfy `Ipv4Addr: Iterator`
| doesn't satisfy `Ipv4Addr: ToTokens`
| doesn't satisfy `Ipv4Addr: ext::RepIteratorExt`
| doesn't satisfy `Ipv4Addr: ext::RepToTokensExt`
--> tests/ui/not-repeatable.rs:7:9
|
3 | struct Ipv4Addr;
| ---------------
| |
| method `quote_into_iter` not found for this struct
| doesn't satisfy `Ipv4Addr: Copy`
| doesn't satisfy `Ipv4Addr: IntoIterator`
| doesn't satisfy `Ipv4Addr: Iterator`
| doesn't satisfy `Ipv4Addr: ToTokens`
| doesn't satisfy `Ipv4Addr: ext::RepIntoIteratorExt`
| doesn't satisfy `Ipv4Addr: ext::RepIteratorExt`
| doesn't satisfy `Ipv4Addr: ext::RepToTokensExt`
...
7 | _ = quote! { #(#ip)* };
| ^^^^^^^^^^^^^^^^^^ method cannot be called on `Ipv4Addr` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`Ipv4Addr: Iterator`
which is required by `Ipv4Addr: ext::RepIteratorExt`
`&Ipv4Addr: Iterator`
which is required by `&Ipv4Addr: ext::RepIteratorExt`
`Ipv4Addr: ToTokens`
which is required by `Ipv4Addr: ext::RepToTokensExt`
`&mut Ipv4Addr: Iterator`
which is required by `&mut Ipv4Addr: ext::RepIteratorExt`
7 | _ = quote! { #(#ip)* };
| ^^^^^^^^^^^^^^^^^^ method cannot be called on `Ipv4Addr` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`Ipv4Addr: Iterator`
which is required by `Ipv4Addr: ext::RepIteratorExt`
`Ipv4Addr: IntoIterator`
which is required by `Ipv4Addr: ext::RepIntoIteratorExt`
`Ipv4Addr: Copy`
which is required by `Ipv4Addr: ext::RepIntoIteratorExt`
`&Ipv4Addr: Iterator`
which is required by `&Ipv4Addr: ext::RepIteratorExt`
`&Ipv4Addr: IntoIterator`
which is required by `&Ipv4Addr: ext::RepIntoIteratorExt`
`Ipv4Addr: ToTokens`
which is required by `Ipv4Addr: ext::RepToTokensExt`
`&mut Ipv4Addr: Iterator`
which is required by `&mut Ipv4Addr: ext::RepIteratorExt`
`&mut Ipv4Addr: IntoIterator`
which is required by `&mut Ipv4Addr: ext::RepIntoIteratorExt`
`&mut Ipv4Addr: Copy`
which is required by `&mut Ipv4Addr: ext::RepIntoIteratorExt`
note: the following traits must be implemented
--> src/to_tokens.rs
|
| pub trait ToTokens {
| ^^^^^^^^^^^^^^^^^^
|
::: $RUST/core/src/iter/traits/iterator.rs
|
| pub trait Iterator {
| ^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `$crate::quote_bind_into_iter` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)
--> src/to_tokens.rs
|
| pub trait ToTokens {
| ^^^^^^^^^^^^^^^^^^
|
::: $RUST/core/src/iter/traits/collect.rs
|
| pub trait IntoIterator {
| ^^^^^^^^^^^^^^^^^^^^^^
|
::: $RUST/core/src/iter/traits/iterator.rs
|
| pub trait Iterator {
| ^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `$crate::quote_bind_into_iter` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Ipv4Addr` with `#[derive(Clone, Copy)]`
|
3 | #[derive(Clone, Copy)]
|