<commit_before>#![crate_id = "hashsum#1.0.0"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 * (c) Vsevolod Velichko <torkvemada@sorokdva.net>
 * (c) Gil Cottle <gcottle@redtown.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]

extern crate regex;

extern crate crypto = "rust-crypto";
extern crate getopts;

use std::io::fs::File;
use std::io::stdio::stdin_raw;
use std::io::BufferedReader;
use std::os;
use regex::Regex;
use crypto::digest::Digest;
use crypto::md5::Md5;
use crypto::sha1::Sha1;
use crypto::sha2::{Sha224, Sha256, Sha384, Sha512};

#[path = "../common/util.rs"]
mod util;

static NAME: &'static str = "hashsum";
static VERSION: &'static str = "1.0.0";

fn is_custom_binary(program: &str) -> bool {
    match program {
        "md5sum" | "sha1sum"
            | "sha224sum" | "sha256sum"
            | "sha384sum" | "sha512sum" => true,
        _ => false
    }
}

fn get_algo_opts(program: &str) -> Vec<getopts::OptGroup> {
    if is_custom_binary(program) {
        Vec::new()
    } else {
        vec!(
            getopts::optflag("", "md5", "work with MD5"),
            getopts::optflag("", "sha1", "work with SHA1"),
            getopts::optflag("", "sha224", "work with SHA224"),
            getopts::optflag("", "sha256", "work with SHA256"),
            getopts::optflag("", "sha384", "work with SHA384"),
            getopts::optflag("", "sha512", "work with SHA512")
        )
    }
}

fn detect_algo(program: &str, matches: &getopts::Matches) -> (&str, Box<Digest>) {
    let mut alg: Option<Box<Digest>> = None;
    let mut name: &'static str = "";
    match program {
        "md5sum" => ("MD5", box Md5::new() as Box<Digest>),
        "sha1sum" => ("SHA1", box Sha1::new() as Box<Digest>),
        "sha224sum" => ("SHA224", box Sha224::new() as Box<Digest>),
        "sha256sum" => ("SHA256", box Sha256::new() as Box<Digest>),
        "sha384sum" => ("SHA384", box Sha384::new() as Box<Digest>),
        "sha512sum" => ("SHA512", box Sha512::new() as Box<Digest>),
        _ => {
            {
                let set_or_crash = |n: &'static str, val: Box<Digest>| -> () {
                    if alg.is_some() { crash!(1, "You cannot combine multiple hash algorithms!") };
                    name = n;
                    alg = Some(val);
                };
                if matches.opt_present("md5") { set_or_crash("MD5", box Md5::new()) };
                if matches.opt_present("sha1") { set_or_crash("SHA1", box Sha1::new()) };
                if matches.opt_present("sha224") { set_or_crash("SHA224", box Sha224::new()) };
                if matches.opt_present("sha256") { set_or_crash("SHA256", box Sha256::new()) };
                if matches.opt_present("sha384") { set_or_crash("SHA384", box Sha384::new()) };
                if matches.opt_present("sha512") { set_or_crash("SHA512", box Sha512::new()) };
            }
            if alg.is_none() { crash!(1, "You must specify hash algorithm!") };
            (name, alg.unwrap())
        }
    }
}

#[allow(dead_code)]
fn main() { os::set_exit_status(uumain(os::args())); }

pub fn uumain(args: Vec<String>) -> int {
    let program = args.get(0).clone();
    let binary = Path::new(program.as_slice());
    let binary_name = binary.filename_str().unwrap();

    let mut opts: Vec<getopts::OptGroup> = vec!(
        getopts::optflag("b", "binary", "read in binary mode"),
        getopts::optflag("c", "check", "read hashsums from the FILEs and check them"),
        getopts::optflag("", "tag", "create a BSD-style checksum"),
        getopts::optflag("t", "text", "read in text mode (default)"),
        getopts::optflag("q", "quiet", "don't print OK for each successfully verified file"),
        getopts::optflag("s", "status", "don't output anything, status code shows success"),
        getopts::optflag("", "strict", "exit non-zero for improperly formatted checksum lines"),
        getopts::optflag("w", "warn", "warn about improperly formatted checksum lines"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    );

    opts.push_all_move(get_algo_opts(binary_name.as_slice()));

    let matches = match getopts::getopts(args.tail(), opts.as_slice()) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f)
    };

    if matches.opt_present("help") {
        usage(program.as_slice(), binary_name.as_slice(), opts.as_slice());
    } else if matches.opt_present("version") {
        version();
    } else {
        let (name, algo) = detect_algo(binary_name.as_slice(), &matches);

        let binary = matches.opt_present("binary");
        let check = matches.opt_present("check");
        let tag = matches.opt_present("tag");
        let status = matches.opt_present("status");
        let quiet = matches.opt_present("quiet") || status;
        let strict = matches.opt_present("strict");
        let warn = matches.opt_present("warn") && !status;
        let files = if matches.free.is_empty() {
            vec!("-".to_string())
        } else {
            matches.free
        };
        match hashsum(name, algo, files, binary, check, tag, status, quiet, strict, warn) {
            Ok(()) => return 0,
            Err(e) => return e
        }
    }

    0
}

fn version() {
    println!("{} v{}", NAME, VERSION);
}

fn usage(program: &str, binary_name: &str, opts: &[getopts::OptGroup]) {
    version();
    println!("");
    println!("Usage:");
    if is_custom_binary(binary_name) {
        println!("  {} [OPTION]... [FILE]...", program);
    } else {
        println!("  {} {{--md5|--sha1|--sha224|--sha256|--sha384|--sha512}} [OPTION]... [FILE]...", program);
    }
    println!("");
    print!("{}", getopts::usage("Compute and check message digests.", opts));
}

fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary: bool, check: bool, tag: bool, status: bool, quiet: bool, strict: bool, warn: bool) -> Result<(), int> {
    let mut bad_format = 0;
    let mut failed = 0;
    let binary_marker = if binary {
        "*"
    } else {
        " "
    };
    for filename in files.iter() {
        let filename: &str = filename.as_slice();
        let mut file = BufferedReader::new(
            if filename == "-" {
                box stdin_raw() as Box<Reader>
            } else {
                box safe_unwrap!(File::open(&Path::new(filename))) as Box<Reader>
            }
        );
        if check {

            // Set up Regexs to support file
            let bytes = digest.output_bits() / 4;
            let gnu_re = safe_unwrap!(Regex::new(format!(
                        r"^(?P<digest>[a-fA-F0-9]{{{}}}) (?P<binary>[ \*])(?P<fileName>.*)",
                        bytes
                        ).as_slice()));
            let bsd_re = safe_unwrap!(Regex::new(format!(
                        r"^{algorithm} \((?P<fileName>.*)\) = (?P<digest>[a-fA-F0-9]{{{digest_size}}})",
                        algorithm = algoname,
                        digest_size = bytes
                        ).as_slice()));

            let mut buffer = file;
            for (i, line) in buffer.lines().enumerate() {
                let line = safe_unwrap!(line);
                let (ck_filename, sum, binary_check) = match gnu_re.captures(line.as_slice()) {
                    Some(caps) => (caps.name("fileName"), caps.name("digest").to_ascii().to_lower(), caps.name("binary") == "*"),
                    None => match bsd_re.captures(line.as_slice()) {
                        Some(caps) => (caps.name("fileName"), caps.name("digest").to_ascii().to_lower(), true),
                        None => {
                            bad_format += 1;
                            if strict {
                                return Err(1);
                            }
                            if warn {
                                show_warning!("{}: {}: improperly formatted {} checksum line", filename, i + 1, algoname);
                            }
                            continue;
                        }
                    }
                };
                let real_sum = calc_sum(&mut digest, &mut safe_unwrap!(File::open(&Path::new(ck_filename))), binary_check)
                    .as_slice().to_ascii().to_lower();
                if sum.as_slice() == real_sum.as_slice() {
                    if !quiet {
                        println!("{}: OK", ck_filename);
                    }
                } else {
                    if !status {
                        println!("{}: FAILED", ck_filename);
                    }
                    failed += 1;
                }
            }
        } else {
            let sum = calc_sum(&mut digest, &mut file, binary);
            if tag {
                println!("{} ({}) = {}", algoname, filename, sum);
            } else {
                println!("{} {}{}", sum, binary_marker, filename);
            }
        }
    }
    if !status {
        if bad_format == 1 {
            show_warning!("{} line is improperly formatted", bad_format);
        } else if bad_format > 1 {
            show_warning!("{} lines are improperly formatted", bad_format);
        }
        if failed > 0 {
            show_warning!("{} computed checksum did NOT match", failed);
        }
    }

    Ok(())
}

fn calc_sum(digest: &mut Box<Digest>, file: &mut Reader, binary: bool) -> String {
    let data =
        if binary {
            (safe_unwrap!(file.read_to_end()))
        } else {
            (safe_unwrap!(file.read_to_str())).into_bytes()
        };
    digest.reset();
    digest.input(data.as_slice());
    digest.result_str()
}

<commit_msg>fix comment<commit_after>#![crate_id = "hashsum#1.0.0"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 * (c) Vsevolod Velichko <torkvemada@sorokdva.net>
 * (c) Gil Cottle <gcottle@redtown.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]

extern crate regex;

extern crate crypto = "rust-crypto";
extern crate getopts;

use std::io::fs::File;
use std::io::stdio::stdin_raw;
use std::io::BufferedReader;
use std::os;
use regex::Regex;
use crypto::digest::Digest;
use crypto::md5::Md5;
use crypto::sha1::Sha1;
use crypto::sha2::{Sha224, Sha256, Sha384, Sha512};

#[path = "../common/util.rs"]
mod util;

static NAME: &'static str = "hashsum";
static VERSION: &'static str = "1.0.0";

