<commit_before>#![feature(collections,std_misc,core,old_path,old_io)]
// This library is inspired by Rodrigo Palacios's excellent
// explanation of autocompletion that can be found here:
// https://github.com/rodricios/autocomplete
use std::old_io::File;
use std::old_io::BufferedReader;
use std::cmp::{Ord,PartialOrd,Ordering};
use std::collections::HashMap;
use std::collections::hash_map::Entry;

/// Single-word entry trainer
///
/// SimpleWordTrainer uses a HashMap representation to train on word
/// frequency. It is fast for looking up words and incrementing their
/// count but since HashMap does not keep track of order, searching the
/// keys of a hashmap takes a long time. After the model is trained it
/// must be converted to a SimpleWordPredictor which stores the words
/// in lexical order and has an index of first letters.
#[derive(Debug)]
pub struct SimpleWordTrainer(HashMap<String, u32>);

/// Single-word prediction engine
///
/// SimpleWordPredictor uses a constant sized vector of entries indexed by
/// first letter. Prediction starts from that index and continues until
/// the first letter in the vector changes.
#[derive(Debug)]
pub struct SimpleWordPredictor {
    entries: Vec<PredictionEntry>,
    ixs: HashMap<char, u32>,
}

/// Struct returned by prediction engines.
#[derive(Debug)]
pub struct PredictionEntry {
    pub word: String,
    pub score: u32,
}

impl Clone for PredictionEntry {
    fn clone(&self) -> Self {
        PredictionEntry {
            word: self.word.clone(),
            score: self.score
        }
    }
}

// Eq, PartialEq, PartialOrd and Ord are necessary to be able to
// .sort() a vec<PredictionEntry>.
impl Eq for PredictionEntry { }

impl PartialEq for PredictionEntry {
    fn eq(&self, other: &Self) -> bool {
        self.word.eq(&other.word)
    }
}

impl PartialOrd for PredictionEntry {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.word.partial_cmp(&other.word)
    }
}

impl Ord for PredictionEntry {
    fn cmp(&self, other: &Self) -> Ordering {
        self.word.cmp(&other.word)
    }
}

impl SimpleWordPredictor {
    // Given an input string, return the top 10 suggestions based on
    // training data.
    pub fn predict(&self, input: &str) -> Vec<PredictionEntry> {
        let mut predictions: Vec<PredictionEntry> = Vec::new();
        let iter = self.entries.iter();
        let first_letter = input.char_at(0);
        let skip_n = self.ixs.get(&first_letter);

        match skip_n {
            Some(n) => {
                let iter = iter.skip(*n as usize);
                for entry in iter {
                    let word = entry.word.as_slice();
                    if word.char_at(0) != first_letter {
                        break;
                    }

                    if word.starts_with(input) {
                        predictions.push(entry.clone());
                    }
                }

                predictions.sort_by(|a, b| {
                    b.score.cmp(&a.score)
                });

                predictions.truncate(10);

                predictions
            },
            None => {
                return predictions;
            },
        }
    }

    // Load training data from a CSV file.
    pub fn from_file(path: &Path) -> SimpleWordPredictor {
        let mut entries = Vec::new();
        let mut file = BufferedReader::new(File::open(path));
        for line_res in file.lines() {
            let line = line_res.unwrap();
            let line = line.trim();
            let str_entry: Vec<&str> = line.split(',').collect();
            let word: String = String::from_str(str_entry[0]);
            let n = str_entry[1].parse().ok().unwrap();
            entries.push(PredictionEntry {word: word, score: n});
        }

        let ixs = generate_ixs(&entries);

        SimpleWordPredictor {entries: entries, ixs: ixs}
    }

    // Save training data to a CSV file.
    pub fn to_file(&self, path: &Path) {
        let mut file = File::create(path);
        for entry in &self.entries {
            write!(&mut file, "{},{}\n", &entry.word, entry.score)
                .unwrap();
        }
    }
}

impl SimpleWordTrainer {
    pub fn from_str(input: &str) -> SimpleWordTrainer {
        let model_hm: HashMap<String, u32> = HashMap::new();
        let mut model = SimpleWordTrainer(model_hm);
        let v_input = input.split(' ').collect();
        count_words(&mut model, &v_input);

        model
    }

    pub fn from_vec(input: &Vec<&str>) -> SimpleWordTrainer {
        let model_hm: HashMap<String, u32> = HashMap::new();
        let mut model = SimpleWordTrainer(model_hm);

        count_words(&mut model, input);

        model
    }

    pub fn new() -> SimpleWordTrainer {
        let model_hm: HashMap<String, u32> = HashMap::new();

        SimpleWordTrainer(model_hm)
    }

    pub fn train_str(&mut self, input: &str) {
        let v_input = input.split(' ').collect();
        count_words(self, &v_input);
    }

    pub fn train_vec(&mut self, input: Vec<&str>) {
        count_words(self, &input);
    }

    // Convert the HashMap representation to an indexed vec.
    pub fn finalize(self) -> SimpleWordPredictor {
        let SimpleWordTrainer(hm) = self;
        let size = hm.len();
        let mut entries = Vec::with_capacity(size);

        for (key, value) in hm {
            entries.push(PredictionEntry {word: key, score: value});
        }

        entries.sort();

        let ixs = generate_ixs(&entries);
        SimpleWordPredictor {entries: entries, ixs: ixs}
    }
}

fn generate_ixs(entries: &Vec<PredictionEntry>) -> HashMap<char, u32>{
    let mut ixs: HashMap<char, u32> = HashMap::new();

    // There will be no newlines in the input. This is a placeholder
    // until the first time the loop runs.
    let mut last_c = '\n';
    let mut ix = 0;

    for entry in entries {
        let c = entry.word.char_at(0);
        if c != last_c {
            ixs.insert(c, ix);
            last_c = c;
        }
        ix += 1;
    }

    ixs
}

