<commit_before>//! Collective communication
//!
//! Developing...
//!
//! # Unfinished features
//!
//! - **5.5**: Varying counts gather operation, `MPI_Gatherv()`
//! - **5.6**: Scatter, `MPI_Scatterv()`
//! - **5.7**: Gather-to-all, `MPI_Allgatherv()`
//! - **5.8**: All-to-all, `MPI_Alltoallv()`, `MPI_Alltoallw()`
//! - **5.9**: Global reduction operations, `MPI_Op_create()`, `MPI_Op_free()`,
//! `MPI_Op_commutative()`
//! - **5.10**: Reduce-scatter, `MPI_Reduce_scatter_block()`, `MPI_Reduce_scatter()`
//! - **5.11**: Scan, `MPI_Scan()`, `MPI_Exscan()`
//! - **5.12**: Nonblocking collective operations, `MPI_Ibcast()`,
//! `MPI_Igather()`, `MPI_Igatherv()`, `MPI_Iscatter()`, `MPI_Iscatterv()`, `MPI_Iallgather()`,
//! `MPI_Iallgatherv()`, `MPI_Ialltoall()`, `MPI_Ialltoallv()`, `MPI_Ialltoallw()`,
//! `MPI_Ireduce()`, `MPI_Iallreduce()`, `MPI_Ireduce_scatter_block()`, `MPI_Ireduce_scatter()`,
//! `MPI_Iscan()`, `MPI_Iexscan()`

use std::{mem, ptr};

use ffi;
use ffi::{MPI_Request, MPI_Op};
use topology::{Rank, Identifier};
use topology::traits::*;
use datatype::traits::*;
use point_to_point::{RawRequest};

pub mod traits;

/// Barrier synchronization among all processes in a `Communicator`
///
/// Calling processes (or threads within the calling processes) will enter the barrier and block
/// execution until all processes in the `Communicator` `&self` have entered the barrier.
///
/// # Standard section(s)
///
/// 5.3
pub trait Barrier {
    /// Partake in a barrier synchronization across all processes in the `Communicator` `&self`.
    ///
    /// # Examples
    ///
    /// See `examples/barrier.rs`
    fn barrier(&self);
}

impl<C: Communicator> Barrier for C {
    fn barrier(&self) {
        unsafe { ffi::MPI_Barrier(self.communicator().raw()); }
    }
}

/// Something that can take the role of 'root' in a collective operation.
///
/// Many collective operations define a 'root' process that takes a special role in the
/// communication. These collective operations are implemented as traits that have blanket
/// implementations for every type that implements the `Root` trait.
pub trait Root: Communicator {
    /// Rank of the root process
    fn root_rank(&self) -> Rank;
}

impl<'a, C: 'a + RawCommunicator> Root for Identifier<'a, C> {
    fn root_rank(&self) -> Rank {
        self.rank()
    }
}

/// Broadcast of the contents of a buffer
///
/// After the call completes, the `Buffer` on all processes in the `Communicator` of the `Root`
/// `&self` will contain what it contains on the `Root`.
///
/// # Standard section(s)
///
/// 5.4
pub trait BroadcastInto {
    /// Broadcast the contents of `buffer` from the `Root` to the `buffer`s on all other processes.
    ///
    /// # Examples
    ///
    /// See `examples/broadcast.rs`
    fn broadcast_into<Buf: BufferMut + ?Sized>(&self, buffer: &mut Buf);
}

impl<T: Root> BroadcastInto for T {
    fn broadcast_into<Buf: BufferMut + ?Sized>(&self, buffer: &mut Buf) {
        unsafe {
            ffi::MPI_Bcast(buffer.pointer_mut(), buffer.count(), buffer.datatype().raw(),
                self.root_rank(), self.communicator().raw());
        }
    }
}

// TODO: Introduce "partitioned buffer" for varying count gather/scatter/alltoall?

/// Gather contents of buffers on `Root`.
///
/// After the call completes, the contents of the `Buffer`s on all ranks will be
/// concatenated into the `Buffer` on `Root`.
///
/// # Standard section(s)
///
/// 5.5
pub trait GatherInto {
    /// Gather the contents of all `sendbuf`s into `recvbuf` on `Root` `&self`.
    ///
    /// # Examples
    ///
    /// See `examples/gather.rs`
    fn gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: Option<&mut R>);
}

impl<T: Root> GatherInto for T {
    fn gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: Option<&mut R>) {
        unsafe {
            let (recvptr, recvcount, recvtype) = recvbuf.map_or(
                (ptr::null_mut(), 0, u8::equivalent_datatype().raw()),
                |x| (x.pointer_mut(), x.count() / self.communicator().size(), x.datatype().raw()));

            ffi::MPI_Gather(sendbuf.pointer(), sendbuf.count(), sendbuf.datatype().raw(),
                recvptr, recvcount, recvtype, self.root_rank(), self.communicator().raw());
        }
    }
}

/// Gather contents of buffers on all participating processes.
///
/// After the call completes, the contents of the send `Buffer`s on all processes will be
/// concatenated into the receive `Buffer`s on all ranks.
///
/// # Standard section(s)
///
/// 5.7
pub trait AllGatherInto {
    /// Gather the contents of all `sendbuf`s into all `rcevbuf`s on all processes in the
    /// communicator.
    ///
    /// # Examples
    ///
    /// See `examples/all_gather.rs`
    fn all_gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R);
}

impl<C: Communicator> AllGatherInto for C {
    fn all_gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R) {
        unsafe {
            ffi::MPI_Allgather(sendbuf.pointer(), sendbuf.count(), sendbuf.datatype().raw(),
                recvbuf.pointer_mut(), recvbuf.count() / self.communicator().size(),
                recvbuf.datatype().raw(), self.communicator().raw());
        }
    }
}

/// Scatter contents of a buffer on the root process to all processes.
///
/// After the call completes each participating process will have received a part of the send
/// `Buffer` on the root process.
///
/// # Standard section(s)
///
/// 5.6
pub trait ScatterInto {
    /// Scatter the contents of `sendbuf` to the participating processes.
    ///
    /// # Examples
    ///
    /// See `examples/scatter.rs`
    fn scatter_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: Option<&S>, recvbuf: &mut R);
}

impl<T: Root> ScatterInto for T {
    fn scatter_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: Option<&S>, recvbuf: &mut R) {
        unsafe {
            let (sendptr, sendcount, sendtype) = sendbuf.map_or(
                (ptr::null(), 0, u8::equivalent_datatype().raw()),
                |x| (x.pointer(), x.count() / self.communicator().size(), x.datatype().raw()));

            ffi::MPI_Scatter(sendptr, sendcount, sendtype,
                recvbuf.pointer_mut(), recvbuf.count(), recvbuf.datatype().raw(),
                self.root_rank(), self.communicator().raw());
        }
    }
}

/// Distribute the send `Buffer`s from all processes to the receive `Buffer`s on all processes.
///
/// # Standard section(s)
///
/// 5.8
pub trait AllToAllInto {
    /// Distribute the `sendbuf` from all ranks to the `recvbuf` on all ranks.
    ///
    /// # Examples
    ///
    /// See `examples/all_to_all.rs`
    fn all_to_all_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R);
}

impl<C: Communicator> AllToAllInto for C {
    fn all_to_all_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R) {
        let c_size = self.communicator().size();
        unsafe {
            ffi::MPI_Alltoall(sendbuf.pointer(), sendbuf.count() / c_size, sendbuf.datatype().raw(),
                recvbuf.pointer_mut(), recvbuf.count() / c_size, recvbuf.datatype().raw(),
                self.communicator().raw());
        }
    }
}

/// Something that can identify as a raw `MPI_Op`
pub trait RawOperation {
    /// The raw `MPI_Op` value
    unsafe fn raw(&self) -> MPI_Op;
}

/// A built-in operation like `MPI_SUM`
///
/// # Standard section(s)
///
/// 5.9.2
#[derive(Copy, Clone)]
pub struct SystemOperation(MPI_Op);

macro_rules! system_operation_constructors {
    ($($ctor:ident => $val:path),*) => (
        $(pub fn $ctor() -> SystemOperation {
            //! The built-in `$ctor` operation
            SystemOperation($val)
        })*
    )
}

impl SystemOperation {
    system_operation_constructors! {
        max => ffi::RSMPI_MAX,
        min => ffi::RSMPI_MIN,
        sum => ffi::RSMPI_SUM,
        product => ffi::RSMPI_PROD,
        logical_and => ffi::RSMPI_LAND,
        bitwise_and => ffi::RSMPI_BAND,
        logical_or => ffi::RSMPI_LOR,
        bitwise_or => ffi::RSMPI_BOR,
        logical_xor => ffi::RSMPI_LXOR,
        bitwise_xor => ffi::RSMPI_BXOR
    }
}

impl RawOperation for SystemOperation {
    unsafe fn raw(&self) -> MPI_Op {
        self.0
    }
}

macro_rules! reduce_into_specializations {
    ($($name:ident => $operation:expr),*) => (
        $(fn $name<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: Option<&mut R>) {
            self.reduce_into(sendbuf, recvbuf, $operation)
        })*
    )
}

/// Perform a global reduction, storing the result on the `Root` process.
///
/// # Standard section(s)
///
/// 5.9.1
pub trait ReduceInto {
    /// Performs a global reduction under the operation `op` of the input data in `sendbuf` and
    /// stores the result in `recvbuf` on the `Root` process.
    ///
    /// `recvbuf` is ignored and can be `None` on all processes but the `Root` process.
    ///
    /// # Examples
    ///
    /// See `examples/reduce.rs`
    fn reduce_into<S: Buffer + ?Sized, R: BufferMut + ?Sized, O: RawOperation>(&self, sendbuf: &S, recvbuf: Option<&mut R>, op: O);

//    reduce_into_specializations! {
//        max_into => SystemOperation::max(),
//        min_into => SystemOperation::min(),
//        sum_into => SystemOperation::sum(),
//        product_into => SystemOperation::product(),
//        logical_and_into => SystemOperation::logical_and(),
//        bitwise_and_into => SystemOperation::bitwise_and(),
//        logical_or_into => SystemOperation::logical_or(),
//        bitwise_or_into => SystemOperation::bitwise_or(),
//        logical_xor_into => SystemOperation::logical_xor(),
//        bitwise_xor_into => SystemOperation::bitwise_xor()
//    }
}