fn is_custom_binary(program: &str) -> bool {
    match program {
        "md5sum" | "sha1sum"
            | "sha224sum" | "sha256sum"
            | "sha384sum" | "sha512sum" => true,
        _ => false
    }
}

fn get_algo_opts(program: &str) -> Vec<getopts::OptGroup> {
    if is_custom_binary(program) {
        Vec::new()
    } else {
        vec!(
            getopts::optflag("", "md5", "work with MD5"),
            getopts::optflag("", "sha1", "work with SHA1"),
            getopts::optflag("", "sha224", "work with SHA224"),
            getopts::optflag("", "sha256", "work with SHA256"),
            getopts::optflag("", "sha384", "work with SHA384"),
            getopts::optflag("", "sha512", "work with SHA512")
        )
    }
}

fn detect_algo(program: &str, matches: &getopts::Matches) -> (&str, Box<Digest>) {
    let mut alg: Option<Box<Digest>> = None;
    let mut name: &'static str = "";
    match program {
        "md5sum" => ("MD5", box Md5::new() as Box<Digest>),
        "sha1sum" => ("SHA1", box Sha1::new() as Box<Digest>),
        "sha224sum" => ("SHA224", box Sha224::new() as Box<Digest>),
        "sha256sum" => ("SHA256", box Sha256::new() as Box<Digest>),
        "sha384sum" => ("SHA384", box Sha384::new() as Box<Digest>),
        "sha512sum" => ("SHA512", box Sha512::new() as Box<Digest>),
        _ => {
            {
                let set_or_crash = |n: &'static str, val: Box<Digest>| -> () {
                    if alg.is_some() { crash!(1, "You cannot combine multiple hash algorithms!") };
                    name = n;
                    alg = Some(val);
                };
                if matches.opt_present("md5") { set_or_crash("MD5", box Md5::new()) };
                if matches.opt_present("sha1") { set_or_crash("SHA1", box Sha1::new()) };
                if matches.opt_present("sha224") { set_or_crash("SHA224", box Sha224::new()) };
                if matches.opt_present("sha256") { set_or_crash("SHA256", box Sha256::new()) };
                if matches.opt_present("sha384") { set_or_crash("SHA384", box Sha384::new()) };
                if matches.opt_present("sha512") { set_or_crash("SHA512", box Sha512::new()) };
            }
            if alg.is_none() { crash!(1, "You must specify hash algorithm!") };
            (name, alg.unwrap())
        }
    }
}

#[allow(dead_code)]
fn main() { os::set_exit_status(uumain(os::args())); }

pub fn uumain(args: Vec<String>) -> int {
    let program = args.get(0).clone();
    let binary = Path::new(program.as_slice());
    let binary_name = binary.filename_str().unwrap();

    let mut opts: Vec<getopts::OptGroup> = vec!(
        getopts::optflag("b", "binary", "read in binary mode"),
        getopts::optflag("c", "check", "read hashsums from the FILEs and check them"),
        getopts::optflag("", "tag", "create a BSD-style checksum"),
        getopts::optflag("t", "text", "read in text mode (default)"),
        getopts::optflag("q", "quiet", "don't print OK for each successfully verified file"),
        getopts::optflag("s", "status", "don't output anything, status code shows success"),
        getopts::optflag("", "strict", "exit non-zero for improperly formatted checksum lines"),
        getopts::optflag("w", "warn", "warn about improperly formatted checksum lines"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    );

    opts.push_all_move(get_algo_opts(binary_name.as_slice()));

    let matches = match getopts::getopts(args.tail(), opts.as_slice()) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f)
    };

    if matches.opt_present("help") {
        usage(program.as_slice(), binary_name.as_slice(), opts.as_slice());
    } else if matches.opt_present("version") {
        version();
    } else {
        let (name, algo) = detect_algo(binary_name.as_slice(), &matches);

        let binary = matches.opt_present("binary");
        let check = matches.opt_present("check");
        let tag = matches.opt_present("tag");
        let status = matches.opt_present("status");
        let quiet = matches.opt_present("quiet") || status;
        let strict = matches.opt_present("strict");
        let warn = matches.opt_present("warn") && !status;
        let files = if matches.free.is_empty() {
            vec!("-".to_string())
        } else {
            matches.free
        };
        match hashsum(name, algo, files, binary, check, tag, status, quiet, strict, warn) {
            Ok(()) => return 0,
            Err(e) => return e
        }
    }

    0
}

fn version() {
    println!("{} v{}", NAME, VERSION);
}

fn usage(program: &str, binary_name: &str, opts: &[getopts::OptGroup]) {
    version();
    println!("");
    println!("Usage:");
    if is_custom_binary(binary_name) {
        println!("  {} [OPTION]... [FILE]...", program);
    } else {
        println!("  {} {{--md5|--sha1|--sha224|--sha256|--sha384|--sha512}} [OPTION]... [FILE]...", program);
    }
    println!("");
    print!("{}", getopts::usage("Compute and check message digests.", opts));
}

fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary: bool, check: bool, tag: bool, status: bool, quiet: bool, strict: bool, warn: bool) -> Result<(), int> {
    let mut bad_format = 0;
    let mut failed = 0;
    let binary_marker = if binary {
        "*"
    } else {
        " "
    };
    for filename in files.iter() {
        let filename: &str = filename.as_slice();
        let mut file = BufferedReader::new(
            if filename == "-" {
                box stdin_raw() as Box<Reader>
            } else {
                box safe_unwrap!(File::open(&Path::new(filename))) as Box<Reader>
            }
        );
        if check {

            // Set up Regexs for line validation and parsing
            let bytes = digest.output_bits() / 4;
            let gnu_re = safe_unwrap!(Regex::new(format!(
                        r"^(?P<digest>[a-fA-F0-9]{{{}}}) (?P<binary>[ \*])(?P<fileName>.*)",
                        bytes
                        ).as_slice()));
            let bsd_re = safe_unwrap!(Regex::new(format!(
                        r"^{algorithm} \((?P<fileName>.*)\) = (?P<digest>[a-fA-F0-9]{{{digest_size}}})",
                        algorithm = algoname,
                        digest_size = bytes
                        ).as_slice()));

            let mut buffer = file;
            for (i, line) in buffer.lines().enumerate() {
                let line = safe_unwrap!(line);
                let (ck_filename, sum, binary_check) = match gnu_re.captures(line.as_slice()) {
                    Some(caps) => (caps.name("fileName"), caps.name("digest").to_ascii().to_lower(), caps.name("binary") == "*"),
                    None => match bsd_re.captures(line.as_slice()) {
                        Some(caps) => (caps.name("fileName"), caps.name("digest").to_ascii().to_lower(), true),
                        None => {
                            bad_format += 1;
                            if strict {
                                return Err(1);
                            }
                            if warn {
                                show_warning!("{}: {}: improperly formatted {} checksum line", filename, i + 1, algoname);
                            }
                            continue;
                        }
                    }
                };
                let real_sum = calc_sum(&mut digest, &mut safe_unwrap!(File::open(&Path::new(ck_filename))), binary_check)
                    .as_slice().to_ascii().to_lower();
                if sum.as_slice() == real_sum.as_slice() {
                    if !quiet {
                        println!("{}: OK", ck_filename);
                    }
                } else {
                    if !status {
                        println!("{}: FAILED", ck_filename);
                    }
                    failed += 1;
                }
            }
        } else {
            let sum = calc_sum(&mut digest, &mut file, binary);
            if tag {
                println!("{} ({}) = {}", algoname, filename, sum);
            } else {
                println!("{} {}{}", sum, binary_marker, filename);
            }
        }
    }
    if !status {
        if bad_format == 1 {
            show_warning!("{} line is improperly formatted", bad_format);
        } else if bad_format > 1 {
            show_warning!("{} lines are improperly formatted", bad_format);
        }
        if failed > 0 {
            show_warning!("{} computed checksum did NOT match", failed);
        }
    }

    Ok(())
}

fn calc_sum(digest: &mut Box<Digest>, file: &mut Reader, binary: bool) -> String {
    let data =
        if binary {
            (safe_unwrap!(file.read_to_end()))
        } else {
            (safe_unwrap!(file.read_to_str())).into_bytes()
        };
    digest.reset();
    digest.input(data.as_slice());
    digest.result_str()
}

<|endoftext|>


<commit_before>extern crate brotli2;
extern crate flate2;
extern crate zopfli;

use structs::*;
use errors::*;
use std::fs::File;
use std::io::{Read, Write};

use std::path::Path;

impl CompressionFormat for CompressionAlgorithm {
    fn extension(&self) -> &'static str {
        match self {
            &CompressionAlgorithm::Brotli => "br",
            &CompressionAlgorithm::GZip => "gz",
            &CompressionAlgorithm::WebP => "webp",
            &CompressionAlgorithm::Zopfli => "gz",
        }
    }
}

impl FileCompressor for CompressionAlgorithm {
    fn compress(&self, src: &Path, dst: &Path, quality: Option<u8>) -> Result<()> {
        match self {
            &CompressionAlgorithm::GZip => gzip_compress(src, dst, quality),
            &CompressionAlgorithm::Brotli => brotli_compress(src, dst),
            &CompressionAlgorithm::WebP => webp_compress(src, dst, quality),
            &CompressionAlgorithm::Zopfli => zopfli_compress(src, dst),
            // _ => bail!("Compression algorithm not implemented!"),
        }
    }
}

