<commit_before>//! This crate provides macros for writing simple vulkan compute shader tests
//! using the [tomaka/vulkano library](https://github.com/tomaka/vulkano).
//!
//! ## About
//!
//! A core problem of developing shaders is the rather difficult environment in which they are
//! executed. Even simple things can go wrong and cost the developer a lot of time to fix.
//! This crate aims at providing a simple-to-use environment for writing vulkan compute shader tests.
//! It uses the vulkano rust-vulkan bindings end exports macros for a fast implementation of tests.
//! These macros mostly generate vulkano boilerplate instantiation code. The interface to the
//! shader are CPU accessible buffers which you can read and write at will and a function for
//! executing the shader code and waiting for the result.
//!
//! ## Import
//!
//! Due to the reexport of utility function from the vulkano crate (which you don't need to access,
//! unless you want to) you need to use the following crates in your application header:
//!
//! ```
//! extern crate vulkano;
//! #[macro_use]
//! extern crate vulkanology;
//! #
//! # fn main() {}
//! ```
//!
//! For basic usage of the library you can refer to the doc-tests and `tests/shaders/example.comp`.
//! For a working example of a fairly elaborate shader test please refer to: `tests/random.rs`
//! and `tests/shaders/random.comp`.
//!
#![deny(missing_docs)]
#![feature(macro_reexport)]

#[macro_use]
#[macro_reexport(pipeline_layout)]
extern crate vulkano;

/// Creates a `vulkano::Instance`. Does not enable any instance extensions.
///
/// # Panics
///
/// Panics if the vulkano instance loading procedure fails.
///
/// # Example
///
/// ```
/// # extern crate vulkano;
/// # #[macro_use]
/// # extern crate vulkanology;
/// #
/// # #[allow(unused_variables)]
/// # fn main() {
/// // Simply invoke the macro and assign the result.
/// let instance = instance!();
/// # }
/// ```
#[macro_export]
macro_rules! instance {
    () => ({
        use vulkano::instance::{Instance, InstanceExtensions};
        let extensions = &InstanceExtensions::none();
        Instance::new(None, extensions, None).expect("Failed to initialize vulkano.")
    })
}

/// This macro generates code for loading a `PhysicalDevice`. It takes
/// the instance variable name and an optional list of features which the device
/// should support.
/// All available features are defined here:
/// https://github.com/tomaka/vulkano/blob/master/vulkano/src/features.rs
///
/// # Panics
///
/// Panics if no device matching the requirements has been found.
///
/// # Example
///
/// ```
/// # extern crate vulkano;
/// # #[macro_use]
/// # extern crate vulkanology;
/// #
/// # #[allow(unused_variables)]
/// # fn main() {
/// // First initialize a `vulkano::Instance`.
/// let instance = instance!();
///
/// // Select the first physical device which supports compute shaders.
/// {
///     // With no explicitly required features:
///     let physical_device = physical_device!(instance);
/// }
/// {
///     // With some features:
///     let physical_device = physical_device!(
///         instance,
///         robust_buffer_access,
///         full_draw_index_uint32);
/// }
/// # }
/// ```
#[macro_export]
macro_rules! physical_device {
    // Rule for selecting a device with specific features.
    ($instance:ident, $($feature:ident),+) => ({
        use vulkano::instance::{PhysicalDevice};
        PhysicalDevice::enumerate(&$instance).find(|p| {
            let supported_features = p.supported_features();
            true $( && supported_features.$feature )*
        }).expect("No physical devices are available.")
    });

    // Rule for selecting the first available physical
    // device when no features are required.
    ($instance:ident) => ({
        use vulkano::instance::{PhysicalDevice};
        PhysicalDevice::enumerate(&$instance).next()
            .expect("No physical devices are available.")
    })
}

/// Creates a `Device` and a `Queue` for compute operations.
///
/// # Panics
///
/// Panics if no conpute-compatible queue has been found, or the
/// device could not be initialized.
///
/// # Example
///
/// ```
/// # extern crate vulkano;
/// # #[macro_use]
/// # extern crate vulkanology;
/// #
/// # #[allow(unused_variables)]
/// # fn main() {
/// let instance = instance!();
/// let physical_device = physical_device!(instance);
/// let (device, queue) = device_and_queue!(physical_device);
/// # }
/// ```
#[macro_export]
macro_rules! device_and_queue {
    ($physical_device:ident) => ({
        use vulkano::device::{Device, DeviceExtensions};

        // Select a queue family which supports compute operations.
        let mut queue_families = $physical_device.queue_families();
        let queue_family = queue_families.find(|q| q.supports_compute())
                .expect("Couldn't find a compute queue family.");

        // Initialize a device and a queue.
        let device_extensions = DeviceExtensions::none();
        let (device, mut queues) = Device::new(&$physical_device,
                                               &$physical_device.supported_features(),
                                               &device_extensions,
                                               [(queue_family, 0.5)].iter().cloned())
                .expect("Failed to create device.");

        // We only requested one queue, so `queues` is an array with only one element.
        (device, queues.next().unwrap())
    })
}

/// Creates a new uninitialized buffer of type `$buf_type` of length `$buf_len`.
///
/// # Panics
///
/// If the array fails to be initialized.
///
/// # Examples
///
/// ```
/// # extern crate vulkano;
/// # #[macro_use]
/// # extern crate vulkanology;
/// #
/// # #[allow(unused_variables)]
/// # fn main() {
/// let instance = instance!();
/// let physical_device = physical_device!(instance);
/// let (ref device, ref queue) = device_and_queue!(physical_device);
///
/// // Initialize a buffer.
/// let buffer = cpu_array_buffer!(device, queue, u32, 13*31);
/// # }
/// ```
#[macro_export]
macro_rules! cpu_array_buffer {
    ($device:ident, $queue:ident, $buf_type:ty, $buf_len:expr) => ({
        use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
        unsafe {
            CpuAccessibleBuffer::<[$buf_type]>::uninitialized_array(
                       $device,
                       $buf_len,
                       &BufferUsage::all(),
                       Some($queue.family()))
                   .expect("Failed to create a cpu accessible buffer.")
        }
    })
}

/// This macro is the core of the shader-testing framework.
/// It generates code for initializing the vulkano environment,
/// it allocates CPU accessible buffers, it compiles the shader,
/// it sets up a `ComputePipeline` and provides a function
/// for executing the shader.
///
/// # Panics
///
/// * If the instance, physical_device, device or queue cannot be selected/initialized.
/// * If the buffers cannot be initialized.
/// * If the shader cannot be loaded.
/// * If the pipeline cannot be created.
///
/// # Example
///
/// ```
/// # extern crate vulkano;
/// # #[macro_use]
/// # extern crate vulkanology;
/// # extern crate rand;
/// #
/// # #[allow(unused_variables)]
/// # fn main() {
/// // The total number of invocations of your shader is defined in two places:
/// //      - The workgroup_count, which is defined in the pipeline macro.
/// //      - The workgroup_size which is defined in the shader program header.
///
/// // Here we compute the total number of invocations. The workgroup size is 8x8x1,
/// // and the workgroup count will be 100x100x1.
/// let total_num_invocations = (8 * 8) * (100 * 100);
///
/// // I. Invoke the `pipeline!` macro.
/// // The macro parameters are:
/// //    1. The path to the shader program, relative to the crate root.
/// //        `shader_path: "path/to/shader/program.comp"`
/// //    2. A three-dimensional array defining the workgroup count:
/// //        `workgroup_count: [1, 2, 3],`
/// //    3. The buffers that your test shader uses:
/// //        `buffers: { input_data: [u32;4], some_buffer: [Dennis;42] },`
/// //    4. The name of the shader execution:
/// //        `execution_command: run_example_shader_function_name`
/// pipeline!{
///     shader_path: "tests/shaders/example.comp",
///     workgroup_count: [100, 100, 1],
///     buffers: {
///        data: [u32; total_num_invocations],
///        result: [u32; total_num_invocations]
///     },
///     execution_command: execute_shader
/// }
///
/// // II. Fill your buffers with input data. The buffers are bound to the
/// //      names given in the `pipeline!` macro.
/// {
///     use std::time::Duration;
///     use rand::random;
///
///     use vulkano::buffer::cpu_access::WriteLock;
///     let mut mapping: WriteLock<[u32]> = data.write(Duration::new(1, 0)).unwrap();
///
///     for item in mapping.iter_mut() {
///         *item = random::<u32>();
///     }
/// }
///
/// // III. Execute the shader.
/// //    `run_example_shader_function_name();`
/// execute_shader();
///
/// // IV. Assert validity of the results.
/// //    `assert!(datainbuffersisvalid())`
/// {
///     use std::time::Duration;
///     use vulkano::buffer::cpu_access::ReadLock;
///     let input: ReadLock<[u32]> = data.read(Duration::new(1, 0)).unwrap();
///     let output: ReadLock<[u32]> = result.read(Duration::new(1, 0)).unwrap();
///     let zipped = input.iter().zip(output.iter());
///
///     for (invocation_uid, (item_in, item_out)) in zipped.enumerate() {
///         assert_eq!(*item_out, (*item_in).wrapping_mul(invocation_uid as u32));
///     }
/// }
/// # }
/// ```
///
#[macro_export]
macro_rules! pipeline {
    {
        shader_path: $shader_path:expr,
        workgroup_count: [$workgroup_x:expr, $workgroup_y:expr, $workgroup_z:expr],
        buffers: { $( $buf_ident:ident : [$buf_type:ty;$buf_len:expr] ),* },
        execution_command: $exec_cmd:ident
    } => {
        use vulkano::command_buffer::PrimaryCommandBufferBuilder;
        use vulkano::command_buffer::submit as submit_command;
        use vulkano::descriptor::descriptor_set::DescriptorPool;
        use vulkano::pipeline::ComputePipeline;

        // Include the shader wrapper.
        mod shader {
            #![allow(dead_code)]
            include!{concat!(env!("OUT_DIR"), concat!("/shaders/", $shader_path))}
        }

        // Create the pipeline layout wrapper.
        mod layout_definition {
            pipeline_layout!{
                buffers: {
                    $( $buf_ident: StorageBuffer<[$buf_type]> ),*
                }
            }
        }

        // Init vulkano.
        let instance = instance!();
        let physical_device = physical_device!(instance);
        let (ref device, ref queue) = device_and_queue!(physical_device);

        // Allocate buffers.
        $( let $buf_ident = cpu_array_buffer!(device, queue, $buf_type, $buf_len); )*

        // Create descriptor pool.
        let descriptor_pool = DescriptorPool::new(device);

        // Create pipeline layout.
        let pipeline_layout = layout_definition::CustomPipeline::new(device).unwrap();
        let buffer_descriptors = layout_definition::buffers::Descriptors {
            $( $buf_ident: &$buf_ident, )*
        };
        let buffer_set = layout_definition::buffers::Set::new(&descriptor_pool,
                                                              &pipeline_layout,
                                                              &buffer_descriptors);

        // Load the shader and assemble the pipeline.
        let compute_shader = shader::Shader::load(device).expect("Failed to create shader module.");
        let pipeline = ComputePipeline::new(device,
                                            &pipeline_layout,
                                            &compute_shader.main_entry_point(),
                                            &())
                .expect("Failed to create compute pipeline.");

        // Assemble and return the execution command.
        let workgroup_count = [$workgroup_x, $workgroup_y, $workgroup_z];
        let execution_command = PrimaryCommandBufferBuilder::new(device, queue.family())
            .dispatch(&pipeline, buffer_set, workgroup_count, &())
            .build();
        let $exec_cmd = || {
            submit_command(&execution_command, queue).unwrap();
        };
    }
}

