<commit_before>//! Functions to find the difference between to texts (strings).
//! Usage
//! ----------
//!
//! Add the following to your Cargo.toml:
//!
//! ```toml
//! [dependencies.text_diff]
//!
//! git = "https://github.com/johannhof/text-diff.rs.git"
//! ```
//!
//! Now you can use the crate in your code
//!
//! ```ignore
//! extern crate text_diff;
//! ```

#![crate_name = "text_diff"]
#![doc(html_root_url = "https://johannhof.github.io/text-diff.rs/")]

#![feature(step_by)]

// I can basically feel the karma already
#![deny(missing_docs)]

mod lcs;
mod merge;

use lcs::lcs;
use merge::merge;

/// Defines the contents of a changeset
/// Changesets will be delivered in order of appearance in the original string
/// Sequences of the same kind will be grouped into one Difference
#[derive(PartialEq, Debug)]
pub enum Difference {
    /// Sequences that are the same
    Same(String),
    /// Sequences that are an addition (don't appear in the first string)
    Add(String),
    /// Sequences that are a removal (don't appear in the second string)
    Rem(String)
}

/// Calculates the edit distance and the changeset for two given strings.
/// The first string is assumed to be the "original", the second to be an
/// edited version of the first. The third parameter specifies how to split
/// the input strings, leading to a more or less exact comparison.
///
/// Common splits are `""` for char-level, `" "` for word-level and `"\n"` for line-level.
///
/// Outputs the edit distance (how much the two strings differ) and a "changeset", that is
/// a `Vec` containing `Difference`s.
///
/// # Examples
///
/// ```
///
/// ```
pub fn diff(orig: &str, edit: &str, split: &str) -> (i32, Vec<Difference>) {
    let (dist, common) = lcs(orig, edit, split);
    (dist, merge(orig, edit, &common))
}

/// Prints a colorful visual representation of the diff.
/// This is just a convenience function for those who want quick results.
///
/// I recommend checking out the examples on how to build your
/// own diff output.
/// # Examples
///
/// ```
/// use text_diff::print_diff;
/// print_diff("Diffs are awesome", "Diffs are cool", " ");
/// ```
pub fn print_diff(orig: &str, edit: &str, split: &str) {
    let (_, changeset) = diff(orig, edit, split);
    let mut ret = String::new();

    for seq in changeset {
        match seq {
            Difference::Same(ref x) => {
                ret.push_str(x);
            },
            Difference::Add(ref x) => {
                ret.push_str("\x1B[92m");
                ret.push_str(x);
                ret.push_str("\x1B[0m");
            },
            Difference::Rem(ref x) => {
                ret.push_str("\x1B[91m");
                ret.push_str(x);
                ret.push_str("\x1B[0m");
            }
        }
    }
    println!("{}", ret);
}

<commit_msg>Diff Example<commit_after>//! Functions to find the difference between to texts (strings).
//! Usage
//! ----------
//!
//! Add the following to your Cargo.toml:
//!
//! ```toml
//! [dependencies.text_diff]
//!
//! git = "https://github.com/johannhof/text-diff.rs.git"
//! ```
//!
//! Now you can use the crate in your code
//!
//! ```ignore
//! extern crate text_diff;
//! ```

#![crate_name = "text_diff"]
#![doc(html_root_url = "https://johannhof.github.io/text-diff.rs/")]

#![feature(step_by)]

// I can basically feel the karma already
#![deny(missing_docs)]

mod lcs;
mod merge;

use lcs::lcs;
use merge::merge;

/// Defines the contents of a changeset
/// Changesets will be delivered in order of appearance in the original string
/// Sequences of the same kind will be grouped into one Difference
#[derive(PartialEq, Debug)]
pub enum Difference {
    /// Sequences that are the same
    Same(String),
    /// Sequences that are an addition (don't appear in the first string)
    Add(String),
    /// Sequences that are a removal (don't appear in the second string)
    Rem(String)
}

/// Calculates the edit distance and the changeset for two given strings.
/// The first string is assumed to be the "original", the second to be an
/// edited version of the first. The third parameter specifies how to split
/// the input strings, leading to a more or less exact comparison.
///
/// Common splits are `""` for char-level, `" "` for word-level and `"\n"` for line-level.
///
/// Outputs the edit distance (how much the two strings differ) and a "changeset", that is
/// a `Vec` containing `Difference`s.
///
/// # Examples
///
/// ```
/// use text_diff::diff;
/// use text_diff::Difference;
///
/// let (dist, changeset) = diff("test", "tent", "");
///
/// assert_eq!(changeset, vec![
///     Difference::Same("te".to_string()),
///     Difference::Rem("s".to_string()),
///     Difference::Add("n".to_string()),
///     Difference::Same("t".to_string())
/// ]);
/// ```
pub fn diff(orig: &str, edit: &str, split: &str) -> (i32, Vec<Difference>) {
    let (dist, common) = lcs(orig, edit, split);
    (dist, merge(orig, edit, &common))
}

/// Prints a colorful visual representation of the diff.
/// This is just a convenience function for those who want quick results.
///
/// I recommend checking out the examples on how to build your
/// own diff output.
/// # Examples
///
/// ```
/// use text_diff::print_diff;
/// print_diff("Diffs are awesome", "Diffs are cool", " ");
/// ```
pub fn print_diff(orig: &str, edit: &str, split: &str) {
    let (_, changeset) = diff(orig, edit, split);
    let mut ret = String::new();

    for seq in changeset {
        match seq {
            Difference::Same(ref x) => {
                ret.push_str(x);
            },
            Difference::Add(ref x) => {
                ret.push_str("\x1B[92m");
                ret.push_str(x);
                ret.push_str("\x1B[0m");
            },
            Difference::Rem(ref x) => {
                ret.push_str("\x1B[91m");
                ret.push_str(x);
                ret.push_str("\x1B[0m");
            }
        }
    }
    println!("{}", ret);
}

<|endoftext|>


<commit_before>

extern crate libc;
#[macro_use]
extern crate enum_primitive;
extern crate opusfile_sys;

use std::borrow::ToOwned;
use std::vec::Vec;
use std::rc::Rc;
use std::{mem, slice, string, io, ptr};
use std::io::{Read, Seek};
use std::ffi::CStr;
use enum_primitive::FromPrimitive;

use opusfile_sys as opus;

static CB : opus::OpusFileCallbacks = opus::OpusFileCallbacks {
    read:  read_cb,
    seek:  Some(seek_cb),
    tell:  Some(tell_cb),
    close: None,
};

enum_from_primitive! {
    pub enum OpusFileError
    {
        False         = opus::OP_FALSE as isize,
        Eof           = opus::OP_EOF as isize,
        Hole          = opus::OP_HOLE as isize,
        ERead         = opus::OP_EREAD as isize,
        EFault        = opus::OP_EFAULT as isize,
        EImpl         = opus::OP_EIMPL as isize,
        EInval        = opus::OP_EINVAL as isize,
        ENotFormat    = opus::OP_ENOTFORMAT as isize,
        EBadHeader    = opus::OP_EBADHEADER as isize,
        EVersion      = opus::OP_EVERSION as isize,
        ENotAudio     = opus::OP_ENOTAUDIO as isize,
        EBadPacket    = opus::OP_EBADPACKET as isize,
        EBadLink      = opus::OP_EBADLINK as isize,
        ENoSeek       = opus::OP_ENOSEEK as isize,
        EBadTimeStamp = opus::OP_EBADTIMESTAMP as isize,
    }
}

pub type OpusFileResult<T> = Result<T, OpusFileError>;

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

