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