<commit_before>/*
 * Copyright 2015-2017 Nathan Fiedler
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

extern crate magick_rust;

use magick_rust::{MagickWand, magick_wand_genesis, MetricType, ColorspaceType, FilterType, DitherMethod};

use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::sync::{Once, ONCE_INIT};
use magick_rust::ToMagick;

// Used to make sure MagickWand is initialized exactly once. Note that we
// do not bother shutting down, we simply exit when the tests are done.
static START: Once = ONCE_INIT;

#[test]
fn test_new_drop() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    MagickWand::new();
}

#[test]
fn test_resize_image() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    assert_eq!(512, wand.get_image_width());
    assert_eq!(384, wand.get_image_height());
    let halfwidth = match wand.get_image_width() {
        1 => 1,
        width => width / 2
    };
    let halfheight = match wand.get_image_height() {
        1 => 1,
        height => height / 2
    };
    wand.resize_image(halfwidth, halfheight, FilterType::LanczosFilter);
    assert_eq!(256, wand.get_image_width());
    assert_eq!(192, wand.get_image_height());
}

#[test]
fn test_read_from_blob() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();

    let path = Path::new("tests/data/IMG_5745.JPG");
    let mut file = match File::open(&path) {
        Err(why) => panic!("couldn't open file: {}", Error::description(&why)),
        Ok(file) => file
    };
    let mut data: Vec<u8> = Vec::new();
    match file.read_to_end(&mut data) {
        Err(why) => panic!("couldn't read file: {}", Error::description(&why)),
        Ok(_) => ()
    };
    assert!(wand.read_image_blob(&data).is_ok());
    assert_eq!(512, wand.get_image_width());
    assert_eq!(384, wand.get_image_height());
}

#[test]
fn test_write_image_to_blob() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    assert_eq!(512, wand.get_image_width());
    assert_eq!(384, wand.get_image_height());
    let blob = wand.write_image_blob("jpeg").unwrap();
    let blob_len = blob.len();
    // There is a slight degree of variability from platform to platform,
    // and version to version of ImageMagick.
    assert!(blob_len > 103000 && blob_len < 105000);
    // should be able to read it back again
    assert!(wand.read_image_blob(&blob).is_ok());
    assert_eq!(512, wand.get_image_width());
    assert_eq!(384, wand.get_image_height());
}

#[test]
fn test_write_images_to_blob() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    assert_eq!(512, wand.get_image_width());
    assert_eq!(384, wand.get_image_height());
    let blob = wand.write_images_blob("jpeg").unwrap();
    let blob_len = blob.len();
    // There is a slight degree of variability from platform to platform,
    // and version to version of ImageMagick.
    assert!(blob_len > 103000 && blob_len < 105000);
    // should be able to read it back again
    assert!(wand.read_image_blob(&blob).is_ok());
    assert_eq!(512, wand.get_image_width());
    assert_eq!(384, wand.get_image_height());
}

#[test]
fn test_fit() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    assert_eq!(512, wand.get_image_width());
    assert_eq!(384, wand.get_image_height());
    wand.fit(240, 240);
    assert_eq!(240, wand.get_image_width());
    assert_eq!(180, wand.get_image_height());
}

#[test]
fn test_get_image_property() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    // retrieve a property we know exists
    let found_value = wand.get_image_property("exif:DateTimeOriginal");
    assert!(found_value.is_ok());
    assert_eq!("2014:04:23 13:33:08", found_value.unwrap());
    // retrieve a property that does not exist
    let missing_value = wand.get_image_property("exif:Foobar");
    assert!(missing_value.is_err());
    assert_eq!("missing property", missing_value.unwrap_err());
}

#[test]
fn test_requires_orientation() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    assert_eq!(false, wand.requires_orientation());
}

#[test]
fn test_auto_orient() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745_rotl.JPG").is_ok());
    assert_eq!(true, wand.requires_orientation());
    assert!(wand.auto_orient());
    assert_eq!(false, wand.requires_orientation());
}

#[test]
fn test_compare_images() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand1 = MagickWand::new();
    assert!(wand1.read_image("tests/data/IMG_5745.JPG").is_ok());

    let wand2 = MagickWand::new();
    assert!(wand2.read_image("tests/data/IMG_5745_rotl.JPG").is_ok());
    wand2.auto_orient();

    let (distortion, diff) = wand1.compare_images(&wand2, MetricType::RootMeanSquaredErrorMetric);
    assert!(distortion < 0.01);
    assert!(diff.is_some());
}

#[test]
fn test_set_option() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let mut wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    // The jpeg:size option is just a hint.
    wand.set_option("jpeg:size", "128x128").unwrap();
    let blob = wand.write_image_blob("jpeg").unwrap();
    assert!(wand.read_image_blob(&blob).is_ok());
    assert_eq!(192, wand.get_image_width());
    assert_eq!(144, wand.get_image_height());
}

#[test]
fn test_page_geometry() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/rust.gif").is_ok());
    assert_eq!((156, 150, 39, 36), wand.get_image_page()); /* width, height, x offset, y offset */
    assert_eq!(80, wand.get_image_width());
    assert_eq!(76, wand.get_image_height());
}

#[test]
fn test_transform_image_colorspace() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    assert_eq!(wand.get_image_colorspace(), ColorspaceType::sRGBColorspace);

    let pixel_color = wand.get_image_pixel_color(10, 10).unwrap();
    assert_ne!(pixel_color.get_hsl().hue, 0.0);

    assert!(wand.transform_image_colorspace(ColorspaceType::GRAYColorspace).is_ok());
    assert_eq!(wand.get_image_colorspace(), ColorspaceType::GRAYColorspace);

    let pixel_grayscale = wand.get_image_pixel_color(10, 10).unwrap();
    assert_eq!(pixel_grayscale.get_hsl().hue, 0.0);

    /* The output of `export_image_pixels` should match
     * `convert -type Grayscale tests/data/IMG_5745.JPG[2x2+0+0] txt:` */
    assert_eq!(wand.export_image_pixels(0, 0, 2, 2, "I").unwrap(),
        vec![212, 212, 210, 210])
}

#[test]
fn test_color_reduction() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    assert_eq!(38322, wand.get_image_colors());

    assert!(wand.quantize_image(6, ColorspaceType::RGBColorspace, 1,
                                DitherMethod::UndefinedDitherMethod, false.to_magick()).is_ok());
    assert_eq!(6, wand.get_image_colors());

    let histogram = wand.get_image_histogram().unwrap();
    assert_eq!(6, histogram.len());
    assert_eq!(wand.get_image_width() * wand.get_image_height(),
               histogram.iter().fold(0, |total_colors, wand| total_colors + wand.get_color_count()));
}
<commit_msg>Image colors value has some variability<commit_after>/*
 * Copyright 2015-2017 Nathan Fiedler
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

extern crate magick_rust;

use magick_rust::{MagickWand, magick_wand_genesis, MetricType, ColorspaceType, FilterType, DitherMethod};

use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::sync::{Once, ONCE_INIT};
use magick_rust::ToMagick;

// Used to make sure MagickWand is initialized exactly once. Note that we
// do not bother shutting down, we simply exit when the tests are done.
static START: Once = ONCE_INIT;

#[test]
fn test_new_drop() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    MagickWand::new();
}

#[test]
fn test_resize_image() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    assert_eq!(512, wand.get_image_width());
    assert_eq!(384, wand.get_image_height());
    let halfwidth = match wand.get_image_width() {
        1 => 1,
        width => width / 2
    };
    let halfheight = match wand.get_image_height() {
        1 => 1,
        height => height / 2
    };
    wand.resize_image(halfwidth, halfheight, FilterType::LanczosFilter);
    assert_eq!(256, wand.get_image_width());
    assert_eq!(192, wand.get_image_height());
}

#[test]
fn test_read_from_blob() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();

    let path = Path::new("tests/data/IMG_5745.JPG");
    let mut file = match File::open(&path) {
        Err(why) => panic!("couldn't open file: {}", Error::description(&why)),
        Ok(file) => file
    };
    let mut data: Vec<u8> = Vec::new();
    match file.read_to_end(&mut data) {
        Err(why) => panic!("couldn't read file: {}", Error::description(&why)),
        Ok(_) => ()
    };
    assert!(wand.read_image_blob(&data).is_ok());
    assert_eq!(512, wand.get_image_width());
    assert_eq!(384, wand.get_image_height());
}

#[test]
fn test_write_image_to_blob() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    assert_eq!(512, wand.get_image_width());
    assert_eq!(384, wand.get_image_height());
    let blob = wand.write_image_blob("jpeg").unwrap();
    let blob_len = blob.len();
    // There is a slight degree of variability from platform to platform,
    // and version to version of ImageMagick.
    assert!(blob_len > 103000 && blob_len < 105000);
    // should be able to read it back again
    assert!(wand.read_image_blob(&blob).is_ok());
    assert_eq!(512, wand.get_image_width());
    assert_eq!(384, wand.get_image_height());
}

#[test]
fn test_write_images_to_blob() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    assert_eq!(512, wand.get_image_width());
    assert_eq!(384, wand.get_image_height());
    let blob = wand.write_images_blob("jpeg").unwrap();
    let blob_len = blob.len();
    // There is a slight degree of variability from platform to platform,
    // and version to version of ImageMagick.
    assert!(blob_len > 103000 && blob_len < 105000);
    // should be able to read it back again
    assert!(wand.read_image_blob(&blob).is_ok());
    assert_eq!(512, wand.get_image_width());
    assert_eq!(384, wand.get_image_height());
}

#[test]
fn test_fit() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    assert_eq!(512, wand.get_image_width());
    assert_eq!(384, wand.get_image_height());
    wand.fit(240, 240);
    assert_eq!(240, wand.get_image_width());
    assert_eq!(180, wand.get_image_height());
}

#[test]
fn test_get_image_property() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    // retrieve a property we know exists
    let found_value = wand.get_image_property("exif:DateTimeOriginal");
    assert!(found_value.is_ok());
    assert_eq!("2014:04:23 13:33:08", found_value.unwrap());
    // retrieve a property that does not exist
    let missing_value = wand.get_image_property("exif:Foobar");
    assert!(missing_value.is_err());
    assert_eq!("missing property", missing_value.unwrap_err());
}

#[test]
fn test_requires_orientation() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    assert_eq!(false, wand.requires_orientation());
}

#[test]
fn test_auto_orient() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745_rotl.JPG").is_ok());
    assert_eq!(true, wand.requires_orientation());
    assert!(wand.auto_orient());
    assert_eq!(false, wand.requires_orientation());
}

#[test]
fn test_compare_images() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand1 = MagickWand::new();
    assert!(wand1.read_image("tests/data/IMG_5745.JPG").is_ok());

    let wand2 = MagickWand::new();
    assert!(wand2.read_image("tests/data/IMG_5745_rotl.JPG").is_ok());
    wand2.auto_orient();

    let (distortion, diff) = wand1.compare_images(&wand2, MetricType::RootMeanSquaredErrorMetric);
    assert!(distortion < 0.01);
    assert!(diff.is_some());
}

#[test]
fn test_set_option() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let mut wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    // The jpeg:size option is just a hint.
    wand.set_option("jpeg:size", "128x128").unwrap();
    let blob = wand.write_image_blob("jpeg").unwrap();
    assert!(wand.read_image_blob(&blob).is_ok());
    assert_eq!(192, wand.get_image_width());
    assert_eq!(144, wand.get_image_height());
}

#[test]
fn test_page_geometry() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/rust.gif").is_ok());
    assert_eq!((156, 150, 39, 36), wand.get_image_page()); /* width, height, x offset, y offset */
    assert_eq!(80, wand.get_image_width());
    assert_eq!(76, wand.get_image_height());
}

