1
votes

While the code below is an early prototype and not to be taken too seriously concerning how I implement protocol buffers at this stage, I fail to understand what the error message rust compilers blesses me with refers to.

src\main.rs:89:9: 89:36 error: type mismatch resolving for<'r> <[closure src\ma in.rs:75:33: 88:10] as core::ops::FnOnce<(u32, gpb::definitions::WireType, &'r collections::vec::Vec<u8>, usize)>>::Output == usize: expected bound lifetime parameter , found concrete lifetime [E0271] src\main.rs:89 gpb::decoding::read_message( source, field_handler );

Even after reading the 3 documentation chapters on lifetimes et. al. I did not come across the term "concrete lifetime" and thus have trouble figuring out what code this error relates to. The closure itself, one or multiple arguments, the return code? The passing of the closure to read_message()? ...

main.rs snippet

fn from_gpb( source : &Vec<u8>) -> TimeMessage {
    fn init_vec_u64( count : usize, init_value : u64) -> Vec<u64> {
        let mut result = Vec::<u64>::with_capacity(count);
        for i in 0..count {
            result.push(init_value);
        }
        result
    }
    let mut message_id : u32 = 0;
    let mut times_sec  = init_vec_u64(4,0u64);
    let mut times_usec = init_vec_u64(4,0u64);
    let mut max_time_index = 0;
    let mut time_index = | index | { if max_time_index < index { max_time_index = index;}};
    let mut field_handler = |tag,wire_type,source,position| -> usize {
        match (tag,wire_type) {
            (1u32,gpb::definitions::WireType::Varint) => {let (v,p) = gpb::decoding::read_varint32(source,position); message_id = v; p},
            (2u32,gpb::definitions::WireType::Fixed64) => {let (sec,p) = gpb::decoding::read_fixed64(source,position); times_sec[0] = sec; time_index(0); p},
            (3u32,gpb::definitions::WireType::Fixed64) => {let (usec,p) = gpb::decoding::read_fixed64(source,position); times_usec[0] = usec; time_index(0); p},
            (4u32,gpb::definitions::WireType::Fixed64) => {let (sec,p) = gpb::decoding::read_fixed64(source,position); times_sec[1] = sec; time_index(1);p},
            (5u32,gpb::definitions::WireType::Fixed64) => {let (usec,p) = gpb::decoding::read_fixed64(source,position); times_usec[1] = usec; time_index(1);p},
            (6u32,gpb::definitions::WireType::Fixed64) => {let (sec,p) = gpb::decoding::read_fixed64(source,position); times_sec[2] = sec; time_index(2);p},
            (7u32,gpb::definitions::WireType::Fixed64) => {let (usec,p) = gpb::decoding::read_fixed64(source,position); times_usec[2] = usec; time_index(2); p},
            (8u32,gpb::definitions::WireType::Fixed64) => {let (sec,p) = gpb::decoding::read_fixed64(source,position); times_sec[3] = sec; time_index(3); p},
            (9u32,gpb::definitions::WireType::Fixed64) => {let (usec,p) = gpb::decoding::read_fixed64(source,position); times_usec[3] = usec; time_index(3); p},
            (_,_) => panic!("Invalid field tag/wire_type combination!") // TODO: change the panic to a gpb::decoding::skip(..) call.
        }
    };
    gpb::decoding::read_message( source, field_handler );
    let mut make_times = || -> Vec<prectime::PrecTime> {
        let time_count = max_time_index+1;
        let mut times = Vec::<prectime::PrecTime>::with_capacity(time_count);
        times_sec.truncate(time_count);
        times_usec.truncate(time_count);
        for i in 0..time_count {
            times.push(prectime::PrecTime { sec : times_sec[i], usec : times_usec[i]});
        }
        times               
    };
    TimeMessage { id : message_id, times : make_times() }    
}

gpb.rs snippet

pub fn read_message<F>( source : &Vec<u8>, field_handler : F) where F: Fn(u32,super::definitions::WireType, &Vec<u8>, usize) -> usize {
    let mut cursor = 0;
    while cursor < source.len() {
        let (tag_and_wire_type, position) = read_varint32( source, cursor );
        let wt = super::definitions::wire_type_from_value( tag_and_wire_type & 0x07u32 );
        let tag = (tag_and_wire_type >> 3);
        let new_pos = field_handler(tag,wt, source,position);
        cursor = new_pos;
    }
}

Summary of what the code does:

  • define field_handler function
  • read_message(data,field_handler) -> calls n times: field_handler
  • exit scope.

