<commit_before>#![feature(collections, core, hash)]
// Silence feature warnings for test module.
#![cfg_attr(test, feature(rand, test))]

extern crate image;
extern crate "rustc-serialize" as serialize;

use self::dct::{dct_2d, crop_dct};

use image::{
    imageops,
    DynamicImage,
    FilterType,
    GrayImage,
    GrayAlphaImage,
    Pixel,
    RgbImage,
    RgbaImage,
};

use serialize::base64::{ToBase64, STANDARD, FromBase64, FromBase64Error};

use std::collections::Bitv;

const FILTER_TYPE: FilterType = FilterType::Nearest;

mod dct;

/// A struct representing an image processed by a perceptual hash.
/// For efficiency, does not retain a copy of the image data after hashing.
///
/// Get an instance with `ImageHash::hash()`.
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
pub struct ImageHash {
    bitv: Bitv,
}

impl ImageHash {

    /// Calculate the Hamming distance between this and `other`.
    /// Equivalent to counting the 1-bits of the XOR of the two `Bitv`.
    ///
    /// Essential to determining the perceived difference between `self` and `other`.
    pub fn dist(&self, other: &ImageHash) -> usize {
        assert!(self.bitv.len() == other.bitv.len(),
                "ImageHashes must be the same length for proper comparison!");

        self.bitv.iter().zip(other.bitv.iter())
            .filter(|&(left, right)| left != right).count()
    }

    /// Calculate the Hamming distance between `self` and `other`,
    /// then normalize it to `[0, 1]`, as a fraction of the total bits.
    ///
    /// Roughly equivalent to the % difference between the two images,
    /// represented as a decimal.
    ///
    /// See `ImageHash::dist()`.
    pub fn dist_ratio(&self, other: &ImageHash) -> f32 {
        self.dist(other) as f32 / self.size() as f32
    }

    /// Get the hash size of this image. Should be equal to the number of bits in the hash.
    pub fn size(&self) -> u32 { self.bitv.len() as u32}

    /// Create a hash of `img` with a length of `hash_size * hash_size`.
    ///
    /// If `fast == true`, use a simple average of the pixels (faster, but less accurate).
    /// Else, perform a Discrete Cosine Transform & Mean hash (slower, but more accurate).
    ///
    /// Setting `fast = true` produces hashes that are really only useful for
    /// comparing *equality* and very *closely* similar images with minor edits or corrections.
    /// Strong color/gamma correction will throw off the hash.
    ///
    /// In practice, on a fast computer, using `fast = false` won't drastically increase the hash
    /// time for a single image. In a program that processes many images at once, the bottleneck
    /// will likely be in loading and decoding the images, and not in the hash function.
    pub fn hash<I: HashImage>(img: &I, hash_size: u32, fast: bool) -> ImageHash {
        let hash = if fast {
            fast_hash(img, hash_size)
        } else {
            dct_hash(img, hash_size)
        };

        assert!((hash_size * hash_size) as usize == hash.len());

        ImageHash {
            bitv: hash,
        }
    }

    /// Create an `ImageHash` instance from the given Base64-encoded string.
    pub fn from_base64(encoded_hash: &str) -> Result<ImageHash, FromBase64Error>{
        let data = try!(encoded_hash.from_base64());

        Ok(ImageHash{
            bitv: Bitv::from_bytes(&*data)
        })
    }

    /// Get a Base64 string representing the bits of this hash.
    ///
    /// Mostly for printing convenience.
    pub fn to_base64(&self) -> String {
        self.bitv.to_bytes().to_base64(STANDARD)
    }
}

fn fast_hash<I: HashImage>(img: &I, hash_size: u32) -> Bitv {
    let hash_values = img.gray_resize_square(hash_size).into_raw();

    let hash_sq = hash_size * hash_size;

    let mean = hash_values.iter().fold(0u32, |b, &a| a as u32 + b) / hash_sq;

    hash_values.into_iter().map(|x| x as u32 >= mean).collect()
}

fn dct_hash<I: HashImage>(img: &I, hash_size: u32) -> Bitv {
    let large_size = hash_size * 4;

    // We take a bigger resize than fast_hash,
    // then we only take the lowest corner of the DCT
    let hash_values: Vec<_> = img.gray_resize_square(large_size)
        .into_raw().into_iter().map(|val| val as f64).collect();

    let dct = dct_2d(hash_values.as_slice(),
        large_size as usize, large_size as usize);

    let original = (large_size as usize, large_size as usize);
    let new = (hash_size as usize, hash_size as usize);

    let cropped_dct = crop_dct(dct, original, new);

    let mean = cropped_dct.iter().fold(0f64, |b, &a| a + b)
        / (hash_size * hash_size) as f64;

    cropped_dct.into_iter().map(|x| x >= mean).collect()
}

/// A trait for describing an image that can be successfully hashed.
pub trait HashImage {
    /// Apply a grayscale filter and drop the alpha channel (if present),
    /// then resize the image to `size` width by `size` height (making it square).
    ///
    /// Returns a copy, leaving `self` unmodified.
    fn gray_resize_square(&self, size: u32) -> GrayImage;
}

macro_rules! hash_img_impl {
    ($ty:ty) => (
        impl HashImage for $ty {
            fn gray_resize_square(&self, size: u32) -> GrayImage {
                let ref gray = imageops::grayscale(self);
                imageops::resize(gray, size, size, FILTER_TYPE)
            }
        }
    );
    ($($ty:ty),+) => ( $(hash_img_impl! { $ty })+ );
}

hash_img_impl! { GrayImage, GrayAlphaImage, RgbImage, RgbaImage, DynamicImage }

#[cfg(test)]
mod test {
    extern crate test;

    use image::{Rgba, ImageBuffer};

    use self::test::Bencher;

    use super::ImageHash;

    use std::rand::{weak_rng, Rng};

    type RgbaBuf = ImageBuffer<Rgba<u8>, Vec<u8>>;

    fn gen_test_img(width: u32, height: u32) -> RgbaBuf {
        let len = (width * height * 4) as usize;
        let mut buf = Vec::with_capacity(len);
        unsafe { buf.set_len(len); } // We immediately fill the buffer.
        weak_rng().fill_bytes(&mut *buf);

        ImageBuffer::from_raw(width, height, buf).unwrap()
    }

    #[test]
    fn hash_equality() {
        let test_img = gen_test_img(1024, 1024);
        let hash1 = ImageHash::hash(&test_img, 32, false);
        let hash2 = ImageHash::hash(&test_img, 32, false);

        assert_eq!(hash1, hash2);
    }

    #[test]
    fn size() {
        let test_img = gen_test_img(1024, 1024);
        let hash = ImageHash::hash(&test_img, 32, false);
        assert_eq!(32*32, hash.size());
    }

    #[test]
    fn base64_encoding_decoding() {
        let test_img = gen_test_img(1024, 1024);
        let hash1 = ImageHash::hash(&test_img, 32, false);

        let base64_string = hash1.to_base64();
        let decoded_result = ImageHash::from_base64(&*base64_string);

        assert!(decoded_result.is_ok());

        assert_eq!(decoded_result.unwrap(), hash1);
    }

    #[bench]
    fn bench_hash(b: &mut Bencher) {
        let test_img = gen_test_img(1024, 1024);

        b.iter(|| ImageHash::hash(&test_img, 32, false));
    }
}
<commit_msg>Convert hash choice to enum with docs.<commit_after>#![feature(collections, core, hash)]
// Silence feature warnings for test module.
#![cfg_attr(test, feature(rand, test))]

extern crate image;
extern crate "rustc-serialize" as serialize;

use self::dct::{dct_2d, crop_dct};

use image::{
    imageops,
    DynamicImage,
    FilterType,
    GrayImage,
    GrayAlphaImage,
    Pixel,
    RgbImage,
    RgbaImage,
};

use serialize::base64::{ToBase64, STANDARD, FromBase64, FromBase64Error};

use std::collections::Bitv;

const FILTER_TYPE: FilterType = FilterType::Nearest;

mod dct;

/// A struct representing an image processed by a perceptual hash.
/// For efficiency, does not retain a copy of the image data after hashing.
///
/// Get an instance with `ImageHash::hash()`.
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
pub struct ImageHash {
    bitv: Bitv,
    hash_type: HashType,
}

impl ImageHash {

    /// Calculate the Hamming distance between this and `other`.
    /// Equivalent to counting the 1-bits of the XOR of the two `Bitv`.
    ///
    /// Essential to determining the perceived difference between `self` and `other`.
    ///
    /// ###Panics
    /// If `self` and `other` have differing hash types or hash sizes.
    pub fn dist(&self, other: &ImageHash) -> usize {
        assert!(self.hash_type == other.hash_type,
               "Image hashes must use the same algorithm for proper comparison!");
        assert!(self.bitv.len() == other.bitv.len(),
                "Image hashes must be the same length for proper comparison!");

        self.bitv.iter().zip(other.bitv.iter())
            .filter(|&(left, right)| left != right).count()
    }

    /// Calculate the Hamming distance between `self` and `other`,
    /// then normalize it to `[0, 1]`, as a fraction of the total bits.
    ///
    /// Roughly equivalent to the % difference between the two images,
    /// represented as a decimal.
    ///
    /// See `ImageHash::dist()`.
    pub fn dist_ratio(&self, other: &ImageHash) -> f32 {
        self.dist(other) as f32 / self.size() as f32
    }

    /// Get the hash size of this image. Should be equal to the number of bits in the hash.
    pub fn size(&self) -> u32 { self.bitv.len() as u32 }

    /// Get the `HashType` that this `ImageHash` was created with.
    pub fn hash_type(&self) -> HashType { self.hash_type }

    /// Create a hash of `img` with a length of `hash_size * hash_size` using the hash algorithm
    /// described by `hash_type`.
    pub fn hash<I: HashImage>(img: &I, hash_size: u32, hash_type: HashType) -> ImageHash {
        let hash = hash_type.hash(img, hash_size);

        assert!((hash_size * hash_size) as usize == hash.len());

        ImageHash {
            bitv: hash,
            hash_type: hash_type,
        }
    }

    /// Create an `ImageHash` instance from the given Base64-encoded string.
    pub fn from_base64(encoded_hash: &str) -> Result<ImageHash, FromBase64Error>{
        let data = try!(encoded_hash.from_base64());
        // The hash type should be the first bit of the hash
        let hash_type = HashType::from_byte(data.remove(0));

        Ok(ImageHash{
            bitv: Bitv::from_bytes(&*data),
            hash_type: hash_type,
        })
    }

    /// Get a Base64 string representing the bits of this hash.
    ///
    /// Mostly for printing convenience.
    pub fn to_base64(&self) -> String {
        let mut bytes = self.bitv.to_bytes();
        // Insert the hash type as the first byte.
        bytes.insert(0, self.hash_type.to_byte());

        bytes.to_base64(STANDARD)
    }
}

/// An enum describing the hash algorithms that `img_hash` offers.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum HashType {
    /// Fastest, but inaccurate. Really only useful for finding duplicates.
    Mean,
    /// Slowest, but detects changes in color gamut and sometimes significant edits.
    DCT,
}

impl HashType {
    fn hash<I: HashImage>(self, img: &I, hash_size: u32) -> Bitv {
        use HashType::*;

        match self {
            Mean => mean_hash(img, hash_size),
            DCT => dct_hash(img, hash_size),
        }
    }

    fn to_byte(self) -> u8 {
        use HashType::*;

        match self {
            Mean => 1,
            DCT => 2,
        }
    }

    fn from_byte(byte: u8) -> HashType {
        use HashType::*;

        match byte {
            1 => Mean,
            2 => DCT,
            _ => panic!("Byte {:?} cannot be coerced to a `HashType`!", byte),
        }
    }
}

fn mean_hash<I: HashImage>(img: &I, hash_size: u32) -> Bitv {
    let hash_values = img.gray_resize_square(hash_size).into_raw();

    let mean = hash_values.iter().fold(0u32, |b, &a| a as u32 + b)
        / hash_values.len() as u32;

    hash_values.into_iter().map(|x| x as u32 >= mean).collect()
}

fn dct_hash<I: HashImage>(img: &I, hash_size: u32) -> Bitv {
    let large_size = hash_size * 4;

    // We take a bigger resize than fast_hash,
    // then we only take the lowest corner of the DCT
    let hash_values: Vec<_> = img.gray_resize_square(large_size)
        .into_raw().into_iter().map(|val| val as f64).collect();

    let dct = dct_2d(hash_values.as_slice(),
        large_size as usize, large_size as usize);

    let original = (large_size as usize, large_size as usize);
    let new = (hash_size as usize, hash_size as usize);

    let cropped_dct = crop_dct(dct, original, new);

    let mean = cropped_dct.iter().fold(0f64, |b, &a| a + b)
        / cropped_dct.len() as f64;

    cropped_dct.into_iter().map(|x| x >= mean).collect()
}

