<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
//!
//! This library does not have any dependencies as it just exports macros for use in your
//! testing modules. This is also required to prevent version incompatibilities between
//! a vulkano which would be used here and your project-local vulkano.
//!
//! Due to the use of utility function and macros 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:
//!
//! ```
//! #[macro_use]
//! 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)]

/// Creates a `vulkano::Instance`. Does not enable any instance extensions.
///
/// # Panics
///
/// Panics if the vulkano instance loading procedure fails.
///
/// # Example
///
/// ```
/// # // These tests du not require vulkano-macros,
/// # // therefore the `macro_use` will be omitted here, unless required.
/// # 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
///
/// ```
/// # #[macro_use]
/// # 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>Fix formatting<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
//!
//! This library does not have any dependencies as it just exports macros for use in your
//! testing modules. This is also required to prevent version incompatibilities between
//! a vulkano which would be used here and your project-local vulkano.
//!
//! Due to the use of utility function and macros 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:
//!
//! ```
//! #[macro_use]
//! 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)]

/// Creates a `vulkano::Instance`. Does not enable any instance extensions.
///
/// # Panics
///
/// Panics if the vulkano instance loading procedure fails.
///
/// # Example
///
/// ```
/// # // These tests du not require vulkano-macros,
/// # // therefore the `macro_use` will be omitted here, unless required.
/// # 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
///
/// ```
/// # #[macro_use]
/// # 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();
        };
    }
}
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

include!("bindings.rs");

use std::ffi::CStr;

pub fn safe_clingo_version() -> (i32, i32, i32) {
    let mut m1 = 0;
    let ma = &mut m1 as *mut c_int;

    let mut m2 = 0;
    let mi = &mut m2 as *mut c_int;

    let mut m3 = 0;
    let re = &mut m3 as *mut c_int;

    unsafe { clingo_version(ma, mi, re) };

    let major = unsafe { *ma };
    let minor = unsafe { *mi };
    let revision = unsafe { *re };
    (major, minor, revision)
}

// pub fn safe_clingo_control_new2(arguments: std::env::Args,
//                                logger: clingo_logger_t,
//                                logger_data: *mut c_void,
//                                message_limit: ::std::os::raw::c_uint
//                               )
//                               -> std::option::Option< &mut clingo_control_t> {
//
//     let mut ctl = std::ptr::null_mut() as *mut clingo_control_t;
//     let control = &mut ctl as *mut *mut clingo_control_t;
//     let arguments_size = arguments.len()-1;
//     // create a vector of zero terminated strings
//     let args = arguments.map(|arg| CString::new(arg).unwrap() ).collect::<Vec<CString>>();
//     // convert the strings to raw pointers
//     let c_args = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<*const c_char>>();
//
//     unsafe {
//              println!("x1{:?}",control);
//              println!("x2{:?}",*control);
//              let ret = clingo_control_new(c_args.as_ptr(),
//                                           arguments_size,
//                                           logger,
//                                           logger_data,
//                                           message_limit,
//                                           control);
//
//              println!("y1{:?}",control);
//              println!("y2{:?}",*control);
//
//              if ret == 0 { None }
//              else { Some(*control) }
//    }
// }

pub fn safe_clingo_control_new(arguments: std::env::Args,
                               logger: clingo_logger_t,
                               logger_data: *mut c_void,
                               message_limit: ::std::os::raw::c_uint)
                               -> std::option::Option<*mut clingo_control_t> {

    let mut ctl = std::ptr::null_mut() as *mut clingo_control_t;
    let control = &mut ctl as *mut *mut clingo_control_t;
    let arguments_size = arguments.len() - 1;
    // create a vector of zero terminated strings
    let args = arguments.map(|arg| CString::new(arg).unwrap()).collect::<Vec<CString>>();
    // convert the strings to raw pointers
    let c_args = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<*const c_char>>();

    unsafe {
        let ret = clingo_control_new(c_args.as_ptr(),
                                     arguments_size,
                                     logger,
                                     logger_data,
                                     message_limit,
                                     control);
        if ret == 0 {
            None
        } else {
            Some(*control)
        }
    }
}

pub fn safe_clingo_control_add(control: *mut clingo_control_t,
                               name: &str,
                               parameters: Vec<&str>,
                               program: &str)
                               -> bool {

    let mname = CString::new(name).unwrap();
    let mprogram = CString::new(program).unwrap();
    let parameters_size = parameters.len();
    // create a vector of zero terminated strings
    let args =
        parameters.into_iter().map(|arg| CString::new(arg).unwrap()).collect::<Vec<CString>>();
    // convert the strings to raw pointers
    let c_args = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<*const c_char>>();

    unsafe {
        clingo_control_add(control,
                           mname.as_ptr(),
                           c_args.as_ptr(),
                           parameters_size,
                           mprogram.as_ptr()) == 1
    }
}

pub struct safe_clingo_part {
    pub params: clingo_symbol_t,
    pub size: size_t,
    pub name: CString,
}
fn from_clingo_part(spart: &safe_clingo_part) -> clingo_part {
    clingo_part {
        name: spart.name.as_ptr(),
        params: &spart.params,
        size: spart.size,
    }
}

pub fn safe_clingo_control_ground(control: *mut clingo_control_t,
                                  sparts: Vec<safe_clingo_part>,
                                  ground_callback: clingo_ground_callback_t,
                                  ground_callback_data: *mut c_void)
                                  -> bool {

    let parts = sparts.iter().map(|arg| from_clingo_part(arg)).collect::<Vec<clingo_part>>();
    let parts_size = parts.len();

    unsafe {
        clingo_control_ground(control,
                              parts.as_ptr(),
                              parts_size,
                              ground_callback,
                              ground_callback_data) == 1
    }
}
pub fn safe_clingo_control_solve(control: *mut clingo_control_t,
                                 model_callback: clingo_model_callback_t,
                                 model_callback_data: *mut c_void,
                                 assumptions: Vec<clingo_symbolic_literal_t>,
                                 result: *mut clingo_solve_result_bitset_t)
                                 -> bool {
    let assumptions_size = assumptions.len();
    unsafe {
        clingo_control_solve(control,
                             model_callback,
                             model_callback_data,
                             assumptions.as_ptr(),
                             assumptions_size,
                             result) == 1
    }
}
pub fn safe_clingo_control_free(control: *mut *mut clingo_control_t) {
    unsafe { clingo_control_free(*control) }
}
pub fn safe_clingo_error_code() -> clingo_error_t {
    unsafe { clingo_error_code() }
}
pub fn safe_clingo_error_message() -> &'static str {
    unsafe {
        let c_buf: *const c_char = clingo_error_message();
        println!("h1{:?}", c_buf);
        if c_buf.is_null() {
            return "";
        } else {
            let c_str = CStr::from_ptr(c_buf);
            println!("h2{:?}", c_str);
            let blub = c_str.to_str();
            println!("hh{:?}", blub);
            return blub.unwrap();
        }
    }
}

pub fn safe_clingo_model_symbols(model: *mut clingo_model_t,
                                 show: clingo_show_type)
                                 -> std::result::Result<Vec<clingo_symbol_t>, u8> {

    let ishow = show as u32;
    let mut size: usize = 0;
    let size_p = &mut size as *mut usize;
    unsafe {
        let err1 = clingo_model_symbols_size(model, ishow, size_p);
        if err1 == 0 {
            Err(err1)
        } else {
            let mut a1 = Vec::<clingo_symbol_t>::with_capacity(size);
            let slice = a1.as_mut_slice();
            let symbols = slice.as_ptr() as *mut clingo_symbol_t;
            let err2 = clingo_model_symbols(model, ishow, symbols, size);
            if err2 == 0 {
                Err(err2)
            } else {
                let res = Vec::from_raw_parts(symbols, size, size);
                Ok(res)
            }
        }
    }
}

