I wrote some code to parse CSV files, and now I'd like to add an abstraction to prevent having duplicated code the CSV reading all over my crate. However, this is causing issues:
use csv::{ReaderBuilder, StringRecord};
use serde::Deserialize;
fn process<'a>(read: &mut Chunk<'a>) {
read_csv::<Raw>(read, HEADER)
}
pub fn read_csv<'a, 'de, T>(chunk: &mut Chunk<'a>, header: &[&str])
where
T: Deserialize<'de>,
{
let mut reader = ReaderBuilder::new().from_reader(chunk.0);
let header = StringRecord::from(header);
let mut buf = StringRecord::new();
loop {
let _ = reader.read_record(&mut buf).unwrap();
let _ = buf.deserialize::<T>(Some(&header));
}
}
#[derive(Debug, Deserialize)]
struct Raw<'a> {
name: &'a str,
}
pub struct Chunk<'a>(&'a [u8]);
const HEADER: &[&str] = &["foo", "bar"];
(Playground.)
Which results in these errors:
error[E0502]: cannot borrow `buf` as mutable because it is also borrowed as immutable
--> src/lib.rs:16:36
|
8 | pub fn read_csv<'a, 'de, T>(chunk: &mut Chunk<'a>, header: &[&str])
| --- lifetime `'de` defined here
...
16 | let _ = reader.read_record(&mut buf).unwrap();
| ^^^^^^^^ mutable borrow occurs here
17 | let _ = buf.deserialize::<T>(Some(&header));
| -----------------------------------
| |
| immutable borrow occurs here
| argument requires that `buf` is borrowed for `'de`
error[E0597]: `buf` does not live long enough
--> src/lib.rs:17:17
|
8 | pub fn read_csv<'a, 'de, T>(chunk: &mut Chunk<'a>, header: &[&str])
| --- lifetime `'de` defined here
...
17 | let _ = buf.deserialize::<T>(Some(&header));
| ^^^--------------------------------
| |
| borrowed value does not live long enough
| argument requires that `buf` is borrowed for `'de`
18 | }
19 | }
| - `buf` dropped here while still borrowed
error[E0597]: `header` does not live long enough
--> src/lib.rs:17:43
|
8 | pub fn read_csv<'a, 'de, T>(chunk: &mut Chunk<'a>, header: &[&str])
| --- lifetime `'de` defined here
...
17 | let _ = buf.deserialize::<T>(Some(&header));
| --------------------------^^^^^^^--
| | |
| | borrowed value does not live long enough
| argument requires that `header` is borrowed for `'de`
18 | }
19 | }
| - `header` dropped here while still borrowed
I find this mightily confusing because (a) it doesn't seem like the mutable borrow and the immutable borrow for buf have overlapping liveness and (b) raw doesn't outlive buf and (c) it seems like buf and header have the same lifetime.
How can I convince rustc that this code is okay? I already tried to change T to be for<'de> Deserialize<'de>, but that gets me into trouble at the callsite (that is, in process()).