<commit_before>extern crate byteorder;

use std::error;
use std::fmt;
use std::io;
use std::io::{Read, Seek, SeekFrom};
use std::result;

use byteorder::{LittleEndian, ReadBytesExt};

// MARK: Error types

/// Represents an error that occurred while reading a wave file.
#[derive(Debug)]
pub enum ReadError {
    /// The file format is incorrect or unsupported.
    Format(FormatErrorKind),
    /// An IO error occurred.
    Io(io::Error),
}

/// Represents a result when reading a wave file.
pub type ReadResult<T> = result::Result<T, ReadError>;

impl fmt::Display for ReadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ReadError::Format(ref err_kind) => write!(f, "Format error: {}", err_kind),
            ReadError::Io(ref err) => write!(f, "IO error: {}", err),
        }
    }
}

/// Represents a file format error, when the wave file is incorrect or unsupported.
#[derive(Debug)]
pub enum FormatErrorKind {
    /// The file does not start with a "RIFF" tag and chunk size.
    NotARiffFile,
    /// The file doesn't continue with "WAVE" after the RIFF chunk header.
    NotAWaveFile,
    /// This file is not an uncompressed PCM wave file. Only uncompressed files are supported.
    NotAnUncompressedPcmWaveFile(u16),
}

impl FormatErrorKind {
    fn to_string(&self) -> &str {
        match *self {
            FormatErrorKind::NotARiffFile => "not a RIFF file",
            FormatErrorKind::NotAWaveFile => "not a WAVE file",
            FormatErrorKind::NotAnUncompressedPcmWaveFile(_) => "Not an uncompressed wave file",
        }
    }
}

impl fmt::Display for FormatErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

impl error::Error for ReadError {
    fn description(&self) -> &str {
        match *self {
            ReadError::Format(ref kind) => kind.to_string(),
            ReadError::Io(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ReadError::Format(_) => None,
            ReadError::Io(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for ReadError {
    fn from(err: io::Error) -> ReadError {
        ReadError::Io(err)
    }
}

// MARK: Validation and parsing functions

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

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

fn validate_pcm_format(format: u16) -> ReadResult<Format> {
    match format {
        FORMAT_UNCOMPRESSED_PCM => Ok(Format::UncompressedPcm),
        FORMAT_EXTENDED => Ok(Format::ExtendedWave),
        _ => Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(format))),
    }
}

trait WaveReader: Read + Seek {
    fn validate_is_riff_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"RIFF", FormatErrorKind::NotARiffFile));
        // The next four bytes represent the chunk size. We're not going to
        // validate it, so that we can still try to read files that might have
        // an incorrect chunk size, so let's skip over it.
        let _ = try!(self.read_chunk_size());
        Ok(())
    }

    fn validate_is_wave_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"WAVE", FormatErrorKind::NotAWaveFile));
        Ok(())
    }

    fn validate_tag(&mut self,
                    expected_tag: &[u8; 4],
                    err_kind: FormatErrorKind)
                    -> ReadResult<()> {
        let tag = try!(self.read_tag());
        if &tag != expected_tag {
            return Err(ReadError::Format(err_kind));
        }
        Ok(())
    }

    fn skip_until_subchunk(&mut self, matching_tag: &[u8; 4]) -> ReadResult<u32> {
        loop {
            let tag = try!(self.read_tag());
            let subchunk_size = try!(self.read_chunk_size());

            if &tag == matching_tag {
                return Ok(subchunk_size);
            } else {
                try!(self.seek(SeekFrom::Current(subchunk_size.into())));
            }
        }
    }

    fn read_tag(&mut self) -> ReadResult<[u8; 4]> {
        let mut tag: [u8; 4] = [0; 4];
        try!(self.read_exact(&mut tag));
        Ok(tag)
    }

    fn read_chunk_size(&mut self) -> ReadResult<u32> {
        Ok(try!(self.read_u32::<LittleEndian>()))
    }
}

impl<T> WaveReader for T where T: Read + Seek {}

// MARK: Tests

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use {FORMAT_UNCOMPRESSED_PCM, FORMAT_EXTENDED};
    use {Format, FormatErrorKind, ReadError, WaveReader};
    use validate_pcm_format;

    // This is a helper macro that helps us validate results in our tests.
    // Thank you bluss and durka42!
    macro_rules! assert_matches {
        ($expected:pat $(if $guard:expr)*, $value:expr) => {
            match $value {
                $expected $(if $guard)* => {},
                ref actual => {
                    panic!("assertion failed: `(left matches right)` (left: `{}`, right: `{:?}`",
                        stringify!($expected), actual);
                },
            }
        };
    }

    // RIFF header tests

    #[test]
    fn test_validate_is_riff_file_ok() {
        let mut data = Cursor::new(b"RIFF    ");
        assert_matches!(Ok(()), data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_incomplete() {
        let mut data = Cursor::new(b"RIF     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    // Wave tag tests

    #[test]
    fn test_validate_is_wave_file_ok() {
        let mut data = Cursor::new(b"WAVE");
        assert_matches!(Ok(()), data.validate_is_wave_file());
    }

    #[test]
    fn test_validate_is_wave_file_err_incomplete() {
        let mut data = Cursor::new(b"WAV ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAWaveFile)),
                        data.validate_is_wave_file());
    }

    #[test]
    fn test_validate_is_wave_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAWaveFile)),
                        data.validate_is_wave_file());
    }

    // Skipping to subchunk tests
    // After reading in the file header, we also need to read in the "fmt " subchunk.
    // The file might contain other subchunks that we don't currently support, so
    // we'll need to skip over them.

    #[test]
    fn test_skip_until_subchunk() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEfmt \x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let size = data.skip_until_subchunk(b"fmt ");
        assert_eq!(0, size.unwrap());
    }

    #[test]
    fn test_skip_until_second_subchunk() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEfmt \x00\x00\x00\x00data\x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let _ = data.skip_until_subchunk(b"fmt ");
        let size = data.skip_until_subchunk(b"data");
        assert_eq!(0, size.unwrap());
    }

    #[test]
    #[should_panic]
    fn test_cant_read_first_subchunk_after_second() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEdata\x00\x00\x00\x00fmt \x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let _ = data.skip_until_subchunk(b"fmt ");
        let size = data.skip_until_subchunk(b"data");
        assert_eq!(0, size.unwrap());
    }

    // Wave format validation tests

    #[test]
    fn test_validate_pcm_format_ok_uncompressed() {
        assert_matches!(Ok(Format::UncompressedPcm),
                        validate_pcm_format(FORMAT_UNCOMPRESSED_PCM));
    }

    #[test]
    fn test_validate_pcm_format_ok_extended() {
        assert_matches!(Ok(Format::ExtendedWave),
                        validate_pcm_format(FORMAT_EXTENDED));
    }

    #[test]
    fn test_validate_pcm_format_err_not_uncompressed() {
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(_))),
        				validate_pcm_format(12345));
    }
}
<commit_msg>Validate the PCM subformat. Only the uncompressed PCM format is supported.<commit_after>extern crate byteorder;

use std::error;
use std::fmt;
use std::io;
use std::io::{Read, Seek, SeekFrom};
use std::result;

use byteorder::{LittleEndian, ReadBytesExt};

// MARK: Error types

/// Represents an error that occurred while reading a wave file.
#[derive(Debug)]
pub enum ReadError {
    /// The file format is incorrect or unsupported.
    Format(FormatErrorKind),
    /// An IO error occurred.
    Io(io::Error),
}

/// Represents a result when reading a wave file.
pub type ReadResult<T> = result::Result<T, ReadError>;

impl fmt::Display for ReadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ReadError::Format(ref err_kind) => write!(f, "Format error: {}", err_kind),
            ReadError::Io(ref err) => write!(f, "IO error: {}", err),
        }
    }
}

/// Represents a file format error, when the wave file is incorrect or unsupported.
#[derive(Debug)]
pub enum FormatErrorKind {
    /// The file does not start with a "RIFF" tag and chunk size.
    NotARiffFile,
    /// The file doesn't continue with "WAVE" after the RIFF chunk header.
    NotAWaveFile,
    /// This file is not an uncompressed PCM wave file. Only uncompressed files are supported.
    NotAnUncompressedPcmWaveFile(u16),
}

impl FormatErrorKind {
    fn to_string(&self) -> &str {
        match *self {
            FormatErrorKind::NotARiffFile => "not a RIFF file",
            FormatErrorKind::NotAWaveFile => "not a WAVE file",
            FormatErrorKind::NotAnUncompressedPcmWaveFile(_) => "Not an uncompressed wave file",
        }
    }
}

impl fmt::Display for FormatErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

impl error::Error for ReadError {
    fn description(&self) -> &str {
        match *self {
            ReadError::Format(ref kind) => kind.to_string(),
            ReadError::Io(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ReadError::Format(_) => None,
            ReadError::Io(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for ReadError {
    fn from(err: io::Error) -> ReadError {
        ReadError::Io(err)
    }
}

// MARK: Validation and parsing functions

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

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

fn validate_pcm_format(format: u16) -> ReadResult<Format> {
    match format {
        FORMAT_UNCOMPRESSED_PCM => Ok(Format::UncompressedPcm),
        FORMAT_EXTENDED => Ok(Format::ExtendedWave),
        _ => Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(format))),
    }
}

fn validate_pcm_subformat(sub_format: u16) -> ReadResult<()> {
    match sub_format {
        FORMAT_UNCOMPRESSED_PCM => Ok(()),
        _ => Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(sub_format))),
    }
}

trait WaveReader: Read + Seek {
    fn validate_is_riff_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"RIFF", FormatErrorKind::NotARiffFile));
        // The next four bytes represent the chunk size. We're not going to
        // validate it, so that we can still try to read files that might have
        // an incorrect chunk size, so let's skip over it.
        let _ = try!(self.read_chunk_size());
        Ok(())
    }

    fn validate_is_wave_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"WAVE", FormatErrorKind::NotAWaveFile));
        Ok(())
    }

    fn validate_tag(&mut self,
                    expected_tag: &[u8; 4],
                    err_kind: FormatErrorKind)
                    -> ReadResult<()> {
        let tag = try!(self.read_tag());
        if &tag != expected_tag {
            return Err(ReadError::Format(err_kind));
        }
        Ok(())
    }

    fn skip_until_subchunk(&mut self, matching_tag: &[u8; 4]) -> ReadResult<u32> {
        loop {
            let tag = try!(self.read_tag());
            let subchunk_size = try!(self.read_chunk_size());

            if &tag == matching_tag {
                return Ok(subchunk_size);
            } else {
                try!(self.seek(SeekFrom::Current(subchunk_size.into())));
            }
        }
    }

    fn read_tag(&mut self) -> ReadResult<[u8; 4]> {
        let mut tag: [u8; 4] = [0; 4];
        try!(self.read_exact(&mut tag));
        Ok(tag)
    }

    fn read_chunk_size(&mut self) -> ReadResult<u32> {
        Ok(try!(self.read_u32::<LittleEndian>()))
    }
}