impl<T: Root> ReduceInto for T {
    fn reduce_into<S: Buffer + ?Sized, R: BufferMut + ?Sized, O: RawOperation>(&self, sendbuf: &S, recvbuf: Option<&mut R>, op: O) {
        unsafe {
            let recvptr = recvbuf.map_or(ptr::null_mut(), |x| { x.pointer_mut() });
            ffi::MPI_Reduce(sendbuf.pointer(), recvptr, sendbuf.count(), sendbuf.datatype().raw(),
                op.raw(), self.root_rank(), self.communicator().raw());
        }
    }
}

/// Perform a global reduction, storing the result on all processes.
///
/// # Standard section(s)
///
/// 5.9.6
pub trait AllReduceInto {
    /// Performs a global reduction under the operation `op` of the input data in `sendbuf` and
    /// stores the result in `recvbuf` on all processes.
    ///
    /// # Examples
    ///
    /// See `examples/reduce.rs`
    fn all_reduce_into<S: Buffer + ?Sized, R: BufferMut + ?Sized, O: RawOperation>(&self, sendbuf: &S, recvbuf: &mut R, op: O);
}

impl<C: Communicator> AllReduceInto for C {
    fn all_reduce_into<S: Buffer + ?Sized, R: BufferMut + ?Sized, O: RawOperation>(&self, sendbuf: &S, recvbuf: &mut R, op: O) {
        unsafe {
            ffi::MPI_Allreduce(sendbuf.pointer(), recvbuf.pointer_mut(), sendbuf.count(),
                sendbuf.datatype().raw(), op.raw(), self.communicator().raw());
        }
    }
}

/// Perform a local reduction.
///
/// # Standard section(s)
///
/// 5.9.7
///
/// # Examples
///
/// See `examples/redure.rs`
pub fn reduce_local_into<S: Buffer + ?Sized, R: BufferMut + ?Sized, O: RawOperation>(inbuf: &S, inoutbuf: &mut R, op: O) {
    unsafe {
        ffi::MPI_Reduce_local(inbuf.pointer(), inoutbuf.pointer_mut(), inbuf.count(),
          inbuf.datatype().raw(), op.raw());
    }
}

/// A request object for an immediate (non-blocking) barrier operation
///
/// # Examples
///
/// See `examples/immediate_barrier.rs`
///
/// # Standard section(s)
///
/// 3.7.1
#[must_use]
pub struct BarrierRequest(MPI_Request);

impl Drop for BarrierRequest {
    fn drop(&mut self) {
        unsafe {
            assert!(self.raw() == ffi::RSMPI_REQUEST_NULL,
                "asynchronous barrier request dropped without ascertaining completion.");
        }
    }
}

impl RawRequest for BarrierRequest {
    unsafe fn raw(&self) -> MPI_Request { self.0 }
    unsafe fn ptr_mut(&mut self) -> *mut MPI_Request { &mut (self.0) }
}

/// Non-blocking barrier synchronization among all processes in a `Communicator`
///
/// Calling processes (or threads within the calling processes) enter the barrier. Completion
/// methods on the associated request object will block until all processes have entered.
///
/// # Standard section(s)
///
/// 5.12.1
pub trait ImmediateBarrier {
    /// Partake in a barrier synchronization across all processes in the `Communicator` `&self`.
    ///
    /// # Examples
    ///
    /// See `examples/immediate_barrier.rs`
    fn immediate_barrier(&self) -> BarrierRequest;
}

impl<C: Communicator> ImmediateBarrier for C {
    fn immediate_barrier(&self) -> BarrierRequest {
        let mut request = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Ibarrier(self.communicator().raw(), &mut request as *mut MPI_Request); }
        BarrierRequest(request)
    }
}
<commit_msg>Macro arguments are not substituted in comments.<commit_after>//! Collective communication
//!
//! Developing...
//!
//! # Unfinished features
//!
//! - **5.5**: Varying counts gather operation, `MPI_Gatherv()`
//! - **5.6**: Scatter, `MPI_Scatterv()`
//! - **5.7**: Gather-to-all, `MPI_Allgatherv()`
//! - **5.8**: All-to-all, `MPI_Alltoallv()`, `MPI_Alltoallw()`
//! - **5.9**: Global reduction operations, `MPI_Op_create()`, `MPI_Op_free()`,
//! `MPI_Op_commutative()`
//! - **5.10**: Reduce-scatter, `MPI_Reduce_scatter_block()`, `MPI_Reduce_scatter()`
//! - **5.11**: Scan, `MPI_Scan()`, `MPI_Exscan()`
//! - **5.12**: Nonblocking collective operations, `MPI_Ibcast()`,
//! `MPI_Igather()`, `MPI_Igatherv()`, `MPI_Iscatter()`, `MPI_Iscatterv()`, `MPI_Iallgather()`,
//! `MPI_Iallgatherv()`, `MPI_Ialltoall()`, `MPI_Ialltoallv()`, `MPI_Ialltoallw()`,
//! `MPI_Ireduce()`, `MPI_Iallreduce()`, `MPI_Ireduce_scatter_block()`, `MPI_Ireduce_scatter()`,
//! `MPI_Iscan()`, `MPI_Iexscan()`

use std::{mem, ptr};

use ffi;
use ffi::{MPI_Request, MPI_Op};
use topology::{Rank, Identifier};
use topology::traits::*;
use datatype::traits::*;
use point_to_point::{RawRequest};

pub mod traits;

/// Barrier synchronization among all processes in a `Communicator`
///
/// Calling processes (or threads within the calling processes) will enter the barrier and block
/// execution until all processes in the `Communicator` `&self` have entered the barrier.
///
/// # Standard section(s)
///
/// 5.3
pub trait Barrier {
    /// Partake in a barrier synchronization across all processes in the `Communicator` `&self`.
    ///
    /// # Examples
    ///
    /// See `examples/barrier.rs`
    fn barrier(&self);
}

impl<C: Communicator> Barrier for C {
    fn barrier(&self) {
        unsafe { ffi::MPI_Barrier(self.communicator().raw()); }
    }
}

/// Something that can take the role of 'root' in a collective operation.
///
/// Many collective operations define a 'root' process that takes a special role in the
/// communication. These collective operations are implemented as traits that have blanket
/// implementations for every type that implements the `Root` trait.
pub trait Root: Communicator {
    /// Rank of the root process
    fn root_rank(&self) -> Rank;
}

impl<'a, C: 'a + RawCommunicator> Root for Identifier<'a, C> {
    fn root_rank(&self) -> Rank {
        self.rank()
    }
}

/// Broadcast of the contents of a buffer
///
/// After the call completes, the `Buffer` on all processes in the `Communicator` of the `Root`
/// `&self` will contain what it contains on the `Root`.
///
/// # Standard section(s)
///
/// 5.4
pub trait BroadcastInto {
    /// Broadcast the contents of `buffer` from the `Root` to the `buffer`s on all other processes.
    ///
    /// # Examples
    ///
    /// See `examples/broadcast.rs`
    fn broadcast_into<Buf: BufferMut + ?Sized>(&self, buffer: &mut Buf);
}

impl<T: Root> BroadcastInto for T {
    fn broadcast_into<Buf: BufferMut + ?Sized>(&self, buffer: &mut Buf) {
        unsafe {
            ffi::MPI_Bcast(buffer.pointer_mut(), buffer.count(), buffer.datatype().raw(),
                self.root_rank(), self.communicator().raw());
        }
    }
}

// TODO: Introduce "partitioned buffer" for varying count gather/scatter/alltoall?

/// Gather contents of buffers on `Root`.
///
/// After the call completes, the contents of the `Buffer`s on all ranks will be
/// concatenated into the `Buffer` on `Root`.
///
/// # Standard section(s)
///
/// 5.5
pub trait GatherInto {
    /// Gather the contents of all `sendbuf`s into `recvbuf` on `Root` `&self`.
    ///
    /// # Examples
    ///
    /// See `examples/gather.rs`
    fn gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: Option<&mut R>);
}

impl<T: Root> GatherInto for T {
    fn gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: Option<&mut R>) {
        unsafe {
            let (recvptr, recvcount, recvtype) = recvbuf.map_or(
                (ptr::null_mut(), 0, u8::equivalent_datatype().raw()),
                |x| (x.pointer_mut(), x.count() / self.communicator().size(), x.datatype().raw()));

            ffi::MPI_Gather(sendbuf.pointer(), sendbuf.count(), sendbuf.datatype().raw(),
                recvptr, recvcount, recvtype, self.root_rank(), self.communicator().raw());
        }
    }
}

/// Gather contents of buffers on all participating processes.
///
/// After the call completes, the contents of the send `Buffer`s on all processes will be
/// concatenated into the receive `Buffer`s on all ranks.
///
/// # Standard section(s)
///
/// 5.7
pub trait AllGatherInto {
    /// Gather the contents of all `sendbuf`s into all `rcevbuf`s on all processes in the
    /// communicator.
    ///
    /// # Examples
    ///
    /// See `examples/all_gather.rs`
    fn all_gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R);
}

impl<C: Communicator> AllGatherInto for C {
    fn all_gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R) {
        unsafe {
            ffi::MPI_Allgather(sendbuf.pointer(), sendbuf.count(), sendbuf.datatype().raw(),
                recvbuf.pointer_mut(), recvbuf.count() / self.communicator().size(),
                recvbuf.datatype().raw(), self.communicator().raw());
        }
    }
}

