Simplify Rust extension trait lifetimes when using Add trait - rust

I need an extension trait for everything that implements AsRef<[T]>. A method of this trait takes a reference to T and based on some math with it returns a sub-slice of the original array.
Sample code can look like:
trait Sample<T> {
fn sample(&self, element: &T, k: usize) -> &[T];
}
impl<'a, A, T> Sample<T> for A
where
A: AsRef<[T]>,
&'a T: Add<Output = T>,
T: 'a,
{
fn sample(&self, element: &T, k: usize) -> &[T] {
let array = self.as_ref();
let doubled = element + element;
&array[0..0]
}
}
It does not compile, though.
error: lifetime may not live long enough
--> src/arrays/sample.rs:15:23
|
7 | impl<'a, A, T> Sample<T> for A
| -- lifetime `'a` defined here
...
13 | fn sample(&self, element: &T, k: usize) -> &[T] {
| - let's call the lifetime of this reference `'1`
14 | let array = self.as_ref();
15 | let doubled = element + element;
| ^^^^^^^^^^^^^^^^^ requires that `'1` must outlive `'a`
I don't really understand why element lifetime must be bigger than 'a.
Anyways, after a while I made it work, but it does not feel right.
use core::ops::Add;
trait KClosestExt<'t, T> {
fn find_k_closest(&'t self, element: &'t T, k: usize) -> &[T];
}
impl<'a, 't, A, T> KClosestExt<'t, T> for A
where
A: AsRef<[T]>,
&'a T: Add<Output = T>,
T: 'a + 't + PartialOrd,
't: 'a,
{
fn find_k_closest(&'t self, element: &'t T, k: usize) -> &[T] {
let array = self.as_ref();
if k > array.len() {
return array;
}
let doubled = element + element;
let left = binary_search(0, array.len() - k, |mid| doubled > &array[mid + k] + &array[mid]);
&array[left..left + k]
}
}
According to what I need, is it possible to simplify lifetime management for this example?

Your lifetime issues stem from the bound &'a T: Add<Output = T>. This says that &T implements Add but only when the lifetime is exactly &'a T.
What you most likely want is for<'a> &'a T: Add<Output = T> which specifies that &T implements Add for any lifetime that you choose. (1)
With this change, you sample code compiles without needing to specify any more lifetimes. playground.
trait Sample<T> {
fn sample(&self, element: &T, k: usize) -> &[T];
}
impl<A, T> Sample<T> for A
where
A: AsRef<[T]>,
for<'a> &'a T: std::ops::Add<Output = T>,
{
fn sample(&self, element: &T, k: usize) -> &[T] {
let array = self.as_ref();
let doubled = element + element;
&array[0..0]
}
}
(1) Strictly speaking, this is a more restrictive bound but I struggle to see a situation where the first one is fulfilled but not the second one.

Related

Generic trait for all containers implementing iter()

I'm trying to implement a trait for all containers that implement iter(), ie. for all containers that provide an IntoIterator<Item=&'a T>. I've tried this, but unfortunately, even for the simplest case it is failing. Maybe someone knows what I'm doing wrong?
trait Monotonic<'a, T: 'a + ?Sized> {
fn is_monotonic(&mut self) -> bool {
return true;
}
}
impl<'a, T: 'a + ?Sized, C> Monotonic<'a, T> for C
where C: IntoIterator<Item=&'a T> + ?Sized {}
fn main() {
let v = vec![1u32, 2u32, 3u32];
if v.is_monotonic() {
print!("Is monotonic!");
}
}
The compiler complains about not satisfied bounds:
error[E0599]: the method `is_monotonic` exists for struct `Vec<u32>`, but its trait bounds were not satisfied
--> src/test.rs:13:10
|
13 | if v.is_monotonic() {
| ^^^^^^^^^^^^ method cannot be called on `Vec<u32>` due to unsatisfied trait bounds
--> /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/alloc/src/vec/mod.rs:400:1
|
| = note: doesn't satisfy `<Vec<u32> as IntoIterator>::Item = &_`
= note: doesn't satisfy `Vec<u32>: Monotonic<'_, _>`
|
note: trait bound `[u32]: IntoIterator` was not satisfied
--> src/test.rs:8:10
|
7 | impl<'a, T: 'a + ?Sized, C> Monotonic<'a, T> for C
| ---------------- -
8 | where C: IntoIterator<Item=&'a T> + ?Sized {}
| ^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
note: the following trait bounds were not satisfied:
`<Vec<u32> as IntoIterator>::Item = &_`
`<[u32] as IntoIterator>::Item = &_`
--> src/test.rs:8:23
|
7 | impl<'a, T: 'a + ?Sized, C> Monotonic<'a, T> for C
| ---------------- -
8 | where C: IntoIterator<Item=&'a T> + ?Sized {}
| ^^^^^^^^^^ unsatisfied trait bound introduced here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0599`.
I've already tried to solve this on my own, but after several attempts I'm at a point where some help would be highly appreciated!
According to its documentation, Vec<T> implements the following IntoIterator traits:
IntoIterator<Item = &'a T> for &'a Vec<T, A>
IntoIterator<Item = &'a mut T> for &'a mut Vec<T, A>
IntoIterator<Item = T> for Vec<T, A>
The variable v you are calling it on is a Vec<u32>, which only implements IntoIterator<Item = u32>, and not any kind of &'a u32 as your trait requires.
There are a couple of solutions. The first one is to run the code on &v:
trait Monotonic<'a, T: 'a + ?Sized> {
fn is_monotonic(&mut self) -> bool {
return true;
}
}
impl<'a, T: 'a + ?Sized, C> Monotonic<'a, T> for C where C: IntoIterator<Item = &'a T> + ?Sized {}
fn main() {
let v = vec![1u32, 2u32, 3u32];
if (&v).is_monotonic() {
print!("Is monotonic!");
}
}
Although that's probably not what you want, because I read from your question that you want your Monotonic trait to be implemented as generically as possible. For that, simply remove the & requirement:
trait Monotonic<'a, T: 'a + ?Sized> {
fn is_monotonic(&mut self) -> bool {
return true;
}
}
impl<'a, T: 'a + ?Sized, C> Monotonic<'a, T> for C where C: IntoIterator<Item = T> + ?Sized {}
fn main() {
let mut v = vec![1u32, 2u32, 3u32];
if v.is_monotonic() {
print!("Is monotonic!");
}
}
Couple of remarks concerning your current code structure, though:
While this technically compiles, it won't be possible to implement your function. IntoIterator consumes the object you call it on, but your is_monotonic function only has &mut access to it, so you won't ever be able to call into_iter here.
What you probably want instead is to have is_monotonic consume the value, but then only implement it for &T.
Your Monotonic function doesn't require any generic parameters, so remove them.
trait Monotonic {
fn is_monotonic(self) -> bool;
}
impl<'a, T, C> Monotonic for &'a C
where
&'a C: IntoIterator<Item = T>,
{
fn is_monotonic(self) -> bool {
let mut iter = self.into_iter();
// Do something with iter
let x = iter.next().unwrap();
// Return result
true
}
}
fn main() {
let v = vec![1u32, 2u32, 3u32];
if v.is_monotonic() {
print!("Is monotonic!");
}
}
Here is an example implementation of is_monotonic, assuming it means monotonic rising:
trait Monotonic {
fn is_monotonic(self) -> bool;
}
impl<'a, T, C> Monotonic for &'a C
where
&'a C: IntoIterator<Item = T>,
T: PartialOrd,
{
fn is_monotonic(self) -> bool {
let mut iter = self.into_iter();
if let Some(first) = iter.next() {
let mut previous = first;
for next in iter {
if !next.ge(&previous) {
return false;
}
previous = next;
}
true
} else {
// An iterator without elements is monotonic.
// Although that's probably up for philosophical debate.
true
}
}
}
fn main() {
let v = vec![1u32, 2u32, 3u32];
if v.is_monotonic() {
println!("Is monotonic!");
}
println!("{:?}", v);
}
Is monotonic!
[1, 2, 3]

Lifetime collision when bounding reference of a trait as IntoIterator

I tried to implement some graph algorithms on generic graphs. For that, I defined two graph traits which would return either a generic trait (having set-operations) SetGraph or an IntoIterator used to iterate over the nodes NeighborhoodIteratorGraph.
pub trait NeighborhoodIteratorGraph<'a> {
//which into_iterator do we have?
type IntoIter: 'a + std::iter::IntoIterator<Item = usize>;
fn get_neighborhood_iterator(&'a self, index: usize) -> Self::IntoIter;
}
pub trait SetGraph<'a>
where
&'a Self::S: IntoIterator<Item = usize>,
Self::S: 'a,
{
type S;
fn get_neighborhood(&'a self, index: usize) -> &'a Self::S;
}
Because one is usually able to iterate over sets, I also implemented NeighborhoodIteratorGraph for all SetGraph which are able to iterate over their sets.
impl<'a, G> NeighborhoodIteratorGraph<'a> for G
where
G: SetGraph<'a>,
&'a G::S: IntoIterator<Item = usize>,
{
type IntoIter = &'a G::S;
fn get_neighborhood_iterator(&'a self, index: usize) -> Self::IntoIter {
self.get_neighborhood(index)
}
}
I needed to add a lifetime to NeighborrhoodIteratorGraph otherwise the compiler would tell me my implementation would have an unbounded lifetime.
However I quicky run into problems with these lifetimes and I get an error for the following code:
struct Foo<'a, G: NeighborhoodIteratorGraph<'a>> {
graph: G,
//otherwise we get an error because 'a wouldn't be used
_marker: std::marker::PhantomData<&'a G>,
}
impl<'a, G: NeighborhoodIteratorGraph<'a>> Foo<'a, G> {
pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
where
I: std::iter::IntoIterator<Item = usize>,
{
for node in self.graph.get_neighborhood_iterator(3) {}
return true;
}
}
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
It seems that the PhantomData field is more a hack and I can't find a way in which I get a set refernce which can be seen as a IntoIterator object.
Here is the Rust Playground of the problem.
Full error message:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:38:32
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 34:5...
--> src/lib.rs:34:5
|
34 | / pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
35 | | where
36 | | I: std::iter::IntoIterator<Item = usize>,
| |_________________________________________________^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:38:21
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 33:6...
--> src/lib.rs:33:6
|
33 | impl<'a, G: NeighborhoodIteratorGraph<'a>> Foo<'a, G> {
| ^^
note: ...so that the types are compatible
--> src/lib.rs:38:32
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `&'a G`
found `&G`
What you want is a workaround for the lack of generic associated types, which are currently very unstable. Something Like
pub trait NeighborhoodIteratorGraph {
type IntoIter<'a>: std::iter::IntoIterator<Item = usize> + 'a;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter<'b>;
}
would serve you perfectly if they were stable.
The first thing I did is remove the lifetime bound on NeighborhoodIteratorGraph and add it to the return type:
pub trait NeighborhoodIteratorGraph {
type IntoIter: std::iter::IntoIterator<Item = usize>;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter
where
Self::IntoIter: 'b;
}
I then removed unnecessary lifetime annotations from SetGraph:
pub trait SetGraph<'a>
where
&'a Self::S: IntoIterator<Item = usize>,
Self::S: 'a,
{
type S;
fn get_neighborhood(&self, index: usize) -> &Self::S;
}
I then changed the blanket impl's signature to match the modified traits, and changed the impl from G to &'a G to properly constrain the lifetime 'a:
impl<'a, G> NeighborhoodIteratorGraph for &'a G
where
G: SetGraph<'a>,
&'a G::S: IntoIterator<Item = usize>,
{
type IntoIter = &'a G::S;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter
where
Self::IntoIter: 'b,
{
self.get_neighborhood(index)
}
}
Because of those changes I was able to simplify Foo and its impl:
struct Foo<G: NeighborhoodIteratorGraph> {
graph: G,
}
impl<G: NeighborhoodIteratorGraph> Foo<G> {
pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
where
I: std::iter::IntoIterator<Item = usize>,
{
for node in self.graph.get_neighborhood_iterator(3) {}
return true;
}
}
Leaving the compiler output with nothing but dead code warnings. Playground link

How to write trait bound that supports += operation whose right hand is reference in complicated case in Rust [duplicate]

This question already has an answer here:
How to write a trait bound for adding two references of a generic type?
(1 answer)
Closed 2 years ago.
I'd like to write an Add operation supported Vector struct, and write a some trait that uses the Vector struct, so I wrote this.
use std::ops::*;
#[derive(Clone)]
struct Vector<T>(Vec<T>);
impl<'a, T> Add<&'a Vector<T>> for Vector<T>
where
T: AddAssign<&'a T>,
{
type Output = Vector<T>;
fn add(mut self, rhs: &'a Vector<T>) -> Self::Output {
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(left, right)| {
*left += right;
});
self
}
}
trait SomeOperation<'a ,T>
where
T: AddAssign<&'a T>+Clone + 'a,
{
fn add(u:Vector<T>,v:&'a Vector<T>)->Vector<T>{
let w = u+v;
let x = v.clone()+&w;
x
}
}
But compilation error occurs.
21 | trait SomeOperation<'a ,T>
| -- lifetime `'a` defined here
...
27 | let x = v.clone()+&w;
| ^^
| |
| borrowed value does not live long enough
| requires that `w` is borrowed for `'a`
28 | x
29 | }
| - `w` dropped here while still borrowed
How can I avoid these types of error.
You talk about implementing AddAssign but your code tries to implement Add. Also, I couldn't figure out what SomeOperation was for. I added the Debug trait to the derive line.
use std::ops::*;
#[derive(Clone, Debug)]
struct Vector<T>(Vec<T>);
impl<'a, T> AddAssign<&'a Vector<T>> for Vector<T>
where
T: AddAssign<&'a T>
{
fn add_assign(&mut self, rhs: &'a Vector<T>) {
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(left, right)| {
*left += right;
});
}
}
impl<'a, 'b, T> Add<& 'b Vector<T>> for & 'a Vector<T>
where
Vector<T>: AddAssign<& 'b Vector<T>>,
T: Clone,
{
type Output = Vector<T>;
fn add(self, other: & 'b Vector<T>) -> Self::Output {
let mut res: Vector<T> = self.clone();
res += other;
res
}
}
fn main() {
let mut v1: Vector<u32> = Vector(vec![1, 2, 3]);
let v2 = Vector(vec![4, 5, 6]);
println!("Add: {:?}", &v1 + &v2);
v1 += &v2;
println!("AddAssign{:?}", v1);
}