#[test]
fn test_transform_image_colorspace() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    assert_eq!(wand.get_image_colorspace(), ColorspaceType::sRGBColorspace);

    let pixel_color = wand.get_image_pixel_color(10, 10).unwrap();
    assert_ne!(pixel_color.get_hsl().hue, 0.0);

    assert!(wand.transform_image_colorspace(ColorspaceType::GRAYColorspace).is_ok());
    assert_eq!(wand.get_image_colorspace(), ColorspaceType::GRAYColorspace);

    let pixel_grayscale = wand.get_image_pixel_color(10, 10).unwrap();
    assert_eq!(pixel_grayscale.get_hsl().hue, 0.0);

    /* The output of `export_image_pixels` should match
     * `convert -type Grayscale tests/data/IMG_5745.JPG[2x2+0+0] txt:` */
    assert_eq!(wand.export_image_pixels(0, 0, 2, 2, "I").unwrap(),
        vec![212, 212, 210, 210])
}

#[test]
fn test_color_reduction() {
    START.call_once(|| {
        magick_wand_genesis();
    });
    let wand = MagickWand::new();
    assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok());
    // There is a slight degree of variability from platform to platform,
    // and version to version of ImageMagick.
    let image_colors = wand.get_image_colors();
    assert!(image_colors > 38000 || image_colors < 40000);

    assert!(wand.quantize_image(6, ColorspaceType::RGBColorspace, 1,
                                DitherMethod::UndefinedDitherMethod, false.to_magick()).is_ok());
    assert_eq!(6, wand.get_image_colors());

    let histogram = wand.get_image_histogram().unwrap();
    assert_eq!(6, histogram.len());
    assert_eq!(wand.get_image_width() * wand.get_image_height(),
               histogram.iter().fold(0, |total_colors, wand| total_colors + wand.get_color_count()));
}
<|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/.
 */

extern crate numeral;

use numeral::Cardinal;

fn read_file(filename: &str) -> Result<String, std::io::Error> {
    use std::fs::File;
    use std::io::Read;

    let mut file = File::open(filename)?;
    let mut buffer = String::new();
    file.read_to_string(&mut buffer)?;
    Ok(buffer)
}

macro_rules! test_call_on_min_max {
    ($fn_name:ident, $numtype:ty) => {
        #[test]
        fn $fn_name() {
            <$numtype>::max_value().cardinal();
            <$numtype>::min_value().cardinal();
        }
    };
}

test_call_on_min_max!(call_on_min_max_i8, i8);
test_call_on_min_max!(call_on_min_max_u8, u8);
test_call_on_min_max!(call_on_min_max_i16, i16);
test_call_on_min_max!(call_on_min_max_u16, u16);
test_call_on_min_max!(call_on_min_max_i32, i32);
test_call_on_min_max!(call_on_min_max_u32, u32);
test_call_on_min_max!(call_on_min_max_i64, i64);
test_call_on_min_max!(call_on_min_max_u64, u64);
test_call_on_min_max!(call_on_min_max_isize, isize);
test_call_on_min_max!(call_on_min_max_usize, usize);

macro_rules! test_call_on_range {
    ($fn_name:ident, $numtype:ty) => {
        #[test]
        fn $fn_name() {
            for n in (<$numtype>::min_value())..=(<$numtype>::max_value()) {
                n.cardinal();
            }
        }
    };
}

test_call_on_range!(call_on_range_i8, i8);
test_call_on_range!(call_on_range_u8, u8);
test_call_on_range!(call_on_range_i16, i16);
test_call_on_range!(call_on_range_u16, u16);

macro_rules! test_call_on_critical_ranges {
    ($fn_name:ident, $numtype:ty) => {
        #[test]
        fn $fn_name() {
            for n in (<$numtype>::min_value())..=(<$numtype>::min_value()) + 130 {
                n.cardinal();
            }
            for n in (<$numtype>::max_value()) - 130..=(<$numtype>::max_value()) {
                n.cardinal();
            }
            if <$numtype>::min_value() != 0 {
                for n in -130..=130 {
                    n.cardinal();
                }
            }
        }
    };
}

test_call_on_critical_ranges!(call_on_critical_ranges_i32, i32);
test_call_on_critical_ranges!(call_on_critical_ranges_u32, u32);
test_call_on_critical_ranges!(call_on_critical_ranges_i64, i64);
test_call_on_critical_ranges!(call_on_critical_ranges_u64, u64);
test_call_on_critical_ranges!(call_on_critical_ranges_isize, isize);
test_call_on_critical_ranges!(call_on_critical_ranges_usize, usize);

#[test]
fn cardinal_value_m256_256() {
    let cardinals = read_file("tests/cardinal_m256..=256.txt").unwrap();
    assert!(
        cardinals
            .lines()
            .eq((-256..=256).map(|n: i32| n.cardinal()))
    );
}

#[test]
fn cardinal_value_min_max_int() {
    let cardinals = read_file("tests/cardinal_min_max.txt").unwrap();
    let mut lines = cardinals.lines();
    macro_rules! assert_eq_min_max {
        ($signed:ty, $unsigned:ty) => {
            assert_eq!(lines.next().unwrap(), <$signed>::min_value().cardinal());
            assert_eq!(lines.next().unwrap(), <$signed>::max_value().cardinal());
            assert_eq!(lines.next().unwrap(), <$unsigned>::max_value().cardinal());
        };
    }
    assert_eq!(lines.next().unwrap(), 0.cardinal());
    assert_eq_min_max!(i8, u8);
    assert_eq_min_max!(i16, u16);
    assert_eq_min_max!(i32, u32);
    assert_eq_min_max!(i64, u64);
}

#[test]
fn cardinal_value_min_max_ptr() {
    use std::mem::size_of;

    macro_rules! assert_eq_min_max_if_ptr_is {
        ($ptr:ty, $int:ty) => {
            if size_of::<$ptr>() == size_of::<$int>() {
                assert_eq!(<$ptr>::min_value().cardinal(), <$int>::min_value().cardinal());
                assert_eq!(<$ptr>::max_value().cardinal(), <$int>::max_value().cardinal());
            }
        };
    }
    assert_eq_min_max_if_ptr_is!(isize, i8);
    assert_eq_min_max_if_ptr_is!(isize, i16);
    assert_eq_min_max_if_ptr_is!(isize, i32);
    assert_eq_min_max_if_ptr_is!(isize, i64);
    assert_eq_min_max_if_ptr_is!(usize, u8);
    assert_eq_min_max_if_ptr_is!(usize, u16);
    assert_eq_min_max_if_ptr_is!(usize, u32);
    assert_eq_min_max_if_ptr_is!(usize, u64);
}
<commit_msg>read_to_string is stable (1.26)<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/.
 */

extern crate numeral;

use numeral::Cardinal;

macro_rules! test_call_on_min_max {
    ($fn_name:ident, $numtype:ty) => {
        #[test]
        fn $fn_name() {
            <$numtype>::max_value().cardinal();
            <$numtype>::min_value().cardinal();
        }
    };
}

test_call_on_min_max!(call_on_min_max_i8, i8);
test_call_on_min_max!(call_on_min_max_u8, u8);
test_call_on_min_max!(call_on_min_max_i16, i16);
test_call_on_min_max!(call_on_min_max_u16, u16);
test_call_on_min_max!(call_on_min_max_i32, i32);
test_call_on_min_max!(call_on_min_max_u32, u32);
test_call_on_min_max!(call_on_min_max_i64, i64);
test_call_on_min_max!(call_on_min_max_u64, u64);
test_call_on_min_max!(call_on_min_max_isize, isize);
test_call_on_min_max!(call_on_min_max_usize, usize);

macro_rules! test_call_on_range {
    ($fn_name:ident, $numtype:ty) => {
        #[test]
        fn $fn_name() {
            for n in (<$numtype>::min_value())..=(<$numtype>::max_value()) {
                n.cardinal();
            }
        }
    };
}

test_call_on_range!(call_on_range_i8, i8);
test_call_on_range!(call_on_range_u8, u8);
test_call_on_range!(call_on_range_i16, i16);
test_call_on_range!(call_on_range_u16, u16);

macro_rules! test_call_on_critical_ranges {
    ($fn_name:ident, $numtype:ty) => {
        #[test]
        fn $fn_name() {
            for n in (<$numtype>::min_value())..=(<$numtype>::min_value()) + 130 {
                n.cardinal();
            }
            for n in (<$numtype>::max_value()) - 130..=(<$numtype>::max_value()) {
                n.cardinal();
            }
            if <$numtype>::min_value() != 0 {
                for n in -130..=130 {
                    n.cardinal();
                }
            }
        }
    };
}

test_call_on_critical_ranges!(call_on_critical_ranges_i32, i32);
test_call_on_critical_ranges!(call_on_critical_ranges_u32, u32);
test_call_on_critical_ranges!(call_on_critical_ranges_i64, i64);
test_call_on_critical_ranges!(call_on_critical_ranges_u64, u64);
test_call_on_critical_ranges!(call_on_critical_ranges_isize, isize);
test_call_on_critical_ranges!(call_on_critical_ranges_usize, usize);

#[test]
fn cardinal_value_m256_256() {
    let cardinals = std::fs::read_to_string("tests/cardinal_m256..=256.txt").unwrap();
    assert!(
        cardinals
            .lines()
            .eq((-256..=256).map(|n: i32| n.cardinal()))
    );
}

