<commit_before>// Copyright (c) 2016 Stu Small
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

extern crate byteorder;

use std::io::Cursor;
use std::io::Read;
use byteorder::{LittleEndian, ReadBytesExt, ByteOrder};

pub fn murmur3_32<T :Read>(source: &mut T, seed: u32) -> u32 {
    const C1: u32 = 0x85ebca6b;
    const C2: u32 = 0xc2b2ae35;
    const R1: u32 = 16;
    const R2: u32 = 13;
    const M: u32 = 5;
    const N: u32 = 0xe6546b64;
    let mut hash = seed;
    let mut buf = [0; 4];
    let mut processed: u32 = 0;
    loop {
        match source.read(&mut buf[..]) {
            Ok(size) => {
                match size {
                    4 => {
                        let mut tmp = Cursor::new(buf);
                        let k = tmp.read_u32::<LittleEndian>().unwrap();
                        hash ^= calc_k(k);
                        hash = hash.rotate_left(R2);
                        hash = (hash.wrapping_mul(M)).wrapping_add(N);
                    }
                    3 => {
                        let k: u32 = ((buf[2] as u32) << 16) | ((buf[1] as u32) << 8) |
                                     (buf[0] as u32);
                        hash ^= calc_k(k);
                    }
                    2 => {
                        let k: u32 = ((buf[1] as u32) << 8) | (buf[0] as u32);
                        hash ^= calc_k(k);
                    }
                    1 => {
                        let k: u32 = buf[0] as u32;
                        hash ^= calc_k(k);
                    }
                    0 => {
                        hash ^= (processed) as u32;
                        hash ^= hash.wrapping_shr(R1);
                        hash = hash.wrapping_mul(C1);
                        hash ^= hash.wrapping_shr(R2);
                        hash = hash.wrapping_mul(C2);
                        hash ^= hash.wrapping_shr(R1);
                        return hash;
                    }
                    _ => panic!("Invalid read size!"),
                };
                processed += size as u32;
            }
            Err(e) => panic!(e),
        }
    }
}

fn calc_k(k: u32) -> u32 {
    const C1: u32 = 0xcc9e2d51;
    const C2: u32 = 0x1b873593;
    const R1: u32 = 15;
    k.wrapping_mul(C1).rotate_left(R1).wrapping_mul(C2)
}

pub fn murmur3_x86_128<T :Read>(source: &mut T, seed: u32, out: &mut [u8]) {
    const C1: u32 = 0x239b961b;
    const C2: u32 = 0xab0e9789;
    const C3: u32 = 0x38b34ae5;
    const C4: u32 = 0xa1e38b93;
    const C5: u32 = 0x561ccd1b;
    const C6: u32 = 0x0bcaa747;
    const C7: u32 = 0x96cd1c35;
    const C8: u32 = 0x32ac3b17;
    const M: u32 = 5;

    let mut h1: u32 = seed;
    let mut h2: u32 = seed;
    let mut h3: u32 = seed;
    let mut h4: u32 = seed;

    let mut buf = [0; 16];
    let mut processed: u32 = 0;

    if out.len() < 16 {
        panic!("Invalid out buffer size");
    }

    loop {
        match source.read(&mut buf[..]) {
            Ok(size) => {
                match size {
                    16 => {
                        let k1: u32 = LittleEndian::read_u32(&buf[0..4]);
                        let k2: u32 = LittleEndian::read_u32(&buf[4..8]);
                        let k3: u32 = LittleEndian::read_u32(&buf[8..12]);
                        let k4: u32 = LittleEndian::read_u32(&buf[12..16]);
                        h1 ^= k1.wrapping_mul(C1).rotate_left(15).wrapping_mul(C2);
                        h1 = h1.rotate_left(19).wrapping_add(h2).wrapping_mul(M).wrapping_add(C5);
                        h2 ^= k2.wrapping_mul(C2).rotate_left(16).wrapping_mul(C3);
                        h2 = h2.rotate_left(17).wrapping_add(h3).wrapping_mul(M).wrapping_add(C6);
                        h3 ^= k3.wrapping_mul(C3).rotate_left(17).wrapping_mul(C4);
                        h3 = h3.rotate_left(15).wrapping_add(h4).wrapping_mul(M).wrapping_add(C7);
                        h4 ^= k4.wrapping_mul(C4).rotate_left(18).wrapping_mul(C1);
                        h4 = h4.rotate_left(13).wrapping_add(h1).wrapping_mul(M).wrapping_add(C8);
                    }
                    13...15 => {
                        h1 ^= process_h1_k_x86(LittleEndian::read_u32(&buf[0..4]));
                        h2 ^= process_h2_k_x86(LittleEndian::read_u32(&buf[4..8]));
                        h3 ^= process_h3_k_x86(LittleEndian::read_u32(&buf[8..12]));
                        h4 ^= process_h4_k_x86(LittleEndian::read_int(&buf[12..size], size -12) as u32);
                    }
                    12 => {
                        h1 ^= process_h1_k_x86(LittleEndian::read_u32(&buf[0..4]));
                        h2 ^= process_h2_k_x86(LittleEndian::read_u32(&buf[4..8]));
                        h3 ^= process_h3_k_x86(LittleEndian::read_u32(&buf[8..12]));
                    }
                    9...11 => {
                        h1 ^= process_h1_k_x86(LittleEndian::read_u32(&buf[0..4]));
                        h2 ^= process_h2_k_x86(LittleEndian::read_u32(&buf[4..8]));
                        h3 ^= process_h3_k_x86(LittleEndian::read_int(&buf[8..size], size -8) as u32);
                    }
                    8 => {
                        h1 ^= process_h1_k_x86(LittleEndian::read_u32(&buf[0..4]));
                        h2 ^= process_h2_k_x86(LittleEndian::read_u32(&buf[4..8]));
                    }
                    5...7 => {
                        h1 ^= process_h1_k_x86(LittleEndian::read_u32(&buf[0..4]));
                        h2 ^= process_h2_k_x86(LittleEndian::read_int(&buf[4..size], size-4) as u32);
                    }
                    4 => {
                        h1 ^= process_h1_k_x86(LittleEndian::read_u32(&buf));
                    }
                    1...3 => {
                        h1 ^= process_h1_k_x86(LittleEndian::read_int(&buf, size) as u32);
                    }
                    0 => {
                        h1 ^= processed;
                        h2 ^= processed;
                        h3 ^= processed;
                        h4 ^= processed;
                        h1 = h1.wrapping_add(h2);
                        h1 = h1.wrapping_add(h3);
                        h1 = h1.wrapping_add(h4);
                        h2 = h2.wrapping_add(h1);
                        h3 = h3.wrapping_add(h1);
                        h4 = h4.wrapping_add(h1);
                        h1 = fmix32(h1);
                        h2 = fmix32(h2);
                        h3 = fmix32(h3);
                        h4 = fmix32(h4);
                        h1 = h1.wrapping_add(h2);
                        h1 = h1.wrapping_add(h3);
                        h1 = h1.wrapping_add(h4);
                        h2 = h2.wrapping_add(h1);
                        h3 = h3.wrapping_add(h1);
                        h4 = h4.wrapping_add(h1);
                        LittleEndian::write_u32(&mut out[0..], h1);
                        LittleEndian::write_u32(&mut out[4..], h2);
                        LittleEndian::write_u32(&mut out[8..], h3);
                        LittleEndian::write_u32(&mut out[12..], h4);
                        return;
                    }
                    _ => {
                        panic!("Invalid read!");
                    }
                }
                processed += size as u32;
            }
            Err(e) => panic!(e),
        }
    }
}

fn process_h1_k_x86(k: u32) -> u32 {
    const C1: u32 = 0x239b961b;
    const C2: u32 = 0xab0e9789;
    k.wrapping_mul(C1).rotate_left(15).wrapping_mul(C2)
}

fn process_h2_k_x86(k: u32) -> u32 {
    const C2: u32 = 0xab0e9789;
    const C3: u32 = 0x38b34ae5;
    k.wrapping_mul(C2).rotate_left(16).wrapping_mul(C3)
}

fn process_h3_k_x86(k: u32) -> u32 {
    const C3: u32 = 0x38b34ae5;
    const C4: u32 = 0xa1e38b93;
    k.wrapping_mul(C3).rotate_left(17).wrapping_mul(C4)
}

fn process_h4_k_x86(k: u32) -> u32 {
    const C1: u32 = 0x239b961b;
    const C4: u32 = 0xa1e38b93;
    k.wrapping_mul(C4).rotate_left(18).wrapping_mul(C1)
}

fn fmix32(k: u32) -> u32 {
    const C1: u32 = 0x85ebca6b;
    const C2: u32 = 0xc2b2ae35;
    const R1: u32 = 16;
    const R2: u32 = 13;
    let mut tmp = k;
    tmp ^= tmp >> R1;
    tmp = tmp.wrapping_mul(C1);
    tmp ^= tmp >> R2;
    tmp = tmp.wrapping_mul(C2);
    tmp ^= tmp >> R1;
    tmp
}

pub fn murmur3_x64_128<T:Read>(source: &mut T, seed: u32, out: &mut [u8]) {
    const C1: u64 = 0x52dce729;
    const C2: u64 = 0x38495ab5;
    const R1: u32 = 27;
    const R2: u32 = 31;
    const M: u64 = 5;
    let mut h1: u64 = seed as u64;
    let mut h2: u64 = seed as u64;
    let mut buf = [0; 16];
    let mut processed: u32 = 0;
    if out.len() < 16 {
        panic!("Invalid out buffer size");
    }
    loop {
        match source.read(&mut buf[..]) {
            Ok(size) => {
                match size {
                    16 => {
                        let k1 = LittleEndian::read_u64(&buf[0..8]);
                        let k2 = LittleEndian::read_u64(&buf[8..]);
                        h1 ^= process_h1_k_x64(k1);
                        h1 = h1.rotate_left(R1).wrapping_add(h2).wrapping_mul(M).wrapping_add(C1);
                        h2 ^= process_h2_k_x64(k2);
                        h2 = h2.rotate_left(R2).wrapping_add(h1).wrapping_mul(M).wrapping_add(C2);
                    }
                    9...15 => {
                        h1 ^= process_h1_k_x64(LittleEndian::read_u64(&buf[0..8]));
                        h2 ^= process_h2_k_x64(LittleEndian::read_int(&buf[8..], size - 8) as u64);
                    }
                    8 => {
                        h1 ^= process_h1_k_x64(LittleEndian::read_u64(&buf));
                    }
                    1...7 => {
                        h1 ^= process_h1_k_x64(LittleEndian::read_int(&buf, size) as u64);
                    }
                    0 => {
                        h1 ^= processed as u64;
                        h2 ^= processed as u64;
                        h1 = h1.wrapping_add(h2);
                        h2 = h2.wrapping_add(h1);
                        h1 = fmix64(h1);
                        h2 = fmix64(h2);
                        h1 = h1.wrapping_add(h2);
                        h2 = h2.wrapping_add(h1);
                        LittleEndian::write_u64(&mut out[0..], h1);
                        LittleEndian::write_u64(&mut out[8..], h2);
                        return;
                    }
                    _ => {
                        panic!("Invalid read");
                    }
                }
                processed += size as u32;
            }
            Err(e) => panic!(e),
        }
    }
}