/// Scatter contents of a buffer on the root process to all processes.
///
/// After the call completes each participating process will have received a part of the send
/// `Buffer` on the root process.
///
/// # Standard section(s)
///
/// 5.6
pub trait ScatterInto {
    /// Scatter the contents of `sendbuf` to the participating processes.
    ///
    /// # Examples
    ///
    /// See `examples/scatter.rs`
    fn scatter_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: Option<&S>, recvbuf: &mut R);
}

impl<T: Root> ScatterInto for T {
    fn scatter_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: Option<&S>, recvbuf: &mut R) {
        unsafe {
            let (sendptr, sendcount, sendtype) = sendbuf.map_or(
                (ptr::null(), 0, u8::equivalent_datatype().raw()),
                |x| (x.pointer(), x.count() / self.communicator().size(), x.datatype().raw()));

            ffi::MPI_Scatter(sendptr, sendcount, sendtype,
                recvbuf.pointer_mut(), recvbuf.count(), recvbuf.datatype().raw(),
                self.root_rank(), self.communicator().raw());
        }
    }
}

/// Distribute the send `Buffer`s from all processes to the receive `Buffer`s on all processes.
///
/// # Standard section(s)
///
/// 5.8
pub trait AllToAllInto {
    /// Distribute the `sendbuf` from all ranks to the `recvbuf` on all ranks.
    ///
    /// # Examples
    ///
    /// See `examples/all_to_all.rs`
    fn all_to_all_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R);
}

impl<C: Communicator> AllToAllInto for C {
    fn all_to_all_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R) {
        let c_size = self.communicator().size();
        unsafe {
            ffi::MPI_Alltoall(sendbuf.pointer(), sendbuf.count() / c_size, sendbuf.datatype().raw(),
                recvbuf.pointer_mut(), recvbuf.count() / c_size, recvbuf.datatype().raw(),
                self.communicator().raw());
        }
    }
}

/// Something that can identify as a raw `MPI_Op`
pub trait RawOperation {
    /// The raw `MPI_Op` value
    unsafe fn raw(&self) -> MPI_Op;
}

/// A built-in operation like `MPI_SUM`
///
/// # Standard section(s)
///
/// 5.9.2
#[derive(Copy, Clone)]
pub struct SystemOperation(MPI_Op);

macro_rules! system_operation_constructors {
    ($($ctor:ident => $val:path),*) => (
        $(pub fn $ctor() -> SystemOperation {
            //! A built-in operation
            SystemOperation($val)
        })*
    )
}

impl SystemOperation {
    system_operation_constructors! {
        max => ffi::RSMPI_MAX,
        min => ffi::RSMPI_MIN,
        sum => ffi::RSMPI_SUM,
        product => ffi::RSMPI_PROD,
        logical_and => ffi::RSMPI_LAND,
        bitwise_and => ffi::RSMPI_BAND,
        logical_or => ffi::RSMPI_LOR,
        bitwise_or => ffi::RSMPI_BOR,
        logical_xor => ffi::RSMPI_LXOR,
        bitwise_xor => ffi::RSMPI_BXOR
    }
}

impl RawOperation for SystemOperation {
    unsafe fn raw(&self) -> MPI_Op {
        self.0
    }
}

macro_rules! reduce_into_specializations {
    ($($name:ident => $operation:expr),*) => (
        $(fn $name<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: Option<&mut R>) {
            self.reduce_into(sendbuf, recvbuf, $operation)
        })*
    )
}

/// Perform a global reduction, storing the result on the `Root` process.
///
/// # Standard section(s)
///
/// 5.9.1
pub trait ReduceInto {
    /// Performs a global reduction under the operation `op` of the input data in `sendbuf` and
    /// stores the result in `recvbuf` on the `Root` process.
    ///
    /// `recvbuf` is ignored and can be `None` on all processes but the `Root` process.
    ///
    /// # Examples
    ///
    /// See `examples/reduce.rs`
    fn reduce_into<S: Buffer + ?Sized, R: BufferMut + ?Sized, O: RawOperation>(&self, sendbuf: &S, recvbuf: Option<&mut R>, op: O);

//    reduce_into_specializations! {
//        max_into => SystemOperation::max(),
//        min_into => SystemOperation::min(),
//        sum_into => SystemOperation::sum(),
//        product_into => SystemOperation::product(),
//        logical_and_into => SystemOperation::logical_and(),
//        bitwise_and_into => SystemOperation::bitwise_and(),
//        logical_or_into => SystemOperation::logical_or(),
//        bitwise_or_into => SystemOperation::bitwise_or(),
//        logical_xor_into => SystemOperation::logical_xor(),
//        bitwise_xor_into => SystemOperation::bitwise_xor()
//    }
}

impl<T: Root> ReduceInto for T {
    fn reduce_into<S: Buffer + ?Sized, R: BufferMut + ?Sized, O: RawOperation>(&self, sendbuf: &S, recvbuf: Option<&mut R>, op: O) {
        unsafe {
            let recvptr = recvbuf.map_or(ptr::null_mut(), |x| { x.pointer_mut() });
            ffi::MPI_Reduce(sendbuf.pointer(), recvptr, sendbuf.count(), sendbuf.datatype().raw(),
                op.raw(), self.root_rank(), self.communicator().raw());
        }
    }
}

/// Perform a global reduction, storing the result on all processes.
///
/// # Standard section(s)
///
/// 5.9.6
pub trait AllReduceInto {
    /// Performs a global reduction under the operation `op` of the input data in `sendbuf` and
    /// stores the result in `recvbuf` on all processes.
    ///
    /// # Examples
    ///
    /// See `examples/reduce.rs`
    fn all_reduce_into<S: Buffer + ?Sized, R: BufferMut + ?Sized, O: RawOperation>(&self, sendbuf: &S, recvbuf: &mut R, op: O);
}

impl<C: Communicator> AllReduceInto for C {
    fn all_reduce_into<S: Buffer + ?Sized, R: BufferMut + ?Sized, O: RawOperation>(&self, sendbuf: &S, recvbuf: &mut R, op: O) {
        unsafe {
            ffi::MPI_Allreduce(sendbuf.pointer(), recvbuf.pointer_mut(), sendbuf.count(),
                sendbuf.datatype().raw(), op.raw(), self.communicator().raw());
        }
    }
}

/// Perform a local reduction.
///
/// # Standard section(s)
///
/// 5.9.7
///
/// # Examples
///
/// See `examples/redure.rs`
pub fn reduce_local_into<S: Buffer + ?Sized, R: BufferMut + ?Sized, O: RawOperation>(inbuf: &S, inoutbuf: &mut R, op: O) {
    unsafe {
        ffi::MPI_Reduce_local(inbuf.pointer(), inoutbuf.pointer_mut(), inbuf.count(),
          inbuf.datatype().raw(), op.raw());
    }
}

/// A request object for an immediate (non-blocking) barrier operation
///
/// # Examples
///
/// See `examples/immediate_barrier.rs`
///
/// # Standard section(s)
///
/// 3.7.1
#[must_use]
pub struct BarrierRequest(MPI_Request);

impl Drop for BarrierRequest {
    fn drop(&mut self) {
        unsafe {
            assert!(self.raw() == ffi::RSMPI_REQUEST_NULL,
                "asynchronous barrier request dropped without ascertaining completion.");
        }
    }
}

impl RawRequest for BarrierRequest {
    unsafe fn raw(&self) -> MPI_Request { self.0 }
    unsafe fn ptr_mut(&mut self) -> *mut MPI_Request { &mut (self.0) }
}

/// Non-blocking barrier synchronization among all processes in a `Communicator`
///
/// Calling processes (or threads within the calling processes) enter the barrier. Completion
/// methods on the associated request object will block until all processes have entered.
///
/// # Standard section(s)
///
/// 5.12.1
pub trait ImmediateBarrier {
    /// Partake in a barrier synchronization across all processes in the `Communicator` `&self`.
    ///
    /// # Examples
    ///
    /// See `examples/immediate_barrier.rs`
    fn immediate_barrier(&self) -> BarrierRequest;
}

impl<C: Communicator> ImmediateBarrier for C {
    fn immediate_barrier(&self) -> BarrierRequest {
        let mut request = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Ibarrier(self.communicator().raw(), &mut request as *mut MPI_Request); }
        BarrierRequest(request)
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;

use std::error;
use std::fs;
use std::io::{Read,SeekFrom,Seek};
use std::path::Path;

use self::byteorder::{LittleEndian,ByteOrder};

#[derive(Clone,Debug)]

/// BIOS parameter block describes the FAT filesystem.
pub struct BIOSParam {
    pub bytes_per_sector: u16,
    pub sectors_per_cluster: u8,
    pub reserved_sectors: u16,
    pub fat_count: u8,
    pub max_roots: u16,
    pub sectors: u32,
    pub media_id: u8,
    pub sectors_per_fat: u32,
}

#[test]
fn test_bios_param_calculations() {
    let mut params = BIOSParam::new();
    params.sectors = 1024;
    params.bytes_per_sector = 512;
    params.sectors_per_cluster = 4;
    assert_eq!(params.len(), 524288 as usize);
    assert_eq!(params.clusters(), 256 as usize);
}

#[allow(dead_code)]
impl BIOSParam {
    /// Create a new empty BIOS parameter block (BPB)
    pub fn new() -> BIOSParam {
        BIOSParam {
            bytes_per_sector: 0,
            sectors_per_cluster: 0,
            reserved_sectors: 0,
            fat_count: 2,
            max_roots: 0,
            sectors: 0,
            media_id: 0,
            sectors_per_fat: 0,
        }
    }