#[test]
fn cardinal_value_min_max_int() {
    let cardinals = std::fs::read_to_string("tests/cardinal_min_max.txt").unwrap();
    let mut lines = cardinals.lines();
    macro_rules! assert_eq_min_max {
        ($signed:ty, $unsigned:ty) => {
            assert_eq!(lines.next().unwrap(), <$signed>::min_value().cardinal());
            assert_eq!(lines.next().unwrap(), <$signed>::max_value().cardinal());
            assert_eq!(lines.next().unwrap(), <$unsigned>::max_value().cardinal());
        };
    }
    assert_eq!(lines.next().unwrap(), 0.cardinal());
    assert_eq_min_max!(i8, u8);
    assert_eq_min_max!(i16, u16);
    assert_eq_min_max!(i32, u32);
    assert_eq_min_max!(i64, u64);
}

#[test]
fn cardinal_value_min_max_ptr() {
    use std::mem::size_of;

    macro_rules! assert_eq_min_max_if_ptr_is {
        ($ptr:ty, $int:ty) => {
            if size_of::<$ptr>() == size_of::<$int>() {
                assert_eq!(<$ptr>::min_value().cardinal(), <$int>::min_value().cardinal());
                assert_eq!(<$ptr>::max_value().cardinal(), <$int>::max_value().cardinal());
            }
        };
    }
    assert_eq_min_max_if_ptr_is!(isize, i8);
    assert_eq_min_max_if_ptr_is!(isize, i16);
    assert_eq_min_max_if_ptr_is!(isize, i32);
    assert_eq_min_max_if_ptr_is!(isize, i64);
    assert_eq_min_max_if_ptr_is!(usize, u8);
    assert_eq_min_max_if_ptr_is!(usize, u16);
    assert_eq_min_max_if_ptr_is!(usize, u32);
    assert_eq_min_max_if_ptr_is!(usize, u64);
}
<|endoftext|>


<commit_before>extern crate tvdb;
extern crate rand;

use tvdb::{Tvdb, EpisodeId, TvdbResult, TvdbError};

const APIKEY: &'static str = "0629B785CE550C8D";

#[test]
fn search() {
    let api = Tvdb::new(APIKEY.to_owned());
    api.login().unwrap();
    let sr = api.search(Some("scrubs"), None);
    println!("{:?}", sr);
    assert!(sr.ok().unwrap().data.unwrap()[0].series_name == "Scrubs");
}

#[test]
fn nonexist() {
    let api = Tvdb::new(APIKEY);
    let sr = api.search(Some("ladlkgdklfgsdfglk"), None);
    assert!(sr.is_err());
}

#[test]
fn lookup_by_epid(){
    let api = Tvdb::new(APIKEY);
    api.login().unwrap();
    let ep = api.episode(EpisodeId::new(184603, "en"));
    println!("Episode: {:?}", ep);
    assert!(ep.unwrap().episode_name == "My Mentor");
}

#[test]
fn lookup_by_u32(){
    let api = Tvdb::new(APIKEY);
    api.login().unwrap();
    let ep = api.episode(184603);
    println!("Episode; {:?}", ep);
    assert!(ep.unwrap().episode_name == "My Mentor");
}

#[test]
fn random_series(){
    // Opening a bunch of ~random series to check for panicing
    use rand::{Rng, SeedableRng, StdRng};

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);
    for _ in 1..10{
        let rid = rng.gen_range::<u32>(1, 20000);
        println!("Getting series {}", rid);

        let api = Tvdb::new(APIKEY);
        let ep = api.episode(EpisodeId::new(rid, "en"));
        println!("{:?}", ep);
        match ep{
            Ok(ep) => println!("{}", ep.episode_name),
            Err(e) => println!("{:?}", e),
        }
    }
}

#[derive(Debug,Clone)]
struct DummyRequestClient;

impl DummyRequestClient{
    pub fn new() -> DummyRequestClient{
        return DummyRequestClient{};
    }
}
use tvdb::RequestClient;
impl RequestClient for DummyRequestClient{
    fn get_url(&self, url: &str, jwt_token: Option<String>) -> TvdbResult<String>{
        return Err(TvdbError::CommunicationError{reason: "Fake error!".into()});
    }
}

#[test]
fn custom_http_client() {
    let c = DummyRequestClient::new();

    let mut api = Tvdb::new(APIKEY);
    api.set_http_client(&c);

    let result = api.search(Some("scrubs"), None);
    println!("{:?}", result);

    match result{
        Ok(_) => panic!("Expected error"),
        Err(e) => (
            match e {
                TvdbError::CommunicationError{reason: _} => (),
                _ => panic!("Unexpected"),
            }
        ),
    }
}

#[test]
fn all_episodes(){
    let api = Tvdb::new(APIKEY.to_owned());
    api.login().unwrap();
    let sr = api.search(Some("scrubs"), None).unwrap();
    let first_id = sr.data.unwrap()[0].id.unwrap();
    let eps = api.series_episodes(first_id, 1).unwrap();
    let data = eps.data.unwrap();
    assert!(data.len() > 10);
    let ep = data[0].clone();
    assert!(ep.episode_name.unwrap() == "My First Day");
}
<commit_msg>Better error in test<commit_after>extern crate tvdb;
extern crate rand;

use tvdb::{Tvdb, EpisodeId, TvdbResult, TvdbError};

const APIKEY: &'static str = "0629B785CE550C8D";

#[test]
fn search() {
    let api = Tvdb::new(APIKEY.to_owned());
    api.login().unwrap();
    let sr = api.search(Some("scrubs"), None);
    println!("{:?}", sr);
    assert!(sr.ok().unwrap().data.unwrap()[0].series_name == "Scrubs");
}

#[test]
fn nonexist() {
    let api = Tvdb::new(APIKEY);
    let sr = api.search(Some("ladlkgdklfgsdfglk"), None);
    assert!(sr.is_err());
}

#[test]
fn lookup_by_epid(){
    let api = Tvdb::new(APIKEY);
    api.login().unwrap();
    let ep = api.episode(EpisodeId::new(184603, "en"));
    println!("Episode: {:?}", ep);
    assert!(ep.unwrap().episode_name == "My Mentor");
}

#[test]
fn lookup_by_u32(){
    let api = Tvdb::new(APIKEY);
    api.login().unwrap();
    let ep = api.episode(184603);
    println!("Episode; {:?}", ep);
    assert!(ep.unwrap().episode_name == "My Mentor");
}

#[test]
fn random_series(){
    // Opening a bunch of ~random series to check for panicing
    use rand::{Rng, SeedableRng, StdRng};

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);
    for _ in 1..10{
        let rid = rng.gen_range::<u32>(1, 20000);
        println!("Getting series {}", rid);

        let api = Tvdb::new(APIKEY);
        let ep = api.episode(EpisodeId::new(rid, "en"));
        println!("{:?}", ep);
        match ep{
            Ok(ep) => println!("{}", ep.episode_name),
            Err(e) => println!("{:?}", e),
        }
    }
}

#[derive(Debug,Clone)]
struct DummyRequestClient;

impl DummyRequestClient{
    pub fn new() -> DummyRequestClient{
        return DummyRequestClient{};
    }
}
use tvdb::RequestClient;
impl RequestClient for DummyRequestClient {
    fn get_url(&self, url: &str, jwt_token: Option<String>) -> TvdbResult<String> {
        return Err(TvdbError::CommunicationError {
            reason: format!(
                "Fake error while doing fake request for: {:?} with JWT {:?}",
                url, jwt_token,
            ),
        });
    }
}

#[test]
fn custom_http_client() {
    let c = DummyRequestClient::new();

    let mut api = Tvdb::new(APIKEY);
    api.set_http_client(&c);

    let result = api.search(Some("scrubs"), None);
    println!("{:?}", result);

    match result{
        Ok(_) => panic!("Expected error"),
        Err(e) => (
            match e {
                TvdbError::CommunicationError{reason: _} => (),
                _ => panic!("Unexpected"),
            }
        ),
    }
}

#[test]
fn all_episodes(){
    let api = Tvdb::new(APIKEY.to_owned());
    api.login().unwrap();
    let sr = api.search(Some("scrubs"), None).unwrap();
    let first_id = sr.data.unwrap()[0].id.unwrap();
    let eps = api.series_episodes(first_id, 1).unwrap();
    let data = eps.data.unwrap();
    assert!(data.len() > 10);
    let ep = data[0].clone();
    assert!(ep.episode_name.unwrap() == "My First Day");
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate rand;

pub const DEFAULT_ENGLISH_DICTIONARY_PATH: &'static str = "/usr/share/dict/words";

#[derive(Debug)]
pub struct EnglishPasswordOptions {
    pub num_words: u8,
    pub dictionary_path: String,
}

#[derive(Debug)]
pub struct KanaPasswordOptions {
    pub syllable_counts: Vec<u8>,
}

pub enum PasswordOptions {
    English(EnglishPasswordOptions),
    Japanese(KanaPasswordOptions),
}

mod args {
    use clap::{value_t, values_t};

    // Aborts this process on error.
    pub fn parse_args() -> crate::PasswordOptions {
        let matches = clap::App::new("xkpw")
            .version("0.1.0")
            .author("j39m")
            .about("Generates passwords")
            .subcommand(
                clap::SubCommand::with_name("en")
                    .about("generates dictionary passwords in English")
                    .arg(clap::Arg::with_name("num-words").required(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("jp")
                    .about("generates random strings of Japanese syllables")
                    .arg(
                        clap::Arg::with_name("syllable-counts")
                            .required(true)
                            .multiple(true),
                    ),
            )
            .get_matches();

        match matches.subcommand() {
            ("en", Some(en_matches)) => {
                return crate::PasswordOptions::English(crate::EnglishPasswordOptions {
                    num_words: clap::value_t!(en_matches, "num-words", u8)
                        .unwrap_or_else(|e| e.exit()),
                    dictionary_path: crate::DEFAULT_ENGLISH_DICTIONARY_PATH.to_owned(),
                })
            }
            ("jp", Some(jp_matches)) => {
                return crate::PasswordOptions::Japanese(crate::KanaPasswordOptions {
                    syllable_counts: clap::values_t!(jp_matches, "syllable-counts", u8)
                        .unwrap_or_else(|e| e.exit()),
                })
            }
            _ => (),
        }
        crate::PasswordOptions::Japanese(crate::KanaPasswordOptions {
            syllable_counts: vec![4, 3, 3, 3],
        })
    }
} // mod args

mod kana {
    const BASE: &'static [&str] = &[
        "a", "i", "u", "e", "o", "ka", "ki", "ku", "ke", "ko", "sa", "shi", "su", "se", "so", "ta",
        "chi", "tsu", "te", "to", "na", "ni", "nu", "ne", "no", "ha", "hi", "hu", "he", "ho", "ma",
        "mi", "mu", "me", "mo", "ya", "yu", "yo", "ra", "ri", "ru", "re", "ro", "wa", "wo",
    ];

    const DIGRAPHS: &'static [&str] = &[
        "kya", "kyu", "kyo", "sha", "shu", "sho", "cha", "chu", "cho", "nya", "nyu", "nyo", "hya",
        "hyu", "hyo", "mya", "myu", "myo", "rya", "ryu", "ryo",
    ];

    const DIACRITICS: &'static [&str] = &[
        "ga", "gi", "gu", "ge", "go", "za", "ji", "zu", "ze", "zo", "da", "de", "do", "ba", "bi",
        "bu", "be", "bo", "pa", "pi", "pu", "pe", "po",
    ];

    const DIGRAPHS_WITH_DIACRITICS: &'static [&str] = &[
        "gya", "gyu", "gyo", "ja", "ju", "jo", "bya", "byu", "byo", "pya", "pyu", "pyo",
    ];

    fn all() -> Vec<&'static str> {
        let mut all_kana: Vec<&'static str> = Vec::new();
        all_kana.extend(BASE);
        all_kana.extend(DIGRAPHS);
        all_kana.extend(DIACRITICS);
        all_kana.extend(DIGRAPHS_WITH_DIACRITICS);
        all_kana
    }

    fn simple() -> Vec<&'static str> {
        let mut simple_kana: Vec<&'static str> = Vec::new();
        simple_kana.extend(BASE);
        simple_kana.extend(DIACRITICS);
        simple_kana
    }

    pub fn get(use_simple: bool) -> Vec<&'static str> {
        match use_simple {
            true => simple(),
            false => all(),
        }
    }
} // mod kana