fn process_h1_k_x64(k: u64) -> u64 {
    const C1: u64 = 0x87c37b91114253d5;
    const C2: u64 = 0x4cf5ad432745937f;
    const R: u32 = 31;
    k.wrapping_mul(C1).rotate_left(R).wrapping_mul(C2)
}

fn process_h2_k_x64(k: u64) -> u64 {
    const C1: u64 = 0x87c37b91114253d5;
    const C2: u64 = 0x4cf5ad432745937f;
    const R: u32 = 33;
    k.wrapping_mul(C2).rotate_left(R).wrapping_mul(C1)
}

fn fmix64(k: u64) -> u64 {
    const C1: u64 = 0xff51afd7ed558ccd;
    const C2: u64 = 0xc4ceb9fe1a85ec53;
    const R: u32 = 33;
    let mut tmp = k;
    tmp ^= tmp >> R;
    tmp = tmp.wrapping_mul(C1);
    tmp ^= tmp >> R;
    tmp = tmp.wrapping_mul(C2);
    tmp ^= tmp >> R;
    tmp
}
<commit_msg>Remove ReadBytesExt<commit_after>// Copyright (c) 2016 Stu Small
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

extern crate byteorder;

use std::io::Cursor;
use std::io::Read;
use byteorder::{LittleEndian, ByteOrder};

pub fn murmur3_32<T :Read>(source: &mut T, seed: u32) -> u32 {
    const C1: u32 = 0x85ebca6b;
    const C2: u32 = 0xc2b2ae35;
    const R1: u32 = 16;
    const R2: u32 = 13;
    const M: u32 = 5;
    const N: u32 = 0xe6546b64;
    let mut hash = seed;
    let mut buf = [0; 4];
    let mut processed: u32 = 0;
    loop {
        match source.read(&mut buf[..]) {
            Ok(size) => {
                match size {
                    4 => {
                        let k = LittleEndian::read_u32(&buf);
                        hash ^= calc_k(k);
                        hash = hash.rotate_left(R2);
                        hash = (hash.wrapping_mul(M)).wrapping_add(N);
                    }
                    3 => {
                        let k: u32 = ((buf[2] as u32) << 16) | ((buf[1] as u32) << 8) |
                                     (buf[0] as u32);
                        hash ^= calc_k(k);
                    }
                    2 => {
                        let k: u32 = ((buf[1] as u32) << 8) | (buf[0] as u32);
                        hash ^= calc_k(k);
                    }
                    1 => {
                        let k: u32 = buf[0] as u32;
                        hash ^= calc_k(k);
                    }
                    0 => {
                        hash ^= (processed) as u32;
                        hash ^= hash.wrapping_shr(R1);
                        hash = hash.wrapping_mul(C1);
                        hash ^= hash.wrapping_shr(R2);
                        hash = hash.wrapping_mul(C2);
                        hash ^= hash.wrapping_shr(R1);
                        return hash;
                    }
                    _ => panic!("Invalid read size!"),
                };
                processed += size as u32;
            }
            Err(e) => panic!(e),
        }
    }
}

fn calc_k(k: u32) -> u32 {
    const C1: u32 = 0xcc9e2d51;
    const C2: u32 = 0x1b873593;
    const R1: u32 = 15;
    k.wrapping_mul(C1).rotate_left(R1).wrapping_mul(C2)
}

pub fn murmur3_x86_128<T :Read>(source: &mut T, seed: u32, out: &mut [u8]) {
    const C1: u32 = 0x239b961b;
    const C2: u32 = 0xab0e9789;
    const C3: u32 = 0x38b34ae5;
    const C4: u32 = 0xa1e38b93;
    const C5: u32 = 0x561ccd1b;
    const C6: u32 = 0x0bcaa747;
    const C7: u32 = 0x96cd1c35;
    const C8: u32 = 0x32ac3b17;
    const M: u32 = 5;

    let mut h1: u32 = seed;
    let mut h2: u32 = seed;
    let mut h3: u32 = seed;
    let mut h4: u32 = seed;

    let mut buf = [0; 16];
    let mut processed: u32 = 0;

    if out.len() < 16 {
        panic!("Invalid out buffer size");
    }

    loop {
        match source.read(&mut buf[..]) {
            Ok(size) => {
                match size {
                    16 => {
                        let k1: u32 = LittleEndian::read_u32(&buf[0..4]);
                        let k2: u32 = LittleEndian::read_u32(&buf[4..8]);
                        let k3: u32 = LittleEndian::read_u32(&buf[8..12]);
                        let k4: u32 = LittleEndian::read_u32(&buf[12..16]);
                        h1 ^= k1.wrapping_mul(C1).rotate_left(15).wrapping_mul(C2);
                        h1 = h1.rotate_left(19).wrapping_add(h2).wrapping_mul(M).wrapping_add(C5);
                        h2 ^= k2.wrapping_mul(C2).rotate_left(16).wrapping_mul(C3);
                        h2 = h2.rotate_left(17).wrapping_add(h3).wrapping_mul(M).wrapping_add(C6);
                        h3 ^= k3.wrapping_mul(C3).rotate_left(17).wrapping_mul(C4);
                        h3 = h3.rotate_left(15).wrapping_add(h4).wrapping_mul(M).wrapping_add(C7);
                        h4 ^= k4.wrapping_mul(C4).rotate_left(18).wrapping_mul(C1);
                        h4 = h4.rotate_left(13).wrapping_add(h1).wrapping_mul(M).wrapping_add(C8);
                    }
                    13...15 => {
                        h1 ^= process_h1_k_x86(LittleEndian::read_u32(&buf[0..4]));
                        h2 ^= process_h2_k_x86(LittleEndian::read_u32(&buf[4..8]));
                        h3 ^= process_h3_k_x86(LittleEndian::read_u32(&buf[8..12]));
                        h4 ^= process_h4_k_x86(LittleEndian::read_int(&buf[12..size], size -12) as u32);
                    }
                    12 => {
                        h1 ^= process_h1_k_x86(LittleEndian::read_u32(&buf[0..4]));
                        h2 ^= process_h2_k_x86(LittleEndian::read_u32(&buf[4..8]));
                        h3 ^= process_h3_k_x86(LittleEndian::read_u32(&buf[8..12]));
                    }
                    9...11 => {
                        h1 ^= process_h1_k_x86(LittleEndian::read_u32(&buf[0..4]));
                        h2 ^= process_h2_k_x86(LittleEndian::read_u32(&buf[4..8]));
                        h3 ^= process_h3_k_x86(LittleEndian::read_int(&buf[8..size], size -8) as u32);
                    }
                    8 => {
                        h1 ^= process_h1_k_x86(LittleEndian::read_u32(&buf[0..4]));
                        h2 ^= process_h2_k_x86(LittleEndian::read_u32(&buf[4..8]));
                    }
                    5...7 => {
                        h1 ^= process_h1_k_x86(LittleEndian::read_u32(&buf[0..4]));
                        h2 ^= process_h2_k_x86(LittleEndian::read_int(&buf[4..size], size-4) as u32);
                    }
                    4 => {
                        h1 ^= process_h1_k_x86(LittleEndian::read_u32(&buf));
                    }
                    1...3 => {
                        h1 ^= process_h1_k_x86(LittleEndian::read_int(&buf, size) as u32);
                    }
                    0 => {
                        h1 ^= processed;
                        h2 ^= processed;
                        h3 ^= processed;
                        h4 ^= processed;
                        h1 = h1.wrapping_add(h2);
                        h1 = h1.wrapping_add(h3);
                        h1 = h1.wrapping_add(h4);
                        h2 = h2.wrapping_add(h1);
                        h3 = h3.wrapping_add(h1);
                        h4 = h4.wrapping_add(h1);
                        h1 = fmix32(h1);
                        h2 = fmix32(h2);
                        h3 = fmix32(h3);
                        h4 = fmix32(h4);
                        h1 = h1.wrapping_add(h2);
                        h1 = h1.wrapping_add(h3);
                        h1 = h1.wrapping_add(h4);
                        h2 = h2.wrapping_add(h1);
                        h3 = h3.wrapping_add(h1);
                        h4 = h4.wrapping_add(h1);
                        LittleEndian::write_u32(&mut out[0..], h1);
                        LittleEndian::write_u32(&mut out[4..], h2);
                        LittleEndian::write_u32(&mut out[8..], h3);
                        LittleEndian::write_u32(&mut out[12..], h4);
                        return;
                    }
                    _ => {
                        panic!("Invalid read!");
                    }
                }
                processed += size as u32;
            }
            Err(e) => panic!(e),
        }
    }
}

fn process_h1_k_x86(k: u32) -> u32 {
    const C1: u32 = 0x239b961b;
    const C2: u32 = 0xab0e9789;
    k.wrapping_mul(C1).rotate_left(15).wrapping_mul(C2)
}

fn process_h2_k_x86(k: u32) -> u32 {
    const C2: u32 = 0xab0e9789;
    const C3: u32 = 0x38b34ae5;
    k.wrapping_mul(C2).rotate_left(16).wrapping_mul(C3)
}

fn process_h3_k_x86(k: u32) -> u32 {
    const C3: u32 = 0x38b34ae5;
    const C4: u32 = 0xa1e38b93;
    k.wrapping_mul(C3).rotate_left(17).wrapping_mul(C4)
}

fn process_h4_k_x86(k: u32) -> u32 {
    const C1: u32 = 0x239b961b;
    const C4: u32 = 0xa1e38b93;
    k.wrapping_mul(C4).rotate_left(18).wrapping_mul(C1)
}

fn fmix32(k: u32) -> u32 {
    const C1: u32 = 0x85ebca6b;
    const C2: u32 = 0xc2b2ae35;
    const R1: u32 = 16;
    const R2: u32 = 13;
    let mut tmp = k;
    tmp ^= tmp >> R1;
    tmp = tmp.wrapping_mul(C1);
    tmp ^= tmp >> R2;
    tmp = tmp.wrapping_mul(C2);
    tmp ^= tmp >> R1;
    tmp
}