impl<T> WaveReader for T where T: Read + Seek {}

// MARK: Tests

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use {FORMAT_UNCOMPRESSED_PCM, FORMAT_EXTENDED};
    use {Format, FormatErrorKind, ReadError, WaveReader};
    use {validate_pcm_format, validate_pcm_subformat};

    // This is a helper macro that helps us validate results in our tests.
    // Thank you bluss and durka42!
    macro_rules! assert_matches {
        ($expected:pat $(if $guard:expr)*, $value:expr) => {
            match $value {
                $expected $(if $guard)* => {},
                ref actual => {
                    panic!("assertion failed: `(left matches right)` (left: `{}`, right: `{:?}`",
                        stringify!($expected), actual);
                },
            }
        };
    }

    // RIFF header tests

    #[test]
    fn test_validate_is_riff_file_ok() {
        let mut data = Cursor::new(b"RIFF    ");
        assert_matches!(Ok(()), data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_incomplete() {
        let mut data = Cursor::new(b"RIF     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    // Wave tag tests

    #[test]
    fn test_validate_is_wave_file_ok() {
        let mut data = Cursor::new(b"WAVE");
        assert_matches!(Ok(()), data.validate_is_wave_file());
    }

    #[test]
    fn test_validate_is_wave_file_err_incomplete() {
        let mut data = Cursor::new(b"WAV ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAWaveFile)),
                        data.validate_is_wave_file());
    }

    #[test]
    fn test_validate_is_wave_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAWaveFile)),
                        data.validate_is_wave_file());
    }

    // Skipping to subchunk tests
    // After reading in the file header, we also need to read in the "fmt " subchunk.
    // The file might contain other subchunks that we don't currently support, so
    // we'll need to skip over them.

    #[test]
    fn test_skip_until_subchunk() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEfmt \x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let size = data.skip_until_subchunk(b"fmt ");
        assert_eq!(0, size.unwrap());
    }

    #[test]
    fn test_skip_until_second_subchunk() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEfmt \x00\x00\x00\x00data\x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let _ = data.skip_until_subchunk(b"fmt ");
        let size = data.skip_until_subchunk(b"data");
        assert_eq!(0, size.unwrap());
    }

    #[test]
    #[should_panic]
    fn test_cant_read_first_subchunk_after_second() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEdata\x00\x00\x00\x00fmt \x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let _ = data.skip_until_subchunk(b"fmt ");
        let size = data.skip_until_subchunk(b"data");
        assert_eq!(0, size.unwrap());
    }

    // Wave format validation tests. We only support uncompressed PCM files,
    // which can be in the "canonical" format or an "extended" format.

    #[test]
    fn test_validate_pcm_format_ok_uncompressed() {
        assert_matches!(Ok(Format::UncompressedPcm),
                        validate_pcm_format(FORMAT_UNCOMPRESSED_PCM));
    }

    #[test]
    fn test_validate_pcm_format_ok_extended() {
        assert_matches!(Ok(Format::ExtendedWave),
                        validate_pcm_format(FORMAT_EXTENDED));
    }

    #[test]
    fn test_validate_pcm_format_err_not_uncompressed() {
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(_))),
        				validate_pcm_format(12345));
    }

    // Wave subformat validation tests. We only support uncompressed PCM files.

    #[test]
    fn test_validate_pcm_subformat_ok_uncompressed() {
        assert_matches!(Ok(()), validate_pcm_subformat(FORMAT_UNCOMPRESSED_PCM));
    }

    #[test]
    fn test_validate_pcm_subformat_err_extended_format_value_not_valid_for_subformat() {
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(_))),
            			validate_pcm_subformat(FORMAT_EXTENDED));
    }

    #[test]
    fn test_validate_pcm_subformat_err_not_uncompressed() {
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(_))),
						validate_pcm_subformat(12345));
    }
}
<|endoftext|>


<commit_before>/// Sorter functions.

/// Implementation of insertion sort.
/// @victim Mutable array.
pub fn insertion_sort<T: Ord>(victim: &mut [T]) {
    for i in 1..victim.len() {
        for j in (0..i).rev() {
            if victim[j+1] < victim[j] { victim.swap(j+1, j); }
            else { break; }
        }
    }
}

/// Binary search which looks after key in sorted array.
/// Kinda useful in partly sorted arrays.
#[inline]
fn binary_search_right<T: Ord>(victim: &[T], key: &T, mut low: usize, mut high: usize) -> usize {
    while low < high {
        let mid = (low + high) / 2;
        if *key < victim[mid] { high = mid; }
        else { low = mid + 1; }
    }

    low
}

/// Implementation of insertion sort.
/// Employs binary search.
pub fn binary_insertion_sort<T: Ord>(victim: &mut [T]) {
    for i in 1..victim.len() {
        let key_loc = binary_search_right(victim, &victim[i], 0, i);

        for j in (key_loc..i).rev() {
            victim.swap(j+1, j);
        }
    }
}

/// Implementation of shell sort.
/// Uses gap sequence: [701, 301, 132, 57, 23, 10, 4, 1]
pub fn shell_sort<T: Ord + Clone>(victim: &mut [T]) {
    let gaps = [701, 301, 132, 57, 23, 10, 4, 1];

    for gap in gaps.iter() {
        for i in *gap..victim.len() {
            let mut j = i;
            let temp = victim[i].clone();
            while j >= *gap && victim[j-*gap] > temp {
                victim.swap(j, j-*gap);
                j -= *gap;
            }
            victim[j] = temp;
        }
    }
}

/// Implementation of shaker sort.
pub fn shaker_sort<T: Ord>(victim: &mut [T]) {
    for _ in 0..victim.len() / 2 + 1 {
        let mut begin: usize = 0;
        let mut ending: usize = victim.len() - 1;

        while begin <= ending {
            if victim[begin] > victim[begin+1] { victim.swap(begin, begin+1); }
            if victim[ending-1] > victim[ending] { victim.swap(ending, ending-1); }
            begin += 1;
            ending -= 1;
        }
    }
}

/// ShiftDown for heap sort
#[inline]
fn shift_down<T: Ord>(victim: &mut [T], start: usize, ending: usize) {
    let mut root = start;
    loop {
        let mut child = root * 2 + 1;

        if child > ending { break; }
        else if child != ending && victim[child] < victim[child+1] { child += 1; }

        if victim[root] < victim[child] {
            victim.swap(root, child);
            root = child;
        }
        else { break; }
    }
}

/// Implementation of heap sort.
pub fn heap_sort<T: Ord>(victim: &mut [T]) {
    let last = victim.len() - 1;
    //remember that range is exclusive for right element
    for i in (0..(last+1) / 2).rev() { shift_down(victim, i, last); }

    let last = last + 1;
    for i in (1..last).rev() {
        victim.swap(0, i);
        shift_down(victim, 0, i-1); }
}

/// Implementation of quick sort.
pub fn quick_sort<T: Ord>(victim: &mut [T]) {
    let last: usize = victim.len();
    if last < 2 { return; }

    let middle = last / 2;
    let last = last - 1;

    //choice of pivot and partition
    victim.swap(middle, last);

    let mut pivot_index = 0;
    for i in 0..last {
        if victim[i] <= victim[last] {
            victim.swap(i, pivot_index);
            pivot_index += 1;
        }
    }

    victim.swap(pivot_index, last);

    //next sort
    quick_sort(&mut victim[0..pivot_index]);
    quick_sort(&mut victim[pivot_index+1..last+1]);
}

/// Implementation of bubble sort.
pub fn bubble_sort<T: Ord>(victim: &mut [T]) {
    for _ in 0..victim.len() {
        for j in 1..victim.len() {
            if victim[j-1] > victim[j] { victim.swap(j-1, j); }
        }
    }
}
<commit_msg>Improve quicksort so that it would switch to simple insertion sort on small input<commit_after>/// Sorter functions.

/// Implementation of insertion sort.
/// @victim Mutable array.
pub fn insertion_sort<T: Ord>(victim: &mut [T]) {
    for i in 1..victim.len() {
        for j in (0..i).rev() {
            if victim[j+1] < victim[j] { victim.swap(j+1, j); }
            else { break; }
        }
    }
}

/// Binary search which looks after key in sorted array.
/// Kinda useful in partly sorted arrays.
#[inline]
fn binary_search_right<T: Ord>(victim: &[T], key: &T, mut low: usize, mut high: usize) -> usize {
    while low < high {
        let mid = (low + high) / 2;
        if *key < victim[mid] { high = mid; }
        else { low = mid + 1; }
    }

    low
}

/// Implementation of insertion sort.
/// Employs binary search.
pub fn binary_insertion_sort<T: Ord>(victim: &mut [T]) {
    for i in 1..victim.len() {
        let key_loc = binary_search_right(victim, &victim[i], 0, i);

        for j in (key_loc..i).rev() {
            victim.swap(j+1, j);
        }
    }
}

/// Implementation of shell sort.
/// Uses gap sequence: [701, 301, 132, 57, 23, 10, 4, 1]
pub fn shell_sort<T: Ord + Clone>(victim: &mut [T]) {
    let gaps = [701, 301, 132, 57, 23, 10, 4, 1];

    for gap in gaps.iter() {
        for i in *gap..victim.len() {
            let mut j = i;
            let temp = victim[i].clone();
            while j >= *gap && victim[j-*gap] > temp {
                victim.swap(j, j-*gap);
                j -= *gap;
            }
            victim[j] = temp;
        }
    }
}

/// Implementation of shaker sort.
pub fn shaker_sort<T: Ord>(victim: &mut [T]) {
    for _ in 0..victim.len() / 2 + 1 {
        let mut begin: usize = 0;
        let mut ending: usize = victim.len() - 1;

        while begin <= ending {
            if victim[begin] > victim[begin+1] { victim.swap(begin, begin+1); }
            if victim[ending-1] > victim[ending] { victim.swap(ending, ending-1); }
            begin += 1;
            ending -= 1;
        }
    }
}

