Pablo
Pablo

Reputation: 889

Type mismatches while calling a Boxed function inside a struct

I tried to sketch a generic way of running “problems” represented according to the struct Problem below. These structs include test input/output and a solver function. My goal is to run these problems either by interacting with standard I/O, or by some tester function that verifies the validity of the solver against the given test_input/test_output. The sketch here only includes a tester function.

When I try to compile it, I get type mismatches:

problem.rs:43:22: 43:27 error: mismatched types:
 expected `R`,
    found `std::io::cursor::Cursor<&[u8]>`
(expected type parameter,
    found struct `std::io::cursor::Cursor`) [E0308]
problem.rs:43     (problem.solver)(input, &mut output);
                                   ^~~~~
problem.rs:43:22: 43:27 help: run `rustc --explain E0308` to see a detailed explanation
problem.rs:43:29: 43:40 error: mismatched types:
 expected `&mut W`,
    found `&mut std::io::cursor::Cursor<collections::vec::Vec<u8>>`
(expected type parameter,
    found struct `std::io::cursor::Cursor`) [E0308]
problem.rs:43     (problem.solver)(input, &mut output);
                                          ^~~~~~~~~~~
problem.rs:43:29: 43:40 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to 2 previous errors

I was expecting the compiler to take Cursor<&[u8]> as a BufReader, and Cursor<Vec<u8>> as a Writer, but it didn’t work. I don’t know what to make of the expectation for an R or a W.

I tried to run a similar tester function by calling directly the solver, without involving a Problem at all, and it worked; so I suppose these errors might have something to do with the way I call (problem.solver)(input, &mut output). Other than this, I have no clue. Can somebody please give me a hint of what’s happening here?

use std::io::prelude::*;
use problems::Problem;

mod problems {
    use std::io::prelude::*;

    pub struct Problem<'a, R, W>
        where R: BufRead, W: Write
    {
        test_input: &'a str,
        test_output: &'a str,
        solver: Box<fn(R, &mut W)>,
    }

    mod a_problem {
        use std::io::prelude::*;
        use super::Problem;

        pub fn getProblem<'a, R, W>() -> Problem<'a, R, W>
            where R: BufRead, W: Write
        {
            Problem {
                test_input: unimplemented!(),
                test_output: unimplemented!(),
                solver: Box::new(solver),
            }
        }

        fn solver<R, W>(input: R, output: &mut W)
            where R: BufRead, W: Write
        {
            unimplemented!();
        }
    }
}

fn test_solver<R, W>(problem: Problem<R, W>)
    where R: BufRead, W: Write
{
    let input = std::io::Cursor::new(problem.test_input.as_bytes());
    let mut output = std::io::Cursor::new(Vec::<u8>::new());

    (problem.solver)(input, &mut output);
    assert_eq!(problem.test_output.as_bytes(), &*output.into_inner());
}

fn main() {
    let problem = problems::a_problem::getProblem();
    test_solver(problem);
}

Upvotes: 1

Views: 471

Answers (1)

Francis Gagn&#233;
Francis Gagn&#233;

Reputation: 65692

The way you defined the Problem struct means that R and W are fixed at the time the Problem is instantiated. In test_solver, you allow the caller to specify any R and any W they want, but then you try to pass specific Cursor types to (problem.solver) instead.

You can fix this in two ways:

1) Don't define test_solver as a generic function. Note that you wouldn't be to call (problem.solver) multiple times with different types for R and W.

fn test_solver<'a>(problem: Problem<'a, std::io::Cursor<&'a [u8]>, std::io::Cursor<Vec<u8>>>)
{
    let input = std::io::Cursor::new(problem.test_input.as_bytes());
    let mut output = std::io::Cursor::new(Vec::<u8>::new());

    (problem.solver)(input, &mut output);
    assert_eq!(problem.test_output.as_bytes(), &*output.into_inner());
}

2) Don't define the solver field as generic. Have the function take trait references instead.

use std::io::prelude::*;
use problems::Problem;

mod problems {
    use std::io::prelude::*;

    pub struct Problem<'a>
    {
        pub test_input: &'a str,
        pub test_output: &'a str,
        pub solver: Box<fn(&mut BufRead, &mut Write)>,
    }

    pub mod a_problem {
        use std::io::prelude::*;
        use super::Problem;

        pub fn getProblem<'a>() -> Problem<'a>
        {
            Problem {
                test_input: unimplemented!(),
                test_output: unimplemented!(),
                solver: Box::new(solver),
            }
        }

        fn solver(input: &mut BufRead, output: &mut Write)
        {
            unimplemented!();
        }
    }
}

fn test_solver(problem: Problem)
{
    let mut input = std::io::Cursor::new(problem.test_input.as_bytes());
    let mut output = std::io::Cursor::new(Vec::<u8>::new());

    (problem.solver)(&mut input, &mut output);
    assert_eq!(problem.test_output.as_bytes(), &*output.into_inner());
}

fn main() {
    let problem = problems::a_problem::getProblem();
    test_solver(problem);
}

Upvotes: 4

Related Questions