mod helpers {
    use rand::seq::SliceRandom;
    use std::convert::TryInto;
    use std::io::Read;

    // Reads the dictionary at |path| and returns a linewise vector of
    // its contents.
    fn ingest_english_dictionary(path: &std::path::Path) -> std::io::Result<Vec<String>> {
        let mut file = std::fs::File::open(path)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        Ok(contents
            .lines()
            .map(|word| word.trim().to_lowercase())
            .collect())
    }

    // Assumes ownership of a Vector of owned |words| and prints them
    // separated by spaces.
    fn print_words(words: Vec<String>) {
        let mut iter = words.into_iter();
        if let Some(word) = iter.next() {
            print!("{}", word);
            for word in iter {
                print!(" {}", word);
            }
            print!("\n");
        }
    }

    // Returns 1 if we fail to read the word dictionary.
    fn print_english_password(options: crate::EnglishPasswordOptions) -> i32 {
        let all_words =
            match ingest_english_dictionary(std::path::Path::new(&options.dictionary_path)) {
                Ok(result) => result,
                Err(error) => {
                    eprintln!("Error reading dictionary: {}", error);
                    return 1;
                }
            };
        let mut rng = &mut rand::thread_rng();
        let selection: Vec<String> = all_words
            .choose_multiple(&mut rng, options.num_words.try_into().unwrap())
            .map(|borrowed| borrowed.to_owned())
            .collect();

        print_words(selection);
        0
    }

    // Builds a single random pseudo-Japanese word from |kana_set|.
    fn build_kana_word(kana_set: &Vec<&'static str>, syllable_count: &u8) -> String {
        let mut collected_kana: Vec<&'static str> = Vec::new();
        let mut rng = &mut rand::thread_rng();
        for _ in 0..*syllable_count {
            collected_kana.push(kana_set.choose(&mut rng).unwrap());
        }
        collected_kana.join("")
    }

    // Builds random pseudo-Japanese words from |kana_set|, observing
    // the word lengths specified by |options|.
    fn build_kana_words(
        kana_set: Vec<&'static str>,
        options: crate::KanaPasswordOptions,
    ) -> Vec<String> {
        options
            .syllable_counts
            .iter()
            .map(|count| build_kana_word(&kana_set, count))
            .collect()
    }

    // Builds a vector of owned kana words, maps these to a vector of
    // borrowed kana words, and then prints the same.
    fn print_kana_password(options: crate::KanaPasswordOptions) {
        print_words(build_kana_words(crate::kana::get(true), options));
    }

    pub fn main() -> i32 {
        let options = crate::args::parse_args();
        match options {
            crate::PasswordOptions::English(options) => return print_english_password(options),
            crate::PasswordOptions::Japanese(options) => print_kana_password(options),
        }
        0
    }
} // mod helpers

fn main() {
    std::process::exit(crate::helpers::main());
}
<commit_msg>xkpw: Change `crate::` convention<commit_after>extern crate clap;
extern crate rand;

pub const DEFAULT_ENGLISH_DICTIONARY_PATH: &'static str = "/usr/share/dict/words";

#[derive(Debug)]
pub struct EnglishPasswordOptions {
    pub num_words: u8,
    pub dictionary_path: String,
}

#[derive(Debug)]
pub struct KanaPasswordOptions {
    pub syllable_counts: Vec<u8>,
}

pub enum PasswordOptions {
    English(EnglishPasswordOptions),
    Japanese(KanaPasswordOptions),
}

mod args {
    use super::{
        EnglishPasswordOptions, KanaPasswordOptions, PasswordOptions,
        DEFAULT_ENGLISH_DICTIONARY_PATH,
    };
    use clap::{value_t, values_t};

    // Aborts this process on error.
    pub fn parse_args() -> PasswordOptions {
        let matches = clap::App::new("xkpw")
            .version("0.1.0")
            .author("j39m")
            .about("Generates passwords")
            .subcommand(
                clap::SubCommand::with_name("en")
                    .about("generates dictionary passwords in English")
                    .arg(clap::Arg::with_name("num-words").required(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("jp")
                    .about("generates random strings of Japanese syllables")
                    .arg(
                        clap::Arg::with_name("syllable-counts")
                            .required(true)
                            .multiple(true),
                    ),
            )
            .get_matches();

        match matches.subcommand() {
            ("en", Some(en_matches)) => {
                return PasswordOptions::English(EnglishPasswordOptions {
                    num_words: clap::value_t!(en_matches, "num-words", u8)
                        .unwrap_or_else(|e| e.exit()),
                    dictionary_path: DEFAULT_ENGLISH_DICTIONARY_PATH.to_owned(),
                })
            }
            ("jp", Some(jp_matches)) => {
                return PasswordOptions::Japanese(KanaPasswordOptions {
                    syllable_counts: clap::values_t!(jp_matches, "syllable-counts", u8)
                        .unwrap_or_else(|e| e.exit()),
                })
            }
            _ => (),
        }
        PasswordOptions::Japanese(KanaPasswordOptions {
            syllable_counts: vec![4, 3, 3, 3],
        })
    }
} // mod args

mod kana {
    const BASE: &'static [&str] = &[
        "a", "i", "u", "e", "o", "ka", "ki", "ku", "ke", "ko", "sa", "shi", "su", "se", "so", "ta",
        "chi", "tsu", "te", "to", "na", "ni", "nu", "ne", "no", "ha", "hi", "hu", "he", "ho", "ma",
        "mi", "mu", "me", "mo", "ya", "yu", "yo", "ra", "ri", "ru", "re", "ro", "wa", "wo",
    ];

    const DIGRAPHS: &'static [&str] = &[
        "kya", "kyu", "kyo", "sha", "shu", "sho", "cha", "chu", "cho", "nya", "nyu", "nyo", "hya",
        "hyu", "hyo", "mya", "myu", "myo", "rya", "ryu", "ryo",
    ];

    const DIACRITICS: &'static [&str] = &[
        "ga", "gi", "gu", "ge", "go", "za", "ji", "zu", "ze", "zo", "da", "de", "do", "ba", "bi",
        "bu", "be", "bo", "pa", "pi", "pu", "pe", "po",
    ];

    const DIGRAPHS_WITH_DIACRITICS: &'static [&str] = &[
        "gya", "gyu", "gyo", "ja", "ju", "jo", "bya", "byu", "byo", "pya", "pyu", "pyo",
    ];

    fn all() -> Vec<&'static str> {
        let mut all_kana: Vec<&'static str> = Vec::new();
        all_kana.extend(BASE);
        all_kana.extend(DIGRAPHS);
        all_kana.extend(DIACRITICS);
        all_kana.extend(DIGRAPHS_WITH_DIACRITICS);
        all_kana
    }

    fn simple() -> Vec<&'static str> {
        let mut simple_kana: Vec<&'static str> = Vec::new();
        simple_kana.extend(BASE);
        simple_kana.extend(DIACRITICS);
        simple_kana
    }

    pub fn get(use_simple: bool) -> Vec<&'static str> {
        match use_simple {
            true => simple(),
            false => all(),
        }
    }
} // mod kana

mod helpers {
    use super::{EnglishPasswordOptions, KanaPasswordOptions, PasswordOptions};
    use rand::seq::SliceRandom;
    use std::convert::TryInto;
    use std::io::Read;

    // Reads the dictionary at |path| and returns a linewise vector of
    // its contents.
    fn ingest_english_dictionary(path: &std::path::Path) -> std::io::Result<Vec<String>> {
        let mut file = std::fs::File::open(path)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        Ok(contents
            .lines()
            .map(|word| word.trim().to_lowercase())
            .collect())
    }

    // Assumes ownership of a Vector of owned |words| and prints them
    // separated by spaces.
    fn print_words(words: Vec<String>) {
        let mut iter = words.into_iter();
        if let Some(word) = iter.next() {
            print!("{}", word);
            for word in iter {
                print!(" {}", word);
            }
            print!("\n");
        }
    }

    // Returns 1 if we fail to read the word dictionary.
    fn print_english_password(options: EnglishPasswordOptions) -> i32 {
        let all_words =
            match ingest_english_dictionary(std::path::Path::new(&options.dictionary_path)) {
                Ok(result) => result,
                Err(error) => {
                    eprintln!("Error reading dictionary: {}", error);
                    return 1;
                }
            };
        let mut rng = &mut rand::thread_rng();
        let selection: Vec<String> = all_words
            .choose_multiple(&mut rng, options.num_words.try_into().unwrap())
            .map(|borrowed| borrowed.to_owned())
            .collect();

        print_words(selection);
        0
    }

