1use std::io::{Cursor, Read, Seek};
2
3pub struct Csv<R> {
4 csv_reader: csv::Reader<R>,
5}
6
7impl<R: Read + Seek + Send> Csv<R> {
8 #[cfg_attr(
11 feature = "rayon-threads",
12 doc = r##"
13```
14use csv_diff::{csv_diff::CsvByteDiffLocal, csv::Csv};
15# fn main() -> Result<(), Box<dyn std::error::Error>> {
16let csv_data_left = "id,name,kind\n\
17 1,lemon,fruit\n\
18 2,strawberry,fruit";
19let csv_data_right = "id,name,kind\n\
20 1,lemon,fruit\n\
21 2,strawberry,fruit";
22
23let csv_byte_diff = CsvByteDiffLocal::new()?;
24
25let mut diff_byte_records = csv_byte_diff.diff(
26 // bytes are not `Seek`able by default, but trait `CsvReadSeek` makes them seekable
27 Csv::with_reader_seek(csv_data_left.as_bytes()),
28 Csv::with_reader_seek(csv_data_right.as_bytes()),
29)?;
30
31let num_of_rows_different = diff_byte_records.as_slice().len();
32
33assert_eq!(
34 num_of_rows_different,
35 0
36);
37Ok(())
38# }
39```
40 "##
41 )]
42 pub fn with_reader_seek<RSeek: CsvReadSeek<R>>(reader: RSeek) -> Self {
43 Self {
44 csv_reader: csv::Reader::from_reader(reader.into_read_seek()),
45 }
46 }
47}
48
49impl<R: Read> Csv<R> {
50 pub fn with_reader(reader: R) -> Self {
51 Self {
52 csv_reader: csv::Reader::from_reader(reader),
53 }
54 }
55}
56
57impl<R> Csv<R> {
58 pub fn into_csv_reader(self) -> csv::Reader<R> {
59 self.csv_reader
60 }
61
62 pub(crate) fn csv_reader_mut(&mut self) -> &mut csv::Reader<R> {
63 &mut self.csv_reader
64 }
65}
66
67impl<R> From<csv::Reader<R>> for Csv<R> {
68 fn from(rdr: csv::Reader<R>) -> Self {
69 Self { csv_reader: rdr }
70 }
71}
72
73pub trait CsvReadSeek<R>
75where
76 R: Read + Seek + Send,
77{
78 fn into_read_seek(self) -> R;
80}
81
82impl<T> CsvReadSeek<Cursor<T>> for T
83where
84 T: AsRef<[u8]> + Send,
85{
86 fn into_read_seek(self) -> Cursor<T> {
87 Cursor::new(self)
88 }
89}
90
91impl<R> CsvReadSeek<R> for R
92where
93 R: Read + Seek + Send,
94{
95 fn into_read_seek(self) -> R {
96 self
97 }
98}
99
100pub trait CsvReaderBuilderExt<R: Read + Seek + Send> {
101 fn from_reader_seek<RSeek: CsvReadSeek<R>>(&self, reader: RSeek) -> csv::Reader<R>;
102}
103
104impl<R: Read + Seek + Send> CsvReaderBuilderExt<R> for csv::ReaderBuilder {
105 fn from_reader_seek<RSeek: CsvReadSeek<R>>(&self, reader: RSeek) -> csv::Reader<R> {
106 self.from_reader(reader.into_read_seek())
107 }
108}