161 lines
4.3 KiB
Rust
161 lines
4.3 KiB
Rust
|
#[cfg(test)]
|
||
|
mod operationtest;
|
||
|
|
||
|
use std::fs::{File, OpenOptions};
|
||
|
use std::io::{Read, Write};
|
||
|
|
||
|
pub trait XORWorker {
|
||
|
fn work(input: [&str; 2], output: &str) -> Result<(), String>;
|
||
|
}
|
||
|
|
||
|
pub struct Worker;
|
||
|
|
||
|
fn open(name: &str, writable: bool) -> Result<File, String> {
|
||
|
let f = OpenOptions::new()
|
||
|
.read(!writable)
|
||
|
.write(writable)
|
||
|
.create(writable)
|
||
|
.open(name);
|
||
|
match f {
|
||
|
Ok(file) => Ok(file),
|
||
|
Err(e) => Err(format!(
|
||
|
"Could not open file \"{}\" for {}:\n{}",
|
||
|
name,
|
||
|
if writable {"writing"} else {"reading"},
|
||
|
e
|
||
|
)),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const BUF_SIZE: usize = (1 << 16);
|
||
|
|
||
|
struct ReadWrapper<'a, T>
|
||
|
where T: Read {
|
||
|
stream: T,
|
||
|
name: &'a str,
|
||
|
}
|
||
|
|
||
|
impl<'a, T> ReadWrapper<'a, T>
|
||
|
where T: Read {
|
||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize, String> {
|
||
|
match self.stream.read(buf) {
|
||
|
Ok(size) => Ok(size),
|
||
|
Err(e) => Err(format!(
|
||
|
"Error reading \"{}\":\n{}",
|
||
|
self.name,
|
||
|
e
|
||
|
)),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct WriteWrapper<'a, T>
|
||
|
where T: Write {
|
||
|
stream: T,
|
||
|
name: &'a str,
|
||
|
}
|
||
|
|
||
|
impl<'a, T> WriteWrapper<'a, T>
|
||
|
where T: Write {
|
||
|
fn write_all(&mut self, buf: &[u8]) -> Result<(), String> {
|
||
|
match self.stream.write_all(buf) {
|
||
|
Ok(()) => Ok(()),
|
||
|
Err(e) => Err(format!(
|
||
|
"Error reading \"{}\":\n{}",
|
||
|
self.name,
|
||
|
e
|
||
|
)),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn xor_into(dest: &mut [u8], src: &[u8]) {
|
||
|
for i in 0..dest.len() {
|
||
|
dest[i] ^= src[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn operate<I1, I2, O>(
|
||
|
mut in1: ReadWrapper<I1>,
|
||
|
mut in2: ReadWrapper<I2>,
|
||
|
mut out: WriteWrapper<O>
|
||
|
) -> Result<(), String>
|
||
|
where I1: Read,
|
||
|
I2: Read,
|
||
|
O: Write
|
||
|
{
|
||
|
let mut in1_buffer = [0u8; BUF_SIZE]; // also used for output
|
||
|
let mut in2_buffer = [0u8; BUF_SIZE];
|
||
|
|
||
|
let mut in1_remaining = &mut[][..]; // empty at begin
|
||
|
let mut in2_remaining = &[][..];
|
||
|
|
||
|
let mut in2_finished = false;
|
||
|
|
||
|
loop {
|
||
|
let l1 = in1_remaining.len();
|
||
|
let l2 = in2_remaining.len();
|
||
|
match (in2_finished, l1, l2) {
|
||
|
(_, 0, _) => {
|
||
|
// in1 buffer is empty, read
|
||
|
match in1.read(&mut in1_buffer[..])? {
|
||
|
0 => {
|
||
|
// nothing more on input1, finished
|
||
|
return Ok(());
|
||
|
},
|
||
|
size => {
|
||
|
// take data
|
||
|
in1_remaining = &mut in1_buffer[0..size];
|
||
|
},
|
||
|
};
|
||
|
},
|
||
|
(false, other, 0) => {
|
||
|
// in2 buffer is empty, read
|
||
|
let toread = if other == 0 {BUF_SIZE} else {other};
|
||
|
in2_remaining = &[][..];
|
||
|
match in2.read(&mut in2_buffer[0..toread])? {
|
||
|
0 => {
|
||
|
// nothing more on input2
|
||
|
in2_finished = true;
|
||
|
},
|
||
|
size => {
|
||
|
in2_remaining = &in2_buffer[0..size];
|
||
|
},
|
||
|
};
|
||
|
},
|
||
|
(true, _, 0) => {
|
||
|
// Data from i1 must be streamed to output
|
||
|
out.write_all(&in1_remaining)?;
|
||
|
in1_remaining = &mut in1_remaining[0..0];
|
||
|
},
|
||
|
(_, i1size, i2size) => {
|
||
|
// There is data on both sides, process it
|
||
|
let amount = if i1size < i2size {i1size} else {i2size};
|
||
|
xor_into(&mut in1_remaining[0..amount], &in2_remaining[0..amount]);
|
||
|
out.write_all(&in1_remaining[0..amount])?;
|
||
|
in1_remaining = &mut in1_remaining[amount..];
|
||
|
in2_remaining = &in2_remaining[amount..];
|
||
|
},
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl XORWorker for Worker {
|
||
|
fn work(input: [&str; 2], output: &str) -> Result<(), String> {
|
||
|
let in1 = ReadWrapper {
|
||
|
stream: open(input[0], false)?,
|
||
|
name: input[0],
|
||
|
};
|
||
|
let in2 = ReadWrapper {
|
||
|
stream: open(input[1], false)?,
|
||
|
name: input[1],
|
||
|
};
|
||
|
let out = WriteWrapper {
|
||
|
stream: open(output, true)?,
|
||
|
name: output,
|
||
|
};
|
||
|
|
||
|
operate(in1, in2, out)
|
||
|
}
|
||
|
}
|