danielhenrymantilla / lending-iterator.rs

Lending iterators on stable Rust
https://docs.rs/lending-iterator
Apache License 2.0
78 stars 4 forks source link

Improve docs on how to implement `LendingIterator` #9

Open jorgecarleitao opened 1 year ago

jorgecarleitao commented 1 year ago

The README describes how to implement anonymous implementations of LendingIterator. Would it be possible to expand a bit and demo how to implement a non-anonymous version?

I.e. given

struct ItemRef<'a>(&'a [u8]);
struct A(Vec<u8>);

how would

impl LendingIterator<ItemRef> for A

look like if say we want to return chunks of size 8 of the Vec<u8>

Thanks for the cool crate!

Qqwy commented 1 year ago

Curiously there is an example in the documentation of the Nougat crate

#[macro_use]
extern crate nougat;

#[gat]
trait LendingIterator {
    type Item<'next>
    where
        Self : 'next,
    ;

    fn next(&mut self) -> Option<Self::Item<'_>>;
}

struct WindowsMut<Slice, const SIZE: usize> {
    slice: Slice,
    start: usize,
}

#[gat]
impl<Item, const SIZE: usize> LendingIterator for WindowsMut<&mut [Item], SIZE> {
    type Item<'next>
    where
        Self : 'next,
    =
        &'next mut [Item; SIZE]
    ;

    fn next(&mut self) -> Option<&mut [Item; SIZE]> {
        let to_yield =
            self.slice
                .get_mut(self.start ..)?
                .get_mut(.. SIZE)?
                .try_into()
                .expect("slice has the right SIZE")
        ;
        self.start += 1;
        Some(to_yield)
    }
}
obskyr commented 4 months ago

I attempted to find documentation on how to impl LendingIterator, but found nothing but @Qqwy's comment – but it's not helping much. I'm trying to create an iterator that offers slice windows into a buffer owned by the iterator itself, and I figured a lending iterator would be the right tool for the job. I seem to be getting the same errors as with a regular Iterator, however… Here's a minimal example:

use ::lending_iterator::prelude::*;

struct Slicer<'a> {
    full: Vec<u32>,
    cur_slice: &'a mut [u32]
}

impl<'a> Slicer<'a> {
    fn new() -> Slicer<'a> {
        let mut full = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        Slicer {
            full: full,
            cur_slice: full.as_mut_slice()
        }
    }
}

#[gat]
impl<'a> LendingIterator for Slicer<'a>
{
    type Item<'next>
    where
        Self: 'next,
    =
        &'next [u32]
    ;

    fn next(&mut self) -> Option<&[u32]> {
        if self.cur_slice.len() != 0 {
            // In the actual program, this is streaming new data into the
            // buffer. This is just a minimal example.
            self.cur_slice = self.cur_slice[..self.cur_slice.len() - 1].as_mut();
            Some(self.cur_slice)
        } else {
            None
        }
    }
}

fn main() {
    let mut slicer = Slicer::new();
    while let Some(x) = slicer.next() {
        println!("{x:?}");
    }
}

I'm still getting a few separate errors, the two mains one being error[E0515]: cannot return value referencing local variable `full` and error: lifetime may not live long enough:

error[E0515]: cannot return value referencing local variable `full`
  --> src\main.rs:11:9
   |
11 | /         Slicer {
12 | |             full: full,
13 | |             cur_slice: full.as_mut_slice()
   | |                        ---- `full` is borrowed here
14 | |         }
   | |_________^ returns a value referencing data owned by the current function
error: lifetime may not live long enough
  --> src\main.rs:31:30
   |
19 | impl<'a> LendingIterator for Slicer<'a>
   |      -- lifetime `'a` defined here
...
28 |     fn next(&mut self) -> Option<&[u32]> {
   |             - let's call the lifetime of this reference `'1`
...
31 |             self.cur_slice = self.cur_slice[..self.cur_slice.len() - 1].as_mut();
   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a`

Am I barking up the wrong tree with lending iterators, or is there a way to accomplish this?