/// A trait for describing an image that can be successfully hashed.
pub trait HashImage {
    /// Apply a grayscale filter and drop the alpha channel (if present),
    /// then resize the image to `size` width by `size` height (making it square).
    ///
    /// Returns a copy, leaving `self` unmodified.
    fn gray_resize_square(&self, size: u32) -> GrayImage;
}

macro_rules! hash_img_impl {
    ($ty:ty) => (
        impl HashImage for $ty {
            fn gray_resize_square(&self, size: u32) -> GrayImage {
                let ref gray = imageops::grayscale(self);
                imageops::resize(gray, size, size, FILTER_TYPE)
            }
        }
    );
    ($($ty:ty),+) => ( $(hash_img_impl! { $ty })+ );
}

hash_img_impl! { GrayImage, GrayAlphaImage, RgbImage, RgbaImage, DynamicImage }

#[cfg(test)]
mod test {
    extern crate test;

    use image::{Rgba, ImageBuffer};

    use self::test::Bencher;

    use super::{HashType, ImageHash};

    use std::rand::{weak_rng, Rng};

    type RgbaBuf = ImageBuffer<Rgba<u8>, Vec<u8>>;

    fn gen_test_img(width: u32, height: u32) -> RgbaBuf {
        let len = (width * height * 4) as usize;
        let mut buf = Vec::with_capacity(len);
        unsafe { buf.set_len(len); } // We immediately fill the buffer.
        weak_rng().fill_bytes(&mut *buf);

        ImageBuffer::from_raw(width, height, buf).unwrap()
    }

    #[test]
    fn hash_equality() {
        let test_img = gen_test_img(1024, 1024);
        let hash1 = ImageHash::hash(&test_img, 32, HashType::Mean);
        let hash2 = ImageHash::hash(&test_img, 32, HashType::Mean);

        assert_eq!(hash1, hash2);
    }

    #[test]
    fn size() {
        let test_img = gen_test_img(1024, 1024);
        let hash = ImageHash::hash(&test_img, 32, HashType::Mean);
        assert_eq!(32*32, hash.size());
    }

    #[test]
    fn base64_encoding_decoding() {
        let test_img = gen_test_img(1024, 1024);
        let hash1 = ImageHash::hash(&test_img, 32, HashType::Mean);

        let base64_string = hash1.to_base64();
        let decoded_result = ImageHash::from_base64(&*base64_string);

        assert!(decoded_result.is_ok());

        assert_eq!(decoded_result.unwrap(), hash1);
    }

    #[bench]
    fn bench_hash(b: &mut Bencher) {
        let test_img = gen_test_img(1024, 1024);

        b.iter(|| ImageHash::hash(&test_img, 32, HashType::Mean));
    }
}
<|endoftext|>


<commit_before>#![feature(std_misc)]
#![cfg_attr(test, feature(test))]

extern crate rand;

mod number_streams;

use std::hash::Hasher;
use std::collections::hash_state::HashState;
use rand::Rng;
use number_streams::NumberStreams;

const CHUNK_SIZE: usize = 32;

const PRIME_1: u64 = 11400714785074694791;
const PRIME_2: u64 = 14029467366897019727;
const PRIME_3: u64 = 1609587929392839161;
const PRIME_4: u64 = 9650029242287828579;
const PRIME_5: u64 = 2870177450012600261;

#[derive(Copy,Clone,PartialEq)]
struct XxCore {
    v1: u64,
    v2: u64,
    v3: u64,
    v4: u64,
}

#[derive(Debug,Copy,Clone)]
pub struct XxHash {
    total_len: u64,
    seed: u64,
    core: XxCore,
    buffer: [u8; CHUNK_SIZE],
    buffer_usage: usize,
}

impl XxCore {
    fn with_seed(seed: u64) -> XxCore {
        XxCore {
            v1: seed.wrapping_add(PRIME_1).wrapping_add(PRIME_2),
            v2: seed.wrapping_add(PRIME_2),
            v3: seed,
            v4: seed.wrapping_sub(PRIME_1),
        }
    }

    #[inline(always)]
    fn ingest_chunks<I>(&mut self, values: I)
        where I: Iterator<Item=u64>
    {
        #[inline(always)]
        fn ingest_one_number(mut current_value: u64, mut value: u64) -> u64 {
            value = value.wrapping_mul(PRIME_2);
            current_value = current_value.wrapping_add(value);
            current_value = current_value.rotate_left(31);
            current_value.wrapping_mul(PRIME_1)
        };

        // By drawing these out, we can avoid going back and forth to
        // memory. It only really helps for large files, when we need
        // to iterate multiple times here.

        let mut v1 = self.v1;
        let mut v2 = self.v2;
        let mut v3 = self.v3;
        let mut v4 = self.v4;

        let mut values = values.peekable();

        while values.peek().is_some() {
            v1 = ingest_one_number(v1, values.next().unwrap());
            v2 = ingest_one_number(v2, values.next().unwrap());
            v3 = ingest_one_number(v3, values.next().unwrap());
            v4 = ingest_one_number(v4, values.next().unwrap());
        }

        self.v1 = v1;
        self.v2 = v2;
        self.v3 = v3;
        self.v4 = v4;
    }

    #[inline(always)]
    fn finish(&self) -> u64 {
        // The original code pulls out local vars for v[1234]
        // here. Performance tests did not show that to be effective
        // here, presumably because this method is not called in a
        // tight loop.

        let mut hash;

        hash =                   self.v1.rotate_left( 1);
        hash = hash.wrapping_add(self.v2.rotate_left( 7));
        hash = hash.wrapping_add(self.v3.rotate_left(12));
        hash = hash.wrapping_add(self.v4.rotate_left(18));

        #[inline(always)]
        fn mix_one(mut hash: u64, mut value: u64) -> u64 {
            value = value.wrapping_mul(PRIME_2);
            value = value.rotate_left(31);
            value = value.wrapping_mul(PRIME_1);
            hash ^= value;
            hash = hash.wrapping_mul(PRIME_1);
            hash.wrapping_add(PRIME_4)
        }

        hash = mix_one(hash, self.v1);
        hash = mix_one(hash, self.v2);
        hash = mix_one(hash, self.v3);
        hash = mix_one(hash, self.v4);

        hash
    }
}

impl std::fmt::Debug for XxCore {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(
            f, "XxCore {{ {:016x} {:016x} {:016x} {:016x} }}",
            self.v1, self.v2, self.v3, self.v4
        )
    }
}

impl XxHash {
    pub fn with_seed(seed: u64) -> XxHash {
        XxHash {
            total_len: 0,
            seed: seed,
            core: XxCore::with_seed(seed),
            buffer: [0; CHUNK_SIZE],
            buffer_usage: 0,
        }
    }
}

impl Default for XxHash {
    fn default() -> XxHash {
        XxHash::with_seed(0)
    }
}

impl Hasher for XxHash {
    fn write(&mut self, bytes: &[u8]) {
        let mut bytes = bytes;

        self.total_len += bytes.len() as u64;

        // Even with new data, we still don't have a full buffer. Wait
        // until we have a full buffer.
        if self.buffer_usage + bytes.len() < self.buffer.len() {
            unsafe {
                let tail = self.buffer.as_mut_ptr().offset(self.buffer_usage as isize);
                std::ptr::copy_nonoverlapping(bytes.as_ptr(), tail, bytes.len());
            }
            self.buffer_usage += bytes.len();
            return;
        }

        // Some data left from previous update. Fill the buffer and
        // consume it first.
        if self.buffer_usage > 0 {
            let bytes_to_use = self.buffer.len() - self.buffer_usage;
            let (to_use, leftover) = bytes.split_at(bytes_to_use);

            unsafe {
                let tail = self.buffer.as_mut_ptr().offset(self.buffer_usage as isize);
                std::ptr::copy_nonoverlapping(to_use.as_ptr(), tail, bytes_to_use);
            }

            let (iter, _) = self.buffer.u64_stream();

            self.core.ingest_chunks(iter);

            bytes = leftover;
            self.buffer_usage = 0;
        }

        // Consume the input data in large chunks
        let (iter, bytes) = bytes.u64_stream_with_stride(4);
        self.core.ingest_chunks(iter);

        // Save any leftover data for the next call
        if bytes.len() > 0 {
            unsafe {
                std::ptr::copy_nonoverlapping(bytes.as_ptr(), self.buffer.as_mut_ptr(), bytes.len());
            }
            self.buffer_usage = bytes.len();
        }
    }

    fn finish(&self) -> u64 {
        let mut hash;

        // We have processed at least one full chunk
        if self.total_len >= CHUNK_SIZE as u64 {
            hash = self.core.finish();
        } else {
            hash = self.seed.wrapping_add(PRIME_5);
        }

        hash = hash.wrapping_add(self.total_len);

        let buffered = &self.buffer[..self.buffer_usage];
        let (buffered_u64s, buffered) = buffered.u64_stream();

        for mut k1 in buffered_u64s {
            k1 = k1.wrapping_mul(PRIME_2);
            k1 = k1.rotate_left(31);
            k1 = k1.wrapping_mul(PRIME_1);
            hash ^= k1;
            hash = hash.rotate_left(27);
            hash = hash.wrapping_mul(PRIME_1);
            hash = hash.wrapping_add(PRIME_4);
        }

        let (buffered_u32s, buffered) = buffered.u32_stream();

        for k1 in buffered_u32s {
            let k1 = (k1 as u64).wrapping_mul(PRIME_1);
            hash ^= k1;
            hash = hash.rotate_left(23);
            hash = hash.wrapping_mul(PRIME_2);
            hash = hash.wrapping_add(PRIME_3);
        }

        for buffered_u8 in buffered {
            let k1 = (*buffered_u8 as u64).wrapping_mul(PRIME_5);
            hash ^= k1;
            hash = hash.rotate_left(11);
            hash = hash.wrapping_mul(PRIME_1);
        }

        // The final intermixing
        hash ^= hash >> 33;
        hash = hash.wrapping_mul(PRIME_2);
        hash ^= hash >> 29;
        hash = hash.wrapping_mul(PRIME_3);
        hash ^= hash >> 32;

        hash
    }
}

struct RandomXxHashState(u64);

impl RandomXxHashState {
    fn new() -> RandomXxHashState {
        RandomXxHashState(rand::thread_rng().gen())
    }
}

impl Default for RandomXxHashState {
    fn default() -> RandomXxHashState { RandomXxHashState::new() }
}

impl HashState for RandomXxHashState {
    type Hasher = XxHash;

    fn hasher(&self) -> XxHash { XxHash::with_seed(self.0) }
}

#[cfg(test)]
mod test {
    use std::hash::Hasher;
    use std::collections::HashMap;
    use std::collections::hash_state::DefaultState;
    use super::{XxHash,RandomXxHashState};

    #[test]
    fn ingesting_byte_by_byte_is_equivalent_to_large_chunks() {
        let bytes: Vec<_> = (0..32).map(|_| 0).collect();

        let mut byte_by_byte = XxHash::with_seed(0);
        for byte in bytes.chunks(1) {
            byte_by_byte.write(byte);
        }

        let mut one_chunk = XxHash::with_seed(0);
        one_chunk.write(&bytes);

        assert_eq!(byte_by_byte.core, one_chunk.core);
    }

    #[test]
    fn hash_of_nothing_matches_c_implementation() {
        let mut hasher = XxHash::with_seed(0);
        hasher.write(&[]);
        assert_eq!(hasher.finish(), 0xef46db3751d8e999);
    }

    #[test]
    fn hash_of_single_byte_matches_c_implementation() {
        let mut hasher = XxHash::with_seed(0);
        hasher.write(&[42]);
        assert_eq!(hasher.finish(), 0x0a9edecebeb03ae4);
    }

    #[test]
    fn hash_of_multiple_bytes_matches_c_implementation() {
        let mut hasher = XxHash::with_seed(0);
        hasher.write(b"Hello, world!\0");
        assert_eq!(hasher.finish(), 0x7b06c531ea43e89f);
    }

    #[test]
    fn hash_of_multiple_chunks_matches_c_implementation() {
        let bytes: Vec<_> = (0..100).collect();
        let mut hasher = XxHash::with_seed(0);
        hasher.write(&bytes);
        assert_eq!(hasher.finish(), 0x6ac1e58032166597);
    }

    #[test]
    fn hash_with_different_seed_matches_c_implementation() {
        let mut hasher = XxHash::with_seed(0xae0543311b702d91);
        hasher.write(&[]);
        assert_eq!(hasher.finish(), 0x4b6a04fcdf7a4672);
    }

    #[test]
    fn hash_with_different_seed_and_multiple_chunks_matches_c_implementation() {
        let bytes: Vec<_> = (0..100).collect();
        let mut hasher = XxHash::with_seed(0xae0543311b702d91);
        hasher.write(&bytes);
        assert_eq!(hasher.finish(), 0x567e355e0682e1f1);
    }