fn gzip_compress(src_path: &Path, dst_path: &Path, quality: Option<u8>) -> Result<()> {
    let mut src = File::open(src_path)?;
    let dst = File::create(dst_path)?;

    let level = match quality {
        None => flate2::Compression::Default,
        Some(0) => flate2::Compression::None,
        Some(1) => flate2::Compression::Fast,
        Some(2...6) => flate2::Compression::Default,
        Some(3...9) => flate2::Compression::Best,
        _ => bail!("Invalid --quality parameter specified!"),
    };

    let mut encoder = flate2::write::GzEncoder::new(dst, level);
    let mut buf = [0u8; 1024];
    loop {
        let bytes_read = src.read(&mut buf).chain_err(|| "Error reading from source file!")?;
        match bytes_read {
            0 => break, //end of file
            l => encoder.write_all(&buf[0..l]).chain_err(|| "Fatal gzip encoder error!")?,
        };
    }

    Ok(())
}

fn brotli_compress(src_path: &Path, dst_path: &Path) -> Result<()> {
    let mut src = File::open(src_path)?;
    let dst = File::create(dst_path)?;

    let mut buf = [0u8; 1024];
    let mut encoder = brotli2::write::BrotliEncoder::new(dst, 6);
    loop {
        let bytes_read = src.read(&mut buf).chain_err(|| "Error reading from source file!")?;
        match bytes_read {
            0 => break, //end of file
            l => encoder.write_all(&buf[0..l]).chain_err(|| "Fatal gzip encoder error!")?,
        };
    }

    Ok(())
}

fn zopfli_compress(src_path: &Path, dst_path: &Path) -> Result<()> {
    let mut src = File::open(src_path)?;
    let mut dst = File::create(dst_path)?;

    let mut src_data = Vec::<u8>::new();
    src.read_to_end(&mut src_data)?;

    zopfli::compress(&zopfli::Options::default(), &zopfli::Format::Gzip, &mut src_data, &mut dst)?;

    Ok(())
}

fn webp_compress(src_path: &Path, dst_path: &Path, quality: Option<u8>) -> Result<()> {
    use std::process::Command;

    let output = Command::new("cwebp")
        .arg("-q")
        .arg(quality.unwrap_or(90).to_string())
        .arg(src_path.as_os_str())
        .arg("-o")
        .arg(dst_path.as_os_str())
        .output()
        .chain_err(|| "Error executing cwebp!")?;

    if !output.status.success() {
        bail!("Error compressing via webp: {:?}", output);
    }

    Ok(())
}
<commit_msg>Implemented --quality for brotli<commit_after>extern crate brotli2;
extern crate flate2;
extern crate zopfli;

use structs::*;
use errors::*;
use std::fs::File;
use std::io::{Read, Write};

use std::path::Path;

impl CompressionFormat for CompressionAlgorithm {
    fn extension(&self) -> &'static str {
        match self {
            &CompressionAlgorithm::Brotli => "br",
            &CompressionAlgorithm::GZip => "gz",
            &CompressionAlgorithm::WebP => "webp",
            &CompressionAlgorithm::Zopfli => "gz",
        }
    }
}

impl FileCompressor for CompressionAlgorithm {
    fn compress(&self, src: &Path, dst: &Path, quality: Option<u8>) -> Result<()> {
        match self {
            &CompressionAlgorithm::GZip => gzip_compress(src, dst, quality),
            &CompressionAlgorithm::Brotli => brotli_compress(src, dst, quality),
            &CompressionAlgorithm::WebP => webp_compress(src, dst, quality),
            &CompressionAlgorithm::Zopfli => zopfli_compress(src, dst),
            // _ => bail!("Compression algorithm not implemented!"),
        }
    }
}

fn gzip_compress(src_path: &Path, dst_path: &Path, quality: Option<u8>) -> Result<()> {
    let mut src = File::open(src_path)?;
    let dst = File::create(dst_path)?;

    let level = match quality {
        None => flate2::Compression::Default,
        Some(0) => flate2::Compression::None,
        Some(1) => flate2::Compression::Fast,
        Some(2...6) => flate2::Compression::Default,
        Some(3...9) => flate2::Compression::Best,
        _ => bail!("Invalid --quality parameter specified!"),
    };

    let mut encoder = flate2::write::GzEncoder::new(dst, level);
    let mut buf = [0u8; 1024];
    loop {
        let bytes_read = src.read(&mut buf).chain_err(|| "Error reading from source file!")?;
        match bytes_read {
            0 => break, //end of file
            l => encoder.write_all(&buf[0..l]).chain_err(|| "Fatal gzip encoder error!")?,
        };
    }

    Ok(())
}

fn brotli_compress(src_path: &Path, dst_path: &Path, quality: Option<u8>) -> Result<()> {
    let mut src = File::open(src_path)?;
    let dst = File::create(dst_path)?;

    let level = match quality {
        None => 6,
        Some(q @ 0...11) => q,
        _ => bail!("Invalid --quality parameter specified!"),
    };

    let mut encoder = brotli2::write::BrotliEncoder::new(dst, level as u32);
    let mut buf = [0u8; 1024];
    loop {
        let bytes_read = src.read(&mut buf).chain_err(|| "Error reading from source file!")?;
        match bytes_read {
            0 => break, //end of file
            l => encoder.write_all(&buf[0..l]).chain_err(|| "Fatal gzip encoder error!")?,
        };
    }

    Ok(())
}

fn zopfli_compress(src_path: &Path, dst_path: &Path) -> Result<()> {
    let mut src = File::open(src_path)?;
    let mut dst = File::create(dst_path)?;

    let mut src_data = Vec::<u8>::new();
    src.read_to_end(&mut src_data)?;

    zopfli::compress(&zopfli::Options::default(), &zopfli::Format::Gzip, &mut src_data, &mut dst)?;

    Ok(())
}

fn webp_compress(src_path: &Path, dst_path: &Path, quality: Option<u8>) -> Result<()> {
    use std::process::Command;

    let output = Command::new("cwebp")
        .arg("-q")
        .arg(quality.unwrap_or(90).to_string())
        .arg(src_path.as_os_str())
        .arg("-o")
        .arg(dst_path.as_os_str())
        .output()
        .chain_err(|| "Error executing cwebp!")?;

    if !output.status.success() {
        bail!("Error compressing via webp: {:?}", output);
    }

    Ok(())
}
<|endoftext|>


