Search code examples
rustiteratorconstraintstraits

Equality constraints in trait in Rust. Variant with Into<T> trait


I want the ToKeyIter::Item be equal to ToKeyIter::KeyIter::Item as KeyIter should implement Iterator trait. I couldn't do it because with constraint equality in where clause. That's why I decided to use trait Into.

pub trait ToKeyIter {
    type Item: Clone + Hash + Eq;
    type KeyIter<'b>: Iterator where Self: 'b, <Self::KeyIter<'b> as Iterator>::Item: Into<Self::Item>;
    fn key_iter<'a> (&'a self) -> Self::KeyIter<'a> 
    where <Self::KeyIter<'a> as Iterator>::Item: Into<Self::Item>;
}

The trait itself compiles, but when I try to impl it for str or String, the compiler fails with "overflow evaluating the requirement".

impl ToKeyIter for str {
    type Item = char;
    type KeyIter<'a> = Chars<'a>;

    fn key_iter<'a> (&'a self) -> Chars<'a> {
        self.chars()
    }
}


impl ToKeyIter for String {
    type Item = char;
    type KeyIter<'a> = Chars<'a>;
    
    fn key_iter<'a> (&'a self) -> Chars<'a> {
        self.chars()
    }
} 

If you can tell how to write something like this

Key::Item == Key::KeyIter::Item

it will be great. But also I want to know what I should do to have correct impl for str and String with Into trait.


Solution

  • You can specify the Iterate<Item=Self::Item> to obtain what you want. See the playground for a live version of this:

    #![feature(generic_associated_types)]
    
    use std::hash::Hash;
    use std::str::Chars;
    
    pub trait ToKeyIter {
        type Item: Clone + Hash + Eq;
        type KeyIter<'a>: Iterator<Item=Self::Item>
        where
            Self: 'a;
        fn key_iter<'a>(&'a self) -> Self::KeyIter<'a>;
    }
    
    impl ToKeyIter for str {
        type Item = char;
        type KeyIter<'a> = Chars<'a>;
    
        fn key_iter<'a> (&'a self) -> Chars<'a> {
            self.chars()
        }
    }
    impl ToKeyIter for String {
        type Item = char;
        type KeyIter<'a> = Chars<'a>;
        
        fn key_iter<'a> (&'a self) -> Chars<'a> {
            self.chars()
        }
    }