As anything (the closure, the calls, the vectors, the field_handler writes in from_gpb() context,...) is defined inside from_gpb() function, I simply do not understand how the lifetime could become an issue. All information about lifetimes should be available to the compiler.

1
Slow today, guys, uh? :) I am also still clueless but I found github.com/rust-lang/rust/issues/26937 and to my not expert eyes, this looks as if it might be related. - BitTickler
Try annotating the closure like this: |tag,wire_type,source: &_ ,position| (you could also use the full type, but let's be ~~as cryptic~~ as lazy as possible.. full type is &Vec<u8>.) - bluss
Looks better but I still get: src\main.rs:89:9: 89:36 error: the trait for<'r> core::ops::Fn<(u32, gpb::definitions::WireType, &'r collections::vec::Vec<u8>, usize)> is not implemented for the type [closure src\main.rs:75:33: 88:10] [E0277] src\main.rs:89 gpb::decoding::read_message( source, field_handler ); - BitTickler

1 Answers

8
votes

First thing's first, if you want a quick answer, you should put some effort into writing a minimal, compilable example so that people don't have to guess whether or not a potential solution is going to work or not. Like this:

enum WireType {}

fn from_gpb(source: &Vec<u8>) {
    let mut field_handler = |tag, wire_type, source, position| -> usize {
        let tag: u32 = tag;
        let wire_type: WireType = wire_type;
        let source: &Vec<u8> = source;
        let position: usize = position;
        panic!();
    };
    read_message(source, field_handler);
}

fn read_message<F>(source: &Vec<u8>, field_handler: F)
where
    F: Fn(u32, WireType, &Vec<u8>, usize) -> usize,
{
    panic!();
}

The rest of this answer is based on the above which appears to replicate your problem:

error[E0631]: type mismatch in closure arguments
  --> src/lib.rs:11:5
   |
4  |     let mut field_handler = |tag, wire_type, source, position| -> usize {
   |                             ------------------------------------------- found signature of `fn(u32, WireType, &std::vec::Vec<u8>, usize) -> _`
...
11 |     read_message(source, field_handler);
   |     ^^^^^^^^^^^^ expected signature of `for<'r> fn(u32, WireType, &'r std::vec::Vec<u8>, usize) -> _`
   |
note: required by `read_message`
  --> src/lib.rs:14:1
   |
14 | / fn read_message<F>(source: &Vec<u8>, field_handler: F)
15 | | where
16 | |     F: Fn(u32, WireType, &Vec<u8>, usize) -> usize,
17 | | {
18 | |     panic!();
19 | | }
   | |_^

error[E0271]: type mismatch resolving `for<'r> <[closure@src/lib.rs:4:29: 10:6] as std::ops::FnOnce<(u32, WireType, &'r std::vec::Vec<u8>, usize)>>::Output == usize`
  --> src/lib.rs:11:5
   |
11 |     read_message(source, field_handler);
   |     ^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
   |
note: required by `read_message`
  --> src/lib.rs:14:1
   |
14 | / fn read_message<F>(source: &Vec<u8>, field_handler: F)
15 | | where
16 | |     F: Fn(u32, WireType, &Vec<u8>, usize) -> usize,
17 | | {
18 | |     panic!();
19 | | }
   | |_^

The simplest thing to do is to allow the compiler to properly infer the closure type:

fn from_gpb_closure_inference(source: &Vec<u8>) {
    read_message(source, |tag, wire_type, source, position| -> usize {
        let tag: u32 = tag;
        let wire_type: WireType = wire_type;
        let source: &Vec<u8> = source;
        let position: usize = position;
        panic!();
    });
}

Closure inference only really works properly when the closure is provided directly as an argument to a function. In theory, the two should be equivalent, but they aren't.

The other thing you can do is kind-of trick the compiler into doing the inference without actually using the closure:

fn constrain_handler<F>(f: F) -> F
where
    F: Fn(u32, WireType, &Vec<u8>, usize) -> usize,
{
    f
}

fn from_gpb_constrain(source: &Vec<u8>) {
    let mut field_handler = constrain_handler(|tag, wire_type, source, position| -> usize {
        let tag: u32 = tag;
        let wire_type: WireType = wire_type;
        let source: &Vec<u8> = source;
        let position: usize = position;
        panic!();
    });
    read_message(source, field_handler);
}

In this case, the constrain_handler function is just getting the compiler to nail down the type of the closure, allowing it to be used (or not) later on.