<commit_before>use keys::*;
use byteorder::{BigEndian, WriteBytesExt};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Color {
    red: u8,
    green: u8,
    blue: u8,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KeyColor {
    key: Key,
    color: Color,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ColorPacket {
    key_type: Option<KeyType>,
    colors: Vec<KeyColor>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FlushPacket {
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum KeyColorError {
    PacketFull,
    InvalidKeyType,
}

impl Color {
    pub fn new(red: u8, green: u8, blue: u8) -> Color {
        Color {
            red: red,
            green: green,
            blue: blue,
        }
    }
}

impl KeyColor {
    pub fn new<T: Into<Key>>(key: T, color: Color) -> KeyColor {
        KeyColor {
            key: key.into(),
            color: color,
        }
    }
}

impl ColorPacket {
    pub fn new() -> ColorPacket {
        ColorPacket {
            key_type: None,
            colors: Vec::new(),
        }
    }

    /// Adds a color to this packet
    ///
    /// If this packet is alredy full, Err will be returned.
    pub fn add_key_color(&mut self, key_color: KeyColor) -> Result<(), KeyColorError> {
        match self.key_type {
            None => self.key_type = Some((&key_color.key).into()),
            Some(key_code) if key_code != (&key_color.key).into() =>
                return Err(KeyColorError::InvalidKeyType),
            _ => {}
        }

        if self.colors.len() >= 14 {
            Err(KeyColorError::PacketFull)
        } else {
            self.colors.push(key_color);
            Ok(())
        }
    }

    /// Wrapper for ColorPacket::into::<[u8; 64]>()
    pub fn to_arr(self) -> [u8; 64] {
        self.into()
    }
}

impl From<ColorPacket> for [u8; 64] {
    fn from(color_packet: ColorPacket) -> [u8; 64] {
        let mut arr = [0u8; 64];
        // head
        (&mut arr[0..4]).write_u32::<BigEndian>(0x12ff0f3b).unwrap();
        // key type
        // if none is specified, no data exists and no key will be set
        // as From can not return a Result, just use any key type
        (&mut arr[4..6]).write_u16::<BigEndian>(color_packet.key_type.unwrap_or(KeyType::Standard) as u16).unwrap();
        // reserved
        arr[6] = 0x00;
        // number of key colors
        arr[7] = color_packet.colors.len() as u8;
        // key colors
        for (key_col, buf) in color_packet.colors.iter().zip((&mut arr[8..64]).chunks_mut(4)) {
            buf[0] = key_col.key.clone().into();
            buf[1] = key_col.color.red;
            buf[2] = key_col.color.green;
            buf[3] = key_col.color.blue;
        }
        arr
    }
}

impl FlushPacket {
    pub fn new() -> FlushPacket {
        FlushPacket {  }
    }

    pub fn to_arr(self) -> [u8; 20] {
        self.into()
    }
}

impl From<FlushPacket> for [u8; 20] {
    #[allow(unused_variables)]
    fn from(p: FlushPacket) -> [u8; 20] {
        let mut arr = [0u8; 20];
        // head
        (&mut arr[0..4]).write_u32::<BigEndian>(0x11ff0f5b).unwrap();
        // body is 0
        arr
    }
}

<commit_msg>feat(color): Make struct attributes public<commit_after>use keys::*;
use byteorder::{BigEndian, WriteBytesExt};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Color {
    pub red: u8,
    pub green: u8,
    pub blue: u8,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KeyColor {
    pub key: Key,
    pub color: Color,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ColorPacket {
    key_type: Option<KeyType>,
    colors: Vec<KeyColor>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FlushPacket {
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum KeyColorError {
    PacketFull,
    InvalidKeyType,
}

impl Color {
    pub fn new(red: u8, green: u8, blue: u8) -> Color {
        Color {
            red: red,
            green: green,
            blue: blue,
        }
    }
}

impl KeyColor {
    pub fn new<T: Into<Key>>(key: T, color: Color) -> KeyColor {
        KeyColor {
            key: key.into(),
            color: color,
        }
    }
}

impl ColorPacket {
    pub fn new() -> ColorPacket {
        ColorPacket {
            key_type: None,
            colors: Vec::new(),
        }
    }

    /// Adds a color to this packet
    ///
    /// If this packet is alredy full, Err will be returned.
    pub fn add_key_color(&mut self, key_color: KeyColor) -> Result<(), KeyColorError> {
        match self.key_type {
            None => self.key_type = Some((&key_color.key).into()),
            Some(key_code) if key_code != (&key_color.key).into() =>
                return Err(KeyColorError::InvalidKeyType),
            _ => {}
        }

        if self.colors.len() >= 14 {
            Err(KeyColorError::PacketFull)
        } else {
            self.colors.push(key_color);
            Ok(())
        }
    }

    /// Wrapper for ColorPacket::into::<[u8; 64]>()
    pub fn to_arr(self) -> [u8; 64] {
        self.into()
    }
}

impl From<ColorPacket> for [u8; 64] {
    fn from(color_packet: ColorPacket) -> [u8; 64] {
        let mut arr = [0u8; 64];
        // head
        (&mut arr[0..4]).write_u32::<BigEndian>(0x12ff0f3b).unwrap();
        // key type
        // if none is specified, no data exists and no key will be set
        // as From can not return a Result, just use any key type
        (&mut arr[4..6]).write_u16::<BigEndian>(color_packet.key_type.unwrap_or(KeyType::Standard) as u16).unwrap();
        // reserved
        arr[6] = 0x00;
        // number of key colors
        arr[7] = color_packet.colors.len() as u8;
        // key colors
        for (key_col, buf) in color_packet.colors.iter().zip((&mut arr[8..64]).chunks_mut(4)) {
            buf[0] = key_col.key.clone().into();
            buf[1] = key_col.color.red;
            buf[2] = key_col.color.green;
            buf[3] = key_col.color.blue;
        }
        arr
    }
}

impl FlushPacket {
    pub fn new() -> FlushPacket {
        FlushPacket {  }
    }

    pub fn to_arr(self) -> [u8; 20] {
        self.into()
    }
}

impl From<FlushPacket> for [u8; 20] {
    #[allow(unused_variables)]
    fn from(p: FlushPacket) -> [u8; 20] {
        let mut arr = [0u8; 20];
        // head
        (&mut arr[0..4]).write_u32::<BigEndian>(0x11ff0f5b).unwrap();
        // body is 0
        arr
    }
}

<|endoftext|>


<commit_before>pub struct Crc32 {
    pub crc: u32,
    pub num_bytes: usize,
}

#[cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
const POLYNOMIALS: [u32; 256] = [
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
];

impl Crc32 {
    pub fn new() -> Crc32 {
        Crc32 {
            crc: 0,
            num_bytes: 0,
        }
    }

    /// Update the CRC32 with the bytes from the slice.
    pub fn update_with_slice(&mut self, buf: &[u8]) {
        for byte in buf {
            self.update_with_byte(*byte);
        }
    }

    /// Update the CRC32 with a single byte.
    #[inline]
    pub fn update_with_byte(&mut self, byte: u8) {
        let mut value = !self.crc;
        value = POLYNOMIALS[((value as u8) ^ byte) as usize] ^ (value >> 8);
        self.crc = !value;
        self.num_bytes += 1;
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_default() {
        let crc32 = Crc32::new();
        assert_eq!(0, crc32.crc, "Invalid checksum");
        assert_eq!(0, crc32.num_bytes, "Invalid number of bytes");
    }

    #[test]
    fn test_empty_slice() {
        let mut crc32 = Crc32::new();
        crc32.update_with_slice(&[0; 0]);
        assert_eq!(0, crc32.crc, "Invalid checksum");
        assert_eq!(0, crc32.num_bytes, "Invalid number of bytes");
    }

    #[test]
    fn test() {
        let mut crc32 = Crc32::new();
        let block = (0..2048).map(|c| c as u8).collect::<Vec<u8>>();
        crc32.update_with_slice(&block);
        assert_eq!(0x9f5edd58, crc32.crc, "Invalid checksum");
        assert_eq!(2048, crc32.num_bytes, "Invalid number of bytes");
    }
}
<commit_msg>Improve crc32 performance<commit_after>pub struct Crc32 {
    pub crc: u32,
    pub num_bytes: usize,
}

#[cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
const POLYNOMIALS: [u32; 256] = [
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
];

impl Crc32 {
    pub fn new() -> Crc32 {
        Crc32 {
            crc: 0,
            num_bytes: 0,
        }
    }

    /// Update the CRC32 with the bytes from the slice.
    pub fn update_with_slice(&mut self, buf: &[u8]) {
        buf.iter().for_each(|&b| {
            let mut value = !self.crc;
            value = POLYNOMIALS[((value as u8) ^ b) as usize] ^ (value >> 8);
            self.crc = !value;
        });
        self.num_bytes += buf.len();
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_default() {
        let crc32 = Crc32::new();
        assert_eq!(0, crc32.crc, "Invalid checksum");
        assert_eq!(0, crc32.num_bytes, "Invalid number of bytes");
    }

    #[test]
    fn test_empty_slice() {
        let mut crc32 = Crc32::new();
        crc32.update_with_slice(&[0; 0]);
        assert_eq!(0, crc32.crc, "Invalid checksum");
        assert_eq!(0, crc32.num_bytes, "Invalid number of bytes");
    }

    #[test]
    fn test() {
        let mut crc32 = Crc32::new();
        let block = (0..2048).map(|c| c as u8).collect::<Vec<u8>>();
        crc32.update_with_slice(&block);
        assert_eq!(0x9f5edd58, crc32.crc, "Invalid checksum");
        assert_eq!(2048, crc32.num_bytes, "Invalid number of bytes");
    }
}
<|endoftext|>


<commit_before>use super::gi_docgen;
use crate::Env;
use once_cell::sync::Lazy;
use regex::{Captures, Match, Regex};

const LANGUAGE_SEP_BEGIN: &str = "<!-- language=\"";
const LANGUAGE_SEP_END: &str = "\" -->";
const LANGUAGE_BLOCK_BEGIN: &str = "|[";
const LANGUAGE_BLOCK_END: &str = "\n]|";

pub fn reformat_doc(input: &str, env: &Env, in_type: &str) -> String {
    code_blocks_transformation(input, env, in_type)
}

fn try_split<'a>(src: &'a str, needle: &str) -> (&'a str, Option<&'a str>) {
    match src.find(needle) {
        Some(pos) => (&src[..pos], Some(&src[pos + needle.len()..])),
        None => (src, None),
    }
}

fn code_blocks_transformation(mut input: &str, env: &Env, in_type: &str) -> String {
    let mut out = String::with_capacity(input.len());

    loop {
        input = match try_split(input, LANGUAGE_BLOCK_BEGIN) {
            (before, Some(after)) => {
                out.push_str(&format(before, env, in_type));
                if let (before, Some(after)) =
                    try_split(get_language(after, &mut out), LANGUAGE_BLOCK_END)
                {
                    out.push_str(before);
                    out.push_str("\n```");
                    after
                } else {
                    after
                }
            }
            (before, None) => {
                out.push_str(&format(before, env, in_type));
                return out;
            }
        };
    }
}

fn get_language<'a>(entry: &'a str, out: &mut String) -> &'a str {
    if let (_, Some(after)) = try_split(entry, LANGUAGE_SEP_BEGIN) {
        if let (before, Some(after)) = try_split(after, LANGUAGE_SEP_END) {
            out.push_str(&format!("\n```{}", before));
            return after;
        }
    }
    out.push_str("\n```text");
    entry
}

fn format(input: &str, env: &Env, in_type: &str) -> String {
    let mut ret = String::with_capacity(input.len());
    // We run gi_docgen first because it's super picky about the types it replaces
    let no_c_types_re = gi_docgen::replace_c_types(input, env, in_type);
    ret.push_str(&replace_c_types(&no_c_types_re, env, in_type));
    ret
}

static SYMBOL: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(^|[^\\])([@#%])(\w+\b)([:.]+[\w-]+\b)?").unwrap());
static FUNCTION: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"([@#%])?(\w+\b[:.]+)?(\b[a-z0-9_]+)\(\)").unwrap());
// **note**
// The optional . at the end is to make the regex more relaxed for some weird broken cases on gtk3's docs
// it doesn't hurt other docs so please don't drop it
static GDK_GTK: Lazy<Regex> = Lazy::new(|| Regex::new(r"`(G[dt]k[A-Z]\w+\b)(\.)?`").unwrap());
static TAGS: Lazy<Regex> = Lazy::new(|| Regex::new(r"<[\w/-]+>").unwrap());
static SPACES: Lazy<Regex> = Lazy::new(|| Regex::new(r"[ ]{2,}").unwrap());

fn replace_c_types(entry: &str, env: &Env, in_type: &str) -> String {
    let symbols = env.symbols.borrow();
    let out = FUNCTION.replace_all(entry, |caps: &Captures<'_>| {
        let name = &caps[3];
        let sym = symbols.by_c_name(name);

        if let Some(sym) = sym {
            if sym.owner_name() == Some(in_type) {
                // `#` or `%` symbols should probably have been `@` to denote
                // that it is a reference within the current type.
                format!("[`Self::{}()`]", sym.name())
            } else {
                match caps.get(1).as_ref().map(Match::as_str) {
                    // Catch invalid @ references that have a C symbol available but do not belong
                    // to the current type (and can hence not use `Self::`). For now generate XXX
                    // but with a valid global link so that the can be easily spotted in the code.
                    // assert_eq!(sym.owner_name(), Some(in_type));
                    Some("@") => format!(
                        "[`crate::{}()`] (XXX: @-reference does not belong to {}!)",
                        sym.full_rust_name(),
                        in_type,
                    ),
                    Some("#") | None => {
                        format!("[`crate::{}()`]", sym.full_rust_name())
                    }
                    Some("%") => panic!("% not allowed for {:?}", caps),
                    Some(c) => panic!("Unknown symbol reference {}", c),
                }
            }
        } else if let Some(typ) = caps.get(2) {
            let typ = typ.as_str();
            if typ == in_type {
                format!("[`Self::{}()`]", name)
            } else {
                format!("[`crate::{}{}()`]", typ, name)
            }
        } else {
            format!("`{}()`", name)
        }
    });

    let out = SYMBOL.replace_all(&out, |caps: &Captures<'_>| {
        let member = caps.get(4).map(|m| m.as_str()).unwrap_or("");
        let sym = symbols.by_c_name(&caps[3]);

        if let Some(sym) = sym {
            if sym.owner_name() == Some(in_type) {
                // `#` or `%` symbols should probably have been `@` to denote
                // that it is a reference within the current type.
                format!("{}[`Self::{}{}`]", &caps[1], sym.name(), member)
            } else {
                match &caps[2] {
                    // Catch invalid @ references that have a C symbol available but do not belong
                    // to the current type (and can hence not use `Self::`). For now generate XXX
                    // but with a valid global link so that the can be easily spotted in the code.
                    // assert_eq!(sym.owner_name(), Some(in_type));
                    "@" => format!(
                        "{}[`crate::{}{}`] (XXX: @-reference does not belong to {}!)",
                        &caps[1],
                        sym.full_rust_name(),
                        member,
                        in_type,
                    ),
                    "%" if sym.is_rust_prelude() => {
                        format!("{}[`{}{}`]", &caps[1], sym.full_rust_name(), member)
                    }
                    "#" | "%" => {
                        format!("{}[`crate::{}{}`]", &caps[1], sym.full_rust_name(), member)
                    }
                    c => panic!("Unknown symbol reference {}", c),
                }
            }
        } else {
            format!("{}`{}{}`", &caps[1], &caps[3], member)
        }
    });
    let out = GDK_GTK.replace_all(&out, |caps: &Captures<'_>| find_struct(&caps[1], env));
    let out = TAGS.replace_all(&out, "`$0`");
    SPACES.replace_all(&out, " ").into_owned()
}

fn find_struct(name: &str, env: &Env) -> String {
    let symbols = env.symbols.borrow();

    let symbol = if let Some(obj) = env
        .analysis
        .objects
        .iter()
        .find(|(_, o)| o.c_type == name)
        .map(|(_, o)| o)
    {
        symbols.by_tid(obj.type_id)
    } else if let Some(record) = env
        .analysis
        .records
        .iter()
        .find(|(_, r)| r.name == name)
        .map(|(_, r)| r)
    {
        symbols.by_tid(record.type_id)
    } else {
        None
    };
    symbol
        .map(|sym| format!("[{name}](crate::{name})", name = sym.full_rust_name()))
        .unwrap_or_else(|| format!("`{}`", name))
}
<commit_msg>docs: make the gtk/gdk regex catch gsk/pango as well<commit_after>use super::gi_docgen;
use crate::Env;
use once_cell::sync::Lazy;
use regex::{Captures, Match, Regex};

const LANGUAGE_SEP_BEGIN: &str = "<!-- language=\"";
const LANGUAGE_SEP_END: &str = "\" -->";
const LANGUAGE_BLOCK_BEGIN: &str = "|[";
const LANGUAGE_BLOCK_END: &str = "\n]|";

pub fn reformat_doc(input: &str, env: &Env, in_type: &str) -> String {
    code_blocks_transformation(input, env, in_type)
}

fn try_split<'a>(src: &'a str, needle: &str) -> (&'a str, Option<&'a str>) {
    match src.find(needle) {
        Some(pos) => (&src[..pos], Some(&src[pos + needle.len()..])),
        None => (src, None),
    }
}

fn code_blocks_transformation(mut input: &str, env: &Env, in_type: &str) -> String {
    let mut out = String::with_capacity(input.len());

    loop {
        input = match try_split(input, LANGUAGE_BLOCK_BEGIN) {
            (before, Some(after)) => {
                out.push_str(&format(before, env, in_type));
                if let (before, Some(after)) =
                    try_split(get_language(after, &mut out), LANGUAGE_BLOCK_END)
                {
                    out.push_str(before);
                    out.push_str("\n```");
                    after
                } else {
                    after
                }
            }
            (before, None) => {
                out.push_str(&format(before, env, in_type));
                return out;
            }
        };
    }
}

fn get_language<'a>(entry: &'a str, out: &mut String) -> &'a str {
    if let (_, Some(after)) = try_split(entry, LANGUAGE_SEP_BEGIN) {
        if let (before, Some(after)) = try_split(after, LANGUAGE_SEP_END) {
            out.push_str(&format!("\n```{}", before));
            return after;
        }
    }
    out.push_str("\n```text");
    entry
}

fn format(input: &str, env: &Env, in_type: &str) -> String {
    let mut ret = String::with_capacity(input.len());
    // We run gi_docgen first because it's super picky about the types it replaces
    let no_c_types_re = gi_docgen::replace_c_types(input, env, in_type);
    ret.push_str(&replace_c_types(&no_c_types_re, env, in_type));
    ret
}

static SYMBOL: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(^|[^\\])([@#%])(\w+\b)([:.]+[\w-]+\b)?").unwrap());
static FUNCTION: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"([@#%])?(\w+\b[:.]+)?(\b[a-z0-9_]+)\(\)").unwrap());
// **note**
// The optional . at the end is to make the regex more relaxed for some weird broken cases on gtk3's docs
// it doesn't hurt other docs so please don't drop it
static GDK_GTK: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"`(G[dts]k|Pango[A-Z]\w+\b)(\.)?`").unwrap());
static TAGS: Lazy<Regex> = Lazy::new(|| Regex::new(r"<[\w/-]+>").unwrap());
static SPACES: Lazy<Regex> = Lazy::new(|| Regex::new(r"[ ]{2,}").unwrap());

fn replace_c_types(entry: &str, env: &Env, in_type: &str) -> String {
    let symbols = env.symbols.borrow();
    let out = FUNCTION.replace_all(entry, |caps: &Captures<'_>| {
        let name = &caps[3];
        let sym = symbols.by_c_name(name);

        if let Some(sym) = sym {
            if sym.owner_name() == Some(in_type) {
                // `#` or `%` symbols should probably have been `@` to denote
                // that it is a reference within the current type.
                format!("[`Self::{}()`]", sym.name())
            } else {
                match caps.get(1).as_ref().map(Match::as_str) {
                    // Catch invalid @ references that have a C symbol available but do not belong
                    // to the current type (and can hence not use `Self::`). For now generate XXX
                    // but with a valid global link so that the can be easily spotted in the code.
                    // assert_eq!(sym.owner_name(), Some(in_type));
                    Some("@") => format!(
                        "[`crate::{}()`] (XXX: @-reference does not belong to {}!)",
                        sym.full_rust_name(),
                        in_type,
                    ),
                    Some("#") | None => {
                        format!("[`crate::{}()`]", sym.full_rust_name())
                    }
                    Some("%") => panic!("% not allowed for {:?}", caps),
                    Some(c) => panic!("Unknown symbol reference {}", c),
                }
            }
        } else if let Some(typ) = caps.get(2) {
            let typ = typ.as_str();
            if typ == in_type {
                format!("[`Self::{}()`]", name)
            } else {
                format!("[`crate::{}{}()`]", typ, name)
            }
        } else {
            format!("`{}()`", name)
        }
    });

    let out = SYMBOL.replace_all(&out, |caps: &Captures<'_>| {
        let member = caps.get(4).map(|m| m.as_str()).unwrap_or("");
        let sym = symbols.by_c_name(&caps[3]);

        if let Some(sym) = sym {
            if sym.owner_name() == Some(in_type) {
                // `#` or `%` symbols should probably have been `@` to denote
                // that it is a reference within the current type.
                format!("{}[`Self::{}{}`]", &caps[1], sym.name(), member)
            } else {
                match &caps[2] {
                    // Catch invalid @ references that have a C symbol available but do not belong
                    // to the current type (and can hence not use `Self::`). For now generate XXX
                    // but with a valid global link so that the can be easily spotted in the code.
                    // assert_eq!(sym.owner_name(), Some(in_type));
                    "@" => format!(
                        "{}[`crate::{}{}`] (XXX: @-reference does not belong to {}!)",
                        &caps[1],
                        sym.full_rust_name(),
                        member,
                        in_type,
                    ),
                    "%" if sym.is_rust_prelude() => {
                        format!("{}[`{}{}`]", &caps[1], sym.full_rust_name(), member)
                    }
                    "#" | "%" => {
                        format!("{}[`crate::{}{}`]", &caps[1], sym.full_rust_name(), member)
                    }
                    c => panic!("Unknown symbol reference {}", c),
                }
            }
        } else {
            format!("{}`{}{}`", &caps[1], &caps[3], member)
        }
    });
    let out = GDK_GTK.replace_all(&out, |caps: &Captures<'_>| find_struct(&caps[1], env));
    let out = TAGS.replace_all(&out, "`$0`");
    SPACES.replace_all(&out, " ").into_owned()
}