pub fn murmur3_x64_128<T:Read>(source: &mut T, seed: u32, out: &mut [u8]) {
    const C1: u64 = 0x52dce729;
    const C2: u64 = 0x38495ab5;
    const R1: u32 = 27;
    const R2: u32 = 31;
    const M: u64 = 5;
    let mut h1: u64 = seed as u64;
    let mut h2: u64 = seed as u64;
    let mut buf = [0; 16];
    let mut processed: u32 = 0;
    if out.len() < 16 {
        panic!("Invalid out buffer size");
    }
    loop {
        match source.read(&mut buf[..]) {
            Ok(size) => {
                match size {
                    16 => {
                        let k1 = LittleEndian::read_u64(&buf[0..8]);
                        let k2 = LittleEndian::read_u64(&buf[8..]);
                        h1 ^= process_h1_k_x64(k1);
                        h1 = h1.rotate_left(R1).wrapping_add(h2).wrapping_mul(M).wrapping_add(C1);
                        h2 ^= process_h2_k_x64(k2);
                        h2 = h2.rotate_left(R2).wrapping_add(h1).wrapping_mul(M).wrapping_add(C2);
                    }
                    9...15 => {
                        h1 ^= process_h1_k_x64(LittleEndian::read_u64(&buf[0..8]));
                        h2 ^= process_h2_k_x64(LittleEndian::read_int(&buf[8..], size - 8) as u64);
                    }
                    8 => {
                        h1 ^= process_h1_k_x64(LittleEndian::read_u64(&buf));
                    }
                    1...7 => {
                        h1 ^= process_h1_k_x64(LittleEndian::read_int(&buf, size) as u64);
                    }
                    0 => {
                        h1 ^= processed as u64;
                        h2 ^= processed as u64;
                        h1 = h1.wrapping_add(h2);
                        h2 = h2.wrapping_add(h1);
                        h1 = fmix64(h1);
                        h2 = fmix64(h2);
                        h1 = h1.wrapping_add(h2);
                        h2 = h2.wrapping_add(h1);
                        LittleEndian::write_u64(&mut out[0..], h1);
                        LittleEndian::write_u64(&mut out[8..], h2);
                        return;
                    }
                    _ => {
                        panic!("Invalid read");
                    }
                }
                processed += size as u32;
            }
            Err(e) => panic!(e),
        }
    }
}

fn process_h1_k_x64(k: u64) -> u64 {
    const C1: u64 = 0x87c37b91114253d5;
    const C2: u64 = 0x4cf5ad432745937f;
    const R: u32 = 31;
    k.wrapping_mul(C1).rotate_left(R).wrapping_mul(C2)
}

fn process_h2_k_x64(k: u64) -> u64 {
    const C1: u64 = 0x87c37b91114253d5;
    const C2: u64 = 0x4cf5ad432745937f;
    const R: u32 = 33;
    k.wrapping_mul(C2).rotate_left(R).wrapping_mul(C1)
}

fn fmix64(k: u64) -> u64 {
    const C1: u64 = 0xff51afd7ed558ccd;
    const C2: u64 = 0xc4ceb9fe1a85ec53;
    const R: u32 = 33;
    let mut tmp = k;
    tmp ^= tmp >> R;
    tmp = tmp.wrapping_mul(C1);
    tmp ^= tmp >> R;
    tmp = tmp.wrapping_mul(C2);
    tmp ^= tmp >> R;
    tmp
}
<|endoftext|>


<commit_before>//! High performance XML reader/writer.
//!
//! ## Description
//!
//! - `Reader`: a low level xml pull-reader where buffer allocation/clearing is left to user
//! - `Writer`: a xml writer. Can be nested with readers if you want to transform xmls
//!
//! ## Examples
//!
//! ### Reader
//!
//! ```rust
//! use quick_xml::Reader;
//! use quick_xml::events::Event;
//!
//! let xml = r#"<tag1 att1 = "test">
//!                 <tag2><!--Test comment-->Test</tag2>
//!                 <tag2>
//!                     Test 2
//!                 </tag2>
//!             </tag1>"#;
//!
//! let mut reader = Reader::from_str(xml);
//! reader.trim_text(true);
//!
//! let mut count = 0;
//! let mut txt = Vec::new();
//! let mut buf = Vec::new();
//!
//! // The `Reader` does not implement `Iterator` because it outputs borrowed data (`Cow`s)
//! loop {
//!     match reader.read_event(&mut buf) {
//!     // for triggering namespaced events, use this instead:
//!     // match reader.read_namespaced_event(&mut buf) {
//!         Ok(Event::Start(ref e)) => {
//!         // for namespaced:
//!         // Ok((ref namespace_value, Event::Start(ref e)))
//!             match e.name() {
//!                 b"tag1" => println!("attributes values: {:?}",
//!                                     e.attributes().map(|a| a.unwrap().value)
//!                                     .collect::<Vec<_>>()),
//!                 b"tag2" => count += 1,
//!                 _ => (),
//!             }
//!         },
//!         // unescape and decode the text event using the reader encoding
//!         Ok(Event::Text(e)) => txt.push(e.unescape_and_decode(&reader).unwrap()),
//!         Ok(Event::Eof) => break, // exits the loop when reaching end of file
//!         Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
//!         _ => (), // There are several other `Event`s we do not consider here
//!     }
//!
//!     // if we don't keep a borrow elsewhere, we can clear the buffer to keep memory usage low
//!     buf.clear();
//! }
//! ```
//!
//! ### Writer
//!
//! ```rust
//! use quick_xml::Writer;
//! use quick_xml::events::{Event, BytesEnd, BytesStart};
//! use quick_xml::Reader;
//! use std::io::Cursor;
//! use std::iter;
//!
//! let xml = r#"<this_tag k1="v1" k2="v2"><child>text</child></this_tag>"#;
//! let mut reader = Reader::from_str(xml);
//! reader.trim_text(true);
//! let mut writer = Writer::new(Cursor::new(Vec::new()));
//! let mut buf = Vec::new();
//! loop {
//!     match reader.read_event(&mut buf) {
//!         Ok(Event::Start(ref e)) if e.name() == b"this_tag" => {
//!
//!             // crates a new element ... alternatively we could reuse `e` by calling
//!             // `e.into_owned()`
//!             let mut elem = BytesStart::owned(b"my_elem".to_vec(), "my_elem".len());
//!
//!             // collect existing attributes
//!             elem.extend_attributes(e.attributes().map(|attr| attr.unwrap()));
//!
//!             // copy existing attributes, adds a new my-key="some value" attribute
//!             elem.push_attribute(("my-key", "some value"));
//!
//!             // writes the event to the writer
//!             assert!(writer.write_event(Event::Start(elem)).is_ok());
//!         },
//!         Ok(Event::End(ref e)) if e.name() == b"this_tag" => {
//!             assert!(writer.write_event(Event::End(BytesEnd::borrowed(b"my_elem"))).is_ok());
//!         },
//!         Ok(Event::Eof) => break,
//!         Ok(e) => assert!(writer.write_event(e).is_ok()),
//!         // or using the buffer
//!         // Ok(e) => assert!(writer.write(&buf).is_ok()),
//!         Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
//!     }
//!     buf.clear();
//! }
//!
//! let result = writer.into_inner().into_inner();
//! let expected = r#"<my_elem k1="v1" k2="v2" my-key="some value"><child>text</child></my_elem>"#;
//! assert_eq!(result, expected.as_bytes());
//! ```
//!
//! # Features
//!
//! quick-xml supports 2 additional features, non activated by default:
//! - `encoding`: support non utf8 xmls
//! - `serialize`: support serde `Serialize`/`Deserialize`
#![deny(missing_docs)]
#![recursion_limit = "1024"]

#[cfg(feature = "encoding_rs")]
extern crate encoding_rs;
extern crate memchr;
#[cfg(feature = "serialize")]
extern crate serde;

#[cfg(feature = "serialize")]
pub mod de;
mod errors;
mod escapei;
pub mod escape {
    //! Manage xml character escapes
    pub(crate) use escapei::EscapeError;
    pub use escapei::{escape, unescape};
}
pub mod events;
mod reader;
#[cfg(feature = "serialize")]
pub mod se;
mod utils;
mod writer;

// reexports
#[cfg(feature = "serialize")]
pub use errors::serialize::DeError;
pub use errors::{Error, Result};
pub use reader::Reader;
pub use writer::Writer;
<commit_msg>Forbid unsafe code<commit_after>//! High performance XML reader/writer.
//!
//! ## Description
//!
//! - `Reader`: a low level xml pull-reader where buffer allocation/clearing is left to user
//! - `Writer`: a xml writer. Can be nested with readers if you want to transform xmls
//!
//! ## Examples
//!
//! ### Reader
//!
//! ```rust
//! use quick_xml::Reader;
//! use quick_xml::events::Event;
//!
//! let xml = r#"<tag1 att1 = "test">
//!                 <tag2><!--Test comment-->Test</tag2>
//!                 <tag2>
//!                     Test 2
//!                 </tag2>
//!             </tag1>"#;
//!
//! let mut reader = Reader::from_str(xml);
//! reader.trim_text(true);
//!
//! let mut count = 0;
//! let mut txt = Vec::new();
//! let mut buf = Vec::new();
//!
//! // The `Reader` does not implement `Iterator` because it outputs borrowed data (`Cow`s)
//! loop {
//!     match reader.read_event(&mut buf) {
//!     // for triggering namespaced events, use this instead:
//!     // match reader.read_namespaced_event(&mut buf) {
//!         Ok(Event::Start(ref e)) => {
//!         // for namespaced:
//!         // Ok((ref namespace_value, Event::Start(ref e)))
//!             match e.name() {
//!                 b"tag1" => println!("attributes values: {:?}",
//!                                     e.attributes().map(|a| a.unwrap().value)
//!                                     .collect::<Vec<_>>()),
//!                 b"tag2" => count += 1,
//!                 _ => (),
//!             }
//!         },
//!         // unescape and decode the text event using the reader encoding
//!         Ok(Event::Text(e)) => txt.push(e.unescape_and_decode(&reader).unwrap()),
//!         Ok(Event::Eof) => break, // exits the loop when reaching end of file
//!         Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
//!         _ => (), // There are several other `Event`s we do not consider here
//!     }
//!
//!     // if we don't keep a borrow elsewhere, we can clear the buffer to keep memory usage low
//!     buf.clear();
//! }
//! ```
//!
//! ### Writer
//!
//! ```rust
//! use quick_xml::Writer;
//! use quick_xml::events::{Event, BytesEnd, BytesStart};
//! use quick_xml::Reader;
//! use std::io::Cursor;
//! use std::iter;
//!
//! let xml = r#"<this_tag k1="v1" k2="v2"><child>text</child></this_tag>"#;
//! let mut reader = Reader::from_str(xml);
//! reader.trim_text(true);
//! let mut writer = Writer::new(Cursor::new(Vec::new()));
//! let mut buf = Vec::new();
//! loop {
//!     match reader.read_event(&mut buf) {
//!         Ok(Event::Start(ref e)) if e.name() == b"this_tag" => {
//!
//!             // crates a new element ... alternatively we could reuse `e` by calling
//!             // `e.into_owned()`
//!             let mut elem = BytesStart::owned(b"my_elem".to_vec(), "my_elem".len());
//!
//!             // collect existing attributes
//!             elem.extend_attributes(e.attributes().map(|attr| attr.unwrap()));
//!
//!             // copy existing attributes, adds a new my-key="some value" attribute
//!             elem.push_attribute(("my-key", "some value"));
//!
//!             // writes the event to the writer
//!             assert!(writer.write_event(Event::Start(elem)).is_ok());
//!         },
//!         Ok(Event::End(ref e)) if e.name() == b"this_tag" => {
//!             assert!(writer.write_event(Event::End(BytesEnd::borrowed(b"my_elem"))).is_ok());
//!         },
//!         Ok(Event::Eof) => break,
//!         Ok(e) => assert!(writer.write_event(e).is_ok()),
//!         // or using the buffer
//!         // Ok(e) => assert!(writer.write(&buf).is_ok()),
//!         Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
//!     }
//!     buf.clear();
//! }
//!
//! let result = writer.into_inner().into_inner();
//! let expected = r#"<my_elem k1="v1" k2="v2" my-key="some value"><child>text</child></my_elem>"#;
//! assert_eq!(result, expected.as_bytes());
//! ```
//!
//! # Features
//!
//! quick-xml supports 2 additional features, non activated by default:
//! - `encoding`: support non utf8 xmls
//! - `serialize`: support serde `Serialize`/`Deserialize`
#![forbid(unsafe_code)]
#![deny(missing_docs)]
#![recursion_limit = "1024"]