enum DataSource <'s> {
    Slice (&'s [u8]),
    Read (&'s mut Read),
    ReadSeek (&'s mut ReadSeek),
}

pub struct OggOpusFile <'s>
{
    of   : *mut opus::OggOpusFile,
    data : DataSource<'s>,
}
impl <'s> OggOpusFile<'s>
{
    pub fn from_slice (data : &[u8]) -> OpusFileResult<OggOpusFile>
    {
        unsafe {
            let mut e: libc::c_int = 0;
            match opus::op_open_memory(data.as_ptr() as *const libc::c_uchar, data.len() as libc::size_t, &mut e as *mut libc::c_int) {
                of if of != ptr::null_mut() => Ok(OggOpusFile { of: of, data: DataSource::Slice(data), }),
                _ => Err(OpusFileError::from_isize(e as isize).unwrap()),
            }
        }
    }

    pub fn from_read (data : &mut Read) -> OpusFileResult<OggOpusFile>
    {
        unsafe {
            let mut e: libc::c_int = 0;
            match opus::op_open_callbacks(mem::transmute_copy(&data), &CB, ptr::null(), 0, &mut e as *mut libc::c_int) {
                of if of != ptr::null_mut() => Ok(OggOpusFile { of: of, data: DataSource::Read(data), }),
                _ => Err(OpusFileError::from_isize(e as isize).unwrap()),
            }
        }
    }

    pub fn from_read_seek (data : &mut ReadSeek) -> OpusFileResult<OggOpusFile>
    {
        unsafe {
            let mut e: libc::c_int = 0;
            match opus::op_open_callbacks(mem::transmute_copy(&data), &CB, ptr::null(), 0, &mut e as *mut libc::c_int) {
                of if of != ptr::null_mut() => Ok(OggOpusFile { of: of, data: DataSource::ReadSeek(data), }),
                _ => Err(OpusFileError::from_isize(e as isize).unwrap()),
            }
        }
    }

    pub fn seekable (&self) -> bool
    {
        unsafe {
            opus::op_seekable(self.of as *const opus::OggOpusFile) != 0
        }
    }

    pub fn link_count (&self) -> i32
    {
        unsafe {
            opus::op_link_count(self.of as *const opus::OggOpusFile) as i32
        }
    }

    pub fn serial_no (&self, li: i32 ) -> u32
    {
        unsafe {
            opus::op_serialno(self.of as *const opus::OggOpusFile, li as libc::c_int) as u32
        }
    }

    pub fn channel_count (&self, li: i32 ) -> i32
    {
        unsafe {
            opus::op_channel_count(self.of as *const opus::OggOpusFile, li as libc::c_int) as i32
        }
    }

    pub fn raw_total (&self, li: i32 ) -> i64
    {
        unsafe {
            opus::op_raw_total(self.of as *const opus::OggOpusFile, li as libc::c_int) as i64
        }
    }

    pub fn pcm_total (&self, li: i32 ) -> i64
    {
        unsafe {
            opus::op_pcm_total(self.of as *const opus::OggOpusFile, li as libc::c_int) as i64
        }
    }

    pub fn head (&self, li: i32) -> Option<OpusHead>
    {
        unsafe {
            match opus::op_head(self.of as *const opus::OggOpusFile, li as libc::c_int) {
                oh if oh != ptr::null() => Some(OpusHead{
                    version:           (*oh).version as i32,
                    channel_count:     (*oh).channel_count as u8,
                    pre_skip:          (*oh).pre_skip as i32,
                    input_sample_rate: (*oh).input_sample_rate as u32,
                    output_gain:       (*oh).output_gain as i32,
                    mapping_family:    (*oh).mapping_family as i32,
                    stream_count:      (*oh).stream_count as u8,
                    coupled_count:     (*oh).coupled_count as u8,
                    mapping:           (*oh).mapping[0 .. (2 * (*oh).coupled_count + ((*oh).stream_count - (*oh).coupled_count)) as usize].to_owned(),
                }),
                _ => None,
            }
        }
    }

    pub fn tags (&self, li: i32) -> Option<OpusTags>
    {
        unsafe {
            match opus::op_tags(self.of as *const opus::OggOpusFile, li as libc::c_int) {
                ot if ot != ptr::null() => Some(OpusTags {
                    user_comments: [0 .. (*ot).comments as usize].map(|ci| {
                        let len = *((*ot).comment_lengths as *const i32).offset(ci as isize) as usize;
                        String::from_utf8_lossy(slice::from_raw_parts(*((*ot).user_comments as *const *const u8).offset(ci as isize), len)).into_owned()
                    }).collect(),
                    vendor: CStr::from_ptr((*ot).vendor as *const i8).to_string_lossy().into_owned(),
                }),
                _ => None,
            }
        }
    }

    pub fn current_link (&self) -> i32
    {
        unsafe {
            opus::op_current_link(self.of as *const opus::OggOpusFile) as i32
        }
    }

    pub fn bitrate (&self, li: i32) -> i32
    {
        unsafe {
            opus::op_bitrate(self.of as *const opus::OggOpusFile, li as libc::c_int) as i32
        }
    }

    pub fn bitrate_instant (&self) -> i32
    {
        unsafe {
            opus::op_bitrate_instant(self.of as *const opus::OggOpusFile) as i32
        }
    }

    pub fn raw_tell (&self) -> i64
    {
        unsafe {
            opus::op_raw_tell(self.of as *const opus::OggOpusFile) as i64
        }
    }

    pub fn pcm_tell (&self) -> i64
    {
        unsafe {
            opus::op_pcm_tell(self.of as *const opus::OggOpusFile) as i64
        }
    }

    pub fn raw_seek (&mut self, offset: i64) -> OpusFileResult<()> {
        unsafe {
            match opus::op_raw_seek(self.of, offset) {
                0 => Ok(()),
                e => Err(OpusFileError::from_i32(e as i32).unwrap()),
            }
        }
    }

    pub fn pcm_seek (&mut self, offset: i64) -> OpusFileResult<()> {
        unsafe {
            match opus::op_raw_seek(self.of, offset) {
                0 => Ok(()),
                e => Err(OpusFileError::from_i32(e as i32).unwrap()),
            }
        }
    }

    pub fn read (&mut self, pcm: &mut [i16], li: &mut i32) -> OpusFileResult<i32>
    {
        unsafe {
            match opus::op_read(self.of, pcm.as_mut_ptr(), pcm.len() as libc::c_int, li as *mut i32 as *mut libc::c_int) {
                e if e < 0 => Err(OpusFileError::from_i32(e as i32).unwrap()),
                n          => Ok(n as i32),
            }
        }
    }

    pub fn read_float (&mut self, pcm: &mut [libc::c_float], li: &mut i32) -> OpusFileResult<i32>
    {
        unsafe {
            match opus::op_read_float(self.of, pcm.as_mut_ptr(), pcm.len() as libc::c_int, li as *mut i32 as *mut libc::c_int) {
                e if e < 0 => Err(OpusFileError::from_i32(e as i32).unwrap()),
                n          => Ok(n as i32),
            }
        }
    }

    pub fn read_stereo (&mut self, pcm: &mut [i16]) -> OpusFileResult<i32>
    {
        unsafe {
            match opus::op_read_stereo(self.of, pcm.as_mut_ptr(), pcm.len() as libc::c_int) {
                e if e < 0 => Err(OpusFileError::from_i32(e as i32).unwrap()),
                n          => Ok(n as i32),
            }
        }
    }

    pub fn read_float_stereo (&mut self, pcm: &mut [f32]) -> OpusFileResult<i32>
    {
        unsafe {
            match opus::op_read_float_stereo(self.of, pcm.as_mut_ptr(), pcm.len() as libc::c_int) {
                e if e < 0 => Err(OpusFileError::from_i32(e as i32).unwrap()),
                n          => Ok(n as i32),
            }
        }
    }
}

unsafe extern "C" fn read_cb (src: *mut libc::c_void, buf: *mut libc::c_uchar, size: libc::c_int) -> libc::c_int {
    fn fill_buffer (read : &mut Read, buf : &[u8]) -> usize
    {
        let mut i = 0;

        0
    }

    match *(src as *mut DataSource) {
        DataSource::Read(r) => fill_buffer(r, slice::from_raw_parts_mut(buf, size)),
        DataSource::ReadSeek(r) => fill_buffer(r),
        _ => -1,
    }
}

unsafe extern "C" fn seek_cb (src : *mut libc::c_void, pos: i64, style : libc::c_int) -> libc::c_int {
    let pos = match style {
        libc::SEEK_SET => io::SeekFrom::Start(pos as u64),
        libc::SEEK_CUR => io::SeekFrom::Current(pos),
        libc::SEEK_END => io::SeekFrom::End(pos),
        _ => return -1,
    };

    match *(src as *mut DataSource) {
        DataSource::ReadSeek(s) => {
            while let Err(e) = s.seek(pos) { match e.kind() {
                io::ErrorKind::Interrupted => continue,
                _ => return -1,
            }}
        }
        _ => -1,
    }
}

unsafe extern "C" fn tell_cb (src: *mut libc::c_void) -> i64 {
    match *(src as *mut DataSource) {
        DataSource::ReadSeek(s) => {
            while let Err(e) = s.seek(io::SeekFrom::Current(0)) { match e.kind() {
                io::ErrorKind::Interrupted => continue,
                _ => return -1,
            }}
        }
        _ => -1,
    }
}

pub struct OpusHead
{
    pub mapping           : Vec<u8>,
    pub version           : i32,
    pub pre_skip          : i32,
    pub input_sample_rate : u32,
    pub output_gain       : i32,
    pub mapping_family    : i32,
    pub channel_count     : u8,
    pub stream_count      : u8,
    pub coupled_count     : u8,
}

pub struct OpusTags
{
    pub user_comments : Vec<String>,
    pub vendor        : String,
}

<commit_msg>Finish modernizing<commit_after>

extern crate libc;
#[macro_use]
extern crate enum_primitive;
extern crate opusfile_sys;

use std::borrow::ToOwned;
use std::vec::Vec;
use std::{mem, slice, io, ptr};
use std::io::{Read, Seek};
use std::ffi::CStr;
use enum_primitive::FromPrimitive;

use opusfile_sys as opus;

static CB : opus::OpusFileCallbacks = opus::OpusFileCallbacks {
    read:  read_cb,
    seek:  Some(seek_cb),
    tell:  Some(tell_cb),
    close: None,
};

enum_from_primitive! {
    pub enum OpusFileError
    {
        False         = opus::OP_FALSE as isize,
        Eof           = opus::OP_EOF as isize,
        Hole          = opus::OP_HOLE as isize,
        ERead         = opus::OP_EREAD as isize,
        EFault        = opus::OP_EFAULT as isize,
        EImpl         = opus::OP_EIMPL as isize,
        EInval        = opus::OP_EINVAL as isize,
        ENotFormat    = opus::OP_ENOTFORMAT as isize,
        EBadHeader    = opus::OP_EBADHEADER as isize,
        EVersion      = opus::OP_EVERSION as isize,
        ENotAudio     = opus::OP_ENOTAUDIO as isize,
        EBadPacket    = opus::OP_EBADPACKET as isize,
        EBadLink      = opus::OP_EBADLINK as isize,
        ENoSeek       = opus::OP_ENOSEEK as isize,
        EBadTimeStamp = opus::OP_EBADTIMESTAMP as isize,
    }
}

pub type OpusFileResult<T> = Result<T, OpusFileError>;

pub trait ReadSeek: Read + Seek { }
impl <T> ReadSeek for T where T : Read + Seek { }

enum DataSource <'s> {
    Slice (&'s [u8]),
    Read (&'s mut Read),
    ReadSeek (&'s mut ReadSeek),
}

pub struct OggOpusFile <'s>
{
    of    : *mut opus::OggOpusFile,
    _data : DataSource<'s>,
}
impl <'s> OggOpusFile<'s>
{
    pub fn from_slice (data : &[u8]) -> OpusFileResult<OggOpusFile>
    {
        unsafe {
            let mut e: libc::c_int = 0;
            match opus::op_open_memory(data.as_ptr() as *const libc::c_uchar, data.len() as libc::size_t, &mut e as *mut libc::c_int) {
                of if of != ptr::null_mut() => Ok(OggOpusFile { of: of, _data: DataSource::Slice(data), }),
                _ => Err(OpusFileError::from_isize(e as isize).unwrap()),
            }
        }
    }

    pub fn from_read (data : &mut Read) -> OpusFileResult<OggOpusFile>
    {
        unsafe {
            let mut e: libc::c_int = 0;
            match opus::op_open_callbacks(mem::transmute_copy(&data), &CB, ptr::null(), 0, &mut e as *mut libc::c_int) {
                of if of != ptr::null_mut() => Ok(OggOpusFile { of: of, _data: DataSource::Read(data), }),
                _ => Err(OpusFileError::from_isize(e as isize).unwrap()),
            }
        }
    }

    pub fn from_read_seek (data : &mut ReadSeek) -> OpusFileResult<OggOpusFile>
    {
        unsafe {
            let mut e: libc::c_int = 0;
            match opus::op_open_callbacks(mem::transmute_copy(&data), &CB, ptr::null(), 0, &mut e as *mut libc::c_int) {
                of if of != ptr::null_mut() => Ok(OggOpusFile { of: of, _data: DataSource::ReadSeek(data), }),
                _ => Err(OpusFileError::from_isize(e as isize).unwrap()),
            }
        }
    }

    pub fn seekable (&self) -> bool
    {
        unsafe {
            opus::op_seekable(self.of as *const opus::OggOpusFile) != 0
        }
    }

    pub fn link_count (&self) -> i32
    {
        unsafe {
            opus::op_link_count(self.of as *const opus::OggOpusFile) as i32
        }
    }

    pub fn serial_no (&self, li: i32 ) -> u32
    {
        unsafe {
            opus::op_serialno(self.of as *const opus::OggOpusFile, li as libc::c_int) as u32
        }
    }

    pub fn channel_count (&self, li: i32 ) -> i32
    {
        unsafe {
            opus::op_channel_count(self.of as *const opus::OggOpusFile, li as libc::c_int) as i32
        }
    }

    pub fn raw_total (&self, li: i32 ) -> i64
    {
        unsafe {
            opus::op_raw_total(self.of as *const opus::OggOpusFile, li as libc::c_int) as i64
        }
    }

    pub fn pcm_total (&self, li: i32 ) -> i64
    {
        unsafe {
            opus::op_pcm_total(self.of as *const opus::OggOpusFile, li as libc::c_int) as i64
        }
    }

    pub fn head (&self, li: i32) -> Option<OpusHead>
    {
        unsafe {
            match opus::op_head(self.of as *const opus::OggOpusFile, li as libc::c_int) {
                oh if oh != ptr::null() => Some(OpusHead{
                    version:           (*oh).version as i32,
                    channel_count:     (*oh).channel_count as u8,
                    pre_skip:          (*oh).pre_skip as i32,
                    input_sample_rate: (*oh).input_sample_rate as u32,
                    output_gain:       (*oh).output_gain as i32,
                    mapping_family:    (*oh).mapping_family as i32,
                    stream_count:      (*oh).stream_count as u8,
                    coupled_count:     (*oh).coupled_count as u8,
                    mapping:           (*oh).mapping[0 .. (2 * (*oh).coupled_count + ((*oh).stream_count - (*oh).coupled_count)) as usize].to_owned(),
                }),
                _ => None,
            }
        }
    }

    pub fn tags (&self, li: i32) -> Option<OpusTags>
    {
        unsafe {
            match opus::op_tags(self.of as *const opus::OggOpusFile, li as libc::c_int) {
                ot if ot != ptr::null() => Some(OpusTags {
                    user_comments: (0 .. (*ot).comments as usize).map(|ci| {
                        let len = *((*ot).comment_lengths as *const i32).offset(ci as isize) as usize;
                        String::from_utf8_lossy(slice::from_raw_parts(*((*ot).user_comments as *const *const u8).offset(ci as isize), len)).into_owned()
                    }).collect(),
                    vendor: String::from_utf8_lossy(CStr::from_ptr((*ot).vendor as *const i8).to_bytes()).into_owned(),
                }),
                _ => None,
            }
        }
    }

    pub fn current_link (&self) -> i32
    {
        unsafe {
            opus::op_current_link(self.of as *const opus::OggOpusFile) as i32
        }
    }

    pub fn bitrate (&self, li: i32) -> i32
    {
        unsafe {
            opus::op_bitrate(self.of as *const opus::OggOpusFile, li as libc::c_int) as i32
        }
    }

    pub fn bitrate_instant (&self) -> i32
    {
        unsafe {
            opus::op_bitrate_instant(self.of as *const opus::OggOpusFile) as i32
        }
    }

    pub fn raw_tell (&self) -> i64
    {
        unsafe {
            opus::op_raw_tell(self.of as *const opus::OggOpusFile) as i64
        }
    }

    pub fn pcm_tell (&self) -> i64
    {
        unsafe {
            opus::op_pcm_tell(self.of as *const opus::OggOpusFile) as i64
        }
    }

    pub fn raw_seek (&mut self, offset: i64) -> OpusFileResult<()> {
        unsafe {
            match opus::op_raw_seek(self.of, offset) {
                0 => Ok(()),
                e => Err(OpusFileError::from_i32(e as i32).unwrap()),
            }
        }
    }

    pub fn pcm_seek (&mut self, offset: i64) -> OpusFileResult<()> {
        unsafe {
            match opus::op_raw_seek(self.of, offset) {
                0 => Ok(()),
                e => Err(OpusFileError::from_i32(e as i32).unwrap()),
            }
        }
    }

    pub fn read (&mut self, pcm: &mut [i16], li: &mut i32) -> OpusFileResult<i32>
    {
        unsafe {
            match opus::op_read(self.of, pcm.as_mut_ptr(), pcm.len() as libc::c_int, li as *mut i32 as *mut libc::c_int) {
                e if e < 0 => Err(OpusFileError::from_i32(e as i32).unwrap()),
                n          => Ok(n as i32),
            }
        }
    }

    pub fn read_float (&mut self, pcm: &mut [libc::c_float], li: &mut i32) -> OpusFileResult<i32>
    {
        unsafe {
            match opus::op_read_float(self.of, pcm.as_mut_ptr(), pcm.len() as libc::c_int, li as *mut i32 as *mut libc::c_int) {
                e if e < 0 => Err(OpusFileError::from_i32(e as i32).unwrap()),
                n          => Ok(n as i32),
            }
        }
    }

    pub fn read_stereo (&mut self, pcm: &mut [i16]) -> OpusFileResult<i32>
    {
        unsafe {
            match opus::op_read_stereo(self.of, pcm.as_mut_ptr(), pcm.len() as libc::c_int) {
                e if e < 0 => Err(OpusFileError::from_i32(e as i32).unwrap()),
                n          => Ok(n as i32),
            }
        }
    }

    pub fn read_float_stereo (&mut self, pcm: &mut [f32]) -> OpusFileResult<i32>
    {
        unsafe {
            match opus::op_read_float_stereo(self.of, pcm.as_mut_ptr(), pcm.len() as libc::c_int) {
                e if e < 0 => Err(OpusFileError::from_i32(e as i32).unwrap()),
                n          => Ok(n as i32),
            }
        }
    }
}

unsafe extern "C" fn read_cb (src: *mut libc::c_void, buf: *mut libc::c_uchar, size: libc::c_int) -> libc::c_int {
    fn fill_buffer <R> (mut read : R, mut buf : &mut [u8]) -> usize
        where R : Read
    {
        let mut i = 0;
        while i < buf.len() {
            let buf = &mut buf[i ..];
            match read.read(buf) {
                Ok(0) => break,
                Ok(n) => i += n,
                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
                Err(_) => break,
            }
        }

        i
    }

    let buf = slice::from_raw_parts_mut(buf, size as usize);
    match *(src as *mut DataSource) {
        DataSource::Read(ref mut r) => fill_buffer(r, buf) as i32,
        DataSource::ReadSeek(ref mut r) => fill_buffer(r, buf) as i32,
        _ => -1,
    }
}

unsafe extern "C" fn seek_cb (src : *mut libc::c_void, pos: i64, style : libc::c_int) -> libc::c_int {
    let pos = match style {
        libc::SEEK_SET => io::SeekFrom::Start(pos as u64),
        libc::SEEK_CUR => io::SeekFrom::Current(pos),
        libc::SEEK_END => io::SeekFrom::End(pos),
        _ => return -1,
    };

    match *(src as *mut DataSource) {
        DataSource::ReadSeek(ref mut s) => {
            loop {
                match s.seek(pos) {
                    Ok(_) => return 0,
                    Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
                    Err(_) => return -1,
                }
            }
        }
        _ => -1,
    }
}

unsafe extern "C" fn tell_cb (src: *mut libc::c_void) -> i64 {
    match *(src as *mut DataSource) {
        DataSource::ReadSeek(ref mut s) => {
            loop {
                match s.seek(io::SeekFrom::Current(0)) {
                    Ok(pos) => return pos as i64,
                    Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
                    Err(_) => return -1,
                }
            }
        }
        _ => -1,
    }
}

pub struct OpusHead
{
    pub mapping           : Vec<u8>,
    pub version           : i32,
    pub pre_skip          : i32,
    pub input_sample_rate : u32,
    pub output_gain       : i32,
    pub mapping_family    : i32,
    pub channel_count     : u8,
    pub stream_count      : u8,
    pub coupled_count     : u8,
}

pub struct OpusTags
{
    pub user_comments : Vec<String>,
    pub vendor        : String,
}

<|endoftext|>


<commit_before>
#![crate_name="mclient"]

#![feature(globs)]
use std::io::*;
use std::io::net::ip::SocketAddr;
use std::from_str::FromStr;
use std::time::Duration;

pub trait Mclient {
    fn get(&mut self,key:&str) -> Result<String,Error> ;
}

pub struct Client {
    addr : SocketAddr,
    conn : Option<TcpStream>
}

#[deriving(PartialEq, Eq, Clone, Show)]
pub enum ErrorKind {
    InvalidHost,
    InterIoErr(IoError)
}

#[deriving(PartialEq, Eq, Clone, Show)]
pub struct Error {
    desc : &'static str,
    detail: Option<String>,
    kind : ErrorKind
}

pub fn new(host:&str,port:u16) -> Result<Client,Error> {
    let ipo : Option<IpAddr> = FromStr::from_str(host);
    match ipo {
        Some(ip) => {
            Ok(Client{addr:SocketAddr{ip:ip,port:port},conn:None})
        },
        None => {
            Err(Error{
                desc : "invalid host",
                kind : InvalidHost,
                detail : None
            })
        }
    }
}

impl Mclient for Client {
    pub fn get(&mut self,key:&str) -> Result<String,Error> {
        assert!(!key.contains(" "));
        assert!(!key.contains_char('\t'));
        assert!(!key.contains_char('\n'));
        let cmd = String::from_str("get ") + key.into_string() + "\r\n".into_string();
        if self.conn.is_none() {
            match TcpStream::connect_timeout(self.addr,Duration::seconds(1)) {
                Ok(c) => {
                    self.conn = Some(c);
                },
                Err(e) => {
                    return Err(Error{
                        desc : "fail to conn",
                        detail : None,
                        kind : InterIoErr(e)
                    })
                }
            }
        }

        self.conn.unwrap().write_str(cmd.as_slice());
        let mut ret = [0u8,..100];
        match self.conn.unwrap().read(ret) {
            Ok(nread) => {
                println!("{} read",nread);
                let mut s = String::new();
                for &x in ret.iter() {
                    println("{}",x);
                    s += x.to_str_radix(16);
                }
                Ok(s)
            },
            Err(err) => {
                    Err(Error{
                        desc : "fail to read",
                        detail : None,
                        kind : InterIoErr(err)
                    })
            }
        }
    }
}

#[test]
fn test_new_client() {
    let c = new("127.0.0.1",11211u16);
    assert!(c.is_ok());
}
<commit_msg>u8->ascii->vec<char>->string<commit_after>
#![crate_name="mclient"]

#![feature(globs)]
use std::io::*;
use std::io::net::ip::SocketAddr;
use std::from_str::FromStr;
use std::time::Duration;

pub trait Mclient {
    fn get(&mut self,key:&str) -> Result<String,Error> ;
}

pub struct Client {
    addr : SocketAddr,
    conn : Option<TcpStream>
}

#[deriving(PartialEq, Eq, Clone, Show)]
pub enum ErrorKind {
    InvalidHost,
    InterIoErr(IoError)
}

#[deriving(PartialEq, Eq, Clone, Show)]
pub struct Error {
    desc : &'static str,
    detail: Option<String>,
    kind : ErrorKind
}

pub fn new(host:&str,port:u16) -> Result<Client,Error> {
    let ipo : Option<IpAddr> = FromStr::from_str(host);
    match ipo {
        Some(ip) => {
            Ok(Client{addr:SocketAddr{ip:ip,port:port},conn:None})
        },
        None => {
            Err(Error{
                desc : "invalid host",
                kind : InvalidHost,
                detail : None
            })
        }
    }
}

impl Mclient for Client {
    fn get(&mut self,key:&str) -> Result<String,Error> {
        assert!(!key.contains(" "));
        assert!(!key.contains_char('\t'));
        assert!(!key.contains_char('\n'));
        let cmd = String::from_str("get ") + key.into_string() + "\r\n".into_string();
        if self.conn.is_none() {
            match TcpStream::connect_timeout(self.addr,Duration::seconds(1)) {
                Ok(c) => {
                    self.conn = Some(c);
                },
                Err(e) => {
                    return Err(Error{
                        desc : "fail to conn",
                        detail : None,
                        kind : InterIoErr(e)
                    })
                }
            }
        }

        let mut tc = self.conn.take().unwrap();
        tc.write_str(cmd.as_slice());
        let mut ret = [0u8,..100];
        match tc.read(ret) {
            Ok(nread) => {
                println!("{} read",nread);
                let v : Vec<char> = ret.iter().map(|x| x.to_ascii().to_char()).collect();
                Ok(String::from_chars(v.as_slice()))
            },
            Err(err) => {
                    Err(Error{
                        desc : "fail to read",
                        detail : None,
                        kind : InterIoErr(err)
                    })
            }
        }
    }
}

#[test]
fn test_get() {
    let mut c = new("127.0.0.1",11211);
    assert!(c.is_ok());
    match c {
        Ok(mut mc) => { let ret = mc.get("foo");println!("ret {}",ret); }
        Err(e) => { fail!("not ok"); }
    }
}

<|endoftext|>


<commit_before>#![warn(missing_docs)]

//! input-map
//! =========
//!
//! A library for binding input keys to actions, and manipulating mouse input

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward. Needs to be hashable, as it is used as a
/// lookup key when rebinding an action to a different key.
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// A three-element tuple of Option<Button>. For simplicity, a maximum number of 3
/// buttons can be bound to each action, and this is exposed through the `InputRebind`
/// struct.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    /// Creates a new tuple with no buttons in it (equivalent to `Default::default()`).
    pub fn new() -> Self { Default::default() }

    /// Check if the button is in the tuple.
    pub fn contains(&self, button: Button) -> bool {
        let sbtn = Some(button);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    /// Insert a button into the tuple if there is room, searching from left to right.
    /// If the button is inserted, returns true. Otherwise, if the button is not inserted,
    /// this function returns false.
    pub fn insert_inplace(&mut self, button: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(button), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(button), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(button)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    /// Creates a new tuple with no buttons in it.
    fn default() -> Self { ButtonTuple(None, None, None) }
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: HashMap<Button, A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: HashMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.get(&$but_var).map(|x| *x) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

#[derive(Clone)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[allow(missing_docs)]
pub struct InputRebind<A: Action> {
    keymap: HashMap<A, ButtonTuple>,
    mouse_data: MouseTranslationData
}

impl<A: Action> InputRebind<A> {
    #[allow(missing_docs)]
    pub fn new(size: Size) -> Self {
        InputRebind {
            keymap: HashMap::new(),
            mouse_data: MouseTranslationData::new(size)
        }
    }

    #[allow(missing_docs)]
    pub fn insert_action(&mut self, action: A) -> Option<ButtonTuple> {
        self.keymap.insert(action, ButtonTuple::new())
    }

    #[allow(missing_docs)]
    pub fn insert_action_with_buttons(&mut self, action: A, buttons: ButtonTuple) -> Option<ButtonTuple> {
        self.keymap.insert(action, buttons)
    }

    #[allow(missing_docs)]
    pub fn get_bindings(&self, action: &A) -> Option<&ButtonTuple> {
        self.keymap.get(action)
    }

    #[allow(missing_docs)]
    pub fn get_bindings_mut(&mut self, action: &mut A) -> Option<&mut ButtonTuple> {
        self.keymap.get_mut(action)
    }

    #[allow(missing_docs)]
    pub fn get_x_scroll_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_scroll_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_motion_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_motion_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_viewport_size(&self) -> &Size {
        &self.mouse_data.viewport_size
    }

    #[allow(missing_docs)]
    pub fn get_viewport_size_mut(&mut self) -> &mut Size {
        &mut self.mouse_data.viewport_size
    }
}

impl<A: Action> Default for InputRebind<A> {
    #[allow(missing_docs)]
    fn default() -> Self {
        InputRebind::new((800, 600).into())
    }
}

impl<A: Action> Into<InputTranslator<A>> for InputRebind<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputTranslator<A> {
        let mut input_translator = InputTranslator::new(self.mouse_data.viewport_size);
        input_translator.mouse_translator.data = self.mouse_data;
        input_translator.keymap = self.keymap.values()
                                             .flat_map(|&bt| bt.into_iter())
                                             .filter_map(|x| x)
                                             .zip(self.keymap.keys().map(|x| *x))
                                             .collect();

        input_translator
    }
}

impl<A: Action> Into<InputRebind<A>> for InputTranslator<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputRebind<A> {
        let mut input_rebind = InputRebind::new(self.mouse_translator.data.viewport_size);
        input_rebind.mouse_data = self.mouse_translator.data;
        //input_rebind.keymap = self.keymap.btn_map.
        //input_rebind.keymap = self.keymap.btn_map.drain().map(|(k, v)| (v, k)).collect();
        input_rebind
    }
}

impl ButtonTuple {
    fn into_iter(self) -> ButtonTupleIterator {
        ButtonTupleIterator {
            button_tuple: self,
            i: 0
        }
    }
}

struct ButtonTupleIterator {
    button_tuple: ButtonTuple,
    i: usize
}

impl Iterator for ButtonTupleIterator {
    type Item = Option<Button>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        self.i += 1;
        match i {
            0 => Some(self.button_tuple.0),
            1 => Some(self.button_tuple.1),
            2 => Some(self.button_tuple.2),
            _ => None
        }
    }
}

<commit_msg>Mark `Into<InputRebind<A>> for InputTranslator<A>` as unimplemented!()<commit_after>#![warn(missing_docs)]

//! input-map
//! =========
//!
//! A library for binding input keys to actions, and manipulating mouse input

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward. Needs to be hashable, as it is used as a
/// lookup key when rebinding an action to a different key.
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// A three-element tuple of Option<Button>. For simplicity, a maximum number of 3
/// buttons can be bound to each action, and this is exposed through the `InputRebind`
/// struct.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    /// Creates a new tuple with no buttons in it (equivalent to `Default::default()`).
    pub fn new() -> Self { Default::default() }

    /// Check if the button is in the tuple.
    pub fn contains(&self, button: Button) -> bool {
        let sbtn = Some(button);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    /// Insert a button into the tuple if there is room, searching from left to right.
    /// If the button is inserted, returns true. Otherwise, if the button is not inserted,
    /// this function returns false.
    pub fn insert_inplace(&mut self, button: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(button), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(button), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(button)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    /// Creates a new tuple with no buttons in it.
    fn default() -> Self { ButtonTuple(None, None, None) }
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: HashMap<Button, A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: HashMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.get(&$but_var).map(|x| *x) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

#[derive(Clone)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[allow(missing_docs)]
pub struct InputRebind<A: Action> {
    keymap: HashMap<A, ButtonTuple>,
    mouse_data: MouseTranslationData
}

impl<A: Action> InputRebind<A> {
    #[allow(missing_docs)]
    pub fn new(size: Size) -> Self {
        InputRebind {
            keymap: HashMap::new(),
            mouse_data: MouseTranslationData::new(size)
        }
    }

    #[allow(missing_docs)]
    pub fn insert_action(&mut self, action: A) -> Option<ButtonTuple> {
        self.keymap.insert(action, ButtonTuple::new())
    }

    #[allow(missing_docs)]
    pub fn insert_action_with_buttons(&mut self, action: A, buttons: ButtonTuple) -> Option<ButtonTuple> {
        self.keymap.insert(action, buttons)
    }

    #[allow(missing_docs)]
    pub fn get_bindings(&self, action: &A) -> Option<&ButtonTuple> {
        self.keymap.get(action)
    }

    #[allow(missing_docs)]
    pub fn get_bindings_mut(&mut self, action: &mut A) -> Option<&mut ButtonTuple> {
        self.keymap.get_mut(action)
    }

    #[allow(missing_docs)]
    pub fn get_x_scroll_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_scroll_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_motion_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_motion_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_viewport_size(&self) -> &Size {
        &self.mouse_data.viewport_size
    }

    #[allow(missing_docs)]
    pub fn get_viewport_size_mut(&mut self) -> &mut Size {
        &mut self.mouse_data.viewport_size
    }
}

impl<A: Action> Default for InputRebind<A> {
    #[allow(missing_docs)]
    fn default() -> Self {
        InputRebind::new((800, 600).into())
    }
}

impl<A: Action> Into<InputTranslator<A>> for InputRebind<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputTranslator<A> {
        let mut input_translator = InputTranslator::new(self.mouse_data.viewport_size);
        input_translator.mouse_translator.data = self.mouse_data;
        input_translator.keymap = self.keymap.values()
                                             .flat_map(|&bt| bt.into_iter())
                                             .filter_map(|x| x)
                                             .zip(self.keymap.keys().map(|x| *x))
                                             .collect();

        input_translator
    }
}

impl<A: Action> Into<InputRebind<A>> for InputTranslator<A> {
    #[allow(missing_docs, unreachable_code)]
    fn into(self) -> InputRebind<A> {
        unimplemented!();

        let mut input_rebind = InputRebind::new(self.mouse_translator.data.viewport_size);
        input_rebind.mouse_data = self.mouse_translator.data;
        //input_rebind.keymap = self.keymap.btn_map.
        //input_rebind.keymap = self.keymap.btn_map.drain().map(|(k, v)| (v, k)).collect();
        input_rebind
    }
}

impl ButtonTuple {
    fn into_iter(self) -> ButtonTupleIterator {
        ButtonTupleIterator {
            button_tuple: self,
            i: 0
        }
    }
}

struct ButtonTupleIterator {
    button_tuple: ButtonTuple,
    i: usize
}

impl Iterator for ButtonTupleIterator {
    type Item = Option<Button>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        self.i += 1;
        match i {
            0 => Some(self.button_tuple.0),
            1 => Some(self.button_tuple.1),
            2 => Some(self.button_tuple.2),
            _ => None
        }
    }
}

<|endoftext|>


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

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

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

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

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

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

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

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

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

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

    /// Calculate the cardinality of this `Petnames`.
    ///
    /// If this is low, names may be repeated by the generator with a higher
    /// frequency than your use-case may allow. If it is 0 (zero) the generator
    /// will panic (unless `words` is also zero).
    ///
    /// This can saturate. If the total possible combinations of words exceeds
    /// `u128::MAX` then this will return `u128::MAX`.
    #[allow(dead_code)]
    pub fn cardinality(&self, words: u8) -> u128 {
        let mut total: u128 = if words == 0 { 0 } else { 1 };
        for num in (0..words).rev() {
            total = total.saturating_mul(match num {
                0 => self.names.len() as u128,
                1 => self.adjectives.len() as u128,
                _ => self.adverbs.len() as u128,
            });
        }
        total
    }

    /// Generate a new petname.
    ///
    /// # Examples
    ///
    /// ```rust
    /// let mut rng = rand::thread_rng();
    /// petname::Petnames::default().generate(&mut rng, 7, ":");
    /// ```
    ///
    /// # Panics
    ///
    /// If a word list is empty.
    ///
    pub fn generate<RNG>(&self, rng: &mut RNG, words: u8, separator: &str) -> String
    where
        RNG: rand::Rng,
    {
        // Adverbs all the way, finishing with adjective then name.
        let mut parts = Vec::with_capacity(words as usize);
        for num in (0..words).rev() {
            parts.push(*match num {
                0 => self.names.choose(rng).unwrap(),
                1 => self.adjectives.choose(rng).unwrap(),
                _ => self.adverbs.choose(rng).unwrap(),
            });
        }
        parts.join(separator)
    }

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

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

#[cfg(test)]
mod tests {

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

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

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

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

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

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

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

    #[test]
    fn petname_renders_with_desired_separator() {
        assert_eq!(petname(7, "@").split("@").count(), 7);
    }
}
<commit_msg>Petnames::cardinality isn't dead code.<commit_after>use rand::seq::SliceRandom;

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

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

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

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

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

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

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

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

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

    /// Calculate the cardinality of this `Petnames`.
    ///
    /// If this is low, names may be repeated by the generator with a higher
    /// frequency than your use-case may allow. If it is 0 (zero) the generator
    /// will panic (unless `words` is also zero).
    ///
    /// This can saturate. If the total possible combinations of words exceeds
    /// `u128::MAX` then this will return `u128::MAX`.
    pub fn cardinality(&self, words: u8) -> u128 {
        let mut total: u128 = if words == 0 { 0 } else { 1 };
        for num in (0..words).rev() {
            total = total.saturating_mul(match num {
                0 => self.names.len() as u128,
                1 => self.adjectives.len() as u128,
                _ => self.adverbs.len() as u128,
            });
        }
        total
    }

    /// Generate a new petname.
    ///
    /// # Examples
    ///
    /// ```rust
    /// let mut rng = rand::thread_rng();
    /// petname::Petnames::default().generate(&mut rng, 7, ":");
    /// ```
    ///
    /// # Panics
    ///
    /// If a word list is empty.
    ///
    pub fn generate<RNG>(&self, rng: &mut RNG, words: u8, separator: &str) -> String
    where
        RNG: rand::Rng,
    {
        // Adverbs all the way, finishing with adjective then name.
        let mut parts = Vec::with_capacity(words as usize);
        for num in (0..words).rev() {
            parts.push(*match num {
                0 => self.names.choose(rng).unwrap(),
                1 => self.adjectives.choose(rng).unwrap(),
                _ => self.adverbs.choose(rng).unwrap(),
            });
        }
        parts.join(separator)
    }

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

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

#[cfg(test)]
mod tests {

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

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

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

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

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

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

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

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


<commit_before>//! redis-rs is a rust implementation of a Redis client library.  It exposes
//! a general purpose interface to Redis and also provides specific helpers for
//! commonly used functionality.
//!
//! The crate is called `redis` and you can depend on it via cargo:
//!
//! ```ini
//! [dependencies.redis]
//! version = "*"
//! ```
//!
//! If you want to use the git version:
//!
//! ```ini
//! [dependencies.redis]
//! git = "https://github.com/mitsuhiko/redis-rs.git"
//! ```
//!
//! # Basic Operation
//!
//! redis-rs exposes to API levels: a low- and a high-level part.  The high-level
//! part does not expose all the functionality of redis and might take some
//! liberties in how it speaks the protocol.  The low-level part of the API
//! allows you to express any request on the redis level.  You can fluently
//! switch between both API levels at any point.
//!
//! ## Connection Handling
//!
//! For connecting to redis you can use a client object which then can produce
//! actual connections.  Connections and clients as well as results of
//! connections and clients are considered `ConnectionLike` objects and
//! can be used anywhere a request is made.
//!
//! The full canonical way to get a connection is to create a client and
//! to ask for a connection from it:
//!
//! ```rust,no_run
//! extern crate redis;
//!
//! fn do_something() -> redis::RedisResult<()> {
//!     let client = try!(redis::Client::open("redis://127.0.0.1/"));
//!     let con = try!(client.get_connection());
//!
//!     /* do something here */
//!
//!     Ok(())
//! }
//! # fn main() {}
//! ```
//!
//! ## Optional Features
//!
//! There are currently two features defined that can enable additional
//! functionality if so desired.
//!
//! `with-unix-sockets`:
//!   By default this library does not support unix sockets on older versions
//!   of Rust but you can optionally compile it with unix sockets enabled by
//!   enabling the `with-unix-sockets` feature flag.  On rust 1.10 or later
//!   this is not needed.
//!
//! `with-rustc-json`:
//!   This feature flag enables the `rustc_serialize` JSON support.
//!
//! ## Connection Parameters
//!
//! redis-rs knows different ways to define where a connection should
//! go.  The parameter to `Client::open` needs to implement the
//! `IntoConnectionInfo` trait of which there are three implementations:
//!
//! * string slices in `redis://` URL format.
//! * URL objects from the redis-url crate.
//! * `ConnectionInfo` objects.
//!
//! The URL format is `redis://[:<passwd>@]<hostname>[:port][/<db>]`
//!
//! In case the create is compiled with Unix socket support you can also
//! use a unix URL in this format:
//!
//! `redis+unix:///[:<passwd>@]<path>[?db=<db>]`
//!
//! For compatibility with some other redis libraries, the "unix" scheme
//! is also supported:
//!
//! `unix:///[:<passwd>@]<path>[?db=<db>]`
//!
//! ## Executing Low-Level Commands
//!
//! To execute low-level commands you can use the `cmd` function which allows
//! you to build redis requests.  Once you have configured a command object
//! to your liking you can send a query into any `ConnectionLike` object:
//!
//! ```rust,no_run
//! fn do_something(con: &redis::Connection) -> redis::RedisResult<()> {
//!     let _ : () = try!(redis::cmd("SET").arg("my_key").arg(42).query(con));
//!     Ok(())
//! }
//! ```
//!
//! Upon querying the return value is a result object.  If you do not care
//! about the actual return value (other than that it is not a failure)
//! you can always type annotate it to the unit type `()`.
//!
//! ## Executing High-Level Commands
//!
//! The high-level interface is similar.  For it to become available you
//! need to use the `Commands` trait in which case all `ConnectionLike`
//! objects the library provides will also have high-level methods which
//! make working with the protocol easier:
//!
//! ```rust,no_run
//! extern crate redis;
//! use redis::Commands;
//!
//! fn do_something(con: &redis::Connection) -> redis::RedisResult<()> {
//!     let _ : () = try!(con.set("my_key", 42));
//!     Ok(())
//! }
//! # fn main() {}
//! ```
//!
//! Note that high-level commands are work in progress and many are still
//! missing!
//!
//! ## Type Conversions
//!
//! Because redis inherently is mostly type-less and the protocol is not
//! exactly friendly to developers, this library provides flexible support
//! for casting values to the intended results.  This is driven through the
//! `FromRedisValue` and `ToRedisArgs` traits.
//!
//! The `arg` method of the command will accept a wide range of types through
//! the `ToRedisArgs` trait and the `query` method of a command can convert the
//! value to what you expect the function to return through the `FromRedisValue`
//! trait.  This is quite flexible and allows vectors, tuples, hashsets, hashmaps
//! as well as optional values:
//!
//! ```rust,no_run
//! # use redis::Commands;
//! # use std::collections::{HashMap, HashSet};
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let count : i32 = try!(con.get("my_counter"));
//! let count = con.get("my_counter").unwrap_or(0i32);
//! let k : Option<String> = try!(con.get("missing_key"));
//! let name : String = try!(con.get("my_name"));
//! let bin : Vec<u8> = try!(con.get("my_binary"));
//! let map : HashMap<String, i32> = try!(con.hgetall("my_hash"));
//! let keys : Vec<String> = try!(con.hkeys("my_hash"));
//! let mems : HashSet<i32> = try!(con.smembers("my_set"));
//! let (k1, k2) : (String, String) = try!(con.get(&["k1", "k2"]));
//! # Ok(())
//! # }
//! ```
//!
//! # Iteration Protocol
//!
//! In addition to sending a single query you iterators are also supported.  When
//! used with regular bulk responses they don't give you much over querying and
//! converting into a vector (both use a vector internally) but they can also
//! be used with `SCAN` like commands in which case iteration will send more
//! queries until the cursor is exhausted:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let mut iter : redis::Iter<isize> = try!(redis::cmd("SSCAN").arg("my_set")
//!     .cursor_arg(0).iter(&con));
//! for x in iter {
//!     // do something with the item
//! }
//! # Ok(()) }
//! ```
//!
//! As you can see the cursor argument needs to be defined with `cursor_arg`
//! instead of `arg` so that the library knows which argument needs updating
//! as the query is run for more items.
//!
//! # Pipelining
//!
//! In addition to simple queries you can also send command pipelines.  This
//! is provided through the `pipe` function.  It works very similar to sending
//! individual commands but you can send more than one in one go.  This also
//! allows you to ignore individual results so that matching on the end result
//! is easier:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = try!(redis::pipe()
//!     .cmd("SET").arg("key_1").arg(42).ignore()
//!     .cmd("SET").arg("key_2").arg(43).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con));
//! # Ok(()) }
//! ```
//!
//! If you want the pipeline to be wrapped in a `MULTI`/`EXEC` block you can
//! easily do that by switching the pipeline into `atomic` mode.  From the
//! caller's point of view nothing changes, the pipeline itself will take
//! care of the rest for you:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = try!(redis::pipe()
//!     .atomic()
//!     .cmd("SET").arg("key_1").arg(42).ignore()
//!     .cmd("SET").arg("key_2").arg(43).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con));
//! # Ok(()) }
//! ```
//!
//! You can also use high-level commands on pipelines through the
//! `PipelineCommands` trait:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! use redis::PipelineCommands;
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = try!(redis::pipe()
//!     .atomic()
//!     .set("key_1", 42).ignore()
//!     .set("key_2", 43).ignore()
//!     .get("key_1")
//!     .get("key_2").query(&con));
//! # Ok(()) }
//! ```
//!
//! # Transactions
//!
//! Transactions are available through atomic pipelines.  In order to use
//! them in a more simple way you can use the `transaction` function of a
//! connection:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! use redis::{Commands, PipelineCommands};
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let key = "the_key";
//! let (new_val,) : (isize,) = try!(redis::transaction(&con, &[key], |pipe| {
//!     let old_val : isize = try!(con.get(key));
//!     pipe
//!         .set(key, old_val + 1).ignore()
//!         .get(key).query(&con)
//! }));
//! println!("The incremented number is: {}", new_val);
//! # Ok(()) }
//! ```
//!
//! For more information see the `transaction` function.
//!
//! # PubSub
//!
//! Pubsub is currently work in progress but provided through the `PubSub`
//! connection object.  Due to the fact that Rust does not have support
//! for async IO in libnative yet, the API does not provide a way to
//! read messages with any form of timeout yet.
//!
//! Example usage:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! let client = try!(redis::Client::open("redis://127.0.0.1/"));
//! let mut pubsub = try!(client.get_pubsub());
//! try!(pubsub.subscribe("channel_1"));
//! try!(pubsub.subscribe("channel_2"));
//!
//! loop {
//!     let msg = try!(pubsub.get_message());
//!     let payload : String = try!(msg.get_payload());
//!     println!("channel '{}': {}", msg.get_channel_name(), payload);
//! }
//! # }
//! ```
//!
//! # Scripts
//!
//! Lua scripts are supported through the `Script` type in a convenient
//! way (it does not support pipelining currently).  It will automatically
//! load the script if it does not exist and invoke it.
//!
//! Example:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let script = redis::Script::new(r"
//!     return tonumber(ARGV[1]) + tonumber(ARGV[2]);
//! ");
//! let result : isize = try!(script.arg(1).arg(2).invoke(&con));
//! assert_eq!(result, 3);
//! # Ok(()) }
//! ```
//!
//! ## Breaking Changes
//!
//! In Rust 0.5.0 the semi-internal `ConnectionInfo` struct had to be
//! changed because of the unix socket support.  You are generally
//! heavily encouraged to use the URL based configuration format which
//! is a lot more stable than the structs.

#![deny(non_camel_case_types)]

extern crate url;
extern crate sha1;

#[cfg(feature="with-rustc-json")]
pub extern crate rustc_serialize as serialize;
#[cfg(feature="with-unix-sockets")]
extern crate unix_socket;

#[doc(hidden)]
#[cfg(feature="with-rustc-json")]
pub use serialize::json::Json;

// public api
pub use parser::{parse_redis_value, Parser};
pub use client::Client;
pub use script::{Script, ScriptInvocation};
pub use connection::{Connection, ConnectionLike, ConnectionInfo, ConnectionAddr,
                     IntoConnectionInfo, PubSub, Msg, transaction, parse_redis_url};
pub use cmd::{cmd, Cmd, pipe, Pipeline, Iter, pack_command};
pub use commands::{Commands, PipelineCommands};

#[doc(hidden)]
pub use types::{/* low level values */ Value, /* error and result types */ RedisError,
                RedisResult, /* error kinds */ ErrorKind, /* utility types */ InfoDict,
                NumericBehavior, /* conversion traits */ FromRedisValue, ToRedisArgs,
                /* utility functions */ from_redis_value};

mod macros;

mod parser;
mod client;
mod connection;
mod types;
mod script;
mod cmd;
mod commands;
<commit_msg>Revert rustfmt-ing<commit_after>//! redis-rs is a rust implementation of a Redis client library.  It exposes
//! a general purpose interface to Redis and also provides specific helpers for
//! commonly used functionality.
//!
//! The crate is called `redis` and you can depend on it via cargo:
//!
//! ```ini
//! [dependencies.redis]
//! version = "*"
//! ```
//!
//! If you want to use the git version:
//!
//! ```ini
//! [dependencies.redis]
//! git = "https://github.com/mitsuhiko/redis-rs.git"
//! ```
//!
//! # Basic Operation
//!
//! redis-rs exposes to API levels: a low- and a high-level part.  The high-level
//! part does not expose all the functionality of redis and might take some
//! liberties in how it speaks the protocol.  The low-level part of the API
//! allows you to express any request on the redis level.  You can fluently
//! switch between both API levels at any point.
//!
//! ## Connection Handling
//!
//! For connecting to redis you can use a client object which then can produce
//! actual connections.  Connections and clients as well as results of
//! connections and clients are considered `ConnectionLike` objects and
//! can be used anywhere a request is made.
//!
//! The full canonical way to get a connection is to create a client and
//! to ask for a connection from it:
//!
//! ```rust,no_run
//! extern crate redis;
//!
//! fn do_something() -> redis::RedisResult<()> {
//!     let client = try!(redis::Client::open("redis://127.0.0.1/"));
//!     let con = try!(client.get_connection());
//!
//!     /* do something here */
//!
//!     Ok(())
//! }
//! # fn main() {}
//! ```
//!
//! ## Optional Features
//!
//! There are currently two features defined that can enable additional
//! functionality if so desired.
//!
//! `with-unix-sockets`:
//!   By default this library does not support unix sockets on older versions
//!   of Rust but you can optionally compile it with unix sockets enabled by
//!   enabling the `with-unix-sockets` feature flag.  On rust 1.10 or later
//!   this is not needed.
//!
//! `with-rustc-json`:
//!   This feature flag enables the `rustc_serialize` JSON support.
//!
//! ## Connection Parameters
//!
//! redis-rs knows different ways to define where a connection should
//! go.  The parameter to `Client::open` needs to implement the
//! `IntoConnectionInfo` trait of which there are three implementations:
//!
//! * string slices in `redis://` URL format.
//! * URL objects from the redis-url crate.
//! * `ConnectionInfo` objects.
//!
//! The URL format is `redis://[:<passwd>@]<hostname>[:port][/<db>]`
//!
//! In case the create is compiled with Unix socket support you can also
//! use a unix URL in this format:
//!
//! `redis+unix:///[:<passwd>@]<path>[?db=<db>]`
//!
//! For compatibility with some other redis libraries, the "unix" scheme
//! is also supported:
//!
//! `unix:///[:<passwd>@]<path>[?db=<db>]`
//!
//! ## Executing Low-Level Commands
//!
//! To execute low-level commands you can use the `cmd` function which allows
//! you to build redis requests.  Once you have configured a command object
//! to your liking you can send a query into any `ConnectionLike` object:
//!
//! ```rust,no_run
//! fn do_something(con: &redis::Connection) -> redis::RedisResult<()> {
//!     let _ : () = try!(redis::cmd("SET").arg("my_key").arg(42).query(con));
//!     Ok(())
//! }
//! ```
//!
//! Upon querying the return value is a result object.  If you do not care
//! about the actual return value (other than that it is not a failure)
//! you can always type annotate it to the unit type `()`.
//!
//! ## Executing High-Level Commands
//!
//! The high-level interface is similar.  For it to become available you
//! need to use the `Commands` trait in which case all `ConnectionLike`
//! objects the library provides will also have high-level methods which
//! make working with the protocol easier:
//!
//! ```rust,no_run
//! extern crate redis;
//! use redis::Commands;
//!
//! fn do_something(con: &redis::Connection) -> redis::RedisResult<()> {
//!     let _ : () = try!(con.set("my_key", 42));
//!     Ok(())
//! }
//! # fn main() {}
//! ```
//!
//! Note that high-level commands are work in progress and many are still
//! missing!
//!
//! ## Type Conversions
//!
//! Because redis inherently is mostly type-less and the protocol is not
//! exactly friendly to developers, this library provides flexible support
//! for casting values to the intended results.  This is driven through the
//! `FromRedisValue` and `ToRedisArgs` traits.
//!
//! The `arg` method of the command will accept a wide range of types through
//! the `ToRedisArgs` trait and the `query` method of a command can convert the
//! value to what you expect the function to return through the `FromRedisValue`
//! trait.  This is quite flexible and allows vectors, tuples, hashsets, hashmaps
//! as well as optional values:
//!
//! ```rust,no_run
//! # use redis::Commands;
//! # use std::collections::{HashMap, HashSet};
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let count : i32 = try!(con.get("my_counter"));
//! let count = con.get("my_counter").unwrap_or(0i32);
//! let k : Option<String> = try!(con.get("missing_key"));
//! let name : String = try!(con.get("my_name"));
//! let bin : Vec<u8> = try!(con.get("my_binary"));
//! let map : HashMap<String, i32> = try!(con.hgetall("my_hash"));
//! let keys : Vec<String> = try!(con.hkeys("my_hash"));
//! let mems : HashSet<i32> = try!(con.smembers("my_set"));
//! let (k1, k2) : (String, String) = try!(con.get(&["k1", "k2"]));
//! # Ok(())
//! # }
//! ```
//!
//! # Iteration Protocol
//!
//! In addition to sending a single query you iterators are also supported.  When
//! used with regular bulk responses they don't give you much over querying and
//! converting into a vector (both use a vector internally) but they can also
//! be used with `SCAN` like commands in which case iteration will send more
//! queries until the cursor is exhausted:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let mut iter : redis::Iter<isize> = try!(redis::cmd("SSCAN").arg("my_set")
//!     .cursor_arg(0).iter(&con));
//! for x in iter {
//!     // do something with the item
//! }
//! # Ok(()) }
//! ```
//!
//! As you can see the cursor argument needs to be defined with `cursor_arg`
//! instead of `arg` so that the library knows which argument needs updating
//! as the query is run for more items.
//!
//! # Pipelining
//!
//! In addition to simple queries you can also send command pipelines.  This
//! is provided through the `pipe` function.  It works very similar to sending
//! individual commands but you can send more than one in one go.  This also
//! allows you to ignore individual results so that matching on the end result
//! is easier:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = try!(redis::pipe()
//!     .cmd("SET").arg("key_1").arg(42).ignore()
//!     .cmd("SET").arg("key_2").arg(43).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con));
//! # Ok(()) }
//! ```
//!
//! If you want the pipeline to be wrapped in a `MULTI`/`EXEC` block you can
//! easily do that by switching the pipeline into `atomic` mode.  From the
//! caller's point of view nothing changes, the pipeline itself will take
//! care of the rest for you:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = try!(redis::pipe()
//!     .atomic()
//!     .cmd("SET").arg("key_1").arg(42).ignore()
//!     .cmd("SET").arg("key_2").arg(43).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con));
//! # Ok(()) }
//! ```
//!
//! You can also use high-level commands on pipelines through the
//! `PipelineCommands` trait:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! use redis::PipelineCommands;
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = try!(redis::pipe()
//!     .atomic()
//!     .set("key_1", 42).ignore()
//!     .set("key_2", 43).ignore()
//!     .get("key_1")
//!     .get("key_2").query(&con));
//! # Ok(()) }
//! ```
//!
//! # Transactions
//!
//! Transactions are available through atomic pipelines.  In order to use
//! them in a more simple way you can use the `transaction` function of a
//! connection:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! use redis::{Commands, PipelineCommands};
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let key = "the_key";
//! let (new_val,) : (isize,) = try!(redis::transaction(&con, &[key], |pipe| {
//!     let old_val : isize = try!(con.get(key));
//!     pipe
//!         .set(key, old_val + 1).ignore()
//!         .get(key).query(&con)
//! }));
//! println!("The incremented number is: {}", new_val);
//! # Ok(()) }
//! ```
//!
//! For more information see the `transaction` function.
//!
//! # PubSub
//!
//! Pubsub is currently work in progress but provided through the `PubSub`
//! connection object.  Due to the fact that Rust does not have support
//! for async IO in libnative yet, the API does not provide a way to
//! read messages with any form of timeout yet.
//!
//! Example usage:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! let client = try!(redis::Client::open("redis://127.0.0.1/"));
//! let mut pubsub = try!(client.get_pubsub());
//! try!(pubsub.subscribe("channel_1"));
//! try!(pubsub.subscribe("channel_2"));
//!
//! loop {
//!     let msg = try!(pubsub.get_message());
//!     let payload : String = try!(msg.get_payload());
//!     println!("channel '{}': {}", msg.get_channel_name(), payload);
//! }
//! # }
//! ```
//!
//! # Scripts
//!
//! Lua scripts are supported through the `Script` type in a convenient
//! way (it does not support pipelining currently).  It will automatically
//! load the script if it does not exist and invoke it.
//!
//! Example:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let script = redis::Script::new(r"
//!     return tonumber(ARGV[1]) + tonumber(ARGV[2]);
//! ");
//! let result : isize = try!(script.arg(1).arg(2).invoke(&con));
//! assert_eq!(result, 3);
//! # Ok(()) }
//! ```
//!
//! ## Breaking Changes
//!
//! In Rust 0.5.0 the semi-internal `ConnectionInfo` struct had to be
//! changed because of the unix socket support.  You are generally
//! heavily encouraged to use the URL based configuration format which
//! is a lot more stable than the structs.

#![deny(non_camel_case_types)]

extern crate url;
extern crate sha1;

#[cfg(feature="with-rustc-json")]
pub extern crate rustc_serialize as serialize;
#[cfg(feature="with-unix-sockets")]
extern crate unix_socket;

#[doc(hidden)]
#[cfg(feature="with-rustc-json")]
pub use serialize::json::Json;

// public api
pub use parser::{parse_redis_value, Parser};
pub use client::Client;
pub use script::{Script, ScriptInvocation};
pub use connection::{Connection, ConnectionLike, ConnectionInfo, ConnectionAddr,
                     IntoConnectionInfo, PubSub, Msg, transaction, parse_redis_url};
pub use cmd::{cmd, Cmd, pipe, Pipeline, Iter, pack_command};
pub use commands::{Commands, PipelineCommands};

#[doc(hidden)]
pub use types::{
    /* low level values */
    Value,

    /* error and result types */
    RedisError,
    RedisResult,

    /* error kinds */
    ErrorKind,

    /* utility types */
    InfoDict,
    NumericBehavior,

    /* conversion traits */
    FromRedisValue,
    ToRedisArgs,

    /* utility functions */
    from_redis_value,
};

mod macros;

mod parser;
mod client;
mod connection;
mod types;
mod script;
mod cmd;
mod commands;
<|endoftext|>


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

//! A set of [cryptographic hash
//! functions](https://en.wikipedia.org/wiki/Cryptographic_hash_function) provided by the operating
//! system, when available.
//!
//! The purpose of this crate is to provide access to hash algorithms with as few dependencies as
//! possible. This means that when possible, the library uses the hashing functions that are
//! provided by the given operating system's bundled cryptographic libraries.
//!
//! # Supported Implementations
//!
//! By operating system:
//!
//! * Windows: `CryptoAPI`
//! * Mac OS X: `CommonCrypto`
//! * Linux/BSD/etc.: `OpenSSL`
//!
//! # Supported Algorithms
//!
//! * MD5
//! * SHA1
//! * SHA256
//! * SHA512

#![warn(missing_docs)]

#[cfg(any(target_os = "macos", target_os = "ios"))]
extern crate commoncrypto;
extern crate hex;
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
extern crate openssl;
#[cfg(target_os = "windows")]
extern crate winapi;

use std::io::Write;

#[cfg(any(target_os = "macos", target_os = "ios"))]
#[path = "imp/commoncrypto.rs"]
mod imp;
#[cfg(target_os = "windows")]
#[path = "imp/cryptoapi.rs"]
mod imp;
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
#[path = "imp/openssl.rs"]
mod imp;

mod test;

pub use imp::Hasher;

/// Available cryptographic hash functions.
#[derive(Clone, Debug)]
pub enum Algorithm {
    /// Popular message digest algorithm, only available for backwards compatibility purposes.
    MD5,
    /// SHA-1 algorithm from NIST FIPS, only available for backwards compatibility purposes.
    SHA1,
    /// SHA-2 family algorithm (256 bits).
    SHA256,
    /// SHA-2 family algorithm (512 bits).
    SHA512,
}

/// Helper function for `Hasher` which generates a cryptographic digest from the given
/// data and algorithm.
///
/// # Examples
///
/// ```rust
/// use crypto_hash::{Algorithm, digest};
///
/// let data = b"crypto-hash";
/// let result = digest(Algorithm::SHA256, data);
/// let expected =
///     b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'"
///     .to_vec();
/// assert_eq!(expected, result)
/// ```
pub fn digest(algorithm: Algorithm, data: &[u8]) -> Vec<u8> {
    let mut hasher = imp::Hasher::new(algorithm);
    hasher.write_all(data).expect("Could not write hash data");
    hasher.finish()
}

/// Helper function for `Hasher` which generates a cryptographic digest serialized in
/// hexadecimal from the given data and algorithm.
///
/// # Examples
///
/// ```rust
/// use crypto_hash::{Algorithm, hex_digest};
///
/// let data = b"crypto-hash";
/// let result = hex_digest(Algorithm::SHA256, data);
/// let expected = "fd1afb6022cd4d47c890961c533928eacfe8219f1b2524f7fb2a61847ddf8c27";
/// assert_eq!(expected, result)
/// ```
pub fn hex_digest(algorithm: Algorithm, data: &[u8]) -> String {
    hex::encode(digest(algorithm, data))
}
<commit_msg>feat: add missing derives for Algorithm (#11)<commit_after>// Copyright (c) 2015, 2016, 2017 Mark Lee
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! A set of [cryptographic hash
//! functions](https://en.wikipedia.org/wiki/Cryptographic_hash_function) provided by the operating
//! system, when available.
//!
//! The purpose of this crate is to provide access to hash algorithms with as few dependencies as
//! possible. This means that when possible, the library uses the hashing functions that are
//! provided by the given operating system's bundled cryptographic libraries.
//!
//! # Supported Implementations
//!
//! By operating system:
//!
//! * Windows: `CryptoAPI`
//! * Mac OS X: `CommonCrypto`
//! * Linux/BSD/etc.: `OpenSSL`
//!
//! # Supported Algorithms
//!
//! * MD5
//! * SHA1
//! * SHA256
//! * SHA512

#![warn(missing_docs)]

#[cfg(any(target_os = "macos", target_os = "ios"))]
extern crate commoncrypto;
extern crate hex;
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
extern crate openssl;
#[cfg(target_os = "windows")]
extern crate winapi;

use std::io::Write;

#[cfg(any(target_os = "macos", target_os = "ios"))]
#[path = "imp/commoncrypto.rs"]
mod imp;
#[cfg(target_os = "windows")]
#[path = "imp/cryptoapi.rs"]
mod imp;
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
#[path = "imp/openssl.rs"]
mod imp;

mod test;

pub use imp::Hasher;

/// Available cryptographic hash functions.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Algorithm {
    /// Popular message digest algorithm, only available for backwards compatibility purposes.
    MD5,
    /// SHA-1 algorithm from NIST FIPS, only available for backwards compatibility purposes.
    SHA1,
    /// SHA-2 family algorithm (256 bits).
    SHA256,
    /// SHA-2 family algorithm (512 bits).
    SHA512,
}

/// Helper function for `Hasher` which generates a cryptographic digest from the given
/// data and algorithm.
///
/// # Examples
///
/// ```rust
/// use crypto_hash::{Algorithm, digest};
///
/// let data = b"crypto-hash";
/// let result = digest(Algorithm::SHA256, data);
/// let expected =
///     b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'"
///     .to_vec();
/// assert_eq!(expected, result)
/// ```
pub fn digest(algorithm: Algorithm, data: &[u8]) -> Vec<u8> {
    let mut hasher = imp::Hasher::new(algorithm);
    hasher.write_all(data).expect("Could not write hash data");
    hasher.finish()
}

/// Helper function for `Hasher` which generates a cryptographic digest serialized in
/// hexadecimal from the given data and algorithm.
///
/// # Examples
///
/// ```rust
/// use crypto_hash::{Algorithm, hex_digest};
///
/// let data = b"crypto-hash";
/// let result = hex_digest(Algorithm::SHA256, data);
/// let expected = "fd1afb6022cd4d47c890961c533928eacfe8219f1b2524f7fb2a61847ddf8c27";
/// assert_eq!(expected, result)
/// ```
pub fn hex_digest(algorithm: Algorithm, data: &[u8]) -> String {
    hex::encode(digest(algorithm, data))
}
<|endoftext|>