pub fn safe_clingo_symbol_to_string(symbol: &clingo_symbol_t) -> std::result::Result<CString, u8> {

    let mut size: usize = 0;
    let size_p = &mut size as *mut usize;
    unsafe {
        let sym = *symbol as clingo_symbol_t;
        let err1 = clingo_symbol_to_string_size(sym, size_p);
        if err1 == 0 {
            Err(err1)
        } else {
            let mut a1 = Vec::<u8>::new();//with_capacity(size);
            for i in 1..size {
                a1.push(1);
            }
            let string = CString::from_vec_unchecked(a1);

            let err2 = clingo_symbol_to_string(sym, string.as_ptr() as *mut i8, size);
            if err2 == 0 {
                Err(err2)
            } else {
                Ok(string)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn version_test() {
        let (ma, mi, re) = safe_clingo_version();
        assert!(ma == 5);
        assert!(mi == 0);
        assert!(re == 0);
    }
}
<commit_msg>create safe_clingo_control_symbolic_atoms<commit_after>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

// mod clingo {
  include!("bindings.rs");
// }
// use clingo;
use std::ffi::CStr;

pub fn safe_clingo_version() -> (i32, i32, i32) {
    let mut m1 = 0;
    let ma = &mut m1 as *mut c_int;

    let mut m2 = 0;
    let mi = &mut m2 as *mut c_int;

    let mut m3 = 0;
    let re = &mut m3 as *mut c_int;

    unsafe { clingo_version(ma, mi, re) };

    let major = unsafe { *ma };
    let minor = unsafe { *mi };
    let revision = unsafe { *re };
    (major, minor, revision)
}

// pub fn safe_clingo_control_new2(arguments: std::env::Args,
//                                logger: clingo_logger_t,
//                                logger_data: *mut c_void,
//                                message_limit: ::std::os::raw::c_uint
//                               )
//                               -> std::option::Option< &mut clingo_control_t> {
//
//     let mut ctl = std::ptr::null_mut() as *mut clingo_control_t;
//     let control = &mut ctl as *mut *mut clingo_control_t;
//     let arguments_size = arguments.len()-1;
//     // create a vector of zero terminated strings
//     let args = arguments.map(|arg| CString::new(arg).unwrap() ).collect::<Vec<CString>>();
//     // convert the strings to raw pointers
//     let c_args = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<*const c_char>>();
//
//     unsafe {
//              println!("x1{:?}",control);
//              println!("x2{:?}",*control);
//              let ret = clingo_control_new(c_args.as_ptr(),
//                                           arguments_size,
//                                           logger,
//                                           logger_data,
//                                           message_limit,
//                                           control);
//
//              println!("y1{:?}",control);
//              println!("y2{:?}",*control);
//
//              if ret == 0 { None }
//              else { Some(*control) }
//    }
// }

pub fn safe_clingo_control_new(arguments: std::env::Args,
                               logger: clingo_logger_t,
                               logger_data: *mut c_void,
                               message_limit: ::std::os::raw::c_uint)
                               -> std::option::Option<*mut clingo_control_t> {

    let arguments_size = arguments.len() - 1;
    // create a vector of zero terminated strings
    let args = arguments.map(|arg| CString::new(arg).unwrap()).collect::<Vec<CString>>();
    // drop first element
    let (_, tail) = args.split_first().unwrap();
    // convert the strings to raw pointers
    let c_args = tail.iter().map(|arg| arg.as_ptr()).collect::<Vec<*const c_char>>();

    let mut ctl = std::ptr::null_mut() as *mut clingo_control_t;

    unsafe {
        let ret = clingo_control_new(c_args.as_ptr(),
                                     arguments_size,
                                     logger,
                                     logger_data,
                                     message_limit,
                                     &mut ctl);
        if ret == 0 {
            None
        } else {
            Some(ctl)
        }
    }
}

pub fn safe_clingo_control_add(control: *mut clingo_control_t,
                               name: &str,
                               parameters: Vec<&str>,
                               program: &str)
                               -> bool {

    let mname = CString::new(name).unwrap();
    let mprogram = CString::new(program).unwrap();
    let parameters_size = parameters.len();
    // create a vector of zero terminated strings
    let args =
        parameters.into_iter().map(|arg| CString::new(arg).unwrap()).collect::<Vec<CString>>();
    // convert the strings to raw pointers
    let c_args = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<*const c_char>>();

    unsafe {
        clingo_control_add(control,
                           mname.as_ptr(),
                           c_args.as_ptr(),
                           parameters_size,
                           mprogram.as_ptr()) == 1
    }
}

pub struct safe_clingo_part {
    pub params: clingo_symbol_t,
    pub size: size_t,
    pub name: CString,
}
fn from_clingo_part(spart: &safe_clingo_part) -> clingo_part {
    clingo_part {
        name: spart.name.as_ptr(),
        params: &spart.params,
        size: spart.size,
    }
}

pub fn safe_clingo_control_ground(control: *mut clingo_control_t,
                                  sparts: Vec<safe_clingo_part>,
                                  ground_callback: clingo_ground_callback_t,
                                  ground_callback_data: *mut c_void)
                                  -> bool {

    let parts = sparts.iter().map(|arg| from_clingo_part(arg)).collect::<Vec<clingo_part>>();
    let parts_size = parts.len();

    unsafe {
        clingo_control_ground(control,
                              parts.as_ptr(),
                              parts_size,
                              ground_callback,
                              ground_callback_data) == 1
    }
}
pub fn safe_clingo_control_solve(control: *mut clingo_control_t,
                                 model_callback: clingo_model_callback_t,
                                 model_callback_data: *mut c_void,
                                 assumptions: Vec<clingo_symbolic_literal_t>,
                                 result: *mut clingo_solve_result_bitset_t)
                                 -> bool {
    let assumptions_size = assumptions.len();
    unsafe {
        clingo_control_solve(control,
                             model_callback,
                             model_callback_data,
                             assumptions.as_ptr(),
                             assumptions_size,
                             result) == 1
    }
}
pub fn safe_clingo_control_free(control: *mut *mut clingo_control_t) {
    unsafe { clingo_control_free(*control) }
}
pub fn safe_clingo_error_code() -> clingo_error_t {
    unsafe { clingo_error_code() }
}
pub fn safe_clingo_error_message() -> &'static str {
    unsafe {
        let c_buf: *const c_char = clingo_error_message();
        println!("h1{:?}", c_buf);
        if c_buf.is_null() {
            return "";
        } else {
            let c_str = CStr::from_ptr(c_buf);
            println!("h2{:?}", c_str);
            let blub = c_str.to_str();
            println!("hh{:?}", blub);
            return blub.unwrap();
        }
    }
}

pub fn safe_clingo_model_symbols(model: *mut clingo_model_t,
                                 show: clingo_show_type)
                                 -> std::result::Result<Vec<clingo_symbol_t>, u8> {

    let ishow = show as u32;
    let mut size: usize = 0;
    let size_p = &mut size as *mut usize;
    unsafe {
        let err1 = clingo_model_symbols_size(model, ishow, size_p);
        if err1 == 0 {
            Err(err1)
        } else {
            let mut a1 = Vec::<clingo_symbol_t>::with_capacity(size);
            let slice = a1.as_mut_slice();
            let symbols = slice.as_ptr() as *mut clingo_symbol_t;
            let err2 = clingo_model_symbols(model, ishow, symbols, size);
            if err2 == 0 {
                Err(err2)
            } else {
                let res = Vec::from_raw_parts(symbols, size, size);
                Ok(res)
            }
        }
    }
}

pub fn safe_clingo_symbol_to_string(symbol: &clingo_symbol_t) -> std::result::Result<CString, u8> {

    let mut size: usize = 0;
    let size_p = &mut size as *mut usize;
    unsafe {
        let sym = *symbol as clingo_symbol_t;
        let err1 = clingo_symbol_to_string_size(sym, size_p);
        if err1 == 0 {
            Err(err1)
        } else {
            let mut a1 = Vec::<u8>::new();//with_capacity(size);
            for i in 1..size {
                a1.push(1);
            }
            let string = CString::from_vec_unchecked(a1);

            let err2 = clingo_symbol_to_string(sym, string.as_ptr() as *mut i8, size);
            if err2 == 0 {
                Err(err2)
            } else {
                Ok(string)
            }
        }
    }
}

pub fn safe_clingo_control_symbolic_atoms(control: *mut clingo_control_t,
                                         )
                                        -> std::result::Result<*mut clingo_symbolic_atoms_t, u8> {
    unsafe {
        let mut ato = std::ptr::null_mut() as *mut clingo_symbolic_atoms_t;
        let err = clingo_control_symbolic_atoms(control, &mut ato);
        if err == 0 {
            Err(err)
        } else {
            Ok(ato)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn version_test() {
        let (ma, mi, re) = safe_clingo_version();
        assert!(ma == 5);
        assert!(mi == 0);
        assert!(re == 0);
    }
}
<|endoftext|>


<commit_before>
#[derive(Debug, PartialEq, Eq)]
pub struct Context;

impl Context {
    pub fn describe<F>(&self, _name: &str, _body: F)
        where F: Fn(&Context) -> () {

    }

    pub fn it<F>(&self, _name: &str, _body: F)
        where F : Fn() -> () {

    }
}

pub fn describe<F>(_block_name: &str, _body: F) -> Runner
    where F : Fn(&Context) -> () {

    Runner {}
}

#[derive(Debug, PartialEq, Eq)]
pub struct Runner;

impl Runner {
    pub fn run(&self) -> Result<(), ()> {
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    pub use super::*;
    #[test]
    fn it_has_a_root_describe_functio() {
        describe("A Test", |_ctx|{});
    }

    #[test]
    fn it_can_call_describe_inside_describe_body() {
        describe("A Root", |ctx| {
            ctx.describe("nested describe", |_ctx| {})
        });
    }

    #[test]
    fn it_can_call_it_inside_describe_body() {
        describe("A root", |ctx| {
            ctx.it("is a test", || {})
        });
    }

    #[test]
    fn it_create_a_runner_that_can_be_runned() {
        let runner = describe("A root", |ctx| {
            ctx.it("is expected to run", || {
                assert_eq!(true, true)
            })
        });
        assert_eq!(Ok(()), runner.run())
    }
}
<commit_msg> introduce lifetime for Context<commit_after>
pub struct Context<'a> {
    pub test: Option<Box<Fn() -> () + 'a>>
}

impl<'a> Context<'a> {
    pub fn describe<F>(&mut self, _name: &str, _body: F)
        where F: Fn(&mut Context) -> () {

    }

    pub fn it<F>(&mut self, _name: &str, body: F)
        where F : 'a + Fn() -> () {

        self.test = Some(Box::new(body))
    }
}

pub fn describe<F>(_block_name: &str, _body: F) -> Runner
    where F : Fn(&mut Context) -> () {

    let c = Context { test: None };
    Runner { describe: c }
}

pub struct Runner<'a> {
    describe: Context<'a>
}

impl<'a> Runner<'a> {
    pub fn run(&self) -> Result<(), ()> {
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    pub use super::*;
    #[test]
    fn it_has_a_root_describe_functio() {
        describe("A Test", |_ctx|{});
    }

    #[test]
    fn it_can_call_describe_inside_describe_body() {
        describe("A Root", |ctx| {
            ctx.describe("nested describe", |_ctx| {})
        });
    }

    #[test]
    fn it_can_call_it_inside_describe_body() {
        describe("A root", |ctx| {
            ctx.it("is a test", || {})
        });
    }

    #[test]
    fn it_create_a_runner_that_can_be_runned() {
        let runner = describe("A root", |ctx| {
            ctx.it("is expected to run", || {
                assert_eq!(true, true)
            })
        });
        assert_eq!(Ok(()), runner.run())
    }
}
<|endoftext|>


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

use std::io;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::ErrorKind;
use std::io::{Seek, Write, SeekFrom};
use std::fs::{OpenOptions, read_dir};
use std::os::unix::prelude::AsRawFd;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::thread;
use std::time::Duration;

use devicemapper::Device;
use devicemapper::types::{Bytes, Sectors};
use devicemapper::consts::SECTOR_SIZE;
use time::Timespec;
use uuid::Uuid;

use consts::IEC;
use engine::{DevUuid, EngineResult, EngineError, ErrorEnum, PoolUuid};
use super::metadata::{StaticHeader, BDA, validate_mda_size};
use super::engine::DevOwnership;
pub use super::BlockDevSave;

const MIN_DEV_SIZE: Bytes = Bytes(IEC::Gi as u64);

ioctl!(read blkgetsize64 with 0x12, 114; u64);

pub fn blkdev_size(file: &File) -> EngineResult<Bytes> {
    let mut val: u64 = 0;

    match unsafe { blkgetsize64(file.as_raw_fd(), &mut val) } {
        Err(x) => Err(EngineError::Nix(x)),
        Ok(_) => Ok(Bytes(val)),
    }
}

/// Resolve a list of Paths of some sort to a set of unique Devices.
/// Return an IOError if there was a problem resolving any particular device.
pub fn resolve_devices(paths: &[&Path]) -> io::Result<HashSet<Device>> {
    let mut devices = HashSet::new();
    for path in paths {
        let dev = try!(Device::from_str(&path.to_string_lossy()));
        devices.insert(dev);
    }
    Ok(devices)
}

/// Find all Stratis Blockdevs.
///
/// Returns a map of pool uuids to maps of blockdev uuids to blockdevs.
pub fn find_all() -> EngineResult<HashMap<PoolUuid, HashMap<DevUuid, BlockDev>>> {

    /// If a Path refers to a valid Stratis blockdev, return a BlockDev
    /// struct. Otherwise, return None. Return an error if there was
    /// a problem inspecting the device.
    fn setup(devnode: &Path) -> EngineResult<Option<BlockDev>> {
        let mut f = try!(OpenOptions::new()
            .read(true)
            .open(devnode));

        if let Some(bda) = BDA::load(&mut f).ok() {
            let dev = try!(Device::from_str(&devnode.to_string_lossy()));
            Ok(Some(BlockDev {
                dev: dev,
                devnode: devnode.to_owned(),
                bda: bda,
            }))
        } else {
            Ok(None)
        }
    }

    let mut pool_map = HashMap::new();
    for dir_e in try!(read_dir("/dev")) {
        let devnode = match dir_e {
            Ok(d) => d.path(),
            Err(_) => continue,
        };

        match setup(&devnode) {
            Ok(Some(blockdev)) => {
                pool_map.entry(blockdev.pool_uuid().clone())
                    .or_insert_with(HashMap::new)
                    .insert(blockdev.uuid().clone(), blockdev);
            }
            _ => continue,
        };
    }

    Ok(pool_map)
}

/// Zero sectors at the given offset
pub fn wipe_sectors(path: &Path, offset: Sectors, sector_count: Sectors) -> EngineResult<()> {
    let mut f = try!(OpenOptions::new()
        .write(true)
        .open(path));

    let zeroed = [0u8; SECTOR_SIZE];

    // set the start point to the offset
    try!(f.seek(SeekFrom::Start(*offset)));
    for _ in 0..*sector_count {
        try!(f.write_all(&zeroed));
    }
    try!(f.flush());
    Ok(())
}

/// Initialize multiple blockdevs at once. This allows all of them
/// to be checked for usability before writing to any of them.
pub fn initialize(pool_uuid: &PoolUuid,
                  devices: HashSet<Device>,
                  mda_size: Sectors,
                  force: bool)
                  -> EngineResult<Vec<BlockDev>> {
    /// Gets device information, returns an error if problem with obtaining
    /// that information.
    /// Returns a tuple with the blockdev's path, its size in bytes,
    /// its ownership as determined by calling determine_ownership(),
    /// and an open File handle, all of which are needed later.
    fn dev_info(dev: &Device) -> EngineResult<(PathBuf, Bytes, DevOwnership, File)> {
        let devnode = try!(dev.path().ok_or_else(|| {
            io::Error::new(ErrorKind::InvalidInput,
                           format!("could not get device node from dev {}", dev.dstr()))
        }));
        let mut f = try!(OpenOptions::new()
            .read(true)
            .write(true)
            .open(&devnode)
            .map_err(|_| {
                io::Error::new(ErrorKind::PermissionDenied,
                               format!("Could not open {}", devnode.display()))
            }));

        let dev_size = try!(blkdev_size(&f));

        let ownership = match StaticHeader::determine_ownership(&mut f) {
            Ok(ownership) => ownership,
            Err(err) => {
                let error_message = format!("{} for device {}", err, devnode.display());
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            }
        };

        Ok((devnode, dev_size, ownership, f))
    }

    /// Filter devices for admission to pool based on dev_infos.
    /// If there is an error finding out the info, return that error.
    /// Also, return an error if a device is not appropriate for this pool.
    fn filter_devs<I>(dev_infos: I,
                      pool_uuid: &PoolUuid,
                      force: bool)
                      -> EngineResult<Vec<(Device, (PathBuf, Bytes, File))>>
        where I: Iterator<Item = (Device, EngineResult<(PathBuf, Bytes, DevOwnership, File)>)>
    {
        let mut add_devs = Vec::new();
        for (dev, dev_result) in dev_infos {
            let (devnode, dev_size, ownership, f) = try!(dev_result);
            if dev_size < MIN_DEV_SIZE {
                let error_message = format!("{} too small, minimum {} bytes",
                                            devnode.display(),
                                            MIN_DEV_SIZE);
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            };
            match ownership {
                DevOwnership::Unowned => add_devs.push((dev, (devnode, dev_size, f))),
                DevOwnership::Theirs => {
                    if !force {
                        let error_str = format!("First 8K of {} not zeroed", devnode.display());
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    } else {
                        add_devs.push((dev, (devnode, dev_size, f)))
                    }
                }
                DevOwnership::Ours(uuid) => {
                    if *pool_uuid != uuid {
                        let error_str = format!("Device {} already belongs to Stratis pool {}",
                                                devnode.display(),
                                                uuid);
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    }
                }
            }
        }
        Ok(add_devs)
    }

    try!(validate_mda_size(mda_size));

    let dev_infos = devices.into_iter().map(|d: Device| (d, dev_info(&d)));

    let add_devs = try!(filter_devs(dev_infos, pool_uuid, force));

    // TODO: Fix this code.  We should deal with any number of blockdevs
    //
    if add_devs.len() < 2 {
        return Err(EngineError::Engine(ErrorEnum::Error,
                                       "Need at least 2 blockdevs to create a pool".into()));
    }

    let mut bds = Vec::new();
    for (dev, (devnode, dev_size, mut f)) in add_devs {

        let bda = try!(BDA::initialize(&mut f,
                                       pool_uuid,
                                       &Uuid::new_v4(),
                                       mda_size,
                                       dev_size.sectors()));

        let bd = BlockDev {
            dev: dev,
            devnode: devnode.clone(),
            bda: bda,
        };
        bds.push(bd);
    }
    Ok(bds)
}

#[derive(Debug)]
pub struct BlockDev {
    dev: Device,
    pub devnode: PathBuf,
    bda: BDA,
}

impl BlockDev {
    pub fn to_save(&self) -> BlockDevSave {
        BlockDevSave {
            devnode: self.devnode.clone(),
            total_size: self.size(),
        }
    }

    pub fn wipe_metadata(self) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        BDA::wipe(&mut f)
    }

    /// Get the "x:y" device string for this blockdev
    pub fn dstr(&self) -> String {
        self.dev.dstr()
    }

    pub fn save_state(&mut self, time: &Timespec, metadata: &[u8]) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        self.bda.save_state(time, metadata, &mut f)
    }

    pub fn load_state(&self) -> EngineResult<Option<Vec<u8>>> {
        let mut f = try!(OpenOptions::new().read(true).open(&self.devnode));
        self.bda.load_state(&mut f)
    }

    /// List the available-for-upper-layer-use range in this blockdev.
    pub fn avail_range(&self) -> (Sectors, Sectors) {
        let start = self.bda.size();
        let size = self.size();
        // Blockdev size is at least MIN_DEV_SIZE, so this can fail only if
        // size of metadata area exceeds 1 GiB. Initial metadata area size
        // is 4 MiB.
        assert!(start <= size);
        (start, size - start)
    }

    /// The /dev/mapper/<name> device is not immediately available for use.
    /// TODO: Implement wait for event or poll.
    pub fn wait_for_dm() {
        thread::sleep(Duration::from_millis(500))
    }

    /// The device's UUID.
    pub fn uuid(&self) -> &DevUuid {
        self.bda.dev_uuid()
    }

    /// The device's pool's UUID.
    pub fn pool_uuid(&self) -> &PoolUuid {
        self.bda.pool_uuid()
    }

    /// The device's size.
    pub fn size(&self) -> Sectors {
        self.bda.dev_size()
    }

    /// Last time metadata was written to this device.
    pub fn last_update_time(&self) -> Option<&Timespec> {
        self.bda.last_update_time()
    }
}
<commit_msg>Add a function called write_sectors<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::io;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::ErrorKind;
use std::io::{Seek, Write, SeekFrom};
use std::fs::{OpenOptions, read_dir};
use std::os::unix::prelude::AsRawFd;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::thread;
use std::time::Duration;

use devicemapper::Device;
use devicemapper::types::{Bytes, Sectors};
use devicemapper::consts::SECTOR_SIZE;
use time::Timespec;
use uuid::Uuid;

use consts::IEC;
use engine::{DevUuid, EngineResult, EngineError, ErrorEnum, PoolUuid};
use super::metadata::{StaticHeader, BDA, validate_mda_size};
use super::engine::DevOwnership;
pub use super::BlockDevSave;

const MIN_DEV_SIZE: Bytes = Bytes(IEC::Gi as u64);

ioctl!(read blkgetsize64 with 0x12, 114; u64);

pub fn blkdev_size(file: &File) -> EngineResult<Bytes> {
    let mut val: u64 = 0;

    match unsafe { blkgetsize64(file.as_raw_fd(), &mut val) } {
        Err(x) => Err(EngineError::Nix(x)),
        Ok(_) => Ok(Bytes(val)),
    }
}

/// Resolve a list of Paths of some sort to a set of unique Devices.
/// Return an IOError if there was a problem resolving any particular device.
pub fn resolve_devices(paths: &[&Path]) -> io::Result<HashSet<Device>> {
    let mut devices = HashSet::new();
    for path in paths {
        let dev = try!(Device::from_str(&path.to_string_lossy()));
        devices.insert(dev);
    }
    Ok(devices)
}

/// Find all Stratis Blockdevs.
///
/// Returns a map of pool uuids to maps of blockdev uuids to blockdevs.
pub fn find_all() -> EngineResult<HashMap<PoolUuid, HashMap<DevUuid, BlockDev>>> {

    /// If a Path refers to a valid Stratis blockdev, return a BlockDev
    /// struct. Otherwise, return None. Return an error if there was
    /// a problem inspecting the device.
    fn setup(devnode: &Path) -> EngineResult<Option<BlockDev>> {
        let mut f = try!(OpenOptions::new()
            .read(true)
            .open(devnode));

        if let Some(bda) = BDA::load(&mut f).ok() {
            let dev = try!(Device::from_str(&devnode.to_string_lossy()));
            Ok(Some(BlockDev {
                dev: dev,
                devnode: devnode.to_owned(),
                bda: bda,
            }))
        } else {
            Ok(None)
        }
    }

    let mut pool_map = HashMap::new();
    for dir_e in try!(read_dir("/dev")) {
        let devnode = match dir_e {
            Ok(d) => d.path(),
            Err(_) => continue,
        };

        match setup(&devnode) {
            Ok(Some(blockdev)) => {
                pool_map.entry(blockdev.pool_uuid().clone())
                    .or_insert_with(HashMap::new)
                    .insert(blockdev.uuid().clone(), blockdev);
            }
            _ => continue,
        };
    }

    Ok(pool_map)
}

/// Write buf at offset length times.
pub fn write_sectors(path: &Path,
                     offset: Sectors,
                     length: Sectors,
                     buf: &[u8; SECTOR_SIZE])
                     -> EngineResult<()> {
    let mut f = try!(OpenOptions::new().write(true).open(path));

    try!(f.seek(SeekFrom::Start(*offset)));
    for _ in 0..*length {
        try!(f.write_all(buf));
    }

    try!(f.flush());
    Ok(())
}

/// Zero sectors at the given offset for length sectors.
pub fn wipe_sectors(path: &Path, offset: Sectors, length: Sectors) -> EngineResult<()> {
    write_sectors(path, offset, length, &[0u8; SECTOR_SIZE])
}

/// Initialize multiple blockdevs at once. This allows all of them
/// to be checked for usability before writing to any of them.
pub fn initialize(pool_uuid: &PoolUuid,
                  devices: HashSet<Device>,
                  mda_size: Sectors,
                  force: bool)
                  -> EngineResult<Vec<BlockDev>> {
    /// Gets device information, returns an error if problem with obtaining
    /// that information.
    /// Returns a tuple with the blockdev's path, its size in bytes,
    /// its ownership as determined by calling determine_ownership(),
    /// and an open File handle, all of which are needed later.
    fn dev_info(dev: &Device) -> EngineResult<(PathBuf, Bytes, DevOwnership, File)> {
        let devnode = try!(dev.path().ok_or_else(|| {
            io::Error::new(ErrorKind::InvalidInput,
                           format!("could not get device node from dev {}", dev.dstr()))
        }));
        let mut f = try!(OpenOptions::new()
            .read(true)
            .write(true)
            .open(&devnode)
            .map_err(|_| {
                io::Error::new(ErrorKind::PermissionDenied,
                               format!("Could not open {}", devnode.display()))
            }));

        let dev_size = try!(blkdev_size(&f));

        let ownership = match StaticHeader::determine_ownership(&mut f) {
            Ok(ownership) => ownership,
            Err(err) => {
                let error_message = format!("{} for device {}", err, devnode.display());
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            }
        };

        Ok((devnode, dev_size, ownership, f))
    }

    /// Filter devices for admission to pool based on dev_infos.
    /// If there is an error finding out the info, return that error.
    /// Also, return an error if a device is not appropriate for this pool.
    fn filter_devs<I>(dev_infos: I,
                      pool_uuid: &PoolUuid,
                      force: bool)
                      -> EngineResult<Vec<(Device, (PathBuf, Bytes, File))>>
        where I: Iterator<Item = (Device, EngineResult<(PathBuf, Bytes, DevOwnership, File)>)>
    {
        let mut add_devs = Vec::new();
        for (dev, dev_result) in dev_infos {
            let (devnode, dev_size, ownership, f) = try!(dev_result);
            if dev_size < MIN_DEV_SIZE {
                let error_message = format!("{} too small, minimum {} bytes",
                                            devnode.display(),
                                            MIN_DEV_SIZE);
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            };
            match ownership {
                DevOwnership::Unowned => add_devs.push((dev, (devnode, dev_size, f))),
                DevOwnership::Theirs => {
                    if !force {
                        let error_str = format!("First 8K of {} not zeroed", devnode.display());
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    } else {
                        add_devs.push((dev, (devnode, dev_size, f)))
                    }
                }
                DevOwnership::Ours(uuid) => {
                    if *pool_uuid != uuid {
                        let error_str = format!("Device {} already belongs to Stratis pool {}",
                                                devnode.display(),
                                                uuid);
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    }
                }
            }
        }
        Ok(add_devs)
    }

    try!(validate_mda_size(mda_size));

    let dev_infos = devices.into_iter().map(|d: Device| (d, dev_info(&d)));

    let add_devs = try!(filter_devs(dev_infos, pool_uuid, force));

    // TODO: Fix this code.  We should deal with any number of blockdevs
    //
    if add_devs.len() < 2 {
        return Err(EngineError::Engine(ErrorEnum::Error,
                                       "Need at least 2 blockdevs to create a pool".into()));
    }

    let mut bds = Vec::new();
    for (dev, (devnode, dev_size, mut f)) in add_devs {

        let bda = try!(BDA::initialize(&mut f,
                                       pool_uuid,
                                       &Uuid::new_v4(),
                                       mda_size,
                                       dev_size.sectors()));

        let bd = BlockDev {
            dev: dev,
            devnode: devnode.clone(),
            bda: bda,
        };
        bds.push(bd);
    }
    Ok(bds)
}

#[derive(Debug)]
pub struct BlockDev {
    dev: Device,
    pub devnode: PathBuf,
    bda: BDA,
}

impl BlockDev {
    pub fn to_save(&self) -> BlockDevSave {
        BlockDevSave {
            devnode: self.devnode.clone(),
            total_size: self.size(),
        }
    }

    pub fn wipe_metadata(self) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        BDA::wipe(&mut f)
    }

    /// Get the "x:y" device string for this blockdev
    pub fn dstr(&self) -> String {
        self.dev.dstr()
    }

    pub fn save_state(&mut self, time: &Timespec, metadata: &[u8]) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        self.bda.save_state(time, metadata, &mut f)
    }

    pub fn load_state(&self) -> EngineResult<Option<Vec<u8>>> {
        let mut f = try!(OpenOptions::new().read(true).open(&self.devnode));
        self.bda.load_state(&mut f)
    }

    /// List the available-for-upper-layer-use range in this blockdev.
    pub fn avail_range(&self) -> (Sectors, Sectors) {
        let start = self.bda.size();
        let size = self.size();
        // Blockdev size is at least MIN_DEV_SIZE, so this can fail only if
        // size of metadata area exceeds 1 GiB. Initial metadata area size
        // is 4 MiB.
        assert!(start <= size);
        (start, size - start)
    }

    /// The /dev/mapper/<name> device is not immediately available for use.
    /// TODO: Implement wait for event or poll.
    pub fn wait_for_dm() {
        thread::sleep(Duration::from_millis(500))
    }

    /// The device's UUID.
    pub fn uuid(&self) -> &DevUuid {
        self.bda.dev_uuid()
    }

    /// The device's pool's UUID.
    pub fn pool_uuid(&self) -> &PoolUuid {
        self.bda.pool_uuid()
    }

    /// The device's size.
    pub fn size(&self) -> Sectors {
        self.bda.dev_size()
    }

    /// Last time metadata was written to this device.
    pub fn last_update_time(&self) -> Option<&Timespec> {
        self.bda.last_update_time()
    }
}
<|endoftext|>