    #[test]
    fn can_be_used_in_a_hashmap_with_a_default_seed() {
        let mut hash: HashMap<_, _, DefaultState<XxHash>> = Default::default();
        hash.insert(42, "the answer");
        assert_eq!(hash.get(&42), Some(&"the answer"));
    }

    #[test]
    fn can_be_used_in_a_hashmap_with_a_random_seed() {
        let mut hash: HashMap<_, _, RandomXxHashState> = Default::default();
        hash.insert(42, "the answer");
        assert_eq!(hash.get(&42), Some(&"the answer"));
    }
}

#[cfg(test)]
mod bench {
    extern crate test;

    use std::hash::Hasher;
    use super::XxHash;

    #[inline(always)]
    fn straight_line_slice_bench(b: &mut test::Bencher, len: usize) {
        let bytes: Vec<_> = (0..100).cycle().take(len).collect();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            let mut hasher = XxHash::with_seed(0);
            hasher.write(&bytes);
            hasher.finish()
        });
    }

    #[bench]
    fn straight_line_megabyte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 1024*1024);
    }

    #[bench]
    fn straight_line_1024_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 1024);
    }

    #[bench]
    fn straight_line_512_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 512);
    }

    #[bench]
    fn straight_line_256_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 256);
    }

    #[bench]
    fn straight_line_128_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 128);
    }

    #[bench]
    fn straight_line_32_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 32);
    }

    #[bench]
    fn straight_line_16_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 16);
    }

    #[bench]
    fn straight_line_4_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 4);
    }

    #[bench]
    fn straight_line_1_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 1);
    }

    #[bench]
    fn straight_line_0_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 0);
    }
}
<commit_msg>Improve performance by not zeroing the temporary buffer<commit_after>#![feature(std_misc)]
#![cfg_attr(test, feature(test))]

extern crate rand;

mod number_streams;

use std::hash::Hasher;
use std::collections::hash_state::HashState;
use rand::Rng;
use number_streams::NumberStreams;

const CHUNK_SIZE: usize = 32;

const PRIME_1: u64 = 11400714785074694791;
const PRIME_2: u64 = 14029467366897019727;
const PRIME_3: u64 = 1609587929392839161;
const PRIME_4: u64 = 9650029242287828579;
const PRIME_5: u64 = 2870177450012600261;

#[derive(Copy,Clone,PartialEq)]
struct XxCore {
    v1: u64,
    v2: u64,
    v3: u64,
    v4: u64,
}

#[derive(Debug,Copy,Clone)]
pub struct XxHash {
    total_len: u64,
    seed: u64,
    core: XxCore,
    buffer: [u8; CHUNK_SIZE],
    buffer_usage: usize,
}

impl XxCore {
    fn with_seed(seed: u64) -> XxCore {
        XxCore {
            v1: seed.wrapping_add(PRIME_1).wrapping_add(PRIME_2),
            v2: seed.wrapping_add(PRIME_2),
            v3: seed,
            v4: seed.wrapping_sub(PRIME_1),
        }
    }

    #[inline(always)]
    fn ingest_chunks<I>(&mut self, values: I)
        where I: Iterator<Item=u64>
    {
        #[inline(always)]
        fn ingest_one_number(mut current_value: u64, mut value: u64) -> u64 {
            value = value.wrapping_mul(PRIME_2);
            current_value = current_value.wrapping_add(value);
            current_value = current_value.rotate_left(31);
            current_value.wrapping_mul(PRIME_1)
        };

        // By drawing these out, we can avoid going back and forth to
        // memory. It only really helps for large files, when we need
        // to iterate multiple times here.

        let mut v1 = self.v1;
        let mut v2 = self.v2;
        let mut v3 = self.v3;
        let mut v4 = self.v4;

        let mut values = values.peekable();

        while values.peek().is_some() {
            v1 = ingest_one_number(v1, values.next().unwrap());
            v2 = ingest_one_number(v2, values.next().unwrap());
            v3 = ingest_one_number(v3, values.next().unwrap());
            v4 = ingest_one_number(v4, values.next().unwrap());
        }

        self.v1 = v1;
        self.v2 = v2;
        self.v3 = v3;
        self.v4 = v4;
    }

    #[inline(always)]
    fn finish(&self) -> u64 {
        // The original code pulls out local vars for v[1234]
        // here. Performance tests did not show that to be effective
        // here, presumably because this method is not called in a
        // tight loop.

        let mut hash;

        hash =                   self.v1.rotate_left( 1);
        hash = hash.wrapping_add(self.v2.rotate_left( 7));
        hash = hash.wrapping_add(self.v3.rotate_left(12));
        hash = hash.wrapping_add(self.v4.rotate_left(18));

        #[inline(always)]
        fn mix_one(mut hash: u64, mut value: u64) -> u64 {
            value = value.wrapping_mul(PRIME_2);
            value = value.rotate_left(31);
            value = value.wrapping_mul(PRIME_1);
            hash ^= value;
            hash = hash.wrapping_mul(PRIME_1);
            hash.wrapping_add(PRIME_4)
        }

        hash = mix_one(hash, self.v1);
        hash = mix_one(hash, self.v2);
        hash = mix_one(hash, self.v3);
        hash = mix_one(hash, self.v4);

        hash
    }
}

impl std::fmt::Debug for XxCore {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(
            f, "XxCore {{ {:016x} {:016x} {:016x} {:016x} }}",
            self.v1, self.v2, self.v3, self.v4
        )
    }
}

impl XxHash {
    pub fn with_seed(seed: u64) -> XxHash {
        XxHash {
            total_len: 0,
            seed: seed,
            core: XxCore::with_seed(seed),
            buffer: unsafe { ::std::mem::uninitialized() },
            buffer_usage: 0,
        }
    }
}

impl Default for XxHash {
    fn default() -> XxHash {
        XxHash::with_seed(0)
    }
}

impl Hasher for XxHash {
    fn write(&mut self, bytes: &[u8]) {
        let mut bytes = bytes;

        self.total_len += bytes.len() as u64;

        // Even with new data, we still don't have a full buffer. Wait
        // until we have a full buffer.
        if self.buffer_usage + bytes.len() < self.buffer.len() {
            unsafe {
                let tail = self.buffer.as_mut_ptr().offset(self.buffer_usage as isize);
                std::ptr::copy_nonoverlapping(bytes.as_ptr(), tail, bytes.len());
            }
            self.buffer_usage += bytes.len();
            return;
        }

        // Some data left from previous update. Fill the buffer and
        // consume it first.
        if self.buffer_usage > 0 {
            let bytes_to_use = self.buffer.len() - self.buffer_usage;
            let (to_use, leftover) = bytes.split_at(bytes_to_use);

            unsafe {
                let tail = self.buffer.as_mut_ptr().offset(self.buffer_usage as isize);
                std::ptr::copy_nonoverlapping(to_use.as_ptr(), tail, bytes_to_use);
            }

            let (iter, _) = self.buffer.u64_stream();

            self.core.ingest_chunks(iter);

            bytes = leftover;
            self.buffer_usage = 0;
        }

        // Consume the input data in large chunks
        let (iter, bytes) = bytes.u64_stream_with_stride(4);
        self.core.ingest_chunks(iter);

        // Save any leftover data for the next call
        if bytes.len() > 0 {
            unsafe {
                std::ptr::copy_nonoverlapping(bytes.as_ptr(), self.buffer.as_mut_ptr(), bytes.len());
            }
            self.buffer_usage = bytes.len();
        }
    }

    fn finish(&self) -> u64 {
        let mut hash;

        // We have processed at least one full chunk
        if self.total_len >= CHUNK_SIZE as u64 {
            hash = self.core.finish();
        } else {
            hash = self.seed.wrapping_add(PRIME_5);
        }

        hash = hash.wrapping_add(self.total_len);

        let buffered = &self.buffer[..self.buffer_usage];
        let (buffered_u64s, buffered) = buffered.u64_stream();

        for mut k1 in buffered_u64s {
            k1 = k1.wrapping_mul(PRIME_2);
            k1 = k1.rotate_left(31);
            k1 = k1.wrapping_mul(PRIME_1);
            hash ^= k1;
            hash = hash.rotate_left(27);
            hash = hash.wrapping_mul(PRIME_1);
            hash = hash.wrapping_add(PRIME_4);
        }

        let (buffered_u32s, buffered) = buffered.u32_stream();

        for k1 in buffered_u32s {
            let k1 = (k1 as u64).wrapping_mul(PRIME_1);
            hash ^= k1;
            hash = hash.rotate_left(23);
            hash = hash.wrapping_mul(PRIME_2);
            hash = hash.wrapping_add(PRIME_3);
        }

        for buffered_u8 in buffered {
            let k1 = (*buffered_u8 as u64).wrapping_mul(PRIME_5);
            hash ^= k1;
            hash = hash.rotate_left(11);
            hash = hash.wrapping_mul(PRIME_1);
        }

        // The final intermixing
        hash ^= hash >> 33;
        hash = hash.wrapping_mul(PRIME_2);
        hash ^= hash >> 29;
        hash = hash.wrapping_mul(PRIME_3);
        hash ^= hash >> 32;

        hash
    }
}

struct RandomXxHashState(u64);

impl RandomXxHashState {
    fn new() -> RandomXxHashState {
        RandomXxHashState(rand::thread_rng().gen())
    }
}

impl Default for RandomXxHashState {
    fn default() -> RandomXxHashState { RandomXxHashState::new() }
}

impl HashState for RandomXxHashState {
    type Hasher = XxHash;

    fn hasher(&self) -> XxHash { XxHash::with_seed(self.0) }
}

#[cfg(test)]
mod test {
    use std::hash::Hasher;
    use std::collections::HashMap;
    use std::collections::hash_state::DefaultState;
    use super::{XxHash,RandomXxHashState};

    #[test]
    fn ingesting_byte_by_byte_is_equivalent_to_large_chunks() {
        let bytes: Vec<_> = (0..32).map(|_| 0).collect();

        let mut byte_by_byte = XxHash::with_seed(0);
        for byte in bytes.chunks(1) {
            byte_by_byte.write(byte);
        }

        let mut one_chunk = XxHash::with_seed(0);
        one_chunk.write(&bytes);

        assert_eq!(byte_by_byte.core, one_chunk.core);
    }

    #[test]
    fn hash_of_nothing_matches_c_implementation() {
        let mut hasher = XxHash::with_seed(0);
        hasher.write(&[]);
        assert_eq!(hasher.finish(), 0xef46db3751d8e999);
    }

    #[test]
    fn hash_of_single_byte_matches_c_implementation() {
        let mut hasher = XxHash::with_seed(0);
        hasher.write(&[42]);
        assert_eq!(hasher.finish(), 0x0a9edecebeb03ae4);
    }

    #[test]
    fn hash_of_multiple_bytes_matches_c_implementation() {
        let mut hasher = XxHash::with_seed(0);
        hasher.write(b"Hello, world!\0");
        assert_eq!(hasher.finish(), 0x7b06c531ea43e89f);
    }

    #[test]
    fn hash_of_multiple_chunks_matches_c_implementation() {
        let bytes: Vec<_> = (0..100).collect();
        let mut hasher = XxHash::with_seed(0);
        hasher.write(&bytes);
        assert_eq!(hasher.finish(), 0x6ac1e58032166597);
    }

    #[test]
    fn hash_with_different_seed_matches_c_implementation() {
        let mut hasher = XxHash::with_seed(0xae0543311b702d91);
        hasher.write(&[]);
        assert_eq!(hasher.finish(), 0x4b6a04fcdf7a4672);
    }

    #[test]
    fn hash_with_different_seed_and_multiple_chunks_matches_c_implementation() {
        let bytes: Vec<_> = (0..100).collect();
        let mut hasher = XxHash::with_seed(0xae0543311b702d91);
        hasher.write(&bytes);
        assert_eq!(hasher.finish(), 0x567e355e0682e1f1);
    }

    #[test]
    fn can_be_used_in_a_hashmap_with_a_default_seed() {
        let mut hash: HashMap<_, _, DefaultState<XxHash>> = Default::default();
        hash.insert(42, "the answer");
        assert_eq!(hash.get(&42), Some(&"the answer"));
    }

    #[test]
    fn can_be_used_in_a_hashmap_with_a_random_seed() {
        let mut hash: HashMap<_, _, RandomXxHashState> = Default::default();
        hash.insert(42, "the answer");
        assert_eq!(hash.get(&42), Some(&"the answer"));
    }
}

#[cfg(test)]
mod bench {
    extern crate test;

    use std::hash::Hasher;
    use super::XxHash;