Lifetime problems on implementing function that maps over an iterator using a HashMap

I tried to implement a function that maps over an iterator using a HashMap:
use std::collections::HashMap;
use std::hash::Hash;
/// Translates every element it gets using a map. In case the map does not help, it is mapped to
/// itself.
fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
where
S: Iterator<Item = T> + 'b,
T: Copy + Eq + Hash,
{
stream.map(|e: T| -> T { *map.get(&e).unwrap_or(&e) })
}
playground
I get an error message for this code:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/lib.rs:11:16
|
11 | stream.map(|e: T| -> T { *map.get(&e).unwrap_or(&e) })
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 6:14...
--> src/lib.rs:6:14
|
6 | fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
| ^^
= note: ...so that the types are compatible:
expected &&std::collections::HashMap<T, T>
found &&'a std::collections::HashMap<T, T>
note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 6:18...
--> src/lib.rs:6:18
|
6 | fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
| ^^
note: ...so that return value is valid for the call
--> src/lib.rs:6:66
|
6 | fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I have not figured out what is wrong or how I can solve it.
I have to guess, as you didn't include a MCVE. Your code doesn't compile, with lifetime errors on the surface. The function signature you probably meant is:
fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a
where
S: Iterator<Item = T> + 'b,
T: Copy + Eq + Hash,
'b: 'a, // Read: "'b outlives 'a"
As S might outlive your return value, and it would still be valid.
However I do not see any advantages of this approach: A longer lifetime is always valid in place of a shorter one, you don't explicitly need to call that out. Simply use a single lifetime, like below.
fn translate<'a, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a
where
S: Iterator<Item = T> + 'a,
T: Copy + Eq + Hash,
{
stream.map(move |e: T| -> T { *map.get(&e).unwrap_or(&e) })
}
As you see, you are also missing the move keyword, which your closure absolutely requires. Otherwise, it might outlive your map, which is owned by the function.
Still, this function is quite dense. If you only use it in a single place, maybe don't introduce it at all, and save some headaches?