<commit_msg>Restructure workgroup count input<commit_after>//! This crate provides macros for writing simple vulkan compute shader tests
//! using the [tomaka/vulkano library](https://github.com/tomaka/vulkano).
//!
//! ## About
//!
//! A core problem of developing shaders is the rather difficult environment in which they are
//! executed. Even simple things can go wrong and cost the developer a lot of time to fix.
//! This crate aims at providing a simple-to-use environment for writing vulkan compute shader tests.
//! It uses the vulkano rust-vulkan bindings end exports macros for a fast implementation of tests.
//! These macros mostly generate vulkano boilerplate instantiation code. The interface to the
//! shader are CPU accessible buffers which you can read and write at will and a function for
//! executing the shader code and waiting for the result.
//!
//! ## Import
//!
//! Due to the reexport of utility function from the vulkano crate (which you don't need to access,
//! unless you want to) you need to use the following crates in your application header:
//!
//! ```
//! extern crate vulkano;
//! #[macro_use]
//! extern crate vulkanology;
//! #
//! # fn main() {}
//! ```
//!
//! For basic usage of the library you can refer to the doc-tests and `tests/shaders/example.comp`.
//! For a working example of a fairly elaborate shader test please refer to: `tests/random.rs`
//! and `tests/shaders/random.comp`.
//!
#![deny(missing_docs)]
#![feature(macro_reexport)]

#[macro_use]
#[macro_reexport(pipeline_layout)]
extern crate vulkano;

/// Creates a `vulkano::Instance`. Does not enable any instance extensions.
///
/// # Panics
///
/// Panics if the vulkano instance loading procedure fails.
///
/// # Example
///
/// ```
/// # extern crate vulkano;
/// # #[macro_use]
/// # extern crate vulkanology;
/// #
/// # #[allow(unused_variables)]
/// # fn main() {
/// // Simply invoke the macro and assign the result.
/// let instance = instance!();
/// # }
/// ```
#[macro_export]
macro_rules! instance {
    () => ({
        use vulkano::instance::{Instance, InstanceExtensions};
        let extensions = &InstanceExtensions::none();
        Instance::new(None, extensions, None).expect("Failed to initialize vulkano.")
    })
}

/// This macro generates code for loading a `PhysicalDevice`. It takes
/// the instance variable name and an optional list of features which the device
/// should support.
/// All available features are defined here:
/// https://github.com/tomaka/vulkano/blob/master/vulkano/src/features.rs
///
/// # Panics
///
/// Panics if no device matching the requirements has been found.
///
/// # Example
///
/// ```
/// # extern crate vulkano;
/// # #[macro_use]
/// # extern crate vulkanology;
/// #
/// # #[allow(unused_variables)]
/// # fn main() {
/// // First initialize a `vulkano::Instance`.
/// let instance = instance!();
///
/// // Select the first physical device which supports compute shaders.
/// {
///     // With no explicitly required features:
///     let physical_device = physical_device!(instance);
/// }
/// {
///     // With some features:
///     let physical_device = physical_device!(
///         instance,
///         robust_buffer_access,
///         full_draw_index_uint32);
/// }
/// # }
/// ```
#[macro_export]
macro_rules! physical_device {
    // Rule for selecting a device with specific features.
    ($instance:ident, $($feature:ident),+) => ({
        use vulkano::instance::{PhysicalDevice};
        PhysicalDevice::enumerate(&$instance).find(|p| {
            let supported_features = p.supported_features();
            true $( && supported_features.$feature )*
        }).expect("No physical devices are available.")
    });

    // Rule for selecting the first available physical
    // device when no features are required.
    ($instance:ident) => ({
        use vulkano::instance::{PhysicalDevice};
        PhysicalDevice::enumerate(&$instance).next()
            .expect("No physical devices are available.")
    })
}

/// Creates a `Device` and a `Queue` for compute operations.
///
/// # Panics
///
/// Panics if no conpute-compatible queue has been found, or the
/// device could not be initialized.
///
/// # Example
///
/// ```
/// # extern crate vulkano;
/// # #[macro_use]
/// # extern crate vulkanology;
/// #
/// # #[allow(unused_variables)]
/// # fn main() {
/// let instance = instance!();
/// let physical_device = physical_device!(instance);
/// let (device, queue) = device_and_queue!(physical_device);
/// # }
/// ```
#[macro_export]
macro_rules! device_and_queue {
    ($physical_device:ident) => ({
        use vulkano::device::{Device, DeviceExtensions};

        // Select a queue family which supports compute operations.
        let mut queue_families = $physical_device.queue_families();
        let queue_family = queue_families.find(|q| q.supports_compute())
                .expect("Couldn't find a compute queue family.");

        // Initialize a device and a queue.
        let device_extensions = DeviceExtensions::none();
        let (device, mut queues) = Device::new(&$physical_device,
                                               &$physical_device.supported_features(),
                                               &device_extensions,
                                               [(queue_family, 0.5)].iter().cloned())
                .expect("Failed to create device.");

        // We only requested one queue, so `queues` is an array with only one element.
        (device, queues.next().unwrap())
    })
}

/// Creates a new uninitialized buffer of type `$buf_type` of length `$buf_len`.
///
/// # Panics
///
/// If the array fails to be initialized.
///
/// # Examples
///
/// ```
/// # extern crate vulkano;
/// # #[macro_use]
/// # extern crate vulkanology;
/// #
/// # #[allow(unused_variables)]
/// # fn main() {
/// let instance = instance!();
/// let physical_device = physical_device!(instance);
/// let (ref device, ref queue) = device_and_queue!(physical_device);
///
/// // Initialize a buffer.
/// let buffer = cpu_array_buffer!(device, queue, u32, 13*31);
/// # }
/// ```
#[macro_export]
macro_rules! cpu_array_buffer {
    ($device:ident, $queue:ident, $buf_type:ty, $buf_len:expr) => ({
        use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
        unsafe {
            CpuAccessibleBuffer::<[$buf_type]>::uninitialized_array(
                       $device,
                       $buf_len,
                       &BufferUsage::all(),
                       Some($queue.family()))
                   .expect("Failed to create a cpu accessible buffer.")
        }
    })
}

/// This macro is the core of the shader-testing framework.
/// It generates code for initializing the vulkano environment,
/// it allocates CPU accessible buffers, it compiles the shader,
/// it sets up a `ComputePipeline` and provides a function
/// for executing the shader.
///
/// # Panics
///
/// * If the instance, physical_device, device or queue cannot be selected/initialized.
/// * If the buffers cannot be initialized.
/// * If the shader cannot be loaded.
/// * If the pipeline cannot be created.
///
/// # Example
///
/// ```
/// # extern crate vulkano;
/// # #[macro_use]
/// # extern crate vulkanology;
/// # extern crate rand;
/// #
/// # #[allow(unused_variables)]
/// # fn main() {
/// // The total number of invocations of your shader is defined in two places:
/// //      - The workgroup_count, which is defined in the pipeline macro.
/// //      - The workgroup_size which is defined in the shader program header.
///
/// // Here we compute the total number of invocations. The workgroup size is 8x8x1,
/// // and the workgroup count will be 100x100x1.
/// let total_num_invocations = (8 * 8) * (100 * 100);
///
/// // I. Invoke the `pipeline!` macro.
/// // The macro parameters are:
/// //    1. The path to the shader program, relative to the crate root.
/// //        `shader_path: "path/to/shader/program.comp"`
/// //    2. A three-dimensional array defining the workgroup count:
/// //        `workgroup_count: [1, 2, 3],`
/// //    3. The buffers that your test shader uses:
/// //        `buffers: { input_data: [u32;4], some_buffer: [Dennis;42] },`
/// //    4. The name of the shader execution:
/// //        `execution_command: run_example_shader_function_name`
/// pipeline!{
///     shader_path: "tests/shaders/example.comp",
///     workgroup_count: [100, 100, 1],
///     buffers: {
///        data: [u32; total_num_invocations],
///        result: [u32; total_num_invocations]
///     },
///     execution_command: execute_shader
/// }
///
/// // II. Fill your buffers with input data. The buffers are bound to the
/// //      names given in the `pipeline!` macro.
/// {
///     use std::time::Duration;
///     use rand::random;
///
///     use vulkano::buffer::cpu_access::WriteLock;
///     let mut mapping: WriteLock<[u32]> = data.write(Duration::new(1, 0)).unwrap();
///
///     for item in mapping.iter_mut() {
///         *item = random::<u32>();
///     }
/// }
///
/// // III. Execute the shader.
/// //    `run_example_shader_function_name();`
/// execute_shader();
///
/// // IV. Assert validity of the results.
/// //    `assert!(datainbuffersisvalid())`
/// {
///     use std::time::Duration;
///     use vulkano::buffer::cpu_access::ReadLock;
///     let input: ReadLock<[u32]> = data.read(Duration::new(1, 0)).unwrap();
///     let output: ReadLock<[u32]> = result.read(Duration::new(1, 0)).unwrap();
///     let zipped = input.iter().zip(output.iter());
///
///     for (invocation_uid, (item_in, item_out)) in zipped.enumerate() {
///         assert_eq!(*item_out, (*item_in).wrapping_mul(invocation_uid as u32));
///     }
/// }
/// # }
/// ```
///
#[macro_export]
macro_rules! pipeline {
    {
        shader_path: $shader_path:expr,
        workgroup_count: $workgroup_count:expr,
        buffers: { $( $buf_ident:ident : [$buf_type:ty;$buf_len:expr] ),* },
        execution_command: $exec_cmd:ident
    } => {
        use vulkano::command_buffer::PrimaryCommandBufferBuilder;
        use vulkano::command_buffer::submit as submit_command;
        use vulkano::descriptor::descriptor_set::DescriptorPool;
        use vulkano::pipeline::ComputePipeline;

        // Include the shader wrapper.
        mod shader {
            #![allow(dead_code)]
            include!{concat!(env!("OUT_DIR"), concat!("/shaders/", $shader_path))}
        }

        // Create the pipeline layout wrapper.
        mod layout_definition {
            pipeline_layout!{
                buffers: {
                    $( $buf_ident: StorageBuffer<[$buf_type]> ),*
                }
            }
        }

        // Init vulkano.
        let instance = instance!();
        let physical_device = physical_device!(instance);
        let (ref device, ref queue) = device_and_queue!(physical_device);

        // Allocate buffers.
        $( let $buf_ident = cpu_array_buffer!(device, queue, $buf_type, $buf_len); )*

        // Create descriptor pool.
        let descriptor_pool = DescriptorPool::new(device);

        // Create pipeline layout.
        let pipeline_layout = layout_definition::CustomPipeline::new(device).unwrap();
        let buffer_descriptors = layout_definition::buffers::Descriptors {
            $( $buf_ident: &$buf_ident, )*
        };
        let buffer_set = layout_definition::buffers::Set::new(&descriptor_pool,
                                                              &pipeline_layout,
                                                              &buffer_descriptors);

        // Load the shader and assemble the pipeline.
        let compute_shader = shader::Shader::load(device).expect("Failed to create shader module.");
        let pipeline = ComputePipeline::new(device,
                                            &pipeline_layout,
                                            &compute_shader.main_entry_point(),
                                            &())
                .expect("Failed to create compute pipeline.");

        // Assemble and return the execution command.
        let execution_command = PrimaryCommandBufferBuilder::new(device, queue.family())
            .dispatch(&pipeline, buffer_set, $workgroup_count, &())
            .build();
        let $exec_cmd = || {
            submit_command(&execution_command, queue).unwrap();
        };
    }
}