    #[inline(always)]
    fn straight_line_slice_bench(b: &mut test::Bencher, len: usize) {
        let bytes: Vec<_> = (0..100).cycle().take(len).collect();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            let mut hasher = XxHash::with_seed(0);
            hasher.write(&bytes);
            hasher.finish()
        });
    }

    #[bench]
    fn straight_line_megabyte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 1024*1024);
    }

    #[bench]
    fn straight_line_1024_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 1024);
    }

    #[bench]
    fn straight_line_512_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 512);
    }

    #[bench]
    fn straight_line_256_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 256);
    }

    #[bench]
    fn straight_line_128_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 128);
    }

    #[bench]
    fn straight_line_32_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 32);
    }

    #[bench]
    fn straight_line_16_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 16);
    }

    #[bench]
    fn straight_line_4_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 4);
    }

    #[bench]
    fn straight_line_1_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 1);
    }

    #[bench]
    fn straight_line_0_byte(b: &mut test::Bencher) {
        straight_line_slice_bench(b, 0);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "rui"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![feature(box_syntax, core, libc, collections)]

/*!
[repository](https://github.com/enex/rust_gui)
*/

extern crate libc;
extern crate glutin;
extern crate nanovg;
extern crate gl;

pub use glutin::{MouseCursor, MouseButton, VirtualKeyCode, Api, WindowBuilder};
pub use context::{Context, DrawContext, EventContext, Common};
pub use nanovg::{Color, Font};
pub use transform::Transform;

use std::fmt;
use state::State;
use std::default::Default;
use nanovg::Ctx;
use nanovg_backend::NanovgBackend;
use draw::{Path, PathInstr, AsPath};
use std::any::Any;
use context::StateT;
use glutin::Event;
use std::ops::Deref;
use std::intrinsics;

pub mod context;
#[macro_use]
pub mod components;
#[macro_use]
pub mod draw;
pub mod primitives;
pub mod nanovg_backend;
pub mod transform;
//pub mod debug;
mod state;

#[macro_use]
mod macros;

pub mod prelude{
	//! this is a bundle of the things most frequently needed
	//!
	//! 	use rui::prelude::*;

	pub use primitives;
	pub use Widget;
	pub use context::Context;
	pub use components;
	pub use draw::{Path, PathInstr, AsPath};
	pub use context::{EventHandle, StateT};
	pub use App;
	pub use Color;
}

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct ID (pub [u16;12]);
impl fmt::Debug for ID{
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{
		let mut first = true;
		try!(write!(f,"$"));
		for i in self.0.iter(){
			if *i == 0{
				break;
			}
			if !first{
				try!(write!(f,"-"));
			}
			try!(write!(f, "{}", i));
			first = false;
		}
		Ok(())
	}
}
impl ID{
	pub fn null() -> ID{
		ID([0;12])
	}
	/// whether it is the id of the root node
	pub fn is_root(&self) -> bool{
		self.0[0] == 0
	}
}

//TODO: maybe change ID type
//TODO: use an array like [u8; 16] for storing keys encoded like 0x[one or two byes][the rest]

/// Backend which should be implemented to support drawing operations
/// the first backend will be cairo + OpenGL but other backends should follow
pub trait Backend{
	/// start drawing the path. The size of the Frame is provided.
	fn begin(&mut self, _:i32, _:i32){}

	/// load a font form a given path and make it available for later use
	/// if it is called with the same font more than one time nothing
	/// should happen
	fn load_font(&mut self, &str, &str);
	fn find_font(&self, name: &str) -> Option<Font>;
	fn font_face(&mut self, font: &str);
	fn font_size(&mut self, size: f32);
	fn font_color(&mut self, color: Color);
    fn text(&self, x: f32, y: f32, text: &str) -> f32;

	fn reset_transform(&mut self);
	fn transform(&mut self, Transform);
	fn set_transform(&mut self, t: Transform){
		self.reset_transform();
		self.transform(t);
	}
	fn current_transform(&self) -> Transform;

	fn draw_path<P:AsPath>(&mut self, P);

	//drawing primitives
	fn draw_line(&mut self, line: primitives::Line){
		self.draw_path(path!(
			M:line.x1,line.y1;
			L:line.x2,line.y2
		));
	}
	/// draw a rectangle
	fn draw_rect(&mut self, rect: primitives::Rect){
		self.draw_path(path!(M:rect.x,rect.y;
			L:(rect.x+rect.width),rect.y;
			L:(rect.x+rect.width),(rect.y+rect.height);
			L:rect.x,(rect.y+rect.height);
			Z:
		));
	}
	/// draw a circle
	fn draw_circle(&mut self, primitives::Circle){
		//TODO: implement it with draw_path
		unimplemented!()
	}
	/// draw a polygon
	fn draw_polygon(&mut self, pg: primitives::Polygon){
		let mut p = primitives::Path::new();
		let mut first = true;

		for c in pg.cords.iter(){
			if first{
				p.move_to(c.0, c.1);
				first = false;
			}else{
				p.line_to(c.0, c.1);
			}
		}

		p.close_path();
		self.draw_path(p);
	}

	/// end of the drawing operation for one frame
	fn end(&mut self){}
}

/// the trait implemented by all widgets displayed.
/// A widget can eather have state, in which case it gets its own frame-buffer
/// or it has no state in which case its result will be thrown away after changes.
pub trait Widget{
	/// The state of this widget if the widget has no state, nothing has
	/// to b done, the state type has to implement the default trait and
	/// it will have the dafault value when accessed first.
	type State: Any + Default = ();

	/// the event the widget returns. This is a enum most of the times.
	type Event = ();

	/// In this function only rendering to the screen and atouching event listeners is done
	/// the state of the component gets passed as a imutable reference, so this rutine is not
	/// able to change anything.
	/// It returns the (width, hight) of the area affected by the render method
	fn render<C:Context<TWidget=Self>>(&self, ctx: &mut C, s: &Self::State);

	/// Method which is used by the layout engine to get the size of a component
	/// by default the size will be calculated by using the render function with
	/// blocked drawing, but if speed matters this function can provide faster information
	#[inline(always)]
	fn size(&self) -> (f64, f64) {
		(0.0,0.0)
	}

	/// This function is called on every type of element visible one time
	/// by default it does nothing
	fn init(){}

	/// the name of the widget, this is optional and for debuging
	fn name() -> &'static str{
		unsafe{
			intrinsics::type_name::<Self>()
		}
	}

	/// function to add a widget to the context.
	fn draw<C:Context>(&self, c: &mut C, id: u16) where Self: Widget+Sized{
		c.add(id, self)
	}
}

/// traite which should be implmented by everything used as ui state
pub trait UIState<E>: StateT{
	/// handle a event emited from the root component
	fn handle(&mut self, e: E);
}
impl UIState<()> for (){
	fn handle(&mut self, _:()){}
}
/// Trait possibly used for the context to add widgets, could abstract
/// transformation
pub trait Adder<T>{
	fn add(&mut self, u16, &T);
}
pub trait AdderEvent<T>{
	fn awe(&mut self, u16, &T);
}

/// this represents a whole app and contains the root widget
pub struct App<W,D:Backend>{
	/// the window struct responsible for event listening
	window: glutin::Window,
	/// the root node which is a Widget
	root: W,
	/// the size of the window (width, height)
	size: (i32, i32),
	/// whether drawing has already begun
	begun: bool,
	/// whether the frame has to be redrawn
	redraw: bool,
	///the data relevant for the contexts
	data: Common<D>,
}

impl<W:Widget<State=S,Event=E>,S:UIState<E>, E> App<W, NanovgBackend>{
	pub fn new(window: glutin::Window, root:W) -> App<W, NanovgBackend>{
		let (w, h) = match window.get_inner_size(){
			Some(s) => s,
			None => {
				println!("was nat able to get inner sizer");
				(0, 0)
			}
		};
		App{
			root: root,
			size: (w as i32, h as i32),
			data: Common{
				be: {
					gl::load_with(|symbol| window.get_proc_address(symbol));
					let vg = Ctx::create_gl3(nanovg::ANTIALIAS | nanovg::STENCIL_STROKES);
					NanovgBackend::new(vg)
				},
				state: State::new(),
				depth: 0,
				id: ID::null(),
				transform: Transform::normal(),
				listeners: Vec::new(),
				event: Event::Resized(w, h),
				affected: Vec::new(),
				redraw: Vec::new(),
				mouse_pos: (0.0, 0.0),
			},
			window: window,
			begun: false,
			redraw: true,
		}
	}

	/// start drawing process if not alerady started
	fn ps(&mut self){
		self.data.be.begin(self.size.0, self.size.1);
		self.begun = true;
	}

	/// start the application with a reference to the state, this will be passed
	/// to the render function of the root component
	pub fn show(&mut self, state: &mut S){
		self.data.be.load_font("sans", "res/Roboto-Regular.ttf");
		self.data.be.load_font("font-awesome", "res/fontawesome-webfont.ttf");
		self.data.be.load_font("sans-bold", "res/Roboto-Bold.ttf");

		while !self.window.is_closed() {
			use glutin::Event::*;

			let event = match self.window.wait_events().next(){
				Some(e) => e,
				None => break
			};

			match event{
				Resized(w, h) => {//handle resizes
					self.size.0 = w as i32;
					self.size.1 = h as i32;
					self.redraw = true;
				},
				MouseMoved((x,y)) => {
					self.data.mouse_pos = (x as f32, y as f32);
				},
				MouseInput(..) | ReceivedCharacter(..) | MouseWheel(..) => {
					self.data.event = event;
					let mut c:EventContext<NanovgBackend, W> = EventContext::new(&mut self.data);
					self.root.render(&mut c, state);
					for e in c.emited{
						state.handle(e);
						self.redraw = true;
					}
				},
				Refresh => { self.redraw = true; },
				_ => ()
			}

			self.data.be.reset_transform();
			if self.redraw{
				self.ps();
				{
					let mut c:DrawContext<NanovgBackend, W> =
						DrawContext::new(&mut self.data);
					self.root.render(&mut c, state);
				}
				//println!("draw ({}, {})", self.size.0, self.size.1);
				self.redraw = false;

				if self.begun{
					self.data.be.end();
					self.data.be.reset_transform();
					self.window.swap_buffers();
					self.begun = false;
				}
			}
		}
	}
}
<commit_msg>resize gl::Viewport on resize<commit_after>#![crate_name = "rui"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![feature(box_syntax, core, libc, collections)]

/*!
[repository](https://github.com/enex/rust_gui)
*/

extern crate libc;
extern crate glutin;
extern crate nanovg;
extern crate gl;

pub use glutin::{MouseCursor, MouseButton, VirtualKeyCode, Api, WindowBuilder};
pub use context::{Context, DrawContext, EventContext, Common};
pub use nanovg::{Color, Font};
pub use transform::Transform;

use std::fmt;
use state::State;
use std::default::Default;
use nanovg::Ctx;
use nanovg_backend::NanovgBackend;
use draw::{Path, PathInstr, AsPath};
use std::any::Any;
use context::StateT;
use glutin::Event;
use std::ops::Deref;
use std::intrinsics;

pub mod context;
#[macro_use]
pub mod components;
#[macro_use]
pub mod draw;
pub mod primitives;
pub mod nanovg_backend;
pub mod transform;
//pub mod debug;
mod state;

#[macro_use]
mod macros;

pub mod prelude{
	//! this is a bundle of the things most frequently needed
	//!
	//! 	use rui::prelude::*;

	pub use primitives;
	pub use Widget;
	pub use context::Context;
	pub use components;
	pub use draw::{Path, PathInstr, AsPath};
	pub use context::{EventHandle, StateT};
	pub use App;
	pub use Color;
}

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct ID (pub [u16;12]);
impl fmt::Debug for ID{
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{
		let mut first = true;
		try!(write!(f,"$"));
		for i in self.0.iter(){
			if *i == 0{
				break;
			}
			if !first{
				try!(write!(f,"-"));
			}
			try!(write!(f, "{}", i));
			first = false;
		}
		Ok(())
	}
}
impl ID{
	pub fn null() -> ID{
		ID([0;12])
	}
	/// whether it is the id of the root node
	pub fn is_root(&self) -> bool{
		self.0[0] == 0
	}
}

//TODO: maybe change ID type
//TODO: use an array like [u8; 16] for storing keys encoded like 0x[one or two byes][the rest]

/// Backend which should be implemented to support drawing operations
/// the first backend will be cairo + OpenGL but other backends should follow
pub trait Backend{
	/// start drawing the path. The size of the Frame is provided.
	fn begin(&mut self, _:i32, _:i32){}

	/// load a font form a given path and make it available for later use
	/// if it is called with the same font more than one time nothing
	/// should happen
	fn load_font(&mut self, &str, &str);
	fn find_font(&self, name: &str) -> Option<Font>;
	fn font_face(&mut self, font: &str);
	fn font_size(&mut self, size: f32);
	fn font_color(&mut self, color: Color);
    fn text(&self, x: f32, y: f32, text: &str) -> f32;