    // Builds a single random pseudo-Japanese word from |kana_set|.
    fn build_kana_word(kana_set: &Vec<&'static str>, syllable_count: &u8) -> String {
        let mut collected_kana: Vec<&'static str> = Vec::new();
        let mut rng = &mut rand::thread_rng();
        for _ in 0..*syllable_count {
            collected_kana.push(kana_set.choose(&mut rng).unwrap());
        }
        collected_kana.join("")
    }

    // Builds random pseudo-Japanese words from |kana_set|, observing
    // the word lengths specified by |options|.
    fn build_kana_words(kana_set: Vec<&'static str>, options: KanaPasswordOptions) -> Vec<String> {
        options
            .syllable_counts
            .iter()
            .map(|count| build_kana_word(&kana_set, count))
            .collect()
    }

    // Builds a vector of owned kana words, maps these to a vector of
    // borrowed kana words, and then prints the same.
    fn print_kana_password(options: KanaPasswordOptions) {
        print_words(build_kana_words(crate::kana::get(true), options));
    }

    pub fn main() -> i32 {
        let options = crate::args::parse_args();
        match options {
            PasswordOptions::English(options) => return print_english_password(options),
            PasswordOptions::Japanese(options) => print_kana_password(options),
        }
        0
    }
} // mod helpers

fn main() {
    std::process::exit(crate::helpers::main());
}
<|endoftext|>


<commit_before>//! Tidy check to ensure that there are no binaries checked into the source tree
//! by accident.
//!
//! In the past we've accidentally checked in test binaries and such which add a
//! huge amount of bloat to the Git history, so it's good to just ensure we
//! don't do that again.

use std::path::Path;

// All files are executable on Windows, so just check on Unix.
#[cfg(windows)]
pub fn check(_path: &Path, _bad: &mut bool) {}

#[cfg(unix)]
pub fn check(path: &Path, bad: &mut bool) {
    use std::fs;
    use std::process::{Command, Stdio};
    use std::os::unix::prelude::*;

    if let Ok(contents) = fs::read_to_string("/proc/version") {
        // Probably on Windows Linux Subsystem or Docker via VirtualBox,
        // all files will be marked as executable, so skip checking.
        if contents.contains("Microsoft") || contents.contains("boot2docker") {
            return;
        }
    }

    super::walk_no_read(path,
                &mut |path| super::filter_dirs(path) || path.ends_with("src/etc"),
                &mut |entry| {
        let file = entry.path();
        let filename = file.file_name().unwrap().to_string_lossy();
        let extensions = [".py", ".sh"];
        if extensions.iter().any(|e| filename.ends_with(e)) {
            return;
        }

        let metadata = t!(fs::symlink_metadata(&file), &file);
        if metadata.mode() & 0o111 != 0 {
            let rel_path = file.strip_prefix(path).unwrap();
            let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
            let output = Command::new("git")
                .arg("ls-files")
                .arg(&git_friendly_path)
                .current_dir(path)
                .stderr(Stdio::null())
                .output()
                .unwrap_or_else(|e| {
                    panic!("could not run git ls-files: {}", e);
                });
            let path_bytes = rel_path.as_os_str().as_bytes();
            if output.status.success() && output.stdout.starts_with(path_bytes) {
                tidy_error!(bad, "binary checked into source: {}", file.display());
            }
        }
    })
}
<commit_msg>Utilize entry.metadata over fs::symlink_metadata<commit_after>//! Tidy check to ensure that there are no binaries checked into the source tree
//! by accident.
//!
//! In the past we've accidentally checked in test binaries and such which add a
//! huge amount of bloat to the Git history, so it's good to just ensure we
//! don't do that again.

use std::path::Path;

// All files are executable on Windows, so just check on Unix.
#[cfg(windows)]
pub fn check(_path: &Path, _bad: &mut bool) {}

#[cfg(unix)]
pub fn check(path: &Path, bad: &mut bool) {
    use std::fs;
    use std::process::{Command, Stdio};
    use std::os::unix::prelude::*;

    if let Ok(contents) = fs::read_to_string("/proc/version") {
        // Probably on Windows Linux Subsystem or Docker via VirtualBox,
        // all files will be marked as executable, so skip checking.
        if contents.contains("Microsoft") || contents.contains("boot2docker") {
            return;
        }
    }

    super::walk_no_read(path,
                &mut |path| super::filter_dirs(path) || path.ends_with("src/etc"),
                &mut |entry| {
        let file = entry.path();
        let filename = file.file_name().unwrap().to_string_lossy();
        let extensions = [".py", ".sh"];
        if extensions.iter().any(|e| filename.ends_with(e)) {
            return;
        }

        let metadata = t!(entry.metadata(), file);
        if metadata.mode() & 0o111 != 0 {
            let rel_path = file.strip_prefix(path).unwrap();
            let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
            let output = Command::new("git")
                .arg("ls-files")
                .arg(&git_friendly_path)
                .current_dir(path)
                .stderr(Stdio::null())
                .output()
                .unwrap_or_else(|e| {
                    panic!("could not run git ls-files: {}", e);
                });
            let path_bytes = rel_path.as_os_str().as_bytes();
            if output.status.success() && output.stdout.starts_with(path_bytes) {
                tidy_error!(bad, "binary checked into source: {}", file.display());
            }
        }
    })
}
<|endoftext|>


<commit_before>extern crate graph_match;
extern crate hyper;
extern crate rustc_serialize;
extern crate iron;
extern crate router;
extern crate encoding;
extern crate regex;

#[macro_use]
mod macros;
mod core_nlp;
mod graph_parser;
mod points;
mod frames;
mod formatting;
mod validate;
mod verbs;
mod sanitize;

use std::io::Read;
use std::collections::HashMap;
use graph_match::graph::Graph;
use iron::prelude::*;
use iron::status;
use router::Router;
use rustc_serialize::json;

use graph_match::matching::EqualityRequirement;

#[derive(RustcEncodable)]
struct Point {
    frame: String,
    pattern: String,
    extract: String,
}

fn main() {
    let frames = frames::frame_index();
    let verbs = verbs::verb_index();
    let banned_edges: Vec<String> = vec![String::from("advcl"), String::from("csubj"), String::from("ccomp"), String::from("dep"), String::from("parataxis")];
    let copula_verbs: Vec<String> = vec![
        String::from("act"), String::from("appear"), String::from("be"), String::from("become"), String::from("come"),
        String::from("end"), String::from("get"), String::from("go"), String::from("grow"), String::from("fall"), String::from("feel"),
        String::from("keep"), String::from("look"), String::from("prove"), String::from("remain"), String::from("run"), String::from("seem"),
        String::from("smell"), String::from("sound"), String::from("stay"), String::from("taste"), String::from("turn"), String::from("wax")
    ];

    let mut router = Router::new();
    router.post("/points", move |r: &mut Request| handle(r, &frames, &verbs, &banned_edges, &copula_verbs));

    Iron::new(router).http("0.0.0.0:3456").unwrap();
    println!("Listening on 3456");
}

fn handle(request: &mut Request,
          frames: &HashMap<String, (usize, Graph)>,
          verbs: &HashMap<String, Vec<String>>,
          banned_edges: &Vec<String>,
          copula_verbs: &Vec<String>) -> IronResult<Response> {
    let mut text: String = String::new();
    if request.body.read_to_string(&mut text).is_err() {
        let response: IronResult<Response> = Ok(Response::with((status::InternalServerError, "Failed to read the request body.")));
        return response;
    }

    match sanitize::force_ascii(&text) {
        Ok(clean_text) => text = clean_text,
        Err(error) => {
            let response: IronResult<Response> = Ok(Response::with((status::InternalServerError, error)));
            return response;
        }
    }

    let string_graphs = match core_nlp::graphs_for_text(&text) {
        Ok(graphs) => graphs,
        Err(message) => {
            let message = format!("There was an error in building the graph string ({})", message);
            let response: IronResult<Response> = Ok(Response::with((status::InternalServerError, message)));
            return response;
        }
    };

    let mut points: Vec<Point> = Vec::new();

    for g in string_graphs {
        let graph = match graph_parser::parse(&g) {
            Ok(g) => g,
            Err(message) => {
                println!("The following graph:\n\n{}\n\nfailed with the following message: {}", g, message);
                continue;
            }
        };

        let verb_indices = match points::find_verbs(&graph) {
            Some(indices) => indices,
            None => {
                println!("There were no verbs.");
                continue;
            }
        };

        let queries = match points::build_queries(&verb_indices, &graph, &verbs, &frames, &copula_verbs) {
            Some(queries) => queries,
            None => {
                println!("No queries could be generated.");
                continue;
            }
        };

        for query in queries {
            match frames.get(&query.1) {
                Some(frame) => {
                    for matched_components in graph_match::match_graph(&frame.1, frame.0, &graph, query.0, &EqualityRequirement::Contains) {
                        let root_node_index = matched_components.list[0].node;
                        let node_indexes = graph_match::expand_subgraph(&graph, root_node_index, &banned_edges);

                        let pattern = points::matched_components_to_pattern(&matched_components, &graph);
                        let extract = points::subgraph_nodes_to_extract_string(&node_indexes, &graph);

                        let pattern = formatting::pattern(pattern);

                        if validate::pattern(&pattern) {
                            points.push(Point {
                                frame: query.1.clone(),
                                pattern: pattern,
                                extract: extract,
                            });
                        }
                    }
                },
                None => println!("Previously matched frame now missing."),
            }
        }
    }

    match json::encode(&points) {
        Ok(string) => {
            let response: IronResult<Response> = Ok(Response::with((status::Ok, string)));
            return response
        },
        Err(_) => {
            let response: IronResult<Response> = Ok(Response::with((status::InternalServerError, "failed to encode points as json")));
            return response
        }

    }
}
<commit_msg>Reject points from with duplicate patterns<commit_after>extern crate graph_match;
extern crate hyper;
extern crate rustc_serialize;
extern crate iron;
extern crate router;
extern crate encoding;
extern crate regex;

#[macro_use]
mod macros;
mod core_nlp;
mod graph_parser;
mod points;
mod frames;
mod formatting;
mod validate;
mod verbs;
mod sanitize;

use std::io::Read;
use std::collections::HashMap;
use graph_match::graph::Graph;
use iron::prelude::*;
use iron::status;
use router::Router;
use rustc_serialize::json;

use graph_match::matching::EqualityRequirement;

#[derive(RustcEncodable)]
struct Point {
    frame: String,
    pattern: String,
    extract: String,
}