<|endoftext|>


<commit_before>extern crate md5;

pub fn puzzle(door_id: &str) -> String {
    let mut answer = String::new();
    let mut index = 0;

    for _ in 0..9 {
        let (new_index, next_char) = next_interesting_md5(door_id, index);
        index = new_index + 1;
        answer.push(next_char);
    }
    answer
}

pub fn next_interesting_md5(door_id: &str, mut index: u32) -> (u32, char) {
    loop {
        if index % 1000000 == 0 {
            println!("at index {}", index);
        }
        let candidate = format!("{}{}", door_id, index);

        let digest = md5::compute(candidate.as_bytes());

        if digest.starts_with(b"00000") {
            return (index, *digest.iter().nth(5).expect("no 5th char") as char)
        } else {
            index += 1;
        }
    }
}

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

    #[test]
    fn once() {
        assert_eq!(next_interesting_md5("abc", 0), (3231929, '1'));
    }

}
<commit_msg>Ok. After reading the tests in the md5 crate, i get it<commit_after>extern crate md5;

pub fn puzzle(door_id: &str) -> String {
    let mut answer = String::new();
    let mut index = 0;

    for _ in 0..9 {
        let (new_index, next_char) = next_interesting_md5(door_id, index);
        index = new_index + 1;
        answer.push(next_char);
    }
    answer
}

pub fn next_interesting_md5(door_id: &str, mut index: u32) -> (u32, char) {
    loop {
        if index % 1000000 == 0 {
            println!("at index {}", index);
        }
        let candidate = format!("{}{}", door_id, index);

        let digest = md5::compute(candidate.as_bytes());

        if digest.starts_with(b"00000") {
            return (index, *digest.iter().nth(5).expect("no 5th char") as char)
        } else {
            index += 1;
        }
    }
}

pub fn starts_with_five_zeroes(door_id: &str, mut index: u32) -> bool {
    let candidate = format!("{}{}", door_id, index);

    println!("candidate = ({})", candidate);

    let mut digest = String::new();
    for b in &md5::compute(candidate.as_bytes())[..] {
        digest.push_str(&format!("{:02x}", b));
    }

    println!("digest = {:?}", digest);

    println!("starts_with = {:?}", "00000");

    digest.starts_with("00000")

}

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

    #[test]
    fn check_hashing_is_working() {
        assert!(starts_with_five_zeroes("abc", 3231929));
    }

    // #[test]
    // fn once() {
    //     assert_eq!(next_interesting_md5("abc", 0), (3231929, '1'));
    // }

}
<|endoftext|>


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

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

/// A word list.
pub type Words<'a> = Vec<&'a str>;

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

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

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

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

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

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

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

    /// Calculate the cardinality of this `Petnames`.
    ///
    /// If this is low, names may be repeated by the generator with a higher
    /// frequency than your use-case may allow. If it is 0 (zero) the generator
    /// will panic (unless `words` is also zero).
    ///
    /// This can saturate. If the total possible combinations of words exceeds
    /// `u128::MAX` then this will return `u128::MAX`.
    pub fn cardinality(&self, words: u8) -> u128 {
        Lists(self, words)
            .map(|list| list.len() as u128)
            .fold1(u128::saturating_mul)
            .unwrap_or(0u128)
    }

    /// Generate a new petname.
    ///
    /// # Examples
    ///
    /// ```rust
    /// let mut rng = rand::thread_rng();
    /// petname::Petnames::default().generate(&mut rng, 7, ":");
    /// ```
    ///
    /// # Notes
    ///
    /// This may return fewer words than you request if one or more of the word
    /// lists are empty. For example, if there are no adverbs, requesting 3 or
    /// more words may still yield only "doubtful-salmon".
    ///
    pub fn generate<RNG>(&self, rng: &mut RNG, words: u8, separator: &str) -> String
    where
        RNG: rand::Rng,
    {
        Lists(self, words)
            .filter_map(|list| list.choose(rng))
            .cloned()
            .intersperse(separator)
            .collect::<String>()
    }

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

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

/// Iterator over a `Petnames`' word lists.
///
/// This yields the appropriate lists from which to select a word when
/// constructing a petname of `n` words. For example, if you want 3 words in
/// your petname, this will first yield the adverbs word list, then adjectives,
/// then names.
struct Lists<'a>(&'a Petnames<'a>, u8);

impl<'a> Iterator for Lists<'a> {
    type Item = &'a Words<'a>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, Some(self.1 as usize))
    }

    fn next(&mut self) -> Option<Self::Item> {
        let Self(petnames, ref mut word) = self;
        match word {
            0 => None,
            1 => {
                *word -= 1;
                Some(&petnames.names)
            }
            2 => {
                *word -= 1;
                Some(&petnames.adjectives)
            }
            _ => {
                *word -= 1;
                Some(&petnames.adverbs)
            }
        }
    }
}

#[cfg(test)]
mod tests {

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

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

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

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

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

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

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

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

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

/// A word list.
pub type Words<'a> = Vec<&'a str>;

/// Word lists and the logic to combine them into _petnames_.
///
/// A _petname_ with `n` words will contain, in order:
///
///   * `n - 2` adverbs when `n >= 2`, otherwise 0 adverbs.
///   * 1 adjective when `n >= 2`, otherwise 0 adjectives.
///   * 1 name / noun when `n >= 1`, otherwise 0 names.
///
#[derive(Clone, Debug, PartialEq)]
pub struct Petnames<'a> {
    pub adjectives: Words<'a>,
    pub adverbs: Words<'a>,
    pub names: Words<'a>,
}

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

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

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

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

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

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

    /// Calculate the cardinality of this `Petnames`.
    ///
    /// If this is low, names may be repeated by the generator with a higher
    /// frequency than your use-case may allow. If it is 0 (zero) the generator
    /// will panic (unless `words` is also zero).
    ///
    /// This can saturate. If the total possible combinations of words exceeds
    /// `u128::MAX` then this will return `u128::MAX`.
    pub fn cardinality(&self, words: u8) -> u128 {
        Lists(self, words)
            .map(|list| list.len() as u128)
            .fold1(u128::saturating_mul)
            .unwrap_or(0u128)
    }

    /// Generate a new petname.
    ///
    /// # Examples
    ///
    /// ```rust
    /// let mut rng = rand::thread_rng();
    /// petname::Petnames::default().generate(&mut rng, 7, ":");
    /// ```
    ///
    /// # Notes
    ///
    /// This may return fewer words than you request if one or more of the word
    /// lists are empty. For example, if there are no adverbs, requesting 3 or
    /// more words may still yield only "doubtful-salmon".
    ///
    pub fn generate<RNG>(&self, rng: &mut RNG, words: u8, separator: &str) -> String
    where
        RNG: rand::Rng,
    {
        Lists(self, words)
            .filter_map(|list| list.choose(rng))
            .cloned()
            .intersperse(separator)
            .collect::<String>()
    }

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

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

/// Iterator over a `Petnames`' word lists.
///
/// This yields the appropriate lists from which to select a word when
/// constructing a petname of `n` words. For example, if you want 3 words in
/// your petname, this will first yield the adverbs word list, then adjectives,
/// then names.
struct Lists<'a>(&'a Petnames<'a>, u8);

impl<'a> Iterator for Lists<'a> {
    type Item = &'a Words<'a>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, Some(self.1 as usize))
    }

    fn next(&mut self) -> Option<Self::Item> {
        let Self(petnames, ref mut word) = self;
        match word {
            0 => None,
            1 => {
                *word -= 1;
                Some(&petnames.names)
            }
            2 => {
                *word -= 1;
                Some(&petnames.adjectives)
            }
            _ => {
                *word -= 1;
                Some(&petnames.adverbs)
            }
        }
    }
}

