-1

I'm making a parser:

pub enum TokenContent {
    Breaks,
    Heading(usize),
    CodeFence(usize),
    Text,
    NewLine(NewLineType),
}

pub struct Token {
    pub content: TokenContent,
    pub range: Range<usize>,
}

pub struct Parser<'raw> {
    stream: TokenStream<'raw>,
}

token_stream is a data structure that can provide a sequence of tokens from the lexer:

pub struct TokenStream<'raw> {
    raw: &'raw str,                    // track the str to parse
    source: Peekable<TokenIter<'raw>>, // iterator of token
}

I want to implement a method on TokenStream named take_until to return a new Iterator from the current position of TokenStream.source to the specific stop symbol:

impl<'raw> TokenStream<'raw> {
    pub fn take_until(&self, stop: TokenContent) -> impl Iterator<Item = Token> + 'raw {
        self.source.peek_while(move |x| x.content != stop)
    }
}

Meet the error:

cannot move out of `self.source` which is behind a mutable reference
move occurs because `self.source` has type `Peekable<LexerIntoIterator<'_>>`, which does not implement the `Copy` traitrustcE0507

How to implement take_until borrow the immutable reference of TokenStream then I can call another method on TokenStream after I call take_until? Is there some Rust-native way to do it?

My peek_while.rs:

use std::{
    iter::Peekable
};

pub struct PeekWhile<I: Iterator, P> {
    iter: Peekable<I>,
    predicate: P,
}

impl<I: Iterator, P> PeekWhile<I, P> {
    pub fn new(iter: I, predicate: P) -> Self {
        Self {
            iter: iter.peekable(),
            predicate,
        }
    }
}

impl<I: Iterator, P> Iterator for PeekWhile<I, P>
where
    P: FnMut(&I::Item) -> bool,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        let x = self.iter.peek()?;
        if (self.predicate)(&x) {
            Some(self.iter.next().unwrap())
        } else {
            None
        }
    }
}

pub trait PeekWhileExt: Iterator {
    fn peek_while<P>(self, predicate: P) -> PeekWhile<Self, P>
    where
        P: FnMut(&<Self as Iterator>::Item) -> bool,
        Self: Sized,
    {
        PeekWhile::new(self, predicate)
    }
}

impl<I: Iterator> PeekWhileExt for I {}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
jctaoo
  • 89
  • 3
  • 9
  • In `TokenStream` you have `source` as `Peekable`, but `Peekable` does not implement `peek_while`. I guess it should be the `PeekWhile` type you provide? – tungli Aug 04 '21 at 15:45
  • Have you seen [this question](https://stackoverflow.com/q/28158738/11328568)? My guess is that it will be the same problem since you have implemented: `fn peek_while

    (self, predicate: P)` instead of `fn peek_while

    (&self, predicate: P)` (note the reference before `self`)

    – tungli Aug 04 '21 at 15:49
  • It's hard to answer your question because it doesn't include a [MRE]. We can't tell what crates (and their versions), types, traits, fields, etc. are present in the code. It would make it easier for us to help you if you try to reproduce your error on the [Rust Playground](https://play.rust-lang.org) if possible, otherwise in a brand new Cargo project, then [edit] your question to include the additional info. There are [Rust-specific MRE tips](//stackoverflow.com/tags/rust/info) you can use to reduce your original code for posting here. Thanks! – Shepmaster Aug 04 '21 at 16:50
  • Please [edit] your question and paste the exact and entire error that you're getting — that will help us to understand what the problem is so we can help best. Sometimes trying to interpret an error message is tricky and it's actually a different part of the error message that's important. Please use the message from running the compiler directly, not the message produced by an IDE, which might be trying to interpret the error for you. – Shepmaster Aug 04 '21 at 16:50
  • Notably, `NewLineType`, `Range` and `TokenIter` are not defined. We don't know if you created these or imported them (and if so, from what crate(s) and their versions). – Shepmaster Aug 04 '21 at 16:52

1 Answers1

-1

This consumes self:

pub trait PeekWhileExt: Iterator {
    fn peek_while<P>(self, predicate: P) -> PeekWhile<Self, P>
    where
        P: FnMut(&<Self as Iterator>::Item) -> bool,
        Self: Sized,
    {
        PeekWhile::new(self, predicate)
    }
}

Taking the reference of self should solve the problem:

fn peek_while<P>(&self, predicate: P)
...

Possible duplicate of this question

tungli
  • 351
  • 1
  • 9