fn main() {
    let frames = frames::frame_index();
    let verbs = verbs::verb_index();
    let banned_edges: Vec<String> = vec![String::from("advcl"), String::from("csubj"), String::from("ccomp"), String::from("dep"), String::from("parataxis")];
    let copula_verbs: Vec<String> = vec![
        String::from("act"), String::from("appear"), String::from("be"), String::from("become"), String::from("come"),
        String::from("end"), String::from("get"), String::from("go"), String::from("grow"), String::from("fall"), String::from("feel"),
        String::from("keep"), String::from("look"), String::from("prove"), String::from("remain"), String::from("run"), String::from("seem"),
        String::from("smell"), String::from("sound"), String::from("stay"), String::from("taste"), String::from("turn"), String::from("wax")
    ];

    let mut router = Router::new();
    router.post("/points", move |r: &mut Request| handle(r, &frames, &verbs, &banned_edges, &copula_verbs));

    Iron::new(router).http("0.0.0.0:3456").unwrap();
    println!("Listening on 3456");
}

fn handle(request: &mut Request,
          frames: &HashMap<String, (usize, Graph)>,
          verbs: &HashMap<String, Vec<String>>,
          banned_edges: &Vec<String>,
          copula_verbs: &Vec<String>) -> IronResult<Response> {
    let mut text: String = String::new();
    if request.body.read_to_string(&mut text).is_err() {
        let response: IronResult<Response> = Ok(Response::with((status::InternalServerError, "Failed to read the request body.")));
        return response;
    }

    match sanitize::force_ascii(&text) {
        Ok(clean_text) => text = clean_text,
        Err(error) => {
            let response: IronResult<Response> = Ok(Response::with((status::InternalServerError, error)));
            return response;
        }
    }

    let string_graphs = match core_nlp::graphs_for_text(&text) {
        Ok(graphs) => graphs,
        Err(message) => {
            let message = format!("There was an error in building the graph string ({})", message);
            let response: IronResult<Response> = Ok(Response::with((status::InternalServerError, message)));
            return response;
        }
    };

    let mut points: Vec<Point> = Vec::new();

    for g in string_graphs {
        let graph = match graph_parser::parse(&g) {
            Ok(g) => g,
            Err(message) => {
                println!("The following graph:\n\n{}\n\nfailed with the following message: {}", g, message);
                continue;
            }
        };

        let verb_indices = match points::find_verbs(&graph) {
            Some(indices) => indices,
            None => {
                println!("There were no verbs.");
                continue;
            }
        };

        let queries = match points::build_queries(&verb_indices, &graph, &verbs, &frames, &copula_verbs) {
            Some(queries) => queries,
            None => {
                println!("No queries could be generated.");
                continue;
            }
        };

        let mut used_patterns: Vec<String> = Vec::new();
        for query in queries {
            match frames.get(&query.1) {
                Some(frame) => {
                    for matched_components in graph_match::match_graph(&frame.1, frame.0, &graph, query.0, &EqualityRequirement::Contains) {
                        let root_node_index = matched_components.list[0].node;
                        let node_indexes = graph_match::expand_subgraph(&graph, root_node_index, &banned_edges);

                        let pattern = points::matched_components_to_pattern(&matched_components, &graph);
                        let extract = points::subgraph_nodes_to_extract_string(&node_indexes, &graph);

                        let pattern = formatting::pattern(pattern);

                        if !used_patterns.contains(&pattern) && validate::pattern(&pattern) {
                            used_patterns.push(pattern.clone());
                            points.push(Point {
                                frame: query.1.clone(),
                                pattern: pattern,
                                extract: extract,
                            });
                        }
                    }
                },
                None => println!("Previously matched frame now missing."),
            }
        }
    }

    match json::encode(&points) {
        Ok(string) => {
            let response: IronResult<Response> = Ok(Response::with((status::Ok, string)));
            return response
        },
        Err(_) => {
            let response: IronResult<Response> = Ok(Response::with((status::InternalServerError, "failed to encode points as json")));
            return response
        }

    }
}
<|endoftext|>


<commit_before>use std::io;
use std::net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs};
use std::time::Duration;

/// A transport for TCP.
pub struct TcpTransport(pub A);
impl super::Transport for TcpTransport {
    type Listener = TcpListener;
    fn bind(&self) -> io::Result<TcpListener> {
        TcpListener::bind(&self.0)
    }
}

impl super::Transport for A {
    type Listener = TcpListener;
    fn bind(&self) -> io::Result<TcpListener> {
        TcpListener::bind(self)
    }
}

impl super::Listener for TcpListener {
    type Dialer = TcpDialer<SocketAddr>;
    type Stream = TcpStream;
    fn accept(&self) -> io::Result<TcpStream> {
        self.accept().map(|(stream, _)| stream)
    }
    fn dialer(&self) -> io::Result<TcpDialer<SocketAddr>> {
        self.local_addr().map(|addr| TcpDialer(addr))
    }
}

impl super::Stream for TcpStream {
    fn try_clone(&self) -> io::Result<Self> {
        self.try_clone()
    }
    fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
        self.set_read_timeout(dur)
    }
    fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
        self.set_write_timeout(dur)
    }
    fn shutdown(&self) -> io::Result<()> {
        self.shutdown(::std::net::Shutdown::Both)
    }
}

/// Connects to a socket address.
pub struct TcpDialer(pub A) where A: ToSocketAddrs;
impl super::Dialer for TcpDialer
    where A: ToSocketAddrs
{
    type Stream = TcpStream;
    fn dial(&self) -> io::Result<TcpStream> {
        TcpStream::connect(&self.0)
    }
}
impl super::Dialer for str {
    type Stream = TcpStream;
    fn dial(&self) -> io::Result<TcpStream> {
        TcpStream::connect(self)
    }
}
<commit_msg>Add a line in between struct and impl<commit_after>use std::io;
use std::net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs};
use std::time::Duration;

/// A transport for TCP.
pub struct TcpTransport(pub A);

impl super::Transport for TcpTransport {
    type Listener = TcpListener;
    fn bind(&self) -> io::Result<TcpListener> {
        TcpListener::bind(&self.0)
    }
}

impl super::Transport for A {
    type Listener = TcpListener;
    fn bind(&self) -> io::Result<TcpListener> {
        TcpListener::bind(self)
    }
}

impl super::Listener for TcpListener {
    type Dialer = TcpDialer<SocketAddr>;
    type Stream = TcpStream;
    fn accept(&self) -> io::Result<TcpStream> {
        self.accept().map(|(stream, _)| stream)
    }
    fn dialer(&self) -> io::Result<TcpDialer<SocketAddr>> {
        self.local_addr().map(|addr| TcpDialer(addr))
    }
}

impl super::Stream for TcpStream {
    fn try_clone(&self) -> io::Result<Self> {
        self.try_clone()
    }
    fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
        self.set_read_timeout(dur)
    }
    fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
        self.set_write_timeout(dur)
    }
    fn shutdown(&self) -> io::Result<()> {
        self.shutdown(::std::net::Shutdown::Both)
    }
}

/// Connects to a socket address.
pub struct TcpDialer(pub A) where A: ToSocketAddrs;
impl super::Dialer for TcpDialer
    where A: ToSocketAddrs
{
    type Stream = TcpStream;
    fn dial(&self) -> io::Result<TcpStream> {
        TcpStream::connect(&self.0)
    }
}
impl super::Dialer for str {
    type Stream = TcpStream;
    fn dial(&self) -> io::Result<TcpStream> {
        TcpStream::connect(self)
    }
}
<|endoftext|>


<commit_before>extern crate cfg_if;
extern crate resize;
extern crate wasm_bindgen;

mod utils;

use cfg_if::cfg_if;
use resize::Pixel::RGBA;
use resize::Type;
use wasm_bindgen::prelude::*;

mod srgb;
use srgb::Clamp;

cfg_if! {
    // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
    // allocator.
    if #[cfg(feature = "wee_alloc")] {
        extern crate wee_alloc;
        #[global_allocator]
        static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
    }
}

include!("./lut.inc");

// If `with_space_conversion` is true, this function returns 2 functions that
// convert from sRGB to linear RGB and vice versa. If `with_space_conversion` is
// false, the 2 functions returned do nothing.
fn converter_funcs(with_space_conversion: bool) -> ((fn(u8) -> f32), (fn(f32) -> u8)) {
    if with_space_conversion {
        (
            |v| SRGB_TO_LINEAR_LUT[v as usize] * 255.0,
            |v| (LINEAR_TO_SRGB_LUT[v as usize] * 255.0) as u8,
        )
    } else {
        (|v| v as f32, |v| v as u8)
    }
}

// If `with_alpha_premultiplication` is true, this function returns a function
// that premultiply the alpha channel with the given channel value and another
// function that reverses that process. If `with_alpha_premultiplication` is
// false, the functions just return the channel value.
fn alpha_multiplier_funcs(
    with_alpha_premultiplication: bool,
) -> ((fn(f32, u8) -> u8), (fn(u8, u8) -> f32)) {
    if with_alpha_premultiplication {
        (
            |v, a| (v * (a as f32) / 255.0) as u8,
            |v, a| (v as f32) * 255.0 / (a as f32).clamp(0.0, 255.0),
        )
    } else {
        (|v, _a| v as u8, |v, _a| v as f32)
    }
}

#[wasm_bindgen]
#[no_mangle]
pub fn resize(
    mut input_image: Vec<u8>,
    input_width: usize,
    input_height: usize,
    output_width: usize,
    output_height: usize,
    typ_idx: usize,
    premultiply: bool,
    color_space_conversion: bool,
) -> Vec<u8> {
    let typ = match typ_idx {
        0 => Type::Triangle,
        1 => Type::Catrom,
        2 => Type::Mitchell,
        3 => Type::Lanczos3,
        _ => panic!("Nope"),
    };
    let num_input_pixels = input_width * input_height;
    let num_output_pixels = output_width * output_height;

    let (to_linear, to_color_space) = converter_funcs(color_space_conversion);
    let (premultiplier, demultiplier) = alpha_multiplier_funcs(premultiply);

    // If both options are false, there is no preprocessing on the pixel valus
    // and we can skip the loop.
    if premultiply || color_space_conversion {
        for i in 0..num_input_pixels {
            for j in 0..3 {
                input_image[4 * i + j] =
                    premultiplier(to_linear(input_image[4 * i + j]), input_image[4 * i + 3]);
            }
        }
    }

    let mut resizer = resize::new(
        input_width,
        input_height,
        output_width,
        output_height,
        RGBA,
        typ,
    );
    let mut output_image = Vec::<u8>::with_capacity(num_output_pixels * 4);
    output_image.resize(num_output_pixels * 4, 0);
    resizer.resize(input_image.as_slice(), output_image.as_mut_slice());

    if premultiply || color_space_conversion {
        for i in 0..num_output_pixels {
            for j in 0..3 {
                // We don’t need to worry about division by zero, as division by zero
                // is well-defined on floats to return ±Inf. ±Inf is converted to 0
                // when casting to integers.
                output_image[4 * i + j] = to_color_space(demultiplier(
                    output_image[4 * i + j],
                    output_image[4 * i + 3],
                ));
            }
        }
    }

    return output_image;
}
<commit_msg>Fix clamping. Fixes #782. Fixes #711.<commit_after>extern crate cfg_if;
extern crate resize;
extern crate wasm_bindgen;