fn find_struct(name: &str, env: &Env) -> String {
    let symbols = env.symbols.borrow();

    let symbol = if let Some(obj) = env
        .analysis
        .objects
        .iter()
        .find(|(_, o)| o.c_type == name)
        .map(|(_, o)| o)
    {
        symbols.by_tid(obj.type_id)
    } else if let Some(record) = env
        .analysis
        .records
        .iter()
        .find(|(_, r)| r.name == name)
        .map(|(_, r)| r)
    {
        symbols.by_tid(record.type_id)
    } else {
        None
    };
    symbol
        .map(|sym| format!("[{name}](crate::{name})", name = sym.full_rust_name()))
        .unwrap_or_else(|| format!("`{}`", name))
}
<|endoftext|>


<commit_before>use resource_manager::Manager;

#[derive(PartialEq)]
pub enum GameState {
    NotStarted,
    InProgress,
}

pub struct Context {
    pub resource_manager: Manager,
    pub game_state: GameState,
}
<commit_msg>Derive PartialEq, Clone, Debug (TODO)<commit_after>use resource_manager::Manager;

#[derive(PartialEq, Clone, Debug)]
pub enum GameState {
    NotStarted,
    InProgress,
}

pub struct Context {
    pub resource_manager: Manager,
    pub game_state: GameState,
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use std::u32;
use Command;

/// A command wrapper which always merges with itself.
///
/// This wrapper has an [`id`] of `u32::MAX`.
///
/// [`id`]: trait.Command.html#method.id
pub struct Merger<R, C: Command<R> + 'static> {
    cmd: C,
    _marker: PhantomData<Box<dyn Command<R> + 'static>>,
}