#[cfg(test)]
mod tests {

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

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

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

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

    #[test]
    fn retain_applies_given_predicate() {
        let petnames_expected = Petnames::init("bob", "bob", "bob jane");
        let mut petnames = Petnames::init("alice bob carol", "alice bob", "bob carol jane");
        petnames.retain(|word| word.len() < 5);
        assert_eq!(petnames_expected, petnames);
    }

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

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

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

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


<commit_before>// riff-wave -- Basic support for reading and writing wave PCM files.
// Copyright (c) 2016 Kevin Brothaler and the riff-wave project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Basic support for reading and writing wave PCM files.
//!
//! This early version of the library seeks to support the "canonical" wave PCM
//! file format, as well as the basic features of the extended file format.
//! Non-PCM files are not currently supported, nor is metadata. Future versions
//! of the library may add support for some of these features.
//!
//! The wave file format was originally defined by Microsoft, and it stores
//! audio wave data in a container using RIFF chunks to encode the header and
//! data. The RIFF format also supports file metadata via a LIST INFO chunk and
//! an associated data chunk.
//!
//! See also:
//!
//! * [Hound][1] - Another wave encoding and decoding library in Rust.
//! * [Multimedia Programming Interface and Data Specifications 1.0][2] - Further
//! info about the RIFF file format.
//! * [RIFF WAVE (.WAV) file format][3] - Also has more info on the RIFF WAVE format.
//!
//! # The wave file format
//!
//! The wave file format starts with the RIFF file header:
//!
//! Offset | Size | Data       |    Description
//! -----: | ---: | ---------- | ----------------------------------------------
//!      0 |    4 | "RIFF"     | Identifies the main chunk.
//!      4 |    4 | chunk size | The size of the rest of the file. This should be equal to the size of the file minus 8 bytes.
//!      8 |    4 | "WAVE"     | Indicates that this is a wave file.
//!
//! The wave file format requires at least two subchunks which follow the main chunk:
//!
//! * The "fmt " subchunk. This contains additional header information.
//! * The "data" subchunk. This contains the actual audio data.
//!
//! ## The "fmt " subchunk
//!
//! The "fmt " subchunk starts with the following fields:
//!
//! Offset | Size | Data            | Description
//! -----: | ---: | --------------- | -----------------------------------------
//!     12 |    4 | "fmt "          | Identifies this subchunk.
//!     16 |    4 | subchunk size   | The size of the rest of this subchunk.
//!     20 |    2 | format (1)      | The format of the wave data, which will be 1 for uncompressed PCM data.
//!     22 |    2 | num channels    | Indicates if the data is mono, stereo, or something else.
//!     24 |    4 | sample rate     | The sample rate per second.
//!     28 |    4 | byte rate       | The total byte rate per second. For 16-bit stereo at 44,100 samples per second, this would be equal to 176,000 bytes per second.
//!     32 |    2 | block align     | How many bytes are needed for each "frame", where a frame is one sample for each channel.
//!     34 |    2 | bits per sample | The bits per sample; i.e. 16 for 16-bit audio.
//!
//! The `format` can take on various values, including the following codes:
//!
//! Value | Description
//! ----: | -------------------------------------------------------------------
//!     1 | Uncompressed PCM
//!     3 | IEEE floating-point
//!     6 | 8-bit ITU-T G.711 A-law
//!     7 | 8-bit ITU-T G.711 µ-law
//! 65534 | A special marker value, indicating that this is an "extended" wave file.
//!
//! This library currently only supports uncompressed PCM in standard and
//! extended wave formats. These files will usually be either 8-bit unsigned or
//! 16-bit signed, mono or stereo.
//!
//! Wave files may include an additional field, usually reserved for non-PCM formats:
//!
//! Offset | Size | Data            | Description
//! -----: | ---: | --------------- | -----------------------------------------
//!     36 |    2 | extra info size | For non-PCM formats, this stores the size of the additional info that follows the end of the standard header. Otherwise, it is set to 0.
//!
//! ### Extended wave files
//!
//! Some wave files may follow the extended format. In this case, the
//! `extra info size` field will be at least 22 instead of 0.
//!
//! Offset | Size | Data            | Description
//! -----: | ---: | --------------- | -----------------------------------------
//!     38 |    2 | sample info     | For PCM files, this contains the valid bits for sample. For example, if this is set to 20 bits and `bits per sample` is set to 24 bits, then that means that 24 bits are being used to store the sample data, but the actual sample data should not exceed 20 bits of precision.
//!     42 |    4 | channel mask    | This specifies the assignment of channels to speaker positions.
//!     46 |   16 | sub format      | For extended wave files, `format` will be set to 0xFFFE to indicate that it's an extended wave file, with the actual format specified here as a [GUID][4]. The first two bytes are the same as specified in `format code`, and the remainder should match 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, and 0x71.
//!
//! The MSDN docs recommend this format for files with more than two channels
//! or more than 16 bits per sample, but it's also possible to encounter such
//! wave files that don't include these extra fields. In my testing, Android
//! Marshmallow was able to play back 24-bit PCM wave files using both the
//! standard format and the extensible format, generated using [Audacity][5].
//!
//! ## The "data" subchunk
//!
//! The "data" subchunk contains the actual audio data:
//!
//! Offset | Size | Data            | Description
//! -----: | ---: | --------------- | -----------------------------------------
//! 36+    |    4 | "data"          | Identifies this subchunk
//! 40+    |    4 | subchunk size   | The size of this chunk. For the simple "canonical" wave file format, this will generally be the size of the file minus 44 bytes for the header data, up to and including this field.
//! 44+    |  ... | audio data      | This stores the actual audio data.
//! ...    |  ... | padding byte    | If the length of audio data is an odd number, then an additional padding byte should be inserted.
//!
//! As the subchunk size is a 32-bit value, the length of audio data cannot
//! exceed 4 GiB, and indeed the entire file can't really exceed 4 GiB as the
//! master RIFF chunk size field is also a 32-bit value.
//!
//! ## Additional meta-data
//!
//! Wave files may also contain other metadata, such as the LIST INFO chunks
//! defined by RIFF or other metadata. The LIST INFO chunk is analogous to
//! the ID3 tag in an MP3 file, and if it's present, it can often be found
//! between the "fmt " and "data" subchunks or after the end of the "data"
//! subchunk.
//!
//! See also:
//!
//! * [WAVEFORMATEXTENSIBLE structure][6]
//! * [Audio File Format Specifications][7]
//! * [WAVE PCM soundfile format][8]
//!
//! [1]: https://github.com/ruud-v-a/hound
//! [2]: https://www.aelius.com/njh/wavemetatools/doc/riffmci.pdf
//! [3]: http://www.neurophys.wisc.edu/auditory/riff-format.txt
//! [4]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa373931(v=vs.85).aspx
//! [5]: http://www.audacityteam.org
//! [6]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd757714(v=vs.85).aspx
//! [7]: http://www-mmsp.ece.mcgill.ca/documents/audioformats/wave/wave.html
//! [8]: http://soundfile.sapp.org/doc/WaveFormat/

extern crate byteorder;

// This is a helper macro that helps us validate results in our tests. It has
// to be defined before the mod definitions below so that it's visible in those
// mods.
// Thank you bluss and durka42!
#[cfg(test)]
macro_rules! assert_matches {
    ($expected:pat $(if $guard:expr)*, $value:expr) => {
        match $value {
            $expected $(if $guard)* => {},
            ref actual => {
                panic!("assertion failed: `(left matches right)` (left: `{}`, right: `{:?}`",
                    stringify!($expected), actual);
            },
        }
    };
}

mod reader;
mod writer;

pub use self::reader::{ReadError, ReadErrorKind, ReadResult, WaveReader};
pub use self::writer::{WaveWriter, WriteError, WriteResult};

pub const FORMAT_UNCOMPRESSED_PCM: u16 = 1;
pub const FORMAT_EXTENDED: u16 = 65534;

pub const MIN_I24_VALUE: i32 = -8388608;
pub const MAX_I24_VALUE: i32 = 8388607;

#[derive(Debug)]
pub enum Format {
    UncompressedPcm,
    Extended,
}

#[derive(Debug)]
pub struct PcmFormat {
    pub num_channels: u16,
    pub sample_rate: u32,
    pub bits_per_sample: u16,
}
<commit_msg>Update lib.rs<commit_after>// riff-wave -- Basic support for reading and writing wave PCM files.
// Copyright (c) 2016 Kevin Brothaler and the riff-wave project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Basic support for reading and writing wave PCM files.
//!
//! This early version of the library seeks to support the "canonical" wave PCM
//! file format, as well as the basic features of the extended file format.
//! Non-PCM files are not currently supported, nor is metadata. Future versions
//! of the library may add support for some of these features.
//!
//! The wave file format was originally defined by Microsoft, and it stores
//! audio wave data in a container using RIFF chunks to encode the header and
//! data. The RIFF format also supports file metadata via a LIST INFO chunk and
//! an associated data chunk.
//!
//! See also:
//!
//! * [Hound][1] - Another wave encoding and decoding library in Rust.
//! * [Multimedia Programming Interface and Data Specifications 1.0][2] - Further
//! info about the RIFF file format.
//! * [RIFF WAVE (.WAV) file format][3] - Also has more info on the RIFF WAVE format.
//!
//! # The wave file format
//!
//! The wave file format starts with the RIFF file header:
//!
//! Offset | Size | Data       |    Description
//! -----: | ---: | ---------- | ----------------------------------------------
//!      0 |    4 | "RIFF"     | Identifies the main chunk.
//!      4 |    4 | chunk size | The size of the rest of the file. This should be equal to the size of the file minus 8 bytes.
//!      8 |    4 | "WAVE"     | Indicates that this is a wave file.
//!
//! The wave file format requires at least two subchunks which follow the main chunk:
//!
//! * The "fmt " subchunk. This contains additional header information.
//! * The "data" subchunk. This contains the actual audio data.
//!
//! ## The "fmt " subchunk
//!
//! The "fmt " subchunk starts with the following fields:
//!
//! Offset | Size | Data            | Description
//! -----: | ---: | --------------- | -----------------------------------------
//!     12 |    4 | "fmt "          | Identifies this subchunk.
//!     16 |    4 | subchunk size   | The size of the rest of this subchunk.
//!     20 |    2 | format (1)      | The format of the wave data, which will be 1 for uncompressed PCM data.
//!     22 |    2 | num channels    | Indicates if the data is mono, stereo, or something else.
//!     24 |    4 | sample rate     | The sample rate per second.
//!     28 |    4 | byte rate       | The total byte rate per second. For 16-bit stereo at 44,100 samples per second, this would be equal to 176,000 bytes per second.
//!     32 |    2 | block align     | How many bytes are needed for each "frame", where a frame is one sample for each channel.
//!     34 |    2 | bits per sample | The bits per sample; i.e. 16 for 16-bit audio.
//!
//! The `format` can take on various values, including the following codes:
//!
//! Value | Description
//! ----: | -------------------------------------------------------------------
//!     1 | Uncompressed PCM
//!     3 | IEEE floating-point
//!     6 | 8-bit ITU-T G.711 A-law
//!     7 | 8-bit ITU-T G.711 µ-law
//! 65534 | A special marker value, indicating that this is an "extended" wave file.
//!
//! This library currently only supports uncompressed PCM in standard and
//! extended wave formats. These files will usually be either 8-bit unsigned or
//! 16-bit signed, mono or stereo.
//!
//! Wave files may include an additional field, usually reserved for non-PCM formats:
//!
//! Offset | Size | Data            | Description
//! -----: | ---: | --------------- | -----------------------------------------
//!     36 |    2 | extra info size | For non-PCM formats, this stores the size of the additional info that follows the end of the standard header. Otherwise, it is set to 0.
//!
//! ### Extended wave files
//!
//! Some wave files may follow the extended format. In this case, the
//! `extra info size` field will be at least 22 instead of 0.
//!
//! Offset | Size | Data            | Description
//! -----: | ---: | --------------- | -----------------------------------------
//!     38 |    2 | sample info     | For PCM files, this contains the valid bits for sample. For example, if this is set to 20 bits and `bits per sample` is set to 24 bits, then that means that 24 bits are being used to store the sample data, but the actual sample data should not exceed 20 bits of precision.
//!     40 |    4 | channel mask    | This specifies the assignment of channels to speaker positions.
//!     44 |   16 | sub format      | For extended wave files, `format` will be set to 0xFFFE to indicate that it's an extended wave file, with the actual format specified here as a [GUID][4]. The first two bytes are the same as specified in `format code`, and the remainder should match 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, and 0x71.
//!
//! The MSDN docs recommend this format for files with more than two channels
//! or more than 16 bits per sample, but it's also possible to encounter such
//! wave files that don't include these extra fields. In my testing, Android
//! Marshmallow was able to play back 24-bit PCM wave files using both the
//! standard format and the extensible format, generated using [Audacity][5].
//!
//! ## The "data" subchunk
//!
//! The "data" subchunk contains the actual audio data:
//!
//! Offset | Size | Data            | Description
//! -----: | ---: | --------------- | -----------------------------------------
//! 36+    |    4 | "data"          | Identifies this subchunk
//! 40+    |    4 | subchunk size   | The size of this chunk. For the simple "canonical" wave file format, this will generally be the size of the file minus 44 bytes for the header data, up to and including this field.
//! 44+    |  ... | audio data      | This stores the actual audio data.
//! ...    |  ... | padding byte    | If the length of audio data is an odd number, then an additional padding byte should be inserted.
//!
//! As the subchunk size is a 32-bit value, the length of audio data cannot
//! exceed 4 GiB, and indeed the entire file can't really exceed 4 GiB as the
//! master RIFF chunk size field is also a 32-bit value.
//!
//! ## Additional meta-data
//!
//! Wave files may also contain other metadata, such as the LIST INFO chunks
//! defined by RIFF or other metadata. The LIST INFO chunk is analogous to
//! the ID3 tag in an MP3 file, and if it's present, it can often be found
//! between the "fmt " and "data" subchunks or after the end of the "data"
//! subchunk.
//!
//! See also:
//!
//! * [WAVEFORMATEXTENSIBLE structure][6]
//! * [Audio File Format Specifications][7]
//! * [WAVE PCM soundfile format][8]
//!
//! [1]: https://github.com/ruud-v-a/hound
//! [2]: https://www.aelius.com/njh/wavemetatools/doc/riffmci.pdf
//! [3]: http://www.neurophys.wisc.edu/auditory/riff-format.txt
//! [4]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa373931(v=vs.85).aspx
//! [5]: http://www.audacityteam.org
//! [6]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd757714(v=vs.85).aspx
//! [7]: http://www-mmsp.ece.mcgill.ca/documents/audioformats/wave/wave.html
//! [8]: http://soundfile.sapp.org/doc/WaveFormat/

extern crate byteorder;

// This is a helper macro that helps us validate results in our tests. It has
// to be defined before the mod definitions below so that it's visible in those
// mods.
// Thank you bluss and durka42!
#[cfg(test)]
macro_rules! assert_matches {
    ($expected:pat $(if $guard:expr)*, $value:expr) => {
        match $value {
            $expected $(if $guard)* => {},
            ref actual => {
                panic!("assertion failed: `(left matches right)` (left: `{}`, right: `{:?}`",
                    stringify!($expected), actual);
            },
        }
    };
}

mod reader;
mod writer;

pub use self::reader::{ReadError, ReadErrorKind, ReadResult, WaveReader};
pub use self::writer::{WaveWriter, WriteError, WriteResult};

pub const FORMAT_UNCOMPRESSED_PCM: u16 = 1;
pub const FORMAT_EXTENDED: u16 = 65534;

pub const MIN_I24_VALUE: i32 = -8388608;
pub const MAX_I24_VALUE: i32 = 8388607;

#[derive(Debug)]
pub enum Format {
    UncompressedPcm,
    Extended,
}

#[derive(Debug)]
pub struct PcmFormat {
    pub num_channels: u16,
    pub sample_rate: u32,
    pub bits_per_sample: u16,
}
<|endoftext|>


<commit_before>mod travis;
mod circle;

use std::env;

#[derive(PartialEq, Debug)]
enum CiService {
    Travis,
    Circle,
    Unknown,
}

macro_rules! err {
    ($expr:expr) => {
        match $expr {
            Ok(val) => Some(val),
            Err(e) => match e {
                ::std::env::VarError::NotPresent => None,
                _ => panic!(e),
            }
        }
    }
}

macro_rules! lang_version {
    ($lang:expr, $name:ident) => {
        /// **Travis only**: Returns the $lang version that is used.
        fn $name(&self) -> Option<String> {
            match self.service {
                CiService::Travis => err!(env::var(format!("TRAVIS_{}_VERSION", $lang))),
                _ => None,
            }
        }
    }
}

struct Ci {
    service: CiService,
}
impl Ci {
    fn new() -> Option<Self> {
        let s = Ci::which_ci();
        match s {
            CiService::Travis | CiService::Circle => Some(Ci { service: s }),
            _ => None,
        }
    }