<commit_before>use std::f32::INFINITY;
use std::ops::Mul;

use num::zero;

use {Point3f, Transform, Vector3f};
use stats;

#[derive(Debug, Copy, Clone)]
pub struct Ray {
    pub o: Point3f,
    pub d: Vector3f,
    pub t_max: f32,
    pub differential: Option<RayDifferential>,
}

impl Ray {
    pub fn new(o: Point3f, d: Vector3f) -> Ray {
        stats::inc_primary_ray();
        assert!(!o.x.is_nan() && !o.y.is_nan() && !o.z.is_nan());
        assert!(!d.x.is_nan() && !d.y.is_nan() && !d.z.is_nan());
        assert_ne!(d.length_squared(), 0.0);
        Ray {
            o: o,
            d: d,
            t_max: INFINITY,
            differential: None,
        }
    }

    pub fn segment(o: Point3f, d: Vector3f, tmax: f32) -> Ray {
        stats::inc_primary_ray();
        assert!(!o.x.is_nan() && !o.y.is_nan() && !o.z.is_nan());
        assert!(!d.x.is_nan() && !d.y.is_nan() && !d.z.is_nan());
        assert_ne!(d.length_squared(), 0.0);
        Ray {
            o: o,
            d: d,
            t_max: tmax,
            differential: None,
        }
    }