	fn reset_transform(&mut self);
	fn transform(&mut self, Transform);
	fn set_transform(&mut self, t: Transform){
		self.reset_transform();
		self.transform(t);
	}
	fn current_transform(&self) -> Transform;

	fn draw_path<P:AsPath>(&mut self, P);

	//drawing primitives
	fn draw_line(&mut self, line: primitives::Line){
		self.draw_path(path!(
			M:line.x1,line.y1;
			L:line.x2,line.y2
		));
	}
	/// draw a rectangle
	fn draw_rect(&mut self, rect: primitives::Rect){
		self.draw_path(path!(M:rect.x,rect.y;
			L:(rect.x+rect.width),rect.y;
			L:(rect.x+rect.width),(rect.y+rect.height);
			L:rect.x,(rect.y+rect.height);
			Z:
		));
	}
	/// draw a circle
	fn draw_circle(&mut self, primitives::Circle){
		//TODO: implement it with draw_path
		unimplemented!()
	}
	/// draw a polygon
	fn draw_polygon(&mut self, pg: primitives::Polygon){
		let mut p = primitives::Path::new();
		let mut first = true;

		for c in pg.cords.iter(){
			if first{
				p.move_to(c.0, c.1);
				first = false;
			}else{
				p.line_to(c.0, c.1);
			}
		}

		p.close_path();
		self.draw_path(p);
	}

	/// end of the drawing operation for one frame
	fn end(&mut self){}
}

/// the trait implemented by all widgets displayed.
/// A widget can eather have state, in which case it gets its own frame-buffer
/// or it has no state in which case its result will be thrown away after changes.
pub trait Widget{
	/// The state of this widget if the widget has no state, nothing has
	/// to b done, the state type has to implement the default trait and
	/// it will have the dafault value when accessed first.
	type State: Any + Default = ();

	/// the event the widget returns. This is a enum most of the times.
	type Event = ();

	/// In this function only rendering to the screen and atouching event listeners is done
	/// the state of the component gets passed as a imutable reference, so this rutine is not
	/// able to change anything.
	/// It returns the (width, hight) of the area affected by the render method
	fn render<C:Context<TWidget=Self>>(&self, ctx: &mut C, s: &Self::State);

	/// Method which is used by the layout engine to get the size of a component
	/// by default the size will be calculated by using the render function with
	/// blocked drawing, but if speed matters this function can provide faster information
	#[inline(always)]
	fn size(&self) -> (f64, f64) {
		(0.0,0.0)
	}

	/// This function is called on every type of element visible one time
	/// by default it does nothing
	fn init(){}

	/// the name of the widget, this is optional and for debuging
	fn name() -> &'static str{
		unsafe{
			intrinsics::type_name::<Self>()
		}
	}

	/// function to add a widget to the context.
	fn draw<C:Context>(&self, c: &mut C, id: u16) where Self: Widget+Sized{
		c.add(id, self)
	}
}

/// traite which should be implmented by everything used as ui state
pub trait UIState<E>: StateT{
	/// handle a event emited from the root component
	fn handle(&mut self, e: E);
}
impl UIState<()> for (){
	fn handle(&mut self, _:()){}
}
/// Trait possibly used for the context to add widgets, could abstract
/// transformation
pub trait Adder<T>{
	fn add(&mut self, u16, &T);
}
pub trait AdderEvent<T>{
	fn awe(&mut self, u16, &T);
}

/// this represents a whole app and contains the root widget
pub struct App<W,D:Backend>{
	/// the window struct responsible for event listening
	window: glutin::Window,
	/// the root node which is a Widget
	root: W,
	/// the size of the window (width, height)
	size: (i32, i32),
	/// whether drawing has already begun
	begun: bool,
	/// whether the frame has to be redrawn
	redraw: bool,
	///the data relevant for the contexts
	data: Common<D>,
}

impl<W:Widget<State=S,Event=E>,S:UIState<E>, E> App<W, NanovgBackend>{
	pub fn new(window: glutin::Window, root:W) -> App<W, NanovgBackend>{
		let (w, h) = match window.get_inner_size(){
			Some(s) => s,
			None => {
				println!("was nat able to get inner sizer");
				(0, 0)
			}
		};
		App{
			root: root,
			size: (w as i32, h as i32),
			data: Common{
				be: {
					gl::load_with(|symbol| window.get_proc_address(symbol));
					let vg = Ctx::create_gl3(nanovg::ANTIALIAS | nanovg::STENCIL_STROKES);
					NanovgBackend::new(vg)
				},
				state: State::new(),
				depth: 0,
				id: ID::null(),
				transform: Transform::normal(),
				listeners: Vec::new(),
				event: Event::Resized(w, h),
				affected: Vec::new(),
				redraw: Vec::new(),
				mouse_pos: (0.0, 0.0),
			},
			window: window,
			begun: false,
			redraw: true,
		}
	}

	/// start drawing process if not alerady started
	fn ps(&mut self){
		self.data.be.begin(self.size.0, self.size.1);
		self.begun = true;
	}

	/// start the application with a reference to the state, this will be passed
	/// to the render function of the root component
	pub fn show(&mut self, state: &mut S){
		self.data.be.load_font("sans", "res/Roboto-Regular.ttf");
		self.data.be.load_font("font-awesome", "res/fontawesome-webfont.ttf");
		self.data.be.load_font("sans-bold", "res/Roboto-Bold.ttf");

		while !self.window.is_closed() {
			use glutin::Event::*;

			let event = match self.window.wait_events().next(){
				Some(e) => e,
				None => break
			};

			match event{
				Resized(w, h) => {//handle resizes
					self.size.0 = w as i32;
					self.size.1 = h as i32;
					self.redraw = true;
					unsafe{//make sure resize does'n result in stretching and displacement
						gl::Viewport(0, 0, self.size.0, self.size.1);
					}
				},
				MouseMoved((x,y)) => {
					self.data.mouse_pos = (x as f32, y as f32);
				},
				MouseInput(..) | ReceivedCharacter(..) | MouseWheel(..) => {
					self.data.event = event;
					let mut c:EventContext<NanovgBackend, W> = EventContext::new(&mut self.data);
					self.root.render(&mut c, state);
					for e in c.emited{
						state.handle(e);
						self.redraw = true;
					}
				},
				Refresh => { self.redraw = true; },
				//_ => ()
			}

			self.data.be.reset_transform();
			if self.redraw{
				self.ps();
				{
					let mut c:DrawContext<NanovgBackend, W> =
						DrawContext::new(&mut self.data);
					self.root.render(&mut c, state);
				}
				//println!("draw ({}, {})", self.size.0, self.size.1);
				self.redraw = false;

				if self.begun{
					self.data.be.end();
					self.data.be.reset_transform();
					self.window.swap_buffers();
					self.begun = false;
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>//! This crate provides a couple of iterator adapters for deduplication of elements from a source iterator, inspired by the dedup methods
//! in `Vec`.
//!
//! # `dedup`
//! The `DedupAdapter` is an iterator adapter that removes consecutive repeated elements from the source iterator.
//! The `dedup` trait method returns a `Dedup` iterator struct.
//! ## Example
//! ```rust
//! use dedup_iter::DedupAdapter;
//!
//! assert_eq!("abcdefe", "aabbccdddeeeeffffeee".chars().dedup().collect::<String>());
//! ```
//!
//! # `dedup_by`
//! The `DedupByAdapter` is an iterator adapter that removes consecutive repeated elements from the source iterator
//! using a function to determine equality.
//! The `dedup_by` trait method returns a `DedupBy` iterator struct.
//! ## Examples
//! ```rust
//! use std::ascii::AsciiExt;
//! use dedup_iter::DedupByAdapter;
//!
//! assert_eq!(
//!        "This string had way too much redundant whitespace!",
//!        "This  string   had      way too     much redundant \n whitespace!".chars()
//!         .dedup_by(|a, b| a.is_whitespace() && b.is_whitespace() )
//!         .collect::<String>()
//!        );
//! ```

//! # `dedup_by_key`
//! The `DedupByKeyAdapter` is an iterator adapter that removes consecutive repeated elements from the source iterator
//! using a key to determine equality.
//! The `dedup_by_key` trait method returns a `DedupByKey` iterator struct.
//! ## Examples
//! ```rust
//! use dedup_iter::DedupByKeyAdapter;
//!
//! assert_eq!(
//!        "abcdefe",
//!        "aabbccdddeeeeffffeee".chars()
//!         .dedup_by_key(|a| *a as usize)
//!         .collect::<String>()
//!        );
//! ```

/// An iterator that removes elements that are the same as previous one.
///
/// This struct is created by the `dedup` method of trait `DedupAdapter`, implemented on Iterator.
/// To use the `dedup` method, `use dedup_iter::DedupAdapter`.
pub struct Dedup<I, T> {
    iter: I,
    current_item: Option<T>,
}

/// An iterator that removes elements that are the same as previous one, according the provided function.
///
/// This struct is created by the `dedup_by` method of trait `DedupByAdapter`, implemented on Iterator.
/// To use the `dedup_by` method, `use dedup_iter::DedupByAdapter`.
pub struct DedupBy<I, F, T> {
    iter: I,
    current_item: Option<T>,
    same_bucket: F,
}

/// An iterator that removes elements that have a key that is the same as the key of previous element.
/// The client provided function computes the key.
///
/// This struct is created by the `dedup_by_key` method of trait `DedupByKeyAdapter`, implemented on Iterator.
/// To use the `dedup_by_key` method, `use dedup_iter::DedupByKeyAdapter`.
pub struct DedupByKey<I, F, K> {
    iter: I,
    current_key: Option<K>,
    key: F,
}

impl<I, T> Iterator for Dedup<I, T>
where
    I: Iterator<Item = T>,
    T: PartialEq + Clone,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<I::Item> {
        for x in self.iter.by_ref() {
            let item = Some(x.clone());
            if self.current_item != item {
                self.current_item = item;
                return Some(x);
            }
        }
        None
    }
}

impl<I, F, T> Iterator for DedupBy<I, F, T>
where
    I: Iterator<Item = T>,
    T: Clone,
    F: Fn(&T, &T) -> bool,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<I::Item> {
        for x in self.iter.by_ref() {
            let item = Some(x.clone());
            let different = match self.current_item {
                None => true,
                Some(ref current_item) => !(self.same_bucket)(current_item, &x),
            };
            if different {
                self.current_item = item;
                return Some(x);
            }
        }
        None
    }
}

impl<I, F, K> Iterator for DedupByKey<I, F, K>
where
    I: Iterator,
    F: Fn(&I::Item) -> K,
    K: PartialEq,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<I::Item> {
        for x in self.iter.by_ref() {
            let key = (self.key)(&x);
            let different = match self.current_key {
                None => true,
                Some(ref current_key) => key != *current_key,
            };
            if different {
                self.current_key = Some(key);
                return Some(x);
            }
        }
        None
    }
}

/// Provides the `dedup` method on `Iterator`s.
pub trait DedupAdapter: Iterator {
    fn dedup(self) -> Dedup<Self, Self::Item>
    where
        Self: Sized,
    {
        Dedup {
            iter: self,
            current_item: None,
        }
    }
}

/// Provides the `dedup_by` method on `Iterator`s.
pub trait DedupByAdapter<F>: Iterator {
    fn dedup_by(self, same_bucket: F) -> DedupBy<Self, F, Self::Item>
    where
        Self: Sized,
        F: Fn(&Self::Item, &Self::Item) -> bool,
    {
        DedupBy {
            iter: self,
            current_item: None,
            same_bucket: same_bucket,
        }

    }
}

/// Provides the `dedup_by_key` method on `Iterator`s.
pub trait DedupByKeyAdapter<F, K>: Iterator {
    fn dedup_by_key(self, key: F) -> DedupByKey<Self, F, K>
    where
        Self: Sized,
        F: Fn(&Self::Item) -> K,
    {
        DedupByKey {
            iter: self,
            current_key: None,
            key: key,
        }

    }
}

impl<I> DedupAdapter for I
where
    I: Iterator,
{
}

impl<I, F> DedupByAdapter<F> for I
where
    I: Iterator,
{
}

impl<I, F, K> DedupByKeyAdapter<F, K> for I
where
    I: Iterator,
{
}

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

    #[test]
    fn remove_duplicate_chars() {
        let t = "Thiss sisssssling ssstring";
        let v = t.chars().dedup().collect::<String>();
        assert_eq!(&v, "This sisling string");
    }

    #[test]
    fn remove_duplicate_whitespace() {
        let t = "Hierr zzitt ikk    well      goedd!";
        let v = t.chars()
            .dedup_by(|a, b| a.is_whitespace() && b.is_whitespace())
            .collect::<String>();
        assert_eq!(&v, "Hierr zzitt ikk well goedd!");
    }

    #[test]
    fn almost_acronym() {
        let t = "First In, Last Out";
        let v = t.chars()
            .dedup_by_key(|a| a.is_whitespace())
            .collect::<String>();
        assert_eq!(&v, "F I L O");
    }

    #[test]
    fn dedup_iter_empty() {
        let t = Vec::<u8>::new();
        let c = t.iter().dedup().count();
        assert_eq!(c, 0);
    }

    #[test]
    fn dedup_iter_numbers() {
        let t = vec![10, 20, 20, 21, 30, 20];
        let v = t.iter().dedup().collect::<Vec<_>>();
        assert_eq!(v, vec![&10, &20, &21, &30, &20]);
    }

    #[test]
    fn dedup_by_eq() {
        let t = "Hierr zzitt ikk    well      goedd!";
        let v = t.chars().dedup_by(|a, b| *a == *b).collect::<String>();
        assert_eq!(&v, "Hier zit ik wel goed!");
    }

    #[test]
    fn dedup_by_key() {
        #[derive(Debug, PartialEq)]
        struct Person<'a> {
            id: u64,
            name: &'a str,
        };
        let t = vec![
            Person {
                id: 0,
                name: "Bilbo",
            },
            Person {
                id: 0,
                name: "Bilbo",
            },
        ];
        let v = t.iter()
            .dedup_by_key(|person| person.id)
            .collect::<Vec<_>>();
        assert_eq!(
            v,
            vec![
                &Person {
                    id: 0,
                    name: "Bilbo",
                },
            ]
        );
    }