/// ShiftDown for heap sort
#[inline]
fn shift_down<T: Ord>(victim: &mut [T], start: usize, ending: usize) {
    let mut root = start;
    loop {
        let mut child = root * 2 + 1;

        if child > ending { break; }
        else if child != ending && victim[child] < victim[child+1] { child += 1; }

        if victim[root] < victim[child] {
            victim.swap(root, child);
            root = child;
        }
        else { break; }
    }
}

/// Implementation of heap sort.
pub fn heap_sort<T: Ord>(victim: &mut [T]) {
    let last = victim.len() - 1;
    //remember that range is exclusive for right element
    for i in (0..(last+1) / 2).rev() { shift_down(victim, i, last); }

    let last = last + 1;
    for i in (1..last).rev() {
        victim.swap(0, i);
        shift_down(victim, 0, i-1); }
}

/// Implementation of quick sort.
pub fn quick_sort<T: Ord>(victim: &mut [T]) {
    let last: usize = victim.len();
    if last < 52 {
        if last > 1 {
            insertion_sort(&mut victim[..]);
        }
        return;
    }

    let middle = last / 2;
    let last = last - 1;

    //choice of pivot and partition
    victim.swap(middle, last);

    let mut pivot_index = 0;
    for i in 0..last {
        if victim[i] <= victim[last] {
            victim.swap(i, pivot_index);
            pivot_index += 1;
        }
    }

    victim.swap(pivot_index, last);

    //next sort
    quick_sort(&mut victim[0..pivot_index]);
    quick_sort(&mut victim[pivot_index+1..last+1]);
}