    fn which_ci() -> CiService {
        match (err!(env::var("TRAVIS")), err!(env::var("CIRCLECI"))) {
            (Some(_), None) => CiService::Travis,
            (None, Some(_)) => CiService::Circle,
            _ => CiService::Unknown,
        }
    }

    /// Returns the locale setting, g.e. `en_US.UTF-8`.
    fn lang() -> Option<String> {
        err!(env::var("LANG"))
    }

    /// Returns the search path.
    fn path() -> Option<String> {
        err!(env::var("PATH"))
    }

    /// Returns the path to the users home directory.
    fn home() -> Option<String> {
        err!(env::var("HOME"))
    }

    fn is_travis(&self) -> bool {
        match self.service {
            CiService::Travis => true,
            _ => false,
        }
    }

    fn is_circle(&self) -> bool {
        match self.service {
            CiService::Circle => true,
            _ => false,
        }
    }

    fn branch(&self) -> Option<String> {
        match self.service {
            CiService::Circle => err!(env::var("CIRCLE_BRANCH")),
            CiService::Travis => err!(env::var("TRAVIS_BRANCH")),
            _ => None,
        }
    }

    /// **Circle only**
    /// A permanent link to the current build, for example,
    /// https://circleci.com/gh/circleci/frontend/933
    fn build_url(&self) -> Option<String> {
        match self.service {
            CiService::Circle => err!(env::var("CIRCLE_BUILD_URL")),
            _ => None,
        }
    }

    /// Returns the build number.
    /// TODO: convert this to a number.
    fn build_id(&self) -> Option<String> {
        match self.service {
            CiService::Circle => err!(env::var("CIRCLE_BUILD_NUM")),
            CiService::Travis => err!(env::var("TRAVIS_BUILD_NUMBER")),
            _ => None,
        }
    }

    /// The sha1 hash of the commit being tested.
    fn commit(&self) -> Option<String> {
        match self.service {
            CiService::Circle => err!(env::var("CIRCLE_SHA1")),
            CiService::Travis => err!(env::var("TRAVIS_COMMIT")),
            _ => None,
        }
    }

    /// The number of the pull request this build forms part of.
    /// If this build is not part of a pull request, `None` is returned.
    /// TODO: convert this to a number.
    fn pull_request(&self) -> Option<String> {
        match self.service {
            CiService::Circle => err!(env::var("CIRCLE_PR_NUMBER")),
            CiService::Travis => {
                let pr = err!(env::var("TRAVIS_PULL_REQUEST")).unwrap_or("false".to_string());
                if pr == "false" {
                    None
                } else {
                    Some(pr)
                }
            }
            _ => None,
        }
    }