impl<R, C: Command<R> + 'static> Merger<R, C> {
    /// Returns a new merger command.
    #[inline]
    pub fn new(cmd: C) -> Merger<R, C> {
        Merger {
            cmd,
            _marker: PhantomData,
        }
    }
}

impl<R, C: Command<R> + 'static> From<C> for Merger<R, C> {
    #[inline]
    fn from(cmd: C) -> Self {
        Merger::new(cmd)
    }
}

impl<R, C: Command<R> + 'static> Command<R> for Merger<R, C> {
    #[inline]
    fn apply(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error>> {
        self.cmd.apply(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error>> {
        self.cmd.undo(receiver)
    }

    #[inline]
    fn redo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error>> {
        self.cmd.redo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        Some(u32::MAX)
    }
}

impl<R, C: Command<R> + 'static> Debug for Merger<R, C> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Merger").field("cmd", &self.cmd).finish()
    }
}

#[cfg(feature = "display")]
impl<R, C: Command<R> + 'static> fmt::Display for Merger<R, C> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        (&self.cmd as &fmt::Display).fmt(f)
    }
}

/// The result of merging two commands.
pub struct Merged<R, C1: Command<R> + 'static, C2: Command<R> + 'static> {
    cmd1: C1,
    cmd2: C2,
    _marker: PhantomData<Box<dyn Command<R> + 'static>>,
}

impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> Merged<R, C1, C2> {
    /// Merges `cmd1` and `cmd2` into a single command.
    #[inline]
    pub fn new(cmd1: C1, cmd2: C2) -> Merged<R, C1, C2> {
        Merged {
            cmd1,
            cmd2,
            _marker: PhantomData,
        }
    }
}

impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> Command<R> for Merged<R, C1, C2> {
    #[inline]
    fn apply(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error>> {
        self.cmd1.apply(receiver)?;
        self.cmd2.apply(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error>> {
        self.cmd2.undo(receiver)?;
        self.cmd1.undo(receiver)
    }

    #[inline]
    fn redo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error>> {
        self.cmd1.redo(receiver)?;
        self.cmd2.redo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        self.cmd1.id()
    }
}

impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> Debug for Merged<R, C1, C2> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Merged")
            .field("cmd1", &self.cmd1)
            .field("cmd2", &self.cmd2)
            .finish()
    }
}

#[cfg(feature = "display")]
impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> fmt::Display for Merged<R, C1, C2> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{cmd1} + {cmd2}", cmd1 = self.cmd1, cmd2 = self.cmd2)
    }
}
<commit_msg>Add merge macro<commit_after>use std::error::Error;
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use std::u32;
use Command;

/// Macro for merging commands.
///
/// # Examples
/// ```
/// # use std::error::Error;
/// # use undo::*;
/// #[derive(Debug)]
/// struct Add(char);
///
/// impl Command<String> for Add {
///     fn apply(&mut self, s: &mut String) -> Result<(), Box<dyn Error>> {
///         s.push(self.0);
///         Ok(())
///     }
///
///     fn undo(&mut self, s: &mut String) -> Result<(), Box<dyn Error>> {
///         self.0 = s.pop().ok_or("`s` is unexpectedly empty")?;
///         Ok(())
///     }
/// }
///
/// fn main() -> Result<(), Box<dyn Error>> {
///     let mut record = Record::default();
///     record.apply(merge![Add('a'), Add('b'), Add('c')])?;
///     assert_eq!(record.as_receiver(), "abc");
///     record.undo().unwrap()?;
///     assert_eq!(record.as_receiver(), "");
///     record.redo().unwrap()?;
///     assert_eq!(record.as_receiver(), "abc");
///     Ok(())
/// }
/// ```
#[macro_export]
macro_rules! merge {
    ($cmd1:expr, $cmd2:expr) => (
        Merged::new($cmd1, $cmd2)
    );
    ($cmd1:expr, $cmd2:expr, $($tail:expr),+) => (
        merge![Merged::new($cmd1, $cmd2), $($tail),*]
    );
}

/// A command wrapper which always merges with itself.
///
/// This wrapper has an [`id`] of `u32::MAX`.
///
/// [`id`]: trait.Command.html#method.id
pub struct Merger<R, C: Command<R> + 'static> {
    cmd: C,
    _marker: PhantomData<Box<dyn Command<R> + 'static>>,
}

impl<R, C: Command<R> + 'static> Merger<R, C> {
    /// Returns a new merger command.
    #[inline]
    pub fn new(cmd: C) -> Merger<R, C> {
        Merger {
            cmd,
            _marker: PhantomData,
        }
    }
}

impl<R, C: Command<R> + 'static> From<C> for Merger<R, C> {
    #[inline]
    fn from(cmd: C) -> Self {
        Merger::new(cmd)
    }
}

impl<R, C: Command<R> + 'static> Command<R> for Merger<R, C> {
    #[inline]
    fn apply(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error>> {
        self.cmd.apply(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error>> {
        self.cmd.undo(receiver)
    }

    #[inline]
    fn redo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error>> {
        self.cmd.redo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        Some(u32::MAX)
    }
}

impl<R, C: Command<R> + 'static> Debug for Merger<R, C> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Merger").field("cmd", &self.cmd).finish()
    }
}

#[cfg(feature = "display")]
impl<R, C: Command<R> + 'static> fmt::Display for Merger<R, C> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        (&self.cmd as &fmt::Display).fmt(f)
    }
}

/// The result of merging two commands.
pub struct Merged<R, C1: Command<R> + 'static, C2: Command<R> + 'static> {
    cmd1: C1,
    cmd2: C2,
    _marker: PhantomData<Box<dyn Command<R> + 'static>>,
}

impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> Merged<R, C1, C2> {
    /// Merges `cmd1` and `cmd2` into a single command.
    #[inline]
    pub fn new(cmd1: C1, cmd2: C2) -> Merged<R, C1, C2> {
        Merged {
            cmd1,
            cmd2,
            _marker: PhantomData,
        }
    }
}

impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> Command<R> for Merged<R, C1, C2> {
    #[inline]
    fn apply(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error>> {
        self.cmd1.apply(receiver)?;
        self.cmd2.apply(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error>> {
        self.cmd2.undo(receiver)?;
        self.cmd1.undo(receiver)
    }

    #[inline]
    fn redo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error>> {
        self.cmd1.redo(receiver)?;
        self.cmd2.redo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        self.cmd1.id()
    }
}

impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> Debug for Merged<R, C1, C2> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Merged")
            .field("cmd1", &self.cmd1)
            .field("cmd2", &self.cmd2)
            .finish()
    }
}

#[cfg(feature = "display")]
impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> fmt::Display for Merged<R, C1, C2> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{cmd1} + {cmd2}", cmd1 = self.cmd1, cmd2 = self.cmd2)
    }
}
<|endoftext|>


<commit_before>//! Protobuf encoding and decoding errors.

use alloc::borrow::Cow;
use alloc::boxed::Box;
use alloc::vec::Vec;

use core::fmt;

/// A Protobuf message decoding error.
///
/// `DecodeError` indicates that the input buffer does not caontain a valid
/// Protobuf message. The error details should be considered 'best effort': in
/// general it is not possible to exactly pinpoint why data is malformed.
#[derive(Clone, PartialEq, Eq)]
pub struct DecodeError {
    inner: Box<Inner>,
}

#[derive(Clone, PartialEq, Eq)]
struct Inner {
    /// A 'best effort' root cause description.
    description: Cow<'static, str>,
    /// A stack of (message, field) name pairs, which identify the specific
    /// message type and field where decoding failed. The stack contains an
    /// entry per level of nesting.
    stack: Vec<(&'static str, &'static str)>,
}

impl DecodeError {
    /// Creates a new `DecodeError` with a 'best effort' root cause description.
    ///
    /// Meant to be used only by `Message` implementations.
    #[cold]
    pub(crate) fn new(description: impl Into<Cow<'static, str>>) -> DecodeError {
        DecodeError {
            inner: Box::new(Inner {
                description: description.into(),
                stack: Vec::new(),
            }),
        }
    }

    /// Pushes a (message, field) name location pair on to the location stack.
    ///
    /// Meant to be used only by `Message` implementations.
    #[doc(hidden)]
    pub fn push(&mut self, message: &'static str, field: &'static str) {
        self.inner.stack.push((message, field));
    }
}