/// Implementation of bubble sort.
pub fn bubble_sort<T: Ord>(victim: &mut [T]) {
    for _ in 0..victim.len() {
        for j in 1..victim.len() {
            if victim[j-1] > victim[j] { victim.swap(j-1, j); }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(field_init_shorthand)]
#![feature(type_ascription)]

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

#[macro_use]
extern crate quick_error;
extern crate byteorder;
extern crate thrift;
extern crate ordered_float;
extern crate try_from;

#[macro_use]
pub mod errors;
pub mod basic;
pub mod parquet_thrift;
pub mod schema;
pub mod file;
<commit_msg>Remove unnecessary feature notation<commit_after>#![feature(type_ascription)]

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

#[macro_use]
extern crate quick_error;
extern crate byteorder;
extern crate thrift;
extern crate ordered_float;
extern crate try_from;

#[macro_use]
pub mod errors;
pub mod basic;
pub mod parquet_thrift;
pub mod schema;
pub mod file;
<|endoftext|>


<commit_before>#![crate_name = "vector"]
#![deny(missing_docs)]

//! Simple vector library

use std::ops::{ Add, Mul, Neg, Sub };

/// 2D Vector; A Vector with 2 components
#[derive(Debug, Copy, Clone)]
pub struct Vector2<T: Copy> {
    e0: T,
    e1: T,
}

impl<T> Vector2<T>  where T: Copy {

    /// Create new Vector2 with two entries of type T
    #[inline(always)]
    pub fn new(e0: T, e1: T) -> Vector2<T> {
        Vector2::<T> { e0: e0, e1: e1 }
    }

    /// First entry in the Vector2
    #[inline(always)]
    pub fn x(self) -> T {
        self.e0
    }

    /// Second entry in the Vector2
    #[inline(always)]
    pub fn y(self) -> T {
        self.e1
    }

    /// Get entry by index
    #[inline(always)]
    pub fn get(self, index: usize) -> T {
        match index {
            0 => self.e0,
            1 => self.e1,
            _ => panic!("index out of bounds: the len is 2 but the index is {}", index)
        }
    }
}

/// Adds other to self
impl<T> Add<Vector2<T>> for Vector2<T> where T: Copy + Add<T, Output = T> {
    type Output = Vector2<T>;

    #[inline(always)]
    fn add (self, other: Vector2<T>) -> Vector2<T> {
        Vector2::<T> { e0: self.e0 + other.e0, e1: self.e1 + other.e1 }
    }
}

/// Compute the DOT PRODUCT of self & other
impl<T> Mul<Vector2<T>> for Vector2<T> where T: Copy + Mul<T, Output = T> + Add<T, Output = T> {
    type Output = T;

    #[inline(always)]
    fn mul (self, other: Vector2<T>) -> T {
        self.e0 * other.e0 + self.e1 * other.e1
    }
}

/// Subtracts other from self
impl<T> Sub<Vector2<T>> for Vector2<T> where T: Copy + Sub<T, Output = T> {
    type Output = Vector2<T>;

    #[inline(always)]
    fn sub (self, other: Vector2<T>) -> Vector2<T> {
        Vector2::<T> { e0: self.e0 - other.e0, e1: self.e1 - other.e1 }
    }
}

/// Negate each entry in the Vector2
impl<T> Neg for Vector2<T> where T: Copy + Neg<Output = T> {
    type Output = Vector2<T>;

    #[inline(always)]
    fn neg(self) -> Vector2<T> {
        Vector2::<T>{ e0: -self.e0, e1: -self.e1 }
    }
}

#[test]
fn test_vector2_add() {
    let v1 = Vector2::<i32> { e0: 2, e1: 6 };
    let v2 = Vector2::<i32> { e0: 4, e1: 8 };
    let v3 = v1 + v2;

    assert_eq!(v3.e0, 6);
    assert_eq!(v3.e1, 14);
}

#[test]
fn test_vector2_sub() {
    let v1 = Vector2::<i32> { e0: 7, e1: 8 };
    let v2 = Vector2::<i32> { e0: 2, e1: 9 };
    let v3 = v1 - v2;

    assert_eq!(v3.e0, 5);
    assert_eq!(v3.e1, -1);
}

#[test]
fn test_vector2_neg() {
    let v1 = Vector2::<i32> { e0: 1, e1: -1 };
    let v2 = -v1;

    assert_eq!(v2.e0, -1);
    assert_eq!(v2.e1, 1);
}

#[test]
fn test_vector2_dot() {
    let v1 = Vector2::<i32> { e0: 2, e1: 3 };
    let v2 = Vector2::<i32> { e0: 4, e1: 5 };
    let s = v1 * v2;

    assert_eq!(s, 23);
}

#[test]
#[should_panic(expected = "index out of bounds: the len is 2 but the index is 2")]
fn test_get_xy() {
    let v = Vector2::<i32> { e0: 1, e1: 2 };

    assert_eq!(v.get(0), 1);
    assert_eq!(v.get(1), 2);
    v.get(2);
}
<commit_msg>Add feature: Implement Vector2 * Scalar<commit_after>#![crate_name = "vector"]
#![deny(missing_docs)]

//! Simple vector library

use std::ops::{ Add, Mul, Neg, Sub };

/// 2D Vector; A Vector with 2 components
#[derive(Debug, Copy, Clone)]
pub struct Vector2<T: Copy> {
    e0: T,
    e1: T,
}

impl<T> Vector2<T>  where T: Copy {

    /// Create new Vector2 with two entries of type T
    #[inline(always)]
    pub fn new(e0: T, e1: T) -> Vector2<T> {
        Vector2::<T> { e0: e0, e1: e1 }
    }

    /// First entry in the Vector2
    #[inline(always)]
    pub fn x(self) -> T {
        self.e0
    }

    /// Second entry in the Vector2
    #[inline(always)]
    pub fn y(self) -> T {
        self.e1
    }

    /// Get entry by index
    #[inline(always)]
    pub fn get(self, index: usize) -> T {
        match index {
            0 => self.e0,
            1 => self.e1,
            _ => panic!("index out of bounds: the len is 2 but the index is {}", index)
        }
    }
}

/// Adds other to self
impl<T> Add<Vector2<T>> for Vector2<T> where T: Copy + Add<T, Output = T> {
    type Output = Vector2<T>;

    #[inline(always)]
    fn add (self, other: Vector2<T>) -> Vector2<T> {
        Vector2::<T> { e0: self.e0 + other.e0, e1: self.e1 + other.e1 }
    }
}

/// Compute the DOT PRODUCT of self & other
impl<T> Mul<Vector2<T>> for Vector2<T> where T: Copy + Mul<T, Output = T> + Add<T, Output = T> {
    type Output = T;

    #[inline(always)]
    fn mul (self, other: Vector2<T>) -> T {
        self.e0 * other.e0 + self.e1 * other.e1
    }
}

/// Compute the DOT PRODUCT of self & other
impl<T> Mul<T> for Vector2<T> where T: Copy + Mul<T, Output = T> {
    type Output = Vector2<T>;

    #[inline(always)]
    fn mul (self, scalar: T) -> Vector2<T> {
        Vector2::<T> { e0: self.e0 * scalar, e1: self.e1 * scalar }
    }
}

/// Subtracts other from self
impl<T> Sub<Vector2<T>> for Vector2<T> where T: Copy + Sub<T, Output = T> {
    type Output = Vector2<T>;

    #[inline(always)]
    fn sub (self, other: Vector2<T>) -> Vector2<T> {
        Vector2::<T> { e0: self.e0 - other.e0, e1: self.e1 - other.e1 }
    }
}

/// Negate each entry in the Vector2
impl<T> Neg for Vector2<T> where T: Copy + Neg<Output = T> {
    type Output = Vector2<T>;

    #[inline(always)]
    fn neg(self) -> Vector2<T> {
        Vector2::<T>{ e0: -self.e0, e1: -self.e1 }
    }
}

#[test]
fn test_vector2_add() {
    let v1 = Vector2::<i32> { e0: 2, e1: 6 };
    let v2 = Vector2::<i32> { e0: 4, e1: 8 };
    let v3 = v1 + v2;

    assert_eq!(v3.e0, 6);
    assert_eq!(v3.e1, 14);
}

#[test]
fn test_vector2_sub() {
    let v1 = Vector2::<i32> { e0: 7, e1: 8 };
    let v2 = Vector2::<i32> { e0: 2, e1: 9 };
    let v3 = v1 - v2;

    assert_eq!(v3.e0, 5);
    assert_eq!(v3.e1, -1);
}

#[test]
fn test_vector2_neg() {
    let v1 = Vector2::<i32> { e0: 1, e1: -1 };
    let v2 = -v1;

    assert_eq!(v2.e0, -1);
    assert_eq!(v2.e1, 1);
}

#[test]
fn test_vector2_dot() {
    let v1 = Vector2::<i32> { e0: 2, e1: 3 };
    let v2 = Vector2::<i32> { e0: 4, e1: 5 };
    let s = v1 * v2;

    assert_eq!(s, 23);
}

#[test]
fn test_vector2_mut_scalar() {
    let v1 = Vector2::<i32>::new(1, 2);
    let v2 = v1 * 2;

    assert_eq!(v2.e0, 2);
    assert_eq!(v2.e1, 4);
}

#[test]
#[should_panic(expected = "index out of bounds: the len is 2 but the index is 2")]
fn test_get_xy() {
    let v = Vector2::<i32> { e0: 1, e1: 2 };

    assert_eq!(v.get(0), 1);
    assert_eq!(v.get(1), 2);
    v.get(2);
}
<|endoftext|>


<commit_before>extern crate base64;
extern crate hyper;
extern crate libc;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use base64::{encode, decode};
use hyper::Client;
use hyper::Error;
use hyper::client::response::Response;
use hyper::header::{Headers, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::status::StatusCode;
use libc::{uint8_t, size_t};
use log::LogLevelFilter;
use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Config, Logger, Root};
use log4rs::encode::pattern::PatternEncoder;
use serde::Serialize;
use std::collections::HashMap;
use std::env::var;
use std::io::Read;
use std::slice;
use std::sync::{Once, ONCE_INIT, Mutex};

const BASE_URL: &'static str = "http://localhost:8080/k2/ctapi/";

static OK: i8 = 0;
static ERR_INVALID: i8 = -1;
static ERR_HOST: i8 = -127;
static ERR_HTSI: i8 = -128;

static INIT: Once = ONCE_INIT;

lazy_static! {
    static ref MAP: Mutex<HashMap<u16, u16>> = Mutex::new(HashMap::new());
}

#[derive(Serialize)]
struct Empty();

#[derive(Serialize)]
struct RequestData {
    dad: u8,
    sad: u8,
    lenc: usize,
    command: String,
    lenr: usize,
}

#[allow(non_snake_case)]
#[derive(Deserialize)]
struct ResponseData {
    dad: u8,
    sad: u8,
    lenr: usize,
    response: String,
    responseCode: i8,
}

macro_rules! post_request {
    ($path:expr) => (post_request($path, &Empty{}));
    ($path:expr, $data:expr) => (post_request($path, $data));
}

#[no_mangle]
#[allow(non_snake_case, unused_must_use)]
pub extern "C" fn CT_init(ctn: u16, pn: u16) -> i8 {
    init_logging();

    debug!("CT_init: Called (ctn {}, pn {})", ctn, pn);

    // Do we know this CTN?
    if MAP.lock().unwrap().contains_key(&ctn) {
        debug!("CT_init: Card terminal has already been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    // Build the request URL
    let endpoint = "ct_init".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    // Perform the request
    match post_request!(&path) {
        Ok(mut response) => {
            debug!("{:?}", response); // TODO enrich output

            match response.status {
                StatusCode::Ok => {
                    // Cast server response
                    let mut body = String::new();
                    response.read_to_string(&mut body).unwrap();

                    let status = body.parse::<i8>().unwrap();
                    if status == OK {
                        // Store CTN
                        MAP.lock().unwrap().insert(ctn, pn);
                        debug!("CT_init: Card terminal opened.");
                    }

                    debug!("CT_init: Returning {}", status);
                    status
                }
                _ => {
                    error!("CT_init: Response not OK! Returning {}", ERR_HOST);
                    ERR_HOST
                }
            }
        }
        Err(error) => {
            debug!("Error: {:?}", error);
            error!("CT_data: Request failed! Returning {}", ERR_HTSI);
            ERR_HTSI
        }
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CT_data(ctn: u16,
                          dad: *mut uint8_t,
                          sad: *mut uint8_t,
                          lenc: size_t,
                          command: *const uint8_t,
                          lenr: *mut size_t,
                          response: *mut uint8_t)
                          -> i8 {
    init_logging();

    debug!("CT_data: Called");
    debug!(" ctn: {}", ctn);

    let _dad: &mut u8 = unsafe { &mut *dad };
    debug!(" dad: {}", _dad);

    let _sad: &mut u8 = unsafe { &mut *sad };
    debug!(" sad: {}", _sad);
    debug!(" lenc: {}", lenc);

    let _command = unsafe { slice::from_raw_parts(command, lenc as usize) };
    debug!(" command: {:?}", _command);

    let _lenr: &mut size_t = unsafe { &mut *lenr };
    debug!(" lenr: {}", _lenr);

    let _response = unsafe { slice::from_raw_parts_mut(response, *_lenr) };
    debug!(" response.len(): {}", _response.len());

    if !MAP.lock().unwrap().contains_key(&ctn) {
        debug!("CT_data: Card terminal has not been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    let requestData = RequestData {
        dad: *_dad,
        sad: *_sad,
        lenc: lenc,
        command: encode(_command),
        lenr: *_lenr,
    };

    let pn = MAP.lock().unwrap();
    let pn = pn.get(&ctn).unwrap();
    let endpoint = "ct_data".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    let mut http_response = post_request(&path, &requestData);

    match http_response.status {
        StatusCode::Ok => {
            // decode server response
            let mut body = String::new();
            http_response.read_to_string(&mut body).unwrap();
            debug!("CT_data: Response body: {}", body);

            let responseData: ResponseData = serde_json::from_str(&body).unwrap();

            if responseData.responseCode == OK {
                *_dad = responseData.dad;
                *_sad = responseData.sad;
                *_lenr = responseData.lenr;

                let decoded = decode(&responseData.response).unwrap();
                debug!("CT_data: Decoded response field {:?}", decoded);

                for (place, element) in _response.iter_mut().zip(decoded.iter()) {
                    *place = *element;
                }
            }
            debug!("CT_data: Returning {}", responseData.responseCode);
            return responseData.responseCode;
        }
        _ => {
            error!("CT_data: Response not OK! Returning {}", ERR_HOST);
            ERR_HOST
        }
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CT_close(ctn: u16) -> i8 {
    init_logging();

    debug!("CT_close: Called (ctn {})", ctn);

    // Do we know this CTN?
    if !MAP.lock().unwrap().contains_key(&ctn) {
        debug!("CT_close: Card terminal has not been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    // Build the request URL
    let pn = MAP.lock().unwrap().get(&ctn).unwrap().clone();
    let endpoint = "ct_close".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    // Perform the request
    let mut response = post_request!(&path);

    match response.status {
        StatusCode::Ok => {
            // Cast server response
            let mut body = String::new();
            response.read_to_string(&mut body).unwrap();

            let status = body.parse::<i8>().unwrap();
            if status == OK {
                // Remove CTN
                MAP.lock().unwrap().remove(&ctn);
                debug!("CT_close: Card terminal has been closed.");
            }

            debug!("CT_close: Returning {}", status);
            status
        }
        _ => {
            error!("CT_close: Response not OK! Returning {}", ERR_HOST);
            ERR_HOST
        }
    }
}

fn init_logging() {
    match var("K2_LOG_PATH") {
        Ok(path) => {
            INIT.call_once(|| {
                let file = FileAppender::builder()
                    .encoder(Box::new(PatternEncoder::new("{d} {l} {M}: {m}{n}")))
                    .build(path + &"/ctehxk2.log".to_string())
                    .unwrap();

                let config = Config::builder()
                    .appender(Appender::builder().build("file", Box::new(file)))
                    .logger(Logger::builder()
                                .appender("file")
                                .additive(false)
                                .build("ctehxk2", LogLevelFilter::Debug))
                    .build(Root::builder()
                               .appender("file")
                               .build(LogLevelFilter::Error))
                    .unwrap();

                log4rs::init_config(config).unwrap();
            })
        }
        _ => (),
    }
}

fn post_request<T>(path: &str, payload: &T) -> Result<Response, Error>
    where T: Serialize
{
    let base_url = var("K2_BASE_URL").unwrap_or(BASE_URL.to_string());
    let url = base_url + path;

    let client = Client::new();

    let mut headers = Headers::new();
    headers.set(ContentType(Mime(TopLevel::Application, SubLevel::Json, vec![])));

    let body = serde_json::to_string(&payload).unwrap();

    debug!("HTTP POST URL: {}", url);
    debug!("HTTP POST body: {:?}", body);

    let mut builder = client.post(&url);
    builder = builder.headers(headers);
    builder = builder.body(&body[..]);
    builder.send()
}
<commit_msg>handle new result type of post_request in CT_data<commit_after>extern crate base64;
extern crate hyper;
extern crate libc;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use base64::{encode, decode};
use hyper::Client;
use hyper::Error;
use hyper::client::response::Response;
use hyper::header::{Headers, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::status::StatusCode;
use libc::{uint8_t, size_t};
use log::LogLevelFilter;
use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Config, Logger, Root};
use log4rs::encode::pattern::PatternEncoder;
use serde::Serialize;
use std::collections::HashMap;
use std::env::var;
use std::io::Read;
use std::slice;
use std::sync::{Once, ONCE_INIT, Mutex};

const BASE_URL: &'static str = "http://localhost:8080/k2/ctapi/";

static OK: i8 = 0;
static ERR_INVALID: i8 = -1;
static ERR_HOST: i8 = -127;
static ERR_HTSI: i8 = -128;

static INIT: Once = ONCE_INIT;

lazy_static! {
    static ref MAP: Mutex<HashMap<u16, u16>> = Mutex::new(HashMap::new());
}

#[derive(Serialize)]
struct Empty();

#[derive(Serialize)]
struct RequestData {
    dad: u8,
    sad: u8,
    lenc: usize,
    command: String,
    lenr: usize,
}

#[allow(non_snake_case)]
#[derive(Deserialize)]
struct ResponseData {
    dad: u8,
    sad: u8,
    lenr: usize,
    response: String,
    responseCode: i8,
}

macro_rules! post_request {
    ($path:expr) => (post_request($path, &Empty{}));
    ($path:expr, $data:expr) => (post_request($path, $data));
}

#[no_mangle]
#[allow(non_snake_case, unused_must_use)]
pub extern "C" fn CT_init(ctn: u16, pn: u16) -> i8 {
    init_logging();

    debug!("CT_init: Called (ctn {}, pn {})", ctn, pn);

    // Do we know this CTN?
    if MAP.lock().unwrap().contains_key(&ctn) {
        debug!("CT_init: Card terminal has already been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    // Build the request URL
    let endpoint = "ct_init".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    // Perform the request
    match post_request!(&path) {
        Ok(mut response) => {
            debug!("{:?}", response); // TODO enrich output

            match response.status {
                StatusCode::Ok => {
                    // Cast server response
                    let mut body = String::new();
                    response.read_to_string(&mut body).unwrap();

                    let status = body.parse::<i8>().unwrap();
                    if status == OK {
                        // Store CTN
                        MAP.lock().unwrap().insert(ctn, pn);
                        debug!("CT_init: Card terminal opened.");
                    }

                    debug!("CT_init: Returning {}", status);
                    status
                }
                _ => {
                    error!("CT_init: Response not OK! Returning {}", ERR_HOST);
                    ERR_HOST
                }
            }
        }
        Err(error) => {
            debug!("Error: {:?}", error);
            error!("CT_data: Request failed! Returning {}", ERR_HTSI);
            ERR_HTSI
        }
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CT_data(ctn: u16,
                          dad: *mut uint8_t,
                          sad: *mut uint8_t,
                          lenc: size_t,
                          command: *const uint8_t,
                          lenr: *mut size_t,
                          response: *mut uint8_t)
                          -> i8 {
    init_logging();

    debug!("CT_data: Called");
    debug!(" ctn: {}", ctn);

    let _dad: &mut u8 = unsafe { &mut *dad };
    debug!(" dad: {}", _dad);

    let _sad: &mut u8 = unsafe { &mut *sad };
    debug!(" sad: {}", _sad);
    debug!(" lenc: {}", lenc);

    let _command = unsafe { slice::from_raw_parts(command, lenc as usize) };
    debug!(" command: {:?}", _command);

    let _lenr: &mut size_t = unsafe { &mut *lenr };
    debug!(" lenr: {}", _lenr);

    let _response = unsafe { slice::from_raw_parts_mut(response, *_lenr) };
    debug!(" response.len(): {}", _response.len());

    if !MAP.lock().unwrap().contains_key(&ctn) {
        debug!("CT_data: Card terminal has not been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    let requestData = RequestData {
        dad: *_dad,
        sad: *_sad,
        lenc: lenc,
        command: encode(_command),
        lenr: *_lenr,
    };

    let pn = MAP.lock().unwrap();
    let pn = pn.get(&ctn).unwrap();
    let endpoint = "ct_data".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    match post_request(&path, &requestData) {
        Ok(mut http_response) => {
            debug!("{:?}", http_response); // TODO enrich output

            match http_response.status {
                StatusCode::Ok => {
                    // decode server response
                    let mut body = String::new();
                    http_response.read_to_string(&mut body).unwrap();
                    debug!("CT_data: Response body: {}", body);

                    let responseData: ResponseData = serde_json::from_str(&body).unwrap();

                    if responseData.responseCode == OK {
                        *_dad = responseData.dad;
                        *_sad = responseData.sad;
                        *_lenr = responseData.lenr;

                        let decoded = decode(&responseData.response).unwrap();
                        debug!("CT_data: Decoded response field {:?}", decoded);

                        for (place, element) in _response.iter_mut().zip(decoded.iter()) {
                            *place = *element;
                        }
                    }
                    debug!("CT_data: Returning {}", responseData.responseCode);
                    return responseData.responseCode;
                }
                _ => {
                    error!("CT_data: Response not OK! Returning {}", ERR_HOST);
                    ERR_HOST
                }
            }
        }
        Err(error) => {
            debug!("Error: {:?}", error);
            error!("CT_data: Request failed! Returning {}", ERR_HTSI);
            ERR_HTSI
        }
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CT_close(ctn: u16) -> i8 {
    init_logging();

    debug!("CT_close: Called (ctn {})", ctn);

    // Do we know this CTN?
    if !MAP.lock().unwrap().contains_key(&ctn) {
        debug!("CT_close: Card terminal has not been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    // Build the request URL
    let pn = MAP.lock().unwrap().get(&ctn).unwrap().clone();
    let endpoint = "ct_close".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    // Perform the request
    let mut response = post_request!(&path);

    match response.status {
        StatusCode::Ok => {
            // Cast server response
            let mut body = String::new();
            response.read_to_string(&mut body).unwrap();

            let status = body.parse::<i8>().unwrap();
            if status == OK {
                // Remove CTN
                MAP.lock().unwrap().remove(&ctn);
                debug!("CT_close: Card terminal has been closed.");
            }

            debug!("CT_close: Returning {}", status);
            status
        }
        _ => {
            error!("CT_close: Response not OK! Returning {}", ERR_HOST);
            ERR_HOST
        }
    }
}

fn init_logging() {
    match var("K2_LOG_PATH") {
        Ok(path) => {
            INIT.call_once(|| {
                let file = FileAppender::builder()
                    .encoder(Box::new(PatternEncoder::new("{d} {l} {M}: {m}{n}")))
                    .build(path + &"/ctehxk2.log".to_string())
                    .unwrap();

                let config = Config::builder()
                    .appender(Appender::builder().build("file", Box::new(file)))
                    .logger(Logger::builder()
                                .appender("file")
                                .additive(false)
                                .build("ctehxk2", LogLevelFilter::Debug))
                    .build(Root::builder()
                               .appender("file")
                               .build(LogLevelFilter::Error))
                    .unwrap();

                log4rs::init_config(config).unwrap();
            })
        }
        _ => (),
    }
}

fn post_request<T>(path: &str, payload: &T) -> Result<Response, Error>
    where T: Serialize
{
    let base_url = var("K2_BASE_URL").unwrap_or(BASE_URL.to_string());
    let url = base_url + path;

    let client = Client::new();

    let mut headers = Headers::new();
    headers.set(ContentType(Mime(TopLevel::Application, SubLevel::Json, vec![])));

    let body = serde_json::to_string(&payload).unwrap();

    debug!("HTTP POST URL: {}", url);
    debug!("HTTP POST body: {:?}", body);

    let mut builder = client.post(&url);
    builder = builder.headers(headers);
    builder = builder.body(&body[..]);
    builder.send()
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate uuid;
extern crate chrono;

#[macro_use] pub mod macros;

pub mod parse;
pub mod method;
pub mod record;
pub mod types;

pub mod mailbox;
pub mod calendar;
pub mod calendar_event;
pub mod contact;
pub mod contact_group;
<commit_msg>Don't export macros<commit_after>extern crate rustc_serialize;
extern crate uuid;
extern crate chrono;

#[macro_use] mod macros;

pub mod parse;
pub mod method;
pub mod record;
pub mod types;

pub mod mailbox;
pub mod calendar;
pub mod calendar_event;
pub mod contact;
pub mod contact_group;
<|endoftext|>


<commit_before>#![feature(str_char)]
extern crate nalgebra;

use nalgebra::DMat;
use std::fmt::{Debug, Formatter, Result};

pub struct SmithWaterman{
    sequence1: String,
    sequence2: String,
    matrix:  DMat<isize>,
    matched: isize,
    missed: isize,
}
pub enum GraphMovements {Blank, Left, Top, Diagonal}

impl SmithWaterman{

    pub fn new(sequence1: String, sequence2: String) -> SmithWaterman {
        SmithWaterman{matrix: nalgebra::DMat::new_zeros(sequence1.len()+1, sequence2.len()+1),
        sequence1: sequence1, sequence2: sequence2, matched: 2, missed: -1}
    }

    fn penalty(&self, value: isize, penalty_value: isize) -> isize{
        match value.checked_add(penalty_value){
            Some(i) =>{
                if i<0 { 0 }else { i }
            },
            _ => {0}
        }
    }

    pub fn score(&mut self){
        let mut max_point = (0,0);
        let mut max = 0;
        for row in (1..self.sequence1.len()+1){
            for col in (1..self.sequence2.len()+1){
                let left = self.penalty(self.matrix[(row, col-1)], self.missed);
                let top = self.penalty(self.matrix[(row-1, col)], self.missed);
                let diagonal = self.matrix[(row-1, col-1)];
                let diagonal_match = if self.sequence2.char_at(col-1) == self.sequence1.char_at(row-1){
                    self.penalty(diagonal, self.matched)
                }else{
                    self.penalty(diagonal, self.missed)
                };
                let n = std::cmp::max(left, std::cmp::max(top, diagonal_match));
                if n >= max{
                    max = n;
                    max_point = (row,col);
                }
                self.matrix[(row, col)] = n;
            }
        }
        let mut last_movement = GraphMovements::Blank;
        let mut sequence1_alignment = String::new();
        let mut sequence2_alignment = String::new();
        while max > 0 {
            let (row, col) = max_point;
            let one = self.sequence1.char_at(row-1);
            let two = self.sequence2.char_at(col-1);
            match last_movement{
                GraphMovements::Blank  => {
                    sequence1_alignment.push(one);
                    sequence2_alignment.push(two);
                },
                GraphMovements::Diagonal => {
                    sequence1_alignment.push(one);
                    sequence2_alignment.push(two);
                },
                GraphMovements::Top => {
                    sequence1_alignment.push(one);
                    sequence2_alignment.push('-');
                },
                GraphMovements::Left => {
                    sequence1_alignment.push(one);
                    sequence2_alignment.push('-');
                },
            }
            let top = self.matrix[(row-1, col)];
            let left = self.matrix[(row, col-1)];
            let diagonal = self.matrix[(row-1, col-1)];
            max  = std::cmp::max(left, std::cmp::max(top, diagonal));
            max_point = if diagonal == max{
                last_movement = GraphMovements::Diagonal;
                (row-1, col-1)
            } else if left == max{
                last_movement = GraphMovements::Left;
                (row, col-1)
            } else {
                last_movement = GraphMovements::Top;
                (row-1, col)
            };
        };
        let x1: String = sequence1_alignment.chars().rev().collect();
        let x2: String = sequence2_alignment.chars().rev().collect();
        println!("{:?}",x1);
        println!("{:?}",x2);
    }
}

impl Debug for SmithWaterman {
    fn fmt(&self, form:&mut Formatter) -> Result {
        //nrows already has an extra over the sequence counts for the row of zeros
        for row in 0..self.matrix.nrows()+1 {
            for col in 0..self.matrix.ncols()+1 {
                let _ = if col==0 && row>1{
                    write!(form, "{:>5}", self.sequence1.char_at(row-2).to_string())
                } else if row==0 && col>1{
                    write!(form, "{:>5}", self.sequence2.char_at(col-2).to_string())
                } else if row>=1 && col>=1{
                    write!(form, "{:>5}", self.matrix[(row-1,col-1)])
                }else{
                    write!(form, "{:>5}", "-")
                };
            }
            let _ = write!(form, "\n");
        }
        write!(form, "\n")
    }
}

#[test]
fn its_debugging() {
    let mut smitty = SmithWaterman::new("atgcatgcatgc".to_string(), "atgggcatg".to_string());
    smitty.score();
    println!("{:?}", smitty);

    let mut smitty = SmithWaterman::new( "atgggcatg".to_string(),"atgcatgcatgc".to_string());
    smitty.score();
    println!("{:?}", smitty);
}
<commit_msg>Rename variables and flip cols with rows<commit_after>#![feature(str_char)]
extern crate nalgebra;

use nalgebra::DMat;
use std::fmt::{Debug, Formatter, Result};

pub struct SmithWaterman{
    genome_sequence: String,
    read_sequence: String,
    matrix:  DMat<isize>,
    matched: isize,
    missed: isize,
}
pub enum GraphMovements {Blank, Left, Top, Diagonal}

impl SmithWaterman{

    pub fn new(genome_sequence: String, read_sequence: String) -> SmithWaterman {
        SmithWaterman{matrix: nalgebra::DMat::new_zeros(read_sequence.len()+1, genome_sequence.len()+1),
        genome_sequence: genome_sequence, read_sequence: read_sequence, matched: 2, missed: -1}
    }

    fn penalty(&self, value: isize, penalty_value: isize) -> isize{
        match value.checked_add(penalty_value){
            Some(i) =>{
                if i<0 { 0 }else { i }
            },
            _ => {0}
        }
    }

    pub fn score(&mut self){
        let mut max_point = (0,0);
        let mut max = 0;
        for row in (1..self.read_sequence.len()+1){
            for col in (1..self.genome_sequence.len()+1){
                let left = self.penalty(self.matrix[(row, col-1)], self.missed);
                let top = self.penalty(self.matrix[(row-1, col)], self.missed);
                let diagonal = self.matrix[(row-1, col-1)];
                let diagonal_match = if self.read_sequence.char_at(row-1) == self.genome_sequence.char_at(col-1){
                    self.penalty(diagonal, self.matched)
                }else{
                    self.penalty(diagonal, self.missed)
                };
                let n = std::cmp::max(left, std::cmp::max(top, diagonal_match));
                if n >= max{
                    max = n;
                    max_point = (row,col);
                }
                self.matrix[(row, col)] = n;
            }
        }
        let mut last_movement = GraphMovements::Blank;
        let mut genome_sequence_alignment = String::new();
        let mut read_sequence_alignment = String::new();
        while max > 0 {
            let (row, col) = max_point;
            let one = self.genome_sequence.char_at(col-1);
            let two = self.read_sequence.char_at(row-1);
            match last_movement{
                GraphMovements::Blank  => {
                    genome_sequence_alignment.push(one);
                    read_sequence_alignment.push(two);
                },
                GraphMovements::Diagonal => {
                    genome_sequence_alignment.push(one);
                    read_sequence_alignment.push(two);
                },
                GraphMovements::Top => {
                    genome_sequence_alignment.push(one);
                    read_sequence_alignment.push('-');
                },
                GraphMovements::Left => {
                    genome_sequence_alignment.push(one);
                    read_sequence_alignment.push('-');
                },
            }
            let top = self.matrix[(row-1, col)];
            let left = self.matrix[(row, col-1)];
            let diagonal = self.matrix[(row-1, col-1)];
            max  = std::cmp::max(left, std::cmp::max(top, diagonal));
            max_point = if diagonal == max{
                last_movement = GraphMovements::Diagonal;
                (row-1, col-1)
            } else if left == max{
                last_movement = GraphMovements::Left;
                (row, col-1)
            } else {
                last_movement = GraphMovements::Top;
                (row-1, col)
            };
        };
        let x1: String = genome_sequence_alignment.chars().rev().collect();
        let x2: String = read_sequence_alignment.chars().rev().collect();
        println!("{:?}",x1);
        println!("{:?}",x2);
    }
}

impl Debug for SmithWaterman {
    fn fmt(&self, form:&mut Formatter) -> Result {
        //nrows already has an extra over the sequence counts for the row of zeros
        for row in 0..self.matrix.nrows()+1 {
            for col in 0..self.matrix.ncols()+1 {
                let _ = if col==0 && row>1{
                    write!(form, "{:>5}", self.read_sequence.char_at(row-2).to_string())
                } else if row==0 && col>1{
                    write!(form, "{:>5}", self.genome_sequence.char_at(col-2).to_string())
                } else if row>=1 && col>=1{
                    write!(form, "{:>5}", self.matrix[(row-1,col-1)])
                }else{
                    write!(form, "{:>5}", "-")
                };
            }
            let _ = write!(form, "\n");
        }
        write!(form, "\n")
    }
}

#[test]
fn its_debugging() {
    let mut smitty = SmithWaterman::new("atgcatgcatgc".to_string(), "atgggcatg".to_string());
    smitty.score();
    println!("{:?}", smitty);

    let mut smitty = SmithWaterman::new( "atgggcatg".to_string(),"atgcatgcatgc".to_string());
    smitty.score();
    println!("{:?}", smitty);
}
<|endoftext|>


<commit_before>//! The essential objective of this crate is to provide an API for copying
//! directories and their contents in a straightforward and predictable way.
//! See the documentation of the `copy_dir` function for more info.

#[macro_use]
extern crate log;

use std::io;
use std::fs;
use std::path::{Path, PathBuf};

// TODO macro this block for portability
use std::os::unix::fs::MetadataExt;

type UniqueId = (u64, u64);

fn new_os_file<P: AsRef<Path>>(path: P) -> Box<OsFile<UniqueId=UniqueId>> {
    Box::new(LunixFile { path: path.as_ref().to_path_buf() })
}
// TODO macro above

#[derive(Debug)]
pub enum Error {
    DestinationExists {
        source: PathBuf,
        destination: PathBuf
    },
    SourceDoesNotExist(PathBuf),
    SourceIsDestinationRoot {
        source: PathBuf,
        destination: PathBuf
    },
    Unknown(PathBuf),
    Io(io::Error),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        Error::Io(err)
    }
}

pub type Result<T> = std::result::Result<T, Error>;

/// This can be used to specify the error reporting behavior of the
/// `copy_dir_with_handler` function.
#[derive(Debug)]
pub enum Handler {
    /// Supply a vector that will be filled with errors
    Vector(Vec<Error>),

    /// Log errors, as per the `log` crate (client must initialize their
    /// own logger object)
    Log,
    ///
    /// Silently swallow errors
    Ignore,
}

impl Handler {
    fn handle(&mut self, error: Error) {
        match *self {
            Handler::Vector(ref mut vec) => vec.push(error),
            Handler::Log => error!("{:?}", error),
            _ => (),
        }
    }
}

macro_rules! handle {
    ($handler:expr, $expr:expr) => {
        match $expr {
            Err(err) => {
                $handler.handle(Error::from(err));
                return;
            },
            Ok(value) => value,
        }
    }
}

trait OsFile {
    type UniqueId;

    fn path(&self) -> &Path;
    fn unique_id(&self) -> Result<UniqueId>;
    fn copy(&self,
            destination: &Path,
            root_destination: Option<Self::UniqueId>,
            error_handler: &mut Handler);

    fn metadata(&self) -> Result<std::fs::Metadata> {
        std::fs::metadata(&self.path())
            .map_err( |err| Error::from(err) )
    }
}

struct LunixFile {
    path: PathBuf,
}

impl OsFile for LunixFile {
    type UniqueId = (u64, u64); // dev and inode

    fn path(&self) -> &Path {
        self.path.as_ref()
    }

    // TODO macro in different variants here for linux/unix
    fn unique_id(&self) -> Result<Self::UniqueId> {
        let metadata = self.metadata()?;
        Ok((metadata.dev(), metadata.ino()))
    }

    fn copy(&self,
            destination: &Path,
            mut root_destination: Option<UniqueId>,
            handler: &mut Handler) {

        let unique_id = handle!(handler, self.unique_id());
        let metadata = handle!(handler, self.metadata());

        if metadata.is_file() {
            handle!(
                handler,
                fs::copy(&self.path, destination).map( |_| () )
                    .map_err( |err| Error::from(err) )
            )

        } else if metadata.is_dir() {
            // if this hasn't been set yet, then this must be the root of
            // the copy, and therefore we can set it to the current
            // destination
            if let None = root_destination {
                root_destination = Some(unique_id);

            // we ignore the root of the new copy so we don't recursively copy
            // forever or until computer gets sad
            } else if unique_id == root_destination.unwrap() {
                handle!(
                    handler,
                    Err(Error::SourceIsDestinationRoot {
                        source: self.path.clone(),
                        destination: destination.to_path_buf(),
                    })
                );
                return
            }

            handle!(
                handler,
                fs::create_dir_all(destination)
            );

            for entry in handle!(handler, fs::read_dir(&self.path)) {
                let entry = handle!(handler, entry);

                LunixFile {
                    path: entry.path()
                }.copy(
                    &destination.join(entry.file_name()),
                    root_destination,
                    handler
                );
            }

            // do this last just to avoid any weirdness during the copy
            // probably totally unnecessary, but why not?
            handle!(
                handler,
                fs::set_permissions(destination, metadata.permissions())
            );

        } else {
            handle!(
                handler,
                Err(Error::Unknown(self.path.clone()))
            )
        }
    }

    // TODO override metadata method to cache it
}

/// Copy a directory and its contents
///
/// The file or directory at the source path is copied
/// to the destination path. If the source path points to a directory, it will
/// be copied recursively with its contents.
///
/// # Errors
///
/// * It's possible for many errors to occur during the recursive copy
///   operation. These errors are all returned in a `Vec`. They may or may
///   not be helpful or useful.
/// * If the source path does not exist.
/// * If the destination path exists.
/// * If something goes wrong with copying a regular file, as with
///   `std::fs::copy()`.
/// * If something goes wrong creating the new root directory when copying
///   a directory, as with `std::fs::create_dir()`.
/// * If you try to copy a directory to a path prefixed by itself e.g.
///   `copy_dir(".", "./foo")`. See below for more details.
///
/// # Caveats/Limitations
///
/// I would like to add some flexibility around how "edge cases" in the copying
/// operation are handled, but for now there is no flexibility and the following
/// caveats and limitations apply (not by any means an exhaustive list):
///
/// * You cannot currently copy a directory into itself i.e.
///   `copy_dir(".", "./foo")`. This is because we are recursively walking
///   the directory to be copied *while* we're copying it, so in this edge
///   case you get an infinite recursion. Fixing this is the top of my list
///   of things to do with this crate.
/// * Hard links are not accounted for, i.e. if more than one hard link
///   pointing to the same inode are to be copied, the data will be copied
///   twice.
/// * Filesystem boundaries may be crossed.
/// * Symbolic links will be copied, not followed.
pub fn copy_dir<Q, P>(from: P, to: Q) -> Result<()>
    where Q: AsRef<Path>, P: AsRef<Path> {

    copy_dir_with_handler(from, to, &mut Handler::Ignore)
}

/// Same as copy_dir, but allows clients to specify a `Handler` for any errors
/// that occur.
pub fn copy_dir_with_handler<Q, P>(from: P, to: Q,
                                   handler: &mut Handler) -> Result<()>
    where Q: AsRef<Path>, P: AsRef<Path> {

    if !from.as_ref().exists() {
        return Err(Error::SourceDoesNotExist(from.as_ref().to_path_buf()));

    } else if to.as_ref().exists() {
        return Err(Error::DestinationExists {
            source: from.as_ref().to_path_buf(),
            destination: to.as_ref().to_path_buf(),
        });
    }

    let source = new_os_file(&from);
    source.copy(to.as_ref(), None, handler);
    Ok(())
}

#[cfg(test)]
mod tests {
    #![allow(unused_variables)]

    extern crate std;
    use std::fs;
    use std::path::Path;
    use std::process::Command;

    extern crate walkdir;

    use super::Error;

    extern crate fs_test_helpers;
    use self::fs_test_helpers::{
        TempDir,
        Fake,
        assert_files_have_same_contents,
    };

    #[test]
    fn single_file() {
        let file = Fake::file("foo.file");
        assert_we_match_the_real_thing(&file, true, None);
    }

    #[test]
    fn directory_with_file() {
        let dir = Fake::dir("foo", vec![
            Fake::file("bar").fill_with_uuid(),
            Fake::dir("baz", vec![
                Fake::file("quux").fill_with_uuid(),
                Fake::file("fobe").fill_with_uuid()
            ])
        ]);
        assert_we_match_the_real_thing(&dir, true, None);
    }

    #[test]
    fn source_does_not_exist() {
        let base_dir = TempDir::new("copy_dir_test").unwrap();
        let source_path = base_dir.as_ref().join("noexist.file");
        match super::copy_dir(&source_path, "dest.file") {
            Ok(_) => panic!("expected Err"),
            Err(err) => match err {
                Error::SourceDoesNotExist { .. } => (),
                _ => panic!("expected SourceDoesNotExist"),
            },
        }
    }

    #[test]
    fn target_exists() {
        let base_dir = TempDir::new("copy_dir_test").unwrap();
        let source_path = base_dir.as_ref().join("exist.file");
        let target_path = base_dir.as_ref().join("exist2.file");

        {
            fs::File::create(&source_path).unwrap();
            fs::File::create(&target_path).unwrap();
        }

        match super::copy_dir(&source_path, &target_path) {
            Ok(_) => panic!("expected Err"),
            Err(err) => match err {
                Error::DestinationExists { .. } => (),
                _ => panic!("expected kind AlreadyExists")
            }
        }
    }

    #[test]
    fn attempt_copy_under_self() {
        let base_dir = TempDir::new("copy_dir_test").unwrap();
        let dir = Fake::dir("foo", vec![
            Fake::file("bar"),
            Fake::dir("baz", vec![
                Fake::file("quux"),
                Fake::file("fobe")
            ])
        ]);
        dir.create(&base_dir).unwrap();

        let from = base_dir.as_ref().join("foo");
        let to = from.as_path().join("beez");

        let copy_result = super::copy_dir(&from, &to).unwrap();
    }

    fn assert_dirs_same<P: AsRef<Path>>(a: P, b: P) {
        let mut wa = walkdir::WalkDir::new(a.as_ref()).into_iter();
        let mut wb = walkdir::WalkDir::new(b.as_ref()).into_iter();

        loop {
            let o_na = wa.next();
            let o_nb = wb.next();

            if o_na.is_some() && o_nb.is_some() {
                let r_na = o_na.unwrap();
                let r_nb = o_nb.unwrap();

                if r_na.is_ok() && r_nb.is_ok() {
                    let na = r_na.unwrap();
                    let nb = r_nb.unwrap();

                    assert_eq!(
                        na.path().strip_prefix(a.as_ref()),
                        nb.path().strip_prefix(b.as_ref())
                    );

                    assert_eq!(na.file_type(), nb.file_type());

                    if na.file_type().is_file() {
                        assert_files_have_same_contents(
                            &na.path(),
                            &nb.path(),
                        )
                    }

                    // TODO test permissions
                }

            } else if o_na.is_none() && o_nb.is_none() {
                return
            } else {
                assert!(false);
            }
        }
    }

    fn assert_we_match_the_real_thing(dir: &Fake,
                                      explicit_name: bool,
                                      o_pre_state: Option<&Fake>) {
        let base_dir = TempDir::new("copy_dir_test").unwrap();

        let source_dir = base_dir.as_ref().join("source");
        let our_dir = base_dir.as_ref().join("ours");
        let their_dir = base_dir.as_ref().join("theirs");

        fs::create_dir(&source_dir).unwrap();
        fs::create_dir(&our_dir).unwrap();
        fs::create_dir(&their_dir).unwrap();

        dir.create(&source_dir).unwrap();
        let source_path = source_dir.as_path().join(dir.name());

        let (our_target, their_target) = if explicit_name {
            (
                our_dir.as_path().join(dir.name()),
                their_dir.as_path().join(dir.name())
            )
        } else {
            (our_dir.clone(), their_dir.clone())
        };

        if let Some(pre_state) = o_pre_state {
            pre_state.create(&our_dir).unwrap();
            pre_state.create(&their_dir).unwrap();
        }

        let we_good = super::copy_dir(&source_path, &our_target).is_ok();

        let their_status = Command::new("cp")
            .arg("-r")
            .arg(source_path.as_os_str())
            .arg(their_target.as_os_str())
            .status()
            .unwrap();

        // TODO any way to ask cp whether it worked or not?
        // portability?
        // assert_eq!(we_good, their_status.success());
        assert_dirs_same(&their_dir, &our_dir);
    }

    #[test]
    fn dir_maker_and_assert_dirs_same_baseline() {
        let dir = Fake::dir(
            "foobar",
            vec![
                Fake::file("bar"),
                Fake::dir("baz", Vec::new())
            ]
        );

        let base_dir = TempDir::new("copy_dir_test").unwrap();

        let a_path = base_dir.as_ref().join("a");
        let b_path = base_dir.as_ref().join("b");

        fs::create_dir(&a_path).unwrap();
        fs::create_dir(&b_path).unwrap();

        dir.create(&a_path).unwrap();
        dir.create(&b_path).unwrap();

        assert_dirs_same(&a_path, &b_path);
    }

    #[test]
    #[should_panic]
    fn assert_dirs_same_properly_fails() {
        let dir = Fake::dir(
            "foobar",
            vec![
                Fake::file("bar"),
                Fake::dir("baz", Vec::new())
            ]
        );

        let dir2 = Fake::dir(
            "foobar",
            vec![
                Fake::file("fobe"),
                Fake::file("beez")
            ]
        );

        let base_dir = TempDir::new("copy_dir_test").unwrap();

        let a_path = base_dir.as_ref().join("a");
        let b_path = base_dir.as_ref().join("b");

        fs::create_dir(&a_path).unwrap();
        fs::create_dir(&b_path).unwrap();

        dir.create(&a_path).unwrap();
        dir2.create(&b_path).unwrap();

        assert_dirs_same(&a_path, &b_path);
    }

}
<commit_msg>fix recursive copy detection<commit_after>//! The essential objective of this crate is to provide an API for copying
//! directories and their contents in a straightforward and predictable way.
//! See the documentation of the `copy_dir` function for more info.

#[macro_use]
extern crate log;

use std::io;
use std::fs;
use std::path::{Path, PathBuf};

#[cfg(unix)]
use std::os::unix::fs::MetadataExt;

#[cfg(unix)]
type UniqueId = (u64, u64);

#[cfg(unix)]
fn new_os_file<P: AsRef<Path>>(path: P) -> Box<OsFile<UniqueId=UniqueId>> {
    Box::new(LunixFile { path: path.as_ref().to_path_buf() })
}
// TODO macro above

#[derive(Debug)]
pub enum Error {
    DestinationExists {
        source: PathBuf,
        destination: PathBuf
    },
    SourceDoesNotExist(PathBuf),
    SourceIsDestinationRoot {
        source: PathBuf,
        destination: PathBuf
    },
    Unknown(PathBuf),
    Io(io::Error),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        Error::Io(err)
    }
}

pub type Result<T> = std::result::Result<T, Error>;

/// This can be used to specify the error reporting behavior of the
/// `copy_dir_with_handler` function.
#[derive(Debug)]
pub enum Handler {
    /// Supply a vector that will be filled with errors
    Vector(Vec<Error>),

    /// Log errors, as per the `log` crate (client must initialize their
    /// own logger object)
    Log,
    ///
    /// Silently swallow errors
    Ignore,
}

impl Handler {
    fn handle(&mut self, error: Error) {
        match *self {
            Handler::Vector(ref mut vec) => vec.push(error),
            Handler::Log => error!("{:?}", error),
            _ => (),
        }
    }
}

macro_rules! handle {
    ($handler:expr, $expr:expr) => {
        match $expr {
            Err(err) => {
                $handler.handle(Error::from(err));
                return;
            },
            Ok(value) => value,
        }
    }
}

trait OsFile {
    type UniqueId;

    fn path(&self) -> &Path;
    fn unique_id(&self) -> Result<UniqueId>;
    fn copy(&self,
            destination: &Path,
            root_destination: Option<Self::UniqueId>,
            error_handler: &mut Handler);

    fn metadata(&self) -> Result<std::fs::Metadata> {
        std::fs::metadata(&self.path())
            .map_err( |err| Error::from(err) )
    }
}

struct LunixFile {
    path: PathBuf,
}

impl OsFile for LunixFile {
    type UniqueId = (u64, u64); // dev and inode

    fn path(&self) -> &Path {
        self.path.as_ref()
    }

    #[cfg(unix)]
    fn unique_id(&self) -> Result<Self::UniqueId> {
        let metadata = self.metadata()?;
        Ok((metadata.dev(), metadata.ino()))
    }

    fn copy(&self,
            destination: &Path,
            mut root_destination: Option<UniqueId>,
            handler: &mut Handler) {

        let unique_id = handle!(handler, self.unique_id());
        let metadata = handle!(handler, self.metadata());

        if metadata.is_file() {
            handle!(
                handler,
                fs::copy(&self.path, destination).map( |_| () )
                    .map_err( |err| Error::from(err) )
            )

        } else if metadata.is_dir() {
            // we ignore the root of the new copy so we don't recursively copy
            // forever or until computer gets sad
            if root_destination.is_some() &&
                root_destination.unwrap() == unique_id {

                handle!(
                    handler,
                    Err(Error::SourceIsDestinationRoot {
                        source: self.path.clone(),
                        destination: destination.to_path_buf(),
                    })
                );
                return
            }

            handle!(
                handler,
                fs::create_dir_all(destination)
            );

            if root_destination.is_none() {
                root_destination = Some(
                    handle!(
                        handler,
                        LunixFile {
                            path: destination.to_path_buf()
                        }.unique_id()
                    )
                );
            }

            for entry in handle!(handler, fs::read_dir(&self.path)) {
                let entry = handle!(handler, entry);

                LunixFile {
                    path: entry.path()
                }.copy(
                    &destination.join(entry.file_name()),
                    root_destination,
                    handler
                );
            }

            // do this last just to avoid any weirdness during the copy
            // probably totally unnecessary, but why not?
            handle!(
                handler,
                fs::set_permissions(destination, metadata.permissions())
            );

        } else {
            handle!(
                handler,
                Err(Error::Unknown(self.path.clone()))
            )
        }
    }

    // TODO override metadata method to cache it
}

/// Copy a directory and its contents
///
/// The file or directory at the source path is copied
/// to the destination path. If the source path points to a directory, it will
/// be copied recursively with its contents.
///
/// # Errors
///
/// * It's possible for many errors to occur during the recursive copy
///   operation. These errors are all returned in a `Vec`. They may or may
///   not be helpful or useful.
/// * If the source path does not exist.
/// * If the destination path exists.
/// * If something goes wrong with copying a regular file, as with
///   `std::fs::copy()`.
/// * If something goes wrong creating the new root directory when copying
///   a directory, as with `std::fs::create_dir()`.
/// * If you try to copy a directory to a path prefixed by itself e.g.
///   `copy_dir(".", "./foo")`. See below for more details.
///
/// # Caveats/Limitations
///
/// I would like to add some flexibility around how "edge cases" in the copying
/// operation are handled, but for now there is no flexibility and the following
/// caveats and limitations apply (not by any means an exhaustive list):
///
/// * You cannot currently copy a directory into itself i.e.
///   `copy_dir(".", "./foo")`. This is because we are recursively walking
///   the directory to be copied *while* we're copying it, so in this edge
///   case you get an infinite recursion. Fixing this is the top of my list
///   of things to do with this crate.
/// * Hard links are not accounted for, i.e. if more than one hard link
///   pointing to the same inode are to be copied, the data will be copied
///   twice.
/// * Filesystem boundaries may be crossed.
/// * Symbolic links will be copied, not followed.
pub fn copy_dir<Q, P>(from: P, to: Q) -> Result<()>
    where Q: AsRef<Path>, P: AsRef<Path> {

    copy_dir_with_handler(from, to, &mut Handler::Ignore)
}

/// Same as copy_dir, but allows clients to specify a `Handler` for any errors
/// that occur.
pub fn copy_dir_with_handler<Q, P>(from: P, to: Q,
                                   handler: &mut Handler) -> Result<()>
    where Q: AsRef<Path>, P: AsRef<Path> {

    if !from.as_ref().exists() {
        return Err(Error::SourceDoesNotExist(from.as_ref().to_path_buf()));

    } else if to.as_ref().exists() {
        return Err(Error::DestinationExists {
            source: from.as_ref().to_path_buf(),
            destination: to.as_ref().to_path_buf(),
        });
    }

    let source = new_os_file(&from);
    source.copy(to.as_ref(), None, handler);
    Ok(())
}

#[cfg(test)]
mod tests {
    #![allow(unused_variables)]

    extern crate std;
    use std::fs;
    use std::path::Path;
    use std::process::Command;

    extern crate walkdir;

    use super::Error;

    extern crate fs_test_helpers;
    use self::fs_test_helpers::{
        TempDir,
        Fake,
        assert_files_have_same_contents,
    };

    #[test]
    fn single_file() {
        let file = Fake::file("foo.file");
        assert_we_match_the_real_thing(&file, true, None);
    }

    #[test]
    fn directory_with_file() {
        let dir = Fake::dir("foo", vec![
            Fake::file("bar").fill_with_uuid(),
            Fake::dir("baz", vec![
                Fake::file("quux").fill_with_uuid(),
                Fake::file("fobe").fill_with_uuid()
            ])
        ]);
        assert_we_match_the_real_thing(&dir, true, None);
    }

    #[test]
    fn source_does_not_exist() {
        let base_dir = TempDir::new("copy_dir_test").unwrap();
        let source_path = base_dir.as_ref().join("noexist.file");
        match super::copy_dir(&source_path, "dest.file") {
            Ok(_) => panic!("expected Err"),
            Err(err) => match err {
                Error::SourceDoesNotExist { .. } => (),
                _ => panic!("expected SourceDoesNotExist"),
            },
        }
    }

    #[test]
    fn target_exists() {
        let base_dir = TempDir::new("copy_dir_test").unwrap();
        let source_path = base_dir.as_ref().join("exist.file");
        let target_path = base_dir.as_ref().join("exist2.file");

        {
            fs::File::create(&source_path).unwrap();
            fs::File::create(&target_path).unwrap();
        }

        match super::copy_dir(&source_path, &target_path) {
            Ok(_) => panic!("expected Err"),
            Err(err) => match err {
                Error::DestinationExists { .. } => (),
                _ => panic!("expected kind AlreadyExists")
            }
        }
    }

    #[test]
    fn attempt_copy_under_self() {
        let base_dir = TempDir::new("copy_dir_test").unwrap();
        let dir = Fake::dir("foo", vec![
            Fake::file("bar"),
            Fake::dir("baz", vec![
                Fake::file("quux"),
                Fake::file("fobe")
            ])
        ]);
        dir.create(&base_dir).unwrap();

        let from = base_dir.as_ref().join("foo");
        let to = from.as_path().join("beez");

        let copy_result = super::copy_dir(&from, &to).unwrap();
    }

    fn assert_dirs_same<P: AsRef<Path>>(a: P, b: P) {
        let mut wa = walkdir::WalkDir::new(a.as_ref()).into_iter();
        let mut wb = walkdir::WalkDir::new(b.as_ref()).into_iter();

        loop {
            let o_na = wa.next();
            let o_nb = wb.next();

            if o_na.is_some() && o_nb.is_some() {
                let r_na = o_na.unwrap();
                let r_nb = o_nb.unwrap();

                if r_na.is_ok() && r_nb.is_ok() {
                    let na = r_na.unwrap();
                    let nb = r_nb.unwrap();

                    assert_eq!(
                        na.path().strip_prefix(a.as_ref()),
                        nb.path().strip_prefix(b.as_ref())
                    );

                    assert_eq!(na.file_type(), nb.file_type());

                    if na.file_type().is_file() {
                        assert_files_have_same_contents(
                            &na.path(),
                            &nb.path(),
                        )
                    }

                    // TODO test permissions
                }

            } else if o_na.is_none() && o_nb.is_none() {
                return
            } else {
                assert!(false);
            }
        }
    }

    fn assert_we_match_the_real_thing(dir: &Fake,
                                      explicit_name: bool,
                                      o_pre_state: Option<&Fake>) {
        let base_dir = TempDir::new("copy_dir_test").unwrap();

        let source_dir = base_dir.as_ref().join("source");
        let our_dir = base_dir.as_ref().join("ours");
        let their_dir = base_dir.as_ref().join("theirs");

        fs::create_dir(&source_dir).unwrap();
        fs::create_dir(&our_dir).unwrap();
        fs::create_dir(&their_dir).unwrap();

        dir.create(&source_dir).unwrap();
        let source_path = source_dir.as_path().join(dir.name());

        let (our_target, their_target) = if explicit_name {
            (
                our_dir.as_path().join(dir.name()),
                their_dir.as_path().join(dir.name())
            )
        } else {
            (our_dir.clone(), their_dir.clone())
        };

        if let Some(pre_state) = o_pre_state {
            pre_state.create(&our_dir).unwrap();
            pre_state.create(&their_dir).unwrap();
        }

        let we_good = super::copy_dir(&source_path, &our_target).is_ok();

        let their_status = Command::new("cp")
            .arg("-r")
            .arg(source_path.as_os_str())
            .arg(their_target.as_os_str())
            .status()
            .unwrap();

        // TODO any way to ask cp whether it worked or not?
        // portability?
        // assert_eq!(we_good, their_status.success());
        assert_dirs_same(&their_dir, &our_dir);
    }

    #[test]
    fn dir_maker_and_assert_dirs_same_baseline() {
        let dir = Fake::dir(
            "foobar",
            vec![
                Fake::file("bar"),
                Fake::dir("baz", Vec::new())
            ]
        );

        let base_dir = TempDir::new("copy_dir_test").unwrap();

        let a_path = base_dir.as_ref().join("a");
        let b_path = base_dir.as_ref().join("b");

        fs::create_dir(&a_path).unwrap();
        fs::create_dir(&b_path).unwrap();

        dir.create(&a_path).unwrap();
        dir.create(&b_path).unwrap();

        assert_dirs_same(&a_path, &b_path);
    }

    #[test]
    #[should_panic]
    fn assert_dirs_same_properly_fails() {
        let dir = Fake::dir(
            "foobar",
            vec![
                Fake::file("bar"),
                Fake::dir("baz", Vec::new())
            ]
        );

        let dir2 = Fake::dir(
            "foobar",
            vec![
                Fake::file("fobe"),
                Fake::file("beez")
            ]
        );

        let base_dir = TempDir::new("copy_dir_test").unwrap();

        let a_path = base_dir.as_ref().join("a");
        let b_path = base_dir.as_ref().join("b");

        fs::create_dir(&a_path).unwrap();
        fs::create_dir(&b_path).unwrap();

        dir.create(&a_path).unwrap();
        dir2.create(&b_path).unwrap();

        assert_dirs_same(&a_path, &b_path);
    }

}
<|endoftext|>