    lang_version!("DART", dart);
    lang_version!("GO", go);
    lang_version!("HAXE", haxe);
    lang_version!("JDK", java);
    lang_version!("JULIA", julia);
    lang_version!("NODE", node);
    lang_version!("OTP", otp);
    lang_version!("PERL", perl);
    lang_version!("PHP", php);
    lang_version!("PYTHON", python);
    lang_version!("R", r);
    lang_version!("RUBY", ruby);
    lang_version!("RUST", rust);
    lang_version!("SCALA", scala);
}

fn ci() -> bool {
    err!(env::var("CI")).is_some() || err!(env::var("CONTINUOUS_INTEGRATION")).is_some()
}

#[test]
fn ci_test_unknown() {
    let ci = Ci::new();
    if ci.is_some() {
        return;
    }
    assert_eq!(Ci::which_ci(), CiService::Unknown);
}
<commit_msg>Add travis specific `build_dir`<commit_after>mod travis;
mod circle;

use std::env;

#[derive(PartialEq, Debug)]
enum CiService {
    Travis,
    Circle,
    Unknown,
}

macro_rules! err {
    ($expr:expr) => {
        match $expr {
            Ok(val) => Some(val),
            Err(e) => match e {
                ::std::env::VarError::NotPresent => None,
                _ => panic!(e),
            }
        }
    }
}

macro_rules! lang_version {
    ($lang:expr, $name:ident) => {
        /// **Travis only**: Returns the $lang version that is used.
        fn $name(&self) -> Option<String> {
            match self.service {
                CiService::Travis => err!(env::var(format!("TRAVIS_{}_VERSION", $lang))),
                _ => None,
            }
        }
    }
}

struct Ci {
    service: CiService,
}
impl Ci {
    fn new() -> Option<Self> {
        let s = Ci::which_ci();
        match s {
            CiService::Travis | CiService::Circle => Some(Ci { service: s }),
            _ => None,
        }
    }

    fn which_ci() -> CiService {
        match (err!(env::var("TRAVIS")), err!(env::var("CIRCLECI"))) {
            (Some(_), None) => CiService::Travis,
            (None, Some(_)) => CiService::Circle,
            _ => CiService::Unknown,
        }
    }

    /// Returns the locale setting, g.e. `en_US.UTF-8`.
    fn lang() -> Option<String> {
        err!(env::var("LANG"))
    }

    /// Returns the search path.
    fn path() -> Option<String> {
        err!(env::var("PATH"))
    }

    /// Returns the path to the users home directory.
    fn home() -> Option<String> {
        err!(env::var("HOME"))
    }

    fn is_travis(&self) -> bool {
        match self.service {
            CiService::Travis => true,
            _ => false,
        }
    }

    fn is_circle(&self) -> bool {
        match self.service {
            CiService::Circle => true,
            _ => false,
        }
    }

    fn branch(&self) -> Option<String> {
        match self.service {
            CiService::Circle => err!(env::var("CIRCLE_BRANCH")),
            CiService::Travis => err!(env::var("TRAVIS_BRANCH")),
            _ => None,
        }
    }

    /// **Circle only**
    /// A permanent link to the current build, for example,
    /// https://circleci.com/gh/circleci/frontend/933
    fn build_url(&self) -> Option<String> {
        match self.service {
            CiService::Circle => err!(env::var("CIRCLE_BUILD_URL")),
            _ => None,
        }
    }

    /// Returns the build number.
    /// TODO: convert this to a number.
    fn build_id(&self) -> Option<String> {
        match self.service {
            CiService::Circle => err!(env::var("CIRCLE_BUILD_NUM")),
            CiService::Travis => err!(env::var("TRAVIS_BUILD_NUMBER")),
            _ => None,
        }
    }

    /// **Travis only**: The absolute path to the directory where the repository
    /// being built has been copied on the worker.
    /// TODO: Return a filesystem path instead?
    fn build_dir(&self) -> Option<String> {
        match self.service {
            CiService::Travis => err!(env::var("TRAVIS_BUILD_DIR")),
            _ => None,
        }
    }

    /// The sha1 hash of the commit being tested.
    fn commit(&self) -> Option<String> {
        match self.service {
            CiService::Circle => err!(env::var("CIRCLE_SHA1")),
            CiService::Travis => err!(env::var("TRAVIS_COMMIT")),
            _ => None,
        }
    }

    /// The number of the pull request this build forms part of.
    /// If this build is not part of a pull request, `None` is returned.
    /// TODO: convert this to a number.
    fn pull_request(&self) -> Option<String> {
        match self.service {
            CiService::Circle => err!(env::var("CIRCLE_PR_NUMBER")),
            CiService::Travis => {
                let pr = err!(env::var("TRAVIS_PULL_REQUEST")).unwrap_or("false".to_string());
                if pr == "false" {
                    None
                } else {
                    Some(pr)
                }
            }
            _ => None,
        }
    }

    lang_version!("DART", dart);
    lang_version!("GO", go);
    lang_version!("HAXE", haxe);
    lang_version!("JDK", java);
    lang_version!("JULIA", julia);
    lang_version!("NODE", node);
    lang_version!("OTP", otp);
    lang_version!("PERL", perl);
    lang_version!("PHP", php);
    lang_version!("PYTHON", python);
    lang_version!("R", r);
    lang_version!("RUBY", ruby);
    lang_version!("RUST", rust);
    lang_version!("SCALA", scala);
}

fn ci() -> bool {
    err!(env::var("CI")).is_some() || err!(env::var("CONTINUOUS_INTEGRATION")).is_some()
}

#[test]
fn ci_test_unknown() {
    let ci = Ci::new();
    if ci.is_some() {
        return;
    }
    assert_eq!(Ci::which_ci(), CiService::Unknown);
}
<|endoftext|>


<commit_before>#![warn(missing_docs)]
#![doc(html_logo_url = "http://lipanski.github.io/mockito/logo-black.png",
    html_root_url = "http://lipanski.github.io/mockito/docs/mockito/index.html")]

//!
//! Mockito is a library for creating HTTP mocks to be used in (integration) tests or for offline work.
//! It runs an HTTP server on your local port 1234 and can register and remove mocks.
//! The server is run on a separate thread within the same process and will be cleaned up
//! at the end of the run.
//!
//! # Getting Started
//!
//! Using compiler flags, set the URL of your web client to `mockito::SERVER_URL` or `mockito::SERVER_ADDRESS`.
//!
//! # Example
//!
//! ```
//! #[cfg(test)]
//! use mockito::SERVER_URL;
//!
//! #[cfg(not(test))]
//! const URL: &'static str = "https://api.twitter.com";
//!
//! #[cfg(test)]
//! const URL: &'static str = mockito::SERVER_URL;
//! ```
//!
//! Then start mocking:
//!
//! # Example
//!
//! ```
//! #[cfg(test)]
//! mod tests {
//!   use mockito::mock;
//!
//!   #[test]
//!   fn test_something() {
//!     mock("GET", "/hello")
//!       .with_status(201)
//!       .with_header("content-type", "text/plain")
//!       .with_body("world")
//!       .create();
//!
//!     // Any calls to GET /hello beyond this line will respond with 201, the
//!     // `content-type: text/plain` header and the body "world".
//!   }
//! }
//! ```
//!
//! Mockito currently matches by method and path, but also by headers. The header field letter case is ignored.
//!
//! # Example
//!
//! ```
//! use mockito::mock;
//!
//! mock("GET", "/hello")
//!   .match_header("content-type", "application/json")
//!   .with_body("{'hello': 'world'}")
//!   .create();
//!
//! mock("GET", "/hello")
//!   .match_header("content-type", "text/plain")
//!   .with_body("world")
//!   .create();
//!
//! // JSON requests to GET /hello will respond with JSON, while plain requests
//! // will respond with text.
//! ```
//!
//! Even though **mocks are matched in reverse order** (most recent one wins), in some situations
//! it might be useful to clean up right after the test. There are multiple ways of doing this:
//!
//! - By using a closure:
//!
//! # Example
//!
//! ```
//! use mockito::mock;
//!
//! mock("GET", "/hello")
//!   .with_body("world")
//!   .create_for(|| {
//!     // mock only valid for the lifetime of this closure
//!     // NOTE: it might still be accessible by separate threads
//!   });
//! ```
//!
//! - By calling `remove()` on the mock:
//!
//! # Example
//!
//! ```
//! use mockito::mock;
//!
//! let mut mock = mock("GET", "/hello");
//! mock.with_body("world").create();
//!
//! // do your thing
//!
//! mock.remove();
//! ```
//!
//! - By calling `reset()` to **remove all mocks**:
//!
//! # Example
//!
//! ```
//! use mockito::reset;
//!
//! reset();
//! ```
//!

extern crate hyper;
extern crate rustc_serialize;
extern crate rand;

mod server;

use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use hyper::client::Client;
use hyper::server::Request;
use hyper::header::{Headers, ContentType, Connection};
use rustc_serialize::json;
use rustc_serialize::{Encodable};
use rand::{thread_rng, Rng};

///
/// Points to the address the mock server is running at.
/// Can be used with `std::net::TcpStream`.
///
pub const SERVER_ADDRESS: &'static str = "0.0.0.0:1234";

///
/// Points to the URL the mock server is running at.
///
pub const SERVER_URL: &'static str = "http://0.0.0.0:1234";

///
/// Initializes a mock for the provided `method` and `path`.
///
/// The mock is registered to the server only after the `create()` method has been called.
///
/// # Example
///
/// ```
/// use mockito::mock;
///
/// mock("GET", "/");
/// mock("POST", "/users");
/// mock("DELETE", "/users?id=1");
/// ```
///
pub fn mock(method: &str, path: &str) -> Mock {
    Mock::new(method, path)
}

///
/// Removes all the mocks stored on the server.
///
pub fn reset() {
    server::try_start();

    Client::new()
        .delete(&[SERVER_URL, "/mocks"].join(""))
        .send()
        .unwrap();
}

///
/// Stores information about a mocked request. Should be initialized via `mockito::mock()`.
///
#[derive(PartialEq, Debug)]
pub struct Mock {
    id: String,
    method: String,
    path: String,
    headers: HashMap<String, String>,
    response: MockResponse,
}

impl Mock {
    fn new(method: &str, path: &str) -> Self {
        Mock {
            id: thread_rng().gen_ascii_chars().take(24).collect(),
            method: method.to_owned().to_uppercase(),
            path: path.to_owned(),
            headers: HashMap::new(),
            response: MockResponse::new(),
        }
    }

    ///
    /// Allows matching a particular request header when responding with a mock.
    ///
    /// When matching a request, the field letter case is ignored.
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// mock("GET", "/").match_header("content-type", "application/json");
    /// ```
    ///
    /// Like most other `Mock` methods, it allows chanining:
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// mock("GET", "/")
    ///   .match_header("content-type", "application/json")
    ///   .match_header("authorization", "password");
    /// ```
    ///
    pub fn match_header(&mut self, field: &str, value: &str) -> &mut Self {
        self.headers.insert(field.to_owned(), value.to_owned());

        self
    }