    pub fn at(&self, t: f32) -> Point3f {
        self.o + t * self.d
    }

    pub fn transform(&self, transform: &Transform) -> (Ray, Vector3f, Vector3f) {
        let (mut o, o_error) = transform.transform_point(&self.o);
        let (d, d_error) = transform.transform_vector(&self.d);
        let t_max = self.t_max;
        let length_squared = d.length_squared();

        if length_squared > 0.0 {
            let dt = d.abs().dot(&o_error) / length_squared;
            o += d * dt;
        }

        let diff = self.differential
            .map(|d| {
                     RayDifferential {
                         rx_origin: transform * &d.rx_origin,
                         ry_origin: transform * &d.ry_origin,
                         rx_direction: transform * &d.rx_direction,
                         ry_direction: transform * &d.ry_direction,
                     }
                 });

        let r = Ray {
            o: o,
            d: d,
            t_max: t_max,
            differential: diff,
        };
        (r, o_error, d_error)
    }

    pub fn scale_differentials(&mut self, s: f32) {
        if let Some(d) = self.differential.iter_mut().next() {
            d.rx_origin = self.o + (d.rx_origin - self.o) * s;
            d.ry_origin = self.o + (d.ry_origin - self.o) * s;
            d.rx_direction = self.d + (d.rx_direction - self.d) * s;
            d.ry_direction = self.d + (d.ry_direction - self.d) * s;
        }
    }
}