    /// Extract the BIOS Parameter Block (BPB) from the FAT filesystem image.
    pub fn from_file<P: AsRef<Path>>(p: P, o: usize)
        -> Result<BIOSParam, Box<error::Error>>
    {
        let mut boot_sector: Vec<u8> = vec![0; 512];
        let mut file = fs::File::open(p.as_ref())?;
        file.seek(SeekFrom::Start(o as u64))?;
        file.read_exact(&mut boot_sector)?;

        let mut params = BIOSParam::new();

        params.bytes_per_sector = LittleEndian::read_u16(&boot_sector[11..13]);
        params.sectors_per_cluster = boot_sector[13];
        params.reserved_sectors = LittleEndian::read_u16(&boot_sector[14..16]);
        params.fat_count = boot_sector[16];
        params.max_roots = LittleEndian::read_u16(&boot_sector[17..19]);
        params.sectors = LittleEndian::read_u16(&boot_sector[19..21]) as u32;
        if params.sectors == 0 {
            // 4 byte sector count at 0x020
            params.sectors = LittleEndian::read_u32(&boot_sector[32..37]);
        }
        params.media_id = boot_sector[21];
        params.sectors_per_fat = LittleEndian::read_u16(&boot_sector[22..24]) as u32;
        if params.sectors_per_fat == 0 {
            // 4 byte sectors per fat count at 0x024
            params.sectors_per_fat = LittleEndian::read_u32(&boot_sector[36..41]);
        }
        return Ok(params);
    }

    /// Reported length of FAT filesystem in bytes.
    pub fn len(&self) -> usize {
        return self.sectors as usize * self.bytes_per_sector as usize;
    }

    /// Reported number of clusters within FAT filesystem.
    pub fn clusters(&self) -> usize {
        if self.sectors_per_cluster == 0 {
            return 0;
        }
        return self.sectors as usize / self.sectors_per_cluster as usize;
    }
}
<commit_msg>bios_param: Fix style issue. No functional change<commit_after>extern crate byteorder;

use std::error;
use std::fs;
use std::io::{Read,SeekFrom,Seek};
use std::path::Path;

use self::byteorder::{LittleEndian,ByteOrder};

#[derive(Clone,Debug)]

/// BIOS parameter block describes the FAT filesystem.
pub struct BIOSParam {
    pub bytes_per_sector: u16,
    pub sectors_per_cluster: u8,
    pub reserved_sectors: u16,
    pub fat_count: u8,
    pub max_roots: u16,
    pub sectors: u32,
    pub media_id: u8,
    pub sectors_per_fat: u32,
}

#[test]
fn test_bios_param_calculations() {
    let mut params = BIOSParam::new();
    params.sectors = 1024;
    params.bytes_per_sector = 512;
    params.sectors_per_cluster = 4;
    assert_eq!(params.len(), 524288 as usize);
    assert_eq!(params.clusters(), 256 as usize);
}

#[allow(dead_code)]
impl BIOSParam {
    /// Create a new empty BIOS parameter block (BPB)
    pub fn new() -> BIOSParam {
        BIOSParam {
            bytes_per_sector: 0,
            sectors_per_cluster: 0,
            reserved_sectors: 0,
            fat_count: 2,
            max_roots: 0,
            sectors: 0,
            media_id: 0,
            sectors_per_fat: 0,
        }
    }

    /// Extract the BIOS Parameter Block (BPB) from the FAT filesystem image.
    pub fn from_file<P: AsRef<Path>>(image_fn: P, offset: usize)
        -> Result<BIOSParam, Box<error::Error>>
    {
        let mut boot_sector: Vec<u8> = vec![0; 512];
        let mut file = fs::File::open(image_fn.as_ref())?;
        file.seek(SeekFrom::Start(offset as u64))?;
        file.read_exact(&mut boot_sector)?;

        let mut params = BIOSParam::new();

        params.bytes_per_sector = LittleEndian::read_u16(&boot_sector[11..13]);
        params.sectors_per_cluster = boot_sector[13];
        params.reserved_sectors = LittleEndian::read_u16(&boot_sector[14..16]);
        params.fat_count = boot_sector[16];
        params.max_roots = LittleEndian::read_u16(&boot_sector[17..19]);
        params.sectors = LittleEndian::read_u16(&boot_sector[19..21]) as u32;
        if params.sectors == 0 {
            // 4 byte sector count at 0x020
            params.sectors = LittleEndian::read_u32(&boot_sector[32..37]);
        }
        params.media_id = boot_sector[21];
        params.sectors_per_fat = LittleEndian::read_u16(&boot_sector[22..24]) as u32;
        if params.sectors_per_fat == 0 {
            // 4 byte sectors per fat count at 0x024
            params.sectors_per_fat = LittleEndian::read_u32(&boot_sector[36..41]);
        }
        return Ok(params);
    }

    /// Reported length of FAT filesystem in bytes.
    pub fn len(&self) -> usize {
        return self.sectors as usize * self.bytes_per_sector as usize;
    }

    /// Reported number of clusters within FAT filesystem.
    pub fn clusters(&self) -> usize {
        if self.sectors_per_cluster == 0 {
            return 0;
        }
        return self.sectors as usize / self.sectors_per_cluster as usize;
    }
}
<|endoftext|>


<commit_before>use gfx_app::{ColorFormat, DepthFormat};
use gfx_app::renderer::EncoderQueue;
use gfx;
use terrain;
use character;
use specs;
use std::time::Instant;
use character::character::CharacterSprite;

pub type Delta = f32;

pub struct DrawSystem<D: gfx::Device> {
  render_target_view: gfx::handle::RenderTargetView<D::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<D::Resources, DepthFormat>,
  terrain_system: terrain::DrawSystem<D::Resources>,
  character_system: character::DrawSystem<D::Resources>,
  encoder_queue: EncoderQueue<D>,
  game_time: Instant,
  frames: u32,
  cool_down: f32,
}

impl<D: gfx::Device> DrawSystem<D> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<D::Resources, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<D::Resources, DepthFormat>,
                encoder_queue: EncoderQueue<D>)
                -> DrawSystem<D>
    where F: gfx::Factory<D::Resources>
  {
    DrawSystem {
      render_target_view: rtv.clone(),
      depth_stencil_view: dsv.clone(),
      terrain_system: terrain::DrawSystem::new(factory, rtv.clone(), dsv.clone()),
      character_system: character::DrawSystem::new(factory, rtv.clone(), dsv.clone()),
      encoder_queue,
      game_time: Instant::now(),
      frames: 0,
      cool_down: 1.0
    }
  }
}

impl<D> specs::System<Delta> for DrawSystem<D>
  where D: gfx::Device,
        D::CommandBuffer: Send,
{
  fn run(&mut self, arg: specs::RunArg, delta: Delta) {
    use specs::Join;
    let mut encoder = self.encoder_queue.receiver.recv().unwrap();
    let (mut terrain, mut character, mut sprite) = arg.fetch(|w| {
      if self.cool_down == 0.0 {
        self.cool_down = self.cool_down + 0.07;
      }
      self.cool_down = (self.cool_down - delta).max(0.0);
      (w.read::<terrain::Drawable>(),
       w.write::<character::CharacterDrawable>(),
       w.write::<CharacterSprite>())
    });

    let current_time = Instant::now();
    self.frames = self.frames + 1;
    if cfg!(feature = "dev") && (current_time.duration_since(self.game_time ).as_secs()) >= 1 {
      println!("{:?} ms/frames", 1000.0 / self.frames as f32);
      self.frames = 0;
      self.game_time = Instant::now();
    }

    encoder.clear(&self.render_target_view, [16.0 / 256.0, 16.0 / 256.0, 20.0 / 256.0, 1.0]);
    encoder.clear_depth(&self.depth_stencil_view, 1.0);

    for t in (&mut terrain).join() {
      self.terrain_system.draw(t, &mut encoder);
    }

    for (c, s) in (&mut character, &mut sprite).join() {
      if self.cool_down == 0.0 {
        s.update();
      }
      self.character_system.draw(c, s, &mut encoder);
    }

    if let Err(e) = self.encoder_queue.sender.send(encoder) {
      println!("Disconnected, cannot return encoder to mpsc: {}", e);
    };
  }
}
<commit_msg>Run terrain and character system draw calls in same join block<commit_after>use gfx_app::{ColorFormat, DepthFormat};
use gfx_app::renderer::EncoderQueue;
use gfx;
use terrain;
use character;
use specs;
use std::time::Instant;
use character::character::CharacterSprite;

pub type Delta = f32;

pub struct DrawSystem<D: gfx::Device> {
  render_target_view: gfx::handle::RenderTargetView<D::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<D::Resources, DepthFormat>,
  terrain_system: terrain::DrawSystem<D::Resources>,
  character_system: character::DrawSystem<D::Resources>,
  encoder_queue: EncoderQueue<D>,
  game_time: Instant,
  frames: u32,
  cool_down: f32,
}

impl<D: gfx::Device> DrawSystem<D> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<D::Resources, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<D::Resources, DepthFormat>,
                encoder_queue: EncoderQueue<D>)
                -> DrawSystem<D>
    where F: gfx::Factory<D::Resources>
  {
    DrawSystem {
      render_target_view: rtv.clone(),
      depth_stencil_view: dsv.clone(),
      terrain_system: terrain::DrawSystem::new(factory, rtv.clone(), dsv.clone()),
      character_system: character::DrawSystem::new(factory, rtv.clone(), dsv.clone()),
      encoder_queue,
      game_time: Instant::now(),
      frames: 0,
      cool_down: 1.0
    }
  }
}