    #[test]
    fn dedup_by_always_same() {
        let t = "abdefghijklmopqrstuvwxyz";
        let v = t.chars().dedup_by(|_, _| true).collect::<String>();
        assert_eq!(&v, "a");
    }

    #[test]
    fn dedup_by_key_always_same() {
        let t = "abdefghijklmopqrstuvwxyz";
        let v = t.chars().dedup_by_key(|_| 0).collect::<String>();
        assert_eq!(&v, "a");
    }
}
<commit_msg>Replace T by I::Item<commit_after>//! This crate provides a couple of iterator adapters for deduplication of elements from a source iterator, inspired by the dedup methods
//! in `Vec`.
//!
//! # `dedup`
//! The `DedupAdapter` is an iterator adapter that removes consecutive repeated elements from the source iterator.
//! The `dedup` trait method returns a `Dedup` iterator struct.
//! ## Example
//! ```rust
//! use dedup_iter::DedupAdapter;
//!
//! assert_eq!("abcdefe", "aabbccdddeeeeffffeee".chars().dedup().collect::<String>());
//! ```
//!
//! # `dedup_by`
//! The `DedupByAdapter` is an iterator adapter that removes consecutive repeated elements from the source iterator
//! using a function to determine equality.
//! The `dedup_by` trait method returns a `DedupBy` iterator struct.
//! ## Examples
//! ```rust
//! use std::ascii::AsciiExt;
//! use dedup_iter::DedupByAdapter;
//!
//! assert_eq!(
//!        "This string had way too much redundant whitespace!",
//!        "This  string   had      way too     much redundant \n whitespace!".chars()
//!         .dedup_by(|a, b| a.is_whitespace() && b.is_whitespace() )
//!         .collect::<String>()
//!        );
//! ```

//! # `dedup_by_key`
//! The `DedupByKeyAdapter` is an iterator adapter that removes consecutive repeated elements from the source iterator
//! using a key to determine equality.
//! The `dedup_by_key` trait method returns a `DedupByKey` iterator struct.
//! ## Examples
//! ```rust
//! use dedup_iter::DedupByKeyAdapter;
//!
//! assert_eq!(
//!        "abcdefe",
//!        "aabbccdddeeeeffffeee".chars()
//!         .dedup_by_key(|a| *a as usize)
//!         .collect::<String>()
//!        );
//! ```

/// An iterator that removes elements that are the same as previous one.
///
/// This struct is created by the `dedup` method of trait `DedupAdapter`, implemented on Iterator.
/// To use the `dedup` method, `use dedup_iter::DedupAdapter`.
pub struct Dedup<I>
where
    I: Iterator,
{
    iter: I,
    current_item: Option<I::Item>,
}

/// An iterator that removes elements that are the same as previous one, according the provided function.
///
/// This struct is created by the `dedup_by` method of trait `DedupByAdapter`, implemented on Iterator.
/// To use the `dedup_by` method, `use dedup_iter::DedupByAdapter`.
pub struct DedupBy<I, F>
where
    I: Iterator,
{
    iter: I,
    current_item: Option<I::Item>,
    same_bucket: F,
}

/// An iterator that removes elements that have a key that is the same as the key of previous element.
/// The client provided function computes the key.
///
/// This struct is created by the `dedup_by_key` method of trait `DedupByKeyAdapter`, implemented on Iterator.
/// To use the `dedup_by_key` method, `use dedup_iter::DedupByKeyAdapter`.
pub struct DedupByKey<I, F, K> {
    iter: I,
    current_key: Option<K>,
    key: F,
}

impl<I> Iterator for Dedup<I>
where
    I: Iterator,
    I::Item: PartialEq + Clone,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<I::Item> {
        for x in self.iter.by_ref() {
            let item = Some(x.clone());
            if self.current_item != item {
                self.current_item = item;
                return Some(x);
            }
        }
        None
    }
}

impl<I, F> Iterator for DedupBy<I, F>
where
    I: Iterator,
    I::Item: Clone,
    F: Fn(&I::Item, &I::Item) -> bool,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<I::Item> {
        for x in self.iter.by_ref() {
            let item = Some(x.clone());
            let different = match self.current_item {
                None => true,
                Some(ref current_item) => !(self.same_bucket)(current_item, &x),
            };
            if different {
                self.current_item = item;
                return Some(x);
            }
        }
        None
    }
}

impl<I, F, K> Iterator for DedupByKey<I, F, K>
where
    I: Iterator,
    F: Fn(&I::Item) -> K,
    K: PartialEq,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<I::Item> {
        for x in self.iter.by_ref() {
            let key = (self.key)(&x);
            let different = match self.current_key {
                None => true,
                Some(ref current_key) => key != *current_key,
            };
            if different {
                self.current_key = Some(key);
                return Some(x);
            }
        }
        None
    }
}

/// Provides the `dedup` method on `Iterator`s.
pub trait DedupAdapter: Iterator {
    fn dedup(self) -> Dedup<Self>
    where
        Self: Sized,
    {
        Dedup {
            iter: self,
            current_item: None,
        }
    }
}

/// Provides the `dedup_by` method on `Iterator`s.
pub trait DedupByAdapter<F>: Iterator {
    fn dedup_by(self, same_bucket: F) -> DedupBy<Self, F>
    where
        Self: Sized,
        F: Fn(&Self::Item, &Self::Item) -> bool,
    {
        DedupBy {
            iter: self,
            current_item: None,
            same_bucket: same_bucket,
        }

    }
}

/// Provides the `dedup_by_key` method on `Iterator`s.
pub trait DedupByKeyAdapter<F, K>: Iterator {
    fn dedup_by_key(self, key: F) -> DedupByKey<Self, F, K>
    where
        Self: Sized,
        F: Fn(&Self::Item) -> K,
    {
        DedupByKey {
            iter: self,
            current_key: None,
            key: key,
        }

    }
}

impl<I> DedupAdapter for I
where
    I: Iterator,
{
}

impl<I, F> DedupByAdapter<F> for I
where
    I: Iterator,
{
}

impl<I, F, K> DedupByKeyAdapter<F, K> for I
where
    I: Iterator,
{
}

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

    #[test]
    fn remove_duplicate_chars() {
        let t = "Thiss sisssssling ssstring";
        let v = t.chars().dedup().collect::<String>();
        assert_eq!(&v, "This sisling string");
    }

    #[test]
    fn remove_duplicate_whitespace() {
        let t = "Hierr zzitt ikk    well      goedd!";
        let v = t.chars()
            .dedup_by(|a, b| a.is_whitespace() && b.is_whitespace())
            .collect::<String>();
        assert_eq!(&v, "Hierr zzitt ikk well goedd!");
    }

    #[test]
    fn almost_acronym() {
        let t = "First In, Last Out";
        let v = t.chars()
            .dedup_by_key(|a| a.is_whitespace())
            .collect::<String>();
        assert_eq!(&v, "F I L O");
    }

    #[test]
    fn dedup_iter_empty() {
        let t = Vec::<u8>::new();
        let c = t.iter().dedup().count();
        assert_eq!(c, 0);
    }

    #[test]
    fn dedup_iter_numbers() {
        let t = vec![10, 20, 20, 21, 30, 20];
        let v = t.iter().dedup().collect::<Vec<_>>();
        assert_eq!(v, vec![&10, &20, &21, &30, &20]);
    }

    #[test]
    fn dedup_by_eq() {
        let t = "Hierr zzitt ikk    well      goedd!";
        let v = t.chars().dedup_by(|a, b| *a == *b).collect::<String>();
        assert_eq!(&v, "Hier zit ik wel goed!");
    }

    #[test]
    fn dedup_by_key() {
        #[derive(Debug, PartialEq)]
        struct Person<'a> {
            id: u64,
            name: &'a str,
        };
        let t = vec![
            Person {
                id: 0,
                name: "Bilbo",
            },
            Person {
                id: 0,
                name: "Bilbo",
            },
        ];
        let v = t.iter()
            .dedup_by_key(|person| person.id)
            .collect::<Vec<_>>();
        assert_eq!(
            v,
            vec![
                &Person {
                    id: 0,
                    name: "Bilbo",
                },
            ]
        );
    }

    #[test]
    fn dedup_by_always_same() {
        let t = "abdefghijklmopqrstuvwxyz";
        let v = t.chars().dedup_by(|_, _| true).collect::<String>();
        assert_eq!(&v, "a");
    }

    #[test]
    fn dedup_by_key_always_same() {
        let t = "abdefghijklmopqrstuvwxyz";
        let v = t.chars().dedup_by_key(|_| 0).collect::<String>();
        assert_eq!(&v, "a");
    }
}
<|endoftext|>


<commit_before>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 * */

#[macro_use]
extern crate log;
extern crate futures;
extern crate tokio_proto;
extern crate tokio_service;
extern crate httbloat;
extern crate cookie;
extern crate urlencoded;
extern crate multipart;

mod handler;
mod request;
mod response;

pub use handler::Handler;
pub use httbloat::Method;
pub use httbloat::Status;
pub use httbloat::Header;
pub use response::Response;
pub use request::Request;

use futures::{Finished, finished};
use tokio_proto::TcpServer;
use tokio_service::Service;

use std::net::SocketAddr;
use std::io;
use std::sync::Arc;

// TODO(nokaa): We probably want to enforce the Clone trait bound on `T`
// here. We can't do this until https://github.com/rust-lang/rust/issues/21903
// is resovled. This shouldn't be a problem because when we use this type we
// are constraining `T` to be Clone.
pub type RequestHandler<T> = Arc<(Fn(&Request, &mut Response, &T)) + Send + Sync>;

#[derive(Clone)]
pub struct Http<T: Clone + Send, H: Clone + Send + Handler<T>> {
    handler: H,
    context: T,
    sanitize_input: bool,
    num_threads: usize,
}

impl<T: 'static + Clone + Send, H: 'static + Clone + Send + Handler<T>> Service for Http<T, H> {
    type Request = httbloat::Request;
    type Response = httbloat::Response;
    type Error = io::Error;
    type Future = Finished<Self::Response, Self::Error>;

    fn call(&self, req: httbloat::Request) -> Self::Future {
        // We declare these variables here to satisfy lifetime requirements.
        // Note that as these are both Rc (smart pointers) we can clone them
        // without issue.
        let handler = self.handler.clone();
        let context = self.context.clone();
        let sanitize = self.sanitize_input;
        let req = Request::new(req, sanitize);

        finished({
            let mut res = Response::new();
            handler.handler(&req, &mut res, &context);
            res.into_httbloat_response()
        })
    }
}

impl<T: 'static + Clone + Send + Sync, H: 'static + Clone + Send + Sync + Handler<T>> Http<T, H> {
    /// Create a new Http handler
    pub fn new(handler: H, context: T) -> Self {
        Http {
            handler: handler,
            context: context,
            sanitize_input: false,
            num_threads: 1,
        }
    }

    /// Calling this method will cause form data to be HTML-escaped
    /// when parsed.
    pub fn sanitize(&mut self) -> &mut Self {
        self.sanitize_input = true;
        self
    }

    /// Sets the number of event loops to run
    pub fn threads(&mut self, threads: usize) -> &mut Self {
        self.num_threads = threads;
        self
    }