impl Mul<Ray> for Transform {
    type Output = Ray;

    fn mul(self, rhs: Ray) -> Ray {
        let mut new_ray = rhs;
        new_ray.o = &self * &rhs.o;
        new_ray.d = &self * &rhs.d;

        new_ray
    }
}

#[derive(Copy, Clone, Debug)]
pub struct RayDifferential {
    pub rx_origin: Point3f,
    pub ry_origin: Point3f,
    pub rx_direction: Vector3f,
    pub ry_direction: Vector3f,
}

impl Default for RayDifferential {
    fn default() -> Self {
        RayDifferential {
            rx_origin: zero(),
            ry_origin: zero(),
            rx_direction: zero(),
            ry_direction: zero(),
        }
    }
}

#[test]
fn test_translation() {
    let r = Ray::new(Point3f::new(1.0, 0.0, 0.0), Vector3f::new(0.0, 1.0, 0.0));
    let t = Transform::translate(&Vector3f::new(1.0, 1.0, 1.0));
    let s = t * r;

    assert_eq!(s.o, Point3f::new(2.0, 1.0, 1.0));
    assert_eq!(s.d, r.d);
}
<commit_msg>Add Display impl for Ray<commit_after>use std::f32::INFINITY;
use std::ops::Mul;
use std::fmt;

use num::zero;

use {Point3f, Transform, Vector3f};
use stats;

#[derive(Debug, Copy, Clone)]
pub struct Ray {
    pub o: Point3f,
    pub d: Vector3f,
    pub t_max: f32,
    pub differential: Option<RayDifferential>,
}

impl Ray {
    pub fn new(o: Point3f, d: Vector3f) -> Ray {
        stats::inc_primary_ray();
        assert!(!o.x.is_nan() && !o.y.is_nan() && !o.z.is_nan());
        assert!(!d.x.is_nan() && !d.y.is_nan() && !d.z.is_nan());
        assert_ne!(d.length_squared(), 0.0);
        Ray {
            o: o,
            d: d,
            t_max: INFINITY,
            differential: None,
        }
    }

    pub fn segment(o: Point3f, d: Vector3f, tmax: f32) -> Ray {
        stats::inc_primary_ray();
        assert!(!o.x.is_nan() && !o.y.is_nan() && !o.z.is_nan());
        assert!(!d.x.is_nan() && !d.y.is_nan() && !d.z.is_nan());
        assert_ne!(d.length_squared(), 0.0);
        Ray {
            o: o,
            d: d,
            t_max: tmax,
            differential: None,
        }
    }

    pub fn at(&self, t: f32) -> Point3f {
        self.o + t * self.d
    }

    pub fn transform(&self, transform: &Transform) -> (Ray, Vector3f, Vector3f) {
        let (mut o, o_error) = transform.transform_point(&self.o);
        let (d, d_error) = transform.transform_vector(&self.d);
        let t_max = self.t_max;
        let length_squared = d.length_squared();

        if length_squared > 0.0 {
            let dt = d.abs().dot(&o_error) / length_squared;
            o += d * dt;
        }

        let diff = self.differential
            .map(|d| {
                     RayDifferential {
                         rx_origin: transform * &d.rx_origin,
                         ry_origin: transform * &d.ry_origin,
                         rx_direction: transform * &d.rx_direction,
                         ry_direction: transform * &d.ry_direction,
                     }
                 });

        let r = Ray {
            o: o,
            d: d,
            t_max: t_max,
            differential: diff,
        };
        (r, o_error, d_error)
    }

    pub fn scale_differentials(&mut self, s: f32) {
        if let Some(d) = self.differential.iter_mut().next() {
            d.rx_origin = self.o + (d.rx_origin - self.o) * s;
            d.ry_origin = self.o + (d.ry_origin - self.o) * s;
            d.rx_direction = self.d + (d.rx_direction - self.d) * s;
            d.ry_direction = self.d + (d.ry_direction - self.d) * s;
        }
    }
}

impl Mul<Ray> for Transform {
    type Output = Ray;