    ///
    /// Sets the status code of the mock response. The default status code is 200.
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// mock("GET", "/").with_status(201);
    /// ```
    ///
    pub fn with_status(&mut self, status: usize) -> &mut Self {
        self.response.status = status;

        self
    }

    ///
    /// Sets a header of the mock response.
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// mock("GET", "/").with_header("content-type", "application/json");
    /// ```
    ///
    pub fn with_header(&mut self, field: &str, value: &str) -> &mut Self {
        self.response.headers.insert(field.to_owned(), value.to_owned());

        self
    }

    ///
    /// Sets the body of the mock response. Its `Content-Length` is handled automatically.
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// mock("GET", "/").with_body("hello world");
    /// ```
    ///
    pub fn with_body(&mut self, body: &str) -> &mut Self {
        self.response.body = body.to_owned();

        self
    }

    ///
    /// Sets the body of the mock response from the contents of a file stored under `path`.
    /// Its `Content-Length` is handled automatically.
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// mock("GET", "/").with_body_from_file("tests/files/simple.http");
    /// ```
    ///
    pub fn with_body_from_file(&mut self, path: &str) -> &mut Self {
        let mut file = File::open(path).unwrap();
        let mut body = String::new();

        file.read_to_string(&mut body).unwrap();

        self.response.body = body;

        self
    }

    ///
    /// Registers the mock to the server - your mock will be served only after calling this method.
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// mock("GET", "/").with_body("hello world").create();
    /// ```
    ///
    pub fn create(&mut self) -> &mut Self {
        server::try_start();

        let mut headers = Headers::new();
        headers.set_raw("x-mock-id", vec!(self.id.as_bytes().to_vec()));
        headers.set_raw("x-mock-method", vec!(self.method.as_bytes().to_vec()));
        headers.set_raw("x-mock-path", vec!(self.path.as_bytes().to_vec()));

        for (field, value) in &self.headers {
            headers.set_raw("x-mock-".to_string() + field, vec!(value.as_bytes().to_vec()));
        }

        let body = json::encode(&self.response).unwrap();
        Client::new()
            .post(&[SERVER_URL, "/mocks"].join(""))
            .headers(headers)
            .header(ContentType::json())
            .header(Connection::close())
            .body(&body)
            .send()
            .unwrap();

        self
    }

    ///
    /// Registers the mock to the server, executes the passed closure and removes the mock afterwards.
    ///
    /// **NOTE:** During the closure lifetime, the mock might still be available to seperate threads.
    ///
    /// # Example
    ///
    /// ```
    /// use std::thread::{sleep};
    /// use std::time::Duration;
    /// use mockito::mock;
    ///
    /// mock("GET", "/").with_body("hello world").create_for(|| {
    ///   // This mock will only be available for the next 10 seconds
    ///   sleep(Duration::new(10, 0));
    /// });
    /// ```
    ///
    pub fn create_for<F: Fn() -> ()>(&mut self, environment: F) -> &mut Self {
        self.create();
        environment();
        self.remove();

        self
    }

    ///
    /// Removes the current mock from the server.
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// let mut mock = mock("GET", "/");
    /// mock.with_body("hello world").create();
    ///
    /// // stuff
    ///
    /// mock.remove();
    /// ```
    ///
    pub fn remove(&self) {
        server::try_start();

        let mut headers = Headers::new();
        headers.set_raw("x-mock-id", vec!(self.id.as_bytes().to_vec()));

        Client::new()
            .delete(&[SERVER_URL, "/mocks"].join(""))
            .headers(headers)
            .header(Connection::close())
            .send()
            .unwrap();
    }

    #[allow(missing_docs)]
    pub fn matches(&self, request: &Request) -> bool {
        self.method_matches(request)
            && self.path_matches(request)
            && self.headers_match(request)
    }

    fn method_matches(&self, request: &Request) -> bool {
        self.method == request.method.to_string().to_uppercase()
    }

    fn path_matches(&self, request: &Request) -> bool {
        self.path == request.uri.to_string()
    }

    fn headers_match(&self, request: &Request) -> bool {
        for (field, value) in self.headers.iter() {
            match request.headers.get_raw(&field) {
                Some(request_header_value) => {
                    let bytes: Vec<u8> = request_header_value.iter().flat_map(|el| el.iter().cloned()).collect();

                    if value == &String::from_utf8(bytes).unwrap() { continue }

                    return false
                },
                _ => return false
            }
        }

        true
    }
}

const DEFAULT_RESPONSE_STATUS: usize = 200;

#[derive(RustcDecodable, RustcEncodable, Debug, PartialEq)]
struct MockResponse {
    status: usize,
    headers: HashMap<String, String>,
    body: String,
}

impl MockResponse {
    pub fn new() -> Self {
        MockResponse {
            status: DEFAULT_RESPONSE_STATUS,
            headers: HashMap::new(),
            body: String::new(),
        }
    }
}
<commit_msg>Change example for use mockito in docs<commit_after>#![warn(missing_docs)]
#![doc(html_logo_url = "http://lipanski.github.io/mockito/logo-black.png",
    html_root_url = "http://lipanski.github.io/mockito/docs/mockito/index.html")]

//!
//! Mockito is a library for creating HTTP mocks to be used in (integration) tests or for offline work.
//! It runs an HTTP server on your local port 1234 and can register and remove mocks.
//! The server is run on a separate thread within the same process and will be cleaned up
//! at the end of the run.
//!
//! # Getting Started
//!
//! Using compiler flags, set the URL of your web client to `mockito::SERVER_URL` or `mockito::SERVER_ADDRESS`.
//!
//! # Example
//!
//! ```
//! #[cfg(test)]
//! use mockito;
//!
//! #[cfg(not(test))]
//! const URL: &'static str = "https://api.twitter.com";
//!
//! #[cfg(test)]
//! const URL: &'static str = mockito::SERVER_URL;
//! ```
//!
//! Then start mocking:
//!
//! # Example
//!
//! ```
//! #[cfg(test)]
//! mod tests {
//!   use mockito::mock;
//!
//!   #[test]
//!   fn test_something() {
//!     mock("GET", "/hello")
//!       .with_status(201)
//!       .with_header("content-type", "text/plain")
//!       .with_body("world")
//!       .create();
//!
//!     // Any calls to GET /hello beyond this line will respond with 201, the
//!     // `content-type: text/plain` header and the body "world".
//!   }
//! }
//! ```
//!
//! Mockito currently matches by method and path, but also by headers. The header field letter case is ignored.
//!
//! # Example
//!
//! ```
//! use mockito::mock;
//!
//! mock("GET", "/hello")
//!   .match_header("content-type", "application/json")
//!   .with_body("{'hello': 'world'}")
//!   .create();
//!
//! mock("GET", "/hello")
//!   .match_header("content-type", "text/plain")
//!   .with_body("world")
//!   .create();
//!
//! // JSON requests to GET /hello will respond with JSON, while plain requests
//! // will respond with text.
//! ```
//!
//! Even though **mocks are matched in reverse order** (most recent one wins), in some situations
//! it might be useful to clean up right after the test. There are multiple ways of doing this:
//!
//! - By using a closure:
//!
//! # Example
//!
//! ```
//! use mockito::mock;
//!
//! mock("GET", "/hello")
//!   .with_body("world")
//!   .create_for(|| {
//!     // mock only valid for the lifetime of this closure
//!     // NOTE: it might still be accessible by separate threads
//!   });
//! ```
//!
//! - By calling `remove()` on the mock:
//!
//! # Example
//!
//! ```
//! use mockito::mock;
//!
//! let mut mock = mock("GET", "/hello");
//! mock.with_body("world").create();
//!
//! // do your thing
//!
//! mock.remove();
//! ```
//!
//! - By calling `reset()` to **remove all mocks**:
//!
//! # Example
//!
//! ```
//! use mockito::reset;
//!
//! reset();
//! ```
//!

extern crate hyper;
extern crate rustc_serialize;
extern crate rand;

mod server;

use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use hyper::client::Client;
use hyper::server::Request;
use hyper::header::{Headers, ContentType, Connection};
use rustc_serialize::json;
use rustc_serialize::{Encodable};
use rand::{thread_rng, Rng};

///
/// Points to the address the mock server is running at.
/// Can be used with `std::net::TcpStream`.
///
pub const SERVER_ADDRESS: &'static str = "0.0.0.0:1234";

///
/// Points to the URL the mock server is running at.
///
pub const SERVER_URL: &'static str = "http://0.0.0.0:1234";

///
/// Initializes a mock for the provided `method` and `path`.
///
/// The mock is registered to the server only after the `create()` method has been called.
///
/// # Example
///
/// ```
/// use mockito::mock;
///
/// mock("GET", "/");
/// mock("POST", "/users");
/// mock("DELETE", "/users?id=1");
/// ```
///
pub fn mock(method: &str, path: &str) -> Mock {
    Mock::new(method, path)
}

///
/// Removes all the mocks stored on the server.
///
pub fn reset() {
    server::try_start();

    Client::new()
        .delete(&[SERVER_URL, "/mocks"].join(""))
        .send()
        .unwrap();
}

///
/// Stores information about a mocked request. Should be initialized via `mockito::mock()`.
///
#[derive(PartialEq, Debug)]
pub struct Mock {
    id: String,
    method: String,
    path: String,
    headers: HashMap<String, String>,
    response: MockResponse,
}

impl Mock {
    fn new(method: &str, path: &str) -> Self {
        Mock {
            id: thread_rng().gen_ascii_chars().take(24).collect(),
            method: method.to_owned().to_uppercase(),
            path: path.to_owned(),
            headers: HashMap::new(),
            response: MockResponse::new(),
        }
    }

    ///
    /// Allows matching a particular request header when responding with a mock.
    ///
    /// When matching a request, the field letter case is ignored.
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// mock("GET", "/").match_header("content-type", "application/json");
    /// ```
    ///
    /// Like most other `Mock` methods, it allows chanining:
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// mock("GET", "/")
    ///   .match_header("content-type", "application/json")
    ///   .match_header("authorization", "password");
    /// ```
    ///
    pub fn match_header(&mut self, field: &str, value: &str) -> &mut Self {
        self.headers.insert(field.to_owned(), value.to_owned());

        self
    }

