insitu
insitu

Reputation: 4698

Why can't I use the same parser twice in a tuple()?

I have written the following nom parser code:

use nom::character::complete::digit1;
use nom::combinator::map_res;
use nom::error::Error;
use nom::sequence::tuple;
use nom::Err;

type E<'a> = Err<Error<&'a str>>;

fn parse_double_int(input: &str) -> Option<(i32, i32)> {
    let num = map_res(digit1, |s: &str| s.parse::<i32>());
    let mut pair = tuple((num, num));
    let res: Result<_, E> = pair(&input.trim());

    match res {
        Ok((_, (a, b))) => Some((a, b)),
        Err(_) => None,
    }
}

Error:

error[E0382]: use of moved value: `num`
  --> src\lib.rs:11:32
   |
10 |     let num = map_res(digit1, |s: &str| s.parse::<i32>());
   |         --- move occurs because `num` has type `impl FnMut<(&str,)>`, which does not implement the `Copy` trait
11 |     let mut pair = tuple((num, num));
   |                           ---  ^^^ value used here after move
   |                           |
   |                           value moved here

For more information about this error, try `rustc --explain E0382`.

How can I reuse the parsers I have defined locally?

Upvotes: 1

Views: 529

Answers (2)

Stargateur
Stargateur

Reputation: 26717

map_res return a FnMut. You can't move twice a FnMut cause FnMut doesn't implement Copy, than the obvious solution would be to borrow it, but you can't cause Parser require mut and you can't have multiple mutable borrow. So the last option is to implement a Parser that either implement Copy or can be create easily:

wrap the FnMut inside a Fn closure that Implement copy:

let num = |input| map_res(digit1, |s: &str| s.parse::<i32>())(input);

Create a function:

fn num(input: &str) -> IResult<&str, i32> {
  map_res(digit1, |s: &str| s.parse::<i32>())(input)
}

Upvotes: 3

FJ_OC
FJ_OC

Reputation: 281

You are "moving the value" meaning that Rust is giving ownership of your value num and then freeing it (deleting it) when it is finished, you can try letting your function borrow the value with the &num notation, or cloning the variable if the struct implements the clone trait. There is a similar problem here I can't recreate your problem with just the snippet but hopefully this gives you enough information to find the solution!

Upvotes: 2

Related Questions