    fn mul(self, rhs: Ray) -> Ray {
        let mut new_ray = rhs;
        new_ray.o = &self * &rhs.o;
        new_ray.d = &self * &rhs.d;

        new_ray
    }
}

impl fmt::Display for Ray {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{
        write!(f, "[o={}, d={}, t_max={}]", self.o, self.d, self.t_max)
    }
}

#[derive(Copy, Clone, Debug)]
pub struct RayDifferential {
    pub rx_origin: Point3f,
    pub ry_origin: Point3f,
    pub rx_direction: Vector3f,
    pub ry_direction: Vector3f,
}

impl Default for RayDifferential {
    fn default() -> Self {
        RayDifferential {
            rx_origin: zero(),
            ry_origin: zero(),
            rx_direction: zero(),
            ry_direction: zero(),
        }
    }
}

#[test]
fn test_translation() {
    let r = Ray::new(Point3f::new(1.0, 0.0, 0.0), Vector3f::new(0.0, 1.0, 0.0));
    let t = Transform::translate(&Vector3f::new(1.0, 1.0, 1.0));
    let s = t * r;

    assert_eq!(s.o, Point3f::new(2.0, 1.0, 1.0));
    assert_eq!(s.d, r.d);
}
<|endoftext|>


<commit_before>use table::LSHTable;
use std::collections::BTreeSet;
// we want many lsh table

pub struct LSHLookup<'a, T: 'a, Q: 'a+?Sized> {
    tables: Vec<LSHTable<'a, T, Q>>,
    data: &'a [T]
}

impl<'a, T, Q: 'a+?Sized> LSHLookup<'a, T, Q> where Q: Fn(&'a T) -> f64 {
    pub fn add_table(&mut self, new_table: LSHTable<'a, T, Q>) {
        self.tables.push(new_table);
    }

    pub fn new(data: &'a [T]) -> Self {
        LSHLookup {
            tables: Vec::new(),
            data: data
        }
    }

    pub fn query_vec(&self, v: &'a T) -> Vec<usize> {
        let mut output_set = BTreeSet::new();
        for table in &self.tables {
            for &reference in &table.query_multiprobe(v) {
                output_set.insert(reference);
            }
        }
        let mut result = Vec::new();
        result.extend(output_set.into_iter());
        result
    }
}
#[cfg(test)]
mod tests {
use super::*;
    use table::LSHTable;
    use multi;
    #[test]
    fn test_init_tables() {
        let test_data = vec![
            vec![1,2,3,4,5],
            vec![0,0,0,0,0],
            vec![1,2,3,4,5]
        ];
        let zjs = multi::get_expected_zj_vals(1,1.0);
        let sets: Vec<multi::PerturbationSet> = multi::gen_perturbation_sets(&zjs)
            .take(5)
            .collect();
        let ms: Vec<Vec<usize>> = sets.into_iter()
            .map(|x| {x.data})
            .collect();
        let mut mylookup = LSHLookup::new(&test_data);
        for _ in 1..10 {
            let val = |_: &Vec<i32>| {0.0 as f64};
            let funcs = vec![Box::new(val)];
            let new_single_table = LSHTable::new(&test_data, funcs, &ms);
            mylookup.add_table(new_single_table);
        }
    }
}
<commit_msg>query tables test passing<commit_after>use table::LSHTable;
use std::collections::BTreeSet;
// we want many lsh table

pub struct LSHLookup<'a, T: 'a, Q: 'a+?Sized> {
    tables: Vec<LSHTable<'a, T, Q>>,
    data: &'a [T]
}

impl<'a, T, Q: 'a+?Sized> LSHLookup<'a, T, Q> where Q: Fn(&'a T) -> f64 {
    pub fn add_table(&mut self, new_table: LSHTable<'a, T, Q>) {
        self.tables.push(new_table);
    }

    pub fn new(data: &'a [T]) -> Self {
        LSHLookup {
            tables: Vec::new(),
            data: data
        }
    }

    pub fn query_vec(&self, v: &'a T) -> Vec<usize> {
        let mut output_set = BTreeSet::new();
        for table in &self.tables {
            for &reference in &table.query_multiprobe(v) {
                output_set.insert(reference);
            }
        }
        let mut result = Vec::new();
        result.extend(output_set.into_iter());
        result
    }
}
#[cfg(test)]
mod tests {
use super::*;
    use table::LSHTable;
    use multi;
    #[test]
    fn test_init_tables() {
        let test_data = vec![
            vec![1,2,3,4,5],
            vec![0,0,0,0,0],
            vec![1,2,3,4,5]
        ];
        let zjs = multi::get_expected_zj_vals(1,1.0);
        let sets: Vec<multi::PerturbationSet> = multi::gen_perturbation_sets(&zjs)
            .take(5)
            .collect();
        let ms: Vec<Vec<usize>> = sets.into_iter()
            .map(|x| {x.data})
            .collect();
        let mut mylookup = LSHLookup::new(&test_data);
        for _ in 1..10 {
            let val = |_: &Vec<i32>| {0.0 as f64};
            let funcs = vec![Box::new(val)];
            let new_single_table = LSHTable::new(&test_data, funcs, &ms);
            mylookup.add_table(new_single_table);
        }
    }

    #[test]
    fn test_query_tables() {
        let test_data = vec![
            vec![1,2,3,4,5],
            vec![0,0,0,0,0],
            vec![1,2,3,4,5]
        ];
        let zjs = multi::get_expected_zj_vals(1,1.0);
        let sets: Vec<multi::PerturbationSet> = multi::gen_perturbation_sets(&zjs)
            .take(5)
            .collect();
        let ms: Vec<Vec<usize>> = sets.into_iter()
            .map(|x| {x.data})
            .collect();
        let mut mylookup = LSHLookup::new(&test_data);
        for _ in 1..10 {
            let val = |_: &Vec<i32>| {0.0 as f64};
            let funcs = vec![Box::new(val)];
            let new_single_table = LSHTable::new(&test_data, funcs, &ms);
            mylookup.add_table(new_single_table);
        }

        for data in &test_data {
            println!("{:?}", mylookup.query_vec(data));
        }
    }
}
<|endoftext|>


<commit_before>//! ROM image loading code

use std::cmp;
use std::str;

/// The (decoded) SNES header
pub struct RomHeader {
    /// ASCII title, filled with spaces to 21 Bytes
    #[allow(dead_code)] // FIXME Use this or drop this
    title: [u8; 21],
    rom_size: u32,
    ram_size: u32,
    checksum: u16,
    rom_type: RomType,
}

#[derive(Debug, PartialEq, Eq)]
enum RomType {
    LoRom,
    HiRom,
}

impl RomHeader {
    /// Loads the ROM header from the given byte slice (must be exactly 64 bytes large).
    /// `rom_type` is the expected type of the ROM header, based on its location. It will be
    /// used for the actual type if the type inside the header mismatches. This is apparently
    /// required for some broken ROMs.
    fn load(bytes: &[u8], rom_type: RomType) -> Result<RomHeader, ()> {
        // The header size must be correct (the ROM loader won't pass a wrong size)
        assert_eq!(bytes.len(), 64);

        debug!("raw rom header: {:?}", bytes);

        // First check: Is the title valid ASCII?
        let mut title = [0; 21];
        for (i, c) in bytes[0..21].iter().enumerate() {
            match *c {
                0x20 ... 0x7E => {
                    title[i] = *c;
                }
                _ => {
                    debug!("title contains non-ascii bytes");
                    return Err(())
                }
            }
        }

        info!("loading '{}'", str::from_utf8(&title).unwrap().trim_right());

        // 21) ROM makeup byte
        // `---smmmm`
        // * `s`: Speed (0: SlowROM, 1: FastROM)
        // * `m`: Map mode
        //  * `0000`: LoROM
        //  * `0001`: HiROM
        //  * `0010`: LoROM + S-DD1
        //  * `0011`: LoROM + SA-1
        //  * `0101`: ExHiROM
        //  * `1010`: HiROM + SPC7110
        if bytes[21] & 0x10 == 0x10 {
            warn!("FastROM not yet implemented!");
        }

        let header_rom_type = match bytes[21] & 0x0f {
            0 => RomType::LoRom,
            1 => RomType::HiRom,
            t => {
                error!("unknown / unimplemented ROM type {}", t);
                return Err(())
            }
        };

        if header_rom_type == rom_type {
            info!("type: {:?}", rom_type);
        } else {
            warn!("expected rom type {:?}, got {:?} (assuming {:?})", rom_type, header_rom_type,
                rom_type);
        }

        // bytes[22] is the chipset info. For now, we don't care about that.
        debug!("chipset: 0x{:02X}", bytes[22]);

        let rom_size = 0x400 << bytes[23] as u32;
        let ram_size = 0x400 << bytes[24] as u32;
        debug!("ROM/RAM size values: {:02X} {:02X}", bytes[23], bytes[24]);
        info!("{} KB of ROM, {} KB of cartridge RAM", rom_size / 1024, ram_size / 1024);

        // bytes[25-26] is a vendor code (doesn't matter)
        debug!("vendor code: 0x{:02X}{:02X}", bytes[25], bytes[26]);
        // 27 = version (also doesn't matter for us)
        debug!("version: 0x{:02X}", bytes[27]);

        // Now it's getting a bit more interesting: The next byte is the checksum's complement
        // followed by the checksum itself. The checksum is the sum of all bytes in the ROM
        // (truncated to 16 bits). It can be validated by the loader.
        // 16 bit, little-endian.
        let check_inv = (bytes[29] as u16) << 8 | bytes[28] as u16;
        let checksum = (bytes[31] as u16) << 8 | bytes[30] as u16;
        if check_inv != !checksum {
            error!("checksum invalid: stored complement is {:04X}, stored checksum is {:04X}",
                check_inv, checksum);
            return Err(())
        }

        Ok(RomHeader {
            title: title,
            rom_size: rom_size,
            ram_size: ram_size,
            checksum: checksum,
            rom_type: rom_type,
        })
    }
}

