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
pub extern crate generic_array;
use std::fs::File;
use std::io::{self, ErrorKind, Read, Seek, SeekFrom};
use generic_array::typenum::{IsGreaterOrEqual, True, U1, U256};
use generic_array::{ArrayLength, GenericArray};
#[inline]
pub fn same_content_from_files(a: &mut File, b: &mut File) -> Result<bool, io::Error> {
same_content_from_files2::<U256>(a, b)
}
#[inline]
pub fn same_content_from_files2<N: ArrayLength<u8> + IsGreaterOrEqual<U1, Output = True>>(
a: &mut File,
b: &mut File,
) -> Result<bool, io::Error> {
let metadata_a = a.metadata()?;
let metadata_b = b.metadata()?;
if metadata_a.len() != metadata_b.len() {
return Ok(false);
}
a.seek(SeekFrom::Start(0))?;
b.seek(SeekFrom::Start(0))?;
same_content_from_readers2::<N>(a, b)
}
#[inline]
pub fn same_content_from_readers(a: &mut dyn Read, b: &mut dyn Read) -> Result<bool, io::Error> {
same_content_from_readers2::<U256>(a, b)
}
pub fn same_content_from_readers2<N: ArrayLength<u8> + IsGreaterOrEqual<U1, Output = True>>(
a: &mut dyn Read,
b: &mut dyn Read,
) -> Result<bool, io::Error> {
let mut buffer1: GenericArray<u8, N> = GenericArray::default();
let mut buffer2: GenericArray<u8, N> = GenericArray::default();
loop {
let ca = a.read(&mut buffer1)?;
if ca == 0 {
let cb = read_try_exact(b, &mut buffer2[..1])?;
return Ok(cb == 0);
} else {
let cb = read_try_exact(b, &mut buffer2[..ca])?;
if ca != cb {
return Ok(false);
}
if buffer1[..ca] != buffer2[..ca] {
return Ok(false);
}
}
}
}
fn read_try_exact(a: &mut dyn Read, mut buffer: &mut [u8]) -> Result<usize, io::Error> {
let mut sum = 0;
while !buffer.is_empty() {
match a.read(buffer) {
Ok(0) => break,
Ok(n) => {
buffer = &mut buffer[n..];
sum += n;
}
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
Ok(sum)
}