#[cfg(feature = "encoding_rs")]
extern crate encoding_rs;
extern crate memchr;
#[cfg(feature = "serialize")]
extern crate serde;

#[cfg(feature = "serialize")]
pub mod de;
mod errors;
mod escapei;
pub mod escape {
    //! Manage xml character escapes
    pub(crate) use escapei::EscapeError;
    pub use escapei::{escape, unescape};
}
pub mod events;
mod reader;
#[cfg(feature = "serialize")]
pub mod se;
mod utils;
mod writer;

// reexports
#[cfg(feature = "serialize")]
pub use errors::serialize::DeError;
pub use errors::{Error, Result};
pub use reader::Reader;
pub use writer::Writer;
<|endoftext|>


<commit_before>#![no_std]

#[macro_export]
macro_rules! simple_bitfield_fields {
   ($t:ty,) => {};
   ($t:ty, _, $setter:ident: $msb:expr, $lsb:expr, $($rest:tt)*) => {
       pub fn $setter(&mut self, value: $t) {
           use $crate::BitRange;
           self.set_bit_range($msb, $lsb, value);
       }
       simple_bitfield_fields!{$t, $($rest)*}
   };
   ($t:ty, _, $setter:ident: $msb:expr, $lsb:expr; $count:expr, $($rest:tt)*) => {
       #[allow(unknown_lints)]
       #[allow(eq_op)]
       pub fn $setter(&mut self, index: usize, value: $t) {
           use $crate::BitRange;
           debug_assert!(index < $count);
           let width = $msb - $lsb + 1;
           let lsb = $lsb + index*width;
           let msb = lsb + width - 1;
           self.set_bit_range(msb, lsb, value);
       }
       simple_bitfield_fields!{$t, $($rest)*}
   };
   ($t:ty, $getter:ident, _: $msb:expr, $lsb:expr, $($rest:tt)*) => {
       pub fn $getter(&self) -> $t {
           use $crate::BitRange;
           self.bit_range($msb, $lsb)
       }
       simple_bitfield_fields!{$t, $($rest)*}
   };
   ($t:ty, $getter:ident, _: $msb:expr, $lsb:expr; $count:expr, $($rest:tt)*) => {
       #[allow(unknown_lints)]
       #[allow(eq_op)]
       pub fn $getter(&self, index: usize) -> $t {
           use $crate::BitRange;
           debug_assert!(index < $count);
           let width = $msb - $lsb + 1;
           let lsb = $lsb + index*width;
           let msb = lsb + width - 1;
           self.bit_range(msb, lsb)
       }
       simple_bitfield_fields!{$t, $($rest)*}
   };
   ($t:ty, $getter:ident, $setter:ident: $msb:expr, $lsb:expr, $($rest:tt)*) => {
       simple_bitfield_fields!{$t, $getter, _: $msb, $lsb, }
       simple_bitfield_fields!{$t, _, $setter: $msb, $lsb, }
       simple_bitfield_fields!{$t, $($rest)*}
   };
   ($t:ty, $getter:ident, $setter:ident: $msb:expr, $lsb:expr; $count:expr, $($rest:tt)*) => {
         simple_bitfield_fields!{$t, $getter, _: $msb, $lsb; $count, }
         simple_bitfield_fields!{$t, _, $setter: $msb, $lsb; $count, }
         simple_bitfield_fields!{$t, $($rest)*}
   };
}

#[macro_export]
macro_rules! simple_bitfield {
    ($name:ident, [$t:ty]; $($rest:tt)*) => {
        pub struct $name<T>(pub T);

        impl<T: AsMut<[$t]> + AsRef<[$t]>> $crate::BitRange<u64> for $name<T> {
            fn bit_range(&self, msb: usize, lsb: usize) -> u64 {
                let bit_len = $crate::size_of::<$t>()*8;
                let mut value = 0;
                for i in (lsb..msb+1).rev() {
                    value <<= 1;
                    value |= ((self.0.as_ref()[i/bit_len] >> (i%bit_len)) & 1) as u64;
                }
                value
            }

            fn set_bit_range(&mut self, msb: usize, lsb: usize, value: u64) {
                let bit_len = $crate::size_of::<$t>()*8;
                let mut value = value;
                for i in lsb..msb+1 {
                    self.0.as_mut()[i/bit_len] &= !(1 << (i%bit_len));
                    self.0.as_mut()[i/bit_len] |= (value & 1) as $t << (i%bit_len);
                    value >>= 1;
                }
            }
        }

        impl<T: AsMut<[$t]> + AsRef<[$t]>> $name<T> {
            simple_bitfield_fields!{u64, $($rest)*}
        }
    };
    ($name:ident, $t:ty; $($rest:tt)*) => {
        #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
        #[repr(C)]
        pub struct $name(pub $t);

        impl $crate::BitRange<$t> for $name {
            fn bit_range(&self, msb: usize, lsb: usize) -> $t {
                self.0.bit_range(msb, lsb)
            }
            fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $t) {
                self.0.set_bit_range(msb, lsb, value);
            }
        }

        impl $name {
            simple_bitfield_fields!{$t, $($rest)*}
         }
    };
}

#[doc(hidden)]
pub use core::mem::size_of;

/// A trait to get or set ranges of bits.
pub trait BitRange<T> {
    /// Get a range of bits.
    fn bit_range(&self, msb: usize, lsb: usize) -> T;
    /// Set a range of bits.
    fn set_bit_range(&mut self, msb: usize, lsb: usize, value: T);
}

macro_rules! impl_bitrange_for_u {
    ($t:ty) => {
        impl BitRange<$t> for $t {
            #[inline]
            fn bit_range(&self, msb: usize, lsb: usize) -> $t {
                let bit_len = size_of::<$t>()*8;
                (*self << (bit_len - msb - 1)) >> (bit_len - msb - 1 + lsb)
            }

            #[inline]
            fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $t) {
                let bit_len = size_of::<$t>()*8;
                let mask: $t = !(0 as $t)
                    << (bit_len - msb - 1)
                    >> (bit_len - msb - 1 + lsb)
                        << (lsb);
                *self &= !mask;
                *self |= (value << lsb) & mask;
            }
        }
    }
}

impl_bitrange_for_u!{u8}
impl_bitrange_for_u!{u16}
impl_bitrange_for_u!{u32}
impl_bitrange_for_u!{u64}
<commit_msg>Impl bitrange for slice with more type<commit_after>#![no_std]

#[macro_export]
macro_rules! simple_bitfield_fields {
   ($t:ty,) => {};
   ($t:ty, _, $setter:ident: $msb:expr, $lsb:expr, $($rest:tt)*) => {
       pub fn $setter(&mut self, value: $t) {
           use $crate::BitRange;
           self.set_bit_range($msb, $lsb, value);
       }
       simple_bitfield_fields!{$t, $($rest)*}
   };
   ($t:ty, _, $setter:ident: $msb:expr, $lsb:expr; $count:expr, $($rest:tt)*) => {
       #[allow(unknown_lints)]
       #[allow(eq_op)]
       pub fn $setter(&mut self, index: usize, value: $t) {
           use $crate::BitRange;
           debug_assert!(index < $count);
           let width = $msb - $lsb + 1;
           let lsb = $lsb + index*width;
           let msb = lsb + width - 1;
           self.set_bit_range(msb, lsb, value);
       }
       simple_bitfield_fields!{$t, $($rest)*}
   };
   ($t:ty, $getter:ident, _: $msb:expr, $lsb:expr, $($rest:tt)*) => {
       pub fn $getter(&self) -> $t {
           use $crate::BitRange;
           self.bit_range($msb, $lsb)
       }
       simple_bitfield_fields!{$t, $($rest)*}
   };
   ($t:ty, $getter:ident, _: $msb:expr, $lsb:expr; $count:expr, $($rest:tt)*) => {
       #[allow(unknown_lints)]
       #[allow(eq_op)]
       pub fn $getter(&self, index: usize) -> $t {
           use $crate::BitRange;
           debug_assert!(index < $count);
           let width = $msb - $lsb + 1;
           let lsb = $lsb + index*width;
           let msb = lsb + width - 1;
           self.bit_range(msb, lsb)
       }
       simple_bitfield_fields!{$t, $($rest)*}
   };
   ($t:ty, $getter:ident, $setter:ident: $msb:expr, $lsb:expr, $($rest:tt)*) => {
       simple_bitfield_fields!{$t, $getter, _: $msb, $lsb, }
       simple_bitfield_fields!{$t, _, $setter: $msb, $lsb, }
       simple_bitfield_fields!{$t, $($rest)*}
   };
   ($t:ty, $getter:ident, $setter:ident: $msb:expr, $lsb:expr; $count:expr, $($rest:tt)*) => {
         simple_bitfield_fields!{$t, $getter, _: $msb, $lsb; $count, }
         simple_bitfield_fields!{$t, _, $setter: $msb, $lsb; $count, }
         simple_bitfield_fields!{$t, $($rest)*}
   };
}