    /// Run the server
    pub fn listen_and_serve(self, addr: SocketAddr) {
        let mut srv = TcpServer::new(httbloat::Http, addr);
        srv.threads(self.num_threads);
        srv.serve(move || Ok(self.clone()));
    }
}
<commit_msg>Update for Service::call api change<commit_after>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 * */

#[macro_use]
extern crate log;
extern crate futures;
extern crate tokio_proto;
extern crate tokio_service;
extern crate httbloat;
extern crate cookie;
extern crate urlencoded;
extern crate multipart;

mod handler;
mod request;
mod response;

pub use handler::Handler;
pub use httbloat::Method;
pub use httbloat::Status;
pub use httbloat::Header;
pub use response::Response;
pub use request::Request;

use futures::{Finished, finished};
use tokio_proto::TcpServer;
use tokio_service::Service;

use std::net::SocketAddr;
use std::io;
use std::sync::Arc;

// TODO(nokaa): We probably want to enforce the Clone trait bound on `T`
// here. We can't do this until https://github.com/rust-lang/rust/issues/21903
// is resovled. This shouldn't be a problem because when we use this type we
// are constraining `T` to be Clone.
pub type RequestHandler<T> = Arc<(Fn(&Request, &mut Response, &T)) + Send + Sync>;

#[derive(Clone)]
pub struct Http<T: Clone + Send, H: Clone + Send + Handler<T>> {
    handler: H,
    context: T,
    sanitize_input: bool,
    num_threads: usize,
}

impl<T: 'static + Clone + Send, H: 'static + Clone + Send + Handler<T>> Service for Http<T, H> {
    type Request = httbloat::Request;
    type Response = httbloat::Response;
    type Error = io::Error;
    type Future = Finished<Self::Response, Self::Error>;

    fn call(&mut self, req: httbloat::Request) -> Self::Future {
        // We declare these variables here to satisfy lifetime requirements.
        // Note that as these are both Rc (smart pointers) we can clone them
        // without issue.
        let handler = self.handler.clone();
        let context = self.context.clone();
        let sanitize = self.sanitize_input;
        let req = Request::new(req, sanitize);

        finished({
            let mut res = Response::new();
            handler.handler(&req, &mut res, &context);
            res.into_httbloat_response()
        })
    }
}

impl<T: 'static + Clone + Send + Sync, H: 'static + Clone + Send + Sync + Handler<T>> Http<T, H> {
    /// Create a new Http handler
    pub fn new(handler: H, context: T) -> Self {
        Http {
            handler: handler,
            context: context,
            sanitize_input: false,
            num_threads: 1,
        }
    }

    /// Calling this method will cause form data to be HTML-escaped
    /// when parsed.
    pub fn sanitize(&mut self) -> &mut Self {
        self.sanitize_input = true;
        self
    }

    /// Sets the number of event loops to run
    pub fn threads(&mut self, threads: usize) -> &mut Self {
        self.num_threads = threads;
        self
    }

    /// Run the server
    pub fn listen_and_serve(self, addr: SocketAddr) {
        let mut srv = TcpServer::new(httbloat::Http, addr);
        srv.threads(self.num_threads);
        srv.serve(move || Ok(self.clone()));
    }
}
<|endoftext|>


<commit_before>// 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. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Message Format
//!
//! A [`Message`] is a piece of user-visible text that typically has
//! variable elements.
//!
//! This crate provides [ICU-style message formatting]. This provides
//! for formatting values taking localization rules into account. ICU
//! Message Format is widely supported in many languages and environments.
//! This library will endeavor to support all of the ICU Message Format
//! with the exception of the deprecated `ChoiceFormat`.
//!
//! [`Message`]: struct.Message.html
//! [ICU-style message formatting]: http://userguide.icu-project.org/formatparse/messages

#![warn(missing_docs)]
#![deny(trivial_numeric_casts,
        unsafe_code, unstable_features,
        unused_import_braces, unused_qualifications)]

#[macro_use]
extern crate nom;

use std::fmt;

pub mod ast;
mod args;
mod parse_message;

use ast::Format;
pub use self::args::{arg, Args};
pub use self::parse_message::parse_message;

/// A message that has been localized and can be formatted in a
/// locale-aware manner.
pub struct Message {
    parts: Vec<Box<Format>>,
}

impl Message {
    /// Construct a message from constituent parts.
    pub fn new(parts: Vec<Box<Format>>) -> Self {
        Message { parts: parts }
    }

    /// Format a message to a stream.
    pub fn format_message<'f>(&'f self,
                              stream: &mut fmt::Write,
                              args: &'f Args<'f>)
                              -> fmt::Result {
        for part in &self.parts {
            try!(part.apply_format(stream, args));
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>Add basic test of message.<commit_after>// 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. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Message Format
//!
//! A [`Message`] is a piece of user-visible text that typically has
//! variable elements.
//!
//! This crate provides [ICU-style message formatting]. This provides
//! for formatting values taking localization rules into account. ICU
//! Message Format is widely supported in many languages and environments.
//! This library will endeavor to support all of the ICU Message Format
//! with the exception of the deprecated `ChoiceFormat`.
//!
//! [`Message`]: struct.Message.html
//! [ICU-style message formatting]: http://userguide.icu-project.org/formatparse/messages

#![warn(missing_docs)]
#![deny(trivial_numeric_casts,
        unsafe_code, unstable_features,
        unused_import_braces, unused_qualifications)]

#[macro_use]
extern crate nom;

use std::fmt;

pub mod ast;
mod args;
mod parse_message;

use ast::Format;
pub use self::args::{arg, Args};
pub use self::parse_message::parse_message;

/// A message that has been localized and can be formatted in a
/// locale-aware manner.
pub struct Message {
    parts: Vec<Box<Format>>,
}

impl Message {
    /// Construct a message from constituent parts.
    pub fn new(parts: Vec<Box<Format>>) -> Self {
        Message { parts: parts }
    }

    /// Format a message to a stream.
    pub fn format_message<'f>(&'f self,
                              stream: &mut fmt::Write,
                              args: &'f Args<'f>)
                              -> fmt::Result {
        for part in &self.parts {
            try!(part.apply_format(stream, args));
        }
        Ok(())
    }
}

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

    #[test]
    fn it_works() {
        let m = Message::new(vec![Box::new(ast::SimpleFormat::new("name")),
                                  Box::new(ast::PlainText::new(" went to ")),
                                  Box::new(ast::SimpleFormat::new("place")),
                                  Box::new(ast::PlainText::new("."))]);
        let mut output = String::new();
        m.format_message(&mut output,
                            &arg("name", &"Jacob").arg("place", &"the store"))
            .unwrap();
        assert_eq!(output, "Jacob went to the store.".to_string());
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_char, c_int, c_void};

#[repr(C)]
#[derive(Copy)]
pub struct PamHandle;

#[repr(C)]
#[derive(Copy)]
pub struct PamConv {
    pub conv: *const c_void,
    pub data_ptr: *mut c_void
}

extern "C" {
    /* --------------             pam_appl.h            ------------- */
    /* -------------- The Linux-PAM Framework layer API ------------- */

    pub fn pam_start(service_name: *const c_char, user: *const c_char,
        pam_conversation: *const PamConv, pamh: *const *mut PamHandle) -> c_int;

    pub fn pam_end(pamh: *mut PamHandle, pam_status: c_int) -> c_int;

    /* Authentication API's */
    pub fn pam_authenticate(pamh: *mut PamHandle, flags: c_int) -> c_int;

    pub fn pam_setcred(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Account Management API's */
    pub fn pam_acct_mgmt(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Session Management API's */
    pub fn pam_open_session(pamh: *mut PamHandle, flags: c_int) -> c_int;

    pub fn pam_close_session(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Password Management API's */
    pub fn pam_chauthtok(pamh: *mut PamHandle, flags: c_int) -> c_int;
}
<commit_msg>Test signature change<commit_after>extern crate libc;

use libc::{c_char, c_int, c_void};

#[repr(C)]
#[derive(Copy)]
pub struct PamHandle;

#[repr(C)]
#[derive(Copy)]
pub struct PamConv {
    pub conv: *const c_void,
    pub data_ptr: *mut c_void
}

extern "C" {
    /* --------------             pam_appl.h            ------------- */
    /* -------------- The Linux-PAM Framework layer API ------------- */

    pub fn pam_start(service_name: *const c_char, user: *const c_char,
        pam_conversation: *const PamConv, pamh: *mut *const PamHandle) -> c_int;

    pub fn pam_end(pamh: *mut PamHandle, pam_status: c_int) -> c_int;

    /* Authentication API's */
    pub fn pam_authenticate(pamh: *mut PamHandle, flags: c_int) -> c_int;

    pub fn pam_setcred(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Account Management API's */
    pub fn pam_acct_mgmt(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Session Management API's */
    pub fn pam_open_session(pamh: *mut PamHandle, flags: c_int) -> c_int;

    pub fn pam_close_session(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Password Management API's */
    pub fn pam_chauthtok(pamh: *mut PamHandle, flags: c_int) -> c_int;
}
<|endoftext|>


<commit_before>#![feature(libc)]
#![feature(plugin)]
#![feature(alloc)]

#![allow(dead_code)]
#![allow(unused_imports)]

extern crate libc;
#[macro_use] extern crate bitflags;

mod nginx;

use std::ffi::CString;
use std::ptr;
use std::mem;
use std::boxed;

use nginx::ffi::{
   ngx_str_t, ngx_http_request_t, ngx_pcalloc, ngx_palloc, ngx_conf_t, ngx_command_t, ngx_http_core_module,
   ngx_http_conf_ctx_t, ngx_int_t, ngx_http_output_filter, ngx_chain_t, ngx_http_send_header, ngx_buf_t,
   ngx_uint_t, ngx_http_core_loc_conf_t, ngx_log_error_core,
};

use libc::{size_t, c_void, c_uchar, c_char};

const NGX_CONF_OK: *const c_void = 0 as *const c_void;
const NGX_CONF_ERROR: *const c_void = -1 as *const c_void;

const NGX_OK:        ngx_int_t =  0;
const NGX_ERROR:     ngx_int_t = -1;
const NGX_AGAIN:     ngx_int_t = -2;
const NGX_BUSY:      ngx_int_t = -3;
const NGX_DONE:      ngx_int_t = -4;
const NGX_DECLINED:  ngx_int_t = -5;
const NGX_ABORT:     ngx_int_t = -6;

const NGX_HTTP_OK:                      ngx_uint_t = 200;
const NGX_HTTP_INTERNAL_SERVER_ERROR:   ngx_uint_t = 500;

macro_rules! ngx_http_conf_get_module_loc_conf {
   ($cf:expr, $module:expr) => ({
      (*
         (
            (*
               (
                  (*$cf).ctx as *mut ngx_http_conf_ctx_t
               )
            ).loc_conf
         ).offset($module.ctx_index as isize)
      ) as *mut ngx_http_core_loc_conf_t
   })
}

macro_rules! ngx_alloc_buf {
   ($pool:expr) => (
      ngx_palloc($pool, mem::size_of::<ngx_buf_t>() as u64)
   )
}

macro_rules! ngx_calloc_buf {
   ($pool:expr) => (
      ngx_pcalloc($pool, mem::size_of::<ngx_buf_t>() as u64)
   )
}

bitflags! {
    flags BufFlags: u32 {
        const FLAG_TEMPORARY        = 0b0000000000000001,
        const FLAG_MEMORY           = 0b0000000000000010,
        const FLAG_MMAP             = 0b0000000000000100,
        const FLAG_RECYCLED         = 0b0000000000001000,
        const FLAG_IN_FILE          = 0b0000000000010000,
        const FLAG_FLUSH            = 0b0000000000100000,
        const FLAG_SYNC             = 0b0000000001000000,
        const FLAG_LAST_BUF         = 0b0000000010000000,
        const FLAG_LAST_IN_CHAIN    = 0b0000000100000000,
        const FLAG_LAST_SHADOW      = 0b0000001000000000,
        const FLAG_TEMP_FILE        = 0b0000010000000000,
    }
}

#[no_mangle]
pub extern fn ngx_http_sample_module_command(
   cf: *mut ngx_conf_t,
   cmd: *mut ngx_command_t,
   conf: *mut c_void
) -> *mut c_char {
   //ngx_http_core_loc_conf_t  *clcf;

   unsafe {
      let clcf = ngx_http_conf_get_module_loc_conf!(cf, ngx_http_core_module);
      (*clcf).handler = Some(ngx_http_sample_handler);
   }

   NGX_CONF_OK as *mut c_char
}

#[no_mangle]
pub extern fn ngx_http_sample_handler(r: *mut ngx_http_request_t) -> ngx_int_t
{
   unsafe {
      let log = (*(*r).connection).log;

      let ngx_http_sample_text: ngx_str_t = sample_text_from_rust(r);

      (*r).headers_out.status = NGX_HTTP_OK;
      (*r).headers_out.content_length_n = ngx_http_sample_text.len as i64;

      let rc: ngx_int_t = ngx_http_send_header(r);
      if rc == NGX_ERROR || rc > NGX_OK { //|| (*r).header_only) {
         return rc;
      }

      let b: *mut ngx_buf_t = ngx_calloc_buf!((*r).pool) as *mut ngx_buf_t;

      if b.is_null() {
         return NGX_HTTP_INTERNAL_SERVER_ERROR as i64;
      };

      let out: Box<ngx_chain_t> = Box::new(
         ngx_chain_t {
            buf: b,
            next: ptr::null_mut(),
         }
      );

      let headers_in = (*r).headers_in;

      let cstr_template = CString::new("BITS: \"%s\"").unwrap();
      let b1 = CString::new(format!("{:032b}", headers_in._bindgen_bitfield_1_)).unwrap();

      ngx_log_error_core(
         2, log, 0,
         cstr_template.as_ptr(),
         b1.as_ptr()
      );

      let out: *mut ngx_chain_t = boxed::into_raw(out);

      (*b).start = ngx_http_sample_text.data;
      (*b).pos = (*b).start;

      (*b).end = ngx_http_sample_text.data.offset(ngx_http_sample_text.len as isize);
      (*b).last = (*b).end;

      let buf_flags = FLAG_MEMORY | FLAG_LAST_BUF | FLAG_LAST_IN_CHAIN;
      (*b)._bindgen_bitfield_1_ = buf_flags.bits();

      ngx_http_output_filter(r, out)
   }
}

fn sample_text_from_rust(r: *mut ngx_http_request_t) -> ngx_str_t
{
   let s = CString::new("<meta charset=\"utf-8\">Здравейте!".to_string()).unwrap();
   let len = s.to_bytes().len() as size_t;

   let result = ngx_str_t {
      len: len,
      data: unsafe {
         ngx_pcalloc((*r).pool, len) as *mut u8
      },
   };

   unsafe {
      ptr::copy_nonoverlapping(result.data, s.as_ptr() as *const u8, len as usize);
   }

   result
}

#[no_mangle]
pub extern fn dump_request(r: *mut ngx_http_request_t) {
   unsafe {
      let log = (*(*r).connection).log;

      let template = "REQ: \
         method=\"%ud\" \
         http_version=\"%ud\" \
         request_line=\"%V\" \
         uri=\"%V\" \
         args=\"%V\" \
         exten=\"%V\" \
         unparsed_uri=\"%V\" \
         method_name=\"%V\" \
         http_protocol=\"%V\" \
         bit1=\"%s\" \
         bit2=\"%s\" \
         bit3=\"%s\" \
         bit4=\"%s\" \
         bits=\"%s\" \
      ";
      let cstr_template = CString::new(template).unwrap();

      let b1 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_1_)).unwrap();
      let b2 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_2_)).unwrap();
      let b3 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_3_)).unwrap();
      let b4 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_4_)).unwrap();

      let buf_flags = FLAG_MEMORY | FLAG_LAST_BUF | FLAG_LAST_IN_CHAIN;
      let bits = CString::new(format!("{:032b}", buf_flags.bits())).unwrap();

      ngx_log_error_core(
         2, log, 0,
         cstr_template.as_ptr(),
         (*r).method,
         (*r).http_version,
         &((*r).request_line),
         &((*r).uri),
         &((*r).args),
         &((*r).exten),
         &((*r).unparsed_uri),
         &((*r).method_name),
         &((*r).http_protocol),
         b1.as_ptr(),
         b2.as_ptr(),
         b3.as_ptr(),
         b4.as_ptr(),
         bits.as_ptr(),
      );
   }
}