impl fmt::Debug for DecodeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("DecodeError")
            .field("description", &self.inner.description)
            .field("stack", &self.inner.stack)
            .finish()
    }
}

impl fmt::Display for DecodeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("failed to decode Protobuf message: ")?;
        for &(message, field) in &self.inner.stack {
            write!(f, "{}.{}: ", message, field)?;
        }
        f.write_str(&self.inner.description)
    }
}

#[cfg(feature = "std")]
impl std::error::Error for DecodeError {}

#[cfg(feature = "std")]
impl From<DecodeError> for std::io::Error {
    fn from(error: DecodeError) -> std::io::Error {
        std::io::Error::new(std::io::ErrorKind::InvalidData, error)
    }
}

/// A Protobuf message encoding error.
///
/// `EncodeError` always indicates that a message failed to encode because the
/// provided buffer had insufficient capacity. Message encoding is otherwise
/// infallible.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct EncodeError {
    required: usize,
    remaining: usize,
}

impl EncodeError {
    /// Creates a new `EncodeError`.
    pub(crate) fn new(required: usize, remaining: usize) -> EncodeError {
        EncodeError {
            required,
            remaining,
        }
    }

    /// Returns the required buffer capacity to encode the message.
    pub fn required_capacity(&self) -> usize {
        self.required
    }

    /// Returns the remaining length in the provided buffer at the time of encoding.
    pub fn remaining(&self) -> usize {
        self.remaining
    }
}

impl fmt::Display for EncodeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "failed to encode Protobuf messsage; insufficient buffer capacity (required: {}, remaining: {})",
            self.required, self.remaining
        )
    }
}

#[cfg(feature = "std")]
impl std::error::Error for EncodeError {}

#[cfg(feature = "std")]
impl From<EncodeError> for std::io::Error {
    fn from(error: EncodeError) -> std::io::Error {
        std::io::Error::new(std::io::ErrorKind::InvalidInput, error)
    }
}
<commit_msg>make DecodeError::new public (#421)<commit_after>//! Protobuf encoding and decoding errors.

use alloc::borrow::Cow;
use alloc::boxed::Box;
use alloc::vec::Vec;

use core::fmt;

/// A Protobuf message decoding error.
///
/// `DecodeError` indicates that the input buffer does not caontain a valid
/// Protobuf message. The error details should be considered 'best effort': in
/// general it is not possible to exactly pinpoint why data is malformed.
#[derive(Clone, PartialEq, Eq)]
pub struct DecodeError {
    inner: Box<Inner>,
}

#[derive(Clone, PartialEq, Eq)]
struct Inner {
    /// A 'best effort' root cause description.
    description: Cow<'static, str>,
    /// A stack of (message, field) name pairs, which identify the specific
    /// message type and field where decoding failed. The stack contains an
    /// entry per level of nesting.
    stack: Vec<(&'static str, &'static str)>,
}

impl DecodeError {
    /// Creates a new `DecodeError` with a 'best effort' root cause description.
    ///
    /// Meant to be used only by `Message` implementations.
    #[doc(hidden)]
    #[cold]
    pub fn new(description: impl Into<Cow<'static, str>>) -> DecodeError {
        DecodeError {
            inner: Box::new(Inner {
                description: description.into(),
                stack: Vec::new(),
            }),
        }
    }

    /// Pushes a (message, field) name location pair on to the location stack.
    ///
    /// Meant to be used only by `Message` implementations.
    #[doc(hidden)]
    pub fn push(&mut self, message: &'static str, field: &'static str) {
        self.inner.stack.push((message, field));
    }
}

impl fmt::Debug for DecodeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("DecodeError")
            .field("description", &self.inner.description)
            .field("stack", &self.inner.stack)
            .finish()
    }
}

impl fmt::Display for DecodeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("failed to decode Protobuf message: ")?;
        for &(message, field) in &self.inner.stack {
            write!(f, "{}.{}: ", message, field)?;
        }
        f.write_str(&self.inner.description)
    }
}

#[cfg(feature = "std")]
impl std::error::Error for DecodeError {}

#[cfg(feature = "std")]
impl From<DecodeError> for std::io::Error {
    fn from(error: DecodeError) -> std::io::Error {
        std::io::Error::new(std::io::ErrorKind::InvalidData, error)
    }
}

/// A Protobuf message encoding error.
///
/// `EncodeError` always indicates that a message failed to encode because the
/// provided buffer had insufficient capacity. Message encoding is otherwise
/// infallible.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct EncodeError {
    required: usize,
    remaining: usize,
}

impl EncodeError {
    /// Creates a new `EncodeError`.
    pub(crate) fn new(required: usize, remaining: usize) -> EncodeError {
        EncodeError {
            required,
            remaining,
        }
    }

    /// Returns the required buffer capacity to encode the message.
    pub fn required_capacity(&self) -> usize {
        self.required
    }

    /// Returns the remaining length in the provided buffer at the time of encoding.
    pub fn remaining(&self) -> usize {
        self.remaining
    }
}

impl fmt::Display for EncodeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "failed to encode Protobuf messsage; insufficient buffer capacity (required: {}, remaining: {})",
            self.required, self.remaining
        )
    }
}

#[cfg(feature = "std")]
impl std::error::Error for EncodeError {}

#[cfg(feature = "std")]
impl From<EncodeError> for std::io::Error {
    fn from(error: EncodeError) -> std::io::Error {
        std::io::Error::new(std::io::ErrorKind::InvalidInput, error)
    }
}
<|endoftext|>


<commit_before>//! Provides a standardized error type for oxcable.

use std::fmt;
use std::io;
use std::result;

use byteorder;
use portaudio::pa;
use portmidi;