    ///
    /// Sets the status code of the mock response. The default status code is 200.
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// mock("GET", "/").with_status(201);
    /// ```
    ///
    pub fn with_status(&mut self, status: usize) -> &mut Self {
        self.response.status = status;

        self
    }

    ///
    /// Sets a header of the mock response.
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// mock("GET", "/").with_header("content-type", "application/json");
    /// ```
    ///
    pub fn with_header(&mut self, field: &str, value: &str) -> &mut Self {
        self.response.headers.insert(field.to_owned(), value.to_owned());

        self
    }

    ///
    /// Sets the body of the mock response. Its `Content-Length` is handled automatically.
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// mock("GET", "/").with_body("hello world");
    /// ```
    ///
    pub fn with_body(&mut self, body: &str) -> &mut Self {
        self.response.body = body.to_owned();

        self
    }

    ///
    /// Sets the body of the mock response from the contents of a file stored under `path`.
    /// Its `Content-Length` is handled automatically.
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// mock("GET", "/").with_body_from_file("tests/files/simple.http");
    /// ```
    ///
    pub fn with_body_from_file(&mut self, path: &str) -> &mut Self {
        let mut file = File::open(path).unwrap();
        let mut body = String::new();

        file.read_to_string(&mut body).unwrap();

        self.response.body = body;

        self
    }

    ///
    /// Registers the mock to the server - your mock will be served only after calling this method.
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// mock("GET", "/").with_body("hello world").create();
    /// ```
    ///
    pub fn create(&mut self) -> &mut Self {
        server::try_start();

        let mut headers = Headers::new();
        headers.set_raw("x-mock-id", vec!(self.id.as_bytes().to_vec()));
        headers.set_raw("x-mock-method", vec!(self.method.as_bytes().to_vec()));
        headers.set_raw("x-mock-path", vec!(self.path.as_bytes().to_vec()));

        for (field, value) in &self.headers {
            headers.set_raw("x-mock-".to_string() + field, vec!(value.as_bytes().to_vec()));
        }

        let body = json::encode(&self.response).unwrap();
        Client::new()
            .post(&[SERVER_URL, "/mocks"].join(""))
            .headers(headers)
            .header(ContentType::json())
            .header(Connection::close())
            .body(&body)
            .send()
            .unwrap();

        self
    }

    ///
    /// Registers the mock to the server, executes the passed closure and removes the mock afterwards.
    ///
    /// **NOTE:** During the closure lifetime, the mock might still be available to seperate threads.
    ///
    /// # Example
    ///
    /// ```
    /// use std::thread::{sleep};
    /// use std::time::Duration;
    /// use mockito::mock;
    ///
    /// mock("GET", "/").with_body("hello world").create_for(|| {
    ///   // This mock will only be available for the next 10 seconds
    ///   sleep(Duration::new(10, 0));
    /// });
    /// ```
    ///
    pub fn create_for<F: Fn() -> ()>(&mut self, environment: F) -> &mut Self {
        self.create();
        environment();
        self.remove();

        self
    }

    ///
    /// Removes the current mock from the server.
    ///
    /// # Example
    ///
    /// ```
    /// use mockito::mock;
    ///
    /// let mut mock = mock("GET", "/");
    /// mock.with_body("hello world").create();
    ///
    /// // stuff
    ///
    /// mock.remove();
    /// ```
    ///
    pub fn remove(&self) {
        server::try_start();

        let mut headers = Headers::new();
        headers.set_raw("x-mock-id", vec!(self.id.as_bytes().to_vec()));

        Client::new()
            .delete(&[SERVER_URL, "/mocks"].join(""))
            .headers(headers)
            .header(Connection::close())
            .send()
            .unwrap();
    }

    #[allow(missing_docs)]
    pub fn matches(&self, request: &Request) -> bool {
        self.method_matches(request)
            && self.path_matches(request)
            && self.headers_match(request)
    }

    fn method_matches(&self, request: &Request) -> bool {
        self.method == request.method.to_string().to_uppercase()
    }

    fn path_matches(&self, request: &Request) -> bool {
        self.path == request.uri.to_string()
    }

    fn headers_match(&self, request: &Request) -> bool {
        for (field, value) in self.headers.iter() {
            match request.headers.get_raw(&field) {
                Some(request_header_value) => {
                    let bytes: Vec<u8> = request_header_value.iter().flat_map(|el| el.iter().cloned()).collect();

                    if value == &String::from_utf8(bytes).unwrap() { continue }

                    return false
                },
                _ => return false
            }
        }

        true
    }
}

const DEFAULT_RESPONSE_STATUS: usize = 200;

#[derive(RustcDecodable, RustcEncodable, Debug, PartialEq)]
struct MockResponse {
    status: usize,
    headers: HashMap<String, String>,
    body: String,
}

impl MockResponse {
    pub fn new() -> Self {
        MockResponse {
            status: DEFAULT_RESPONSE_STATUS,
            headers: HashMap::new(),
            body: String::new(),
        }
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#![feature(collections)]

extern crate libc;
extern crate winapi;

pub use ffi::*;

use libc::funcs::extra::kernel32;
use winapi::HANDLE;
use std::{ ptr, mem };

mod ffi;

pub struct Connection {
	// Pointer to the serial connection
	com_handle: HANDLE
}

impl Connection {
	pub fn new(port: &str, baud_rate: u32) -> Result<Connection, &'static str> {
		let (com_handle, cf_result) = unsafe {
			let mut port_u16: Vec<_> = port.utf16_units().collect();
			port_u16.push(0);
			(
				kernel32::CreateFileW(port_u16.as_ptr(),
					winapi::GENERIC_READ | winapi::GENERIC_WRITE,
					0,
					ptr::null_mut(),
					winapi::OPEN_EXISTING,
					winapi::FILE_FLAG_OVERLAPPED,
					ptr::null_mut()),
				kernel32::GetLastError()
			)
		};

		if com_handle == winapi::INVALID_HANDLE_VALUE {
			match cf_result {
				winapi::ERROR_ACCESS_DENIED => Err("Access denied, port might be busy"),
				winapi::ERROR_FILE_NOT_FOUND => Err("COM port does not exist"),
				_ => Err("Invalid COM port handle")
			}
		} else {
			let mut conn = Connection{ com_handle: com_handle };
			match conn.set_baud_rate(baud_rate) {
				Ok(_) => Ok(conn),
				Err(_) => Err("Error setting baud rate"),
			}
		}
	}

	pub fn set_baud_rate(&mut self, baud_rate: u32) -> Result<(), ()> {
		unsafe {
			let mut dcb = mem::zeroed();
			if GetCommState(self.com_handle, &mut dcb) == 0 {
				Err(())
			} else {
				dcb.BaudRate = baud_rate;
				if SetCommState(self.com_handle, &mut dcb) == 0 {
					Err(())
				} else {
					Ok(())
				}
			}
		}
	}
}

#[test]
fn test() {
	let con = Connection::new("COM8", 9600).unwrap();
}<commit_msg>impl Read for Connection<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#![feature(collections)]

extern crate libc;
extern crate winapi;

pub use ffi::*;

use libc::funcs::extra::kernel32;
use libc::c_void;
use winapi::HANDLE;
use std::{ ptr, mem, io };
use std::io::{Error, ErrorKind};

mod ffi;

pub struct Connection {
	// Pointer to the serial connection
	comm_handle: HANDLE
}

impl Connection {
	pub fn new(port: &str, baud_rate: u32) -> io::Result<Connection> {
		let (comm_handle, cf_result) = unsafe {
			let mut port_u16: Vec<_> = port.utf16_units().collect();
			port_u16.push(0);
			(
				kernel32::CreateFileW(port_u16.as_ptr(),
					winapi::GENERIC_READ | winapi::GENERIC_WRITE,
					0,
					ptr::null_mut(),
					winapi::OPEN_EXISTING,
					0,
					ptr::null_mut()),
				kernel32::GetLastError()
			)
		};

		if comm_handle == winapi::INVALID_HANDLE_VALUE {
			Err(match cf_result {
				winapi::ERROR_ACCESS_DENIED =>
					Error::new(ErrorKind::AlreadyExists, "Access denied, port might be busy"),
				winapi::ERROR_FILE_NOT_FOUND =>
					Error::new(ErrorKind::NotFound, "COM port does not exist"),
				_ => Error::new(ErrorKind::Other, "Invalid COM port handle")
			})
		} else {
			let mut conn = Connection{ comm_handle: comm_handle };
			match conn.set_baud_rate(baud_rate) {
				Ok(_) => Ok(conn),
				Err(e) => Err(Error::new(ErrorKind::Other, "Error setting baud rate")),
			}
		}
	}

	pub fn set_baud_rate(&mut self, baud_rate: u32) -> Result<(), ()> {
		unsafe {
			let mut dcb = mem::zeroed();
			if GetCommState(self.comm_handle, &mut dcb) <= 0 {
				Err(())
			} else {
				dcb.BaudRate = baud_rate;
				if SetCommState(self.comm_handle, &mut dcb) <= 0 {
					Err(())
				} else {
					Ok(())
				}
			}
		}
	}
}
impl io::Read for Connection {
	fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
		let mut n_bytes_read = 0;

		let (succeded, err) = unsafe { (
			kernel32::ReadFile(self.comm_handle,
				buf.as_mut_ptr() as *mut c_void,
				buf.len() as u32,
				&mut n_bytes_read,
				ptr::null_mut()) > 0,
			kernel32::GetLastError()
		) };

		if succeded {
			Ok(n_bytes_read as usize)
		} else {
			Err(match err {
				winapi::ERROR_INVALID_USER_BUFFER =>
					Error::new(ErrorKind::InvalidInput, "Supplied buffer is invalid"),
				winapi::ERROR_NOT_ENOUGH_MEMORY =>
					Error::new(ErrorKind::Other, "Too many I/O requests"),
				winapi::ERROR_OPERATION_ABORTED =>
					Error::new(ErrorKind::Interrupted, "Operation was canceled"),
				_ => Error::new(ErrorKind::Other, format!("Read failed with 0x{:x}", err))
			})
		}
	}
}

#[test]
fn test() {
	let con = Connection::new("COM8", 9600).unwrap();
}<|endoftext|>