How to make this simple wrapper for csv::Reader & serde::Deserialize?

Trying to make a shorthand function to replace some lines of code.

Instead of this:

let csvr = csv::Reader::from_path(my_path)?;
for item in csvr.deserialize() {
    let item = item?;
    // useful job
}

I want to remove the first lines (and imports) into one func placed in utility module:

pub fn read_from_file<'de, D: Deserialize<'de>>(path: &str) -> Result<DeserializeRecordsIter<'de, File, D>, Box<dyn Error>> {
	let csvr: Reader<File> = csv::Reader::from_path(path)?;
	Ok(csvr.deserialize())
}

for item: MyType in read_from_file(&my_path)? {
    let item = item?;
    // useful job
}

(It doesn't save much code, but saves me from importing pieces of serde and csv and adding them to every Cargo.toml, which is annoying.)

I get a new sort of error message (did I miss something in nightly builds?)

error[E0277]: the trait bound `for<'de> D: serde::Deserialize<'de>` is not satisfied
    --> src/main.rs:9:10
     |
9    |     Ok(csvr.deserialize())
     |             ^^^^^^^^^^^ the trait `for<'de> serde::Deserialize<'de>` is not implemented for `D`
     |
     = note: required for `D` to implement `DeserializeOwned`
note: required by a bound in `Reader::<R>::deserialize`
    --> /home/culebron/.cargo/registry/src/github.com-1ecc6299db9ec823/csv-1.2.1/src/reader.rs:1050:12
     |
1050 |         D: DeserializeOwned,
     |            ^^^^^^^^^^^^^^^^ required by this bound in `Reader::<R>::deserialize`
help: consider further restricting this bound
     |
7    | pub fn read_from_file<'de, D: Deserialize<'de> + for<'de> serde::Deserialize<'de>>(path: &str) -> Result<DeserializeRecordsIter<'de, File, D>, Box<dyn Error>> {
     |                                                ++++++++++++++++++++++++++++++++++

When I add this for<'de> serde... etc., I get this same message again and again.

The for<'de> Deserialize<'de> HRTB should be the only bound; there's no need to say that "this type must implement Deserialize for all lifetimes and this one specific lifetime". It's at best useless, but I'm not sure whether it isn't in fact incorrect.

You are also trying to return an iterator that borrows the reader; that's impossible because the reader is a local variable. You should have used .into_deserialize() instead.

Here's a correct and more idiomatic version:

pub fn read_from_file<D, P>(path: P) -> Result<impl Iterator<Item = Result<D, CsvError>>, CsvError>
where
    D: for<'de> Deserialize<'de>,
    P: AsRef<Path>,
{
	Reader::from_path(path).map(Reader::into_deserialize)
}
1 Like

I didn't even reach that secret level. LOL. Thank you very much!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.