librsyncr 0.1.1

librsyncr is a Rust library to calculate and apply deltas between two files without having access to both files on the same system.
Documentation

extern crate gumdrop;
extern crate librsyncr as rsync;

use std::fs::File;
use std::io::{self, BufReader, BufWriter};

use gumdrop::Options;

#[derive(Debug, Options)]
struct CliOptions {
    help: bool,

    #[options(command)]
    command: Option<Command>,
}

#[derive(Debug, Options)]
enum Command {
    #[options(help = "Creates a signature file")]
    Signature(SigOptions),
    #[options(help = "Creates a delta file")]
    Delta(DeltaOptions),
    #[options(help = "Applies a delta file")]
    Patch(PatchOptions),
}

#[derive(Debug, Options)]
struct SigOptions {
    #[options(free)]
    old_file: String,

    #[options(free)]
    signature_file: String,

    #[options(help = "The bytes per block")]
    block_size: u32,

    #[options(short = "S",
        help = "Set to smaller than the strong sum size (32 for Blake2) to truncate it")]
    sum_size: u32,
}

#[derive(Debug, Options)]
struct DeltaOptions {
    #[options(free)]
    signature_file: String,

    #[options(free)]
    new_file: String,

    #[options(free)]
    delta_file: String,
}

#[derive(Debug, Options)]
struct PatchOptions {
    #[options(free)]
    old_file: String,

    #[options(free)]
    delta_file: String,

    #[options(free)]
    new_file: String,
}

fn main() -> Result<(), io::Error> {
    let opts = CliOptions::parse_args_default_or_exit();

    match opts.command {
        Some(Command::Signature(sig_opts)) => {
            let old_file_reader = BufReader::new(File::open(sig_opts.old_file)?);
            let sig_file_writer = BufWriter::new(File::create(sig_opts.signature_file)?);
            rsync::calculate_signature(old_file_reader, sig_file_writer)?;
        },
        Some(Command::Delta(delta_opts)) => {
            let sig_file_reader = BufReader::new(File::open(delta_opts.signature_file)?);
            let new_file_reader = BufReader::new(File::open(delta_opts.new_file)?);
            let delta_file_writer = BufWriter::new(File::create(delta_opts.delta_file)?);
            rsync::calculate_delta(sig_file_reader, new_file_reader, delta_file_writer).unwrap();
            // TODO: remove unwraps
        },
        Some(Command::Patch(patch_opts)) => {
            let old_file_reader = BufReader::new(File::open(patch_opts.old_file)?);
            let delta_file_reader = BufReader::new(File::open(patch_opts.delta_file)?);
            let new_file_writer = BufWriter::new(File::create(patch_opts.new_file)?);
            rsync::apply_delta(old_file_reader, delta_file_reader, new_file_writer).unwrap();
        },
        _ => println!("{}", CliOptions::usage()),
    }
    Ok(())
}