mod utils;

use cfg_if::cfg_if;
use resize::Pixel::RGBA;
use resize::Type;
use wasm_bindgen::prelude::*;

mod srgb;
use srgb::Clamp;

cfg_if! {
    // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
    // allocator.
    if #[cfg(feature = "wee_alloc")] {
        extern crate wee_alloc;
        #[global_allocator]
        static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
    }
}

include!("./lut.inc");

// If `with_space_conversion` is true, this function returns 2 functions that
// convert from sRGB to linear RGB and vice versa. If `with_space_conversion` is
// false, the 2 functions returned do nothing.
fn converter_funcs(with_space_conversion: bool) -> ((fn(u8) -> f32), (fn(f32) -> u8)) {
    if with_space_conversion {
        (
            |v| SRGB_TO_LINEAR_LUT[v as usize] * 255.0,
            |v| (LINEAR_TO_SRGB_LUT[v as usize] * 255.0) as u8,
        )
    } else {
        (|v| v as f32, |v| v as u8)
    }
}

// If `with_alpha_premultiplication` is true, this function returns a function
// that premultiply the alpha channel with the given channel value and another
// function that reverses that process. If `with_alpha_premultiplication` is
// false, the functions just return the channel value.
fn alpha_multiplier_funcs(
    with_alpha_premultiplication: bool,
) -> ((fn(f32, u8) -> u8), (fn(u8, u8) -> f32)) {
    if with_alpha_premultiplication {
        (
            |v, a| (v * (a as f32) / 255.0) as u8,
            |v, a| ((v as f32) * 255.0 / (a as f32)).clamp(0.0, 255.0),
        )
    } else {
        (|v, _a| v as u8, |v, _a| v as f32)
    }
}

#[wasm_bindgen]
#[no_mangle]
pub fn resize(
    mut input_image: Vec<u8>,
    input_width: usize,
    input_height: usize,
    output_width: usize,
    output_height: usize,
    typ_idx: usize,
    premultiply: bool,
    color_space_conversion: bool,
) -> Vec<u8> {
    let typ = match typ_idx {
        0 => Type::Triangle,
        1 => Type::Catrom,
        2 => Type::Mitchell,
        3 => Type::Lanczos3,
        _ => panic!("Nope"),
    };
    let num_input_pixels = input_width * input_height;
    let num_output_pixels = output_width * output_height;

    let (to_linear, to_color_space) = converter_funcs(color_space_conversion);
    let (premultiplier, demultiplier) = alpha_multiplier_funcs(premultiply);

    // If both options are false, there is no preprocessing on the pixel valus
    // and we can skip the loop.
    if premultiply || color_space_conversion {
        for i in 0..num_input_pixels {
            for j in 0..3 {
                input_image[4 * i + j] =
                    premultiplier(to_linear(input_image[4 * i + j]), input_image[4 * i + 3]);
            }
        }
    }

    let mut resizer = resize::new(
        input_width,
        input_height,
        output_width,
        output_height,
        RGBA,
        typ,
    );
    let mut output_image = Vec::<u8>::with_capacity(num_output_pixels * 4);
    output_image.resize(num_output_pixels * 4, 0);
    resizer.resize(input_image.as_slice(), output_image.as_mut_slice());

    if premultiply || color_space_conversion {
        for i in 0..num_output_pixels {
            for j in 0..3 {
                // We don’t need to worry about division by zero, as division by zero
                // is well-defined on floats to return ±Inf. ±Inf is converted to 0
                // when casting to integers.
                output_image[4 * i + j] = to_color_space(demultiplier(
                    output_image[4 * i + j],
                    output_image[4 * i + 3],
                ));
            }
        }
    }

    return output_image;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use io;
use message::*;
use serialize::*;

pub struct PackedInputStream<'self, T> {
    inner : &'self mut T
}

impl <'self, T : std::rt::io::Reader> std::rt::io::Reader for PackedInputStream<'self, T> {
    fn eof(&mut self) -> bool {
        self.inner.eof()
    }

    fn read(&mut self, outBuf: &mut [u8]) -> Option<uint> {
        let len = outBuf.len();

        if (len == 0) { return Some(0); }

        assert!(len % 8 == 0, "PackInputStream reads must be word-aligned");

        let mut outPos = 0;
        while (outPos < len && ! self.inner.eof() ) {

            let tag : u8 = self.inner.read_u8();

            for n in range(0, 8) {
                let isNonzero = (tag & (1 as u8 << n)) != 0;//..as bool;
                if (isNonzero) {
                    // TODO capnproto-c++ gets away without using a
                    // conditional here. Can we do something like that
                    // and would it speed things up?
                    outBuf[outPos] = self.inner.read_u8();
                    outPos += 1;
                } else {
                    outBuf[outPos] = 0;
                    outPos += 1;
                }
            }

            if (tag == 0) {

                let runLength : uint = self.inner.read_u8() as uint * 8;
                assert!(runLength <= outBuf.len() - outPos);
                unsafe {
                    std::ptr::set_memory(outBuf.unsafe_mut_ref(outPos),
                                         0, runLength);
                };
                outPos += runLength;

            } else if (tag == 0xff) {
                let runLength : uint = self.inner.read_u8() as uint * 8;

                let mut bytes_read = 0;
                while bytes_read < runLength {
                    let pos = outPos + bytes_read;
                    match self.inner.read(outBuf.mut_slice(pos, outPos + runLength)) {
                        Some(n) => bytes_read += n,
                        None => fail!("failed to read bytes")
                    }
                }
                outPos += runLength;
            }

        }

        return Some(outPos);
    }

}

pub struct PackedOutputStream<'a, 'b, W> {
    inner : &'a mut io::BufferedOutputStream<'b, W>
}

#[inline]
fn ptr_inc(p : &mut *mut u8, count : int) {
    unsafe {
        *p = std::ptr::mut_offset(*p, count);
    }
}

#[inline]
fn ptr_sub(p1 : *mut u8, p2 : *mut u8) -> uint {
    unsafe {
        let p1Addr : uint = std::cast::transmute(p1);
        let p2Addr : uint = std::cast::transmute(p2);
        return p1Addr - p2Addr;
    }
}

impl <'a, 'b, W : std::rt::io::Writer> std::rt::io::Writer for PackedOutputStream<'a, 'b, W> {
    fn write(&mut self, inBuf : &[u8]) {

        let (mut out, mut bufferEnd) = self.inner.getWriteBuffer();
        let mut bufferBegin = out;
        let mut slowBuffer : [u8,..20] = [0, ..20];

        let mut inPos : uint = 0;

        while (inPos < inBuf.len()) {

            if (ptr_sub(bufferEnd, out) < 10) {
                //# Oops, we're out of space. We need at least 10
                //# bytes for the fast path, since we don't
                //# bounds-check on every byte.
                self.inner.write_ptr(bufferBegin, ptr_sub(out, bufferBegin));

                unsafe { out = slowBuffer.unsafe_mut_ref(0) }
                unsafe { bufferEnd = slowBuffer.unsafe_mut_ref(20) }
                bufferBegin = out;
            }

            let tagPos : *mut u8 = out;
            ptr_inc(&mut out, 1);

            let bit0 = (inBuf[inPos] != 0) as u8;
            unsafe { *out = inBuf[inPos] }
            ptr_inc(&mut out, bit0 as int);
            inPos += 1;

            let bit1 = (inBuf[inPos] != 0) as u8;
            unsafe { *out = inBuf[inPos] }
            ptr_inc(&mut out, bit1 as int);
            inPos += 1;

            let bit2 = (inBuf[inPos] != 0) as u8;
            unsafe { *out = inBuf[inPos] }
            ptr_inc(&mut out, bit2 as int);
            inPos += 1;

            let bit3 = (inBuf[inPos] != 0) as u8;
            unsafe { *out = inBuf[inPos] }
            ptr_inc(&mut out, bit3 as int);
            inPos += 1;

            let bit4 = (inBuf[inPos] != 0) as u8;
            unsafe { *out = inBuf[inPos] }
            ptr_inc(&mut out, bit4 as int);
            inPos += 1;

            let bit5 = (inBuf[inPos] != 0) as u8;
            unsafe { *out = inBuf[inPos] }
            ptr_inc(&mut out, bit5 as int);
            inPos += 1;

            let bit6 = (inBuf[inPos] != 0) as u8;
            unsafe { *out = inBuf[inPos] }
            ptr_inc(&mut out, bit6 as int);
            inPos += 1;

            let bit7 = (inBuf[inPos] != 0) as u8;
            unsafe { *out = inBuf[inPos] }
            ptr_inc(&mut out, bit7 as int);
            inPos += 1;

            let tag : u8 = (bit0 << 0) | (bit1 << 1) | (bit2 << 2) | (bit3 << 3)
                         | (bit4 << 4) | (bit5 << 5) | (bit6 << 6) | (bit7 << 7);

            unsafe {*tagPos = tag }

            if (tag == 0) {
                //# An all-zero word is followed by a count of
                //# consecutive zero words (not including the first
                //# one).

                let mut count : u8 = 0;
                unsafe {
                    let mut inWord : *u64 =
                        std::cast::transmute(inBuf.unsafe_ref(inPos));
                    while (count < 255 && inPos < inBuf.len() && *inWord == 0) {
                        inPos += 8;
                        inWord = std::cast::transmute(inBuf.unsafe_ref(inPos));
                        count += 1;
                    }
                }
                unsafe {*out = count }
                ptr_inc(&mut out, 1);

            } else if (tag == 0xff) {
                //# An all-nonzero word is followed by a count of
                //# consecutive uncompressed words, followed by the
                //# uncompressed words themselves.

                //# Count the number of consecutive words in the input
                //# which have no more than a single zero-byte. We look
                //# for at least two zeros because that's the point
                //# where our compression scheme becomes a net win.
                let mut count : u8 = 0;
                let runStart = inPos;
                while (inPos < inBuf.len() && count < 255) {
                    let mut c = 0;

                    for _ in range(0,8) {
                        c += (inBuf[inPos] == 0) as u8;
                        inPos += 1;
                    }

                    if (c >= 2) {
                        //# Un-read the word with multiple zeros, since
                        //# we'll want to compress that one.
                        inPos -= 8;
                        break;
                    }

                    count += 1;
                }
                unsafe { *out = count }
                ptr_inc(&mut out, 1);

                if (count as uint * 8 <= ptr_sub(bufferEnd, out)) {
                    //# There's enough space to memcpy.
                    unsafe {
                        let src : *u8 = inBuf.unsafe_ref(runStart);
                        std::ptr::copy_memory(out, src, 8 * count as uint);
                    }
                    ptr_inc(&mut out, count as int * 8);
                } else {
                    //# Input overruns the output buffer. We'll give it
                    //# to the output stream in one chunk and let it
                    //# decide what to do.
                    self.inner.write_ptr(bufferBegin, ptr_sub(out, bufferBegin));

                    self.inner.write(inBuf.slice(runStart, runStart + 8 * count as uint));

                    let (out1, bufferEnd1) = self.inner.getWriteBuffer();
                    out = out1; bufferEnd = bufferEnd1;
                    bufferBegin = out;
                }
            }
        }

        self.inner.write_ptr(bufferBegin, ptr_sub(out, bufferBegin));
        self.inner.flush();
    }

