<commit_before>extern crate toml;
extern crate reqwest;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate glob;
extern crate nix;

#[macro_use]
extern crate lazy_static;

use std::io::{Write, BufRead};
use std::ffi::CStr;
extern crate libc;

mod structs;
use structs::Config;
mod ghclient;
use ghclient::GithubClient;
mod buffer;
use buffer::Buffer;
mod cstructs;
use cstructs::{Passwd, Spwd, Group};
mod runfiles;
mod statics;
use statics::CONF_PATH;

lazy_static! {
    pub static ref CONFIG:Config = Config::new(&CONF_PATH).unwrap();
    pub static ref CLIENT:GithubClient = GithubClient::new(&CONFIG).unwrap();
}

#[allow(dead_code)]
enum NssStatus {
    TryAgain,
    Unavail,
    NotFound,
    Success,
}

impl From<NssStatus> for libc::c_int {
    fn from(status: NssStatus) -> libc::c_int {
        match status {
            NssStatus::TryAgain => -2,
            NssStatus::Unavail => -1,
            NssStatus::NotFound => 0,
            NssStatus::Success => 1,
        }
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getpwnam_r(cnameptr: *const libc::c_char,
                                         pw: *mut Passwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         _: *mut libc::c_int)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let cname: &CStr = unsafe { CStr::from_ptr(cnameptr) };
    let name = String::from(cname.to_str().unwrap());
    let (_, members) = CLIENT.get_team_members().unwrap();
    match members.get(&name) {
        Some(member) => {
            match unsafe { (*pw).pack_args(&mut buffer, &member.login, member.id, &CONFIG) } {
                Ok(_) => libc::c_int::from(NssStatus::Success),
                Err(_) => nix::Errno::ERANGE as libc::c_int,
            }
        }
        None => libc::c_int::from(NssStatus::NotFound),
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getpwuid_r(uid: libc::uid_t,
                                         pw: *mut Passwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         _: *mut libc::c_int)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let (_, members) = CLIENT.get_team_members().unwrap();
    for member in members.values() {
        if uid == member.id as libc::uid_t {
            match unsafe { (*pw).pack_args(&mut buffer, &member.login, member.id, &CONFIG) } {
                Ok(_) => return libc::c_int::from(NssStatus::Success),
                Err(_) => return nix::Errno::ERANGE as libc::c_int,
            }
        }
    }
    libc::c_int::from(NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_setpwent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let members = match CLIENT.get_team_members() {
        Ok((_, members)) => members,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    for member in members.values() {
        list_file.write(format!("{}\t{}\n", member.login, member.id).as_bytes())
                 .unwrap();
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getpwent_r(pwbuf: *mut Passwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         pwbufp: *mut *mut Passwd)
                                         -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Unavail),
    };
    for (i, line) in list.lines().enumerate() {
        if i != idx {
            continue;
        }
        if let Ok(l) = line {
            let mut buffer = Buffer::new(buf, buflen);
            let words: Vec<&str> = l.split("\t").collect();
            let id = words[1].parse::<u64>().unwrap();
            match unsafe { (*pwbuf).pack_args(&mut buffer, words[0], id, &CONFIG) } {
                Ok(_) => {
                    runfiles::increment(idx, idx_file);
                    unsafe { *pwbufp = pwbuf };
                    return libc::c_int::from(NssStatus::Success);
                }
                Err(_) => {
                    unsafe { *pwbufp = std::ptr::null_mut() };
                    return nix::Errno::ERANGE as libc::c_int;
                }
            }
        }
    }
    libc::c_int::from(NssStatus::Unavail)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_endpwent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getspnam_r(cnameptr: *const libc::c_char,
                                         spwd: *mut Spwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         _: *mut libc::c_int)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let cname: &CStr = unsafe { CStr::from_ptr(cnameptr) };
    let name = String::from(cname.to_str().unwrap());
    let (_, members) = CLIENT.get_team_members().unwrap();
    match members.get(&name) {
        Some(member) => {
            match unsafe { (*spwd).pack_args(&mut buffer, &member.login) } {
                Ok(_) => libc::c_int::from(NssStatus::Success),
                Err(_) => nix::Errno::ERANGE as libc::c_int,
            }
        }
        None => libc::c_int::from(NssStatus::NotFound),
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_setspent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let members = match CLIENT.get_team_members() {
        Ok((_, members)) => members,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    for member in members.values() {
        list_file.write(format!("{}\t{}\n", member.login, member.id).as_bytes())
                 .unwrap();
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getspent_r(spbuf: *mut Spwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         spbufp: *mut *mut Spwd)
                                         -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Unavail),
    };
    for (i, line) in list.lines().enumerate() {
        if i != idx {
            continue;
        }
        if let Ok(l) = line {
            let mut buffer = Buffer::new(buf, buflen);
            let words: Vec<&str> = l.split("\t").collect();
            match unsafe { (*spbuf).pack_args(&mut buffer, words[0]) } {
                Ok(_) => {
                    runfiles::increment(idx, idx_file);
                    unsafe { *spbufp = spbuf };
                    return libc::c_int::from(NssStatus::Success);
                }
                Err(_) => {
                    unsafe { *spbufp = std::ptr::null_mut() };
                    return nix::Errno::ERANGE as libc::c_int;
                }
            }
        }
    }
    libc::c_int::from(NssStatus::Unavail)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_endspent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getgrgid_r(gid: libc::gid_t,
                                         group: *mut Group,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         _: *mut libc::c_int)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let (team, members) = CLIENT.get_team_members().unwrap();
    let members: Vec<&str> = members.values().map(|m| m.login.as_str()).collect();
    if gid as u64 == team.id {
        match unsafe { (*group).pack_args(&mut buffer, &team.name, gid as u64, &members) } {
            Ok(_) => libc::c_int::from(NssStatus::Success),
            Err(_) => nix::Errno::ERANGE as libc::c_int,
        }
    } else {
        libc::c_int::from(NssStatus::NotFound)
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getgrnam_r(cnameptr: *const libc::c_char,
                                         group: *mut Group,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         _: *mut libc::c_int)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let cname: &CStr = unsafe { CStr::from_ptr(cnameptr) };
    let name = String::from(cname.to_str().unwrap());
    let (team, members) = CLIENT.get_team_members().unwrap();
    let members: Vec<&str> = members.values().map(|m| m.login.as_str()).collect();
    if name == team.name {
        match unsafe { (*group).pack_args(&mut buffer, &team.name, team.id, &members) } {
            Ok(_) => libc::c_int::from(NssStatus::Success),
            Err(_) => nix::Errno::ERANGE as libc::c_int,
        }
    } else {
        libc::c_int::from(NssStatus::NotFound)
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_setgrent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let (team, members) = match CLIENT.get_team_members() {
        Ok(team_members) => team_members,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let member_names = members.values().map(|x| x.login.as_str()).collect::<Vec<&str>>().join(" ");
    list_file.write(format!("{}\t{}\t{}\n", team.name, team.id, member_names).as_bytes())
             .unwrap();
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getgrent_r(grbuf: *mut Group,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         grbufp: *mut *mut Group)
                                         -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Unavail),
    };
    for (i, line) in list.lines().enumerate() {
        if i != idx {
            continue;
        }
        if let Ok(l) = line {
            let mut buffer = Buffer::new(buf, buflen);
            let words: Vec<&str> = l.split("\t").collect();
            let member_names: Vec<&str> = words[2].split(" ").collect();
            let id: u64 = words[1].parse::<u64>().unwrap();
            match unsafe { (*grbuf).pack_args(&mut buffer, words[0], id, &member_names) } {
                Ok(_) => {
                    runfiles::increment(idx, idx_file);
                    unsafe { *grbufp = grbuf };
                    return libc::c_int::from(NssStatus::Success);
                }
                Err(_) => {
                    unsafe { *grbufp = std::ptr::null_mut() };
                    return nix::Errno::ERANGE as libc::c_int;
                }
            }
        }
    }
    libc::c_int::from(NssStatus::Unavail)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_endgrent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}
<commit_msg>Simplify and delete loops<commit_after>extern crate toml;
extern crate reqwest;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate glob;
extern crate nix;

#[macro_use]
extern crate lazy_static;

use std::io::{Write, BufRead};
use std::ffi::CStr;
extern crate libc;

mod structs;
use structs::Config;
mod ghclient;
use ghclient::GithubClient;
mod buffer;
use buffer::Buffer;
mod cstructs;
use cstructs::{Passwd, Spwd, Group};
mod runfiles;
mod statics;
use statics::CONF_PATH;

lazy_static! {
    pub static ref CONFIG:Config = Config::new(&CONF_PATH).unwrap();
    pub static ref CLIENT:GithubClient = GithubClient::new(&CONFIG).unwrap();
}

#[allow(dead_code)]
enum NssStatus {
    TryAgain,
    Unavail,
    NotFound,
    Success,
}

impl From<NssStatus> for libc::c_int {
    fn from(status: NssStatus) -> libc::c_int {
        match status {
            NssStatus::TryAgain => -2,
            NssStatus::Unavail => -1,
            NssStatus::NotFound => 0,
            NssStatus::Success => 1,
        }
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getpwnam_r(cnameptr: *const libc::c_char,
                                         pw: *mut Passwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         _: *mut libc::c_int)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let cname: &CStr = unsafe { CStr::from_ptr(cnameptr) };
    let name = String::from(cname.to_str().unwrap());
    let (_, members) = CLIENT.get_team_members().unwrap();
    match members.get(&name) {
        Some(member) => {
            match unsafe { (*pw).pack_args(&mut buffer, &member.login, member.id, &CONFIG) } {
                Ok(_) => libc::c_int::from(NssStatus::Success),
                Err(_) => nix::Errno::ERANGE as libc::c_int,
            }
        }
        None => libc::c_int::from(NssStatus::NotFound),
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getpwuid_r(uid: libc::uid_t,
                                         pw: *mut Passwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         _: *mut libc::c_int)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let (_, members) = CLIENT.get_team_members().unwrap();
    for member in members.values() {
        if uid == member.id as libc::uid_t {
            match unsafe { (*pw).pack_args(&mut buffer, &member.login, member.id, &CONFIG) } {
                Ok(_) => return libc::c_int::from(NssStatus::Success),
                Err(_) => return nix::Errno::ERANGE as libc::c_int,
            }
        }
    }
    libc::c_int::from(NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_setpwent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let members = match CLIENT.get_team_members() {
        Ok((_, members)) => members,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    for member in members.values() {
        list_file.write(format!("{}\t{}\n", member.login, member.id).as_bytes())
                 .unwrap();
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getpwent_r(pwbuf: *mut Passwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         pwbufp: *mut *mut Passwd)
                                         -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Unavail),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        let id = words[1].parse::<u64>().unwrap();
        match unsafe { (*pwbuf).pack_args(&mut buffer, words[0], id, &CONFIG) } {
            Ok(_) => {
                runfiles::increment(idx, idx_file);
                unsafe { *pwbufp = pwbuf };
                return libc::c_int::from(NssStatus::Success);
            }
            Err(_) => {
                unsafe { *pwbufp = std::ptr::null_mut() };
                return nix::Errno::ERANGE as libc::c_int;
            }
        }
    }
    libc::c_int::from(NssStatus::Unavail)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_endpwent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getspnam_r(cnameptr: *const libc::c_char,
                                         spwd: *mut Spwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         _: *mut libc::c_int)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let cname: &CStr = unsafe { CStr::from_ptr(cnameptr) };
    let name = String::from(cname.to_str().unwrap());
    let (_, members) = CLIENT.get_team_members().unwrap();
    match members.get(&name) {
        Some(member) => {
            match unsafe { (*spwd).pack_args(&mut buffer, &member.login) } {
                Ok(_) => libc::c_int::from(NssStatus::Success),
                Err(_) => nix::Errno::ERANGE as libc::c_int,
            }
        }
        None => libc::c_int::from(NssStatus::NotFound),
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_setspent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let members = match CLIENT.get_team_members() {
        Ok((_, members)) => members,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    for member in members.values() {
        list_file.write(format!("{}\t{}\n", member.login, member.id).as_bytes())
                 .unwrap();
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getspent_r(spbuf: *mut Spwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         spbufp: *mut *mut Spwd)
                                         -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Unavail),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        match unsafe { (*spbuf).pack_args(&mut buffer, words[0]) } {
            Ok(_) => {
                runfiles::increment(idx, idx_file);
                unsafe { *spbufp = spbuf };
                return libc::c_int::from(NssStatus::Success);
            }
            Err(_) => {
                unsafe { *spbufp = std::ptr::null_mut() };
                return nix::Errno::ERANGE as libc::c_int;
            }
        }
    }
    libc::c_int::from(NssStatus::Unavail)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_endspent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getgrgid_r(gid: libc::gid_t,
                                         group: *mut Group,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         _: *mut libc::c_int)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let (team, members) = CLIENT.get_team_members().unwrap();
    let members: Vec<&str> = members.values().map(|m| m.login.as_str()).collect();
    if gid as u64 == team.id {
        match unsafe { (*group).pack_args(&mut buffer, &team.name, gid as u64, &members) } {
            Ok(_) => libc::c_int::from(NssStatus::Success),
            Err(_) => nix::Errno::ERANGE as libc::c_int,
        }
    } else {
        libc::c_int::from(NssStatus::NotFound)
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getgrnam_r(cnameptr: *const libc::c_char,
                                         group: *mut Group,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         _: *mut libc::c_int)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let cname: &CStr = unsafe { CStr::from_ptr(cnameptr) };
    let name = String::from(cname.to_str().unwrap());
    let (team, members) = CLIENT.get_team_members().unwrap();
    let members: Vec<&str> = members.values().map(|m| m.login.as_str()).collect();
    if name == team.name {
        match unsafe { (*group).pack_args(&mut buffer, &team.name, team.id, &members) } {
            Ok(_) => libc::c_int::from(NssStatus::Success),
            Err(_) => nix::Errno::ERANGE as libc::c_int,
        }
    } else {
        libc::c_int::from(NssStatus::NotFound)
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_setgrent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let (team, members) = match CLIENT.get_team_members() {
        Ok(team_members) => team_members,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let member_names = members.values().map(|x| x.login.as_str()).collect::<Vec<&str>>().join(" ");
    list_file.write(format!("{}\t{}\t{}\n", team.name, team.id, member_names).as_bytes())
             .unwrap();
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getgrent_r(grbuf: *mut Group,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         grbufp: *mut *mut Group)
                                         -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Unavail),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        let member_names: Vec<&str> = words[2].split(" ").collect();
        let id: u64 = words[1].parse::<u64>().unwrap();
        match unsafe { (*grbuf).pack_args(&mut buffer, words[0], id, &member_names) } {
            Ok(_) => {
                runfiles::increment(idx, idx_file);
                unsafe { *grbufp = grbuf };
                return libc::c_int::from(NssStatus::Success);
            }
            Err(_) => {
                unsafe { *grbufp = std::ptr::null_mut() };
                return nix::Errno::ERANGE as libc::c_int;
            }
        }
    }
    libc::c_int::from(NssStatus::Unavail)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_endgrent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]
use std::collections::{HashMap, TreeMap, VecMap, TrieMap};
use std::hash::Hash;

/// Conversion from an `Iterator` of pairs.
pub trait Groupable<K, V> {
    /// Loops through the entire iterator, grouping all keys into a container
    /// implementing `FromKeyedIterator` with a container of values per key.
    /// The values will be aggregated per key into a container implementing
    /// `Extendable` for the value type.
    ///
    /// # Example
    ///
    /// ```rust
    /// use std::collections::HashMap;
    /// use groupable::Groupable;
    ///
    /// let evens = range(0u, 10).map(|i| (i % 2 == 0, i))
    ///                         .group::<HashMap<bool, Vec<uint>>>();
    ///
    /// assert_eq!(evens[true].as_slice(), [0, 2, 4, 6, 8].as_slice());
    /// assert_eq!(evens[false].as_slice(), [1, 3, 5, 7, 9].as_slice());
    /// ```
    fn group<B: FromKeyedIterator<K, V>>(&mut self) -> B;
}

impl<K, V, I: Iterator<(K, V)>> Groupable<K, V> for I {
    fn group<B: FromKeyedIterator<K, V>>(&mut self) -> B {
        FromKeyedIterator::from_keyed_iter(self.by_ref())
    }
}

/// Conversion from an `Iterator` of key-value pairs.
pub trait FromKeyedIterator<K, V> {
    /// Build a container with groups of elements from an external iterator.
    fn from_keyed_iter<I: Iterator<(K, V)>>(I) -> Self;
}

macro_rules! group_into(
    ($iter:ident, $map:ident) => (
        for (key, val) in $iter {
            let val_iter = Some(val).into_iter();
            match $map.find_mut(&key) {
                Some(collection) => {
                    collection.extend(val_iter);
                    continue
                },
                None => {} // insert below
            }

            $map.insert(key, FromIterator::from_iter(val_iter));
        }
    )
)

macro_rules! impl_keyed_iter (
    ($name:ident: $($bounds:ident),+) => (
        impl <K: $($bounds+)+, V, U: Extendable<V>> FromKeyedIterator<K, V> for $name<K, U> {
            fn from_keyed_iter<T: Iterator<(K, V)>>(mut iter: T) -> $name<K, U> {
                let mut map = $name::<K, U>::new();
                group_into!(iter, map);
                map
            }
        }
    )
)

macro_rules! impl_uint_keyed_iter (
    ($name:ident) => (
        impl <V, U: Extendable<V>> FromKeyedIterator<uint, V> for $name<U> {
            fn from_keyed_iter<T: Iterator<(uint, V)>>(mut iter: T) -> $name<U> {
                let mut map = $name::<U>::new();
                group_into!(iter, map)
                map
            }
        }
    )
)

impl_keyed_iter!(HashMap: Ord, Hash)
impl_keyed_iter!(TreeMap: Ord)
impl_uint_keyed_iter!(VecMap)
impl_uint_keyed_iter!(TrieMap)
<commit_msg>More Collections Reform, Extendable -> Extend<commit_after>#![feature(macro_rules)]
use std::collections::{HashMap, TreeMap, VecMap, TrieMap};
use std::hash::Hash;

/// Conversion from an `Iterator` of pairs.
pub trait Groupable<K, V> {
    /// Loops through the entire iterator, grouping all keys into a container
    /// implementing `FromKeyedIterator` with a container of values per key.
    /// The values will be aggregated per key into a container implementing
    /// `Extendable` for the value type.
    ///
    /// # Example
    ///
    /// ```rust
    /// use std::collections::HashMap;
    /// use groupable::Groupable;
    ///
    /// let evens = range(0u, 10).map(|i| (i % 2 == 0, i))
    ///                         .group::<HashMap<bool, Vec<uint>>>();
    ///
    /// assert_eq!(evens[true].as_slice(), [0, 2, 4, 6, 8].as_slice());
    /// assert_eq!(evens[false].as_slice(), [1, 3, 5, 7, 9].as_slice());
    /// ```
    fn group<B: FromKeyedIterator<K, V>>(&mut self) -> B;
}

impl<K, V, I: Iterator<(K, V)>> Groupable<K, V> for I {
    fn group<B: FromKeyedIterator<K, V>>(&mut self) -> B {
        FromKeyedIterator::from_keyed_iter(self.by_ref())
    }
}

/// Conversion from an `Iterator` of key-value pairs.
pub trait FromKeyedIterator<K, V> {
    /// Build a container with groups of elements from an external iterator.
    fn from_keyed_iter<I: Iterator<(K, V)>>(I) -> Self;
}

macro_rules! group_into(
    ($iter:ident, $map:ident) => (
        for (key, val) in $iter {
            let val_iter = Some(val).into_iter();
            match $map.find_mut(&key) {
                Some(collection) => {
                    collection.extend(val_iter);
                    continue
                },
                None => {} // insert below
            }

            $map.insert(key, FromIterator::from_iter(val_iter));
        }
    )
)

macro_rules! impl_keyed_iter (
    ($name:ident: $($bounds:ident),+) => (
        impl <K: $($bounds+)+, V, U: Extend<V> + FromIterator<V>> FromKeyedIterator<K, V> for $name<K, U> {
            fn from_keyed_iter<T: Iterator<(K, V)>>(mut iter: T) -> $name<K, U> {
                let mut map = $name::<K, U>::new();
                group_into!(iter, map);
                map
            }
        }
    )
)

macro_rules! impl_uint_keyed_iter (
    ($name:ident) => (
        impl <V, U: Extend<V> + FromIterator<V>> FromKeyedIterator<uint, V> for $name<U> {
            fn from_keyed_iter<T: Iterator<(uint, V)>>(mut iter: T) -> $name<U> {
                let mut map = $name::<U>::new();
                group_into!(iter, map)
                map
            }
        }
    )
)

impl_keyed_iter!(HashMap: Ord, Hash)
impl_keyed_iter!(TreeMap: Ord)
impl_uint_keyed_iter!(VecMap)
impl_uint_keyed_iter!(TrieMap)
<|endoftext|>


<commit_before>//! Straight-forward functions and types for basic data parallel
//! operations.
//!
//! This library provides a few building blocks for operating on data
//! in parallel, particularly iterators. At the moment, it is not
//! designed to be robust or eek out every last drop of performance,
//! but rather explore some ways in which Rust's type system allows
//! for some fairly fancy things to be written with a guarantee of
//! safety, all without a garbage collector.
//!
//! The only dependency is `std` and the basic functionality has no
//! `unsafe` code at all (the thread pool does use unsafe). Other than
//! the pool, parallelism is built directly from the functionality
//! provided by `std::thread` and `std::sync` and leverages their
//! correctness to automatically ensure the correctness of this
//! library (at the memory safety level).
//!
//! The core design is to simply allow for operations that could occur
//! on a single thread to execute on many, it is not intending to
//! serve as a hard boundary between threads; in particular, if
//! something (a `panic!`) would take down the main thread when run
//! sequentially, it will also take down the main thread (eventually)
//! when run using the functions in this library.
//!
//! On the point of performance and robustness, the top level
//! functions do no thread pooling and so everything essentially
//! spawns a new thread for each element, which is definitely
//! suboptimal for many reasons. Fortunately, not all is lost, the
//! functionality is designed to be as generic as possible, so the
//! iterator functions work with many many iterators, e.g. instead of
//! executing a thread on every element of a vector individually, a
//! user can divide that vector into disjoint sections and spread
//! those across much fewer threads (e.g. [the `chunks`
//! method](http://doc.rust-lang.org/nightly/std/slice/trait.SliceExt.html#tymethod.chunks)).
//!
//! Further, the thread pooling that does exist has a lot of
//! synchronisation overhead, and so is actually rarely a performance
//! improvement (although it is a robustness improvement over the
//! top-level functions, since it limits the number of threads that
//! will be spawned).
//!
//! Either way, **this is not recommended for general use**.
//!
//! # Usage
//!
//! This is [available on
//! crates.io](https://crates.io/crates/simple_parallel). Add this to
//! your Cargo.toml:
//!
//! ```toml
//! [dependencies]
//! simple_parallel = "0.1"
//! ```
//!
//! The latest development version can be obtained [on
//! GitHub](https://github.com/huonw/simple_parallel).
//!
//! # Examples
//!
//! Initialise an array, in parallel.
//!
//! ```rust
//! let mut data = [0; 10];
//! // fill the array, with one thread for each element:
//! simple_parallel::for_(data.iter_mut().enumerate(), |(i, elem)| {
//!     *elem = i as i32;
//! });
//!
//! // now adjust that data, with a threadpool:
//! let mut pool = simple_parallel::Pool::new(4);
//! pool.for_(data.iter_mut(), |elem| *elem *= 2);
//! ```
//!
//! Transform each element of an ordered map in a fancy way, in
//! parallel, with `map` (`map` ensures the output order matches the
//! input order, unlike `unordered_map`),
//!
//! ```rust
//! use std::collections::BTreeMap;
//!
//! let mut map = BTreeMap::new();
//! map.insert('a', 1);
//! map.insert('x', 55);
//!
//! let f = |(&c, &elem): (&char, _)| {
//!     let mut x = elem  * c as i32;
//!     // ... something complicated and expensive ...
//!     return x as f64
//! };
//!
//! // (`IntoIterator` is used, so "direct" iteration like this is fine.)
//! let par_iter = simple_parallel::map(&map, &f);
//!
//! // the computation is executing on several threads in the
//! // background, so that elements are hopefully ready as soon as
//! // possible.
//!
//! for value in par_iter {
//!     println!("I computed {}", value);
//! }
//! ```
//!
//! Sum an arbitrarily long slice, in parallel, by summing subsections and adding
//! everything to a shared mutex, stored on the stack of the main
//! thread. (A parallel fold is currently missing, hence the mutex.)
//!
//! ```rust
//! use std::sync::Mutex;
//!
//! // limit the spew of thread spawning to something sensible
//! const NUM_CHUNKS: usize = 8;
//!
//! fn sum(x: &[f64]) -> f64 {
//!     // (round up)
//!     let elements_per_chunk = (x.len() + NUM_CHUNKS - 1) / NUM_CHUNKS;
//!
//!     let total = Mutex::new(0.0);
//!     simple_parallel::for_(x.chunks(elements_per_chunk), |chunk| {
//!         // sum up this little subsection
//!         let subsum = chunk.iter().fold(0.0, |a, b| a + *b);
//!         *total.lock().unwrap() += subsum;
//!     });
//!
//!     let answer = *total.lock().unwrap();
//!     answer
//! }
//! ```
//!
//! Alternatively, one could use a thread pool, and assign an absolute
//! number of elements to each subsection and let the pool manage
//! distributing the work among threads, instead of being forced to
//! computing the length of the subsections to limit the number of
//! threads spawned.
//!
//! ```rust
//! use std::sync::Mutex;
//!
//! // limit the spew of thread spawning to something sensible
//! const ELEMS_PER_JOB: usize = 1_000;
//!
//! fn pooled_sum(pool: &mut simple_parallel::Pool, x: &[f64]) -> f64 {
//!     let total = Mutex::new(0.0);
//!     simple_parallel::for_(x.chunks(ELEMS_PER_JOB), |chunk| {
//!         // sum up this little subsection
//!         let subsum = chunk.iter().fold(0.0, |a, b| a + *b);
//!         *total.lock().unwrap() += subsum;
//!     });
//!
//!     let answer = *total.lock().unwrap();
//!     answer
//! }
//! ```
//!
//! A sketch of a very simple recursive parallel merge-sort, using
//! `both` to handle the recursion. (A working implementation may
//! really need some temporary buffers to mangle the data, but the key
//! point is `both` naturally running things in parallel.)
//!
//! ```rust
//! /// Merges the two sorted runs `left` and `right`.
//! /// That is, after `merge(left, right)`,
//! ///
//! ///    left[0] <= left[1] <= ... <= left[last] <= right[0] <= ...
//! fn merge<T: Ord>(left: &mut [T], right: &mut [T]) {
//!     // magic (but non-parallel, so boring)
//! }
//!
//! fn parallel_merge_sort<T: Ord + Send>(x: &mut [T]) {
//!    // base case
//!    if x.len() <= 1 { return }
//!
//!    // get two disjoint halves of the `x`,
//!    let half = x.len() / 2;
//!    let (left, right) = x.split_at_mut(half);
//!    // and sort them recursively, in parallel
//!    simple_parallel::both(&mut *left, &mut *right, |v| parallel_merge_sort(v));
//!
//!    // now combine the two sorted halves
//!    merge(left, right)
//! }
//! ```
//!
//! The [`examples`
//! folder](https://github.com/huonw/simple_parallel/tree/master/examples)
//! contains more intricate example(s), such as a parallel fast
//! Fourier transform implementation (it really works, and the
//! parallelism does buy something... when tuned).
#![feature(core)]

use std::thread;
use std::iter::IntoIterator;

mod maps;

pub mod pool;

pub mod one_to_one {
    pub use maps::{unordered_map, UnorderedParMap, map, ParMap};
}

pub use one_to_one::{map, unordered_map};

pub use pool::Pool;

/// Execute `f` on each element of `iter`, in their own `scoped`
/// thread.
///
/// If `f` panics, so does `for_`. If this occurs, the number of
/// elements of `iter` that have had `f` called on them is
/// unspecified.
pub fn for_<I: IntoIterator, F>(iter: I, ref f: F)
    where I::Item: Send, F: Fn(I::Item) + Sync
{
    let _guards: Vec<_> = iter.into_iter().map(|elem| {
        thread::scoped(move || {
            f(elem)
        })
    }).collect();
}

/// Execute `f` on both `x` and `y`, in parallel, returning the
/// result.
///
/// This is the same (including panic semantics) as `(f(x), f(y))`, up
/// to ordering. It is designed to be used for divide-and-conquer
/// algorithms.
pub fn both<T, U, F>(x: T, y: T, ref f: F) -> (U, U)
    where T: Send,
          U: Send,
          F: Sync + Fn(T) -> U
{
    let guard = thread::scoped(move || f(y));
    let a = f(x);
    let b = guard.join();
    (a, b)
}
<commit_msg>Fix example<commit_after>//! Straight-forward functions and types for basic data parallel
//! operations.
//!
//! This library provides a few building blocks for operating on data
//! in parallel, particularly iterators. At the moment, it is not
//! designed to be robust or eek out every last drop of performance,
//! but rather explore some ways in which Rust's type system allows
//! for some fairly fancy things to be written with a guarantee of
//! safety, all without a garbage collector.
//!
//! The only dependency is `std` and the basic functionality has no
//! `unsafe` code at all (the thread pool does use unsafe). Other than
//! the pool, parallelism is built directly from the functionality
//! provided by `std::thread` and `std::sync` and leverages their
//! correctness to automatically ensure the correctness of this
//! library (at the memory safety level).
//!
//! The core design is to simply allow for operations that could occur
//! on a single thread to execute on many, it is not intending to
//! serve as a hard boundary between threads; in particular, if
//! something (a `panic!`) would take down the main thread when run
//! sequentially, it will also take down the main thread (eventually)
//! when run using the functions in this library.
//!
//! On the point of performance and robustness, the top level
//! functions do no thread pooling and so everything essentially
//! spawns a new thread for each element, which is definitely
//! suboptimal for many reasons. Fortunately, not all is lost, the
//! functionality is designed to be as generic as possible, so the
//! iterator functions work with many many iterators, e.g. instead of
//! executing a thread on every element of a vector individually, a
//! user can divide that vector into disjoint sections and spread
//! those across much fewer threads (e.g. [the `chunks`
//! method](http://doc.rust-lang.org/nightly/std/slice/trait.SliceExt.html#tymethod.chunks)).
//!
//! Further, the thread pooling that does exist has a lot of
//! synchronisation overhead, and so is actually rarely a performance
//! improvement (although it is a robustness improvement over the
//! top-level functions, since it limits the number of threads that
//! will be spawned).
//!
//! Either way, **this is not recommended for general use**.
//!
//! # Usage
//!
//! This is [available on
//! crates.io](https://crates.io/crates/simple_parallel). Add this to
//! your Cargo.toml:
//!
//! ```toml
//! [dependencies]
//! simple_parallel = "0.1"
//! ```
//!
//! The latest development version can be obtained [on
//! GitHub](https://github.com/huonw/simple_parallel).
//!
//! # Examples
//!
//! Initialise an array, in parallel.
//!
//! ```rust
//! let mut data = [0; 10];
//! // fill the array, with one thread for each element:
//! simple_parallel::for_(data.iter_mut().enumerate(), |(i, elem)| {
//!     *elem = i as i32;
//! });
//!
//! // now adjust that data, with a threadpool:
//! let mut pool = simple_parallel::Pool::new(4);
//! pool.for_(data.iter_mut(), |elem| *elem *= 2);
//! ```
//!
//! Transform each element of an ordered map in a fancy way, in
//! parallel, with `map` (`map` ensures the output order matches the
//! input order, unlike `unordered_map`),
//!
//! ```rust
//! use std::collections::BTreeMap;
//!
//! let mut map = BTreeMap::new();
//! map.insert('a', 1);
//! map.insert('x', 55);
//!
//! let f = |(&c, &elem): (&char, _)| {
//!     let mut x = elem  * c as i32;
//!     // ... something complicated and expensive ...
//!     return x as f64
//! };
//!
//! // (`IntoIterator` is used, so "direct" iteration like this is fine.)
//! let par_iter = simple_parallel::map(&map, &f);
//!
//! // the computation is executing on several threads in the
//! // background, so that elements are hopefully ready as soon as
//! // possible.
//!
//! for value in par_iter {
//!     println!("I computed {}", value);
//! }
//! ```
//!
//! Sum an arbitrarily long slice, in parallel, by summing subsections and adding
//! everything to a shared mutex, stored on the stack of the main
//! thread. (A parallel fold is currently missing, hence the mutex.)
//!
//! ```rust
//! use std::sync::Mutex;
//!
//! // limit the spew of thread spawning to something sensible
//! const NUM_CHUNKS: usize = 8;
//!
//! fn sum(x: &[f64]) -> f64 {
//!     // (round up)
//!     let elements_per_chunk = (x.len() + NUM_CHUNKS - 1) / NUM_CHUNKS;
//!
//!     let total = Mutex::new(0.0);
//!     simple_parallel::for_(x.chunks(elements_per_chunk), |chunk| {
//!         // sum up this little subsection
//!         let subsum = chunk.iter().fold(0.0, |a, b| a + *b);
//!         *total.lock().unwrap() += subsum;
//!     });
//!
//!     let answer = *total.lock().unwrap();
//!     answer
//! }
//! ```
//!
//! Alternatively, one could use a thread pool, and assign an absolute
//! number of elements to each subsection and let the pool manage
//! distributing the work among threads, instead of being forced to
//! computing the length of the subsections to limit the number of
//! threads spawned.
//!
//! ```rust
//! use std::sync::Mutex;
//!
//! // limit the spew of thread spawning to something sensible
//! const ELEMS_PER_JOB: usize = 1_000;
//!
//! fn pooled_sum(pool: &mut simple_parallel::Pool, x: &[f64]) -> f64 {
//!     let total = Mutex::new(0.0);
//!     pool.for_(x.chunks(ELEMS_PER_JOB), |chunk| {
//!         // sum up this little subsection
//!         let subsum = chunk.iter().fold(0.0, |a, b| a + *b);
//!         *total.lock().unwrap() += subsum;
//!     });
//!
//!     let answer = *total.lock().unwrap();
//!     answer
//! }
//! ```
//!
//! A sketch of a very simple recursive parallel merge-sort, using
//! `both` to handle the recursion. (A working implementation may
//! really need some temporary buffers to mangle the data, but the key
//! point is `both` naturally running things in parallel.)
//!
//! ```rust
//! /// Merges the two sorted runs `left` and `right`.
//! /// That is, after `merge(left, right)`,
//! ///
//! ///    left[0] <= left[1] <= ... <= left[last] <= right[0] <= ...
//! fn merge<T: Ord>(left: &mut [T], right: &mut [T]) {
//!     // magic (but non-parallel, so boring)
//! }
//!
//! fn parallel_merge_sort<T: Ord + Send>(x: &mut [T]) {
//!    // base case
//!    if x.len() <= 1 { return }
//!
//!    // get two disjoint halves of the `x`,
//!    let half = x.len() / 2;
//!    let (left, right) = x.split_at_mut(half);
//!    // and sort them recursively, in parallel
//!    simple_parallel::both(&mut *left, &mut *right, |v| parallel_merge_sort(v));
//!
//!    // now combine the two sorted halves
//!    merge(left, right)
//! }
//! ```
//!
//! The [`examples`
//! folder](https://github.com/huonw/simple_parallel/tree/master/examples)
//! contains more intricate example(s), such as a parallel fast
//! Fourier transform implementation (it really works, and the
//! parallelism does buy something... when tuned).
#![feature(core)]

use std::thread;
use std::iter::IntoIterator;

mod maps;

pub mod pool;

pub mod one_to_one {
    pub use maps::{unordered_map, UnorderedParMap, map, ParMap};
}

pub use one_to_one::{map, unordered_map};

pub use pool::Pool;

/// Execute `f` on each element of `iter`, in their own `scoped`
/// thread.
///
/// If `f` panics, so does `for_`. If this occurs, the number of
/// elements of `iter` that have had `f` called on them is
/// unspecified.
pub fn for_<I: IntoIterator, F>(iter: I, ref f: F)
    where I::Item: Send, F: Fn(I::Item) + Sync
{
    let _guards: Vec<_> = iter.into_iter().map(|elem| {
        thread::scoped(move || {
            f(elem)
        })
    }).collect();
}

/// Execute `f` on both `x` and `y`, in parallel, returning the
/// result.
///
/// This is the same (including panic semantics) as `(f(x), f(y))`, up
/// to ordering. It is designed to be used for divide-and-conquer
/// algorithms.
pub fn both<T, U, F>(x: T, y: T, ref f: F) -> (U, U)
    where T: Send,
          U: Send,
          F: Sync + Fn(T) -> U
{
    let guard = thread::scoped(move || f(y));
    let a = f(x);
    let b = guard.join();
    (a, b)
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

extern crate libc;
extern crate zmq_sys;

use std::ffi;
use std::vec::Vec;
use std::slice;
use std::mem::transmute;
use libc::{ c_int, c_void, size_t };

pub const ZMQ_VERSION_MAJOR:i32 = 4;
pub const ZMQ_VERSION_MINOR:i32 = 1;
pub const ZMQ_VERSION_PATCH:i32 = 4;

macro_rules! ret_when_null {
    ($ptr: expr) => {{
        if $ptr.is_null() {
            return Err(Error::from_last_err());
        }
    }}
}

#[macro_export]
macro_rules! ZMQ_MAKE_VERSION {
    ($major: expr, $minor: expr, $patch: expr) => {
        {
            $major * 10000 + $minor * 100 + $patch
        }
    }
}

pub const ZMQ_VERSION:i32 = ZMQ_MAKE_VERSION!(
    ZMQ_VERSION_MAJOR,
    ZMQ_VERSION_MINOR,
    ZMQ_VERSION_PATCH
);

/*
const ZMQ_HAUSNUMERO: c_int = 156384712;

const ENOTSUP: c_int = (ZMQ_HAUSNUMERO + 1);
const EPROTONOSUPPORT: c_int = (ZMQ_HAUSNUMERO + 2);
const ENOBUFS: c_int = (ZMQ_HAUSNUMERO + 3);
const ENETDOWN: c_int = (ZMQ_HAUSNUMERO + 4);
const EADDRINUSE: c_int = (ZMQ_HAUSNUMERO + 5);
const EADDRNOTAVAIL: c_int = (ZMQ_HAUSNUMERO + 6);
const ECONNREFUSED: c_int = (ZMQ_HAUSNUMERO + 7);
const EINPROGRESS: c_int = (ZMQ_HAUSNUMERO + 8);
const ENOTSOCK: c_int = (ZMQ_HAUSNUMERO + 9);
const EMSGSIZE: c_int = (ZMQ_HAUSNUMERO + 10);
const EAFNOSUPPORT: c_int = (ZMQ_HAUSNUMERO + 11);
const ENETUNREACH: c_int = (ZMQ_HAUSNUMERO + 12);
const ECONNABORTED: c_int = (ZMQ_HAUSNUMERO + 13);
const ECONNRESET: c_int = (ZMQ_HAUSNUMERO + 14);
const ENOTCONN: c_int = (ZMQ_HAUSNUMERO + 15);
const ETIMEDOUT: c_int = (ZMQ_HAUSNUMERO + 16);
const EHOSTUNREACH: c_int = (ZMQ_HAUSNUMERO + 17);
const ENETRESET: c_int = (ZMQ_HAUSNUMERO + 18);

const EFSM: c_int = (ZMQ_HAUSNUMERO + 51);
const ENOCOMPATPROTO: c_int = (ZMQ_HAUSNUMERO + 52);
const ETERM: c_int = (ZMQ_HAUSNUMERO + 53);
const EMTHREAD: c_int = (ZMQ_HAUSNUMERO + 54);
*/

pub fn errno() -> c_int {
    unsafe {
        zmq_sys::zmq_errno()
    }
}

pub fn strerror(errnum: c_int) -> String {
    unsafe {
        let s = zmq_sys::zmq_strerror(errnum);
        ffi::CStr::from_ptr(s).to_str().unwrap().to_string()
    }
}

pub fn version() -> (i32, i32, i32) {
    let mut major = 0;
    let mut minor = 0;
    let mut patch = 0;

    unsafe {
        zmq_sys::zmq_version(&mut major, &mut minor, &mut patch);
    }

    (major as i32, minor as i32, patch as i32)
}

#[derive(Clone)]
pub struct Error {
    err_num: c_int,
    err_str: String,
}

impl Error {
    fn from_last_err() -> Error {
        let err_num = errno();
        let err_str = strerror(err_num);

        Error {
            err_num: err_num,
            err_str: err_str,
        }
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{} (code {})", self.err_str, self.err_num)
    }
}

impl std::fmt::Debug for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Display::fmt(self, f)
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        &self.err_str
    }
}

#[allow(non_camel_case_types)]
pub enum ContextSetOption {
    ZMQ_IO_THREADS = 1,
    ZMQ_MAX_SOCKETS = 2,
    ZMQ_THREAD_PRIORITY = 3,
    ZMQ_THREAD_SCHED_POLICY = 4,
    ZMQ_IPV6 = 42,
}

#[allow(non_camel_case_types)]
pub enum ContextGetOption {
    ZMQ_IO_THREADS = 1,
    ZMQ_MAX_SOCKETS = 2,
    ZMQ_SOCKET_LIMIT = 3,
    ZMQ_IPV6 = 42,
}

pub struct Context {
    ctx_ptr: *mut c_void,
}

impl Context {
    /// void *zmq_ctx_new (void)
    pub fn new() -> Result<Context, Error> {
        let ctx_ptr = unsafe { zmq_sys::zmq_ctx_new() };
        ret_when_null!(ctx_ptr);

        Ok(Context {
            ctx_ptr: ctx_ptr,
        })
    }

    /// int zmq_ctx_term (void *context)
    fn term(&mut self) -> Option<Error> {        // trasnfer owner
        let rc = unsafe { zmq_sys::zmq_ctx_term(self.ctx_ptr) };
        if rc == -1 {
            Some(Error::from_last_err())
        } else {
            None
        }
    }

    /// int zmq_ctx_shutdown (void *ctx_)
    pub fn shutdown(&self) -> Option<Error> {
        let rc = unsafe { zmq_sys::zmq_ctx_shutdown(self.ctx_ptr) };
        if rc == -1 {
            Some(Error::from_last_err())
        } else {
            None
        }
    }

    /// int zmq_ctx_set (void *context, int option, int optval)
    pub fn set_option(&self, option_name: ContextSetOption, option_value: c_int) -> Option<Error> {
        let rc = unsafe { zmq_sys::zmq_ctx_set(self.ctx_ptr, option_name as c_int, option_value) };
        if rc == -1 {
            Some(Error::from_last_err())
        } else {
            None
        }
    }

    /// int zmq_ctx_get (void *context, int option)
    pub fn get_option(&self, option_name: ContextGetOption) -> Result<c_int, Error> {
        let rc = unsafe { zmq_sys::zmq_ctx_get(self.ctx_ptr, option_name as c_int) };
        if rc == -1 {
            Err(Error::from_last_err())
        } else {
            Ok(rc)
        }
    }
}

unsafe impl Send for Context {}
unsafe impl Sync for Context {}

impl Drop for Context {
    fn drop(&mut self) {
        self.term().unwrap();
    }
}

const MSG_SIZE: usize = 64;

pub struct Message {
    msg: zmq_sys::zmq_msg_t,
}

unsafe extern "C" fn zmq_free_fn(data: *mut c_void, hint: *mut c_void) {
    let len = transmute(hint);
    let slice = slice::from_raw_parts_mut(transmute::<*mut c_void, *mut u8>(data), len);
    let _: Box<[u8]> = Box::from_raw(slice);
}

impl Message {
    /// zmq_msg_init
    pub fn new() -> Result<Message, Error> {
        let mut msg = zmq_sys::zmq_msg_t { unknown: [0; MSG_SIZE] };
        let rc = unsafe { zmq_sys::zmq_msg_init(&mut msg) };
        if rc == -1 {
            Err(Error::from_last_err())
        } else {
            Ok(Message { msg: msg })
        }
    }

    /// zmq_msg_init_size
    pub fn with_capcity(len: usize) -> Result<Message, Error> {
        let mut msg = zmq_sys::zmq_msg_t { unknown: [0; MSG_SIZE] };
        let rc = unsafe { zmq_sys::zmq_msg_init_size(&mut msg, len as size_t) };
        if rc == -1 {
            Err(Error::from_last_err())
        } else {
            Ok(Message { msg: msg })
        }
    }

    /// zmq_msg_init_data
    pub fn from_vec(vec: Vec<u8>) -> Result<Message, Error> {
        let len = vec.len() as size_t;
        let data = vec.into_boxed_slice();
        let free_fn = unsafe { transmute(zmq_free_fn) };

        let mut msg = zmq_sys::zmq_msg_t { unknown: [0; MSG_SIZE] };
        let rc = unsafe {
            zmq_sys::zmq_msg_init_data(&mut msg, Box::into_raw(data) as *mut c_void, len,
                free_fn, transmute(len))
            };
        if rc == -1 {
            Err(Error::from_last_err())
        } else {
            Ok(Message { msg: msg })
        }
    }
}

impl Drop for Message {
    fn drop(&mut self) {
        let rc = unsafe { zmq_sys::zmq_msg_close(&mut self.msg) };
        if rc != 0 {
            panic!(Error::from_last_err());
        }
    }
}
<commit_msg>docs and new_socket<commit_after>#![allow(dead_code)]

extern crate libc;
extern crate zmq_sys;

use std::ffi;
use std::vec::Vec;
use std::slice;
use std::mem::transmute;
use libc::{ c_int, c_void, size_t };

pub const ZMQ_VERSION_MAJOR:i32 = 4;
pub const ZMQ_VERSION_MINOR:i32 = 1;
pub const ZMQ_VERSION_PATCH:i32 = 4;

macro_rules! ret_when_null {
    ($ptr: expr) => {{
        if $ptr.is_null() {
            return Err(Error::from_last_err());
        }
    }}
}

#[macro_export]
macro_rules! ZMQ_MAKE_VERSION {
    ($major: expr, $minor: expr, $patch: expr) => {
        {
            $major * 10000 + $minor * 100 + $patch
        }
    }
}

pub const ZMQ_VERSION:i32 = ZMQ_MAKE_VERSION!(
    ZMQ_VERSION_MAJOR,
    ZMQ_VERSION_MINOR,
    ZMQ_VERSION_PATCH
);

/*
const ZMQ_HAUSNUMERO: c_int = 156384712;

const ENOTSUP: c_int = (ZMQ_HAUSNUMERO + 1);
const EPROTONOSUPPORT: c_int = (ZMQ_HAUSNUMERO + 2);
const ENOBUFS: c_int = (ZMQ_HAUSNUMERO + 3);
const ENETDOWN: c_int = (ZMQ_HAUSNUMERO + 4);
const EADDRINUSE: c_int = (ZMQ_HAUSNUMERO + 5);
const EADDRNOTAVAIL: c_int = (ZMQ_HAUSNUMERO + 6);
const ECONNREFUSED: c_int = (ZMQ_HAUSNUMERO + 7);
const EINPROGRESS: c_int = (ZMQ_HAUSNUMERO + 8);
const ENOTSOCK: c_int = (ZMQ_HAUSNUMERO + 9);
const EMSGSIZE: c_int = (ZMQ_HAUSNUMERO + 10);
const EAFNOSUPPORT: c_int = (ZMQ_HAUSNUMERO + 11);
const ENETUNREACH: c_int = (ZMQ_HAUSNUMERO + 12);
const ECONNABORTED: c_int = (ZMQ_HAUSNUMERO + 13);
const ECONNRESET: c_int = (ZMQ_HAUSNUMERO + 14);
const ENOTCONN: c_int = (ZMQ_HAUSNUMERO + 15);
const ETIMEDOUT: c_int = (ZMQ_HAUSNUMERO + 16);
const EHOSTUNREACH: c_int = (ZMQ_HAUSNUMERO + 17);
const ENETRESET: c_int = (ZMQ_HAUSNUMERO + 18);

const EFSM: c_int = (ZMQ_HAUSNUMERO + 51);
const ENOCOMPATPROTO: c_int = (ZMQ_HAUSNUMERO + 52);
const ETERM: c_int = (ZMQ_HAUSNUMERO + 53);
const EMTHREAD: c_int = (ZMQ_HAUSNUMERO + 54);
*/

fn errno() -> c_int {
    unsafe {
        zmq_sys::zmq_errno()
    }
}

fn strerror(errnum: c_int) -> String {
    unsafe {
        let s = zmq_sys::zmq_strerror(errnum);
        ffi::CStr::from_ptr(s).to_str().unwrap().to_string()
    }
}

/// Report 0MQ library version
///
/// Binding of `void zmq_version (int *major, int *minor, int *patch)`
///
/// The function will return tuple of major, minor and patch of the ØMQ library version.
pub fn version() -> (i32, i32, i32) {
    let mut major = 0;
    let mut minor = 0;
    let mut patch = 0;

    unsafe {
        zmq_sys::zmq_version(&mut major, &mut minor, &mut patch);
    }

    (major as i32, minor as i32, patch as i32)
}

#[derive(Clone)]
pub struct Error {
    err_num: c_int,
    err_str: String,
}

impl Error {
    fn from_last_err() -> Error {
        let err_num = errno();
        let err_str = strerror(err_num);

        Error {
            err_num: err_num,
            err_str: err_str,
        }
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{} (code {})", self.err_str, self.err_num)
    }
}

impl std::fmt::Debug for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Display::fmt(self, f)
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        &self.err_str
    }
}

#[allow(non_camel_case_types)]
pub enum ContextSetOption {
    ZMQ_IO_THREADS = 1,
    ZMQ_MAX_SOCKETS = 2,
    ZMQ_THREAD_PRIORITY = 3,
    ZMQ_THREAD_SCHED_POLICY = 4,
    ZMQ_IPV6 = 42,
}

#[allow(non_camel_case_types)]
pub enum ContextGetOption {
    ZMQ_IO_THREADS = 1,
    ZMQ_MAX_SOCKETS = 2,
    ZMQ_SOCKET_LIMIT = 3,
    ZMQ_IPV6 = 42,
}

pub struct Context {
    ctx_ptr: *mut c_void,
}

impl Context {
    /// Create new 0MQ context
    ///
    /// Binding of `void *zmq_ctx_new ();`
    ///
    /// The function creates a new ØMQ context.
    /// # Thread safety
    /// A ØMQ context is thread safe and may be shared among as many application threads as necessary,
    /// without any additional locking required on the part of the caller.
    pub fn new() -> Result<Context, Error> {
        let ctx_ptr = unsafe { zmq_sys::zmq_ctx_new() };
        ret_when_null!(ctx_ptr);
        Ok(Context {
            ctx_ptr: ctx_ptr,
        })
    }

    /// Destroy a 0MQ context
    ///
    /// Binding of `int zmq_ctx_term (void *context);`
    /// This function will be called automatically when context goes out of scope
    fn term(&mut self) -> Option<Error> {
        let rc = unsafe { zmq_sys::zmq_ctx_term(self.ctx_ptr) };
        if rc == -1 {
            Some(Error::from_last_err())
        } else {
            None
        }
    }

    /// Shutdown a 0MQ context
    ///
    /// Binding of `int zmq_ctx_shutdown (void *context);`
    ///
    /// The function will shutdown the ØMQ context context.
    /// Context shutdown will cause any blocking operations currently in progress on sockets open within context to return immediately with an error code of ETERM.
    /// With the exception of Socket::Close(), any further operations on sockets open within context will fail with an error code of ETERM.
    pub fn shutdown(&self) -> Option<Error> {
        let rc = unsafe { zmq_sys::zmq_ctx_shutdown(self.ctx_ptr) };
        if rc == -1 {
            Some(Error::from_last_err())
        } else {
            None
        }
    }

    /// Set context options
    ///
    /// Bindnig of `int zmq_ctx_set (void *context, int option_name, int option_value);`
    ///
    /// The function will set the option specified by the option_name argument to the value of the option_value argument.
    pub fn set_option(&self, option_name: ContextSetOption, option_value: c_int) -> Option<Error> {
        let rc = unsafe { zmq_sys::zmq_ctx_set(self.ctx_ptr, option_name as c_int, option_value) };
        if rc == -1 {
            Some(Error::from_last_err())
        } else {
            None
        }
    }

    /// Get context options
    ///
    /// Binding of `int zmq_ctx_get (void *context, int option_name);`
    ///
    /// The function will return the option specified by the option_name argument.
    pub fn get_option(&self, option_name: ContextGetOption) -> Result<c_int, Error> {
        let rc = unsafe { zmq_sys::zmq_ctx_get(self.ctx_ptr, option_name as c_int) };
        if rc == -1 {
            Err(Error::from_last_err())
        } else {
            Ok(rc)
        }
    }

    /// Create 0MQ socket
    ///
    /// Binding of `void *zmq_socket (void *context, int type);`
    ///
    /// The type argument specifies the socket type, which determines the semantics of communication over the socket.
    /// The newly created socket is initially unbound, and not associated with any endpoints.
    /// In order to establish a message flow a socket must first be connected to at least one endpoint with Scoket::Connect,
    /// or at least one endpoint must be created for accepting incoming connections with Socket::Bind().
    pub fn new_socket(&self, t: SocketType) -> Result<Socket, Error> {
        let socket_ptr = unsafe { zmq_sys::zmq_socket(self.ctx_ptr, t as c_int) };
        ret_when_null!(socket_ptr);
        Ok(Socket { socket_ptr: socket_ptr })
    }
}

unsafe impl Send for Context {}
unsafe impl Sync for Context {}

impl Drop for Context {
    fn drop(&mut self) {
        self.term().unwrap();
    }
}

const MSG_SIZE: usize = 64;

pub struct Message {
    msg: zmq_sys::zmq_msg_t,
}

unsafe extern "C" fn zmq_free_fn(data: *mut c_void, hint: *mut c_void) {
    let len = transmute(hint);
    let slice = slice::from_raw_parts_mut(transmute::<*mut c_void, *mut u8>(data), len);
    let _: Box<[u8]> = Box::from_raw(slice);
}

impl Message {
    /// initialise empty 0MQ message.
    ///
    /// Binding of `int zmq_msg_init (zmq_msg_t *msg);`.
    ///
    /// The function will return a message object to represent an empty message.
    /// This function is most useful when called before receiving a message.
    pub fn new() -> Result<Message, Error> {
        let mut msg = zmq_sys::zmq_msg_t { unknown: [0; MSG_SIZE] };
        let rc = unsafe { zmq_sys::zmq_msg_init(&mut msg) };
        if rc == -1 {
            Err(Error::from_last_err())
        } else {
            Ok(Message { msg: msg })
        }
    }

    ///  Initialise 0MQ message of a specified size.
    ///
    /// Binding of `int zmq_msg_init_size (zmq_msg_t *msg, size_t size);`.
    ///
    /// The function will allocate any resources required to store a message size bytes long and
    /// return a message object to represent the newly allocated message.
    pub fn with_capcity(len: usize) -> Result<Message, Error> {
        let mut msg = zmq_sys::zmq_msg_t { unknown: [0; MSG_SIZE] };
        let rc = unsafe { zmq_sys::zmq_msg_init_size(&mut msg, len as size_t) };
        if rc == -1 {
            Err(Error::from_last_err())
        } else {
            Ok(Message { msg: msg })
        }
    }

    /// Initialise 0MQ message from a supplied std::vec::Vec<u8>.
    ///
    /// Binding of `int zmq_msg_init_data (zmq_msg_t *msg, void *data,
    ///    size_t size, zmq_free_fn *ffn, void *hint);`.
    ///
    /// The function will take ownership of the Vec and
    /// return a message object to represent the content referenced by the Vec.
    ///
    /// No copy of data will be performed.
    pub fn from_vec(vec: Vec<u8>) -> Result<Message, Error> {
        let len = vec.len() as size_t;
        let data = vec.into_boxed_slice();
        let free_fn = unsafe { transmute(zmq_free_fn) };

        let mut msg = zmq_sys::zmq_msg_t { unknown: [0; MSG_SIZE] };
        let rc = unsafe {
            zmq_sys::zmq_msg_init_data(&mut msg, Box::into_raw(data) as *mut c_void, len,
                free_fn, transmute(len))
            };
        if rc == -1 {
            Err(Error::from_last_err())
        } else {
            Ok(Message { msg: msg })
        }
    }

    /// Move content of a message to another message.
    ///
    /// Binding of `int zmq_msg_move (zmq_msg_t *dest, zmq_msg_t *src);`.
    ///
    /// Move the content of the message object referenced by src to the message object referenced by dest.
    /// No actual copying of message content is performed,
    /// dest is simply updated to reference the new content.
    /// src becomes an empty message after calling Message::msg_move().
    /// The original content of dest, if any, will be released
    pub fn msg_move(dest: &mut Message, src: &mut Message) -> Option<Error> {
        let rc = unsafe {
            zmq_sys::zmq_msg_move(&mut dest.msg, &mut src.msg)
        };
        if rc == -1 {
            Some(Error::from_last_err())
        } else {
            None
        }
    }

    /// Copy content of a message to another message.
    ///
    /// Binding of `int zmq_msg_copy (zmq_msg_t *dest, zmq_msg_t *src);`.
    ///
    /// Copy the message object referenced by src to the message object referenced by dest.
    /// The original content of dest, if any, will be released.
    pub fn msg_copy(dest: &mut Message, src: &Message) -> Option<Error> {
        let rc = unsafe {
            zmq_sys::zmq_msg_copy(&mut dest.msg, transmute(&src.msg))
        };
        if rc == -1 {
            Some(Error::from_last_err())
        } else {
            None
        }
    }

    /// Retrieve pointer to message content.
    ///
    /// Binding of `void *zmq_msg_data (zmq_msg_t *msg);`.
    ///
    /// The function will return a pointer to the message content.
    pub unsafe fn get_data_pointer(&mut self) -> *mut c_void {
        zmq_sys::zmq_msg_data(&mut self.msg)
    }
}

impl Drop for Message {
    fn drop(&mut self) {
        let rc = unsafe { zmq_sys::zmq_msg_close(&mut self.msg) };
        if rc != 0 {
            panic!(Error::from_last_err());
        }
    }
}

#[allow(non_camel_case_types)]
#[derive(Clone, Debug)]
pub enum SocketType {
    PAIR        = 0,
    PUB         = 1,
    SUB         = 2,
    REQ         = 3,
    REP         = 4,
    DEALER      = 5,
    ROUTER      = 6,
    PULL        = 7,
    PUSH        = 8,
    XPUB        = 9,
    XSUB        = 10,
    ZMQ_STREAM  = 11,
}

#[allow(non_camel_case_types)]
#[derive(Clone, Debug)]
pub enum SocketOption {
    AFFINITY = 4,
    IDENTITY = 5,
    SUBSCRIBE = 6,
    UNSUBSCRIBE = 7,
    RATE = 8,
    RECOVERY_IVL = 9,
    SNDBUF = 11,
    RCVBUF = 12,
    RCVMORE = 13,
    FD = 14,
    EVENTS = 15,
    TYPE = 16,
    LINGER = 17,
    RECONNECT_IVL = 18,
    BACKLOG = 19,
    RECONNECT_IVL_MAX = 21,
    MAXMSGSIZE = 22,
    SNDHWM = 23,
    RCVHWM = 24,
    MULTICAST_HOPS = 25,
    RCVTIMEO = 27,
    SNDTIMEO = 28,
    LAST_ENDPOINT = 32,
    ROUTER_MANDATORY = 33,
    TCP_KEEPALIVE = 34,
    TCP_KEEPALIVE_CNT = 35,
    TCP_KEEPALIVE_IDLE = 36,
    TCP_KEEPALIVE_INTVL = 37,
    IMMEDIATE = 39,
    XPUB_VERBOSE = 40,
    ROUTER_RAW = 41,
    IPV6 = 42,
    MECHANISM = 43,
    PLAIN_SERVER = 44,
    PLAIN_USERNAME = 45,
    PLAIN_PASSWORD = 46,
    CURVE_SERVER = 47,
    CURVE_PUBLICKEY = 48,
    CURVE_SECRETKEY = 49,
    CURVE_SERVERKEY = 50,
    PROBE_ROUTER = 51,
    REQ_CORRELATE = 52,
    REQ_RELAXED = 53,
    CONFLATE = 54,
    ZAP_DOMAIN = 55,
    ROUTER_HANDOVER = 56,
    TOS = 57,
    CONNECT_RID = 61,
    GSSAPI_SERVER = 62,
    GSSAPI_PRINCIPAL = 63,
    GSSAPI_SERVICE_PRINCIPAL = 64,
    GSSAPI_PLAINTEXT = 65,
    HANDSHAKE_IVL = 66,
    SOCKS_PROXY = 68,
    XPUB_NODROP = 69,
}

#[allow(non_camel_case_types)]
#[derive(Clone, Debug)]
pub enum MessageOption {
    MORE        = 1,
    SRCFD       = 2,
    SHARED      = 3,
}

#[allow(non_camel_case_types)]
#[derive(Clone, Debug)]
pub enum SendRecvOption {
    DONTWAIT    = 1,
    SNDMORE     = 2,
}

#[allow(non_camel_case_types)]
#[derive(Clone, Debug)]
pub enum SecurityMechanism {
    ZMQ_NULL    = 0,
    ZMQ_PLAIN   = 1,
    ZMQ_CURVE   = 2,
    ZMQ_GSSAPI  = 3,
}

#[allow(non_camel_case_types)]
#[derive(Clone, Debug)]
pub enum SocketEvent {
    CONNECTED         = 0x0001,
    CONNECT_DELAYED   = 0x0002,
    CONNECT_RETRIED   = 0x0004,
    LISTENING         = 0x0008,
    BIND_FAILED       = 0x0010,
    ACCEPTED          = 0x0020,
    ACCEPT_FAILED     = 0x0040,
    CLOSED            = 0x0080,
    CLOSE_FAILED      = 0x0100,
    DISCONNECTED      = 0x0200,
    MONITOR_STOPPED   = 0x0400,
    ALL               = 0xFFFF,
}

pub struct Socket {
    socket_ptr: *mut c_void,
}

impl Socket {

}
<|endoftext|>


<commit_before>// Copyright 2014-2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! # Rust-bio, a bioinformatics library for Rust.
//! This library provides implementations of many algorithms and data structures
//! that are useful for bioinformatics.
//! All provided implementations are rigorously tested via continuous
//! integration.
//!
//! For **getting started** with using `rust-bio`, see [the `Getting started` section below](#getting-started).
//! For navigating the documentation of the available modules, see [the `Modules` section below](#modules).
//! If you want to contribute to `rust-bio`, see [the `Contribute` section in the repo](https://github.com/rust-bio/rust-bio#contribute).
//!
//! Currently, rust-bio provides
//!
//! * most major pattern matching algorithms,
//! * a convenient alphabet implementation,
//! * pairwise alignment,
//! * suffix arrays,
//! * the [Burrows-Wheeler-transform (BWT)]()
//! * the [Full-text index in Minute space index (FM-index)](https://doi.org/10.1109/SFCS.2000.892127),
//! * FMD-Index for finding supermaximal exact matches,
//! * a q-gram index,
//! * utilities to work with [PSSMs](https://en.wikipedia.org/wiki/Position_weight_matrix),
//! * an open reading frame (ORF) search algorithm,
//! * a rank/select data structure,
//! * [serde](https://github.com/serde-rs/serde) support for all data structures when built with `nightly` feature,
//! * readers and writers for FASTQ, FASTA and BED,
//! * helper functions for combinatorics and dealing with log probabilities,
//! * an implementation of the Hidden Markov Model and related algorithms.
//!
//! For reading and writing SAM/BAM/CRAM, VCF/BCF files or tabix indexed files, have a look at [rust-htslib](https://docs.rs/rust-htslib).
//!
//! # Getting started
//!
//! We explain how to use Rust-Bio step-by-step.
//! Users who already have experience with Rust can skip right to [Step 3: Use Rust-Bio in your project](https://docs.rs/bio/#step-3-use-rust-bio-in-your-project).
//! Users who already know `rust-bio` might want to jump right into the [modules docs](https://docs.rs/bio/#modules)
//!
//! ## Step 1: Setting up Rust
//!
//! Rust can be installed following the instruction for [rustup](https://rustup.rs/).
//!
//!
//! ## Step 2: Setting up a new Rust project
//!
//! Since Rust-Bio is a library, you need to setup your own new Rust project to use Rust-Bio.
//! With Rust, projects and their dependencies are managed with the builtin package manager [Cargo](https://doc.rust-lang.org/cargo/index.html).
//! To create a new Rust project, issue
//!
//! ```bash
//! cargo new hello_world --bin
//! cd hello_world
//! ```
//! in your terminal. The flag `--bin` tells Cargo to create an executable project instead of a library.
//! In [this section](https://doc.rust-lang.org/nightly/book/hello-cargo.html#a-new-project) of the Rust docs, you find details about what Cargo just created for you.
//!
//! Your new project can be compiled with
//! ```bash
//! cargo build
//! ```
//! If dependencies in your project are out of date, update with
//! ```bash
//! cargo update
//! ```
//! Execute the compiled code with
//! ```bash
//! cargo run
//! ```
//! If you are new to Rust, we suggest to proceed with [learning Rust](https://www.rust-lang.org/learn) via the Rust docs.
//!
//! ## Step 3: Use Rust-Bio in your project
//!
//! To use Rust-Bio in your Rust project, add the following to your `Cargo.toml`
//!
//! ```toml
//! [dependencies]
//! bio = "*"
//! ```
//!
//! and import the crate from your source code:
//!
//! ```rust
//! extern crate bio;
//! ```
//!
//! ## Example: FM-index and FASTQ
//!
//! An example of using `rust-bio`:
//!
//! ```rust
//! // Import some modules
//! use bio::alphabets;
//! use bio::data_structures::bwt::{bwt, less, Occ};
//! use bio::data_structures::fmindex::{FMIndex, FMIndexable};
//! use bio::data_structures::suffix_array::suffix_array;
//! use bio::io::fastq;
//! use bio::io::fastq::FastqRead;
//! use std::io;
//!
//! // a given text
//! let text = b"ACAGCTCGATCGGTA$";
//! let pattern = b"ATCG";
//!
//! // Create an FM-Index for the given text.
//!
//! // instantiate an alphabet
//! let alphabet = alphabets::dna::iupac_alphabet();
//! // calculate a suffix array
//! let sa = suffix_array(text);
//! // calculate the Burrows-Wheeler-transform
//! let bwt = bwt(text, &sa);
//! // calculate the vectors less and Occ (occurrences)
//! let less = less(&bwt, &alphabet);
//! let occ = Occ::new(&bwt, 3, &alphabet);
//! // set up FMIndex
//! let fmindex = FMIndex::new(&bwt, &less, &occ);
//! // do a backwards search for the pattern
//! let interval = fmindex.backward_search(pattern.iter());
//! let positions = interval.occ(&sa);
//!
//! // Iterate over a FASTQ file, use the alphabet to validate read
//! // sequences and search for exact matches in the FM-Index.
//!
//! // create FASTQ reader
//! let mut reader = fastq::Reader::new(io::stdin());
//! let mut record = fastq::Record::new();
//! reader.read(&mut record).expect("Failed to parse record");
//! while !record.is_empty() {
//!     let check = record.check();
//!     if check.is_err() {
//!         panic!("I got a rubbish record!")
//!     }
//!     // obtain sequence
//!     let seq = record.seq();
//!     // check, whether seq is in the expected alphabet
//!     if alphabet.is_word(seq) {
//!         let interval = fmindex.backward_search(seq.iter());
//!         let positions = interval.occ(&positions);
//!     }
//!     reader.read(&mut record).expect("Failed to parse record");
//! }
//! ```
//!
//! Documentation and further examples for each module can be found in the module descriptions below.
//!
//!
//! ## Example: Multithreaded
//!
//! ```rust
//! use bio::alphabets;
//! use bio::data_structures::bwt::{bwt, less, Occ};
//! use bio::data_structures::fmindex::{FMIndex, FMIndexable};
//! use bio::data_structures::suffix_array::suffix_array;
//! use std::sync::Arc;
//! use std::thread;
//!
//! let text = b"ACGGATGCTGGATCGGATCGCGCTAGCTA$";
//! let patterns = vec![b"ACCG", b"TGCT"];
//!
//! // Create an FM-Index for a given text.
//! let alphabet = alphabets::dna::iupac_alphabet();
//! let sa = suffix_array(text);
//! let bwt = Arc::new(bwt(text, &sa));
//! let less = Arc::new(less(bwt.as_ref(), &alphabet));
//! let occ = Arc::new(Occ::new(bwt.as_ref(), 3, &alphabet));
//! let fmindex = Arc::new(FMIndex::new(bwt, less, occ));
//!
//! // Spawn threads to perform backward searches for each interval
//! let interval_calculators = patterns
//!     .into_iter()
//!     .map(|pattern| {
//!         let fmindex = fmindex.clone();
//!         thread::spawn(move || fmindex.backward_search(pattern.iter()))
//!     })
//!     .collect::<Vec<_>>();
//!
//! // Loop through the results, extracting the positions array for each pattern
//! for interval_calculator in interval_calculators {
//!     let positions = interval_calculator.join().unwrap().occ(&sa);
//! }
//! ```
//!
//! Documentation and further examples for each module can be found in the module descriptions below.
//!
//! # Benchmarks
//!
//! Since Rust-Bio is based on a compiled language, similar performance to C/C++ based libraries can be expected. Indeed, we find the pattern matching algorithms of Rust-Bio to perform in the range of the C++ library Seqan:
//!
//! | Algorithm | Rust-Bio | Seqan   |
//! | --------- | -------: | ------: |
//! | BNDM      | 77ms     | 80ms    |
//! | Horspool  | 122ms    | 125ms   |
//! | BOM       | 103ms    | 107ms   |
//! | Shift-And | 241ms    | 545ms   |
//!
//! We measured 10000 iterations of searching pattern `GCGCGTACACACCGCCCG` in the sequence of the hg38 MT chromosome.
//! Initialization time of each algorithm for the given pattern was included in each iteration. Benchmarks were conducted with *Cargo bench* for Rust-Bio and *Python timeit* for Seqan on an Intel Core i5-3427U CPU.
//! Benchmarking Seqan from *Python timeit* entails an overhead of 1.46ms for calling a C++ binary. This overhead was subtracted from above Seqan run times.
//! Note that this benchmark only compares the two libraries to exemplify that Rust-Bio has comparable speed to C++ libraries: all used algorithms have their advantages for specific text and pattern structures and lengths (see [the pattern matching section in the documentation](https://docs.rs/bio/0.28.2/bio/pattern_matching/index.html))./!

#[macro_use]
extern crate approx;

#[macro_use]
extern crate custom_derive;

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate newtype_derive;

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate strum_macros;

#[macro_use]
extern crate snafu;

#[macro_use]
extern crate getset;

pub mod alignment;
pub mod alphabets;
pub mod data_structures;
pub mod io;
pub mod pattern_matching;
pub mod scores;
pub mod seq_analysis;
pub mod stats;
pub mod utils;
<commit_msg>add BioFerris to rustdoc! (#378)<commit_after>// Copyright 2014-2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

#![doc(
    html_logo_url = "https://raw.githubusercontent.com/rust-bio/rust-bio/master/img/bioferris.svg",
    html_favicon_url = "https://raw.githubusercontent.com/rust-bio/rust-bio/master/img/bioferris.svg"
)]

//! # Rust-bio, a bioinformatics library for Rust.
//! This library provides implementations of many algorithms and data structures
//! that are useful for bioinformatics.
//! All provided implementations are rigorously tested via continuous
//! integration.
//!
//! For **getting started** with using `rust-bio`, see [the `Getting started` section below](#getting-started).
//! For navigating the documentation of the available modules, see [the `Modules` section below](#modules).
//! If you want to contribute to `rust-bio`, see [the `Contribute` section in the repo](https://github.com/rust-bio/rust-bio#contribute).
//!
//! Currently, rust-bio provides
//!
//! * most major pattern matching algorithms,
//! * a convenient alphabet implementation,
//! * pairwise alignment,
//! * suffix arrays,
//! * the [Burrows-Wheeler-transform (BWT)]()
//! * the [Full-text index in Minute space index (FM-index)](https://doi.org/10.1109/SFCS.2000.892127),
//! * FMD-Index for finding supermaximal exact matches,
//! * a q-gram index,
//! * utilities to work with [PSSMs](https://en.wikipedia.org/wiki/Position_weight_matrix),
//! * an open reading frame (ORF) search algorithm,
//! * a rank/select data structure,
//! * [serde](https://github.com/serde-rs/serde) support for all data structures when built with `nightly` feature,
//! * readers and writers for FASTQ, FASTA and BED,
//! * helper functions for combinatorics and dealing with log probabilities,
//! * an implementation of the Hidden Markov Model and related algorithms.
//!
//! For reading and writing SAM/BAM/CRAM, VCF/BCF files or tabix indexed files, have a look at [rust-htslib](https://docs.rs/rust-htslib).
//!
//! # Getting started
//!
//! We explain how to use Rust-Bio step-by-step.
//! Users who already have experience with Rust can skip right to [Step 3: Use Rust-Bio in your project](https://docs.rs/bio/#step-3-use-rust-bio-in-your-project).
//! Users who already know `rust-bio` might want to jump right into the [modules docs](https://docs.rs/bio/#modules)
//!
//! ## Step 1: Setting up Rust
//!
//! Rust can be installed following the instruction for [rustup](https://rustup.rs/).
//!
//!
//! ## Step 2: Setting up a new Rust project
//!
//! Since Rust-Bio is a library, you need to setup your own new Rust project to use Rust-Bio.
//! With Rust, projects and their dependencies are managed with the builtin package manager [Cargo](https://doc.rust-lang.org/cargo/index.html).
//! To create a new Rust project, issue
//!
//! ```bash
//! cargo new hello_world --bin
//! cd hello_world
//! ```
//! in your terminal. The flag `--bin` tells Cargo to create an executable project instead of a library.
//! In [this section](https://doc.rust-lang.org/nightly/book/hello-cargo.html#a-new-project) of the Rust docs, you find details about what Cargo just created for you.
//!
//! Your new project can be compiled with
//! ```bash
//! cargo build
//! ```
//! If dependencies in your project are out of date, update with
//! ```bash
//! cargo update
//! ```
//! Execute the compiled code with
//! ```bash
//! cargo run
//! ```
//! If you are new to Rust, we suggest to proceed with [learning Rust](https://www.rust-lang.org/learn) via the Rust docs.
//!
//! ## Step 3: Use Rust-Bio in your project
//!
//! To use Rust-Bio in your Rust project, add the following to your `Cargo.toml`
//!
//! ```toml
//! [dependencies]
//! bio = "*"
//! ```
//!
//! and import the crate from your source code:
//!
//! ```rust
//! extern crate bio;
//! ```
//!
//! ## Example: FM-index and FASTQ
//!
//! An example of using `rust-bio`:
//!
//! ```rust
//! // Import some modules
//! use bio::alphabets;
//! use bio::data_structures::bwt::{bwt, less, Occ};
//! use bio::data_structures::fmindex::{FMIndex, FMIndexable};
//! use bio::data_structures::suffix_array::suffix_array;
//! use bio::io::fastq;
//! use bio::io::fastq::FastqRead;
//! use std::io;
//!
//! // a given text
//! let text = b"ACAGCTCGATCGGTA$";
//! let pattern = b"ATCG";
//!
//! // Create an FM-Index for the given text.
//!
//! // instantiate an alphabet
//! let alphabet = alphabets::dna::iupac_alphabet();
//! // calculate a suffix array
//! let sa = suffix_array(text);
//! // calculate the Burrows-Wheeler-transform
//! let bwt = bwt(text, &sa);
//! // calculate the vectors less and Occ (occurrences)
//! let less = less(&bwt, &alphabet);
//! let occ = Occ::new(&bwt, 3, &alphabet);
//! // set up FMIndex
//! let fmindex = FMIndex::new(&bwt, &less, &occ);
//! // do a backwards search for the pattern
//! let interval = fmindex.backward_search(pattern.iter());
//! let positions = interval.occ(&sa);
//!
//! // Iterate over a FASTQ file, use the alphabet to validate read
//! // sequences and search for exact matches in the FM-Index.
//!
//! // create FASTQ reader
//! let mut reader = fastq::Reader::new(io::stdin());
//! let mut record = fastq::Record::new();
//! reader.read(&mut record).expect("Failed to parse record");
//! while !record.is_empty() {
//!     let check = record.check();
//!     if check.is_err() {
//!         panic!("I got a rubbish record!")
//!     }
//!     // obtain sequence
//!     let seq = record.seq();
//!     // check, whether seq is in the expected alphabet
//!     if alphabet.is_word(seq) {
//!         let interval = fmindex.backward_search(seq.iter());
//!         let positions = interval.occ(&positions);
//!     }
//!     reader.read(&mut record).expect("Failed to parse record");
//! }
//! ```
//!
//! Documentation and further examples for each module can be found in the module descriptions below.
//!
//!
//! ## Example: Multithreaded
//!
//! ```rust
//! use bio::alphabets;
//! use bio::data_structures::bwt::{bwt, less, Occ};
//! use bio::data_structures::fmindex::{FMIndex, FMIndexable};
//! use bio::data_structures::suffix_array::suffix_array;
//! use std::sync::Arc;
//! use std::thread;
//!
//! let text = b"ACGGATGCTGGATCGGATCGCGCTAGCTA$";
//! let patterns = vec![b"ACCG", b"TGCT"];
//!
//! // Create an FM-Index for a given text.
//! let alphabet = alphabets::dna::iupac_alphabet();
//! let sa = suffix_array(text);
//! let bwt = Arc::new(bwt(text, &sa));
//! let less = Arc::new(less(bwt.as_ref(), &alphabet));
//! let occ = Arc::new(Occ::new(bwt.as_ref(), 3, &alphabet));
//! let fmindex = Arc::new(FMIndex::new(bwt, less, occ));
//!
//! // Spawn threads to perform backward searches for each interval
//! let interval_calculators = patterns
//!     .into_iter()
//!     .map(|pattern| {
//!         let fmindex = fmindex.clone();
//!         thread::spawn(move || fmindex.backward_search(pattern.iter()))
//!     })
//!     .collect::<Vec<_>>();
//!
//! // Loop through the results, extracting the positions array for each pattern
//! for interval_calculator in interval_calculators {
//!     let positions = interval_calculator.join().unwrap().occ(&sa);
//! }
//! ```
//!
//! Documentation and further examples for each module can be found in the module descriptions below.
//!
//! # Benchmarks
//!
//! Since Rust-Bio is based on a compiled language, similar performance to C/C++ based libraries can be expected. Indeed, we find the pattern matching algorithms of Rust-Bio to perform in the range of the C++ library Seqan:
//!
//! | Algorithm | Rust-Bio | Seqan   |
//! | --------- | -------: | ------: |
//! | BNDM      | 77ms     | 80ms    |
//! | Horspool  | 122ms    | 125ms   |
//! | BOM       | 103ms    | 107ms   |
//! | Shift-And | 241ms    | 545ms   |
//!
//! We measured 10000 iterations of searching pattern `GCGCGTACACACCGCCCG` in the sequence of the hg38 MT chromosome.
//! Initialization time of each algorithm for the given pattern was included in each iteration. Benchmarks were conducted with *Cargo bench* for Rust-Bio and *Python timeit* for Seqan on an Intel Core i5-3427U CPU.
//! Benchmarking Seqan from *Python timeit* entails an overhead of 1.46ms for calling a C++ binary. This overhead was subtracted from above Seqan run times.
//! Note that this benchmark only compares the two libraries to exemplify that Rust-Bio has comparable speed to C++ libraries: all used algorithms have their advantages for specific text and pattern structures and lengths (see [the pattern matching section in the documentation](https://docs.rs/bio/0.28.2/bio/pattern_matching/index.html))./!

#[macro_use]
extern crate approx;

#[macro_use]
extern crate custom_derive;

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate newtype_derive;

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate strum_macros;

#[macro_use]
extern crate snafu;

#[macro_use]
extern crate getset;

pub mod alignment;
pub mod alphabets;
pub mod data_structures;
pub mod io;
pub mod pattern_matching;
pub mod scores;
pub mod seq_analysis;
pub mod stats;
pub mod utils;
<|endoftext|>