impl<D> specs::System<Delta> for DrawSystem<D>
  where D: gfx::Device,
        D::CommandBuffer: Send,
{
  fn run(&mut self, arg: specs::RunArg, delta: Delta) {
    use specs::Join;
    let mut encoder = self.encoder_queue.receiver.recv().unwrap();
    let (mut terrain, mut character, mut sprite) = arg.fetch(|w| {
      if self.cool_down == 0.0 {
        self.cool_down = self.cool_down + 0.07;
      }
      self.cool_down = (self.cool_down - delta).max(0.0);
      (w.write::<terrain::Drawable>(),
       w.write::<character::CharacterDrawable>(),
       w.write::<CharacterSprite>())
    });

    let current_time = Instant::now();
    self.frames = self.frames + 1;
    if cfg!(feature = "dev") && (current_time.duration_since(self.game_time ).as_secs()) >= 1 {
      println!("{:?} ms/frames", 1000.0 / self.frames as f32);
      self.frames = 0;
      self.game_time = Instant::now();
    }

    encoder.clear(&self.render_target_view, [16.0 / 256.0, 16.0 / 256.0, 20.0 / 256.0, 1.0]);
    encoder.clear_depth(&self.depth_stencil_view, 1.0);

    for (t, c, s) in (&mut terrain, &mut character, &mut sprite).join() {
      self.terrain_system.draw(t, &mut encoder);
      if self.cool_down == 0.0 {
        s.update();
      }
      self.character_system.draw(c, s, &mut encoder);
    }

    if let Err(e) = self.encoder_queue.sender.send(encoder) {
      println!("Disconnected, cannot return encoder to mpsc: {}", e);
    };
  }
}
<|endoftext|>


<commit_before><commit_msg>refactor channel node remove operation<commit_after><|endoftext|>


<commit_before>fn get_words(sec: &str, w: usize) -> Vec<String> {
    let lim = sec.len() - w + 1;
    let mut words = Vec::new();

    for i in 0..lim {
        let mut word = String::new();
        word.push(sec.as_bytes()[i] as char);
        word.push(sec.as_bytes()[i + 1] as char);
        word.push(sec.as_bytes()[i + 2] as char);

        words.push(word);
    }

    words
}

fn get_hsp(w1: &String, w2: &String, match_scr: i32, mism_scr: i32) -> i32 {
    let mut hsp = 0;

    let mut chars2 = w2.chars();
    for c in w1.chars() {
        hsp += if c == chars2.next().unwrap() {
            match_scr
        } else {
            mism_scr
        }
    }

    hsp
}

fn expand_words(align1: &mut String,
                align2: &mut String,
                sec_1: &str,
                sec_2: &str,
                indx1_i: &mut usize,
                indx1_f: &mut usize,
                indx2_i: &mut usize,
                indx2_f: &mut usize)
                -> (bool, bool) {
    if *indx1_i != 0 && *indx2_i != 0 {
        let mut ps_align1 = align1.chars().rev().collect::<String>();
        let mut ps_align2 = align2.chars().rev().collect::<String>();
        ps_align1.push(sec_1.as_bytes()[*indx1_i - 1] as char);
        ps_align2.push(sec_2.as_bytes()[*indx2_i - 1] as char);
        *align1 = ps_align1.chars().rev().collect::<String>();
        *align2 = ps_align2.chars().rev().collect::<String>();
        *indx1_i -= 1;
        *indx2_i -= 1;
    }

    if *indx1_f < sec_1.len() && *indx2_f < sec_2.len() {
        align1.push(sec_1.as_bytes()[*indx1_f] as char);
        align2.push(sec_2.as_bytes()[*indx2_f] as char);
        *indx1_f += 1;
        *indx2_f += 1;
    }

    // let mut begin = true;
    // let mut end = true;

    // begin = if *indx1_i != 0 && *indx2_i != 0 {false} else {true};
    // end = if *indx1_f < sec_1.len() && *indx2_f < sec_2.len() {
    //     false
    // } else {
    //     true
    // };
    // (begin, end)
    (!(*indx1_i != 0 && *indx2_i != 0), !(*indx1_f < sec_1.len() && *indx2_f < sec_2.len()))
}

fn print_alignment(align1: String, align2: String) {
    let mut chars2 = align2.chars();
    let mut end_first_it = false;
    let mut algn1 = String::new();
    let mut algn2 = String::new();

    for c1 in align1.chars() {
        let c2 = chars2.next().unwrap();
        if c1 == c2 {
            end_first_it = true;
        }
        if end_first_it {
            algn1.push(c1);
            algn2.push(c2);
        }
    }

    println!(">{}\n>{}", algn1, algn2);
}

fn align_secuence(sec_1: &str,
                  sec_2: &str,
                  w: usize,
                  match_scr: i32,
                  mism_scr: i32,
                  hps: i32,
                  u: i32) {
    let words_s1 = get_words(sec_1, w);
    let words_s2 = get_words(sec_2, w);

    let mut indx1_i: usize = 0;
    let mut indx2_i: usize = 0;
    let mut align1 = String::new();
    let mut align2 = String::new();

    'outer: for word1 in words_s1.iter() {
        indx2_i = 0;
        for word2 in words_s2.iter() {
            if get_hsp(word1, word2, match_scr, mism_scr) >= hps {
                align1 = word1.clone();
                align2 = word2.clone();
                break 'outer;
            }
            indx2_i += 1;
        }
        indx1_i += 1;
    }

    let mut indx1_f = indx1_i + w;
    let mut indx2_f = indx2_i + w;

    let mut algn1 = align1.clone();
    let mut algn2 = align2.clone();

    println!("{}, {}", algn1, algn2);

    while {
        let hsp = get_hsp(&align1, &align2, match_scr, mism_scr);
        println!("{}, {}", align1, align2);
        println!("{} -> {}", hsp, hsp > u);
        println!("");
        hsp > u
    } {
        algn1 = align1.clone();
        algn2 = align2.clone();

        let (a, b) = expand_words(&mut align1,
                                  &mut align2,
                                  &sec_1,
                                  &sec_2,
                                  &mut indx1_i,
                                  &mut indx1_f,
                                  &mut indx2_i,
                                  &mut indx2_f);

        if a && b {
            algn1 = align1.clone();
            algn2 = align2.clone();
            break;
        }
    }

    print_alignment(algn1, algn2);
}

fn main() {
    align_secuence("TCAGATCACTC", "GTATCGCTC", 3, 1, -2, 3, -3);
}
<commit_msg>Code cleaned :)<commit_after>fn get_words(sec: &str, w: usize) -> Vec<String> {
    let lim = sec.len() - w + 1;
    let mut words = Vec::new();

    for i in 0..lim {
        let mut word = String::new();
        word.push(sec.as_bytes()[i] as char);
        word.push(sec.as_bytes()[i + 1] as char);
        word.push(sec.as_bytes()[i + 2] as char);

        words.push(word);
    }

    words
}

fn get_hsp(w1: &String, w2: &String, match_scr: i32, mism_scr: i32) -> i32 {
    let mut hsp = 0;

    let mut chars2 = w2.chars();
    for c in w1.chars() {
        hsp += if c == chars2.next().unwrap() {
            match_scr
        } else {
            mism_scr
        }
    }

    hsp
}

fn expand_words(align1: &mut String,
                align2: &mut String,
                sec_1: &str,
                sec_2: &str,
                indx1_i: &mut usize,
                indx1_f: &mut usize,
                indx2_i: &mut usize,
                indx2_f: &mut usize)
                -> (bool, bool) {
    if *indx1_i != 0 && *indx2_i != 0 {
        let mut ps_align1 = align1.chars().rev().collect::<String>();
        let mut ps_align2 = align2.chars().rev().collect::<String>();
        ps_align1.push(sec_1.as_bytes()[*indx1_i - 1] as char);
        ps_align2.push(sec_2.as_bytes()[*indx2_i - 1] as char);
        *align1 = ps_align1.chars().rev().collect::<String>();
        *align2 = ps_align2.chars().rev().collect::<String>();
        *indx1_i -= 1;
        *indx2_i -= 1;
    }

    if *indx1_f < sec_1.len() && *indx2_f < sec_2.len() {
        align1.push(sec_1.as_bytes()[*indx1_f] as char);
        align2.push(sec_2.as_bytes()[*indx2_f] as char);
        *indx1_f += 1;
        *indx2_f += 1;
    }

    (!(*indx1_i != 0 && *indx2_i != 0), !(*indx1_f < sec_1.len() && *indx2_f < sec_2.len()))
}

fn print_alignment(align1: String, align2: String) {
    let mut chars2 = align2.chars();
    let mut end_first_it = false;
    let mut algn1 = String::new();
    let mut algn2 = String::new();

    for c1 in align1.chars() {
        let c2 = chars2.next().unwrap();
        if c1 == c2 {
            end_first_it = true;
        }
        if end_first_it {
            algn1.push(c1);
            algn2.push(c2);
        }
    }

    println!(">{}\n>{}", algn1, algn2);
}

fn align_secuence(sec_1: &str,
                  sec_2: &str,
                  w: usize,
                  match_scr: i32,
                  mism_scr: i32,
                  hps: i32,
                  u: i32) {
    let words_s1 = get_words(sec_1, w);
    let words_s2 = get_words(sec_2, w);

    let mut indx1_i: usize = 0;
    let mut indx2_i: usize = 0;
    let mut align1 = String::new();
    let mut align2 = String::new();

    'outer: for word1 in words_s1.iter() {
        indx2_i = 0;
        for word2 in words_s2.iter() {
            if get_hsp(word1, word2, match_scr, mism_scr) >= hps {
                align1 = word1.clone();
                align2 = word2.clone();
                break 'outer;
            }
            indx2_i += 1;
        }
        indx1_i += 1;
    }

    let mut indx1_f = indx1_i + w;
    let mut indx2_f = indx2_i + w;

    let mut algn1 = align1.clone();
    let mut algn2 = align2.clone();

    while {
        let hsp = get_hsp(&align1, &align2, match_scr, mism_scr);
        // println!("{}, {}\n{} -> {}\n", align1, align2, hsp, hsp > u);
        hsp > u
    } {
        algn1 = align1.clone();
        algn2 = align2.clone();

        let (a, b) = expand_words(&mut align1, &mut align2, &sec_1, &sec_2, &mut indx1_i, &mut indx1_f, &mut indx2_i, &mut indx2_f);

        if a && b {
            algn1 = align1.clone();
            algn2 = align2.clone();
            break;
        }
    }

    print_alignment(algn1, algn2);
}