#[macro_export]
macro_rules! simple_bitfield {
    ($name:ident, [$t:ty]; $($rest:tt)*) => {
        pub struct $name<T>(pub T);

        impl_bitrange_slice!($name, $t, u8);
        impl_bitrange_slice!($name, $t, u16);
        impl_bitrange_slice!($name, $t, u32);
        impl_bitrange_slice!($name, $t, u64);

        impl<T: AsMut<[$t]> + AsRef<[$t]>> $name<T> {
            simple_bitfield_fields!{u64, $($rest)*}
        }
    };
    ($name:ident, $t:ty; $($rest:tt)*) => {
        #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
        #[repr(C)]
        pub struct $name(pub $t);

        impl $crate::BitRange<$t> for $name {
            fn bit_range(&self, msb: usize, lsb: usize) -> $t {
                self.0.bit_range(msb, lsb)
            }
            fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $t) {
                self.0.set_bit_range(msb, lsb, value);
            }
        }

        impl $name {
            simple_bitfield_fields!{$t, $($rest)*}
         }
    };
}

#[doc(hidden)]
pub use core::mem::size_of;

/// A trait to get or set ranges of bits.
pub trait BitRange<T> {
    /// Get a range of bits.
    fn bit_range(&self, msb: usize, lsb: usize) -> T;
    /// Set a range of bits.
    fn set_bit_range(&mut self, msb: usize, lsb: usize, value: T);
}

macro_rules! impl_bitrange_for_u {
    ($t:ty) => {
        impl BitRange<$t> for $t {
            #[inline]
            fn bit_range(&self, msb: usize, lsb: usize) -> $t {
                let bit_len = size_of::<$t>()*8;
                (*self << (bit_len - msb - 1)) >> (bit_len - msb - 1 + lsb)
            }

            #[inline]
            fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $t) {
                let bit_len = size_of::<$t>()*8;
                let mask: $t = !(0 as $t)
                    << (bit_len - msb - 1)
                    >> (bit_len - msb - 1 + lsb)
                        << (lsb);
                *self &= !mask;
                *self |= (value << lsb) & mask;
            }
        }
    }
}

impl_bitrange_for_u!{u8}
impl_bitrange_for_u!{u16}
impl_bitrange_for_u!{u32}
impl_bitrange_for_u!{u64}

#[doc(hidden)]
#[macro_export]
macro_rules! impl_bitrange_slice {
    ($name:ident, $slice_ty:ty, $bitrange_ty:ty) => {
        impl<T: AsMut<[$slice_ty]> + AsRef<[$slice_ty]>> $crate::BitRange<$bitrange_ty>
            for $name<T> {
            fn bit_range(&self, msb: usize, lsb: usize) -> $bitrange_ty {
                let bit_len = $crate::size_of::<$slice_ty>()*8;
                let mut value = 0;
                for i in (lsb..msb+1).rev() {
                    value <<= 1;
                    value |= ((self.0.as_ref()[i/bit_len] >> (i%bit_len)) & 1) as $bitrange_ty;
                }
                value
            }

            fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $bitrange_ty) {
                let bit_len = $crate::size_of::<$slice_ty>()*8;
                let mut value = value;
                for i in lsb..msb+1 {
                    self.0.as_mut()[i/bit_len] &= !(1 << (i%bit_len));
                    self.0.as_mut()[i/bit_len] |= (value & 1) as $slice_ty << (i%bit_len);
                    value >>= 1;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Infinity for types without infinite values
//!
//! Infinitable introduces the notion of "infinity" and "negative infinity"
//! to numeric types, such as integers, that do not have infinite values.
//!
//! A representation of infinity is useful for graph algorithms such as
//! Dijkstra's algorithm, as well as for representing a graph with an
//! adjacency matrix.
//!
//! # Basic Usage
//!
//! ```
//! use infinitable::Infinitable;
//!
//! let finite = Infinitable::Finite(5);
//! let infinity = Infinitable::Infinity;
//! let negative_infinity = Infinitable::NegativeInfinity;
//!
//! assert!(finite < infinity);
//! assert!(finite > negative_infinity);
//! ```

use std::cmp::Ordering;
use std::ops::Neg;
use std::fmt;
use std::fmt::{Display,Formatter};

/// An "infinitable" value, one that can be either finite or infinite
#[derive(Debug, Copy, Clone)]
pub enum Infinitable<T> {
	/// A finite value `T`
	Finite(T),
	/// Positive infinity, which compares greater than all finite values
	Infinity,
	/// Negative infinity, which compares less than all finite values
	NegativeInfinity,
}

impl<T> Infinitable<T> {
	/// Returns `true` if the value is `Finite`.
	///
	/// # Examples
	///
	/// ```
	/// use infinitable::Infinitable;
	///
	/// let finite = Infinitable::Finite(5);
	/// assert!(finite.is_finite());
	/// ```
	pub fn is_finite(&self) -> bool {
		match self {
			&Infinitable::Finite(_) => true,
			_ => false,
		}
	}

	/// Converts from an `Infinitable<T>` to an `Option<T>`.
	///
	/// Converts `self` into an `Option<T>` possibly containing a finite value,
	/// consuming `self`.
	///
	/// # Examples
	///
	/// ```
	/// use infinitable::Infinitable;
	///
	/// let finite = Infinitable::Finite(5);
	/// assert_eq!(Some(5), finite.finite());
	/// let infinite: Infinitable<i32> = Infinitable::Infinity;
	/// assert_eq!(None, infinite.finite());
	/// ```
	pub fn finite(self) -> Option<T> {
		match self {
			Infinitable::Finite(x) => Some(x),
			_ => None,
		}
	}
}

impl<T> From<T> for Infinitable<T> {
	fn from(value: T) -> Infinitable<T> {
		Infinitable::Finite(value)
	}
}

impl<T> PartialEq for Infinitable<T> where T: PartialEq {
	fn eq(&self, other: &Self) -> bool {
		match (self, other) {
			(&Infinitable::Infinity, &Infinitable::Infinity)
			| (&Infinitable::NegativeInfinity, &Infinitable::NegativeInfinity)
				=> true,
			(&Infinitable::Finite(ref x), &Infinitable::Finite(ref y))
				=> x == y,
			(..)
				=> false,
		}
	}
}

impl<T> Eq for Infinitable<T> where T: Eq {
}

impl<T> PartialOrd for Infinitable<T> where T: PartialOrd {
	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
		match (self, other) {
			(&Infinitable::Infinity, &Infinitable::Infinity)
			| (&Infinitable::NegativeInfinity, &Infinitable::NegativeInfinity)
				=> Some(Ordering::Equal),
			(&Infinitable::Infinity, _)
			| (_, &Infinitable::NegativeInfinity)
				=> Some(Ordering::Greater),
			(&Infinitable::NegativeInfinity, _)
			| (_, &Infinitable::Infinity)
				=> Some(Ordering::Less),
			(&Infinitable::Finite(ref x), &Infinitable::Finite(ref y))
				=> x.partial_cmp(y),
		}
	}
}

impl<T> Ord for Infinitable<T> where T: Ord {
	fn cmp(&self, other: &Self) -> Ordering {
		match (self, other) {
			(&Infinitable::Finite(ref x), &Infinitable::Finite(ref y))
				=> x.cmp(y),
			(..)
				=> self.partial_cmp(other).unwrap(),
		}
	}
}

impl<T> Neg for Infinitable<T> where T: Neg {
	type Output = Infinitable<T::Output>;

	fn neg(self) -> Infinitable<T::Output> {
		match self {
			Infinitable::Finite(x) => Infinitable::Finite(-x),
			Infinitable::Infinity => Infinitable::NegativeInfinity,
			Infinitable::NegativeInfinity => Infinitable::Infinity,
		}
	}
}

impl<T> Display for Infinitable<T> where T: Display {
	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
		match self {
			&Infinitable::Finite(ref x) => write!(f, "{}", x),
			&Infinitable::Infinity => write!(f, "inf"),
			&Infinitable::NegativeInfinity => write!(f, "-inf"),
		}
	}
}
<commit_msg>Derive PartialEq and Eq<commit_after>//! Infinity for types without infinite values
//!
//! Infinitable introduces the notion of "infinity" and "negative infinity"
//! to numeric types, such as integers, that do not have infinite values.
//!
//! A representation of infinity is useful for graph algorithms such as
//! Dijkstra's algorithm, as well as for representing a graph with an
//! adjacency matrix.
//!
//! # Basic Usage
//!
//! ```
//! use infinitable::Infinitable;
//!
//! let finite = Infinitable::Finite(5);
//! let infinity = Infinitable::Infinity;
//! let negative_infinity = Infinitable::NegativeInfinity;
//!
//! assert!(finite < infinity);
//! assert!(finite > negative_infinity);
//! ```

use std::cmp::Ordering;
use std::ops::Neg;
use std::fmt;
use std::fmt::{Display,Formatter};

/// An "infinitable" value, one that can be either finite or infinite
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Infinitable<T> {
	/// A finite value `T`
	Finite(T),
	/// Positive infinity, which compares greater than all finite values
	Infinity,
	/// Negative infinity, which compares less than all finite values
	NegativeInfinity,
}

impl<T> Infinitable<T> {
	/// Returns `true` if the value is `Finite`.
	///
	/// # Examples
	///
	/// ```
	/// use infinitable::Infinitable;
	///
	/// let finite = Infinitable::Finite(5);
	/// assert!(finite.is_finite());
	/// ```
	pub fn is_finite(&self) -> bool {
		match self {
			&Infinitable::Finite(_) => true,
			_ => false,
		}
	}

	/// Converts from an `Infinitable<T>` to an `Option<T>`.
	///
	/// Converts `self` into an `Option<T>` possibly containing a finite value,
	/// consuming `self`.
	///
	/// # Examples
	///
	/// ```
	/// use infinitable::Infinitable;
	///
	/// let finite = Infinitable::Finite(5);
	/// assert_eq!(Some(5), finite.finite());
	/// let infinite: Infinitable<i32> = Infinitable::Infinity;
	/// assert_eq!(None, infinite.finite());
	/// ```
	pub fn finite(self) -> Option<T> {
		match self {
			Infinitable::Finite(x) => Some(x),
			_ => None,
		}
	}
}

impl<T> From<T> for Infinitable<T> {
	fn from(value: T) -> Infinitable<T> {
		Infinitable::Finite(value)
	}
}

impl<T> PartialOrd for Infinitable<T> where T: PartialOrd {
	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
		match (self, other) {
			(&Infinitable::Infinity, &Infinitable::Infinity)
			| (&Infinitable::NegativeInfinity, &Infinitable::NegativeInfinity)
				=> Some(Ordering::Equal),
			(&Infinitable::Infinity, _)
			| (_, &Infinitable::NegativeInfinity)
				=> Some(Ordering::Greater),
			(&Infinitable::NegativeInfinity, _)
			| (_, &Infinitable::Infinity)
				=> Some(Ordering::Less),
			(&Infinitable::Finite(ref x), &Infinitable::Finite(ref y))
				=> x.partial_cmp(y),
		}
	}
}

impl<T> Ord for Infinitable<T> where T: Ord {
	fn cmp(&self, other: &Self) -> Ordering {
		match (self, other) {
			(&Infinitable::Finite(ref x), &Infinitable::Finite(ref y))
				=> x.cmp(y),
			(..)
				=> self.partial_cmp(other).unwrap(),
		}
	}
}

impl<T> Neg for Infinitable<T> where T: Neg {
	type Output = Infinitable<T::Output>;

	fn neg(self) -> Infinitable<T::Output> {
		match self {
			Infinitable::Finite(x) => Infinitable::Finite(-x),
			Infinitable::Infinity => Infinitable::NegativeInfinity,
			Infinitable::NegativeInfinity => Infinitable::Infinity,
		}
	}
}

impl<T> Display for Infinitable<T> where T: Display {
	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
		match self {
			&Infinitable::Finite(ref x) => write!(f, "{}", x),
			&Infinitable::Infinity => write!(f, "inf"),
			&Infinitable::NegativeInfinity => write!(f, "-inf"),
		}
	}
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::io::Read;
use std::sync::mpsc::channel;
use std::sync::mpsc::Receiver;
use std::thread;

const LF: u8 = b'\n';
const CR: u8 = b'\r';
const QUOTE: u8 = b'"';
const COMMA: u8 = b',';

// Error messages
pub const UNEXPECTED_EOL: &'static str = "Unexpected end of line";
pub const UNEXPECTED_CHAR: &'static str = "Unexpected character after quote";
pub const EXPECTED_LF: &'static str = "Expected linefeed after carriage return";

enum CSVState {
    Start,
    NonQuotedValue,
    QuotedValue,
    QuoteQuote,
    ExpectLF,
    Error,
}

type CSVResult = Result<CSVState, &'static str>;

#[derive(Debug, PartialEq, Eq)]
pub struct CSVError {
    pub line: i32,
    pub col: i32,
    pub text: &'static str,
}

fn parse_start(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuotedValue),
        COMMA => Ok(CSVState::Start),
        _ => Ok(CSVState::NonQuotedValue),
    }
}