   fn flush(&mut self) { self.inner.flush(); }
}

pub trait WritePacked {
    fn writePackedMessage(&mut self, message : &MessageBuilder);
}

impl <'self, T : std::rt::io::Writer> WritePacked for io::BufferedOutputStream<'self, T> {
    fn writePackedMessage(&mut self, message : &MessageBuilder) {
        let mut packedOutputStream = PackedOutputStream {inner : self};
        writeMessage(&mut packedOutputStream, message);
    }
}

pub struct WritePackedWrapper<'a, T> {writer : &'a mut T }

impl <'a, T: std::rt::io::Writer> WritePacked for WritePackedWrapper<'a, T> {
    fn writePackedMessage(&mut self, message : &MessageBuilder) {
        let mut buffered = io::BufferedOutputStream::new(self.writer);
        buffered.writePackedMessage(message);
    }
}
<commit_msg>unchecked access<commit_after>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use io;
use message::*;
use serialize::*;

pub struct PackedInputStream<'self, T> {
    inner : &'self mut T
}

impl <'self, T : std::rt::io::Reader> std::rt::io::Reader for PackedInputStream<'self, T> {
    fn eof(&mut self) -> bool {
        self.inner.eof()
    }

    fn read(&mut self, outBuf: &mut [u8]) -> Option<uint> {
        let len = outBuf.len();

        if (len == 0) { return Some(0); }

        assert!(len % 8 == 0, "PackInputStream reads must be word-aligned");

        let mut outPos = 0;
        while (outPos < len && ! self.inner.eof() ) {

            let tag : u8 = self.inner.read_u8();

            for n in range(0, 8) {
                let isNonzero = (tag & (1 as u8 << n)) != 0;//..as bool;
                if (isNonzero) {
                    // TODO capnproto-c++ gets away without using a
                    // conditional here. Can we do something like that
                    // and would it speed things up?
                    outBuf[outPos] = self.inner.read_u8();
                    outPos += 1;
                } else {
                    outBuf[outPos] = 0;
                    outPos += 1;
                }
            }

            if (tag == 0) {

                let runLength : uint = self.inner.read_u8() as uint * 8;
                assert!(runLength <= outBuf.len() - outPos);
                unsafe {
                    std::ptr::set_memory(outBuf.unsafe_mut_ref(outPos),
                                         0, runLength);
                };
                outPos += runLength;

            } else if (tag == 0xff) {
                let runLength : uint = self.inner.read_u8() as uint * 8;

                let mut bytes_read = 0;
                while bytes_read < runLength {
                    let pos = outPos + bytes_read;
                    match self.inner.read(outBuf.mut_slice(pos, outPos + runLength)) {
                        Some(n) => bytes_read += n,
                        None => fail!("failed to read bytes")
                    }
                }
                outPos += runLength;
            }

        }

        return Some(outPos);
    }

}

pub struct PackedOutputStream<'a, 'b, W> {
    inner : &'a mut io::BufferedOutputStream<'b, W>
}

#[inline]
fn ptr_inc(p : &mut *mut u8, count : int) {
    unsafe {
        *p = std::ptr::mut_offset(*p, count);
    }
}

#[inline]
fn ptr_sub<T>(p1 : * T, p2 : * T) -> uint {
    unsafe {
        let p1Addr : uint = std::cast::transmute(p1);
        let p2Addr : uint = std::cast::transmute(p2);
        return (p1Addr - p2Addr) / std::mem::size_of::<T>();
    }
}

#[inline]
fn ptr_sub_mut <T>(p1 : *mut T, p2 : *mut T) -> uint {
    unsafe {
        let p1Addr : uint = std::cast::transmute(p1);
        let p2Addr : uint = std::cast::transmute(p2);
        return (p1Addr - p2Addr) / std::mem::size_of::<T>();
    }
}

impl <'a, 'b, W : std::rt::io::Writer> std::rt::io::Writer for PackedOutputStream<'a, 'b, W> {
    fn write(&mut self, inBuf : &[u8]) {
        unsafe {
            let (mut out, mut bufferEnd) = self.inner.getWriteBuffer();
            let mut bufferBegin = out;
            let mut slowBuffer : [u8,..20] = [0, ..20];

            let mut inPtr : *u8 = inBuf.unsafe_ref(0);
            let inEnd : *u8 = inBuf.unsafe_ref(inBuf.len());

            while (inPtr < inEnd) {

                if (ptr_sub_mut(bufferEnd, out) < 10) {
                    //# Oops, we're out of space. We need at least 10
                    //# bytes for the fast path, since we don't
                    //# bounds-check on every byte.
                    self.inner.write_ptr(bufferBegin, ptr_sub_mut(out, bufferBegin));

                    out = slowBuffer.unsafe_mut_ref(0);
                    bufferEnd = slowBuffer.unsafe_mut_ref(20);
                    bufferBegin = out;
                }

                let tagPos : *mut u8 = out;
                ptr_inc(&mut out, 1);

                let bit0 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit0 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit1 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit1 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit2 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit2 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit3 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit3 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit4 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit4 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit5 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit5 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit6 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit6 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit7 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit7 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let tag : u8 = (bit0 << 0) | (bit1 << 1) | (bit2 << 2) | (bit3 << 3)
                    | (bit4 << 4) | (bit5 << 5) | (bit6 << 6) | (bit7 << 7);

                *tagPos = tag;

                if (tag == 0) {
                    //# An all-zero word is followed by a count of
                    //# consecutive zero words (not including the first
                    //# one).

                    let mut inWord : *u64 = std::cast::transmute(inPtr);
                    let mut limit : *u64 = std::cast::transmute(inEnd);
                    if (ptr_sub(limit, inWord) > 255) {
                        limit = std::ptr::offset(inWord, 255);
                    }
                    while (inWord < limit && *inWord == 0) {
                        inWord = std::ptr::offset(inWord, 1)
                    }
                    *out = ptr_sub(inWord, std::cast::transmute::<*u8, *u64>(inPtr)) as u8;

                    ptr_inc(&mut out, 1);
                    inPtr = std::cast::transmute::<*u64, *u8>(inWord);

                } else if (tag == 0xff) {
                    //# An all-nonzero word is followed by a count of
                    //# consecutive uncompressed words, followed by the
                    //# uncompressed words themselves.

                    //# Count the number of consecutive words in the input
                    //# which have no more than a single zero-byte. We look
                    //# for at least two zeros because that's the point
                    //# where our compression scheme becomes a net win.
                    let runStart = inPtr;
                    let mut limit = inEnd;
                    if (ptr_sub(limit, inPtr) > 255 * 8) {
                        limit = std::ptr::offset(inPtr, 255 * 8);
                    }

                    while (inPtr < limit) {
                        let mut c = 0;

                        for _ in range(0,8) {
                            c += (*inPtr == 0) as u8;
                            inPtr = std::ptr::offset(inPtr, 1);
                        }

                        if (c >= 2) {
                            //# Un-read the word with multiple zeros, since
                            //# we'll want to compress that one.
                            inPtr = std::ptr::offset(inPtr, -8);
                            break;
                        }
                    }
                    let count : uint = ptr_sub(inPtr, runStart);
                    *out = (count / 8) as u8;
                    ptr_inc(&mut out, 1);

                    if (count <= ptr_sub_mut(bufferEnd, out)) {
                        //# There's enough space to memcpy.

                        let src : *u8 = runStart;
                        std::ptr::copy_memory(out, src, count);

                        ptr_inc(&mut out, count as int);
                    } else {
                        //# Input overruns the output buffer. We'll give it
                        //# to the output stream in one chunk and let it
                        //# decide what to do.
                        self.inner.write_ptr(bufferBegin, ptr_sub_mut(out, bufferBegin));

                        do std::vec::raw::buf_as_slice::<u8,()>(runStart, count) |buf| {
                            self.write(buf);
                        }

                        let (out1, bufferEnd1) = self.inner.getWriteBuffer();
                        out = out1; bufferEnd = bufferEnd1;
                        bufferBegin = out;
                    }
                }
            }

            self.inner.write_ptr(bufferBegin, ptr_sub_mut(out, bufferBegin));
            self.inner.flush();
        }
    }

   fn flush(&mut self) { self.inner.flush(); }
}

pub trait WritePacked {
    fn writePackedMessage(&mut self, message : &MessageBuilder);
}

impl <'self, T : std::rt::io::Writer> WritePacked for io::BufferedOutputStream<'self, T> {
    fn writePackedMessage(&mut self, message : &MessageBuilder) {
        let mut packedOutputStream = PackedOutputStream {inner : self};
        writeMessage(&mut packedOutputStream, message);
    }
}

pub struct WritePackedWrapper<'a, T> {writer : &'a mut T }

impl <'a, T: std::rt::io::Writer> WritePacked for WritePackedWrapper<'a, T> {
    fn writePackedMessage(&mut self, message : &MessageBuilder) {
        let mut buffered = io::BufferedOutputStream::new(self.writer);
        buffered.writePackedMessage(message);
    }
}
<|endoftext|>