fn main() {
    align_secuence("TCAGATCACGG", "GTATCGCTC", 3, 1, -2, 3, -3);
}
<|endoftext|>


<commit_before>use bvh::*;
use bounding_hierarchy::BHShape;
use std::collections::HashSet;

// TODO Consider: Instead of getting the scene's shapes passed, let leaf nodes store an AABB
// that is updated from the outside, perhaps by passing not only the indices of the changed
// shapes, but also their new AABBs into optimize().

impl BVH {
    /// Optimizes the `BVH` by batch-reorganizing updated nodes.
    /// Based on https://github.com/jeske/SimpleScene/blob/master/SimpleScene/Util/ssBVH/ssBVH.cs
    ///
    /// Needs all the scene's shapes, plus the indices of the shapes that were updated.
    ///
    pub fn optimize<Shape: BHShape>(&mut self,
                                    refit_shape_indices: &HashSet<usize>,
                                    shapes: &[Shape]) {
        let mut refit_node_indices: HashSet<usize> = refit_shape_indices.iter()
            .map(|x| shapes[*x].bh_node_index())
            .collect();

        // As long as we have refit nodes left, take the list of refit nodes
        // with the highest depth (sweep nodes) and try to rotate them all
        while refit_node_indices.len() > 0 {
            let mut max_depth = 0;
            let mut sweep_node_indices: Vec<usize> = Vec::new();

            // Find max_depth and sweep_node_indices in one iteration
            for refit_node_index in refit_node_indices.iter() {
                let depth = match self.nodes[*refit_node_index] {
                    BVHNode::Node { depth, .. } => depth,
                    BVHNode::Leaf { depth, .. } => depth,
                    BVHNode::Dummy => panic!("Dummy node found during BVH optimization!"),
                };

                if depth > max_depth {
                    max_depth = depth;
                    sweep_node_indices.clear();
                    sweep_node_indices.push(*refit_node_index);
                } else if depth == max_depth {
                    sweep_node_indices.push(*refit_node_index);
                }
            }

            // Try to find a useful tree rotation with all nodes previously found
            for sweep_node_index in sweep_node_indices.iter() {
                // This node does not need to be checked again
                refit_node_indices.remove(&sweep_node_index);

                let new_refit_node_index = self.try_rotate(*sweep_node_index, shapes);

                // Instead of finding a useful tree rotation, we found another node
                // that we should check, so we add its index to the refit_node_indices.
                if let Some(index) = new_refit_node_index {
                    refit_node_indices.insert(index);
                }
            }
        }
    }

    /// Checks if there is a way to rotate a child and a grandchild (or two grandchildren) of
    /// the given node (specified by `node_index`) that would improve the `BVH`.
    /// If there is, the best rotation found is performed.
    /// Relies on the children and transitive children of the given node having correct AABBs.
    ///
    /// Returns Some(index_of_node) if a new node was found that should be used for optimization.
    ///
    fn try_rotate<Shape: BHShape>(&mut self, node_index: usize, shapes: &[Shape]) -> Option<usize> {
        let mut nodes = &mut self.nodes;

        let mut node_clone = nodes[node_index].clone();

        // Contains the surface area that would result from applying the currently favored rotation.
        // The rotation with the smallest SA will be applied in the end.
        // The value is calculated by child_l_aabb.surface_area() + child_r_aabb.surface_area()
        let mut best_SA = 0f32;

        // TODO Re-implement without mutability
        let mut parent_index: usize = 0;

        struct NodeData {
            index: usize,
            aabb: AABB,
        }

        // If this node is not a grandparent, update the AABB,
        // queue the parent for refitting, and bail out.
        // If it is a grandparent, calculate the current best_SA.
        let (child_l, child_r) = match node_clone {
            BVHNode::Node { parent, child_l, child_r, child_l_aabb, child_r_aabb, .. } => {
                if let BVHNode::Leaf { shape, .. } = nodes[child_l] {
                    let shape_l_index = shape;
                    if let BVHNode::Leaf { shape, .. } = nodes[child_r] {
                        let shape_r_index = shape;

                        // Update the AABBs saved for the children
                        // since at least one of them changed
                        let mut node = &mut nodes[node_index];
                        match node {
                            &mut BVHNode::Node { ref mut child_l_aabb,
                                                 ref mut child_r_aabb,
                                                 .. } => {
                                *child_l_aabb = shapes[shape_l_index].aabb();
                                *child_r_aabb = shapes[shape_r_index].aabb();
                            }
                            _ => unreachable!(),
                        }

                        return Some(parent);
                    }
                }

                parent_index = parent;
                best_SA = child_l_aabb.surface_area() + child_r_aabb.surface_area();
                (NodeData{index: child_l, aabb: child_l_aabb},
                 NodeData{index:child_r, aabb:child_r_aabb})
            }
            BVHNode::Leaf { parent, .. } => {
                return Some(parent);
            }
            BVHNode::Dummy => panic!("Dummy node found during BVH optimization!"),
        };

        // Stores the Rotation that would result in the surface area best_SA,
        // thus being the favored rotation that will be executed after considering all rotations.
        let mut best_rotation: Option<(usize, usize)> = None;

        // TODO Get indices and AABBs of all grandchildren

        macro_rules! consider_rotation {
            ($a:expr, $b:expr) => {
                // TODO Calculate surface area that would result from rotating the given nodes.
                let surface_area = 100f32;

                if surface_area < best_SA {
                    best_SA = surface_area;
                    best_rotation = Some(($a.index, $b.index));
                }
                unimplemented!();
            };
        }

        // Child to grandchild rotations
        consider_rotation!(child_l, child_rl);
        consider_rotation!(child_l, child_rr);
        consider_rotation!(child_r, child_ll);
        consider_rotation!(child_r, child_lr);
        // Grandchild to grandchild rotations
        consider_rotation!(child_ll, child_rl);
        consider_rotation!(child_ll, child_rr);

        let new_refit_node_index = if parent_index > 0 {
            Some(parent_index)
        } else {
            None
        };

        if best_rotation == None {
            // TODO Recalculate this node's AABBs (child_l_aabb, child_r_aabb)
            // according to the children nodes' AABBs.

            // Even with no rotation being useful for this node, a parent node's rotation
            // could be beneficial, so queue the parent sometimes.
            // TODO Return None most of the time, randomly
            // (see https://github.com/jeske/SimpleScene/blob/master/SimpleScene/Util/ssBVH/ssBVH_Node.cs#L307)
            new_refit_node_index
        } else {
            // TODO Perform rotation using rotate()

            // TODO Update all changed node AABBs

            // Return parent node's index for upcoming refitting,
            // since this node just changed its AABB
            new_refit_node_index
        }
    }

    /// Switch two nodes by rewiring the involved indices (not by moving them in the nodes slice).
    fn rotate(&mut self, node_a_index: usize, node_b_index: usize) {
        let mut nodes = &mut self.nodes;

        macro_rules! should_not_happen {
            () => ( panic!("While rotating BVH nodes, something unexpected happened."); );
            ($s:expr) => ( panic!("While rotating BVH nodes, something unexpected happened: {}", $s); );
        }

        #[allow(dead_code)] // The compiler falsely detects dead code here
        fn get_parent_index(nodes: &Vec<BVHNode>, node_index: usize) -> usize {
            let node = &nodes[node_index];

            match *node {
                BVHNode::Node { parent, .. } |
                BVHNode::Leaf { parent, .. } => parent,
                _ => should_not_happen!(),
            }
        }

        // Get parent indices
        let node_a_parent_index = get_parent_index(nodes, node_a_index);
        let node_b_parent_index = get_parent_index(nodes, node_b_index);

        #[allow(dead_code)] // The compiler falsely detects dead code here
        fn get_is_left_child(nodes: &Vec<BVHNode>,
                             node_index: usize,
                             node_parent_index: usize)
                             -> bool {
            let node_parent = &nodes[node_parent_index];

            match *node_parent {
                BVHNode::Node { child_l, .. } => child_l == node_index,
                _ => should_not_happen!(),
            }
        }

        // Get info about the nodes being a left or right child
        let node_a_is_left_child = get_is_left_child(nodes, node_a_index, node_a_parent_index);
        let node_b_is_left_child = get_is_left_child(nodes, node_b_index, node_b_parent_index);

        #[allow(dead_code)] // The compiler falsely detects dead code here
        fn connect_nodes(nodes: &mut Vec<BVHNode>,
                         child_index: usize,
                         parent_index: usize,
                         left_child: bool) {
            // Set parent's child and get its depth
            let parent_depth = {
                let mut parent = &mut nodes[parent_index];
                match parent {
                    &mut BVHNode::Node { ref mut child_l, ref mut child_r, depth, .. } => {
                        if left_child {
                            *child_l = child_index;
                        } else {
                            *child_r = child_index;
                        }
                        depth
                    }
                    _ => should_not_happen!(),
                }
            };

            // Set child's parent and depth
            {
                let mut child = &mut nodes[child_index];
                match child {
                    &mut BVHNode::Node { ref mut parent, ref mut depth, .. } |
                    &mut BVHNode::Leaf { ref mut parent, ref mut depth, .. } => {
                        *parent = parent_index;
                        *depth = parent_depth + 1;
                    }
                    _ => should_not_happen!(),
                };
            }
        }

        // Perform the switch
        connect_nodes(nodes,
                      node_a_index,
                      node_b_parent_index,
                      node_b_is_left_child);
        connect_nodes(nodes,
                      node_b_index,
                      node_a_parent_index,
                      node_a_is_left_child);
    }
}