/// A ROM image
pub struct Rom {
    header: RomHeader,
    ram: Vec<u8>,
    rom: Vec<u8>,
}

impl_save_state!(Rom { ram } ignore { header, rom });

impl Rom {
    /// Loads a ROM from raw data.
    pub fn from_bytes(mut bytes: &[u8]) -> Result<Rom, ()> {
        // FIXME Return a proper error!

        debug!("raw size: {} bytes ({:#X})", bytes.len(), bytes.len());

        // ROMs may begin with a 512 Bytes SMC header. It needs to go.
        match bytes.len() % 1024 {
            512 => {
                debug!("stripping SMC header");
                bytes = &bytes[512..];
            }
            0 => {},
            n => panic!("len() % 1024 == {} (expected 512 or 0)", n),
        }

        // Read the SNES header. It is located in a really stupid location which depends on whether
        // the ROM is HiROM or LoROM, so we must check both locations and pick the right one.
        // LoROM header is at 0x7FFF - 63, HiROM is at 0xFFFF - 63 (it is 64 Bytes large)

        // Test LoROM first (it's more common)
        let header = try!(RomHeader::load(&bytes[0x7FFF - 63..0x7FFF + 1], RomType::LoRom)
            .or_else(|_| RomHeader::load(&bytes[0xFFFF - 63..0xFFFF + 1], RomType::HiRom)));

        if bytes.len() != header.rom_size as usize {
            warn!("raw ROM is {} KB, but header specifies {} KB",
                bytes.len() / 1024, header.rom_size / 1024);
        }

        // Create the right amount of RAM...
        let ram = vec![0; header.ram_size as usize];
        // ...and copy the ROM
        let rom = bytes.iter().cloned().cycle()
            .take(cmp::max(header.rom_size as usize, bytes.len())).collect();

        // Calculate the ROM's checksum
        let mut checksum: u16 = 0;
        for &byte in &rom {
            checksum = checksum.wrapping_add(byte as u16);
        }

        debug!("computed checksum: ${:04X}", checksum);

        if header.checksum != checksum {
            warn!("incorrect checksum: computed ${:04X}, expected ${:04X}",
                checksum, header.checksum);
        }

        Ok(Rom {
            header: header,
            ram: ram,
            rom: rom,
        })
    }

    fn resolve_lorom(&mut self, bank: u8, addr: u16) -> &mut u8 {
        match addr {
            0x0000 ... 0x7fff => {
                // Cartridge RAM mapped to the low 32 KB
                // (there's other stuff here, but that's handled much earlier than we are called)
                match bank {
                    0x70 ... 0x7d => {
                        let a = (bank as u32 - 0x70) * 0x8000 + addr as u32;
                        self.ram.get_mut(a as usize).unwrap_or_else(|| out_of_ram_bounds(bank, addr, a))
                    }
                    0xfe ... 0xff => {
                        // last 64k of RAM
                        let start = self.ram.len() as u32 - 64 * 1024;
                        let a = start + (bank - 0xfe) as u32 * 0x8000 + addr as u32;
                        self.ram.get_mut(a as usize).unwrap_or_else(|| out_of_ram_bounds(bank, addr, a))
                    }
                    _ => {
                        // 0x40 ... 0x6f | 0x7e ... 0xfd
                        panic!("attempted to access unmapped address: ${:02X}:{:04X}", bank, addr);
                    }
                }
            },
            0x8000 ... 0xffff => match bank {
                // LoROM is mapped to the higher 8 pages
                0xfe => {
                    let a = 0x3f0000 + addr as u32 - 0x8000;
                    self.rom.get_mut(a as usize).unwrap_or_else(|| out_of_rom_bounds(bank, addr, a))
                }
                0xff => {
                    let a = 0x3f8000 + addr as u32 - 0x8000;
                    self.rom.get_mut(a as usize).unwrap_or_else(|| out_of_rom_bounds(bank, addr, a))
                }
                0x80 ... 0xfd | 0x00 ... 0x7d => {
                    // `& !0x80` because 0x80-0xFD mirrors 0x00-0x7D
                    let a = (bank as u32 & !0x80) * 0x8000 + addr as u32 - 0x8000;
                    self.rom.get_mut(a as usize).unwrap_or_else(|| out_of_rom_bounds(bank, addr, a))
                }
                _ => panic!("attempted to access unmapped address: ${:02X}:{:04X}", bank, addr)
            },
            _ => unreachable!()
        }
    }

    fn resolve_hirom(&mut self, bank: u8, addr: u16) -> &mut u8 {
        let addr = addr as usize;
        match bank {
            0x00 ... 0x3f | 0x80 ... 0xbf if addr >= 0x8000 => {
                &mut self.rom[(bank as usize & 0x3f) << 16 | addr]
            }
            0x20 ... 0x3f | 0xa0 ... 0xbf if addr >= 0x6000 && addr <= 0x7fff => {
                let a = ((bank as usize & 0x3f) - 0x20) * 0x2000 + (addr - 0x6000);
                &mut self.ram[a]
            }
            0x40 ... 0x7d | 0xc0 ... 0xfd => {
                &mut self.rom[((bank as usize & 0x7f) - 0x40) << 16 | addr]
            }
            0x7e ... 0x7f => unreachable!(),    // WRAM banks
            0xfe ... 0xff => {
                &mut self.rom[(bank as usize - 0xfe + 0x3e) << 16 | addr]
            }
            _ => panic!("attempted to access unmapped address: ${:02}:{:04X}", bank, addr),
        }
    }

    fn resolve_addr(&mut self, bank: u8, addr: u16) -> &mut u8 {
        match self.header.rom_type {
            RomType::LoRom => self.resolve_lorom(bank, addr),
            RomType::HiRom => self.resolve_hirom(bank, addr),
        }
    }
}

impl Rom {
    pub fn load(&mut self, bank: u8, addr: u16) -> u8 {
        *self.resolve_addr(bank, addr)
    }

    pub fn store(&mut self, bank: u8, addr: u16, value: u8) {
        if addr >= 0x8000 {
            warn!("writing ${:02X} to ROM address ${:02X}:{:04X}", value, bank, addr);
        }
        *self.resolve_addr(bank, addr) = value;
    }
}

fn out_of_ram_bounds(bank: u8, addr: u16, abs: u32) -> ! {
    panic!("RAM access out of bounds at {:02X}:{:04X} -> {:04X}",
        bank, addr, abs)
}

fn out_of_rom_bounds(bank: u8, addr: u16, abs: u32) -> ! {
    panic!("ROM access out of bounds at {:02X}:{:04X} -> {:06X}",
        bank, addr, abs)
}
<commit_msg>Allow ROMs with non-ascii title<commit_after>//! ROM image loading code

use std::cmp;
use std::str;

/// The (decoded) SNES header
pub struct RomHeader {
    /// ASCII title, filled with spaces to 21 Bytes
    #[allow(dead_code)] // FIXME Use this or drop this
    title: [u8; 21],
    rom_size: u32,
    ram_size: u32,
    checksum: u16,
    rom_type: RomType,
}

#[derive(Debug, PartialEq, Eq)]
enum RomType {
    LoRom,
    HiRom,
}

