1

Here's a reduced form of problem: I have a trait

pub trait GetIter {
    type IntoIter: IntoIterator<Item=usize>;
    fn get_iter( &self ) -> Self::IntoIter;
}

There are several use cases where I can implement GetIter on a reference &'a T, but not on T. This is fine for pure Rust, but lately I've needed to build a python interface with pyo3.

Since pyo3 wrappers are incompatible with lifetime parameters, I'd like to do something like the following

pub struct  NoRef< T > { inner: T }

impl <T> GetIter for NoRef< T > 
    where &T: GetIter
{
    type IntoIter = Vec<usize>;
    fn get_iter( &self )-> Vec<usize> { 
        (&self.inner).get_iter().into_iter().collect() 
    }
}

That is, we create a temporary reference internally, just long enough to dump the contents of the iterator to a vector, the drop the reference. The problem is that Rust doesn't like the constraint &T: GetIter -- it wants a lifetime parameter.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
GHPR
  • 45
  • 6
  • Have you tried declaring it with a `'static` lifetime? The memory management in python is more relaxed, I imagine you would not have problems with `static references. I'm not sure what I'm saying, though. – al3x Mar 31 '23 at 03:22
  • Thanks! Tried two variations: first was ``` impl <'a, T: 'static> GetIter for NoRef< T > where &'a T: GetIter ``` second was ``` impl < T: 'static> GetIter for NoRef< T > where &'static T: GetIter ``` But both gave errors about an variable living too long (I'm no expert but I'd guess it's because rust assumes the reference we create in the function body must have a static lifetime, which means it has to persist after the scope of the function body drops). – GHPR Mar 31 '23 at 06:00
  • 2
    You probably want a HRTB: `where for<'a> &'a T: GetIter`. – Jmb Mar 31 '23 at 06:36
  • Yes, Adding to @Jmb's answer, I think the `&self.inner` is tryng to constrain it to the lifetime `'a` on the trait and there is no way for the compiler to figure that out. The `&self.inner` is looked at as a "shorter" lifetime/borrow than `'a` and you can't present a short lifetime as a longer one. https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=797535f9dfa80b58dc4717c080046853 – vikram2784 Mar 31 '23 at 06:49
  • That works great! This problem has a few level of complexity, and since the first level is now nicely resolved, I'm editing the post to include both the solution and the next level of detail. – GHPR Mar 31 '23 at 07:58
  • Please don't do that. If you have other questions then [ask a new question](https://stackoverflow.com/questions/ask), possibly linking to this one for reference. – Jmb Mar 31 '23 at 08:01

1 Answers1

1

Use an HRTB:

impl < T > GetIter for NoRef< T > 
    where for <'a>  &'a T: GetIter,
{
    type IntoIter = Vec<usize>;
    fn get_iter( & self )-> Vec<usize> { 
        (&self.inner).get_iter().into_iter().collect() 
    }
}

Just for added detail, you can check that this compiles/executes correctly with an example:

impl <'a> GetIter for &'a Vec<usize> { 
    type IntoIter=Vec<usize>; 
    
    fn get_iter(&self)->Self::IntoIter { 
        (*self).clone() 
    } 
}
Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77