#[cfg(test)]
pub mod tests {
    use bvh::BVH;

    #[test]
    /// Tests if the optimize function tries to change a fresh BVH even though it shouldn't
    fn test_optimizing_new_bvh() {
        let (mut shapes, mut bvh) = build_some_bh::<BVH>();

        let refit_shape_indices: HashSet<usize> = (0..shapes.len()).collect();
        bvh.optimize(&refit_shape_indices, &mut shapes);
    }

    // TODO Add tests for:
    // * correct parent
    // * correct depth
    // * correct BVH after optimizing
    // * correct parent and depth after optimizing
}
<commit_msg>Get grandchildren data<commit_after>use bvh::*;
use bounding_hierarchy::BHShape;
use aabb::AABB;
use std::collections::HashSet;

// TODO Consider: Instead of getting the scene's shapes passed, let leaf nodes store an AABB
// that is updated from the outside, perhaps by passing not only the indices of the changed
// shapes, but also their new AABBs into optimize().

impl BVH {
    /// Optimizes the `BVH` by batch-reorganizing updated nodes.
    /// Based on https://github.com/jeske/SimpleScene/blob/master/SimpleScene/Util/ssBVH/ssBVH.cs
    ///
    /// Needs all the scene's shapes, plus the indices of the shapes that were updated.
    ///
    pub fn optimize<Shape: BHShape>(&mut self,
                                    refit_shape_indices: &HashSet<usize>,
                                    shapes: &[Shape]) {
        let mut refit_node_indices: HashSet<usize> = refit_shape_indices.iter()
            .map(|x| shapes[*x].bh_node_index())
            .collect();

        // As long as we have refit nodes left, take the list of refit nodes
        // with the highest depth (sweep nodes) and try to rotate them all
        while refit_node_indices.len() > 0 {
            let mut max_depth = 0;
            let mut sweep_node_indices: Vec<usize> = Vec::new();

            // Find max_depth and sweep_node_indices in one iteration
            for refit_node_index in refit_node_indices.iter() {
                let depth = match self.nodes[*refit_node_index] {
                    BVHNode::Node { depth, .. } => depth,
                    BVHNode::Leaf { depth, .. } => depth,
                    BVHNode::Dummy => panic!("Dummy node found during BVH optimization!"),
                };

                if depth > max_depth {
                    max_depth = depth;
                    sweep_node_indices.clear();
                    sweep_node_indices.push(*refit_node_index);
                } else if depth == max_depth {
                    sweep_node_indices.push(*refit_node_index);
                }
            }

            // Try to find a useful tree rotation with all nodes previously found
            for sweep_node_index in sweep_node_indices.iter() {
                // This node does not need to be checked again
                refit_node_indices.remove(&sweep_node_index);

                let new_refit_node_index = self.try_rotate(*sweep_node_index, shapes);

                // Instead of finding a useful tree rotation, we found another node
                // that we should check, so we add its index to the refit_node_indices.
                if let Some(index) = new_refit_node_index {
                    refit_node_indices.insert(index);
                }
            }
        }
    }

    /// Checks if there is a way to rotate a child and a grandchild (or two grandchildren) of
    /// the given node (specified by `node_index`) that would improve the `BVH`.
    /// If there is, the best rotation found is performed.
    /// Relies on the children and transitive children of the given node having correct AABBs.
    ///
    /// Returns Some(index_of_node) if a new node was found that should be used for optimization.
    ///
    fn try_rotate<Shape: BHShape>(&mut self, node_index: usize, shapes: &[Shape]) -> Option<usize> {
        let mut nodes = &mut self.nodes;

        let mut node_clone = nodes[node_index].clone();

        // Contains the surface area that would result from applying the currently favored rotation.
        // The rotation with the smallest SA will be applied in the end.
        // The value is calculated by child_l_aabb.surface_area() + child_r_aabb.surface_area()
        let mut best_SA = 0f32;

        // TODO Re-implement without mutability
        let mut parent_index: usize = 0;

        struct NodeData {
            index: usize,
            aabb: AABB,
        }

        // If this node is not a grandparent, update the AABB,
        // queue the parent for refitting, and bail out.
        // If it is a grandparent, calculate the current best_SA.
        let (child_l, child_r) = match node_clone {
            BVHNode::Node { parent, child_l, child_r, child_l_aabb, child_r_aabb, .. } => {
                if let BVHNode::Leaf { shape, .. } = nodes[child_l] {
                    let shape_l_index = shape;
                    if let BVHNode::Leaf { shape, .. } = nodes[child_r] {
                        let shape_r_index = shape;

                        // Update the AABBs saved for the children
                        // since at least one of them changed
                        let mut node = &mut nodes[node_index];
                        match node {
                            &mut BVHNode::Node { ref mut child_l_aabb,
                                                 ref mut child_r_aabb,
                                                 .. } => {
                                *child_l_aabb = shapes[shape_l_index].aabb();
                                *child_r_aabb = shapes[shape_r_index].aabb();
                            }
                            _ => unreachable!(),
                        }

                        return Some(parent);
                    }
                }

                parent_index = parent;
                best_SA = child_l_aabb.surface_area() + child_r_aabb.surface_area();
                (NodeData{index: child_l, aabb: child_l_aabb},
                 NodeData{index:child_r, aabb:child_r_aabb})
            }
            BVHNode::Leaf { parent, .. } => {
                return Some(parent);
            }
            BVHNode::Dummy => panic!("Dummy node found during BVH optimization!"),
        };

        // Stores the Rotation that would result in the surface area best_SA,
        // thus being the favored rotation that will be executed after considering all rotations.
        let mut best_rotation: Option<(usize, usize)> = None;

        macro_rules! consider_rotation {
            ($a:expr, $b:expr) => {
                // TODO Calculate surface area that would result from rotating the given nodes.
                let surface_area = 100f32;

                if surface_area < best_SA {
                    best_SA = surface_area;
                    best_rotation = Some(($a.index, $b.index));
                }
                unimplemented!();
            };
        }

        macro_rules! get_children_node_data {
            ($node:expr) => ({
                let node = &nodes[$node.index];
                match *node {
                    BVHNode::Node { child_l, child_r, child_l_aabb, child_r_aabb, .. } => {
                        Some((NodeData{ index: child_l, aabb: child_l_aabb},
                            NodeData{ index: child_r, aabb: child_r_aabb}))
                    }
                    BVHNode::Leaf { .. } => {
                        None
                    }
                    BVHNode::Dummy => panic!("Dummy node found during BVH optimization!"),
                }
            });
        }

        // Get indices and AABBs of all grandchildren
        let left_children_nodes = get_children_node_data!(child_l);
        let right_children_nodes = get_children_node_data!(child_r);

        // Child to grandchild rotations
        if let Some((child_rl, child_rr)) = right_children_nodes {
            consider_rotation!(child_l, child_rl);
            consider_rotation!(child_l, child_rr);
        }
        if let Some((child_ll, child_lr)) = left_children_nodes {
            consider_rotation!(child_r, child_ll);
            consider_rotation!(child_r, child_lr);

            // Grandchild to grandchild rotations
            if let Some((child_rl, child_rr)) = right_children_nodes {
                consider_rotation!(child_ll, child_rl);
                consider_rotation!(child_ll, child_rr);
            }
        }

        let new_refit_node_index = if parent_index > 0 {
            Some(parent_index)
        } else {
            None
        };

        if best_rotation == None {
            // TODO Recalculate this node's AABBs (child_l_aabb, child_r_aabb)
            // according to the children nodes' AABBs.

            // Even with no rotation being useful for this node, a parent node's rotation
            // could be beneficial, so queue the parent sometimes.
            // TODO Return None most of the time, randomly
            // (see https://github.com/jeske/SimpleScene/blob/master/SimpleScene/Util/ssBVH/ssBVH_Node.cs#L307)
            new_refit_node_index
        } else {
            // TODO Perform rotation using rotate()

            // TODO Update all changed node AABBs

            // Return parent node's index for upcoming refitting,
            // since this node just changed its AABB
            new_refit_node_index
        }
    }

    /// Switch two nodes by rewiring the involved indices (not by moving them in the nodes slice).
    fn rotate(&mut self, node_a_index: usize, node_b_index: usize) {
        let mut nodes = &mut self.nodes;

        macro_rules! should_not_happen {
            () => ( panic!("While rotating BVH nodes, something unexpected happened."); );
            ($s:expr) => ( panic!("While rotating BVH nodes, something unexpected happened: {}", $s); );
        }

        #[allow(dead_code)] // The compiler falsely detects dead code here
        fn get_parent_index(nodes: &Vec<BVHNode>, node_index: usize) -> usize {
            let node = &nodes[node_index];

            match *node {
                BVHNode::Node { parent, .. } |
                BVHNode::Leaf { parent, .. } => parent,
                _ => should_not_happen!(),
            }
        }

        // Get parent indices
        let node_a_parent_index = get_parent_index(nodes, node_a_index);
        let node_b_parent_index = get_parent_index(nodes, node_b_index);

        #[allow(dead_code)] // The compiler falsely detects dead code here
        fn get_is_left_child(nodes: &Vec<BVHNode>,
                             node_index: usize,
                             node_parent_index: usize)
                             -> bool {
            let node_parent = &nodes[node_parent_index];

            match *node_parent {
                BVHNode::Node { child_l, .. } => child_l == node_index,
                _ => should_not_happen!(),
            }
        }

        // Get info about the nodes being a left or right child
        let node_a_is_left_child = get_is_left_child(nodes, node_a_index, node_a_parent_index);
        let node_b_is_left_child = get_is_left_child(nodes, node_b_index, node_b_parent_index);

        #[allow(dead_code)] // The compiler falsely detects dead code here
        fn connect_nodes(nodes: &mut Vec<BVHNode>,
                         child_index: usize,
                         parent_index: usize,
                         left_child: bool) {
            // Set parent's child and get its depth
            let parent_depth = {
                let mut parent = &mut nodes[parent_index];
                match parent {
                    &mut BVHNode::Node { ref mut child_l, ref mut child_r, depth, .. } => {
                        if left_child {
                            *child_l = child_index;
                        } else {
                            *child_r = child_index;
                        }
                        depth
                    }
                    _ => should_not_happen!(),
                }
            };

            // Set child's parent and depth
            {
                let mut child = &mut nodes[child_index];
                match child {
                    &mut BVHNode::Node { ref mut parent, ref mut depth, .. } |
                    &mut BVHNode::Leaf { ref mut parent, ref mut depth, .. } => {
                        *parent = parent_index;
                        *depth = parent_depth + 1;
                    }
                    _ => should_not_happen!(),
                };
            }
        }

        // Perform the switch
        connect_nodes(nodes,
                      node_a_index,
                      node_b_parent_index,
                      node_b_is_left_child);
        connect_nodes(nodes,
                      node_b_index,
                      node_a_parent_index,
                      node_a_is_left_child);
    }
}