fn parse_non_quoted(byte: u8) -> CSVResult {
    match byte {
        COMMA | LF => Ok(CSVState::Start),
        CR => Ok(CSVState::ExpectLF),
        _ => Ok(CSVState::NonQuotedValue),
    }
}

fn parse_quoted(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuoteQuote),
        CR | LF => Err(UNEXPECTED_EOL),
        _ => Ok(CSVState::QuotedValue),
    }
}

fn parse_quote_quote(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuotedValue),
        COMMA | LF => Ok(CSVState::Start),
        CR => Ok(CSVState::ExpectLF),
        _ => Err(UNEXPECTED_CHAR),
    }
}

fn parse_cr(byte: u8) -> CSVResult {
    match byte {
        LF => Ok(CSVState::Start),
        _ => Err(EXPECTED_LF),
    }
}

fn parse_err(byte: u8) -> CSVResult {
    match byte {
        LF => Ok(CSVState::Start),
        _ => Ok(CSVState::Error),
    }
}

fn next_state(state: CSVState, byte: u8) -> CSVResult {
    match state {
        CSVState::Start => parse_start(byte),
        CSVState::NonQuotedValue => parse_non_quoted(byte),
        CSVState::QuotedValue => parse_quoted(byte),
        CSVState::QuoteQuote => parse_quote_quote(byte),
        CSVState::ExpectLF => parse_cr(byte),
        CSVState::Error => parse_err(byte),
    }
}

pub fn publish_errors_for_csv<T: Read + Send + 'static>(reader: T) -> Receiver<CSVError> {
    let (sender, receiver) = channel();

    thread::spawn(move || {
        let mut state = CSVState::Start;
        let mut line = 1;
        let mut col = 0;

        for b in reader.bytes() {
            let byte = b.unwrap();

            state = match next_state(state, byte) {
                Ok(new_state) => new_state,
                Err(error) => {
                    sender.send(CSVError {
                        line: line,
                        col: col,
                        text: error,
                    }).unwrap();
                    match error {
                        UNEXPECTED_EOL => CSVState::Start,
                        _ => CSVState::Error
                    }
                }
            };

            if byte == LF {
                line += 1;
                col = 0;
            } else {
                col += 1;
            }
        }
    });

    receiver
}
<commit_msg>No longer need to declare static lifetimes here<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::io::Read;
use std::sync::mpsc::channel;
use std::sync::mpsc::Receiver;
use std::thread;

const LF: u8 = b'\n';
const CR: u8 = b'\r';
const QUOTE: u8 = b'"';
const COMMA: u8 = b',';

// Error messages
pub const UNEXPECTED_EOL: &str = "Unexpected end of line";
pub const UNEXPECTED_CHAR: &str = "Unexpected character after quote";
pub const EXPECTED_LF: &str = "Expected linefeed after carriage return";

enum CSVState {
    Start,
    NonQuotedValue,
    QuotedValue,
    QuoteQuote,
    ExpectLF,
    Error,
}

type CSVResult = Result<CSVState, &'static str>;

#[derive(Debug, PartialEq, Eq)]
pub struct CSVError {
    pub line: i32,
    pub col: i32,
    pub text: &'static str,
}

fn parse_start(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuotedValue),
        COMMA => Ok(CSVState::Start),
        _ => Ok(CSVState::NonQuotedValue),
    }
}

fn parse_non_quoted(byte: u8) -> CSVResult {
    match byte {
        COMMA | LF => Ok(CSVState::Start),
        CR => Ok(CSVState::ExpectLF),
        _ => Ok(CSVState::NonQuotedValue),
    }
}

fn parse_quoted(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuoteQuote),
        CR | LF => Err(UNEXPECTED_EOL),
        _ => Ok(CSVState::QuotedValue),
    }
}

fn parse_quote_quote(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuotedValue),
        COMMA | LF => Ok(CSVState::Start),
        CR => Ok(CSVState::ExpectLF),
        _ => Err(UNEXPECTED_CHAR),
    }
}

fn parse_cr(byte: u8) -> CSVResult {
    match byte {
        LF => Ok(CSVState::Start),
        _ => Err(EXPECTED_LF),
    }
}

fn parse_err(byte: u8) -> CSVResult {
    match byte {
        LF => Ok(CSVState::Start),
        _ => Ok(CSVState::Error),
    }
}

fn next_state(state: CSVState, byte: u8) -> CSVResult {
    match state {
        CSVState::Start => parse_start(byte),
        CSVState::NonQuotedValue => parse_non_quoted(byte),
        CSVState::QuotedValue => parse_quoted(byte),
        CSVState::QuoteQuote => parse_quote_quote(byte),
        CSVState::ExpectLF => parse_cr(byte),
        CSVState::Error => parse_err(byte),
    }
}

pub fn publish_errors_for_csv<T: Read + Send + 'static>(reader: T) -> Receiver<CSVError> {
    let (sender, receiver) = channel();

    thread::spawn(move || {
        let mut state = CSVState::Start;
        let mut line = 1;
        let mut col = 0;

        for b in reader.bytes() {
            let byte = b.unwrap();

            state = match next_state(state, byte) {
                Ok(new_state) => new_state,
                Err(error) => {
                    sender.send(CSVError {
                        line: line,
                        col: col,
                        text: error,
                    }).unwrap();
                    match error {
                        UNEXPECTED_EOL => CSVState::Start,
                        _ => CSVState::Error
                    }
                }
            };

            if byte == LF {
                line += 1;
                col = 0;
            } else {
                col += 1;
            }
        }
    });

    receiver
}
<|endoftext|>


<commit_before>extern crate bit_vec;
extern crate byteorder;
extern crate crc;
extern crate libc;
extern crate libz_sys;

use std::collections::HashMap;
use std::collections::HashSet;
use std::fs;
use std::fs::File;
use std::io;
use std::io::BufWriter;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;

pub mod deflate {
    pub mod deflate;
    pub mod stream;
}
pub mod png;

pub struct Options {
    pub backup: bool,
    pub out_file: PathBuf,
    pub out_dir: Option<PathBuf>,
    pub stdout: bool,
    pub fix_errors: bool,
    pub pretend: bool,
    pub recursive: bool,
    pub clobber: bool,
    pub create: bool,
    pub force: bool,
    pub preserve_attrs: bool,
    pub verbosity: Option<u8>,
    pub filter: HashSet<u8>,
    pub interlace: Option<u8>,
    pub compression: HashSet<u8>,
    pub memory: HashSet<u8>,
    pub strategies: HashSet<u8>,
    pub window: u8,
    pub bit_depth_reduction: bool,
    pub color_type_reduction: bool,
    pub palette_reduction: bool,
    pub idat_recoding: bool,
    pub strip: bool,
}

pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), String> {
    // Decode PNG from file
    println!("Processing: {}", filepath.to_str().unwrap());
    let in_file = Path::new(filepath);
    let mut png = match png::PngData::new(&in_file) {
        Ok(x) => x,
        Err(x) => return Err(x),
    };

    // Print png info
    let idat_original_size = png.idat_data.len();
    let file_original_size = filepath.metadata().unwrap().len() as usize;
    if opts.verbosity.is_some() {
        println!("    {}x{} pixels, PNG format",
                 png.ihdr_data.width,
                 png.ihdr_data.height);
        if let Some(palette) = png.palette.clone() {
            println!("    {} bits/pixel, {} colors in palette",
                     png.ihdr_data.bit_depth,
                     palette.len() / 3);
        } else {
            println!("    {}x{} bits/pixel, {:?}",
                     png.bits_per_pixel_raw(),
                     png.ihdr_data.bit_depth,
                     png.ihdr_data.color_type);
        }
        println!("    IDAT size = {} bytes", idat_original_size);
        println!("    File size = {} bytes", file_original_size);
    }

    let mut something_changed = false;

    if opts.color_type_reduction {
        if png.reduce_color_type() {
            something_changed = true;
            // TODO: Print message to terminal
        };
    }

    if opts.bit_depth_reduction {
        if png.reduce_bit_depth() {
            something_changed = true;
            // TODO: Print message to terminal
        };
    }

    if opts.palette_reduction {
        if png.reduce_palette() {
            something_changed = true;
            // TODO: Print message to terminal
        };
    }

    if let Some(interlacing) = opts.interlace {
        if png.change_interlacing(interlacing) {
            something_changed = true;
            // TODO: Print message to terminal
        };
    }

    if opts.idat_recoding || something_changed {
        // Go through selected permutations and determine the best
        let mut best: Option<(u8, u8, u8, u8)> = None;
        let combinations = opts.filter.len() * opts.compression.len() * opts.memory.len() *
                           opts.strategies.len();
        println!("Trying: {} combinations", combinations);
        // TODO: Multithreading
        for f in &opts.filter {
            let filtered = png.filter_image(*f);
            for zc in &opts.compression {
                for zm in &opts.memory {
                    for zs in &opts.strategies {
                        let new_idat = match deflate::deflate::deflate(&filtered,
                                                                       *zc,
                                                                       *zm,
                                                                       *zs,
                                                                       opts.window) {
                            Ok(x) => x,
                            Err(x) => return Err(x),
                        };
                        if new_idat.len() < png.idat_data.len() ||
                           (best.is_none() && something_changed) {
                            best = Some((*f, *zc, *zm, *zs));
                            png.idat_data = new_idat.clone();
                        }
                        if opts.verbosity == Some(1) {
                            println!("    zc = {}  zm = {}  zs = {}  f = {}        {} bytes",
                                     *zc,
                                     *zm,
                                     *zs,
                                     *f,
                                     new_idat.len());
                        }
                    }
                }
            }
        }

        if let Some(better) = best {
            println!("Found better combination:");
            println!("    zc = {}  zm = {}  zs = {}  f = {}        {} bytes",
                     better.1,
                     better.2,
                     better.3,
                     better.0,
                     png.idat_data.len());
        }
    }

    if opts.strip {
        // Strip headers
        png.aux_headers = HashMap::new();
    }

    let output_data = png.output();
    if file_original_size <= output_data.len() && !opts.force && opts.interlace.is_none() {
        println!("File already optimized");
        return Ok(());
    }

    if opts.pretend {
        println!("Running in pretend mode, no output");
    } else {
        if opts.backup {
            match fs::copy(in_file,
                           in_file.with_extension(format!("bak.{}",
                                                          in_file.extension()
                                                                 .unwrap()
                                                                 .to_str()
                                                                 .unwrap()))) {
                Ok(x) => x,
                Err(_) => {
                    return Err(format!("Unable to write to backup file at {}",
                                       opts.out_file.display()))
                }
            };
        }

        if opts.stdout {
            let mut buffer = BufWriter::new(io::stdout());
            match buffer.write_all(&output_data) {
                Ok(_) => (),
                Err(_) => return Err(format!("Unable to write to stdout")),
            }
        } else {
            let out_file = match File::create(&opts.out_file) {
                Ok(x) => x,
                Err(_) => {
                    return Err(format!("Unable to write to file {}", opts.out_file.display()))
                }
            };
            let mut buffer = BufWriter::new(out_file);
            match buffer.write_all(&output_data) {
                Ok(_) => println!("Output: {}", opts.out_file.display()),
                Err(_) => {
                    return Err(format!("Unable to write to file {}", opts.out_file.display()))
                }
            }
        }
    }
    if idat_original_size >= png.idat_data.len() {
        println!("    IDAT size = {} bytes ({} bytes decrease)",
                 png.idat_data.len(),
                 idat_original_size - png.idat_data.len());
    } else {
        println!("    IDAT size = {} bytes ({} bytes increate)",
                 png.idat_data.len(),
                 png.idat_data.len() - idat_original_size);
    }
    if file_original_size >= output_data.len() {
        println!("    file size = {} bytes ({} bytes = {:.2}% decrease)",
                 output_data.len(),
                 file_original_size - output_data.len(),
                 (file_original_size - output_data.len()) as f64 / file_original_size as f64);
    } else {
        println!("    file size = {} bytes ({} bytes = {:.2}% increase)",
                 output_data.len(),
                 output_data.len() - file_original_size,
                 (output_data.len() - file_original_size) as f64 / file_original_size as f64);
    }

    Ok(())
}
<commit_msg>Only change interlacing if we have to<commit_after>extern crate bit_vec;
extern crate byteorder;
extern crate crc;
extern crate libc;
extern crate libz_sys;

use std::collections::HashMap;
use std::collections::HashSet;
use std::fs;
use std::fs::File;
use std::io;
use std::io::BufWriter;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;

pub mod deflate {
    pub mod deflate;
    pub mod stream;
}
pub mod png;

pub struct Options {
    pub backup: bool,
    pub out_file: PathBuf,
    pub out_dir: Option<PathBuf>,
    pub stdout: bool,
    pub fix_errors: bool,
    pub pretend: bool,
    pub recursive: bool,
    pub clobber: bool,
    pub create: bool,
    pub force: bool,
    pub preserve_attrs: bool,
    pub verbosity: Option<u8>,
    pub filter: HashSet<u8>,
    pub interlace: Option<u8>,
    pub compression: HashSet<u8>,
    pub memory: HashSet<u8>,
    pub strategies: HashSet<u8>,
    pub window: u8,
    pub bit_depth_reduction: bool,
    pub color_type_reduction: bool,
    pub palette_reduction: bool,
    pub idat_recoding: bool,
    pub strip: bool,
}

pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), String> {
    // Decode PNG from file
    println!("Processing: {}", filepath.to_str().unwrap());
    let in_file = Path::new(filepath);
    let mut png = match png::PngData::new(&in_file) {
        Ok(x) => x,
        Err(x) => return Err(x),
    };

    // Print png info
    let idat_original_size = png.idat_data.len();
    let file_original_size = filepath.metadata().unwrap().len() as usize;
    if opts.verbosity.is_some() {
        println!("    {}x{} pixels, PNG format",
                 png.ihdr_data.width,
                 png.ihdr_data.height);
        if let Some(palette) = png.palette.clone() {
            println!("    {} bits/pixel, {} colors in palette",
                     png.ihdr_data.bit_depth,
                     palette.len() / 3);
        } else {
            println!("    {}x{} bits/pixel, {:?}",
                     png.bits_per_pixel_raw(),
                     png.ihdr_data.bit_depth,
                     png.ihdr_data.color_type);
        }
        println!("    IDAT size = {} bytes", idat_original_size);
        println!("    File size = {} bytes", file_original_size);
    }

    let mut something_changed = false;

    if opts.color_type_reduction {
        if png.reduce_color_type() {
            something_changed = true;
            // TODO: Print message to terminal
        };
    }

    if opts.bit_depth_reduction {
        if png.reduce_bit_depth() {
            something_changed = true;
            // TODO: Print message to terminal
        };
    }

    if opts.palette_reduction {
        if png.reduce_palette() {
            something_changed = true;
            // TODO: Print message to terminal
        };
    }

    if let Some(interlacing) = opts.interlace {
        if interlacing != png.ihdr_data.interlaced {
            if png.change_interlacing(interlacing) {
                something_changed = true;
                // TODO: Print message to terminal
            }
        }
    }

    if opts.idat_recoding || something_changed {
        // Go through selected permutations and determine the best
        let mut best: Option<(u8, u8, u8, u8)> = None;
        let combinations = opts.filter.len() * opts.compression.len() * opts.memory.len() *
                           opts.strategies.len();
        println!("Trying: {} combinations", combinations);
        // TODO: Multithreading
        for f in &opts.filter {
            let filtered = png.filter_image(*f);
            for zc in &opts.compression {
                for zm in &opts.memory {
                    for zs in &opts.strategies {
                        let new_idat = match deflate::deflate::deflate(&filtered,
                                                                       *zc,
                                                                       *zm,
                                                                       *zs,
                                                                       opts.window) {
                            Ok(x) => x,
                            Err(x) => return Err(x),
                        };
                        if new_idat.len() < png.idat_data.len() ||
                           (best.is_none() && something_changed) {
                            best = Some((*f, *zc, *zm, *zs));
                            png.idat_data = new_idat.clone();
                        }
                        if opts.verbosity == Some(1) {
                            println!("    zc = {}  zm = {}  zs = {}  f = {}        {} bytes",
                                     *zc,
                                     *zm,
                                     *zs,
                                     *f,
                                     new_idat.len());
                        }
                    }
                }
            }
        }

        if let Some(better) = best {
            println!("Found better combination:");
            println!("    zc = {}  zm = {}  zs = {}  f = {}        {} bytes",
                     better.1,
                     better.2,
                     better.3,
                     better.0,
                     png.idat_data.len());
        }
    }

    if opts.strip {
        // Strip headers
        png.aux_headers = HashMap::new();
    }

    let output_data = png.output();
    if file_original_size <= output_data.len() && !opts.force && opts.interlace.is_none() {
        println!("File already optimized");
        return Ok(());
    }

    if opts.pretend {
        println!("Running in pretend mode, no output");
    } else {
        if opts.backup {
            match fs::copy(in_file,
                           in_file.with_extension(format!("bak.{}",
                                                          in_file.extension()
                                                                 .unwrap()
                                                                 .to_str()
                                                                 .unwrap()))) {
                Ok(x) => x,
                Err(_) => {
                    return Err(format!("Unable to write to backup file at {}",
                                       opts.out_file.display()))
                }
            };
        }

        if opts.stdout {
            let mut buffer = BufWriter::new(io::stdout());
            match buffer.write_all(&output_data) {
                Ok(_) => (),
                Err(_) => return Err(format!("Unable to write to stdout")),
            }
        } else {
            let out_file = match File::create(&opts.out_file) {
                Ok(x) => x,
                Err(_) => {
                    return Err(format!("Unable to write to file {}", opts.out_file.display()))
                }
            };
            let mut buffer = BufWriter::new(out_file);
            match buffer.write_all(&output_data) {
                Ok(_) => println!("Output: {}", opts.out_file.display()),
                Err(_) => {
                    return Err(format!("Unable to write to file {}", opts.out_file.display()))
                }
            }
        }
    }
    if idat_original_size >= png.idat_data.len() {
        println!("    IDAT size = {} bytes ({} bytes decrease)",
                 png.idat_data.len(),
                 idat_original_size - png.idat_data.len());
    } else {
        println!("    IDAT size = {} bytes ({} bytes increate)",
                 png.idat_data.len(),
                 png.idat_data.len() - idat_original_size);
    }
    if file_original_size >= output_data.len() {
        println!("    file size = {} bytes ({} bytes = {:.2}% decrease)",
                 output_data.len(),
                 file_original_size - output_data.len(),
                 (file_original_size - output_data.len()) as f64 / file_original_size as f64);
    } else {
        println!("    file size = {} bytes ({} bytes = {:.2}% increase)",
                 output_data.len(),
                 output_data.len() - file_original_size,
                 (output_data.len() - file_original_size) as f64 / file_original_size as f64);
    }

    Ok(())
}
<|endoftext|>


<commit_before>use rand::seq::SliceRandom;

/// Convenience function to generate a new petname from default word lists.
#[allow(dead_code)]
pub fn petname(words: u8, separator: &str) -> String {
    Petnames::default().generate_one(words, separator)
}