/// A global error type for all oxcable operations.
///
/// Many of the errors simply wrap the errors provided by our supporting
/// libraries.
#[derive(Debug)]
pub enum Error {
    /// No audio resources can be opened.
    NoAudioDevices,
    /// No MIDI resources can be opened.
    NoMidiDevices,
    /// A file is not formatted properly.
    InvalidFile,
    /// A requested index is out of range.
    ///
    /// The string argument specifies which index was out of range.
    OutOfRange(&'static str),
    /// The requested operation would create a graph cycle.
    CreatesCycle,
    /// A feature isn't supported.
    ///
    /// The string argument describes what feature.
    Unsupported(&'static str),
    /// A std::io operation failed.
    Io(io::Error),
    /// A portaudio operation failed.
    PortAudio(pa::Error),
    /// A portmidi operation failed.
    PortMidi(portmidi::PortMidiError),
}
use self::Error::*;

impl From<byteorder::Error> for Error {
    fn from(e: byteorder::Error) -> Self {
        match e {
            byteorder::Error::UnexpectedEOF => Error::InvalidFile,
            byteorder::Error::Io(e) => Error::Io(e),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

impl From<pa::Error> for Error {
    fn from(e: pa::Error) -> Error {
        Error::PortAudio(e)
    }
}

impl From<portmidi::PortMidiError> for Error {
    fn from(e: portmidi::PortMidiError) -> Error {
        Error::PortMidi(e)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &NoAudioDevices => write!(f, "No audio devices found."),
            &NoMidiDevices => write!(f, "No midi devices found."),
            &InvalidFile => write!(f, "The provided was not valid."),
            &OutOfRange(ref idx) => write!(f, "Index `{}` was out of range.", idx),
            &CreatesCycle =>
                write!(f, "The requested action creates a graph cycle."),
            &Unsupported(ref feat) =>
                write!(f, "Unsupported feature: {}", feat),
            &Io(ref e) => write!(f, "IO error: {}", e),
            &PortAudio(ref e) => write!(f, "PortAudio error: {}", e),
            &PortMidi(ref e) => write!(f, "PortMidi error: {:?}", e),
        }
    }
}

pub type Result<T> = result::Result<T, Error>;
<commit_msg>Implement Error trait for Error<commit_after>//! Provides a standardized error type for oxcable.

use std::error;
use std::fmt;
use std::io;
use std::result;

use byteorder;
use portaudio::pa;
use portmidi;

/// A global error type for all oxcable operations.
///
/// Many of the errors simply wrap the errors provided by our supporting
/// libraries.
#[derive(Debug)]
pub enum Error {
    /// No audio resources can be opened.
    NoAudioDevices,
    /// No MIDI resources can be opened.
    NoMidiDevices,
    /// A file is not formatted properly.
    InvalidFile,
    /// A requested index is out of range.
    ///
    /// The string argument specifies which index was out of range.
    OutOfRange(&'static str),
    /// The requested operation would create a graph cycle.
    CreatesCycle,
    /// A feature isn't supported.
    ///
    /// The string argument describes what feature.
    Unsupported(&'static str),
    /// A std::io operation failed.
    Io(io::Error),
    /// A portaudio operation failed.
    PortAudio(pa::Error),
    /// A portmidi operation failed.
    PortMidi(portmidi::PortMidiError),
}
use self::Error::*;

impl From<byteorder::Error> for Error {
    fn from(e: byteorder::Error) -> Self {
        match e {
            byteorder::Error::UnexpectedEOF => Error::InvalidFile,
            byteorder::Error::Io(e) => Error::Io(e),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

impl From<pa::Error> for Error {
    fn from(e: pa::Error) -> Error {
        Error::PortAudio(e)
    }
}

impl From<portmidi::PortMidiError> for Error {
    fn from(e: portmidi::PortMidiError) -> Error {
        Error::PortMidi(e)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &NoAudioDevices => write!(f, "No audio devices found."),
            &NoMidiDevices => write!(f, "No midi devices found."),
            &InvalidFile => write!(f, "The provided was not valid."),
            &OutOfRange(ref idx) => write!(f, "Index `{}` was out of range.", idx),
            &CreatesCycle =>
                write!(f, "The requested action creates a graph cycle."),
            &Unsupported(ref feat) =>
                write!(f, "Unsupported feature: {}", feat),
            &Io(ref e) => write!(f, "IO error: {}", e),
            &PortAudio(ref e) => write!(f, "PortAudio error: {}", e),
            &PortMidi(ref e) => write!(f, "PortMidi error: {:?}", e),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &NoAudioDevices => "No audio devices found.",
            &NoMidiDevices => "No midi devices found.",
            &InvalidFile => "The provided was not valid.",
            &OutOfRange(_) => "Index was out of range.",
            &CreatesCycle => "The requested action creates a graph cycle.",
            &Unsupported(_) => "Unsupported feature.",
            &Io(_) => "std::io error",
            &PortAudio(_) => "PortAudio error",
            &PortMidi(_) => "PortMidi error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &Io(ref e) => Some(e),
            &PortAudio(ref e) => Some(e),
            // I would like this to be here, but PortMidiError does not
            // implement Error...
            // &PortMidi(ref e) => Some(e),
            _ => None,
        }
    }
}

pub type Result<T> = result::Result<T, Error>;
<|endoftext|>


<commit_before>use std::ffi::CString;

/// A `dlerror` error.
pub struct DlDescription(pub(crate) CString);

impl std::fmt::Debug for DlDescription {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Debug::fmt(&self.0, f)
    }
}

/// A Windows API error.
pub struct WindowsError(pub(crate) std::io::Error);

impl std::fmt::Debug for WindowsError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Debug::fmt(&self.0, f)
    }
}

/// Errors.
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
    /// The `dlopen` call failed.
    DlOpen {
        /// The source error.
        desc: DlDescription
    },
    /// The `dlopen` call failed and system did not report an error.
    DlOpenUnknown,
    /// The `dlsym` call failed.
    DlSym {
        /// The source error.
        desc: DlDescription
    },
    /// The `dlsym` call failed and system did not report an error.
    DlSymUnknown,
    /// The `dlclose` call failed.
    DlClose {
        /// The source error.
        desc: DlDescription
    },
    /// The `dlclose` call failed and system did not report an error.
    DlCloseUnknown,
    /// The `LoadLibraryW` call failed.
    LoadLibraryW {
        /// The source error.
        source: WindowsError
    },
    /// The `LoadLibraryW` call failed and system did not report an error.
    LoadLibraryWUnknown,
    /// The `GetModuleHandleExW` call failed.
    GetModuleHandleExW {
        /// The source error.
        source: WindowsError
    },
    /// The `LoadLibraryW` call failed and system did not report an error.
    GetModuleHandleExWUnknown,
    /// The `GetProcAddress` call failed.
    GetProcAddress {
        /// The source error.
        source: WindowsError
    },
    /// The `GetProcAddressUnknown` call failed and system did not report an error.
    GetProcAddressUnknown,
    /// The `FreeLibrary` call failed.
    FreeLibrary {
        /// The source error.
        source: WindowsError
    },
    /// The `FreeLibrary` call failed and system did not report an error.
    FreeLibraryUnknown,
    /// The requested type cannot possibly work.
    IncompatibleSize,
    /// Could not create a new CString.
    CreateCString {
        /// The source error.
        source: std::ffi::NulError
    },
    /// Could not create a new CString from bytes with trailing null.
    CreateCStringWithTrailing {
        /// The source error.
        source: std::ffi::FromBytesWithNulError
    },
}

impl std::error::Error for Error {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use Error::*;
        match *self {
            CreateCString { ref source } => Some(source),
            CreateCStringWithTrailing { ref source } => Some(source),
            LoadLibraryW { ref source } => Some(&source.0),
            GetProcAddress { ref source } => Some(&source.0),
            FreeLibrary { ref source } => Some(&source.0),
            _ => None,
        }
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use Error::*;
        match *self {
            DlOpen { ref desc } => write!(f, "{}", desc.0.to_string_lossy()),
            DlOpenUnknown => write!(f, "dlopen failed, but system did not report the error"),
            DlSym { ref desc } => write!(f, "{}", desc.0.to_string_lossy()),
            DlSymUnknown => write!(f, "dlsym failed, but system did not report the error"),
            DlClose { ref desc } => write!(f, "{}", desc.0.to_string_lossy()),
            DlCloseUnknown => write!(f, "dlclose failed, but system did not report the error"),
            LoadLibraryW { .. } => write!(f, "LoadLibraryExW failed"),
            LoadLibraryWUnknown =>
                write!(f, "LoadLibraryExW failed, but system did not report the error"),
            GetModuleHandleExW { .. } => write!(f, "GetModuleHandleExW failed"),
            GetModuleHandleExWUnknown =>
                write!(f, "GetModuleHandleExWUnknown failed, but system did not report the error"),
            GetProcAddress { .. } => write!(f, "GetProcAddress failed"),
            GetProcAddressUnknown =>
                write!(f, "GetProcAddress failed, but system did not report the error"),
            FreeLibrary { .. } => write!(f, "FreeLibrary failed"),
            FreeLibraryUnknown =>
                write!(f, "FreeLibrary failed, but system did not report the error"),
            CreateCString { .. } => write!(f, "could not create a C string from bytes"),
            CreateCStringWithTrailing { .. } =>
                write!(f, "could not create a C string from bytes with trailing null"),
            IncompatibleSize => write!(f, "requested type cannot possibly work"),
        }
    }
}
<commit_msg>Fix error comment<commit_after>use std::ffi::CString;

/// A `dlerror` error.
pub struct DlDescription(pub(crate) CString);

impl std::fmt::Debug for DlDescription {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Debug::fmt(&self.0, f)
    }
}

/// A Windows API error.
pub struct WindowsError(pub(crate) std::io::Error);

impl std::fmt::Debug for WindowsError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Debug::fmt(&self.0, f)
    }
}

/// Errors.
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
    /// The `dlopen` call failed.
    DlOpen {
        /// The source error.
        desc: DlDescription
    },
    /// The `dlopen` call failed and system did not report an error.
    DlOpenUnknown,
    /// The `dlsym` call failed.
    DlSym {
        /// The source error.
        desc: DlDescription
    },
    /// The `dlsym` call failed and system did not report an error.
    DlSymUnknown,
    /// The `dlclose` call failed.
    DlClose {
        /// The source error.
        desc: DlDescription
    },
    /// The `dlclose` call failed and system did not report an error.
    DlCloseUnknown,
    /// The `LoadLibraryW` call failed.
    LoadLibraryW {
        /// The source error.
        source: WindowsError
    },
    /// The `LoadLibraryW` call failed and system did not report an error.
    LoadLibraryWUnknown,
    /// The `GetModuleHandleExW` call failed.
    GetModuleHandleExW {
        /// The source error.
        source: WindowsError
    },
    /// The `GetModuleHandleExW` call failed and system did not report an error.
    GetModuleHandleExWUnknown,
    /// The `GetProcAddress` call failed.
    GetProcAddress {
        /// The source error.
        source: WindowsError
    },
    /// The `GetProcAddressUnknown` call failed and system did not report an error.
    GetProcAddressUnknown,
    /// The `FreeLibrary` call failed.
    FreeLibrary {
        /// The source error.
        source: WindowsError
    },
    /// The `FreeLibrary` call failed and system did not report an error.
    FreeLibraryUnknown,
    /// The requested type cannot possibly work.
    IncompatibleSize,
    /// Could not create a new CString.
    CreateCString {
        /// The source error.
        source: std::ffi::NulError
    },
    /// Could not create a new CString from bytes with trailing null.
    CreateCStringWithTrailing {
        /// The source error.
        source: std::ffi::FromBytesWithNulError
    },
}

impl std::error::Error for Error {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use Error::*;
        match *self {
            CreateCString { ref source } => Some(source),
            CreateCStringWithTrailing { ref source } => Some(source),
            LoadLibraryW { ref source } => Some(&source.0),
            GetProcAddress { ref source } => Some(&source.0),
            FreeLibrary { ref source } => Some(&source.0),
            _ => None,
        }
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use Error::*;
        match *self {
            DlOpen { ref desc } => write!(f, "{}", desc.0.to_string_lossy()),
            DlOpenUnknown => write!(f, "dlopen failed, but system did not report the error"),
            DlSym { ref desc } => write!(f, "{}", desc.0.to_string_lossy()),
            DlSymUnknown => write!(f, "dlsym failed, but system did not report the error"),
            DlClose { ref desc } => write!(f, "{}", desc.0.to_string_lossy()),
            DlCloseUnknown => write!(f, "dlclose failed, but system did not report the error"),
            LoadLibraryW { .. } => write!(f, "LoadLibraryExW failed"),
            LoadLibraryWUnknown =>
                write!(f, "LoadLibraryExW failed, but system did not report the error"),
            GetModuleHandleExW { .. } => write!(f, "GetModuleHandleExW failed"),
            GetModuleHandleExWUnknown =>
                write!(f, "GetModuleHandleExWUnknown failed, but system did not report the error"),
            GetProcAddress { .. } => write!(f, "GetProcAddress failed"),
            GetProcAddressUnknown =>
                write!(f, "GetProcAddress failed, but system did not report the error"),
            FreeLibrary { .. } => write!(f, "FreeLibrary failed"),
            FreeLibraryUnknown =>
                write!(f, "FreeLibrary failed, but system did not report the error"),
            CreateCString { .. } => write!(f, "could not create a C string from bytes"),
            CreateCStringWithTrailing { .. } =>
                write!(f, "could not create a C string from bytes with trailing null"),
            IncompatibleSize => write!(f, "requested type cannot possibly work"),
        }
    }
}
<|endoftext|>