impl RomHeader {
    /// Loads the ROM header from the given byte slice (must be exactly 64 bytes large).
    /// `rom_type` is the expected type of the ROM header, based on its location. It will be
    /// used for the actual type if the type inside the header mismatches. This is apparently
    /// required for some broken ROMs.
    fn load(bytes: &[u8], rom_type: RomType) -> Result<RomHeader, ()> {
        // The header size must be correct (the ROM loader won't pass a wrong size)
        assert_eq!(bytes.len(), 64);

        debug!("raw rom header: {:?}", bytes);

        let mut title = [0; 21];
        for (i, c) in bytes[0..21].iter().enumerate() {
            match *c {
                0x20 ... 0x7E => {
                    title[i] = *c;
                }
                _ => {
                    warn!("title contains non-ascii byte: ${:02X}", *c);
                    title[i] = b' ';
                }
            }
        }

        info!("loading '{}'", str::from_utf8(&title).unwrap().trim_right());

        // 21) ROM makeup byte
        // `---smmmm`
        // * `s`: Speed (0: SlowROM, 1: FastROM)
        // * `m`: Map mode
        //  * `0000`: LoROM
        //  * `0001`: HiROM
        //  * `0010`: LoROM + S-DD1
        //  * `0011`: LoROM + SA-1
        //  * `0101`: ExHiROM
        //  * `1010`: HiROM + SPC7110
        if bytes[21] & 0x10 == 0x10 {
            warn!("FastROM not yet implemented!");
        }

        let header_rom_type = match bytes[21] & 0x0f {
            0 => RomType::LoRom,
            1 => RomType::HiRom,
            t => {
                error!("unknown / unimplemented ROM type {}", t);
                return Err(())
            }
        };

        if header_rom_type == rom_type {
            info!("type: {:?}", rom_type);
        } else {
            warn!("expected rom type {:?}, got {:?} (assuming {:?})", rom_type, header_rom_type,
                rom_type);
        }

        // bytes[22] is the chipset info. For now, we don't care about that.
        debug!("chipset: 0x{:02X}", bytes[22]);

        let rom_size = 0x400 << bytes[23] as u32;
        let ram_size = 0x400 << bytes[24] as u32;
        debug!("ROM/RAM size values: {:02X} {:02X}", bytes[23], bytes[24]);
        info!("{} KB of ROM, {} KB of cartridge RAM", rom_size / 1024, ram_size / 1024);

        // bytes[25-26] is a vendor code (doesn't matter)
        debug!("vendor code: 0x{:02X}{:02X}", bytes[25], bytes[26]);
        // 27 = version (also doesn't matter for us)
        debug!("version: 0x{:02X}", bytes[27]);

        // Now it's getting a bit more interesting: The next byte is the checksum's complement
        // followed by the checksum itself. The checksum is the sum of all bytes in the ROM
        // (truncated to 16 bits). It can be validated by the loader.
        // 16 bit, little-endian.
        let check_inv = (bytes[29] as u16) << 8 | bytes[28] as u16;
        let checksum = (bytes[31] as u16) << 8 | bytes[30] as u16;
        if check_inv != !checksum {
            error!("checksum invalid: stored complement is {:04X}, stored checksum is {:04X}",
                check_inv, checksum);
            return Err(())
        }

        Ok(RomHeader {
            title: title,
            rom_size: rom_size,
            ram_size: ram_size,
            checksum: checksum,
            rom_type: rom_type,
        })
    }
}

/// A ROM image
pub struct Rom {
    header: RomHeader,
    ram: Vec<u8>,
    rom: Vec<u8>,
}

impl_save_state!(Rom { ram } ignore { header, rom });

impl Rom {
    /// Loads a ROM from raw data.
    pub fn from_bytes(mut bytes: &[u8]) -> Result<Rom, ()> {
        // FIXME Return a proper error!

        debug!("raw size: {} bytes ({:#X})", bytes.len(), bytes.len());

        // ROMs may begin with a 512 Bytes SMC header. It needs to go.
        match bytes.len() % 1024 {
            512 => {
                debug!("stripping SMC header");
                bytes = &bytes[512..];
            }
            0 => {},
            n => panic!("len() % 1024 == {} (expected 512 or 0)", n),
        }

        // Read the SNES header. It is located in a really stupid location which depends on whether
        // the ROM is HiROM or LoROM, so we must check both locations and pick the right one.
        // LoROM header is at 0x7FFF - 63, HiROM is at 0xFFFF - 63 (it is 64 Bytes large)

        // Test LoROM first (it's more common)
        let header = try!(RomHeader::load(&bytes[0x7FFF - 63..0x7FFF + 1], RomType::LoRom)
            .or_else(|_| RomHeader::load(&bytes[0xFFFF - 63..0xFFFF + 1], RomType::HiRom)));

        if bytes.len() != header.rom_size as usize {
            warn!("raw ROM is {} KB, but header specifies {} KB",
                bytes.len() / 1024, header.rom_size / 1024);
        }

        // Create the right amount of RAM...
        let ram = vec![0; header.ram_size as usize];
        // ...and copy the ROM
        let rom = bytes.iter().cloned().cycle()
            .take(cmp::max(header.rom_size as usize, bytes.len())).collect();

        // Calculate the ROM's checksum
        let mut checksum: u16 = 0;
        for &byte in &rom {
            checksum = checksum.wrapping_add(byte as u16);
        }

        debug!("computed checksum: ${:04X}", checksum);

        if header.checksum != checksum {
            warn!("incorrect checksum: computed ${:04X}, expected ${:04X}",
                checksum, header.checksum);
        }

        Ok(Rom {
            header: header,
            ram: ram,
            rom: rom,
        })
    }

    fn resolve_lorom(&mut self, bank: u8, addr: u16) -> &mut u8 {
        match addr {
            0x0000 ... 0x7fff => {
                // Cartridge RAM mapped to the low 32 KB
                // (there's other stuff here, but that's handled much earlier than we are called)
                match bank {
                    0x70 ... 0x7d => {
                        let a = (bank as u32 - 0x70) * 0x8000 + addr as u32;
                        self.ram.get_mut(a as usize).unwrap_or_else(|| out_of_ram_bounds(bank, addr, a))
                    }
                    0xfe ... 0xff => {
                        // last 64k of RAM
                        let start = self.ram.len() as u32 - 64 * 1024;
                        let a = start + (bank - 0xfe) as u32 * 0x8000 + addr as u32;
                        self.ram.get_mut(a as usize).unwrap_or_else(|| out_of_ram_bounds(bank, addr, a))
                    }
                    _ => {
                        // 0x40 ... 0x6f | 0x7e ... 0xfd
                        panic!("attempted to access unmapped address: ${:02X}:{:04X}", bank, addr);
                    }
                }
            },
            0x8000 ... 0xffff => match bank {
                // LoROM is mapped to the higher 8 pages
                0xfe => {
                    let a = 0x3f0000 + addr as u32 - 0x8000;
                    self.rom.get_mut(a as usize).unwrap_or_else(|| out_of_rom_bounds(bank, addr, a))
                }
                0xff => {
                    let a = 0x3f8000 + addr as u32 - 0x8000;
                    self.rom.get_mut(a as usize).unwrap_or_else(|| out_of_rom_bounds(bank, addr, a))
                }
                0x80 ... 0xfd | 0x00 ... 0x7d => {
                    // `& !0x80` because 0x80-0xFD mirrors 0x00-0x7D
                    let a = (bank as u32 & !0x80) * 0x8000 + addr as u32 - 0x8000;
                    self.rom.get_mut(a as usize).unwrap_or_else(|| out_of_rom_bounds(bank, addr, a))
                }
                _ => panic!("attempted to access unmapped address: ${:02X}:{:04X}", bank, addr)
            },
            _ => unreachable!()
        }
    }

    fn resolve_hirom(&mut self, bank: u8, addr: u16) -> &mut u8 {
        let addr = addr as usize;
        match bank {
            0x00 ... 0x3f | 0x80 ... 0xbf if addr >= 0x8000 => {
                &mut self.rom[(bank as usize & 0x3f) << 16 | addr]
            }
            0x20 ... 0x3f | 0xa0 ... 0xbf if addr >= 0x6000 && addr <= 0x7fff => {
                let a = ((bank as usize & 0x3f) - 0x20) * 0x2000 + (addr - 0x6000);
                &mut self.ram[a]
            }
            0x40 ... 0x7d | 0xc0 ... 0xfd => {
                &mut self.rom[((bank as usize & 0x7f) - 0x40) << 16 | addr]
            }
            0x7e ... 0x7f => unreachable!(),    // WRAM banks
            0xfe ... 0xff => {
                &mut self.rom[(bank as usize - 0xfe + 0x3e) << 16 | addr]
            }
            _ => panic!("attempted to access unmapped address: ${:02}:{:04X}", bank, addr),
        }
    }

    fn resolve_addr(&mut self, bank: u8, addr: u16) -> &mut u8 {
        match self.header.rom_type {
            RomType::LoRom => self.resolve_lorom(bank, addr),
            RomType::HiRom => self.resolve_hirom(bank, addr),
        }
    }
}

impl Rom {
    pub fn load(&mut self, bank: u8, addr: u16) -> u8 {
        *self.resolve_addr(bank, addr)
    }

    pub fn store(&mut self, bank: u8, addr: u16, value: u8) {
        if addr >= 0x8000 {
            warn!("writing ${:02X} to ROM address ${:02X}:{:04X}", value, bank, addr);
        }
        *self.resolve_addr(bank, addr) = value;
    }
}

fn out_of_ram_bounds(bank: u8, addr: u16, abs: u32) -> ! {
    panic!("RAM access out of bounds at {:02X}:{:04X} -> {:04X}",
        bank, addr, abs)
}

fn out_of_rom_bounds(bank: u8, addr: u16, abs: u32) -> ! {
    panic!("ROM access out of bounds at {:02X}:{:04X} -> {:06X}",
        bank, addr, abs)
}
<|endoftext|>