/// Word lists and the logic to combine them into _petnames_.
///
/// A _petname_ with `n` words will contain, in order:
///
///   * 1 adjective when `n >= 2`, otherwise 0 adjectives.
///   * `n - 2` adverbs when `n >= 2`.
///   * 1 name / noun.
///
pub struct Petnames<'a> {
    pub adjectives: Vec<&'a str>,
    pub adverbs: Vec<&'a str>,
    pub names: Vec<&'a str>,
}

impl<'a> Petnames<'a> {
    /// Constructs a new `Petnames` from the default (small) word lists.
    pub fn default() -> Self {
        Self::small()
    }

    /// Constructs a new `Petnames` from the small word lists.
    pub fn small() -> Self {
        Self::init(
            include_str!("../words/small/adjectives.txt"),
            include_str!("../words/small/adverbs.txt"),
            include_str!("../words/small/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the medium word lists.
    pub fn medium() -> Self {
        Self::init(
            include_str!("../words/medium/adjectives.txt"),
            include_str!("../words/medium/adverbs.txt"),
            include_str!("../words/medium/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the large word lists.
    pub fn large() -> Self {
        Self::init(
            include_str!("../words/large/adjectives.txt"),
            include_str!("../words/large/adverbs.txt"),
            include_str!("../words/large/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the given word lists.
    ///
    /// The words are extracted from the given strings by splitting on whitespace.
    pub fn init(adjectives: &'a str, adverbs: &'a str, names: &'a str) -> Self {
        Self {
            adjectives: adjectives.split_whitespace().collect(),
            adverbs: adverbs.split_whitespace().collect(),
            names: names.split_whitespace().collect(),
        }
    }

    /// Keep words matching a predicate.
    ///
    /// # Examples
    ///
    /// ```rust
    /// let mut petnames = petname::Petnames::default();
    /// petnames.retain(|s| s.starts_with("b"));
    /// petnames.generate_one(2, ".");
    /// ```
    ///
    /// This is merely a convenience wrapper that applies the same predicate to
    /// the adjectives, adverbs, and names lists.
    ///
    pub fn retain<F>(&mut self, predicate: F)
    where
        F: Fn(&&str) -> bool,
    {
        self.adjectives.retain(&predicate);
        self.adverbs.retain(&predicate);
        self.names.retain(&predicate);
    }

    /// Generate a new petname.
    ///
    /// # Examples
    ///
    /// ```rust
    /// let mut rng = rand::thread_rng();
    /// petname::Petnames::default().generate(&mut rng, 7, ":");
    /// ```
    ///
    /// # Panics
    ///
    /// If a word list is empty.
    ///
    pub fn generate<RNG>(&self, rng: &mut RNG, words: u8, separator: &str) -> String
    where
        RNG: rand::Rng,
    {
        // Adverbs all the way, finishing with adjective then name.
        let mut parts = Vec::with_capacity(words as usize);
        for num in (0..words).rev() {
            parts.push(*match num {
                0 => self.names.choose(rng).unwrap(),
                1 => self.adjectives.choose(rng).unwrap(),
                _ => self.adverbs.choose(rng).unwrap(),
            });
        }
        parts.join(separator)
    }

    /// Generate a single new petname.
    ///
    /// This is like `generate` but uses `rand::thread_rng` as the random
    /// source. For efficiency use `generate` when creating multiple names, or
    /// when you want to use a custom source of randomness.
    pub fn generate_one(&self, words: u8, separator: &str) -> String {
        self.generate(&mut rand::thread_rng(), words, separator)
    }
}

impl<'a> Default for Petnames<'a> {
    fn default() -> Self {
        Self::default()
    }
}

#[cfg(test)]
mod tests {

    use super::{petname, Petnames};
    use rand;

    #[test]
    fn default_petnames_has_adjectives() {
        let petnames = Petnames::default();
        assert_ne!(petnames.adjectives.len(), 0);
    }

    #[test]
    fn default_petnames_has_adverbs() {
        let petnames = Petnames::default();
        assert_ne!(petnames.adverbs.len(), 0);
    }

    #[test]
    fn default_petnames_has_names() {
        let petnames = Petnames::default();
        assert_ne!(petnames.names.len(), 0);
    }

    #[test]
    fn generate_uses_adverb_adjective_name() {
        let petnames = Petnames {
            adjectives: vec!["adjective"],
            adverbs: vec!["adverb"],
            names: vec!["name"],
        };
        assert_eq!(
            petnames.generate(&mut rand::thread_rng(), 3, "-"),
            "adverb-adjective-name"
        );
    }

    #[test]
    fn petname_renders_desired_number_of_words() {
        assert_eq!(petname(7, "-").split("-").count(), 7);
    }

    #[test]
    fn petname_renders_with_desired_separator() {
        assert_eq!(petname(7, "@").split("@").count(), 7);
    }
}
<commit_msg>Add Petnames::cardinality.<commit_after>use rand::seq::SliceRandom;

/// Convenience function to generate a new petname from default word lists.
#[allow(dead_code)]
pub fn petname(words: u8, separator: &str) -> String {
    Petnames::default().generate_one(words, separator)
}

/// Word lists and the logic to combine them into _petnames_.
///
/// A _petname_ with `n` words will contain, in order:
///
///   * 1 adjective when `n >= 2`, otherwise 0 adjectives.
///   * `n - 2` adverbs when `n >= 2`.
///   * 1 name / noun.
///
pub struct Petnames<'a> {
    pub adjectives: Vec<&'a str>,
    pub adverbs: Vec<&'a str>,
    pub names: Vec<&'a str>,
}

impl<'a> Petnames<'a> {
    /// Constructs a new `Petnames` from the default (small) word lists.
    pub fn default() -> Self {
        Self::small()
    }

    /// Constructs a new `Petnames` from the small word lists.
    pub fn small() -> Self {
        Self::init(
            include_str!("../words/small/adjectives.txt"),
            include_str!("../words/small/adverbs.txt"),
            include_str!("../words/small/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the medium word lists.
    pub fn medium() -> Self {
        Self::init(
            include_str!("../words/medium/adjectives.txt"),
            include_str!("../words/medium/adverbs.txt"),
            include_str!("../words/medium/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the large word lists.
    pub fn large() -> Self {
        Self::init(
            include_str!("../words/large/adjectives.txt"),
            include_str!("../words/large/adverbs.txt"),
            include_str!("../words/large/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the given word lists.
    ///
    /// The words are extracted from the given strings by splitting on whitespace.
    pub fn init(adjectives: &'a str, adverbs: &'a str, names: &'a str) -> Self {
        Self {
            adjectives: adjectives.split_whitespace().collect(),
            adverbs: adverbs.split_whitespace().collect(),
            names: names.split_whitespace().collect(),
        }
    }

    /// Keep words matching a predicate.
    ///
    /// # Examples
    ///
    /// ```rust
    /// let mut petnames = petname::Petnames::default();
    /// petnames.retain(|s| s.starts_with("b"));
    /// petnames.generate_one(2, ".");
    /// ```
    ///
    /// This is merely a convenience wrapper that applies the same predicate to
    /// the adjectives, adverbs, and names lists.
    ///
    pub fn retain<F>(&mut self, predicate: F)
    where
        F: Fn(&&str) -> bool,
    {
        self.adjectives.retain(&predicate);
        self.adverbs.retain(&predicate);
        self.names.retain(&predicate);
    }

    /// Calculate the cardinality of this `Petnames`.
    ///
    /// If this is low, names may be repeated by the generator with a higher
    /// frequency than your use-case may allow. If it is 0 (zero) the generator
    /// will panic (unless `words` is also zero).
    ///
    /// This can saturate. If the total possible combinations of words exceeds
    /// `u128::MAX` then this will return `u128::MAX`.
    pub fn cardinality(&self, words: u8) -> u128 {
        let mut total: u128 = if words == 0 { 0 } else { 1 };
        for num in (0..words).rev() {
            total = total.saturating_mul(match num {
                0 => self.names.len() as u128,
                1 => self.adjectives.len() as u128,
                _ => self.adverbs.len() as u128,
            });
        }
        total
    }

    /// Generate a new petname.
    ///
    /// # Examples
    ///
    /// ```rust
    /// let mut rng = rand::thread_rng();
    /// petname::Petnames::default().generate(&mut rng, 7, ":");
    /// ```
    ///
    /// # Panics
    ///
    /// If a word list is empty.
    ///
    pub fn generate<RNG>(&self, rng: &mut RNG, words: u8, separator: &str) -> String
    where
        RNG: rand::Rng,
    {
        // Adverbs all the way, finishing with adjective then name.
        let mut parts = Vec::with_capacity(words as usize);
        for num in (0..words).rev() {
            parts.push(*match num {
                0 => self.names.choose(rng).unwrap(),
                1 => self.adjectives.choose(rng).unwrap(),
                _ => self.adverbs.choose(rng).unwrap(),
            });
        }
        parts.join(separator)
    }

    /// Generate a single new petname.
    ///
    /// This is like `generate` but uses `rand::thread_rng` as the random
    /// source. For efficiency use `generate` when creating multiple names, or
    /// when you want to use a custom source of randomness.
    pub fn generate_one(&self, words: u8, separator: &str) -> String {
        self.generate(&mut rand::thread_rng(), words, separator)
    }
}

impl<'a> Default for Petnames<'a> {
    fn default() -> Self {
        Self::default()
    }
}

#[cfg(test)]
mod tests {

    use super::{petname, Petnames};
    use rand;

    #[test]
    fn default_petnames_has_adjectives() {
        let petnames = Petnames::default();
        assert_ne!(petnames.adjectives.len(), 0);
    }

    #[test]
    fn default_petnames_has_adverbs() {
        let petnames = Petnames::default();
        assert_ne!(petnames.adverbs.len(), 0);
    }

    #[test]
    fn default_petnames_has_names() {
        let petnames = Petnames::default();
        assert_ne!(petnames.names.len(), 0);
    }

    #[test]
    fn default_petnames_has_non_zero_cardinality() {
        let petnames = Petnames::default();
        // This test will need to be adjusted when word lists change.
        assert_eq!(0, petnames.cardinality(0));
        assert_eq!(456, petnames.cardinality(1));
        assert_eq!(204744, petnames.cardinality(2));
        assert_eq!(53438184, petnames.cardinality(3));
        assert_eq!(13947366024, petnames.cardinality(4));
    }

    #[test]
    fn generate_uses_adverb_adjective_name() {
        let petnames = Petnames {
            adjectives: vec!["adjective"],
            adverbs: vec!["adverb"],
            names: vec!["name"],
        };
        assert_eq!(
            petnames.generate(&mut rand::thread_rng(), 3, "-"),
            "adverb-adjective-name"
        );
    }

    #[test]
    fn petname_renders_desired_number_of_words() {
        assert_eq!(petname(7, "-").split("-").count(), 7);
    }

    #[test]
    fn petname_renders_with_desired_separator() {
        assert_eq!(petname(7, "@").split("@").count(), 7);
    }
}
<|endoftext|>