#[no_mangle]
pub extern fn dump_buffer(r: *mut ngx_http_request_t, b: *mut ngx_buf_t) {
   unsafe {
      let log = (*(*r).connection).log;

      let template = "BUF: \
         pos=\"%p\" \
         last=\"%p\" \
         start=\"%p\" \
         end=\"%p\" \
         num=\"%d\" \
         bit1=\"%s\" \
      ";
      let cstr_template = CString::new(template).unwrap();

      let b1 = CString::new(format!("{:064b}", (*b)._bindgen_bitfield_1_)).unwrap();

      ngx_log_error_core(
         2, log, 0,
         cstr_template.as_ptr(),
         (*b).pos,
         (*b).last,
         (*b).start,
         (*b).end,
         (*b).num,
         b1.as_ptr(),
      );
   }
}
<commit_msg>Simplifying module config setting function return values.<commit_after>#![feature(libc)]
#![feature(plugin)]
#![feature(alloc)]

#![allow(dead_code)]
#![allow(unused_imports)]

extern crate libc;
#[macro_use] extern crate bitflags;

mod nginx;

use std::ffi::CString;
use std::ptr;
use std::mem;
use std::boxed;

use nginx::ffi::{
   ngx_str_t, ngx_http_request_t, ngx_pcalloc, ngx_palloc, ngx_conf_t, ngx_command_t, ngx_http_core_module,
   ngx_http_conf_ctx_t, ngx_int_t, ngx_http_output_filter, ngx_chain_t, ngx_http_send_header, ngx_buf_t,
   ngx_uint_t, ngx_http_core_loc_conf_t, ngx_log_error_core,
};

use libc::{size_t, c_void, c_uchar, c_char};

const NGX_CONF_OK: *const c_char = 0 as *const c_char;
const NGX_CONF_ERROR: *const c_char = -1 as *const c_char;

const NGX_OK:        ngx_int_t =  0;
const NGX_ERROR:     ngx_int_t = -1;
const NGX_AGAIN:     ngx_int_t = -2;
const NGX_BUSY:      ngx_int_t = -3;
const NGX_DONE:      ngx_int_t = -4;
const NGX_DECLINED:  ngx_int_t = -5;
const NGX_ABORT:     ngx_int_t = -6;

const NGX_HTTP_OK:                      ngx_uint_t = 200;
const NGX_HTTP_INTERNAL_SERVER_ERROR:   ngx_uint_t = 500;

macro_rules! ngx_http_conf_get_module_loc_conf {
   ($cf:expr, $module:expr) => ({
      (*
         (
            (*
               (
                  (*$cf).ctx as *mut ngx_http_conf_ctx_t
               )
            ).loc_conf
         ).offset($module.ctx_index as isize)
      ) as *mut ngx_http_core_loc_conf_t
   })
}

macro_rules! ngx_alloc_buf {
   ($pool:expr) => (
      ngx_palloc($pool, mem::size_of::<ngx_buf_t>() as u64)
   )
}

macro_rules! ngx_calloc_buf {
   ($pool:expr) => (
      ngx_pcalloc($pool, mem::size_of::<ngx_buf_t>() as u64)
   )
}

bitflags! {
    flags BufFlags: u32 {
        const FLAG_TEMPORARY        = 0b0000000000000001,
        const FLAG_MEMORY           = 0b0000000000000010,
        const FLAG_MMAP             = 0b0000000000000100,
        const FLAG_RECYCLED         = 0b0000000000001000,
        const FLAG_IN_FILE          = 0b0000000000010000,
        const FLAG_FLUSH            = 0b0000000000100000,
        const FLAG_SYNC             = 0b0000000001000000,
        const FLAG_LAST_BUF         = 0b0000000010000000,
        const FLAG_LAST_IN_CHAIN    = 0b0000000100000000,
        const FLAG_LAST_SHADOW      = 0b0000001000000000,
        const FLAG_TEMP_FILE        = 0b0000010000000000,
    }
}

#[no_mangle]
pub extern fn ngx_http_sample_module_command(
   cf: *mut ngx_conf_t,
   cmd: *mut ngx_command_t,
   conf: *mut c_void
) -> *const c_char {
   unsafe {
      let clcf = ngx_http_conf_get_module_loc_conf!(cf, ngx_http_core_module);
      (*clcf).handler = Some(ngx_http_sample_handler);
   }

   NGX_CONF_OK
}

#[no_mangle]
pub extern fn ngx_http_sample_handler(r: *mut ngx_http_request_t) -> ngx_int_t
{
   unsafe {
      let log = (*(*r).connection).log;

      let ngx_http_sample_text: ngx_str_t = sample_text_from_rust(r);

      (*r).headers_out.status = NGX_HTTP_OK;
      (*r).headers_out.content_length_n = ngx_http_sample_text.len as i64;

      let rc: ngx_int_t = ngx_http_send_header(r);
      if rc == NGX_ERROR || rc > NGX_OK { //|| (*r).header_only) {
         return rc;
      }

      let b: *mut ngx_buf_t = ngx_calloc_buf!((*r).pool) as *mut ngx_buf_t;

      if b.is_null() {
         return NGX_HTTP_INTERNAL_SERVER_ERROR as i64;
      };

      let out: Box<ngx_chain_t> = Box::new(
         ngx_chain_t {
            buf: b,
            next: ptr::null_mut(),
         }
      );

      let headers_in = (*r).headers_in;

      let cstr_template = CString::new("BITS: \"%s\"").unwrap();
      let b1 = CString::new(format!("{:032b}", headers_in._bindgen_bitfield_1_)).unwrap();

      ngx_log_error_core(
         2, log, 0,
         cstr_template.as_ptr(),
         b1.as_ptr()
      );

      let out: *mut ngx_chain_t = boxed::into_raw(out);

      (*b).start = ngx_http_sample_text.data;
      (*b).pos = (*b).start;

      (*b).end = ngx_http_sample_text.data.offset(ngx_http_sample_text.len as isize);
      (*b).last = (*b).end;

      let buf_flags = FLAG_MEMORY | FLAG_LAST_BUF | FLAG_LAST_IN_CHAIN;
      (*b)._bindgen_bitfield_1_ = buf_flags.bits();

      ngx_http_output_filter(r, out)
   }
}

fn sample_text_from_rust(r: *mut ngx_http_request_t) -> ngx_str_t
{
   let s = CString::new("<meta charset=\"utf-8\">Здравейте!".to_string()).unwrap();
   let len = s.to_bytes().len() as size_t;

   let result = ngx_str_t {
      len: len,
      data: unsafe {
         ngx_pcalloc((*r).pool, len) as *mut u8
      },
   };

   unsafe {
      ptr::copy_nonoverlapping(result.data, s.as_ptr() as *const u8, len as usize);
   }

   result
}

#[no_mangle]
pub extern fn dump_request(r: *mut ngx_http_request_t) {
   unsafe {
      let log = (*(*r).connection).log;

      let template = "REQ: \
         method=\"%ud\" \
         http_version=\"%ud\" \
         request_line=\"%V\" \
         uri=\"%V\" \
         args=\"%V\" \
         exten=\"%V\" \
         unparsed_uri=\"%V\" \
         method_name=\"%V\" \
         http_protocol=\"%V\" \
         bit1=\"%s\" \
         bit2=\"%s\" \
         bit3=\"%s\" \
         bit4=\"%s\" \
         bits=\"%s\" \
      ";
      let cstr_template = CString::new(template).unwrap();

      let b1 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_1_)).unwrap();
      let b2 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_2_)).unwrap();
      let b3 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_3_)).unwrap();
      let b4 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_4_)).unwrap();

      let buf_flags = FLAG_MEMORY | FLAG_LAST_BUF | FLAG_LAST_IN_CHAIN;
      let bits = CString::new(format!("{:032b}", buf_flags.bits())).unwrap();

      ngx_log_error_core(
         2, log, 0,
         cstr_template.as_ptr(),
         (*r).method,
         (*r).http_version,
         &((*r).request_line),
         &((*r).uri),
         &((*r).args),
         &((*r).exten),
         &((*r).unparsed_uri),
         &((*r).method_name),
         &((*r).http_protocol),
         b1.as_ptr(),
         b2.as_ptr(),
         b3.as_ptr(),
         b4.as_ptr(),
         bits.as_ptr(),
      );
   }
}

#[no_mangle]
pub extern fn dump_buffer(r: *mut ngx_http_request_t, b: *mut ngx_buf_t) {
   unsafe {
      let log = (*(*r).connection).log;

      let template = "BUF: \
         pos=\"%p\" \
         last=\"%p\" \
         start=\"%p\" \
         end=\"%p\" \
         num=\"%d\" \
         bit1=\"%s\" \
      ";
      let cstr_template = CString::new(template).unwrap();

      let b1 = CString::new(format!("{:064b}", (*b)._bindgen_bitfield_1_)).unwrap();

      ngx_log_error_core(
         2, log, 0,
         cstr_template.as_ptr(),
         (*b).pos,
         (*b).last,
         (*b).start,
         (*b).end,
         (*b).num,
         b1.as_ptr(),
      );
   }
}
<|endoftext|>