How do I use a &HashSet<&T> as an IntoIterator<Item = &T>?

I have a function that takes a collection of &T (represented by IntoIterator) with the requirement that every element is unique.
fn foo<'a, 'b, T: std::fmt::Debug, I>(elements: &'b I)
where
&'b I: IntoIterator<Item = &'a T>,
T: 'a,
'b: 'a,
I would like to also write a wrapper function which can work even if the elements are not unique, by using a HashSet to remove the duplicate elements first.
I tried the following implementation:
use std::collections::HashSet;
fn wrap<'a, 'b, T: std::fmt::Debug + Eq + std::hash::Hash, J>(elements: &'b J)
where
&'b J: IntoIterator<Item = &'a T>,
T: 'a,
'b: 'a,
{
let hashset: HashSet<&T> = elements.into_iter().into_iter().collect();
foo(&hashset);
}
playground
However, the compiler doesn't seem happy with my assumption that HashSet<&T> implements IntoIterator<Item = &'a T>:
error[E0308]: mismatched types
--> src/lib.rs:10:9
|
10 | foo(&hashset);
| ^^^^^^^^ expected type parameter, found struct `std::collections::HashSet`
|
= note: expected type `&J`
found type `&std::collections::HashSet<&T>`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
I know I could use a HashSet<T> by cloning all the input elements, but I want to avoid unnecessary copying and memory use.
If you have a &HashSet<&T> and need an iterator of &T (not &&T) that you can process multiple times, then you can use Iterator::copied to convert the iterator's &&T to a &T:
use std::{collections::HashSet, fmt::Debug, hash::Hash, marker::PhantomData};
struct Collection<T> {
item: PhantomData<T>,
}
impl<T> Collection<T>
where
T: Debug,
{
fn foo<'a, I>(elements: I) -> Self
where
I: IntoIterator<Item = &'a T> + Clone,
T: 'a,
{
for element in elements.clone() {
println!("{:?}", element);
}
for element in elements {
println!("{:?}", element);
}
Self { item: PhantomData }
}
}
impl<T> Collection<T>
where
T: Debug + Eq + Hash,
{
fn wrap<'a, I>(elements: I) -> Self
where
I: IntoIterator<Item = &'a T>,
T: 'a,
{
let set: HashSet<_> = elements.into_iter().collect();
Self::foo(set.iter().copied())
}
}
#[derive(Debug, Hash, PartialEq, Eq)]
struct Foo(i32);
fn main() {
let v = vec![Foo(1), Foo(2), Foo(4)];
Collection::<Foo>::wrap(&v);
}
See also:
Using the same iterator multiple times in Rust
Does cloning an iterator copy the entire underlying vector?
Why does cloning my custom type result in &T instead of T?
Note that the rest of this answer made the assumption that a struct named Collection<T> was a collection of values of type T. OP has clarified that this is not true.
That's not your problem, as shown by your later examples. That can be boiled down to this:
struct Collection<T>(T);
impl<T> Collection<T> {
fn new(value: &T) -> Self {
Collection(value)
}
}
You are taking a reference to a type (&T) and trying to store it where a T is required; these are different types and will generate an error. You are using PhantomData for some reason and accepting references via the iterator, but the problem is the same.
In fact, PhantomData makes the problem harder to see as you can just make up values that don't work. For example, we never have any kind of string here but we "successfully" created the struct:
use std::marker::PhantomData;
struct Collection<T>(PhantomData<T>);
impl Collection<String> {
fn new<T>(value: &T) -> Self {
Collection(PhantomData)
}
}
Ultimately, your wrap function doesn't make sense, either:
impl<T: Eq + Hash> Collection<T> {
fn wrap<I>(elements: I) -> Self
where
I: IntoIterator<Item = T>,
This is equivalent to
impl<T: Eq + Hash> Collection<T> {
fn wrap<I>(elements: I) -> Collection<T>
where
I: IntoIterator<Item = T>,
Which says that, given an iterator of elements T, you will return a collection of those elements. However, you put them in a HashMap and iterate on a reference to it, which yields &T. Thus this function signature cannot be right.
It seems most likely that you want to accept an iterator of owned values instead:
use std::{collections::HashSet, fmt::Debug, hash::Hash};
struct Collection<T> {
item: T,
}
impl<T> Collection<T> {
fn foo<I>(elements: I) -> Self
where
I: IntoIterator<Item = T>,
for<'a> &'a I: IntoIterator<Item = &'a T>,
T: Debug,
{
for element in &elements {
println!("{:?}", element);
}
for element in &elements {
println!("{:?}", element);
}
Self {
item: elements.into_iter().next().unwrap(),
}
}
}
impl<T> Collection<T>
where
T: Eq + Hash,
{
fn wrap<I>(elements: I) -> Self
where
I: IntoIterator<Item = T>,
T: Debug,
{
let s: HashSet<_> = elements.into_iter().collect();
Self::foo(s)
}
}
#[derive(Debug, Hash, PartialEq, Eq)]
struct Foo(i32);
fn main() {
let v = vec![Foo(1), Foo(2), Foo(4)];
let c = Collection::wrap(v);
println!("{:?}", c.item)
}
Here we place a trait bound on the generic iterator type directly and a second higher-ranked trait bound on a reference to the iterator. This allows us to use a reference to the iterator as an iterator itself.
See also:
How does one generically duplicate a value in Rust?
Is there any way to return a reference to a variable created in a function?
How do I write the lifetimes for references in a type constraint when one of them is a local reference?
There were a number of orthogonal issues with my code that Shepmaster pointed out, but to solve the issue of using a HashSet<&T> as an IntoIterator<Item=&T>, I found that one way to solve it is with a wrapper struct:
struct Helper<T, D: Deref<Target = T>>(HashSet<D>);
struct HelperIter<'a, T, D: Deref<Target = T>>(std::collections::hash_set::Iter<'a, D>);
impl<'a, T, D: Deref<Target = T>> Iterator for HelperIter<'a, T, D>
where
T: 'a,
{
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|x| x.deref())
}
}
impl<'a, T, D: Deref<Target = T>> IntoIterator for &'a Helper<T, D> {
type Item = &'a T;
type IntoIter = HelperIter<'a, T, D>;
fn into_iter(self) -> Self::IntoIter {
HelperIter((&self.0).into_iter())
}
}
Which is used as follows:
struct Collection<T> {
item: PhantomData<T>,
}
impl<T: Debug> Collection<T> {
fn foo<I>(elements: I) -> Self
where
I: IntoIterator + Copy,
I::Item: Deref<Target = T>,
{
for element in elements {
println!("{:?}", *element);
}
for element in elements {
println!("{:?}", *element);
}
return Self { item: PhantomData };
}
}
impl<T: Debug + Eq + Hash> Collection<T> {
fn wrap<I>(elements: I) -> Self
where
I: IntoIterator + Copy,
I::Item: Deref<Target = T> + Eq + Hash,
{
let helper = Helper(elements.into_iter().collect());
Self::foo(&helper);
return Self { item: PhantomData };
}
}
fn main() {
let v = vec![Foo(1), Foo(2), Foo(4)];
Collection::<Foo>::wrap(&v);
}
I'm guessing that some of this may be more complicated than it needs to be, but I'm not sure how.
full playground

Resources