fn count_words(model: &mut SimpleWordTrainer, input: &Vec<&str>) {
    let &mut SimpleWordTrainer(ref mut model_hm) = model;
    for word in input {
        if word.len() == 0 {
            continue;
        }
        let string_word = String::from_str(*word);
        let entry = model_hm.entry(string_word);
        match entry {
            Entry::Vacant(vacant_entry) => {
                vacant_entry.insert(1);
            },
            Entry::Occupied(mut occ_entry) => {
                let c = occ_entry.get_mut();
                *c += 1;
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use SimpleWordTrainer;

    #[test]
    fn test_from_str() {
        let model = SimpleWordTrainer::from_str("world domination is my profession hello hello");

        let SimpleWordTrainer(hash_map) = model;

        assert_eq!(1, *hash_map.get("world").unwrap());
        assert_eq!(2, *hash_map.get("hello").unwrap());
    }

    #[test]
    fn test_from_vec() {
        let model = SimpleWordTrainer::from_vec(&vec!["rabbit", "rabbit", "hare"]);

        let SimpleWordTrainer(hash_map) = model;

        assert_eq!(1, *hash_map.get("hare").unwrap());
        assert_eq!(2, *hash_map.get("rabbit").unwrap());
    }

    #[test]
    fn test_train_str() {
        let mut model = SimpleWordTrainer::new();

        model.train_str("hello hello hello there there");

        let SimpleWordTrainer(hash_map) = model;
        assert_eq!(3, *hash_map.get("hello").unwrap());
        assert_eq!(2, *hash_map.get("there").unwrap());
    }

    #[test]
    fn test_train_vec() {
        let mut model = SimpleWordTrainer::new();

        model.train_vec(vec!["hello", "hello", "hello", "what",
                             "is", "this"]);

        let SimpleWordTrainer(hash_map) = model;
        assert_eq!(3, *hash_map.get("hello").unwrap());
        assert_eq!(1, *hash_map.get("what").unwrap());
    }

    #[test]
    fn test_finalize() {
        let mut model = SimpleWordTrainer::new();

        model.train_str(concat!["anybody can become angry that is easy but to be ",
                                "angry with the right person and to the right degree ",
                                "and at the right time and for the right purpose ",
                                "and in the right way that is not within everybody's ",
                                "power and is not easy"]);

        let predictor = model.finalize();

        assert_eq!(predictor.entries[0].word, "and");
        assert_eq!(predictor.entries[0].score, 5);
    }

    #[test]
    fn test_predict() {
        let mut model = SimpleWordTrainer::new();

        model.train_str(concat!["anybody can become angry that is easy but to be ",
                                "angry with the right person and to the right degree ",
                                "and at the right time and for the right purpose ",
                                "and in the right way that is not within everybody's ",
                                "power and is not easy"]);

        let predictor = model.finalize();
        println!("{:?}", predictor.predict("a"));
    }

}
<commit_msg>Added rustdoc.<commit_after>#![feature(collections,std_misc,core,old_path,old_io)]
// This library is inspired by Rodrigo Palacios's excellent
// explanation of autocompletion that can be found here:
// https://github.com/rodricios/autocomplete
use std::old_io::File;
use std::old_io::BufferedReader;
use std::cmp::{Ord,PartialOrd,Ordering};
use std::collections::HashMap;
use std::collections::hash_map::Entry;

/// Single-word entry trainer
///
/// SimpleWordTrainer uses a HashMap representation to train on word
/// frequency. It is fast for looking up words and incrementing their
/// count but since HashMap does not keep track of order, searching the
/// keys of a hashmap takes a long time. After the model is trained it
/// must be converted to a SimpleWordPredictor which stores the words
/// in lexical order and has an index of first letters.
#[derive(Debug)]
pub struct SimpleWordTrainer(HashMap<String, u32>);

/// Single-word prediction engine
///
/// SimpleWordPredictor uses a constant sized vector of entries indexed by
/// first letter. Prediction starts from that index and continues until
/// the first letter in the vector changes.
#[derive(Debug)]
pub struct SimpleWordPredictor {
    entries: Vec<PredictionEntry>,
    ixs: HashMap<char, u32>,
}

/// Struct returned by prediction engines.
#[derive(Debug)]
pub struct PredictionEntry {
    pub word: String,
    pub score: u32,
}

impl Clone for PredictionEntry {
    fn clone(&self) -> Self {
        PredictionEntry {
            word: self.word.clone(),
            score: self.score
        }
    }
}

// Eq, PartialEq, PartialOrd and Ord are necessary to be able to
// .sort() a vec<PredictionEntry>.
impl Eq for PredictionEntry { }

impl PartialEq for PredictionEntry {
    fn eq(&self, other: &Self) -> bool {
        self.word.eq(&other.word)
    }
}

impl PartialOrd for PredictionEntry {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.word.partial_cmp(&other.word)
    }
}

impl Ord for PredictionEntry {
    fn cmp(&self, other: &Self) -> Ordering {
        self.word.cmp(&other.word)
    }
}

impl SimpleWordPredictor {
    /// Given an initial input string, return 10 predictions.
    pub fn predict(&self, input: &str) -> Vec<PredictionEntry> {
        let mut predictions: Vec<PredictionEntry> = Vec::new();
        let iter = self.entries.iter();
        let first_letter = input.char_at(0);
        let skip_n = self.ixs.get(&first_letter);

        match skip_n {
            Some(n) => {
                let iter = iter.skip(*n as usize);
                for entry in iter {
                    let word = entry.word.as_slice();
                    if word.char_at(0) != first_letter {
                        break;
                    }

                    if word.starts_with(input) {
                        predictions.push(entry.clone());
                    }
                }

                predictions.sort_by(|a, b| {
                    b.score.cmp(&a.score)
                });

                predictions.truncate(10);

                predictions
            },
            None => {
                return predictions;
            },
        }
    }

    /// Load training data from a CSV file.
    pub fn from_file(path: &Path) -> SimpleWordPredictor {
        let mut entries = Vec::new();
        let mut file = BufferedReader::new(File::open(path));
        for line_res in file.lines() {
            let line = line_res.unwrap();
            let line = line.trim();
            let str_entry: Vec<&str> = line.split(',').collect();
            let word: String = String::from_str(str_entry[0]);
            let n = str_entry[1].parse().ok().unwrap();
            entries.push(PredictionEntry {word: word, score: n});
        }

        let ixs = generate_ixs(&entries);

        SimpleWordPredictor {entries: entries, ixs: ixs}
    }

    /// Save training data to a CSV file.
    pub fn to_file(&self, path: &Path) {
        let mut file = File::create(path);
        for entry in &self.entries {
            write!(&mut file, "{},{}\n", &entry.word, entry.score)
                .unwrap();
        }
    }
}

impl SimpleWordTrainer {
    /// Create a trainer trained on an initial str.
    pub fn from_str(input: &str) -> SimpleWordTrainer {
        let model_hm: HashMap<String, u32> = HashMap::new();
        let mut model = SimpleWordTrainer(model_hm);
        let v_input = input.split(' ').collect();
        count_words(&mut model, &v_input);

        model
    }

    /// Create a trainer trained on an initial vector strs.
    pub fn from_vec(input: &Vec<&str>) -> SimpleWordTrainer {
        let model_hm: HashMap<String, u32> = HashMap::new();
        let mut model = SimpleWordTrainer(model_hm);

        count_words(&mut model, input);

        model
    }

    /// Create a new untrained trainer.
    pub fn new() -> SimpleWordTrainer {
        let model_hm: HashMap<String, u32> = HashMap::new();

        SimpleWordTrainer(model_hm)
    }

    /// Train the model on a string that will be split on spaces.
    pub fn train_str(&mut self, input: &str) {
        let v_input = input.split(' ').collect();
        count_words(self, &v_input);
    }

    /// Train the model on a vector of words.
    pub fn train_vec(&mut self, input: Vec<&str>) {
        count_words(self, &input);
    }

    /// Perform the calculations needed to predict the next word.
    pub fn finalize(self) -> SimpleWordPredictor {
        let SimpleWordTrainer(hm) = self;
        let size = hm.len();
        let mut entries = Vec::with_capacity(size);

        for (key, value) in hm {
            entries.push(PredictionEntry {word: key, score: value});
        }

        entries.sort();

        let ixs = generate_ixs(&entries);
        SimpleWordPredictor {entries: entries, ixs: ixs}
    }
}

fn generate_ixs(entries: &Vec<PredictionEntry>) -> HashMap<char, u32>{
    let mut ixs: HashMap<char, u32> = HashMap::new();

    // There will be no newlines in the input. This is a placeholder
    // until the first time the loop runs.
    let mut last_c = '\n';
    let mut ix = 0;

    for entry in entries {
        let c = entry.word.char_at(0);
        if c != last_c {
            ixs.insert(c, ix);
            last_c = c;
        }
        ix += 1;
    }

    ixs
}

fn count_words(model: &mut SimpleWordTrainer, input: &Vec<&str>) {
    let &mut SimpleWordTrainer(ref mut model_hm) = model;
    for word in input {
        if word.len() == 0 {
            continue;
        }
        let string_word = String::from_str(*word);
        let entry = model_hm.entry(string_word);
        match entry {
            Entry::Vacant(vacant_entry) => {
                vacant_entry.insert(1);
            },
            Entry::Occupied(mut occ_entry) => {
                let c = occ_entry.get_mut();
                *c += 1;
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use SimpleWordTrainer;

    #[test]
    fn test_from_str() {
        let model = SimpleWordTrainer::from_str("world domination is my profession hello hello");

        let SimpleWordTrainer(hash_map) = model;

        assert_eq!(1, *hash_map.get("world").unwrap());
        assert_eq!(2, *hash_map.get("hello").unwrap());
    }

    #[test]
    fn test_from_vec() {
        let model = SimpleWordTrainer::from_vec(&vec!["rabbit", "rabbit", "hare"]);

        let SimpleWordTrainer(hash_map) = model;

        assert_eq!(1, *hash_map.get("hare").unwrap());
        assert_eq!(2, *hash_map.get("rabbit").unwrap());
    }

    #[test]
    fn test_train_str() {
        let mut model = SimpleWordTrainer::new();

        model.train_str("hello hello hello there there");

        let SimpleWordTrainer(hash_map) = model;
        assert_eq!(3, *hash_map.get("hello").unwrap());
        assert_eq!(2, *hash_map.get("there").unwrap());
    }

    #[test]
    fn test_train_vec() {
        let mut model = SimpleWordTrainer::new();

        model.train_vec(vec!["hello", "hello", "hello", "what",
                             "is", "this"]);

        let SimpleWordTrainer(hash_map) = model;
        assert_eq!(3, *hash_map.get("hello").unwrap());
        assert_eq!(1, *hash_map.get("what").unwrap());
    }

    #[test]
    fn test_finalize() {
        let mut model = SimpleWordTrainer::new();

        model.train_str(concat!["anybody can become angry that is easy but to be ",
                                "angry with the right person and to the right degree ",
                                "and at the right time and for the right purpose ",
                                "and in the right way that is not within everybody's ",
                                "power and is not easy"]);

        let predictor = model.finalize();

        assert_eq!(predictor.entries[0].word, "and");
        assert_eq!(predictor.entries[0].score, 5);
    }

    #[test]
    fn test_predict() {
        let mut model = SimpleWordTrainer::new();

        model.train_str(concat!["anybody can become angry that is easy but to be ",
                                "angry with the right person and to the right degree ",
                                "and at the right time and for the right purpose ",
                                "and in the right way that is not within everybody's ",
                                "power and is not easy"]);

        let predictor = model.finalize();
        println!("{:?}", predictor.predict("a"));
    }

}
<|endoftext|>


<commit_before>extern crate rayon;

use std::cmp;

mod operator;
pub use operator::{Neg, Not,
                   Add, Sub, Mul, Div,
                   BitOr, BitAnd, BitXor};
mod raw;
pub use raw::{Zip, Map};

pub mod iterators;

mod simple;
pub use simple::{Value, Constant};

const MIN_THRESHOLD: usize = 1000;
const MAX_COUNT: usize = 20;

fn join<F: Send + FnOnce(), G: Send + FnOnce()>(f: F, g: G) {
    rayon::join(f, g);
}

pub fn evaluate<E>(dst: &mut [E::Element], e: E)
    where E: Expression + Send, E::Element: Send
{
    let len = dst.len();

    eval_inner(dst, e, cmp::max(len / MAX_COUNT, MIN_THRESHOLD));
}

fn eval_inner<E>(dst: &mut [E::Element], e: E, threshold: usize)
    where E: Expression + Send, E::Element: Send
{
    let len = dst.len();
    assert!(e.len().compatible(Length::Finite(len)));

    if len > threshold {
        let (low, high) = dst.split_at_mut(len / 2);
        let (e_low, e_high) = e.split();
        join(|| eval_inner(low, e_low, threshold),
             || eval_inner(high, e_high, threshold));
    } else {
        for (o, i) in dst.iter_mut().zip(e.values()) {
            *o = i;
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Length {
    Finite(usize),
    Infinite,
}

impl Length {
    fn compatible(self, other: Length) -> bool {
        match (self, other) {
            (Length::Finite(a), Length::Finite(b)) => a == b,
            (Length::Infinite, _) | (_, Length::Infinite) => true,
        }
    }
}

pub trait Expression {
    type Element;
    type Values: Iterator<Item = Self::Element>;

    fn len(&self) -> Length;

    fn values(self) -> Self::Values;

    fn split(self) -> (Self, Self);

    // TODO: this need to handle SIMD etc.
    fn zip<E2: Expression>(self, e: E2) -> Zip<Self, E2> where Self: Sized {
        raw::make_zip(self, e)
    }
    // TODO: this needs to handle SIMD etc.
    fn map<O, F: FnMut(Self::Element) -> O>(self, f: F) -> Map<Self, F> where Self: Sized {
        raw::make_map(self, f)
    }
}
<commit_msg>Tweak parallelism thresholds.<commit_after>extern crate rayon;

use std::cmp;

mod operator;
pub use operator::{Neg, Not,
                   Add, Sub, Mul, Div,
                   BitOr, BitAnd, BitXor};
mod raw;
pub use raw::{Zip, Map};

pub mod iterators;

mod simple;
pub use simple::{Value, Constant};

const MIN_THRESHOLD: usize = 1024;
const MAX_COUNT: usize = 32;

fn join<F: Send + FnOnce(), G: Send + FnOnce()>(f: F, g: G) {
    rayon::join(f, g);
}

pub fn evaluate<E>(dst: &mut [E::Element], e: E)
    where E: Expression + Send, E::Element: Send
{
    let len = dst.len();

    eval_inner(dst, e, cmp::max(len / MAX_COUNT, MIN_THRESHOLD));
}

fn eval_inner<E>(dst: &mut [E::Element], e: E, threshold: usize)
    where E: Expression + Send, E::Element: Send
{
    let len = dst.len();
    assert!(e.len().compatible(Length::Finite(len)));

    if len > threshold {
        let (low, high) = dst.split_at_mut(len / 2);
        let (e_low, e_high) = e.split();
        join(|| eval_inner(low, e_low, threshold),
             || eval_inner(high, e_high, threshold));
    } else {
        for (o, i) in dst.iter_mut().zip(e.values()) {
            *o = i;
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Length {
    Finite(usize),
    Infinite,
}

impl Length {
    fn compatible(self, other: Length) -> bool {
        match (self, other) {
            (Length::Finite(a), Length::Finite(b)) => a == b,
            (Length::Infinite, _) | (_, Length::Infinite) => true,
        }
    }
}

pub trait Expression {
    type Element;
    type Values: Iterator<Item = Self::Element>;

    fn len(&self) -> Length;

    fn values(self) -> Self::Values;

    fn split(self) -> (Self, Self);

    // TODO: this need to handle SIMD etc.
    fn zip<E2: Expression>(self, e: E2) -> Zip<Self, E2> where Self: Sized {
        raw::make_zip(self, e)
    }
    // TODO: this needs to handle SIMD etc.
    fn map<O, F: FnMut(Self::Element) -> O>(self, f: F) -> Map<Self, F> where Self: Sized {
        raw::make_map(self, f)
    }
}
<|endoftext|>


<commit_before>#![feature(core)]
#![feature(old_io)]
#![feature(std_misc)]
#![feature(collections)]

extern crate "rustc-serialize" as rustc_serialize;
extern crate time;
extern crate uuid;
extern crate rand;

use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;
use std::old_io::net::ip::{SocketAddr, ToSocketAddr};
use std::old_io::net::udp::UdpSocket;
use std::old_io::timer::Timer;
use std::str::FromStr;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::time::Duration;
use std::thread;

use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_serialize::json;
use uuid::Uuid;

mod member;
mod memberlist;

use member::{Member, MemberState, StateChange};
use memberlist::MemberList;

pub type ClusterEvent = (Vec<Member>, MemberEvent);

#[derive(Debug)]
pub enum MemberEvent {
    MemberJoined(Member),
    MemberWentUp(Member),
    MemberSuspectedDown(Member),
    MemberWentDown(Member),
}

pub struct Cluster {
    pub events: Receiver<ClusterEvent>,
    comm: Sender<InternalRequest>,
}

#[derive(Debug, Clone)]
struct EncSocketAddr(SocketAddr);

#[derive(RustcEncodable, RustcDecodable, Debug, Clone)]
enum Request {
    Ping,
    Ack,
    PingRequest(EncSocketAddr),
    AckHost(Member),
}

#[derive(Debug, Clone)]
struct TargetedRequest {
    request: Request,
    target: SocketAddr,
}

#[derive(Debug, Clone)]
enum InternalRequest {
    AddSeed(SocketAddr),
    Respond(SocketAddr, Message),
}

struct State {
    host_key: Uuid,
    cluster_key: Vec<u8>,
    members: MemberList,
    seed_queue: Vec<SocketAddr>,
    pending_responses: Vec<(time::Tm, SocketAddr, Vec<StateChange>)>,
    state_changes: Vec<StateChange>,
    wait_list: HashMap<SocketAddr, Vec<SocketAddr>>,
    socket: UdpSocket,
    request_tx: Sender<TargetedRequest>,
    event_tx: Sender<ClusterEvent>,
}

#[derive(RustcEncodable, RustcDecodable, Debug, Clone)]
struct Message {
    sender: Uuid,
    cluster_key: Vec<u8>,
    request: Request,
    state_changes: Vec<StateChange>,
}

pub fn start_cluster<A: ToSocketAddr>(host_key: Uuid, cluster_key: &str, listen_addr: A) -> Cluster {
    let (event_tx, event_rx) = channel();
    let (request_tx, request_rx) = channel();
    let (internal_tx, internal_rx) = channel();
    let socket = UdpSocket::bind(listen_addr).unwrap();
    let cluster_key = cluster_key.as_bytes().to_vec();

    let timeout_tx = request_tx.clone();
    let worker_socket = socket.clone();
    thread::spawn(move || {
        let me = Member::myself(host_key.clone());

        let mut state = State {
            host_key: host_key,
            cluster_key: cluster_key,
            members: MemberList::new(me.clone()),
            seed_queue: Vec::new(),
            pending_responses: Vec::new(),
            state_changes: vec![StateChange::new(me)],
            wait_list: HashMap::new(),
            socket: worker_socket,
            request_tx: timeout_tx,
            event_tx: event_tx,
        };

        let mut timer = Timer::new().unwrap();
        let periodic = timer.periodic(Duration::seconds(1));

        loop {
            select!(
                _ = periodic.recv() => {
                    enqueue_seed_nodes(&state.seed_queue, &state.request_tx);
                    enqueue_random_ping(&mut state);
                },
                request = request_rx.recv() => {
                    prune_timed_out_responses(&mut state);
                    process_request(&mut state, request.unwrap());
                },
                internal_message = internal_rx.recv() => {
                    process_internal_request(&mut state, internal_message.unwrap());
                }
            );
        }
    });

    let listener_tx = internal_tx.clone();
    let mut listener_socket = socket.clone();
    thread::spawn(move || {
        loop {
            let mut buf = [0; 512];

            match listener_socket.recv_from(&mut buf) {
                Ok((size, src_addr)) => {
                    let message = json::decode(&*String::from_utf8_lossy(&buf[..size]));
                    listener_tx.send(InternalRequest::Respond(src_addr, message.unwrap())).unwrap();
                },
                Err(e) => {
                    println!("Error while reading: {:?}", e);
                }
            };
        }
    });

    return Cluster { events: event_rx, comm: internal_tx };
}

impl Cluster {
    pub fn add_seed_node<A: ToSocketAddr>(&self, addr: A) {
        self.comm.send(InternalRequest::AddSeed(addr.to_socket_addr().unwrap())).unwrap();
    }
}

fn process_request(state: &mut State, request: TargetedRequest) {
    use Request::*;

    let timeout = time::now_utc() + Duration::seconds(3);
    let should_add_pending = match request.request { Ping => true, _ => false };
    let message = build_message(&state.host_key, &state.cluster_key, request.request, state.state_changes.clone());

    if should_add_pending {
        state.pending_responses.push((timeout, request.target.clone(), message.state_changes.clone()));
    }

    let encoded = json::encode(&message).unwrap();

    assert!(encoded.len() < 512);

    state.socket.send_to(encoded.as_bytes(), request.target).unwrap();
}

fn build_message(sender: &Uuid, cluster_key: &Vec<u8>, request: Request, state_changes: Vec<StateChange>) -> Message {
    let mut message = Message {
        sender: sender.clone(),
        cluster_key: cluster_key.clone(),
        request: request.clone(),
        state_changes: Vec::new(),
    };

    for i in range(0, state_changes.len() + 1) {
        message = Message {
            sender: sender.clone(),
            cluster_key: cluster_key.clone(),
            request: request.clone(),
            state_changes: (&state_changes[..i]).iter().cloned().collect(),
        };

        let encoded = json::encode(&message).unwrap();
        if encoded.len() >= 512 {
            return message;
        }
    }

    return message;
}

fn enqueue_seed_nodes(seed_nodes: &[SocketAddr], tx: &Sender<TargetedRequest>) {
    for seed_node in seed_nodes {
        tx.send(TargetedRequest { request: Request::Ping, target: seed_node.clone() }).unwrap();
    }
}

fn enqueue_random_ping(state: &mut State) {
    if let Some(member) = state.members.next_random_member() {
        state.request_tx.send(TargetedRequest { request: Request::Ping, target: member.remote_host().unwrap() }).unwrap();
    }
}

fn prune_timed_out_responses(state: &mut State) {
    let now = time::now_utc();

    let (remaining, expired): (Vec<_>, Vec<_>) = state.pending_responses
        .iter()
        .cloned()
        .partition(| &(t, _, _) | t < now);

    let expired_hosts: HashSet<SocketAddr> = expired
        .iter()
        .map(| &(_, a, _) | a)
        .collect();

    state.pending_responses = remaining;

    let (suspect, down) = state.members.time_out_nodes(expired_hosts);

    enqueue_state_change(state, down.as_slice());
    enqueue_state_change(state, suspect.as_slice());

    for member in suspect {
        send_ping_requests(state, &member);
        send_member_event(&state.members, &state.event_tx, MemberEvent::MemberSuspectedDown(member.clone()));
    }

    for member in down {
        send_member_event(&state.members, &state.event_tx, MemberEvent::MemberWentDown(member.clone()));
    }
}

fn send_ping_requests(state: &State, target: &Member) {
    if let Some(target_host) = target.remote_host() {
        for relay in state.members.hosts_for_indirect_ping(&target_host) {
            state.request_tx.send(TargetedRequest {
                request: Request::PingRequest(EncSocketAddr::from_addr(&target_host)),
                target: relay,
            }).unwrap();
        }
    }
}

fn send_member_event(members: &MemberList, event_tx: &Sender<ClusterEvent>, event: MemberEvent) {
    use MemberEvent::*;

    match event {
        MemberJoined(_) => {},
        MemberWentUp(ref m) => assert_eq!(m.state(), MemberState::Alive),
        MemberWentDown(ref m) => assert_eq!(m.state(), MemberState::Down),
        MemberSuspectedDown(ref m) => assert_eq!(m.state(), MemberState::Suspect),
    };

    event_tx.send((members.to_vec(), event)).unwrap();
}

fn process_internal_request(state: &mut State, message: InternalRequest) {
    use InternalRequest::*;
    use Request::*;

    match message {
        AddSeed(addr) => {
            state.seed_queue.push(addr);
        },
        Respond(src_addr, message) => {
            if message.cluster_key != state.cluster_key {
                println!("ERROR: Mismatching cluster keys, ignoring message");
            }
            else {
                apply_state_changes(state, message.state_changes, src_addr);
                remove_potential_seed(state, src_addr);

                ensure_node_is_member(state, src_addr, message.sender);

                let response = match message.request {
                    Ping => Some(TargetedRequest { request: Ack, target: src_addr }),
                    Ack => {
                        ack_response(state, src_addr);
                        mark_node_alive(state, src_addr);
                        None
                    },
                    PingRequest(dest_addr) => {
                        let EncSocketAddr(dest_addr) = dest_addr;
                        add_to_wait_list(state, &dest_addr, &src_addr);
                        Some(TargetedRequest { request: Ping, target: dest_addr })
                    },
                    AckHost(member) => {
                        ack_response(state, member.remote_host().unwrap());
                        mark_node_alive(state, member.remote_host().unwrap());
                        None
                    }
                };

                match response {
                    Some(response) => state.request_tx.send(response).unwrap(),
                    None => (),
                };
            }
        },
    };
}

fn add_to_wait_list(state: &mut State, wait_addr: &SocketAddr, notify_addr: &SocketAddr) {
    match state.wait_list.entry(*wait_addr) {
        Entry::Occupied(mut entry) => { entry.get_mut().push(notify_addr.clone()); },
        Entry::Vacant(entry) => { entry.insert(vec![notify_addr.clone()]); }
    };
}

fn remove_potential_seed(state: &mut State, src_addr: SocketAddr) {
    state.seed_queue.retain(|&addr| addr != src_addr)
}

fn ack_response(state: &mut State, src_addr: SocketAddr) {
    let mut to_remove = Vec::new();

    for &(ref t, ref addr, ref state_changes) in state.pending_responses.iter() {
        if src_addr != *addr {
            continue;
        }

        to_remove.push((t.clone(), addr.clone(), state_changes.clone()));

        state.state_changes
            .retain(|os| !state_changes.iter().any(| is | is.member().host_key() == os.member().host_key()))
    }

    state.pending_responses.retain(|op| !to_remove.iter().any(|ip| ip == op));
}

fn ensure_node_is_member(state: &mut State, src_addr: SocketAddr, sender: Uuid) {
    if state.members.has_member(&src_addr) {
        return;
    }

    let new_member = Member::new(sender, src_addr, 0, MemberState::Alive);

    state.members.add_member(new_member.clone());
    enqueue_state_change(state, &[new_member.clone()]);
    send_member_event(&state.members, &state.event_tx, MemberEvent::MemberJoined(new_member));
}

fn mark_node_alive(state: &mut State, src_addr: SocketAddr) {
    if let Some(member) = state.members.mark_node_alive(&src_addr) {
        match state.wait_list.get_mut(&src_addr) {
            Some(mut wait_list) => {
                for remote in wait_list.drain() {
                    state.request_tx.send(TargetedRequest { request: Request::AckHost(member.clone()), target: remote }).unwrap();
                }
            },
            None => ()
        };

        enqueue_state_change(state, &[member.clone()]);
        send_member_event(&state.members, &state.event_tx, MemberEvent::MemberWentUp(member.clone()));
    }
}

fn apply_state_changes(state: &mut State, state_changes: Vec<StateChange>, from: SocketAddr) {
    let (new, changed) = state.members.apply_state_changes(state_changes, &from);

    enqueue_state_change(state, new.as_slice());
    enqueue_state_change(state, changed.as_slice());

    for member in new {
        send_member_event(&state.members, &state.event_tx, MemberEvent::MemberJoined(member));
    }

    for member in changed {
        send_member_event(&state.members, &state.event_tx, determine_member_event(member));
    }
}

fn determine_member_event(member: Member) -> MemberEvent {
    use member::MemberState::*;
    use MemberEvent::*;

    return match member.state() {
        Alive => MemberWentUp(member),
        Suspect => MemberSuspectedDown(member),
        Down => MemberWentDown(member),
    };
}

fn enqueue_state_change(state: &mut State, members: &[Member]) {
    for member in members {
        for state_change in &mut state.state_changes {
            if state_change.member().host_key() == member.host_key() {
                state_change.update(member.clone());
                return;
            }
        }

        state.state_changes.push(StateChange::new(member.clone()));
    }
}

impl Decodable for EncSocketAddr {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        match d.read_str() {
            Ok(s) => match FromStr::from_str(s.as_slice()) {
                Ok(addr) => Ok(EncSocketAddr(addr)),
                Err(e) => Err(d.error(format!("{:?}", e).as_slice())),
            },
            Err(e) => Err(e),
        }
    }
}

impl Encodable for EncSocketAddr {
    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
        let &EncSocketAddr(addr) = self;
        format!("{}", addr).encode(e)
    }
}

impl EncSocketAddr {
    fn from_addr(addr: &SocketAddr) -> Self {
        EncSocketAddr(addr.clone())
    }
}
<commit_msg>Add cluster State impl, move bunch of state mutating functions there<commit_after>#![feature(core)]
#![feature(old_io)]
#![feature(std_misc)]
#![feature(collections)]

extern crate "rustc-serialize" as rustc_serialize;
extern crate time;
extern crate uuid;
extern crate rand;

use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;
use std::old_io::net::ip::{SocketAddr, ToSocketAddr};
use std::old_io::net::udp::UdpSocket;
use std::old_io::timer::Timer;
use std::str::FromStr;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::time::Duration;
use std::thread;

use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_serialize::json;
use uuid::Uuid;

mod member;
mod memberlist;

use member::{Member, MemberState, StateChange};
use memberlist::MemberList;

pub type ClusterEvent = (Vec<Member>, MemberEvent);
type WaitList = HashMap<SocketAddr, Vec<SocketAddr>>;

#[derive(Debug)]
pub enum MemberEvent {
    MemberJoined(Member),
    MemberWentUp(Member),
    MemberSuspectedDown(Member),
    MemberWentDown(Member),
}

pub struct Cluster {
    pub events: Receiver<ClusterEvent>,
    comm: Sender<InternalRequest>,
}

#[derive(Debug, Clone)]
struct EncSocketAddr(SocketAddr);

#[derive(RustcEncodable, RustcDecodable, Debug, Clone)]
enum Request {
    Ping,
    Ack,
    PingRequest(EncSocketAddr),
    AckHost(Member),
}

#[derive(Debug, Clone)]
struct TargetedRequest {
    request: Request,
    target: SocketAddr,
}

#[derive(Debug, Clone)]
enum InternalRequest {
    AddSeed(SocketAddr),
    Respond(SocketAddr, Message),
}

struct State {
    host_key: Uuid,
    cluster_key: Vec<u8>,
    members: MemberList,
    seed_queue: Vec<SocketAddr>,
    pending_responses: Vec<(time::Tm, SocketAddr, Vec<StateChange>)>,
    state_changes: Vec<StateChange>,
    wait_list: WaitList,
    socket: UdpSocket,
    request_tx: Sender<TargetedRequest>,
    event_tx: Sender<ClusterEvent>,
}

#[derive(RustcEncodable, RustcDecodable, Debug, Clone)]
struct Message {
    sender: Uuid,
    cluster_key: Vec<u8>,
    request: Request,
    state_changes: Vec<StateChange>,
}

pub fn start_cluster<A: ToSocketAddr>(host_key: Uuid, cluster_key: &str, listen_addr: A) -> Cluster {
    let (event_tx, event_rx) = channel();
    let (request_tx, request_rx) = channel();
    let (internal_tx, internal_rx) = channel();
    let socket = UdpSocket::bind(listen_addr).unwrap();
    let cluster_key = cluster_key.as_bytes().to_vec();

    let timeout_tx = request_tx.clone();
    let worker_socket = socket.clone();
    thread::spawn(move || {
        let me = Member::myself(host_key.clone());

        let mut state = State {
            host_key: host_key,
            cluster_key: cluster_key,
            members: MemberList::new(me.clone()),
            seed_queue: Vec::new(),
            pending_responses: Vec::new(),
            state_changes: vec![StateChange::new(me)],
            wait_list: HashMap::new(),
            socket: worker_socket,
            request_tx: timeout_tx,
            event_tx: event_tx,
        };

        let mut timer = Timer::new().unwrap();
        let periodic = timer.periodic(Duration::seconds(1));

        loop {
            select!(
                _ = periodic.recv() => {
                    state.enqueue_seed_nodes();
                    state.enqueue_random_ping();
                },
                request = request_rx.recv() => {
                    state.prune_timed_out_responses();
                    state.process_request(request.unwrap());
                },
                internal_message = internal_rx.recv() => {
                    state.process_internal_request(internal_message.unwrap());
                }
            );
        }
    });

    let listener_tx = internal_tx.clone();
    let mut listener_socket = socket.clone();
    thread::spawn(move || {
        loop {
            let mut buf = [0; 512];

            match listener_socket.recv_from(&mut buf) {
                Ok((size, src_addr)) => {
                    let message = json::decode(&*String::from_utf8_lossy(&buf[..size]));
                    listener_tx.send(InternalRequest::Respond(src_addr, message.unwrap())).unwrap();
                },
                Err(e) => {
                    println!("Error while reading: {:?}", e);
                }
            };
        }
    });

    return Cluster { events: event_rx, comm: internal_tx };
}

impl Cluster {
    pub fn add_seed_node<A: ToSocketAddr>(&self, addr: A) {
        self.comm.send(InternalRequest::AddSeed(addr.to_socket_addr().unwrap())).unwrap();
    }
}

impl State {
    fn process_request(&mut self, request: TargetedRequest) {
        use Request::*;

        let timeout = time::now_utc() + Duration::seconds(3);
        let should_add_pending = match request.request { Ping => true, _ => false };
        let message = build_message(&self.host_key, &self.cluster_key, request.request, self.state_changes.clone());

        if should_add_pending {
            self.pending_responses.push((timeout, request.target.clone(), message.state_changes.clone()));
        }

        let encoded = json::encode(&message).unwrap();

        assert!(encoded.len() < 512);

        self.socket.send_to(encoded.as_bytes(), request.target).unwrap();
    }

    fn enqueue_seed_nodes(&self) {
        for seed_node in &self.seed_queue {
            self.request_tx.send(TargetedRequest { request: Request::Ping, target: seed_node.clone() }).unwrap();
        }
    }

    fn enqueue_random_ping(&mut self) {
        if let Some(member) = self.members.next_random_member() {
            self.request_tx.send(TargetedRequest { request: Request::Ping, target: member.remote_host().unwrap() }).unwrap();
        }
    }

    fn prune_timed_out_responses(&mut self) {
        let now = time::now_utc();

        let (remaining, expired): (Vec<_>, Vec<_>) = self.pending_responses
            .iter()
            .cloned()
            .partition(| &(t, _, _) | t < now);

        let expired_hosts: HashSet<SocketAddr> = expired
            .iter()
            .map(| &(_, a, _) | a)
            .collect();

        self.pending_responses = remaining;

        let (suspect, down) = self.members.time_out_nodes(expired_hosts);

        enqueue_state_change(&mut self.state_changes, down.as_slice());
        enqueue_state_change(&mut self.state_changes, suspect.as_slice());

        for member in suspect {
            self.send_ping_requests(&member);
            self.send_member_event(MemberEvent::MemberSuspectedDown(member.clone()));
        }

        for member in down {
            self.send_member_event(MemberEvent::MemberWentDown(member.clone()));
        }
    }

    fn send_ping_requests(&self, target: &Member) {
        if let Some(target_host) = target.remote_host() {
            for relay in self.members.hosts_for_indirect_ping(&target_host) {
                self.request_tx.send(TargetedRequest {
                    request: Request::PingRequest(EncSocketAddr::from_addr(&target_host)),
                    target: relay,
                }).unwrap();
            }
        }
    }

    fn process_internal_request(&mut self, message: InternalRequest) {
        use InternalRequest::*;

        match message {
            AddSeed(addr) => self.seed_queue.push(addr),
            Respond(src_addr, message) => self.respond_to_message(src_addr, message),
        };
    }

    fn respond_to_message(&mut self, src_addr: SocketAddr, message: Message) {
        use Request::*;

        if message.cluster_key != self.cluster_key {
            println!("ERROR: Mismatching cluster keys, ignoring message");
        }
        else {
            self.apply_state_changes(message.state_changes, src_addr);
            remove_potential_seed(&mut self.seed_queue, src_addr);

            self.ensure_node_is_member(src_addr, message.sender);

            let response = match message.request {
                Ping => Some(TargetedRequest { request: Ack, target: src_addr }),
                Ack => {
                    self.ack_response(src_addr);
                    self.mark_node_alive(src_addr);
                    None
                },
                PingRequest(dest_addr) => {
                    let EncSocketAddr(dest_addr) = dest_addr;
                    add_to_wait_list(&mut self.wait_list, &dest_addr, &src_addr);
                    Some(TargetedRequest { request: Ping, target: dest_addr })
                },
                AckHost(member) => {
                    self.ack_response(member.remote_host().unwrap());
                    self.mark_node_alive(member.remote_host().unwrap());
                    None
                }
            };

            match response {
                Some(response) => self.request_tx.send(response).unwrap(),
                None => (),
            };
        }
    }

    fn ack_response(&mut self, src_addr: SocketAddr) {
        let mut to_remove = Vec::new();

        for &(ref t, ref addr, ref state_changes) in self.pending_responses.iter() {
            if src_addr != *addr {
                continue;
            }

            to_remove.push((t.clone(), addr.clone(), state_changes.clone()));

            self.state_changes
                .retain(|os| !state_changes.iter().any(| is | is.member().host_key() == os.member().host_key()))
        }

        self.pending_responses.retain(|op| !to_remove.iter().any(|ip| ip == op));
    }

    fn ensure_node_is_member(&mut self, src_addr: SocketAddr, sender: Uuid) {
        if self.members.has_member(&src_addr) {
            return;
        }

        let new_member = Member::new(sender, src_addr, 0, MemberState::Alive);

        self.members.add_member(new_member.clone());
        enqueue_state_change(&mut self.state_changes, &[new_member.clone()]);
        self.send_member_event(MemberEvent::MemberJoined(new_member));
    }

    fn send_member_event(&self, event: MemberEvent) {
        use MemberEvent::*;

        match event {
            MemberJoined(_) => {},
            MemberWentUp(ref m) => assert_eq!(m.state(), MemberState::Alive),
            MemberWentDown(ref m) => assert_eq!(m.state(), MemberState::Down),
            MemberSuspectedDown(ref m) => assert_eq!(m.state(), MemberState::Suspect),
        };

        self.event_tx.send((self.members.to_vec(), event)).unwrap();
    }

    fn apply_state_changes(&mut self, state_changes: Vec<StateChange>, from: SocketAddr) {
        let (new, changed) = self.members.apply_state_changes(state_changes, &from);

        enqueue_state_change(&mut self.state_changes, new.as_slice());
        enqueue_state_change(&mut self.state_changes, changed.as_slice());

        for member in new {
            self.send_member_event(MemberEvent::MemberJoined(member));
        }

        for member in changed {
            self.send_member_event(determine_member_event(member));
        }
    }

    fn mark_node_alive(&mut self, src_addr: SocketAddr) {
        if let Some(member) = self.members.mark_node_alive(&src_addr) {
            match self.wait_list.get_mut(&src_addr) {
                Some(mut wait_list) => {
                    for remote in wait_list.drain() {
                        self.request_tx.send(TargetedRequest { request: Request::AckHost(member.clone()), target: remote }).unwrap();
                    }
                },
                None => ()
            };

            enqueue_state_change(&mut self.state_changes, &[member.clone()]);
            self.send_member_event(MemberEvent::MemberWentUp(member.clone()));
        }
    }

}

fn build_message(sender: &Uuid, cluster_key: &Vec<u8>, request: Request, state_changes: Vec<StateChange>) -> Message {
    let mut message = Message {
        sender: sender.clone(),
        cluster_key: cluster_key.clone(),
        request: request.clone(),
        state_changes: Vec::new(),
    };

    for i in range(0, state_changes.len() + 1) {
        message = Message {
            sender: sender.clone(),
            cluster_key: cluster_key.clone(),
            request: request.clone(),
            state_changes: (&state_changes[..i]).iter().cloned().collect(),
        };

        let encoded = json::encode(&message).unwrap();
        if encoded.len() >= 512 {
            return message;
        }
    }

    return message;
}

fn add_to_wait_list(wait_list: &mut WaitList, wait_addr: &SocketAddr, notify_addr: &SocketAddr) {
    match wait_list.entry(*wait_addr) {
        Entry::Occupied(mut entry) => { entry.get_mut().push(notify_addr.clone()); },
        Entry::Vacant(entry) => { entry.insert(vec![notify_addr.clone()]); }
    };
}

fn remove_potential_seed(seed_queue: &mut Vec<SocketAddr>, src_addr: SocketAddr) {
    seed_queue.retain(|&addr| addr != src_addr)
}

fn determine_member_event(member: Member) -> MemberEvent {
    use member::MemberState::*;
    use MemberEvent::*;

    return match member.state() {
        Alive => MemberWentUp(member),
        Suspect => MemberSuspectedDown(member),
        Down => MemberWentDown(member),
    };
}

fn enqueue_state_change(state_changes: &mut Vec<StateChange>, members: &[Member]) {
    for member in members {
        for state_change in state_changes.iter_mut() {
            if state_change.member().host_key() == member.host_key() {
                state_change.update(member.clone());
                return;
            }
        }

        state_changes.push(StateChange::new(member.clone()));
    }
}

impl Decodable for EncSocketAddr {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        match d.read_str() {
            Ok(s) => match FromStr::from_str(s.as_slice()) {
                Ok(addr) => Ok(EncSocketAddr(addr)),
                Err(e) => Err(d.error(format!("{:?}", e).as_slice())),
            },
            Err(e) => Err(e),
        }
    }
}

impl Encodable for EncSocketAddr {
    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
        let &EncSocketAddr(addr) = self;
        format!("{}", addr).encode(e)
    }
}

impl EncSocketAddr {
    fn from_addr(addr: &SocketAddr) -> Self {
        EncSocketAddr(addr.clone())
    }
}
<|endoftext|>


<commit_before>//! ### rust-mysql-simple
//! Mysql client library implemented in rust.
//!
//! #### Install
//! Please use *mysql* crate:
//!
//! ```toml
//! [dependencies]
//! mysql = "*"
//! ```
//!
//! #### Example
//!
//! ```rust
//! #[macro_use]
//! extern crate mysql;
//! // ...
//!
//! # fn main() {
//! use mysql as my;
//!
//! #[derive(Debug, PartialEq, Eq)]
//! struct Payment {
//!     customer_id: i32,
//!     amount: i32,
//!     account_name: Option<String>,
//! }
//!
//! # fn get_opts() -> my::Opts {
//! #     let url = if let Ok(url) = std::env::var("DATABASE_URL") {
//! #         let opts = my::Opts::from_url(&url).expect("DATABASE_URL invalid");
//! #         if opts.get_db_name().expect("a database name is required").is_empty() {
//! #             panic!("database name is empty");
//! #         }
//! #         url
//! #     } else {
//! #         "mysql://root:password@127.0.0.1:3307/mysql".to_string()
//! #     };
//! #     my::Opts::from_url(&*url).unwrap()
//! # }
//!
//! fn main() {
//! #   let opts = get_opts();
//! #   if opts.get_tcp_port() == 3307 && opts.get_pass() == Some("password") {
//!     // See docs on the `OptsBuilder`'s methods for the list of options available via URL.
//!     let pool = my::Pool::new("mysql://root:password@localhost:3307/mysql").unwrap();
//! #   }
//! #   let pool = my::Pool::new_manual(1, 1, opts).unwrap();
//!
//!     // Let's create payment table.
//!     // Unwrap just to make sure no error happened.
//!     pool.prep_exec(r"CREATE TEMPORARY TABLE payment (
//!                          customer_id int not null,
//!                          amount int not null,
//!                          account_name text
//!                      )", ()).unwrap();
//!
//!     let payments = vec![
//!         Payment { customer_id: 1, amount: 2, account_name: None },
//!         Payment { customer_id: 3, amount: 4, account_name: Some("foo".into()) },
//!         Payment { customer_id: 5, amount: 6, account_name: None },
//!         Payment { customer_id: 7, amount: 8, account_name: None },
//!         Payment { customer_id: 9, amount: 10, account_name: Some("bar".into()) },
//!     ];
//!
//!     // Let's insert payments to the database
//!     // We will use into_iter() because we do not need to map Stmt to anything else.
//!     // Also we assume that no error happened in `prepare`.
//!     for mut stmt in pool.prepare(r"INSERT INTO payment
//!                                        (customer_id, amount, account_name)
//!                                    VALUES
//!                                        (:customer_id, :amount, :account_name)").into_iter() {
//!         for p in payments.iter() {
//!             // `execute` takes ownership of `params` so we pass account name by reference.
//!             // Unwrap each result just to make sure no errors happened.
//!             stmt.execute(params!{
//!                 "customer_id" => p.customer_id,
//!                 "amount" => p.amount,
//!                 "account_name" => &p.account_name,
//!             }).unwrap();
//!         }
//!     }
//!
//!     // Let's select payments from database
//!     let selected_payments: Vec<Payment> =
//!     pool.prep_exec("SELECT customer_id, amount, account_name from payment", ())
//!     .map(|result| { // In this closure we will map `QueryResult` to `Vec<Payment>`
//!         // `QueryResult` is iterator over `MyResult<row, err>` so first call to `map`
//!         // will map each `MyResult` to contained `row` (no proper error handling)
//!         // and second call to `map` will map each `row` to `Payment`
//!         result.map(|x| x.unwrap()).map(|row| {
//!             // ⚠ Note that from_row will panic if you don't follow your schema
//!             let (customer_id, amount, account_name) = my::from_row(row);
//!             Payment {
//!                 customer_id: customer_id,
//!                 amount: amount,
//!                 account_name: account_name,
//!             }
//!         }).collect() // Collect payments so now `QueryResult` is mapped to `Vec<Payment>`
//!     }).unwrap(); // Unwrap `Vec<Payment>`
//!
//!     // Now make sure that `payments` equals to `selected_payments`.
//!     // Mysql gives no guaranties on order of returned rows without `ORDER BY`
//!     // so assume we are lukky.
//!     assert_eq!(payments, selected_payments);
//!     println!("Yay!");
//! }
//! # main();
//! # }
//! ```

#![crate_name = "mysql"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![cfg_attr(feature = "nightly", feature(test, const_fn))]
#[cfg(feature = "nightly")]
extern crate test;

use mysql_common as myc;
pub extern crate serde;
pub extern crate serde_json;
#[cfg(test)]
#[macro_use]
extern crate serde_derive;

/// Reexport of `chrono` crate.
pub use crate::myc::chrono;
/// Reexport of `time` crate.
pub use crate::myc::time;
/// Reexport of `uuid` crate.
pub use crate::myc::uuid;

// Until `macro_reexport` stabilisation.

mod conn;
pub mod error;
mod io;

#[doc(inline)]
pub use crate::myc::constants as consts;

#[doc(inline)]
pub use crate::conn::local_infile::{LocalInfile, LocalInfileHandler};
#[doc(inline)]
pub use crate::conn::opts::SslOpts;
#[doc(inline)]
pub use crate::conn::opts::{Opts, OptsBuilder};
#[doc(inline)]
pub use crate::conn::pool::{Pool, PooledConn};
#[doc(inline)]
pub use crate::conn::query_result::QueryResult;
#[doc(inline)]
pub use crate::conn::stmt::Stmt;
#[doc(inline)]
pub use crate::conn::transaction::{IsolationLevel, Transaction};
#[doc(inline)]
pub use crate::conn::Conn;
#[doc(inline)]
pub use crate::error::{DriverError, Error, MySqlError, Result, ServerError, UrlError};
#[doc(inline)]
pub use crate::myc::packets::Column;
#[doc(inline)]
pub use crate::myc::params::Params;
#[doc(inline)]
pub use crate::myc::proto::codec::Compression;
#[doc(inline)]
pub use crate::myc::row::convert::{from_row, from_row_opt, FromRowError};
#[doc(inline)]
pub use crate::myc::row::Row;
#[doc(inline)]
pub use crate::myc::value::convert::{from_value, from_value_opt, FromValueError};
#[doc(inline)]
pub use crate::myc::value::json::{Deserialized, Serialized};
#[doc(inline)]
pub use crate::myc::value::Value;

pub mod prelude {
    #[doc(inline)]
    pub use crate::conn::GenericConnection;
    #[doc(inline)]
    pub use crate::myc::row::convert::FromRow;
    #[doc(inline)]
    pub use crate::myc::value::convert::{ConvIr, FromValue, ToValue};
}

#[doc(inline)]
pub use crate::myc::params;

#[cfg(test)]
mod test_misc {
    use lazy_static::lazy_static;

    use std::env;

    use crate::conn::opts::{Opts, OptsBuilder};
    use crate::SslOpts;

    #[allow(dead_code)]
    fn error_should_implement_send_and_sync() {
        fn _dummy<T: Send + Sync>(_: T) {}
        _dummy(crate::error::Error::FromValueError(crate::Value::NULL));
    }

    lazy_static! {
        pub static ref DATABASE_URL: String = {
            if let Ok(url) = env::var("DATABASE_URL") {
                let opts = Opts::from_url(&url).expect("DATABASE_URL invalid");
                if opts
                    .get_db_name()
                    .expect("a database name is required")
                    .is_empty()
                {
                    panic!("database name is empty");
                }
                url
            } else {
                "mysql://root:password@127.0.0.1:3307/mysql".into()
            }
        };
    }

    pub fn get_opts() -> OptsBuilder {
        let mut builder = OptsBuilder::from_opts(&**DATABASE_URL);
        builder.init(vec!["SET GLOBAL sql_mode = 'TRADITIONAL'"]);
        if test_compression() {
            builder.compress(Some(Default::default()));
        }
        if test_ssl() {
            builder.prefer_socket(false);
            let mut ssl_opts = SslOpts::default();
            ssl_opts.set_danger_skip_domain_validation(true);
            ssl_opts.set_danger_accept_invalid_certs(true);
            builder.ssl_opts(ssl_opts);
        }
        builder
    }

    pub fn test_ssl() -> bool {
        let ssl = env::var("SSL").ok().unwrap_or("false".into());
        ssl == "true" || ssl == "1"
    }

    pub fn test_compression() -> bool {
        let compress = env::var("COMPRESS").ok().unwrap_or("false".into());
        compress == "true" || compress == "1"
    }
}
<commit_msg>Reexport ColumnIndex trait (fix #194)<commit_after>//! ### rust-mysql-simple
//! Mysql client library implemented in rust.
//!
//! #### Install
//! Please use *mysql* crate:
//!
//! ```toml
//! [dependencies]
//! mysql = "*"
//! ```
//!
//! #### Example
//!
//! ```rust
//! #[macro_use]
//! extern crate mysql;
//! // ...
//!
//! # fn main() {
//! use mysql as my;
//!
//! #[derive(Debug, PartialEq, Eq)]
//! struct Payment {
//!     customer_id: i32,
//!     amount: i32,
//!     account_name: Option<String>,
//! }
//!
//! # fn get_opts() -> my::Opts {
//! #     let url = if let Ok(url) = std::env::var("DATABASE_URL") {
//! #         let opts = my::Opts::from_url(&url).expect("DATABASE_URL invalid");
//! #         if opts.get_db_name().expect("a database name is required").is_empty() {
//! #             panic!("database name is empty");
//! #         }
//! #         url
//! #     } else {
//! #         "mysql://root:password@127.0.0.1:3307/mysql".to_string()
//! #     };
//! #     my::Opts::from_url(&*url).unwrap()
//! # }
//!
//! fn main() {
//! #   let opts = get_opts();
//! #   if opts.get_tcp_port() == 3307 && opts.get_pass() == Some("password") {
//!     // See docs on the `OptsBuilder`'s methods for the list of options available via URL.
//!     let pool = my::Pool::new("mysql://root:password@localhost:3307/mysql").unwrap();
//! #   }
//! #   let pool = my::Pool::new_manual(1, 1, opts).unwrap();
//!
//!     // Let's create payment table.
//!     // Unwrap just to make sure no error happened.
//!     pool.prep_exec(r"CREATE TEMPORARY TABLE payment (
//!                          customer_id int not null,
//!                          amount int not null,
//!                          account_name text
//!                      )", ()).unwrap();
//!
//!     let payments = vec![
//!         Payment { customer_id: 1, amount: 2, account_name: None },
//!         Payment { customer_id: 3, amount: 4, account_name: Some("foo".into()) },
//!         Payment { customer_id: 5, amount: 6, account_name: None },
//!         Payment { customer_id: 7, amount: 8, account_name: None },
//!         Payment { customer_id: 9, amount: 10, account_name: Some("bar".into()) },
//!     ];
//!
//!     // Let's insert payments to the database
//!     // We will use into_iter() because we do not need to map Stmt to anything else.
//!     // Also we assume that no error happened in `prepare`.
//!     for mut stmt in pool.prepare(r"INSERT INTO payment
//!                                        (customer_id, amount, account_name)
//!                                    VALUES
//!                                        (:customer_id, :amount, :account_name)").into_iter() {
//!         for p in payments.iter() {
//!             // `execute` takes ownership of `params` so we pass account name by reference.
//!             // Unwrap each result just to make sure no errors happened.
//!             stmt.execute(params!{
//!                 "customer_id" => p.customer_id,
//!                 "amount" => p.amount,
//!                 "account_name" => &p.account_name,
//!             }).unwrap();
//!         }
//!     }
//!
//!     // Let's select payments from database
//!     let selected_payments: Vec<Payment> =
//!     pool.prep_exec("SELECT customer_id, amount, account_name from payment", ())
//!     .map(|result| { // In this closure we will map `QueryResult` to `Vec<Payment>`
//!         // `QueryResult` is iterator over `MyResult<row, err>` so first call to `map`
//!         // will map each `MyResult` to contained `row` (no proper error handling)
//!         // and second call to `map` will map each `row` to `Payment`
//!         result.map(|x| x.unwrap()).map(|row| {
//!             // ⚠ Note that from_row will panic if you don't follow your schema
//!             let (customer_id, amount, account_name) = my::from_row(row);
//!             Payment {
//!                 customer_id: customer_id,
//!                 amount: amount,
//!                 account_name: account_name,
//!             }
//!         }).collect() // Collect payments so now `QueryResult` is mapped to `Vec<Payment>`
//!     }).unwrap(); // Unwrap `Vec<Payment>`
//!
//!     // Now make sure that `payments` equals to `selected_payments`.
//!     // Mysql gives no guaranties on order of returned rows without `ORDER BY`
//!     // so assume we are lukky.
//!     assert_eq!(payments, selected_payments);
//!     println!("Yay!");
//! }
//! # main();
//! # }
//! ```

#![crate_name = "mysql"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![cfg_attr(feature = "nightly", feature(test, const_fn))]
#[cfg(feature = "nightly")]
extern crate test;

use mysql_common as myc;
pub extern crate serde;
pub extern crate serde_json;
#[cfg(test)]
#[macro_use]
extern crate serde_derive;

/// Reexport of `chrono` crate.
pub use crate::myc::chrono;
/// Reexport of `time` crate.
pub use crate::myc::time;
/// Reexport of `uuid` crate.
pub use crate::myc::uuid;

// Until `macro_reexport` stabilisation.

mod conn;
pub mod error;
mod io;

#[doc(inline)]
pub use crate::myc::constants as consts;

#[doc(inline)]
pub use crate::conn::local_infile::{LocalInfile, LocalInfileHandler};
#[doc(inline)]
pub use crate::conn::opts::SslOpts;
#[doc(inline)]
pub use crate::conn::opts::{Opts, OptsBuilder};
#[doc(inline)]
pub use crate::conn::pool::{Pool, PooledConn};
#[doc(inline)]
pub use crate::conn::query_result::QueryResult;
#[doc(inline)]
pub use crate::conn::stmt::Stmt;
#[doc(inline)]
pub use crate::conn::transaction::{IsolationLevel, Transaction};
#[doc(inline)]
pub use crate::conn::Conn;
#[doc(inline)]
pub use crate::error::{DriverError, Error, MySqlError, Result, ServerError, UrlError};
#[doc(inline)]
pub use crate::myc::packets::Column;
#[doc(inline)]
pub use crate::myc::params::Params;
#[doc(inline)]
pub use crate::myc::proto::codec::Compression;
#[doc(inline)]
pub use crate::myc::row::convert::{from_row, from_row_opt, FromRowError};
#[doc(inline)]
pub use crate::myc::row::Row;
#[doc(inline)]
pub use crate::myc::value::convert::{from_value, from_value_opt, FromValueError};
#[doc(inline)]
pub use crate::myc::value::json::{Deserialized, Serialized};
#[doc(inline)]
pub use crate::myc::value::Value;

pub mod prelude {
    #[doc(inline)]
    pub use crate::conn::GenericConnection;
    #[doc(inline)]
    pub use crate::myc::row::ColumnIndex;
    #[doc(inline)]
    pub use crate::myc::row::convert::FromRow;
    #[doc(inline)]
    pub use crate::myc::value::convert::{ConvIr, FromValue, ToValue};
}

#[doc(inline)]
pub use crate::myc::params;

#[cfg(test)]
mod test_misc {
    use lazy_static::lazy_static;

    use std::env;

    use crate::conn::opts::{Opts, OptsBuilder};
    use crate::SslOpts;

    #[allow(dead_code)]
    fn error_should_implement_send_and_sync() {
        fn _dummy<T: Send + Sync>(_: T) {}
        _dummy(crate::error::Error::FromValueError(crate::Value::NULL));
    }

    lazy_static! {
        pub static ref DATABASE_URL: String = {
            if let Ok(url) = env::var("DATABASE_URL") {
                let opts = Opts::from_url(&url).expect("DATABASE_URL invalid");
                if opts
                    .get_db_name()
                    .expect("a database name is required")
                    .is_empty()
                {
                    panic!("database name is empty");
                }
                url
            } else {
                "mysql://root:password@127.0.0.1:3307/mysql".into()
            }
        };
    }

    pub fn get_opts() -> OptsBuilder {
        let mut builder = OptsBuilder::from_opts(&**DATABASE_URL);
        builder.init(vec!["SET GLOBAL sql_mode = 'TRADITIONAL'"]);
        if test_compression() {
            builder.compress(Some(Default::default()));
        }
        if test_ssl() {
            builder.prefer_socket(false);
            let mut ssl_opts = SslOpts::default();
            ssl_opts.set_danger_skip_domain_validation(true);
            ssl_opts.set_danger_accept_invalid_certs(true);
            builder.ssl_opts(ssl_opts);
        }
        builder
    }

    pub fn test_ssl() -> bool {
        let ssl = env::var("SSL").ok().unwrap_or("false".into());
        ssl == "true" || ssl == "1"
    }

    pub fn test_compression() -> bool {
        let compress = env::var("COMPRESS").ok().unwrap_or("false".into());
        compress == "true" || compress == "1"
    }
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 Sam Doshi (sam@metal-fish.co.uk)
// Copyright 2013-2014 Philippe Delrieu (philippe.delrieu@free.fr)
//
// Licensed under either of
//          Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
//          MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT).
// This file may not be copied, modified, or distributed except according to those terms.
use std::ptr;
use std::os::raw::c_char;

mod ffi;
use ffi::MaybeError;
pub mod types;
pub use types::*;

// Global fns
// ----------
/// `initialize` initalizes the underlying PortMidi C library, call this
/// before using the library.
///
/// Once initialized, PortMidi will no longer pickup any new Midi devices that are
/// connected, i.e. it does not support hot plugging.
pub fn initialize() -> PortMidiResult<()> {
    PortMidiResult::from(unsafe { ffi::Pm_Initialize() })
}

/// `terminate` terminates the underlying PortMidi C library, call this
/// after using the library.
pub fn terminate() -> PortMidiResult<()> {
    PortMidiResult::from(unsafe { ffi::Pm_Terminate() })
}

/// Return the number of devices. This number will not change during the lifetime
/// of the program.
pub fn count_devices() -> PortMidiDeviceId {
    unsafe { ffi::Pm_CountDevices() }
}

/// Gets the `PortMidiDeviceId` for the default input, or `None` if
/// there isn't one
///
/// See the PortMidi documentation for details of how to set the default device
pub fn get_default_input_device_id() -> Option<PortMidiDeviceId> {
    let id = unsafe { ffi::Pm_GetDefaultInputDeviceID() };
    if id == ffi::PM_NO_DEVICE {
        None
    } else {
        Some(id)
    }
}

/// Gets the `PortMidiDeviceId` for the default output, or `None` if
/// there isn't one
///
/// See the PortMidi documentation for details of how to set the default device
pub fn get_default_output_device_id() -> Option<PortMidiDeviceId> {
    let id = unsafe { ffi::Pm_GetDefaultOutputDeviceID() };
    if id == ffi::PM_NO_DEVICE {
        None
    } else {
        Some(id)
    }
}

// DeviceInfo
// ----------
/// Represents what we know about a device
#[derive(Clone, Debug)]
pub struct DeviceInfo {
    /// The `PortMidiDeviceId` used with `OutputPort::new` and `InputPort::new`
    pub device_id: PortMidiDeviceId,
    /// The name of the device
    pub name: String,
    /// Is the device an input
    pub input: bool,
    /// Is the device an output
    pub output: bool,
}

impl DeviceInfo {
    fn wrap(device_id: PortMidiDeviceId, device_info: *const ffi::PmDeviceInfo) -> DeviceInfo {
        let name = unsafe {
            let bytes = std::ffi::CStr::from_ptr((*device_info).name).to_bytes();
            std::str::from_utf8_unchecked(bytes).to_string()
        };
        let input = unsafe { (*device_info).input };
        let output = unsafe { (*device_info).output };

        DeviceInfo {
            device_id: device_id,
            name: name,
            input: input > 0,
            output: output > 0,
        }
    }
}

/// Returns a `DeviceInfo` with information about a device, or `None` if
/// it does not exist
pub fn get_device_info(device_id: PortMidiDeviceId) -> Option<DeviceInfo> {
    let info = unsafe { ffi::Pm_GetDeviceInfo(device_id) };
    if info.is_null() {
        None
    } else {
        Some(DeviceInfo::wrap(device_id, info))
    }
}

// Midi events
// -----------
/// Represents a single midi message, see also `MidiEvent`
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct MidiMessage {
    pub status: u8,
    pub data1: u8,
    pub data2: u8,
}

impl MidiMessage {
    fn wrap(cmessage: ffi::PmMessage) -> MidiMessage {
        MidiMessage {
            status: ((cmessage) & 0xFF) as u8,
            data1: (((cmessage) >> 8) & 0xFF) as u8,
            data2: (((cmessage) >> 16) & 0xFF) as u8,
        }
    }

    fn unwrap(&self) -> ffi::PmMessage {
        ((((self.data2 as i32) << 16) & 0xFF0000) | (((self.data1 as i32) << 8) & 0xFF00) |
         ((self.status as i32) & 0xFF)) as i32
    }
}

/// Represents a time stamped midi event. See also `MidiMessage`
///
/// See the PortMidi documentation for how SysEx and midi realtime messages
/// are handled
///
/// TODO: what to do about the timestamp?
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct MidiEvent {
    pub message: MidiMessage,
    pub timestamp: ffi::PmTimestamp,
}

impl MidiEvent {
    fn wrap(event: ffi::PmEvent) -> MidiEvent {
        MidiEvent {
            message: MidiMessage::wrap(event.message),
            timestamp: event.timestamp,
        }
    }

    fn unwrap(&self) -> ffi::PmEvent {
        ffi::PmEvent {
            message: self.message.unwrap(),
            timestamp: self.timestamp,
        }
    }
}

// Input
// -----
/// Representation of an input midi port
#[allow(missing_copy_implementations)]
pub struct InputPort {
    pm_stream: *const ffi::PortMidiStream,
    input_device: ffi::PmDeviceId,
    buffer_size: i32,
}

const EVENT_BUFFER_SIZE: usize = 128;
impl InputPort {
    /// Construct a new `InputPort` for `input_device`
    pub fn new(input_device: PortMidiDeviceId, buffer_size: i32) -> InputPort {
        InputPort {
            pm_stream: ptr::null(),
            input_device: input_device,
            buffer_size: buffer_size,
        }
    }

    /// Open the port returning an error if there is a problem
    pub fn open(&mut self) -> PortMidiResult<()> {
        PortMidiResult::from(unsafe {
            ffi::Pm_OpenInput(&self.pm_stream,
                              self.input_device,
                              ptr::null(),
                              self.buffer_size,
                              ptr::null(),
                              ptr::null())
        })
    }

    pub fn read_n(&mut self, cnt: usize) -> PortMidiResult<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > EVENT_BUFFER_SIZE {
            EVENT_BUFFER_SIZE as i32
        } else {
            cnt as i32
        };
        let mut event_buffer = [ffi::PmEvent::default(); EVENT_BUFFER_SIZE];
        let res = unsafe {
            ffi::Pm_Read(self.pm_stream,
                         event_buffer.as_mut_ptr(),
                         read_cnt)
        };
        if res < 0 {
            let err = ffi::PmError::try_from(res).unwrap();
            // TODO: Return the error
            println!("error: {:?}", err);
            return Ok(None);
        } else if res == 0 {
            Ok(None)
        } else {
            // remove mutability and replace return value
            let mut events = (0..res as usize)
                             .map(|i| MidiEvent::wrap(event_buffer[i].clone()))
                             .collect::<Vec<MidiEvent>>();
            Ok(Some(events))
        }
    }

    /// Reads a single `MidiEvent` if one is avaible
    ///
    /// A `Result` of `None` means no event was available.
    ///
    /// See the PortMidi documentation for information on how it deals with input
    /// overflows
    /// TODO: call `read_n`
    pub fn read(&mut self) -> PortMidiResult<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// `poll` tests if there is input available, either returing a bool or an error
    pub fn poll(&self) -> PortMidiResult<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.pm_stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            other => PortMidiResult::from(other).map(|_| false),
        }
    }

    /// Closes the input, flushing any pending buffers
    ///
    /// PortMidi attempts to close open streams when the application
    /// exits, but this can be difficult under Windows
    /// (according to the PortMidi documentation).
    pub fn close(&mut self) -> PortMidiResult<()> {
        PortMidiResult::from(unsafe { ffi::Pm_Close(self.pm_stream) })
    }

    //    Test whether stream has a pending host error. Normally, the client finds
    //    out about errors through returned error codes, but some errors can occur
    //    asynchronously where the client does not
    //    explicitly call a function, and therefore cannot receive an error code.
    //    The client can test for a pending error using has_host_error(). If true,
    //    the error can be accessed and cleared by calling get_Error_text().
    //    Errors are also cleared by calling other functions that can return
    //    errors, e.g. open_input(), open_output(), read(), write(). The
    //    client does not need to call Pm_HasHostError(). Any pending error will be
    //    reported the next time the client performs an explicit function call on
    //    the stream, e.g. an input or output operation. Until the error is cleared,
    //    no new error codes will be obtained, even for a different stream.
    //
    pub fn has_host_error(&self) -> bool {
        unsafe { ffi::Pm_HasHostError(self.pm_stream) > 0 }
    }
}

// Output
// ------
/// Representation of an output midi port
#[allow(missing_copy_implementations)]
pub struct OutputPort {
    pm_stream: *const ffi::PortMidiStream,
    output_device: ffi::PmDeviceId,
    buffer_size: i32,
}
impl OutputPort {
    /// Construct a new `InputPort` for `input_device`
    pub fn new(output_device: PortMidiDeviceId, buffer_size: i32) -> OutputPort {
        OutputPort {
            pm_stream: ptr::null(),
            output_device: output_device,
            buffer_size: buffer_size,
        }
    }

    /// Open the port returning an error if there is a problem
    pub fn open(&mut self) -> PortMidiResult<()> {
        PortMidiResult::from(unsafe {
            ffi::Pm_OpenOutput(&self.pm_stream,
                               self.output_device,
                               ptr::null(),
                               self.buffer_size,
                               ptr::null(),
                               ptr::null(),
                               0)
        })
    }

    /// Terminates outgoing messages immediately
    ///
    /// The caller should immediately close the output port, this may
    /// result in transmission of a partial midi message. Note, not all platforms
    /// support abort.
    pub fn abort(&mut self) -> PortMidiResult<()> {
        PortMidiResult::from(unsafe { ffi::Pm_Abort(self.pm_stream) })
    }

    /// Closes the midi stream, flushing any pending buffers
    ///
    /// PortMidi attempts to close open streams when the application
    /// exits, but this can be difficult under Windows
    /// (according to the PortMidi documentation).
    pub fn close(&mut self) -> PortMidiResult<()> {
        PortMidiResult::from(unsafe { ffi::Pm_Close(self.pm_stream) })
    }

    /// Write a single `MidiEvent`
    pub fn write_event(&mut self, midi_event: MidiEvent) -> PortMidiResult<()> {
        let event = midi_event.unwrap();
        PortMidiResult::from(unsafe { ffi::Pm_Write(self.pm_stream, &event, 1) })
    }

    /// Write a single `MidiMessage` immediately
    pub fn write_message(&mut self, midi_message: MidiMessage) -> PortMidiResult<()> {
        let message = midi_message.unwrap();
        PortMidiResult::from(unsafe { ffi::Pm_WriteShort(self.pm_stream, 0, message) })
    }

    //    Test whether stream has a pending host error. Normally, the client finds
    //    out about errors through returned error codes, but some errors can occur
    //    asynchronously where the client does not
    //    explicitly call a function, and therefore cannot receive an error code.
    //    The client can test for a pending error using has_host_error(). If true,
    //    the error can be accessed and cleared by calling get_Error_text().
    //    Errors are also cleared by calling other functions that can return
    //    errors, e.g. open_input(), open_output(), read(), write(). The
    //    client does not need to call Pm_HasHostError(). Any pending error will be
    //    reported the next time the client performs an explicit function call on
    //    the stream, e.g. an input or output operation. Until the error is cleared,
    //    no new error codes will be obtained, even for a different stream.
    //
    pub fn has_host_error(&self) -> bool {
        unsafe { ffi::Pm_HasHostError(self.pm_stream) > 0 }
    }
}

// Old code
// --------
/**  Translate portmidi error number into human readable message.
*    These strings are constants (set at compile time) so client has
*    no need to allocate storage
*/
pub fn get_error_text(error_code: ffi::PmError) -> String {
    unsafe {
        let error_text = ffi::Pm_GetErrorText(error_code);
        let bytes = std::ffi::CStr::from_ptr(error_text).to_bytes();
        std::str::from_utf8_unchecked(bytes).to_string()
    }
}

/**  Translate portmidi host error into human readable message.
     These strings are computed at run time, so client has to allocate storage.
     After this routine executes, the host error is cleared.
*/
pub fn get_host_error_text(msg: *const c_char, len: i32) {
    unsafe {
        ffi::Pm_GetHostErrorText(msg, len);
    }
}

pub const HDRLENGTH: i32 = 50;
pub const PM_HOST_ERROR_MSG_LEN: i32 = 256;
<commit_msg>s/pm_stream/stream/g<commit_after>// Copyright 2014-2015 Sam Doshi (sam@metal-fish.co.uk)
// Copyright 2013-2014 Philippe Delrieu (philippe.delrieu@free.fr)
//
// Licensed under either of
//          Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
//          MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT).
// This file may not be copied, modified, or distributed except according to those terms.
use std::ptr;
use std::os::raw::c_char;

mod ffi;
use ffi::MaybeError;
pub mod types;
pub use types::*;

// Global fns
// ----------
/// `initialize` initalizes the underlying PortMidi C library, call this
/// before using the library.
///
/// Once initialized, PortMidi will no longer pickup any new Midi devices that are
/// connected, i.e. it does not support hot plugging.
pub fn initialize() -> PortMidiResult<()> {
    PortMidiResult::from(unsafe { ffi::Pm_Initialize() })
}

/// `terminate` terminates the underlying PortMidi C library, call this
/// after using the library.
pub fn terminate() -> PortMidiResult<()> {
    PortMidiResult::from(unsafe { ffi::Pm_Terminate() })
}

/// Return the number of devices. This number will not change during the lifetime
/// of the program.
pub fn count_devices() -> PortMidiDeviceId {
    unsafe { ffi::Pm_CountDevices() }
}

/// Gets the `PortMidiDeviceId` for the default input, or `None` if
/// there isn't one
///
/// See the PortMidi documentation for details of how to set the default device
pub fn get_default_input_device_id() -> Option<PortMidiDeviceId> {
    let id = unsafe { ffi::Pm_GetDefaultInputDeviceID() };
    if id == ffi::PM_NO_DEVICE {
        None
    } else {
        Some(id)
    }
}

/// Gets the `PortMidiDeviceId` for the default output, or `None` if
/// there isn't one
///
/// See the PortMidi documentation for details of how to set the default device
pub fn get_default_output_device_id() -> Option<PortMidiDeviceId> {
    let id = unsafe { ffi::Pm_GetDefaultOutputDeviceID() };
    if id == ffi::PM_NO_DEVICE {
        None
    } else {
        Some(id)
    }
}

// DeviceInfo
// ----------
/// Represents what we know about a device
#[derive(Clone, Debug)]
pub struct DeviceInfo {
    /// The `PortMidiDeviceId` used with `OutputPort::new` and `InputPort::new`
    pub device_id: PortMidiDeviceId,
    /// The name of the device
    pub name: String,
    /// Is the device an input
    pub input: bool,
    /// Is the device an output
    pub output: bool,
}

impl DeviceInfo {
    fn wrap(device_id: PortMidiDeviceId, device_info: *const ffi::PmDeviceInfo) -> DeviceInfo {
        let name = unsafe {
            let bytes = std::ffi::CStr::from_ptr((*device_info).name).to_bytes();
            std::str::from_utf8_unchecked(bytes).to_string()
        };
        let input = unsafe { (*device_info).input };
        let output = unsafe { (*device_info).output };

        DeviceInfo {
            device_id: device_id,
            name: name,
            input: input > 0,
            output: output > 0,
        }
    }
}

/// Returns a `DeviceInfo` with information about a device, or `None` if
/// it does not exist
pub fn get_device_info(device_id: PortMidiDeviceId) -> Option<DeviceInfo> {
    let info = unsafe { ffi::Pm_GetDeviceInfo(device_id) };
    if info.is_null() {
        None
    } else {
        Some(DeviceInfo::wrap(device_id, info))
    }
}

// Midi events
// -----------
/// Represents a single midi message, see also `MidiEvent`
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct MidiMessage {
    pub status: u8,
    pub data1: u8,
    pub data2: u8,
}

impl MidiMessage {
    fn wrap(cmessage: ffi::PmMessage) -> MidiMessage {
        MidiMessage {
            status: ((cmessage) & 0xFF) as u8,
            data1: (((cmessage) >> 8) & 0xFF) as u8,
            data2: (((cmessage) >> 16) & 0xFF) as u8,
        }
    }

    fn unwrap(&self) -> ffi::PmMessage {
        ((((self.data2 as i32) << 16) & 0xFF0000) | (((self.data1 as i32) << 8) & 0xFF00) |
         ((self.status as i32) & 0xFF)) as i32
    }
}

/// Represents a time stamped midi event. See also `MidiMessage`
///
/// See the PortMidi documentation for how SysEx and midi realtime messages
/// are handled
///
/// TODO: what to do about the timestamp?
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct MidiEvent {
    pub message: MidiMessage,
    pub timestamp: ffi::PmTimestamp,
}

impl MidiEvent {
    fn wrap(event: ffi::PmEvent) -> MidiEvent {
        MidiEvent {
            message: MidiMessage::wrap(event.message),
            timestamp: event.timestamp,
        }
    }

    fn unwrap(&self) -> ffi::PmEvent {
        ffi::PmEvent {
            message: self.message.unwrap(),
            timestamp: self.timestamp,
        }
    }
}

// Input
// -----
/// Representation of an input midi port
#[allow(missing_copy_implementations)]
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    input_device: ffi::PmDeviceId,
    buffer_size: i32,
}

const EVENT_BUFFER_SIZE: usize = 128;
impl InputPort {
    /// Construct a new `InputPort` for `input_device`
    pub fn new(input_device: PortMidiDeviceId, buffer_size: i32) -> InputPort {
        InputPort {
            stream: ptr::null(),
            input_device: input_device,
            buffer_size: buffer_size,
        }
    }

    /// Open the port returning an error if there is a problem
    pub fn open(&mut self) -> PortMidiResult<()> {
        PortMidiResult::from(unsafe {
            ffi::Pm_OpenInput(&self.stream,
                              self.input_device,
                              ptr::null(),
                              self.buffer_size,
                              ptr::null(),
                              ptr::null())
        })
    }

    pub fn read_n(&mut self, cnt: usize) -> PortMidiResult<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > EVENT_BUFFER_SIZE {
            EVENT_BUFFER_SIZE as i32
        } else {
            cnt as i32
        };
        let mut event_buffer = [ffi::PmEvent::default(); EVENT_BUFFER_SIZE];
        let res = unsafe {
            ffi::Pm_Read(self.stream,
                         event_buffer.as_mut_ptr(),
                         read_cnt)
        };
        if res < 0 {
            let err = ffi::PmError::try_from(res).unwrap();
            // TODO: Return the error
            println!("error: {:?}", err);
            return Ok(None);
        } else if res == 0 {
            Ok(None)
        } else {
            // remove mutability and replace return value
            let mut events = (0..res as usize)
                             .map(|i| MidiEvent::wrap(event_buffer[i].clone()))
                             .collect::<Vec<MidiEvent>>();
            Ok(Some(events))
        }
    }

    /// Reads a single `MidiEvent` if one is avaible
    ///
    /// A `Result` of `None` means no event was available.
    ///
    /// See the PortMidi documentation for information on how it deals with input
    /// overflows
    /// TODO: call `read_n`
    pub fn read(&mut self) -> PortMidiResult<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// `poll` tests if there is input available, either returing a bool or an error
    pub fn poll(&self) -> PortMidiResult<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            other => PortMidiResult::from(other).map(|_| false),
        }
    }

    /// Closes the input, flushing any pending buffers
    ///
    /// PortMidi attempts to close open streams when the application
    /// exits, but this can be difficult under Windows
    /// (according to the PortMidi documentation).
    pub fn close(&mut self) -> PortMidiResult<()> {
        PortMidiResult::from(unsafe { ffi::Pm_Close(self.stream) })
    }

    //    Test whether stream has a pending host error. Normally, the client finds
    //    out about errors through returned error codes, but some errors can occur
    //    asynchronously where the client does not
    //    explicitly call a function, and therefore cannot receive an error code.
    //    The client can test for a pending error using has_host_error(). If true,
    //    the error can be accessed and cleared by calling get_Error_text().
    //    Errors are also cleared by calling other functions that can return
    //    errors, e.g. open_input(), open_output(), read(), write(). The
    //    client does not need to call Pm_HasHostError(). Any pending error will be
    //    reported the next time the client performs an explicit function call on
    //    the stream, e.g. an input or output operation. Until the error is cleared,
    //    no new error codes will be obtained, even for a different stream.
    //
    fn has_host_error(&self) -> bool {
        unsafe { ffi::Pm_HasHostError(self.stream) > 0 }
    }
}

// Output
// ------
/// Representation of an output midi port
#[allow(missing_copy_implementations)]
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
    output_device: ffi::PmDeviceId,
    buffer_size: i32,
}
impl OutputPort {
    /// Construct a new `InputPort` for `input_device`
    pub fn new(output_device: PortMidiDeviceId, buffer_size: i32) -> OutputPort {
        OutputPort {
            stream: ptr::null(),
            output_device: output_device,
            buffer_size: buffer_size,
        }
    }

    /// Open the port returning an error if there is a problem
    pub fn open(&mut self) -> PortMidiResult<()> {
        PortMidiResult::from(unsafe {
            ffi::Pm_OpenOutput(&self.stream,
                               self.output_device,
                               ptr::null(),
                               self.buffer_size,
                               ptr::null(),
                               ptr::null(),
                               0)
        })
    }

    /// Terminates outgoing messages immediately
    ///
    /// The caller should immediately close the output port, this may
    /// result in transmission of a partial midi message. Note, not all platforms
    /// support abort.
    pub fn abort(&mut self) -> PortMidiResult<()> {
        PortMidiResult::from(unsafe { ffi::Pm_Abort(self.stream) })
    }

    /// Closes the midi stream, flushing any pending buffers
    ///
    /// PortMidi attempts to close open streams when the application
    /// exits, but this can be difficult under Windows
    /// (according to the PortMidi documentation).
    pub fn close(&mut self) -> PortMidiResult<()> {
        PortMidiResult::from(unsafe { ffi::Pm_Close(self.stream) })
    }

    /// Write a single `MidiEvent`
    pub fn write_event(&mut self, midi_event: MidiEvent) -> PortMidiResult<()> {
        let event = midi_event.unwrap();
        PortMidiResult::from(unsafe { ffi::Pm_Write(self.stream, &event, 1) })
    }

    /// Write a single `MidiMessage` immediately
    pub fn write_message(&mut self, midi_message: MidiMessage) -> PortMidiResult<()> {
        let message = midi_message.unwrap();
        PortMidiResult::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, message) })
    }

    //    Test whether stream has a pending host error. Normally, the client finds
    //    out about errors through returned error codes, but some errors can occur
    //    asynchronously where the client does not
    //    explicitly call a function, and therefore cannot receive an error code.
    //    The client can test for a pending error using has_host_error(). If true,
    //    the error can be accessed and cleared by calling get_Error_text().
    //    Errors are also cleared by calling other functions that can return
    //    errors, e.g. open_input(), open_output(), read(), write(). The
    //    client does not need to call Pm_HasHostError(). Any pending error will be
    //    reported the next time the client performs an explicit function call on
    //    the stream, e.g. an input or output operation. Until the error is cleared,
    //    no new error codes will be obtained, even for a different stream.
    //
    pub fn has_host_error(&self) -> bool {
        unsafe { ffi::Pm_HasHostError(self.stream) > 0 }
    }
}

// Old code
// --------
/**  Translate portmidi error number into human readable message.
*    These strings are constants (set at compile time) so client has
*    no need to allocate storage
*/
pub fn get_error_text(error_code: ffi::PmError) -> String {
    unsafe {
        let error_text = ffi::Pm_GetErrorText(error_code);
        let bytes = std::ffi::CStr::from_ptr(error_text).to_bytes();
        std::str::from_utf8_unchecked(bytes).to_string()
    }
}

/**  Translate portmidi host error into human readable message.
     These strings are computed at run time, so client has to allocate storage.
     After this routine executes, the host error is cleared.
*/
pub fn get_host_error_text(msg: *const c_char, len: i32) {
    unsafe {
        ffi::Pm_GetHostErrorText(msg, len);
    }
}

pub const HDRLENGTH: i32 = 50;
pub const PM_HOST_ERROR_MSG_LEN: i32 = 256;
<|endoftext|>