#[cfg(test)]
pub mod tests {
    use bvh::BVH;

    #[test]
    /// Tests if the optimize function tries to change a fresh BVH even though it shouldn't
    fn test_optimizing_new_bvh() {
        let (mut shapes, mut bvh) = build_some_bh::<BVH>();

        let refit_shape_indices: HashSet<usize> = (0..shapes.len()).collect();
        bvh.optimize(&refit_shape_indices, &mut shapes);
    }

    // TODO Add tests for:
    // * correct parent
    // * correct depth
    // * correct BVH after optimizing
    // * correct parent and depth after optimizing
}
<|endoftext|>


<commit_before>use super::super::request::Request;
use super::super::response::Response;
use super::super::middleware::{Middleware, Continue, Unwind, Status};
use super::super::alloy::Alloy;

use super::Chain;

/// The default `Chain` used by `Iron`.
/// `StackChain` runs each `Request` through all `Middleware` in its stack.
/// When it hits `Middleware` which returns `Unwind`, it passes
/// the `Request` back up through all `Middleware` it has hit so far.
pub struct StackChain {
    /// The storage used by `StackChain` to hold all `Middleware`
    /// that have been `linked` to it.
    stack: Vec<Box<Middleware + Send>>,
    exit_stack: Vec<Box<Middleware + Send>>
}

impl Clone for StackChain {
    fn clone(&self) -> StackChain {
        StackChain {
            stack: self.stack.clone(),
            exit_stack: self.exit_stack.clone()
        }
    }
}

/// `StackChain` is a `Chain`
impl Chain for StackChain {
    fn chain_enter(&mut self,
             request: &mut Request,
             response: &mut Response,
             alloy: &mut Alloy) -> Status {
        // The `exit_stack` will hold all `Middleware` that are passed through
        // in the enter loop. This is so we know to take exactly the same
        // path through `Middleware` in reverse order than we did on the way in.
        self.exit_stack = vec![];

        'enter: for middleware in self.stack.mut_iter() {
            match middleware.enter(request, response, alloy) {
                Unwind   => return Unwind,
                // Mark the middleware for traversal on exit.
                Continue => self.exit_stack.push(middleware.clone_box())
            }
        }

        Continue
    }

    fn chain_exit(&mut self,
             request: &mut Request,
             response: &mut Response,
             alloy: &mut Alloy) -> Status {
        // Reverse the stack so we go through in the reverse order.
        // i.e. LIFO.
        self.exit_stack.reverse();
        // Call each middleware's exit handler.
        'exit: for middleware in self.exit_stack.mut_iter() {
            let _ = middleware.exit(request, response, alloy);
        }

        Continue
    }

    /// Add `Middleware` to the `Chain`.
    fn link<M: Middleware>(&mut self, middleware: M) {
        self.stack.push(box middleware);
    }

    /// Create a new instance of `StackChain`.
    fn new() -> StackChain {
        StackChain {
            stack: vec![],
            exit_stack: vec![]
        }
    }
}

#[cfg(test)]
mod test {
    pub use super::*;
    pub use super::super::super::request::Request;
    pub use super::super::super::response::Response;
    pub use super::super::super::alloy::Alloy;
    pub use super::super::super::middleware::{Middleware, Status, Continue};

    #[deriving(Clone)]
    pub struct CallCount {
        enter: u64,
        exit: u64
    }

    impl Middleware for CallCount {
        fn enter(&mut self, _req: &mut Request,
                 _res: &mut Response, _alloy: &mut Alloy) -> Status {
            self.enter += 1; Continue
        }

        fn exit(&mut self, _req: &mut Request,
                _res: &mut Response, _alloy: &mut Alloy) -> Status {
            self.exit += 1; Continue
        }
    }

    mod dispatch {
        use super::{CallCount, Middleware};
        use super::super::StackChain;
        use super::super::super::Chain;
        use std::mem::{uninitialized, transmute};

        #[test]
        fn calls_middleware_enter() {
            let mut testchain: StackChain = Chain::new();
            testchain.link(CallCount { enter: 0, exit: 0 });
            unsafe {
                let _ = testchain.dispatch(uninitialized(), uninitialized(), uninitialized());
                assert_eq!(transmute::<Box<Middleware + Send>, Box<CallCount>>(testchain.stack.get(0).clone()).enter, 1);
                assert_eq!(transmute::<Box<Middleware + Send>, Box<CallCount>>(testchain.stack.get(0).clone()).exit, 1);
            }
        }
    }
}

<commit_msg>(test) Implemented basic testing using Arc and Mutex.<commit_after>use super::super::request::Request;
use super::super::response::Response;
use super::super::middleware::{Middleware, Continue, Unwind, Status};
use super::super::alloy::Alloy;

use super::Chain;

/// The default `Chain` used by `Iron`.
/// `StackChain` runs each `Request` through all `Middleware` in its stack.
/// When it hits `Middleware` which returns `Unwind`, it passes
/// the `Request` back up through all `Middleware` it has hit so far.
pub struct StackChain {
    /// The storage used by `StackChain` to hold all `Middleware`
    /// that have been `linked` to it.
    stack: Vec<Box<Middleware + Send>>,
    exit_stack: Vec<Box<Middleware + Send>>
}

impl Clone for StackChain {
    fn clone(&self) -> StackChain {
        StackChain {
            stack: self.stack.clone(),
            exit_stack: self.exit_stack.clone()
        }
    }
}

/// `StackChain` is a `Chain`
impl Chain for StackChain {
    fn chain_enter(&mut self,
             request: &mut Request,
             response: &mut Response,
             alloy: &mut Alloy) -> Status {
        // The `exit_stack` will hold all `Middleware` that are passed through
        // in the enter loop. This is so we know to take exactly the same
        // path through `Middleware` in reverse order than we did on the way in.
        self.exit_stack = vec![];

        'enter: for middleware in self.stack.mut_iter() {
            match middleware.enter(request, response, alloy) {
                Unwind   => return Unwind,
                // Mark the middleware for traversal on exit.
                Continue => self.exit_stack.push(middleware.clone_box())
            }
        }

        Continue
    }

    fn chain_exit(&mut self,
             request: &mut Request,
             response: &mut Response,
             alloy: &mut Alloy) -> Status {
        // Reverse the stack so we go through in the reverse order.
        // i.e. LIFO.
        self.exit_stack.reverse();
        // Call each middleware's exit handler.
        'exit: for middleware in self.exit_stack.mut_iter() {
            let _ = middleware.exit(request, response, alloy);
        }

        Continue
    }

    /// Add `Middleware` to the `Chain`.
    fn link<M: Middleware>(&mut self, middleware: M) {
        self.stack.push(box middleware);
    }

    /// Create a new instance of `StackChain`.
    fn new() -> StackChain {
        StackChain {
            stack: vec![],
            exit_stack: vec![]
        }
    }
}

#[cfg(test)]
mod test {
    pub use super::*;
    pub use super::super::super::request::Request;
    pub use super::super::super::response::Response;
    pub use super::super::super::alloy::Alloy;
    pub use super::super::super::middleware::{Middleware, Status, Continue};
    pub use std::sync::{Arc, Mutex};

    #[deriving(Clone)]
    pub struct CallCount {
        enter: Arc<Mutex<u64>>,
        exit: Arc<Mutex<u64>>
    }

    impl Middleware for CallCount {
        fn enter(&mut self, _req: &mut Request,
                 _res: &mut Response, _alloy: &mut Alloy) -> Status {
            let mut enter = self.enter.lock();
            *enter += 1;
            Continue
        }

        fn exit(&mut self, _req: &mut Request,
                _res: &mut Response, _alloy: &mut Alloy) -> Status {
            let mut exit = self.exit.lock();
            *exit += 1;
            Continue
        }
    }

    mod dispatch {
        use super::{CallCount, Arc, Mutex};
        use super::super::StackChain;
        use super::super::super::Chain;
        use std::mem::{uninitialized};

        #[test]
        fn calls_middleware_enter() {
            let mut testchain: StackChain = Chain::new();
            let enter = Arc::new(Mutex::new(0));
            let exit = Arc::new(Mutex::new(0));
            testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
            unsafe {
                let _ = testchain.dispatch(
                    uninitialized(),
                    uninitialized(),
                    uninitialized()
                );
            }
            assert_eq!(*enter.lock(), 1);
        }

        #[test]
        fn calls_middleware_exit() {
            let mut testchain: StackChain = Chain::new();
            let enter = Arc::new(Mutex::new(0));
            let exit = Arc::new(Mutex::new(0));
            testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
            unsafe {
                let _ = testchain.dispatch(
                    uninitialized(),
                    uninitialized(),
                    uninitialized()
                );
            }
            assert_eq!(*exit.lock(), 1);
        }
    }
}

<|endoftext|>