<commit_before>use super::utils::*;
use super::surname;
use super::namecase;
use std::borrow::Cow;
use std::ascii::AsciiExt;
use phf;
use unicode_segmentation::UnicodeSegmentation;

// If Start and End overlap, use End
#[derive(Eq,PartialEq,Debug)]
pub enum Location {
    Start,
    Middle,
    End,
}

pub struct NameParts<'a> {
    text: &'a str,
    trust_capitalization: bool,
    location: Location,
}

impl <'a>NameParts<'a> {
    fn next_location(&mut self) -> Location {
        if self.location == Location::Middle {
            // If the whole section is in the middle, so are all parts
            Location::Middle
        } else if self.location == Location::Start {
            self.location = Location::Middle;
            Location::Start
        } else if self.text.chars().find(|c| c.is_alphabetic()).is_none() {
            Location::End
        } else {
            Location::Middle
        }
    }
}

impl <'a>Iterator for NameParts<'a> {
    type Item = NamePart<'a>;

    fn next(&mut self) -> Option<NamePart<'a>> {
        // Skip any leading whitespace
        self.text = self.text.trim_left();

        if self.text.is_empty() {
            return None;
        }

        // Now look for the next whitespace that remains
        let next_whitespace = self.text.find(char::is_whitespace).unwrap_or(self.text.len());
        let next_inner_period = self.text[0..next_whitespace].find('.');
        let next_boundary = match next_inner_period {
            Some(i) => i + 1,
            None => next_whitespace,
        };

        let word = &self.text[0..next_boundary];

        if word == "&" {
            // Special case: only allowed word without alphabetical characters
            self.text = &self.text[next_boundary..];
            Some(NamePart {
                word: word,
                chars: 1,
                category: Category::Other,
                namecased: Cow::Borrowed(word),
            })
        } else if !word.chars().any(char::is_alphabetic) {
            // Not a word, skip it by recursing
            self.text = &self.text[next_boundary..];
            self.next()
        } else if !word.chars().any(|c| c.is_ascii()) {
            // For non-ASCII, we defer to the unicode_segmentation library
            let (next_word_boundary, subword) = word.split_word_bound_indices()
                                                    .find(|&(_, subword)| {
                                                        subword.chars().any(char::is_alphabetic)
                                                    })
                                                    .unwrap();
            self.text = &self.text[next_word_boundary + subword.len()..];
            Some(NamePart::from_word(subword, self.trust_capitalization, self.next_location()))
        } else {
            // For ASCII, we split on whitespace and periods only
            self.text = &self.text[next_boundary..];
            Some(NamePart::from_word(word, self.trust_capitalization, self.next_location()))
        }
    }
}

#[derive(Eq,PartialEq,Debug)]
pub enum Category {
    Name,
    Initials,
    Abbreviation,
    Other,
}

#[derive(Debug)]
pub struct NamePart<'a> {
    pub word: &'a str,
    pub chars: usize,
    pub category: Category,
    pub namecased: Cow<'a, str>,
}

impl <'a>NamePart<'a> {

    pub fn all_from_text(text: &str, trust_capitalization: bool, location: Location) -> NameParts {
        NameParts {
            text: text,
            trust_capitalization: trust_capitalization,
            location: location,
        }
    }

    pub fn from_word(word: &str, trust_capitalization: bool, location: Location) -> NamePart {
        let chars = word.chars().count();
        let ascii = word.chars().all(|c| c.is_ascii());

        let category = if chars == 1 && ascii {
            Category::Initials
        } else if chars == 1 {
            Category::Name
        } else if word.ends_with('.') {
            if chars > 2 && has_sequential_alphas(word) {
                Category::Abbreviation
            } else {
                Category::Initials
            }
        } else if word.chars()
                              .filter(|c| !c.is_alphabetic() && !is_combining(*c))
                              .count() > 2 {
            Category::Other
        } else if is_missing_vowels(word) {
            if trust_capitalization &&
               word.chars().all(|c| !c.is_alphabetic() || c.is_uppercase()) {
                Category::Initials
            } else if location == Location::End &&
               surname::is_vowelless_surname(word, trust_capitalization) {
                Category::Name
            } else if chars <= 5 {
                Category::Initials
            } else {
                Category::Other
            }
        } else {
            if chars <= 5 && trust_capitalization &&
               word.chars().all(|c| !c.is_alphabetic() || c.is_uppercase()) {
                Category::Initials
            } else if chars == 2 && !trust_capitalization && !TWO_LETTER_GIVEN_NAMES.contains(word) {
                Category::Initials
            } else {
                Category::Name
            }
        };

        let namecased = if trust_capitalization && ascii && is_capitalized(word) {
            Cow::Borrowed(word)
        } else {
            let might_be_particle = location == Location::Middle;
            Cow::Owned(namecase::namecase(word, might_be_particle))
        };

        NamePart {
            word: word,
            chars: chars,
            category: category,
            namecased: namecased,
        }
    }

    #[inline]
    pub fn is_initials(&self) -> bool {
        self.category == Category::Initials
    }

    #[inline]
    pub fn is_namelike(&self) -> bool {
        self.category == Category::Name
    }

    #[inline]
    pub fn is_abbreviation(&self) -> bool {
        self.category == Category::Abbreviation
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn one_word() {
        assert_eq!(1,
                   NamePart::all_from_text("John", true, Location::Start).count());
    }

    #[test]
    fn two_words() {
        assert_eq!(2,
                   NamePart::all_from_text("&* John Doe! ☃", true, Location::Start).count());
    }

    #[test]
    fn only_junk() {
        assert_eq!(0,
                   NamePart::all_from_text(" ... 23 ", true, Location::Start).count());
    }

    #[test]
    fn single_ascii() {
        assert_eq!(Category::Initials,
                   NamePart::from_word("I", true, Location::Start).category);
    }

    #[test]
    fn single_han() {
        assert_eq!(Category::Name,
                   NamePart::from_word("鄭", true, Location::Start).category);
    }

    #[test]
    fn abbreviated_ascii() {
        assert_eq!(Category::Initials,
                   NamePart::from_word("I.", true, Location::Start).category);
    }

    #[test]
    fn abbreviated_double_ascii() {
        assert_eq!(Category::Abbreviation,
                   NamePart::from_word("MI.", true, Location::Start).category);
    }

    #[test]
    fn double_abbreviated_double_ascii() {
        assert_eq!(Category::Initials,
                   NamePart::from_word("M.I.", true, Location::Start).category);
    }

    #[test]
    fn junk() {
        assert_eq!(Category::Other,
                   NamePart::from_word("503(a)", true, Location::Start).category);
    }

    #[test]
    fn no_vowels() {
        assert_eq!(Category::Initials,
                   NamePart::from_word("JM", true, Location::Start).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("jm", true, Location::Start).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("JM", false, Location::Start).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("JMMMMM", true, Location::Start).category);
        assert_eq!(Category::Other,
                   NamePart::from_word("jmmmmm", true, Location::Start).category);
        assert_eq!(Category::Other,
                   NamePart::from_word("JMMMMM", false, Location::Start).category);
    }

    #[test]
    fn vowelless_surname() {
        assert_eq!(Category::Initials,
                   NamePart::from_word("NG", true, Location::Start).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("Ng", true, Location::Start).category);
        assert_eq!(Category::Name,
                   NamePart::from_word("Ng", true, Location::End).category);
        assert_eq!(Category::Name,
                   NamePart::from_word("NG", false, Location::End).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("NG", true, Location::End).category);
    }

    #[test]
    fn word() {
        assert_eq!(Category::Initials,
                   NamePart::from_word("JEM", true, Location::Start).category);
        assert_eq!(Category::Name,
                   NamePart::from_word("Jem", true, Location::Start).category);
        assert_eq!(Category::Name,
                   NamePart::from_word("JEM", false, Location::Start).category);
    }

    #[test]
    fn two_letters() {
        assert_eq!(Category::Name,
                   NamePart::from_word("Al", true, Location::Start).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("AL", true, Location::Start).category);
        assert_eq!(Category::Name,
                   NamePart::from_word("AL", false, Location::Start).category);
        assert_eq!(Category::Name,
                   NamePart::from_word("At", true, Location::Start).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("AT", true, Location::Start).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("AT", false, Location::Start).category);
    }
}

// Everything with a vowel reasonably popular in the Social Security data:
// https://www.ssa.gov/oact/babynames/limits.html
static TWO_LETTER_GIVEN_NAMES: phf::Set<&'static str> = phf_set! {
    "Jo",
    "JO",
    "jo",
    "Ty",
    "TY",
    "ty",
    "Ed",
    "ED",
    "ed",
    "Al",
    "AL",
    "al",
    "Bo",
    "BO",
    "bo",
    "Lu",
    "LU",
    "lu",
    "Cy",
    "CY",
    "cy",
    "An",
    "AN",
    "an",
    "La",
    "LA",
    "la",
    "Aj",
    "AJ",
    "aj",
    "Le",
    "LE",
    "le",
    "Om",
    "OM",
    "om",
    "Pa",
    "PA",
    "pa",
    "De",
    "DE",
    "de",
    "Ky",
    "KY",
    "ky",
    "My",
    "MY",
    "my",
    "Vy",
    "VY",
    "vy",
    "Vi",
    "VI",
    "vi",
    "Ka",
    "KA",
    "ka",
    "Sy",
    "SY",
    "sy",
    "Vu",
    "VU",
    "vu",
    "Yu",
    "YU",
    "yu",
    "Mi",
    "MI",
    "mi",
    "Su",
    "SU",
    "su",
    "Ma",
    "MA",
    "ma",
    "Ha",
    "HA",
    "ha",
    "Ki",
    "KI",
    "ki",
    "Tu",
    "TU",
    "tu",
    "Ji",
    "JI",
    "ji",
    "Ja",
    "JA",
    "ja",
    "Ly",
    "LY",
    "ly",
    "Li",
    "LI",
    "li",
    "Ai",
    "AI",
    "ai",
    "Ry",
    "RY",
    "ry",
    "Ab",
    "AB",
    "ab",
    "Ho",
    "HO",
    "ho",
    "Da",
    "DA",
    "da",
    "Oz",
    "OZ",
    "oz",
    "El",
    "EL",
    "el",
    "Na",
    "NA",
    "na",
    "Yi",
    "YI",
    "yi",
};
<commit_msg>Add more two-letter given names - nicknames + East Asian from Googling<commit_after>use super::utils::*;
use super::surname;
use super::namecase;
use std::borrow::Cow;
use std::ascii::AsciiExt;
use phf;
use unicode_segmentation::UnicodeSegmentation;

// If Start and End overlap, use End
#[derive(Eq,PartialEq,Debug)]
pub enum Location {
    Start,
    Middle,
    End,
}

pub struct NameParts<'a> {
    text: &'a str,
    trust_capitalization: bool,
    location: Location,
}

impl <'a>NameParts<'a> {
    fn next_location(&mut self) -> Location {
        if self.location == Location::Middle {
            // If the whole section is in the middle, so are all parts
            Location::Middle
        } else if self.location == Location::Start {
            self.location = Location::Middle;
            Location::Start
        } else if self.text.chars().find(|c| c.is_alphabetic()).is_none() {
            Location::End
        } else {
            Location::Middle
        }
    }
}

impl <'a>Iterator for NameParts<'a> {
    type Item = NamePart<'a>;

    fn next(&mut self) -> Option<NamePart<'a>> {
        // Skip any leading whitespace
        self.text = self.text.trim_left();

        if self.text.is_empty() {
            return None;
        }

        // Now look for the next whitespace that remains
        let next_whitespace = self.text.find(char::is_whitespace).unwrap_or(self.text.len());
        let next_inner_period = self.text[0..next_whitespace].find('.');
        let next_boundary = match next_inner_period {
            Some(i) => i + 1,
            None => next_whitespace,
        };

        let word = &self.text[0..next_boundary];

        if word == "&" {
            // Special case: only allowed word without alphabetical characters
            self.text = &self.text[next_boundary..];
            Some(NamePart {
                word: word,
                chars: 1,
                category: Category::Other,
                namecased: Cow::Borrowed(word),
            })
        } else if !word.chars().any(char::is_alphabetic) {
            // Not a word, skip it by recursing
            self.text = &self.text[next_boundary..];
            self.next()
        } else if !word.chars().any(|c| c.is_ascii()) {
            // For non-ASCII, we defer to the unicode_segmentation library
            let (next_word_boundary, subword) = word.split_word_bound_indices()
                                                    .find(|&(_, subword)| {
                                                        subword.chars().any(char::is_alphabetic)
                                                    })
                                                    .unwrap();
            self.text = &self.text[next_word_boundary + subword.len()..];
            Some(NamePart::from_word(subword, self.trust_capitalization, self.next_location()))
        } else {
            // For ASCII, we split on whitespace and periods only
            self.text = &self.text[next_boundary..];
            Some(NamePart::from_word(word, self.trust_capitalization, self.next_location()))
        }
    }
}

#[derive(Eq,PartialEq,Debug)]
pub enum Category {
    Name,
    Initials,
    Abbreviation,
    Other,
}

#[derive(Debug)]
pub struct NamePart<'a> {
    pub word: &'a str,
    pub chars: usize,
    pub category: Category,
    pub namecased: Cow<'a, str>,
}

impl <'a>NamePart<'a> {

    pub fn all_from_text(text: &str, trust_capitalization: bool, location: Location) -> NameParts {
        NameParts {
            text: text,
            trust_capitalization: trust_capitalization,
            location: location,
        }
    }

    pub fn from_word(word: &str, trust_capitalization: bool, location: Location) -> NamePart {
        let chars = word.chars().count();
        let ascii = word.chars().all(|c| c.is_ascii());

        let category = if chars == 1 && ascii {
            Category::Initials
        } else if chars == 1 {
            Category::Name
        } else if word.ends_with('.') {
            if chars > 2 && has_sequential_alphas(word) {
                Category::Abbreviation
            } else {
                Category::Initials
            }
        } else if word.chars()
                              .filter(|c| !c.is_alphabetic() && !is_combining(*c))
                              .count() > 2 {
            Category::Other
        } else if is_missing_vowels(word) {
            if trust_capitalization &&
               word.chars().all(|c| !c.is_alphabetic() || c.is_uppercase()) {
                Category::Initials
            } else if location == Location::End &&
               surname::is_vowelless_surname(word, trust_capitalization) {
                Category::Name
            } else if chars <= 5 {
                Category::Initials
            } else {
                Category::Other
            }
        } else {
            if chars <= 5 && trust_capitalization &&
               word.chars().all(|c| !c.is_alphabetic() || c.is_uppercase()) {
                Category::Initials
            } else if chars == 2 && !trust_capitalization && !TWO_LETTER_GIVEN_NAMES.contains(word) {
                Category::Initials
            } else {
                Category::Name
            }
        };

        let namecased = if trust_capitalization && ascii && is_capitalized(word) {
            Cow::Borrowed(word)
        } else {
            let might_be_particle = location == Location::Middle;
            Cow::Owned(namecase::namecase(word, might_be_particle))
        };

        NamePart {
            word: word,
            chars: chars,
            category: category,
            namecased: namecased,
        }
    }

    #[inline]
    pub fn is_initials(&self) -> bool {
        self.category == Category::Initials
    }

    #[inline]
    pub fn is_namelike(&self) -> bool {
        self.category == Category::Name
    }

    #[inline]
    pub fn is_abbreviation(&self) -> bool {
        self.category == Category::Abbreviation
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn one_word() {
        assert_eq!(1,
                   NamePart::all_from_text("John", true, Location::Start).count());
    }

    #[test]
    fn two_words() {
        assert_eq!(2,
                   NamePart::all_from_text("&* John Doe! ☃", true, Location::Start).count());
    }

    #[test]
    fn only_junk() {
        assert_eq!(0,
                   NamePart::all_from_text(" ... 23 ", true, Location::Start).count());
    }

    #[test]
    fn single_ascii() {
        assert_eq!(Category::Initials,
                   NamePart::from_word("I", true, Location::Start).category);
    }

    #[test]
    fn single_han() {
        assert_eq!(Category::Name,
                   NamePart::from_word("鄭", true, Location::Start).category);
    }

    #[test]
    fn abbreviated_ascii() {
        assert_eq!(Category::Initials,
                   NamePart::from_word("I.", true, Location::Start).category);
    }

    #[test]
    fn abbreviated_double_ascii() {
        assert_eq!(Category::Abbreviation,
                   NamePart::from_word("MI.", true, Location::Start).category);
    }

    #[test]
    fn double_abbreviated_double_ascii() {
        assert_eq!(Category::Initials,
                   NamePart::from_word("M.I.", true, Location::Start).category);
    }

    #[test]
    fn junk() {
        assert_eq!(Category::Other,
                   NamePart::from_word("503(a)", true, Location::Start).category);
    }

    #[test]
    fn no_vowels() {
        assert_eq!(Category::Initials,
                   NamePart::from_word("JM", true, Location::Start).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("jm", true, Location::Start).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("JM", false, Location::Start).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("JMMMMM", true, Location::Start).category);
        assert_eq!(Category::Other,
                   NamePart::from_word("jmmmmm", true, Location::Start).category);
        assert_eq!(Category::Other,
                   NamePart::from_word("JMMMMM", false, Location::Start).category);
    }

    #[test]
    fn vowelless_surname() {
        assert_eq!(Category::Initials,
                   NamePart::from_word("NG", true, Location::Start).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("Ng", true, Location::Start).category);
        assert_eq!(Category::Name,
                   NamePart::from_word("Ng", true, Location::End).category);
        assert_eq!(Category::Name,
                   NamePart::from_word("NG", false, Location::End).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("NG", true, Location::End).category);
    }

    #[test]
    fn word() {
        assert_eq!(Category::Initials,
                   NamePart::from_word("JEM", true, Location::Start).category);
        assert_eq!(Category::Name,
                   NamePart::from_word("Jem", true, Location::Start).category);
        assert_eq!(Category::Name,
                   NamePart::from_word("JEM", false, Location::Start).category);
    }

    #[test]
    fn two_letters() {
        assert_eq!(Category::Name,
                   NamePart::from_word("Al", true, Location::Start).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("AL", true, Location::Start).category);
        assert_eq!(Category::Name,
                   NamePart::from_word("AL", false, Location::Start).category);
        assert_eq!(Category::Name,
                   NamePart::from_word("At", true, Location::Start).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("AT", true, Location::Start).category);
        assert_eq!(Category::Initials,
                   NamePart::from_word("AT", false, Location::Start).category);
    }
}

// Everything with a vowel reasonably popular in the Social Security data:
// https://www.ssa.gov/oact/babynames/limits.html
static TWO_LETTER_GIVEN_NAMES: phf::Set<&'static str> = phf_set! {
    "Jo",
    "JO",
    "jo",
    "Ty",
    "TY",
    "ty",
    "Ed",
    "ED",
    "ed",
    "Al",
    "AL",
    "al",
    "Bo",
    "BO",
    "bo",
    "Lu",
    "LU",
    "lu",
    "Cy",
    "CY",
    "cy",
    "An",
    "AN",
    "an",
    "La",
    "LA",
    "la",
    "Aj",
    "AJ",
    "aj",
    "Le",
    "LE",
    "le",
    "Om",
    "OM",
    "om",
    "Pa",
    "PA",
    "pa",
    "De",
    "DE",
    "de",
    "Ky",
    "KY",
    "ky",
    "My",
    "MY",
    "my",
    "Vy",
    "VY",
    "vy",
    "Vi",
    "VI",
    "vi",
    "Ka",
    "KA",
    "ka",
    "Sy",
    "SY",
    "sy",
    "Vu",
    "VU",
    "vu",
    "Yu",
    "YU",
    "yu",
    "Mi",
    "MI",
    "mi",
    "Su",
    "SU",
    "su",
    "Ma",
    "MA",
    "ma",
    "Ha",
    "HA",
    "ha",
    "Ki",
    "KI",
    "ki",
    "Tu",
    "TU",
    "tu",
    "Ji",
    "JI",
    "ji",
    "Ja",
    "JA",
    "ja",
    "Ly",
    "LY",
    "ly",
    "Li",
    "LI",
    "li",
    "Ai",
    "AI",
    "ai",
    "Ry",
    "RY",
    "ry",
    "Ab",
    "AB",
    "ab",
    "Ho",
    "HO",
    "ho",
    "Da",
    "DA",
    "da",
    "Oz",
    "OZ",
    "oz",
    "El",
    "EL",
    "el",
    "Na",
    "NA",
    "na",
    "Yi",
    "YI",
    "yi",
    "Em",
    "EM",
    "em",
    "Di",
    "DI",
    "di",
    "Go",
    "GO",
    "go",
    "Ev",
    "EV",
    "ev",
    "Ho",
    "HO",
    "ho",
    "Mo",
    "MO",
    "mo",
    "Lo",
    "LO",
    "lo",
    "Ra",
    "RA",
    "ra",
    "Do",
    "DO",
    "do",
    "Gi",
    "GI",
    "gi",
};
<|endoftext|>


<commit_before>//! Various definitions of types, constants, traint, ... related to network

use core::fmt::{
    Binary,
    Octal,
    LowerHex,
    UpperHex,
    Debug,
    Display,
    Formatter,
    Error
};

use vec::Vec;
use string::String;

use num::PrimInt;

use net::Packet;

/// Trait implemented by hardware interfaces
pub trait Device {
    /// Periodically called by the network thread to let the interface
    /// refresh its rx/tx buffers, ...
    fn refresh(&mut self);

    /// Transmit a packet via the interface
    fn tx_packet(&mut self, pkt: Packet);
}

/// Network integer representation
///
/// This type stores an integer using network's endianness and let the user
/// manipulates it using host's endianness.
#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Int<T: PrimInt + Clone>(T);

impl<T> Int<T> where T: PrimInt + Clone {
    /// Construct from an integer represented using network's endianness
    pub fn from_net(i: T) -> Self {
        Int(i)
    }

    /// Construct from an integer represented using host's endianness
    pub fn from_host(i: T) -> Self {
        Int(i.to_be())
    }

    /// Returns the contained integer using host's endianness
    pub fn as_host(&self) -> T {
        T::from_be(self.0.clone())
    }

    /// Returns the contained integer using network's endianness
    pub fn as_net(&self) -> T {
        self.0.clone()
    }
}

impl<T> Binary for Int<T> where T: PrimInt + Clone + Binary {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Octal for Int<T> where T: PrimInt + Clone + Octal {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> LowerHex for Int<T> where T: PrimInt + Clone + LowerHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> UpperHex for Int<T> where T: PrimInt + Clone + UpperHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Debug for Int<T> where T: PrimInt + Clone + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Display for Int<T> where T: PrimInt + Clone + Display {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

const COUNT_HWADDR_BYTES: usize = 6;

#[repr(C, packed)]
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IPv4 address
pub struct Ipv4Addr {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
}

impl Ipv4Addr {
    /// Creates a new IPv4 address
    ///
    /// The result will represent the IP address `a`.`b`.`c`.`d`
    pub fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
        Ipv4Addr {
            a: a,
            b: b,
            c: c,
            d: d,
        }
    }
}

impl Display for Ipv4Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}.{}.{}.{}", self.a, self.b, self.c,
                                 self.d))
    }
}

#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IPv6 address
pub struct Ipv6Addr {
    a: Int<u16>,
    b: Int<u16>,
    c: Int<u16>,
    d: Int<u16>,
    e: Int<u16>,
    f: Int<u16>,
    g: Int<u16>,
    h: Int<u16>,
}

impl Ipv6Addr {
    /// Creates a new IPv6 address
    ///
    /// The result will represent the IP address `a`:`b`:`c`:`d`:`e`:`f`:`g`:`h`
    pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
               h: u16) -> Ipv6Addr {
        Ipv6Addr {
            a: Int::from_host(a),
            b: Int::from_host(b),
            c: Int::from_host(c),
            d: Int::from_host(d),
            e: Int::from_host(e),
            f: Int::from_host(f),
            g: Int::from_host(g),
            h: Int::from_host(h),
        }
    }
}

impl Display for Ipv6Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}:{}:{}:{}:{}:{}:{}:{}", self.a, self.b,
                                 self.c, self.d, self.e, self.f, self.g,
                                 self.h))
    }
}

#[repr(C, packed)]
#[derive(Copy, Clone)]
/// A MAC address
pub struct HwAddr {
    bytes: [u8; COUNT_HWADDR_BYTES],
}

impl HwAddr {
    /// Create an empty hardware address (i.e., 00:00:00:00:00:00)
    pub fn empty() -> Self {
        HwAddr {
            bytes: [0; COUNT_HWADDR_BYTES],
        }
    }

    /// Convert a string with format XX:XX:XX:XX:XX:XX to an hardware address
    pub fn from_str(s: String) -> Result<Self, ()> {
        let split: Vec<&str> = s.split(':').collect();

        if split.len() != COUNT_HWADDR_BYTES {
            return Err(())
        }

        let mut i = 0;
        let mut ret = Self::empty();

        for b in split {
            let bytes = b.as_bytes();

            if bytes.len() != 2 {
                return Err(())
            }

            let d1 = try!(b.char_at(0).to_digit(16).ok_or(())) * 16;
            let d2 = try!(b.char_at(1).to_digit(16).ok_or(()));

            ret.bytes[i] = d1 as u8 + d2 as u8;

            i += 1;
        }

        Ok(ret)
    }

    /// Create an hardware address from bytes.
    ///
    /// This method is unsafe because the slice *MUST* contain at least 6
    /// elements.
    pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
        let mut ret = Self::empty();

        ret.bytes[0] = bytes[0];
        ret.bytes[1] = bytes[1];
        ret.bytes[2] = bytes[2];
        ret.bytes[3] = bytes[3];
        ret.bytes[4] = bytes[4];
        ret.bytes[5] = bytes[5];

        ret
    }

    #[inline]
    /// Returns the internal representation of an hardware address
    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..]
    }
}

impl PartialEq for HwAddr {
    fn eq(&self, rhs: &Self) -> bool {
        self.bytes[0] == rhs.bytes[0] &&
        self.bytes[1] == rhs.bytes[1] &&
        self.bytes[2] == rhs.bytes[2] &&
        self.bytes[3] == rhs.bytes[3] &&
        self.bytes[4] == rhs.bytes[4] &&
        self.bytes[5] == rhs.bytes[5]
    }
}

impl Display for HwAddr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
                                 self.bytes[0], self.bytes[1], self.bytes[2],
                                 self.bytes[3], self.bytes[4], self.bytes[5]))
    }
}
<commit_msg>net/defs: HwAddr now derives Ord, PartialOrd, Eq, PartialEq<commit_after>//! Various definitions of types, constants, traint, ... related to network

use core::fmt::{
    Binary,
    Octal,
    LowerHex,
    UpperHex,
    Debug,
    Display,
    Formatter,
    Error
};

use vec::Vec;
use string::String;

use num::PrimInt;

use net::Packet;

/// Trait implemented by hardware interfaces
pub trait Device {
    /// Periodically called by the network thread to let the interface
    /// refresh its rx/tx buffers, ...
    fn refresh(&mut self);

    /// Transmit a packet via the interface
    fn tx_packet(&mut self, pkt: Packet);
}

/// Network integer representation
///
/// This type stores an integer using network's endianness and let the user
/// manipulates it using host's endianness.
#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Int<T: PrimInt + Clone>(T);

impl<T> Int<T> where T: PrimInt + Clone {
    /// Construct from an integer represented using network's endianness
    pub fn from_net(i: T) -> Self {
        Int(i)
    }

    /// Construct from an integer represented using host's endianness
    pub fn from_host(i: T) -> Self {
        Int(i.to_be())
    }

    /// Returns the contained integer using host's endianness
    pub fn as_host(&self) -> T {
        T::from_be(self.0.clone())
    }

    /// Returns the contained integer using network's endianness
    pub fn as_net(&self) -> T {
        self.0.clone()
    }
}

impl<T> Binary for Int<T> where T: PrimInt + Clone + Binary {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Octal for Int<T> where T: PrimInt + Clone + Octal {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> LowerHex for Int<T> where T: PrimInt + Clone + LowerHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> UpperHex for Int<T> where T: PrimInt + Clone + UpperHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Debug for Int<T> where T: PrimInt + Clone + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Display for Int<T> where T: PrimInt + Clone + Display {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

const COUNT_HWADDR_BYTES: usize = 6;

#[repr(C, packed)]
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IPv4 address
pub struct Ipv4Addr {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
}

impl Ipv4Addr {
    /// Creates a new IPv4 address
    ///
    /// The result will represent the IP address `a`.`b`.`c`.`d`
    pub fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
        Ipv4Addr {
            a: a,
            b: b,
            c: c,
            d: d,
        }
    }
}

impl Display for Ipv4Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}.{}.{}.{}", self.a, self.b, self.c,
                                 self.d))
    }
}

#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IPv6 address
pub struct Ipv6Addr {
    a: Int<u16>,
    b: Int<u16>,
    c: Int<u16>,
    d: Int<u16>,
    e: Int<u16>,
    f: Int<u16>,
    g: Int<u16>,
    h: Int<u16>,
}

impl Ipv6Addr {
    /// Creates a new IPv6 address
    ///
    /// The result will represent the IP address `a`:`b`:`c`:`d`:`e`:`f`:`g`:`h`
    pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
               h: u16) -> Ipv6Addr {
        Ipv6Addr {
            a: Int::from_host(a),
            b: Int::from_host(b),
            c: Int::from_host(c),
            d: Int::from_host(d),
            e: Int::from_host(e),
            f: Int::from_host(f),
            g: Int::from_host(g),
            h: Int::from_host(h),
        }
    }
}

impl Display for Ipv6Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}:{}:{}:{}:{}:{}:{}:{}", self.a, self.b,
                                 self.c, self.d, self.e, self.f, self.g,
                                 self.h))
    }
}

#[repr(C, packed)]
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
/// A MAC address
pub struct HwAddr {
    bytes: [u8; COUNT_HWADDR_BYTES],
}

impl HwAddr {
    /// Create an empty hardware address (i.e., 00:00:00:00:00:00)
    pub fn empty() -> Self {
        HwAddr {
            bytes: [0; COUNT_HWADDR_BYTES],
        }
    }

    /// Convert a string with format XX:XX:XX:XX:XX:XX to an hardware address
    pub fn from_str(s: String) -> Result<Self, ()> {
        let split: Vec<&str> = s.split(':').collect();

        if split.len() != COUNT_HWADDR_BYTES {
            return Err(())
        }

        let mut i = 0;
        let mut ret = Self::empty();

        for b in split {
            let bytes = b.as_bytes();

            if bytes.len() != 2 {
                return Err(())
            }

            let d1 = try!(b.char_at(0).to_digit(16).ok_or(())) * 16;
            let d2 = try!(b.char_at(1).to_digit(16).ok_or(()));

            ret.bytes[i] = d1 as u8 + d2 as u8;

            i += 1;
        }

        Ok(ret)
    }

    /// Create an hardware address from bytes.
    ///
    /// This method is unsafe because the slice *MUST* contain at least 6
    /// elements.
    pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
        let mut ret = Self::empty();

        ret.bytes[0] = bytes[0];
        ret.bytes[1] = bytes[1];
        ret.bytes[2] = bytes[2];
        ret.bytes[3] = bytes[3];
        ret.bytes[4] = bytes[4];
        ret.bytes[5] = bytes[5];

        ret
    }

    #[inline]
    /// Returns the internal representation of an hardware address
    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..]
    }
}

impl Display for HwAddr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
                                 self.bytes[0], self.bytes[1], self.bytes[2],
                                 self.bytes[3], self.bytes[4], self.bytes[5]))
    }
}
<|endoftext|>


<commit_before>use futures;
use futures::future::Future;
use futures::stream::Stream;
use futures::unsync::oneshot::{channel, Receiver, Sender};
use std;
use std::io::Result as IoResult;
use std::io::{Read, Write};
use std::net::SocketAddr;
use tokio_io::{AsyncRead, AsyncWrite};

use std::cell::RefCell;
use std::rc::Rc;

use tokio_tcp::{TcpListener, TcpStream};
use tokio_udp::UdpSocket;

use super::L2rUser;
use super::{box_up_err, peer_err_s, wouldblock, BoxedNewPeerFuture, BoxedNewPeerStream, Peer};
use super::{multi, once, ConstructParams, Options, PeerConstructor, Specifier};

#[derive(Debug, Clone)]
pub struct TcpConnect(pub Vec<SocketAddr>);
impl Specifier for TcpConnect {
    fn construct(&self, _: ConstructParams) -> PeerConstructor {
        // FIXME: connect to multiple things
        once(tcp_connect_peer(&self.0[0]))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec );
}
specifier_class!(
    name = TcpConnectClass,
    target = TcpConnect,
    prefixes = ["tcp:", "tcp-connect:", "connect-tcp:", "tcp-c:", "c-tcp:"],
    arg_handling = parseresolve,
    overlay = false,
    StreamOriented,
    SingleConnect,
    help = r#"
Connect to specified TCP host and port. Argument is a socket address.

Example: simulate netcat netcat

    websocat - tcp:127.0.0.1:22

Example: redirect websocket connections to local SSH server over IPv6

    websocat ws-l:0.0.0.0:8084 tcp:[::1]:22
"#
);

#[derive(Debug, Clone)]
pub struct TcpListen(pub SocketAddr);
impl Specifier for TcpListen {
    fn construct(&self, p: ConstructParams) -> PeerConstructor {
        multi(tcp_listen_peer(&self.0, p.left_to_right))
    }
    specifier_boilerplate!(noglobalstate multiconnect no_subspec );
}
specifier_class!(
    name = TcpListenClass,
    target = TcpListen,
    prefixes = ["tcp-listen:", "listen-tcp:", "tcp-l:", "l-tcp:"],
    arg_handling = parse,
    overlay = false,
    StreamOriented,
    MultiConnect,
    help = r#"
Listen TCP port on specified address.

Example: echo server

    websocat tcp-l:0.0.0.0:1441 mirror:

Example: redirect TCP to a websocket

    websocat tcp-l:0.0.0.0:8088 ws://echo.websocket.org
"#
);

#[derive(Debug, Clone)]
pub struct UdpConnect(pub SocketAddr);
impl Specifier for UdpConnect {
    fn construct(&self, p: ConstructParams) -> PeerConstructor {
        once(udp_connect_peer(&self.0, &p.program_options))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec );
}
specifier_class!(
    name = UdpConnectClass,
    target = UdpConnect,
    prefixes = ["udp:", "udp-connect:", "connect-udp:", "udp-c:", "c-udp:"],
    arg_handling = parse,
    overlay = false,
    MessageOriented,
    SingleConnect,
    help = r#"
Send and receive packets to specified UDP socket, from random UDP port
"#
);

#[derive(Debug, Clone)]
pub struct UdpListen(pub SocketAddr);
impl Specifier for UdpListen {
    fn construct(&self, p: ConstructParams) -> PeerConstructor {
        once(udp_listen_peer(&self.0, &p.program_options))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec );
}
specifier_class!(
    name = UdpListenClass,
    target = UdpListen,
    prefixes = ["udp-listen:", "listen-udp:", "udp-l:", "l-udp:"],
    arg_handling = parse,
    overlay = false,
    MessageOriented,
    SingleConnect,
    help = r#"
Bind an UDP socket to specified host:port, receive packet
from any remote UDP socket, send replies to recently observed
remote UDP socket.

Note that it is not a multiconnect specifier like e.g. `tcp-listen`:
entire lifecycle of the UDP socket is the same connection.

File a feature request on Github if you want proper DNS-like request-reply UDP mode here.
"#
);

/*
struct RcReadProxy<R>(Rc<R>) where for<'a> &'a R : AsyncRead;

impl<R> AsyncRead for RcReadProxy<R> where for<'a> &'a R : AsyncRead{}
impl<R> Read for RcReadProxy<R> where for<'a> &'a R : AsyncRead {
    fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
        (&*self.0).read(buf)
    }
}

struct RcWriteProxy<W>(Rc<W>) where for<'a> &'a W : AsyncWrite;

impl<W> AsyncWrite for RcWriteProxy<W> where for<'a> &'a W : AsyncWrite {
    fn shutdown(&mut self) -> futures::Poll<(),std::io::Error> {
        (&*self.0).shutdown()
    }
}
impl<W> Write for RcWriteProxy<W> where for<'a> &'a W : AsyncWrite {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        (&*self.0).write(buf)
    }
    fn flush(&mut self) -> IoResult<()> {
        (&*self.0).flush()
    }
}
*/

// based on https://github.com/tokio-rs/tokio-core/blob/master/examples/proxy.rs
#[derive(Clone)]
struct MyTcpStream(Rc<TcpStream>, bool);

impl Read for MyTcpStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        (&*self.0).read(buf)
    }
}

impl Write for MyTcpStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        (&*self.0).write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsyncRead for MyTcpStream {}

impl AsyncWrite for MyTcpStream {
    fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
        try!(self.0.shutdown(std::net::Shutdown::Write));
        Ok(().into())
    }
}

impl Drop for MyTcpStream {
    fn drop(&mut self) {
        let i_am_read_part = self.1;
        if i_am_read_part {
            let _ = self.0.shutdown(std::net::Shutdown::Read);
        }
    }
}

pub fn tcp_connect_peer(addr: &SocketAddr) -> BoxedNewPeerFuture {
    Box::new(
        TcpStream::connect(&addr)
            .map(|x| {
                info!("Connected to TCP");
                let x = Rc::new(x);
                Peer::new(MyTcpStream(x.clone(), true), MyTcpStream(x.clone(), false))
            })
            .map_err(box_up_err),
    ) as BoxedNewPeerFuture
}

pub fn tcp_listen_peer(addr: &SocketAddr, l2r: L2rUser) -> BoxedNewPeerStream {
    let bound = match TcpListener::bind(&addr) {
        Ok(x) => x,
        Err(e) => return peer_err_s(e),
    };
    use tk_listen::ListenExt;
    Box::new(
        bound
            .incoming()
            .sleep_on_error(::std::time::Duration::from_millis(500))
            .map(move |x| {
                let addr = x.peer_addr().ok();
                info!("Incoming TCP connection from {:?}", addr);

                match l2r {
                    L2rUser::FillIn(ref y) => {
                        let mut z = y.borrow_mut();
                        z.client_addr = addr.map(|a| format!("{}", a));
                    }
                    L2rUser::ReadFrom(_) => {}
                }

                let x = Rc::new(x);
                Peer::new(MyTcpStream(x.clone(), true), MyTcpStream(x.clone(), false))
            })
            .map_err(|()| ::simple_err2("unreachable error?")),
    ) as BoxedNewPeerStream
}

#[derive(Debug)]
enum UdpPeerState {
    ConnectMode,
    WaitingForAddress((Sender<()>, Receiver<()>)),
    HasAddress(SocketAddr),
}

struct UdpPeer {
    s: UdpSocket,
    state: Option<UdpPeerState>,
    oneshot_mode: bool,
}

#[derive(Clone)]
struct UdpPeerHandle(Rc<RefCell<UdpPeer>>);

fn get_zero_address(addr: &SocketAddr) -> SocketAddr {
    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
    let ip = match addr.ip() {
        IpAddr::V4(_) => IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
        IpAddr::V6(_) => IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)),
    };
    SocketAddr::new(ip, 0)
}

pub fn udp_connect_peer(addr: &SocketAddr, opts: &Rc<Options>) -> BoxedNewPeerFuture {
    let za = get_zero_address(addr);

    Box::new(futures::future::result(
        UdpSocket::bind(&za)
            .and_then(|x| {
                x.connect(addr)?;

                let h1 = UdpPeerHandle(Rc::new(RefCell::new(UdpPeer {
                    s: x,
                    state: Some(UdpPeerState::ConnectMode),
                    oneshot_mode: opts.udp_oneshot_mode,
                })));
                let h2 = h1.clone();
                Ok(Peer::new(h1, h2))
            })
            .map_err(box_up_err),
    )) as BoxedNewPeerFuture
}

pub fn udp_listen_peer(addr: &SocketAddr, opts: &Rc<Options>) -> BoxedNewPeerFuture {
    Box::new(futures::future::result(
        UdpSocket::bind(addr)
            .and_then(|x| {
                let h1 = UdpPeerHandle(Rc::new(RefCell::new(UdpPeer {
                    s: x,
                    state: Some(UdpPeerState::WaitingForAddress(channel())),
                    oneshot_mode: opts.udp_oneshot_mode,
                })));
                let h2 = h1.clone();
                Ok(Peer::new(h1, h2))
            })
            .map_err(box_up_err),
    )) as BoxedNewPeerFuture
}

impl Read for UdpPeerHandle {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        let mut p = self.0.borrow_mut();
        match p.state.take().expect("Assertion failed 193912") {
            UdpPeerState::ConnectMode => {
                p.state = Some(UdpPeerState::ConnectMode);
                p.s.recv2(buf)
            }
            UdpPeerState::HasAddress(oldaddr) => {
                p.s.recv_from2(buf)
                    .map(|(ret, addr)| {
                        if addr != oldaddr {
                            warn!("New client for the same listening UDP socket");
                        }
                        p.state = Some(UdpPeerState::HasAddress(addr));
                        ret
                    })
                    .map_err(|e| {
                        p.state = Some(UdpPeerState::HasAddress(oldaddr));
                        e
                    })
            }
            UdpPeerState::WaitingForAddress((cmpl, pollster)) => match p.s.recv_from2(buf) {
                Ok((ret, addr)) => {
                    p.state = Some(UdpPeerState::HasAddress(addr));
                    let _ = cmpl.send(());
                    Ok(ret)
                }
                Err(e) => {
                    p.state = Some(UdpPeerState::WaitingForAddress((cmpl, pollster)));
                    Err(e)
                }
            },
        }
    }
}

impl Write for UdpPeerHandle {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        let mut p = self.0.borrow_mut();
        match p.state.take().expect("Assertion failed 193913") {
            UdpPeerState::ConnectMode => {
                p.state = Some(UdpPeerState::ConnectMode);
                p.s.send2(buf)
            }
            UdpPeerState::HasAddress(a) => {
                if p.oneshot_mode {
                    p.state = Some(UdpPeerState::WaitingForAddress(channel()));
                } else {
                    p.state = Some(UdpPeerState::HasAddress(a));
                }
                p.s.send_to2(buf, &a)
            }
            UdpPeerState::WaitingForAddress((cmpl, mut pollster)) => {
                let _ = pollster.poll(); // register wakeup
                p.state = Some(UdpPeerState::WaitingForAddress((cmpl, pollster)));
                wouldblock()
            }
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsyncRead for UdpPeerHandle {}

impl AsyncWrite for UdpPeerHandle {
    fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
        Ok(().into())
    }
}

/// Squirreled await from deprecated UdpSocket functions
trait UndeprecateNonpollSendRecv {
    fn recv2(&mut self, buf: &mut [u8]) -> std::io::Result<usize>;
    fn recv_from2(&mut self, buf: &mut [u8]) -> std::io::Result<(usize, SocketAddr)>;
    fn send2(&mut self, buf: &[u8]) -> std::io::Result<usize>;
    fn send_to2(&mut self, buf: &[u8], target: &SocketAddr) -> std::io::Result<usize>;
}

impl UndeprecateNonpollSendRecv for UdpSocket {
    fn recv2(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        match self.poll_recv(buf)? {
            futures::Async::Ready(n) => Ok(n),
            futures::Async::NotReady => Err(std::io::ErrorKind::WouldBlock.into()),
        }
    }

    fn recv_from2(&mut self, buf: &mut [u8]) -> std::io::Result<(usize, SocketAddr)> {
        match self.poll_recv_from(buf)? {
            futures::Async::Ready(ret) => Ok(ret),
            futures::Async::NotReady => Err(std::io::ErrorKind::WouldBlock.into()),
        }
    }

    fn send2(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        match self.poll_send(buf)? {
            futures::Async::Ready(n) => Ok(n),
            futures::Async::NotReady => Err(std::io::ErrorKind::WouldBlock.into()),
        }
    }

    fn send_to2(&mut self, buf: &[u8], target: &SocketAddr) -> std::io::Result<usize> {
        match self.poll_send_to(buf, target)? {
            futures::Async::Ready(n) => Ok(n),
            futures::Async::NotReady => Err(std::io::ErrorKind::WouldBlock.into()),
        }
    }
}
<commit_msg>Happy Eyeballs for TCP client<commit_after>use futures;
use futures::future::Future;
use futures::stream::Stream;
use futures::unsync::oneshot::{channel, Receiver, Sender};
use std;
use std::io::Result as IoResult;
use std::io::{Read, Write};
use std::net::SocketAddr;
use tokio_io::{AsyncRead, AsyncWrite};

use std::cell::RefCell;
use std::rc::Rc;

use tokio_tcp::{TcpListener, TcpStream};
use tokio_udp::UdpSocket;

use super::L2rUser;
use super::{box_up_err, peer_err_s, wouldblock, BoxedNewPeerFuture, BoxedNewPeerStream, Peer};
use super::{multi, once, ConstructParams, Options, PeerConstructor, Specifier};

#[derive(Debug, Clone)]
pub struct TcpConnect(pub Vec<SocketAddr>);
impl Specifier for TcpConnect {
    fn construct(&self, _: ConstructParams) -> PeerConstructor {
        // FIXME: connect to multiple things
        once(tcp_connect_peer(&self.0[..]))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec );
}
specifier_class!(
    name = TcpConnectClass,
    target = TcpConnect,
    prefixes = ["tcp:", "tcp-connect:", "connect-tcp:", "tcp-c:", "c-tcp:"],
    arg_handling = parseresolve,
    overlay = false,
    StreamOriented,
    SingleConnect,
    help = r#"
Connect to specified TCP host and port. Argument is a socket address.

Example: simulate netcat netcat

    websocat - tcp:127.0.0.1:22

Example: redirect websocket connections to local SSH server over IPv6

    websocat ws-l:0.0.0.0:8084 tcp:[::1]:22
"#
);

#[derive(Debug, Clone)]
pub struct TcpListen(pub SocketAddr);
impl Specifier for TcpListen {
    fn construct(&self, p: ConstructParams) -> PeerConstructor {
        multi(tcp_listen_peer(&self.0, p.left_to_right))
    }
    specifier_boilerplate!(noglobalstate multiconnect no_subspec );
}
specifier_class!(
    name = TcpListenClass,
    target = TcpListen,
    prefixes = ["tcp-listen:", "listen-tcp:", "tcp-l:", "l-tcp:"],
    arg_handling = parse,
    overlay = false,
    StreamOriented,
    MultiConnect,
    help = r#"
Listen TCP port on specified address.

Example: echo server

    websocat tcp-l:0.0.0.0:1441 mirror:

Example: redirect TCP to a websocket

    websocat tcp-l:0.0.0.0:8088 ws://echo.websocket.org
"#
);

#[derive(Debug, Clone)]
pub struct UdpConnect(pub SocketAddr);
impl Specifier for UdpConnect {
    fn construct(&self, p: ConstructParams) -> PeerConstructor {
        once(udp_connect_peer(&self.0, &p.program_options))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec );
}
specifier_class!(
    name = UdpConnectClass,
    target = UdpConnect,
    prefixes = ["udp:", "udp-connect:", "connect-udp:", "udp-c:", "c-udp:"],
    arg_handling = parse,
    overlay = false,
    MessageOriented,
    SingleConnect,
    help = r#"
Send and receive packets to specified UDP socket, from random UDP port
"#
);

#[derive(Debug, Clone)]
pub struct UdpListen(pub SocketAddr);
impl Specifier for UdpListen {
    fn construct(&self, p: ConstructParams) -> PeerConstructor {
        once(udp_listen_peer(&self.0, &p.program_options))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec );
}
specifier_class!(
    name = UdpListenClass,
    target = UdpListen,
    prefixes = ["udp-listen:", "listen-udp:", "udp-l:", "l-udp:"],
    arg_handling = parse,
    overlay = false,
    MessageOriented,
    SingleConnect,
    help = r#"
Bind an UDP socket to specified host:port, receive packet
from any remote UDP socket, send replies to recently observed
remote UDP socket.

Note that it is not a multiconnect specifier like e.g. `tcp-listen`:
entire lifecycle of the UDP socket is the same connection.

File a feature request on Github if you want proper DNS-like request-reply UDP mode here.
"#
);

/*
struct RcReadProxy<R>(Rc<R>) where for<'a> &'a R : AsyncRead;

impl<R> AsyncRead for RcReadProxy<R> where for<'a> &'a R : AsyncRead{}
impl<R> Read for RcReadProxy<R> where for<'a> &'a R : AsyncRead {
    fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
        (&*self.0).read(buf)
    }
}

struct RcWriteProxy<W>(Rc<W>) where for<'a> &'a W : AsyncWrite;

impl<W> AsyncWrite for RcWriteProxy<W> where for<'a> &'a W : AsyncWrite {
    fn shutdown(&mut self) -> futures::Poll<(),std::io::Error> {
        (&*self.0).shutdown()
    }
}
impl<W> Write for RcWriteProxy<W> where for<'a> &'a W : AsyncWrite {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        (&*self.0).write(buf)
    }
    fn flush(&mut self) -> IoResult<()> {
        (&*self.0).flush()
    }
}
*/

// based on https://github.com/tokio-rs/tokio-core/blob/master/examples/proxy.rs
#[derive(Clone)]
struct MyTcpStream(Rc<TcpStream>, bool);

impl Read for MyTcpStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        (&*self.0).read(buf)
    }
}

impl Write for MyTcpStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        (&*self.0).write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsyncRead for MyTcpStream {}

impl AsyncWrite for MyTcpStream {
    fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
        try!(self.0.shutdown(std::net::Shutdown::Write));
        Ok(().into())
    }
}

impl Drop for MyTcpStream {
    fn drop(&mut self) {
        let i_am_read_part = self.1;
        if i_am_read_part {
            let _ = self.0.shutdown(std::net::Shutdown::Read);
        }
    }
}

pub fn tcp_connect_peer(addrs: &[SocketAddr]) -> BoxedNewPeerFuture {
    // Apply Happy Eyeballs in case of multiple proposed addresses.
    if addrs.len() > 1 {
        debug!("Setting up a race between multiple TCP client sockets. Who connects the first?");
    }
    use futures::stream::futures_unordered::FuturesUnordered;
    let mut fu = FuturesUnordered::new();
    for addr in addrs {
        let addr = addr.clone();
        fu.push(
            TcpStream::connect(&addr)
            .map(move |x| {
                info!("Connected to TCP {}", addr);
                let x = Rc::new(x);
                Peer::new(MyTcpStream(x.clone(), true), MyTcpStream(x.clone(), false))
            })
            .map_err(box_up_err)
        );
    }
    let p = fu.into_future().and_then(|(x, _losers)| {
        let peer = x.unwrap();
        debug!("We have a winner. Disconnecting losers.");
        futures::future::ok(peer)
    });
    Box::new(p.map_err(|(e,_)|e)) as BoxedNewPeerFuture
}

pub fn tcp_listen_peer(addr: &SocketAddr, l2r: L2rUser) -> BoxedNewPeerStream {
    let bound = match TcpListener::bind(&addr) {
        Ok(x) => x,
        Err(e) => return peer_err_s(e),
    };
    use tk_listen::ListenExt;
    Box::new(
        bound
            .incoming()
            .sleep_on_error(::std::time::Duration::from_millis(500))
            .map(move |x| {
                let addr = x.peer_addr().ok();
                info!("Incoming TCP connection from {:?}", addr);

                match l2r {
                    L2rUser::FillIn(ref y) => {
                        let mut z = y.borrow_mut();
                        z.client_addr = addr.map(|a| format!("{}", a));
                    }
                    L2rUser::ReadFrom(_) => {}
                }

                let x = Rc::new(x);
                Peer::new(MyTcpStream(x.clone(), true), MyTcpStream(x.clone(), false))
            })
            .map_err(|()| ::simple_err2("unreachable error?")),
    ) as BoxedNewPeerStream
}

#[derive(Debug)]
enum UdpPeerState {
    ConnectMode,
    WaitingForAddress((Sender<()>, Receiver<()>)),
    HasAddress(SocketAddr),
}

struct UdpPeer {
    s: UdpSocket,
    state: Option<UdpPeerState>,
    oneshot_mode: bool,
}

#[derive(Clone)]
struct UdpPeerHandle(Rc<RefCell<UdpPeer>>);

fn get_zero_address(addr: &SocketAddr) -> SocketAddr {
    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
    let ip = match addr.ip() {
        IpAddr::V4(_) => IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
        IpAddr::V6(_) => IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)),
    };
    SocketAddr::new(ip, 0)
}

pub fn udp_connect_peer(addr: &SocketAddr, opts: &Rc<Options>) -> BoxedNewPeerFuture {
    let za = get_zero_address(addr);

    Box::new(futures::future::result(
        UdpSocket::bind(&za)
            .and_then(|x| {
                x.connect(addr)?;

                let h1 = UdpPeerHandle(Rc::new(RefCell::new(UdpPeer {
                    s: x,
                    state: Some(UdpPeerState::ConnectMode),
                    oneshot_mode: opts.udp_oneshot_mode,
                })));
                let h2 = h1.clone();
                Ok(Peer::new(h1, h2))
            })
            .map_err(box_up_err),
    )) as BoxedNewPeerFuture
}

pub fn udp_listen_peer(addr: &SocketAddr, opts: &Rc<Options>) -> BoxedNewPeerFuture {
    Box::new(futures::future::result(
        UdpSocket::bind(addr)
            .and_then(|x| {
                let h1 = UdpPeerHandle(Rc::new(RefCell::new(UdpPeer {
                    s: x,
                    state: Some(UdpPeerState::WaitingForAddress(channel())),
                    oneshot_mode: opts.udp_oneshot_mode,
                })));
                let h2 = h1.clone();
                Ok(Peer::new(h1, h2))
            })
            .map_err(box_up_err),
    )) as BoxedNewPeerFuture
}

impl Read for UdpPeerHandle {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        let mut p = self.0.borrow_mut();
        match p.state.take().expect("Assertion failed 193912") {
            UdpPeerState::ConnectMode => {
                p.state = Some(UdpPeerState::ConnectMode);
                p.s.recv2(buf)
            }
            UdpPeerState::HasAddress(oldaddr) => {
                p.s.recv_from2(buf)
                    .map(|(ret, addr)| {
                        if addr != oldaddr {
                            warn!("New client for the same listening UDP socket");
                        }
                        p.state = Some(UdpPeerState::HasAddress(addr));
                        ret
                    })
                    .map_err(|e| {
                        p.state = Some(UdpPeerState::HasAddress(oldaddr));
                        e
                    })
            }
            UdpPeerState::WaitingForAddress((cmpl, pollster)) => match p.s.recv_from2(buf) {
                Ok((ret, addr)) => {
                    p.state = Some(UdpPeerState::HasAddress(addr));
                    let _ = cmpl.send(());
                    Ok(ret)
                }
                Err(e) => {
                    p.state = Some(UdpPeerState::WaitingForAddress((cmpl, pollster)));
                    Err(e)
                }
            },
        }
    }
}

impl Write for UdpPeerHandle {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        let mut p = self.0.borrow_mut();
        match p.state.take().expect("Assertion failed 193913") {
            UdpPeerState::ConnectMode => {
                p.state = Some(UdpPeerState::ConnectMode);
                p.s.send2(buf)
            }
            UdpPeerState::HasAddress(a) => {
                if p.oneshot_mode {
                    p.state = Some(UdpPeerState::WaitingForAddress(channel()));
                } else {
                    p.state = Some(UdpPeerState::HasAddress(a));
                }
                p.s.send_to2(buf, &a)
            }
            UdpPeerState::WaitingForAddress((cmpl, mut pollster)) => {
                let _ = pollster.poll(); // register wakeup
                p.state = Some(UdpPeerState::WaitingForAddress((cmpl, pollster)));
                wouldblock()
            }
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsyncRead for UdpPeerHandle {}

impl AsyncWrite for UdpPeerHandle {
    fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
        Ok(().into())
    }
}

/// Squirreled await from deprecated UdpSocket functions
trait UndeprecateNonpollSendRecv {
    fn recv2(&mut self, buf: &mut [u8]) -> std::io::Result<usize>;
    fn recv_from2(&mut self, buf: &mut [u8]) -> std::io::Result<(usize, SocketAddr)>;
    fn send2(&mut self, buf: &[u8]) -> std::io::Result<usize>;
    fn send_to2(&mut self, buf: &[u8], target: &SocketAddr) -> std::io::Result<usize>;
}

impl UndeprecateNonpollSendRecv for UdpSocket {
    fn recv2(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        match self.poll_recv(buf)? {
            futures::Async::Ready(n) => Ok(n),
            futures::Async::NotReady => Err(std::io::ErrorKind::WouldBlock.into()),
        }
    }

    fn recv_from2(&mut self, buf: &mut [u8]) -> std::io::Result<(usize, SocketAddr)> {
        match self.poll_recv_from(buf)? {
            futures::Async::Ready(ret) => Ok(ret),
            futures::Async::NotReady => Err(std::io::ErrorKind::WouldBlock.into()),
        }
    }

    fn send2(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        match self.poll_send(buf)? {
            futures::Async::Ready(n) => Ok(n),
            futures::Async::NotReady => Err(std::io::ErrorKind::WouldBlock.into()),
        }
    }

    fn send_to2(&mut self, buf: &[u8], target: &SocketAddr) -> std::io::Result<usize> {
        match self.poll_send_to(buf, target)? {
            futures::Async::Ready(n) => Ok(n),
            futures::Async::NotReady => Err(std::io::ErrorKind::WouldBlock.into()),
        }
    }
}
<|endoftext|>


<commit_before>//! Experiments with parallel processing
//!
//! The provided functions focus on the possibility of
//! returning results while the parser proceeds. Sequences are processesd in
//! batches (`RecordSet`) because sending across channels has a performance
//! impact. FASTA/FASTQ records can be accessed in both the 'worker' function and
//! (after processing) a function running in the main thread.
//!
//! # Search first occurrence of a sequence pattern
//!
//! ```no_run
//! use seq_io::fastq::{Reader,Record};
//! use seq_io::parallel::read_parallel;
//!
//! let reader = Reader::from_path("seqs.fastq").unwrap();
//!
//! read_parallel(reader, 4, 2, |record_set| {
//!     // this function does the heavy work
//!     for (i, record) in record_set.into_iter().enumerate() {
//!         // this is not very efficient code, just for demonstration
//!         if let Some(pos) = record.seq().windows(3).position(|s| s == b"AAA") {
//!             return Some((i, pos));
//!         }
//!     }
//!     None
//! }, |record_sets| {
//!     // This function runs in the main thread. It provides a streaming iterator over
//!     // record sets and the corresponding return values from the worker function
//!     // (not necessarily in the same order as in the file)
//!     while let Some(result) = record_sets.next() {
//!         let (record_set, found) = result.unwrap();
//!         if let Some((i, pos)) = found {
//!             let record = record_set.into_iter().nth(i).unwrap();
//!             println!("Found AAA in record {} at position {}", record.id().unwrap(), pos);
//!              // this will also stop the worker threads, although with some delay
//!             return;
//!         }
//!     }
//! });
//! ```
//!
//! # Per-record processsing
//! The `parallel_fasta` / `parallel_fastq` functions are designed to efficiently pass
//! results for **each record** to the main thread without having to care about record sets.
//! This example filters sequences by the occurrence of a pattern:
//!
//! ```no_run
//! use seq_io::fastq::{Reader,Record};
//! use seq_io::parallel::parallel_fastq;
//! use std::fs::File;
//! use std::io::BufWriter;
//!
//! let reader = Reader::from_path("seqs.fastq").unwrap();
//! let mut writer = BufWriter::new(File::create("filtered.fastq").unwrap());
//!
//! parallel_fastq(reader, 4, 2,
//!     |record, found| { // runs in worker
//!         *found = record.seq().windows(3).position(|s| s == b"AAA").is_some();
//!     },
//!     |record, found| { // runs in main thread
//!         if *found {
//!             record.write(&mut writer).unwrap();
//!         }
//!         // Some(value) will stop the reader, and the value will be returned.
//!         // In the case of never stopping, we need to give the compiler a hint about the
//!         // type parameter, thus the special 'turbofish' notation is needed.
//!         None::<()>
//! }).unwrap();
//! ```

use std::io;

extern crate crossbeam;
extern crate scoped_threadpool;

use std::sync::mpsc;
use std::marker::PhantomData;

pub trait Reader: Send {
    type DataSet: Default + Send;
    type Err: Send;
    fn fill_data(&mut self, record: &mut Self::DataSet) -> Option<Result<(), Self::Err>>;
}

pub fn read_parallel<P, O, W, F, Out>(mut reader: P, n_threads: u32, queue_len: usize, work: W, func: F) -> Out
    where P: Reader,
          O: Default + Send,
          W: Send + Sync,
          W: Fn(&mut P::DataSet) -> O,
          F: FnOnce(&mut ParallelRecordsets<P::DataSet, P::Err, O>) -> Out,
{

    let (done_send, done_recv) = mpsc::sync_channel(queue_len);
    let (empty_send, empty_recv): (mpsc::SyncSender<Option<P::DataSet>>, _) = mpsc::sync_channel(queue_len);

    crossbeam::scope(|scope| {

        scope.spawn(move || {

            let mut pool = scoped_threadpool::Pool::new(n_threads);

            pool.scoped(|pool_scope| {

                let work = &work;

                loop {
                    // recycle an old DataSet sent back after use by the streaming iterator
                    let mut data =
                        if let Ok(Some(r)) = empty_recv.recv() {
                            r
                        } else {
                            // 'ParallelRecordsets::stop()' called
                            return;
                        };

                    // each time, we need a new reference
                    let done_send = done_send.clone();

                    if let Some(res) = reader.fill_data(&mut data) {
                        match res {
                            Ok(_) => {
                                // expensive work carried out by func()
                                pool_scope.execute(move || {

                                    let out = work(&mut data);

                                    done_send.send(Some(Ok((data, out)))).ok();
                                });
                            }
                            Err(e) => {
                                done_send.send(Some(Err(e))).ok();
                                break;
                            }
                        }
                    } else {
                        break;
                    }
                }

                // make sure that the 'done' signal is only sent after everything else is done
                pool_scope.join_all();

                done_send.send(None).ok();
            });
        });

        for _ in 0..queue_len  {
            empty_send.send(Some(P::DataSet::default())).unwrap();
        }

        let mut records = ParallelRecordsets {
            empty_send: empty_send,
            done_recv: done_recv,
            current_recordset: P::DataSet::default(),
        };

        let out = func(&mut records);

        records.stop();

        out
    })
}

pub struct ParallelRecordsets<R, E, O>
    where R: Default + Send,
          E: Send,
          O: Send,
{
    empty_send: mpsc::SyncSender<Option<R>>,
    done_recv: mpsc::Receiver<Option<Result<(R, O), E>>>,
    current_recordset: R,
}

impl<R, E, O> ParallelRecordsets<R, E, O>
    where R: Default + Send,
          E: Send,
          O: Send,
 {

    pub fn next<'b>(&'b mut self) -> Option<Result<(&'b R, O), E>> {
        if let Some(result) = self.done_recv.recv().unwrap() {
            match result {
                Ok((r, o)) => {
                     let prev_rset = ::std::mem::replace(&mut self.current_recordset, r);
                     self.empty_send.send(Some(prev_rset)).ok(); // error: channel closed is not a problem, happens after calling stop()
                    return Some(Ok((&self.current_recordset, o)));
                }
                Err(e) => return Some(Err(e))
            }
        } else {
            // 'done' signal received
            return None;
        }
    }

    // has to be called before object goes out of scope
    // currently, the signal is delayed (has to wait until it is popped from the
    // 'empty' queue)
    // TODO: should an AtomicBool be used?
    fn stop(self) {
        self.empty_send.send(None).ok();
    }
}

#[macro_export]
macro_rules! parallel_record_impl {
    ($name:ident, $io_r:tt, $rdr:ty, $record:ty, $err:ty) => {

        pub fn $name<$io_r, O, W, F, Out>(parser: $rdr, n_threads: u32, queue_len: usize, work: W, mut func: F) -> Result<Option<Out>, $err>
            where $io_r: io::Read + Send,
                  O: Default + Send,
                  W: Send + Sync,
                  W: Fn($record, &mut O),
                  F: FnMut($record, &O) -> Option<Out>,
        {
            let reader = $crate::parallel::ReusableReader::new(parser);

            $crate::parallel::read_parallel(reader, n_threads, queue_len, |d| {
                let mut iter = d.0.into_iter();
                let out: &mut Vec<O> = &mut d.1;
                for mut x in out.iter_mut().zip(&mut iter) {
                    work(x.1, &mut x.0);
                }
                for i in iter {
                    out.push(O::default());
                    work(i, out.last_mut().unwrap())
                }

            }, |records| {
                while let Some(result) = records.next() {
                    let (r, _) = result?;
                    for x in r.0.into_iter().zip(&r.1) {
                        if let Some(out) = func(x.0, x.1) {
                            return Ok(Some(out));
                        }
                    }
                }
                Ok(None)
            })
        }
     };
}

parallel_record_impl!(parallel_fasta, R, fasta::Reader<R>, fasta::RefRecord, fasta::ParseError);

parallel_record_impl!(parallel_fastq, R, fastq::Reader<R>, fastq::RefRecord, fastq::ParseError);

/// Wrapper for `parallel::Reader` instances allowing
/// the output to be reused in order to save allocations.
/// Used by `parallel_fasta`/`parallel_fastq`
///
/// ```no_run
/// use seq_io::fastq::{Reader,Record,RecordSet};
/// use seq_io::parallel::{read_parallel,ReusableReader};
///
/// let inner = Reader::from_path("seqs.fastq").unwrap();
/// let reader = ReusableReader::new(inner);
///
/// read_parallel(reader, 4, 2, |&mut (ref record_set, ref mut out): &mut (RecordSet, Vec<bool>)| {
///     out.clear();
///     for record in record_set {
///         let found = record.seq().windows(3).position(|s| s == b"AAA").is_some();
///         out.push(found);
///     }
/// }, |record_sets| {
///     while let Some(result) = record_sets.next() {
///         let &(ref record_set, ref out) = result.unwrap().0;
///         for (record, found) in record_set.into_iter().zip(out) {
///             // ...
///         }
///     }
/// });
/// ```
pub struct ReusableReader<P, O>(P, PhantomData<O>);

impl<P, O> ReusableReader<P, O> {
    pub fn new(p: P) -> ReusableReader<P, O> {
        ReusableReader(p, PhantomData)
    }
}

impl<P, O> Reader for ReusableReader<P, O>
    where P: Reader,
          O: Default + Send {

    type DataSet = (P::DataSet, O);
    type Err = P::Err;
    fn fill_data(&mut self, data: &mut Self::DataSet) -> Option<Result<(), P::Err>> {
        self.0.fill_data(&mut data.0)
    }
}

/// Using this function currently does not work due to a
/// [compiler bug](https://github.com/rust-lang/rust/issues/42950).
///
/// `parallel_fasta`/`parallel_fastq` provide the same functionality for now
/// (implemented using `parallel_record_impl` macro)
pub fn parallel_records<P, O, W, F, Out>(parser: P, n_threads: u32, queue_len: usize, work: W, mut func: F) -> Result<Option<Out>, P::Err>
    where P: Reader,
          for<'a> &'a P::DataSet: IntoIterator,
          O: Default + Send,
          W: Send + Sync,
          W: Fn(<&P::DataSet as IntoIterator>::Item, &mut O),
          F: FnMut(<&P::DataSet as IntoIterator>::Item, &O) -> Option<Out>,
{
    let reader = ReusableReader(parser, PhantomData);

    read_parallel(reader, n_threads, queue_len, |d| {
        let mut iter = d.0.into_iter();
        let out: &mut Vec<O> = &mut d.1;
        for mut x in out.iter_mut().zip(&mut iter) {
            work(x.1, &mut x.0);
        }
        for i in iter {
            out.push(O::default());
            work(i, out.last_mut().unwrap())
        }

    }, |records| {
        while let Some(result) = records.next() {
            let (r, _) = result?;
            for x in r.0.into_iter().zip(&r.1) {
                if let Some(out) = func(x.0, x.1) {
                    return Ok(Some(out));
                }
            }
        }
        Ok(None)
    })
}

// trait impls

use super::fasta;

impl<R, S> Reader for fasta::Reader<R, S>
    where R: io::Read + Send,
          S: super::strategy::BufGrowStrategy + Send
{
    type DataSet = fasta::RecordSet;
    type Err = fasta::ParseError;
    fn fill_data(&mut self, rset: &mut fasta::RecordSet) -> Option<Result<(), fasta::ParseError>> {
        self.read_record_set(rset)
    }
}

use super::fastq;

impl<R, S> Reader for fastq::Reader<R, S>
    where R: io::Read + Send,
          S: super::strategy::BufGrowStrategy + Send
{
    type DataSet = fastq::RecordSet;
    type Err = fastq::ParseError;
    fn fill_data(&mut self, rset: &mut fastq::RecordSet) -> Option<Result<(), fastq::ParseError>> {
        self.read_record_set(rset)
    }
}
<commit_msg>Improve and extend parallel module.<commit_after>//! Experiments with parallel processing
//!
//! The provided functions focus on the possibility of
//! returning results while the parser proceeds. Sequences are processesd in
//! batches (`RecordSet`) because sending across channels has a performance
//! impact. FASTA/FASTQ records can be accessed in both the 'worker' function and
//! (after processing) a function running in the main thread.
//!
//! # Search first occurrence of a sequence pattern
//!
//! ```no_run
//! use seq_io::fastq::{Reader,Record};
//! use seq_io::parallel::read_parallel;
//!
//! let reader = Reader::from_path("seqs.fastq").unwrap();
//!
//! read_parallel(reader, 4, 2, |record_set| {
//!     // this function does the heavy work
//!     for (i, record) in record_set.into_iter().enumerate() {
//!         // this is not very efficient code, just for demonstration
//!         if let Some(pos) = record.seq().windows(3).position(|s| s == b"AAA") {
//!             return Some((i, pos));
//!         }
//!     }
//!     None
//! }, |record_sets| {
//!     // This function runs in the main thread. It provides a streaming iterator over
//!     // record sets and the corresponding return values from the worker function
//!     // (not necessarily in the same order as in the file)
//!     while let Some(result) = record_sets.next() {
//!         let (record_set, found) = result.unwrap();
//!         if let Some((i, pos)) = found {
//!             let record = record_set.into_iter().nth(i).unwrap();
//!             println!("Found AAA in record {} at position {}", record.id().unwrap(), pos);
//!              // this will also stop the worker threads, although with some delay
//!             return;
//!         }
//!     }
//! });
//! ```
//!
//! # Per-record processsing
//! The `parallel_fasta` / `parallel_fastq` functions are designed to efficiently pass
//! results for **each record** to the main thread without having to care about record sets.
//! This example filters sequences by the occurrence of a pattern:
//!
//! ```no_run
//! use seq_io::fastq::{Reader,Record};
//! use seq_io::parallel::parallel_fastq;
//! use std::fs::File;
//! use std::io::BufWriter;
//!
//! let reader = Reader::from_path("seqs.fastq").unwrap();
//! let mut writer = BufWriter::new(File::create("filtered.fastq").unwrap());
//!
//! parallel_fastq(reader, 4, 2,
//!     |record, found| { // runs in worker
//!         *found = record.seq().windows(3).position(|s| s == b"AAA").is_some();
//!     },
//!     |record, found| { // runs in main thread
//!         if *found {
//!             record.write(&mut writer).unwrap();
//!         }
//!         // Some(value) will stop the reader, and the value will be returned.
//!         // In the case of never stopping, we need to give the compiler a hint about the
//!         // type parameter, thus the special 'turbofish' notation is needed.
//!         None::<()>
//! }).unwrap();
//! ```

use std::io;

extern crate crossbeam;
extern crate scoped_threadpool;

use std::sync::mpsc;
use std::marker::PhantomData;

pub trait Reader: Send {
    type DataSet: Send;
    type Err: Send;
    fn fill_data(&mut self, record: &mut Self::DataSet) -> Option<Result<(), Self::Err>>;
}

pub fn read_parallel<R, O, W, F, Out>(reader: R, n_threads: u32, queue_len: usize, work: W, func: F) -> Out
    where R: Reader,
          R::DataSet: Default,
          O: Default + Send,
          W: Send + Sync,
          W: Fn(&mut R::DataSet) -> O,
          F: FnMut(&mut ParallelRecordsets<R::DataSet, R::Err, O>) -> Out,
{
    read_parallel_with(reader, n_threads, queue_len, || R::DataSet::default(), work, func)
}

pub fn read_parallel_with<R, O, D, W, F, Out>(
        mut reader: R, n_threads: u32, queue_len: usize,
        mut dataset_init: D, work: W, func: F
    ) -> Out
    where R: Reader,
          O: Send,
          D: Send + Sync + FnMut() -> R::DataSet,
          W: Send + Sync,
          W: Fn(&mut R::DataSet) -> O,
          F: FnOnce(&mut ParallelRecordsets<R::DataSet, R::Err, O>) -> Out,
{

    let (done_send, done_recv) = mpsc::sync_channel(queue_len);
    let (empty_send, empty_recv): (mpsc::SyncSender<R::DataSet>, _) = mpsc::sync_channel(queue_len);

    crossbeam::scope(|scope| {

        scope.spawn(move || {

            let mut pool = scoped_threadpool::Pool::new(n_threads);

            pool.scoped(|pool_scope| {

                let work = &work;

                loop {
                    // recycle an old DataSet sent back after use by the streaming iterator
                    let mut data =
                        if let Ok(r) = empty_recv.recv() {
                            r
                        } else {
                            // ParallelRecordsets dropped -> stop
                            return;
                        };

                    let done_send = done_send.clone();

                    if let Some(res) = reader.fill_data(&mut data) {
                        match res {
                            Ok(_) => {
                                // expensive work carried out by func()
                                pool_scope.execute(move || {

                                    let out = work(&mut data);

                                    done_send.send(Some(Ok((data, out)))).ok();
                                });
                            }
                            Err(e) => {
                                done_send.send(Some(Err(e))).ok();
                                break;
                            }
                        }
                    } else {
                        break;
                    }
                }

                // make sure that the 'done' signal is only sent after everything else is done
                pool_scope.join_all();

                done_send.send(None).ok();
            });
        });

        for _ in 0..queue_len  {
            empty_send.send(dataset_init()).unwrap();
        }

        let mut rsets = ParallelRecordsets {
            empty_send: empty_send,
            done_recv: done_recv,
            current_recordset: dataset_init(),
        };

        let out = func(&mut rsets);
        ::std::mem::drop(rsets);
        out
    })
}

pub struct ParallelRecordsets<R, E, O>
    where R: Send,
          E: Send,
          O: Send,
{
    empty_send: mpsc::SyncSender<R>,
    done_recv: mpsc::Receiver<Option<Result<(R, O), E>>>,
    current_recordset: R,
}

impl<R, E, O> ParallelRecordsets<R, E, O>
    where R: Send,
          E: Send,
          O: Send,
 {
    pub fn next<'b>(&'b mut self) -> Option<Result<(&'b mut R, O), E>> {
        self.done_recv.recv().unwrap().map(move |result| {
            match result {
                Ok((r, o)) => {
                     let prev_rset = ::std::mem::replace(&mut self.current_recordset, r);
                     self.empty_send.send(prev_rset).ok(); // error: channel closed is not a problem, happens after calling stop()
                     Ok((&mut self.current_recordset, o))
                }
                Err(e) => Err(e)
            }
        })
    }
}

#[macro_export]
macro_rules! parallel_record_impl {
    ($name:ident, $io_r:tt, $rdr:ty, $record:ty, $err:ty) => {

        pub fn $name<$io_r, O, W, F, Out>(parser: $rdr, n_threads: u32, queue_len: usize, work: W, mut func: F) -> Result<Option<Out>, $err>
            where $io_r: io::Read + Send,
                  O: Default + Send,
                  W: Send + Sync,
                  W: Fn($record, &mut O),
                  F: FnMut($record, &mut O) -> Option<Out>,
        {
            let reader = $crate::parallel::ReusableReader::new(parser);

            $crate::parallel::read_parallel(reader, n_threads, queue_len, |d| {
                let mut iter = d.0.into_iter();
                let out: &mut Vec<O> = &mut d.1;
                for mut x in out.iter_mut().zip(&mut iter) {
                    work(x.1, &mut x.0);
                }
                for i in iter {
                    out.push(O::default());
                    work(i, out.last_mut().unwrap())
                }

            }, |records| {
                while let Some(result) = records.next() {
                    let (r, _) = result?;
                    for x in r.0.into_iter().zip(&mut r.1) {
                        if let Some(out) = func(x.0, x.1) {
                            return Ok(Some(out));
                        }
                    }
                }
                Ok(None)
            })
        }
     };
}

parallel_record_impl!(parallel_fasta, R, fasta::Reader<R>, fasta::RefRecord, fasta::ParseError);

parallel_record_impl!(parallel_fastq, R, fastq::Reader<R>, fastq::RefRecord, fastq::ParseError);

/// Wrapper for `parallel::Reader` instances allowing
/// the output to be reused in order to save allocations.
/// Used by `parallel_fasta`/`parallel_fastq`
///
/// ```no_run
/// use seq_io::fastq::{Reader,Record,RecordSet};
/// use seq_io::parallel::{read_parallel,ReusableReader};
///
/// let inner = Reader::from_path("seqs.fastq").unwrap();
/// let reader = ReusableReader::new(inner);
///
/// read_parallel(reader, 4, 2, |&mut (ref record_set, ref mut out): &mut (RecordSet, Vec<bool>)| {
///     out.clear();
///     for record in record_set {
///         let found = record.seq().windows(3).position(|s| s == b"AAA").is_some();
///         out.push(found);
///     }
/// }, |record_sets| {
///     while let Some(result) = record_sets.next() {
///         let &(ref record_set, ref out) = &*result.unwrap().0;
///         for (record, found) in record_set.into_iter().zip(out) {
///             // ...
///         }
///     }
/// });
/// ```
pub struct ReusableReader<P, O>(P, PhantomData<O>);

impl<P, O> ReusableReader<P, O> {
    pub fn new(p: P) -> ReusableReader<P, O> {
        ReusableReader(p, PhantomData)
    }
}

impl<P, O> Reader for ReusableReader<P, O>
    where P: Reader,
          O: Send {

    type DataSet = (P::DataSet, O);
    type Err = P::Err;
    fn fill_data(&mut self, data: &mut Self::DataSet) -> Option<Result<(), P::Err>> {
        self.0.fill_data(&mut data.0)
    }
}

/// Using this function currently does not work due to a
/// [compiler bug](https://github.com/rust-lang/rust/issues/42950).
///
/// `parallel_fasta`/`parallel_fastq` provide the same functionality for now
/// (implemented using `parallel_record_impl` macro)
pub fn parallel_records<R, O, W, F, Out>(parser: R, n_threads: u32, queue_len: usize, work: W, mut func: F) -> Result<Option<Out>, R::Err>
    where R: Reader,
          for<'a> &'a R::DataSet: IntoIterator,
          R::DataSet: Default,
          O: Default + Send,
          W: Send + Sync,
          W: Fn(<&R::DataSet as IntoIterator>::Item, &mut O),
          F: FnMut(<&R::DataSet as IntoIterator>::Item, &O) -> Option<Out>,
{
    let reader = ReusableReader(parser, PhantomData);

    read_parallel(reader, n_threads, queue_len, |d| {
        let mut iter = d.0.into_iter();
        let out: &mut Vec<O> = &mut d.1;
        for mut x in out.iter_mut().zip(&mut iter) {
            work(x.1, &mut x.0);
        }
        for i in iter {
            out.push(O::default());
            work(i, out.last_mut().unwrap())
        }

    }, |records| {
        while let Some(result) = records.next() {
            let (r, _) = result?;
            for x in r.0.into_iter().zip(&r.1) {
                if let Some(out) = func(x.0, x.1) {
                    return Ok(Some(out));
                }
            }
        }
        Ok(None)
    })
}

// trait impls

use super::fasta;

impl<R, S> Reader for fasta::Reader<R, S>
    where R: io::Read + Send,
          S: super::strategy::BufGrowStrategy + Send
{
    type DataSet = fasta::RecordSet;
    type Err = fasta::ParseError;
    fn fill_data(&mut self, rset: &mut fasta::RecordSet) -> Option<Result<(), fasta::ParseError>> {
        self.read_record_set(rset)
    }
}

use super::fastq;

impl<R, S> Reader for fastq::Reader<R, S>
    where R: io::Read + Send,
          S: super::strategy::BufGrowStrategy + Send
{
    type DataSet = fastq::RecordSet;
    type Err = fastq::ParseError;
    fn fill_data(&mut self, rset: &mut fastq::RecordSet) -> Option<Result<(), fastq::ParseError>> {
        self.read_record_set(rset)
    }
}
<|endoftext|>


<commit_before>#![feature(unboxed_closures)]
#![feature(globs)]
#![feature(phase)]
#![feature(macro_rules)]
#[phase(plugin, link)]
extern crate log;
#[phase(plugin)]
extern crate wtftw_core;

extern crate wtftw_core;

use wtftw_core::window_system::*;
use wtftw_core::window_manager::*;
use wtftw_core::handlers::default::*;
use wtftw_core::config::*;
use wtftw_core::util::*;
use wtftw_core::layout::*;
use wtftw_core::layout::Direction::*;
use wtftw_core::layout::LayoutMessage::*;
use wtftw_core::core::*;

#[no_mangle]
pub extern fn configure(_: &mut WindowManager, w: &WindowSystem, config: &mut Config) {
    let modm = MOD1MASK;

    config.general.mod_mask = modm;
    config.general.spacing = 0;
    config.general.border_color = 0x3f3f4c;
    config.general.focus_border_color = 0x525263;
    config.general.terminal = (String::from_str("urxvt"), String::from_str(""));
    config.general.layout = LayoutCollection::new(vec!(
        GapLayout::new(16, AvoidStrutsLayout::new(vec!(Direction::Up), ResizableTallLayout::new())),
        GapLayout::new(16, AvoidStrutsLayout::new(vec!(Direction::Up),
MirrorLayout::new(ResizableTallLayout::new()))),
        box FullLayout));

    config.general.tags = (vec!("1: term", "2: web", "3: code",
                                "4: media", "5: steam", "6: latex",
                                "7: music", "8: im", "9: rest"))
        .into_iter().map(String::from_str).collect();

    // Register key handlers

    // Some standard key handlers for starting, restarting, etc.
    add_key_handler_str!(config, w, "q",      modm | SHIFTMASK, exit);
    add_key_handler_str!(config, w, "q",      modm,             restart);
    add_key_handler_str!(config, w, "Return", modm | SHIFTMASK, start_terminal);
    add_key_handler_str!(config, w, "p",      modm,             start_launcher);

    // Focus and window movement
    add_key_handler_str!(config, w, "j", modm, |&: m, w, c| m.windows(w, c, |x| x.focus_down()));
    add_key_handler_str!(config, w, "k", modm, |&: m, w, c| m.windows(w, c, |x| x.focus_up()));
    add_key_handler_str!(config, w, "j", modm | SHIFTMASK, |&: m, w, c| m.windows(w, c, |x|
x.swap_down()));
    add_key_handler_str!(config, w, "k", modm | SHIFTMASK, |&: m, w, c| m.windows(w, c, |x| x.swap_up()));
    add_key_handler_str!(config, w, "Return", modm, |&: m, w, c| m.windows(w, c, |x| x.swap_master()));
    add_key_handler_str!(config, w, "c", modm, |&: m, w, c| m.kill_window(w).windows(w, c, |x| x.clone()));

    add_key_handler_str!(config, w, "t", modm, |&: m, w, c| {
        match m.workspaces.peek() {
            Some(window) => m.windows(w, c, |x| x.sink(window)),
            None => m.clone()
        }
    });

    // Layout messages
    add_key_handler_str!(config, w, "h", modm,
            |&: m, w, c| { m.send_layout_message(LayoutMessage::Decrease).windows(w, c, |x| x.clone()) });
    add_key_handler_str!(config, w, "l", modm,
            |&: m, w, c| { m.send_layout_message(LayoutMessage::Increase).windows(w, c, |x| x.clone()) });
    add_key_handler_str!(config, w, "comma", modm,
            |&: m, w, c| { m.send_layout_message(LayoutMessage::IncreaseMaster).windows(w, c, |x| x.clone()) });
    add_key_handler_str!(config, w, "period", modm,
            |&: m, w, c| m.send_layout_message(LayoutMessage::DecreaseMaster).windows(w, c, |x| x.clone()));
    add_key_handler_str!(config, w, "space", modm,
            |&: m, w, c| m.send_layout_message(LayoutMessage::Next).windows(w, c, |x| x.clone()));

    // Workspace switching and moving
    for i in range(1u, 10) {
        add_key_handler_str!(config, w, i.to_string().as_slice(), modm,
            move |&: m, w, c| switch_to_workspace(m, w, c, i - 1));

        add_key_handler_str!(config, w, i.to_string().as_slice(), modm | SHIFTMASK,
            move |&: m, w, c| move_window_to_workspace(m, w, c, i - 1));
    }

    // Media keys
    add_key_handler_str!(config, w, "j", modm | CONTROLMASK,
            |&: w, _, _| { run("amixer", Some("-q set Master 5%-")); w });
    add_key_handler_str!(config, w, "k", modm | CONTROLMASK,
            |&: w, _, _| { run("amixer", Some("-q set Master 5%+")); w });

    add_key_handler_code!(config, 0x1008ff11, NONEMASK,
            |&: w, _, _| { run("amixer", Some("-q set Master 5%-")); w });
    add_key_handler_code!(config, 0x1008ff13, NONEMASK,
            |&: w, _, _| { run("amixer", Some("-q set Master 5%+")); w });

    add_key_handler_code!(config, 0x1008ff02, NONEMASK,
            |&: w, _, _| { run("xbacklight", Some("+10")); w });
    add_key_handler_code!(config, 0x1008ff03, NONEMASK,
            |&: w, _, _| { run("xbacklight", Some("-10")); w });

    add_mouse_handler!(config, BUTTON1, modm,
            |&: m, w, c, s| {
                m.focus(s, w, c).mouse_move_window(w, c, s).windows(w, c, |x| x.shift_master())
            });
    add_mouse_handler!(config, BUTTON3, modm,
            |&: m, w, c, s| {
                m.focus(s, w, c).mouse_resize_window(w, c, s).windows(w, c, |x| x.shift_master())
            });

    // Place specific applications on specific workspaces
    config.set_manage_hook(box |&: workspaces, window_system, window| {
                match window_system.get_class_name(window).as_slice() {
                    "MPlayer" => spawn_on(workspaces, window_system, window, 3),
                    "vlc"     => spawn_on(workspaces, window_system, window, 3),
                    _         => workspaces.clone()
                }
            });

    // Xmobar handling and formatting
    let mut xmobar = spawn_pipe(config, String::from_str("xmobar"),
                                Some(String::from_str("/home/rootnode/.xmonad/xmobar1.hs")));
    let tags = config.general.tags.clone();
    config.set_log_hook(box move |&mut: m, _| {
        let p = &mut xmobar;
        let tags = &tags;
        let workspaces = tags.clone().iter()
            .enumerate()
            .map(|(i, x)| if i as u32 == m.workspaces.current.workspace.id {
                format!("[<fc=#196271>{}</fc>] ", x)
            } else {
                format!("[{}] ", x)
            })
            .fold(String::from_str(""), |a, x| {
                let mut r = a.clone();
                r.push_str(x.as_slice());
                r
            });

        let content = format!("{} {}", workspaces, m.workspaces.current.workspace.layout.description());
        match p.deref().write().deref_mut().stdin.as_mut() {
            Some(pin) => match pin.write_line(content.as_slice()) {
                _ => ()
            },
            _ => ()
        }
    });
}

<commit_msg>updated example config<commit_after>#![feature(unboxed_closures)]
#![feature(globs)]
#![feature(phase)]
#![feature(macro_rules)]
#[phase(plugin, link)]
extern crate log;
#[phase(plugin)]
extern crate wtftw_core;

extern crate wtftw_core;

use wtftw_core::window_system::*;
use wtftw_core::window_manager::*;
use wtftw_core::handlers::default::*;
use wtftw_core::config::*;
use wtftw_core::util::*;
use wtftw_core::layout::*;
use wtftw_core::layout::Direction::*;
use wtftw_core::layout::LayoutMessage::*;
use wtftw_core::core::*;

#[no_mangle]
pub extern fn configure(_: &mut WindowManager, w: &WindowSystem, config: &mut Config) {
    let modm = MOD1MASK;

    config.general.mod_mask = modm;
    config.general.spacing = 0;
    config.general.border_color = 0x3f3f4c;
    config.general.focus_border_color = 0x525263;
    config.general.terminal = (String::from_str("urxvt"), String::from_str(""));
    config.general.layout = LayoutCollection::new(vec!(
        GapLayout::new(16, AvoidStrutsLayout::new(vec!(Direction::Up), ResizableTallLayout::new())),
        GapLayout::new(16, AvoidStrutsLayout::new(vec!(Direction::Up),
MirrorLayout::new(ResizableTallLayout::new()))),
        NoBordersLayout::new(box FullLayout)));

    config.general.tags = (vec!("1: term", "2: web", "3: code",
                                "4: media", "5: steam", "6: latex",
                                "7: music", "8: im", "9: rest"))
        .into_iter().map(String::from_str).collect();

    // Register key handlers

    // Some standard key handlers for starting, restarting, etc.
    add_key_handler_str!(config, w, "q",      modm | SHIFTMASK, exit);
    add_key_handler_str!(config, w, "q",      modm,             restart);
    add_key_handler_str!(config, w, "Return", modm | SHIFTMASK, start_terminal);
    add_key_handler_str!(config, w, "p",      modm,             start_launcher);

    // Focus and window movement
    add_key_handler_str!(config, w, "j", modm, |&: m, w, c| m.windows(w, c, |x| x.focus_down()));
    add_key_handler_str!(config, w, "k", modm, |&: m, w, c| m.windows(w, c, |x| x.focus_up()));
    add_key_handler_str!(config, w, "j", modm | SHIFTMASK, |&: m, w, c| m.windows(w, c, |x|
x.swap_down()));
    add_key_handler_str!(config, w, "k", modm | SHIFTMASK, |&: m, w, c| m.windows(w, c, |x| x.swap_up()));
    add_key_handler_str!(config, w, "Return", modm, |&: m, w, c| m.windows(w, c, |x| x.swap_master()));
    add_key_handler_str!(config, w, "c", modm, |&: m, w, c| m.kill_window(w).windows(w, c, |x| x.clone()));

    add_key_handler_str!(config, w, "t", modm, |&: m, w, c| {
        match m.workspaces.peek() {
            Some(window) => m.windows(w, c, |x| x.sink(window)),
            None => m.clone()
        }
    });

    // Layout messages
    add_key_handler_str!(config, w, "h", modm,
            |&: m, w, c| { m.send_layout_message(LayoutMessage::Decrease).windows(w, c, |x| x.clone()) });
    add_key_handler_str!(config, w, "l", modm,
            |&: m, w, c| { m.send_layout_message(LayoutMessage::Increase).windows(w, c, |x| x.clone()) });
    add_key_handler_str!(config, w, "comma", modm,
            |&: m, w, c| { m.send_layout_message(LayoutMessage::IncreaseMaster).windows(w, c, |x| x.clone()) });
    add_key_handler_str!(config, w, "period", modm,
            |&: m, w, c| m.send_layout_message(LayoutMessage::DecreaseMaster).windows(w, c, |x| x.clone()));
    add_key_handler_str!(config, w, "space", modm,
            |&: m, w, c| m.send_layout_message(LayoutMessage::Next).windows(w, c, |x| x.clone()));

    // Workspace switching and moving
    for i in range(1u, 10) {
        add_key_handler_str!(config, w, i.to_string().as_slice(), modm,
            move |&: m, w, c| switch_to_workspace(m, w, c, i - 1));

        add_key_handler_str!(config, w, i.to_string().as_slice(), modm | SHIFTMASK,
            move |&: m, w, c| move_window_to_workspace(m, w, c, i - 1));
    }

    // Media keys
    add_key_handler_str!(config, w, "j", modm | CONTROLMASK,
            |&: w, _, _| { run("amixer", Some("-q set Master 5%-")); w });
    add_key_handler_str!(config, w, "k", modm | CONTROLMASK,
            |&: w, _, _| { run("amixer", Some("-q set Master 5%+")); w });

    add_key_handler_code!(config, 0x1008ff11, NONEMASK,
            |&: w, _, _| { run("amixer", Some("-q set Master 5%-")); w });
    add_key_handler_code!(config, 0x1008ff13, NONEMASK,
            |&: w, _, _| { run("amixer", Some("-q set Master 5%+")); w });

    add_key_handler_code!(config, 0x1008ff02, NONEMASK,
            |&: w, _, _| { run("xbacklight", Some("+10")); w });
    add_key_handler_code!(config, 0x1008ff03, NONEMASK,
            |&: w, _, _| { run("xbacklight", Some("-10")); w });

    add_mouse_handler!(config, BUTTON1, modm,
            |&: m, w, c, s| {
                m.focus(s, w, c).mouse_move_window(w, c, s).windows(w, c, |x| x.shift_master())
            });
    add_mouse_handler!(config, BUTTON3, modm,
            |&: m, w, c, s| {
                m.focus(s, w, c).mouse_resize_window(w, c, s).windows(w, c, |x| x.shift_master())
            });

    // Place specific applications on specific workspaces
    config.set_manage_hook(box |&: workspaces, window_system, window| {
                match window_system.get_class_name(window).as_slice() {
                    "MPlayer" => spawn_on(workspaces, window_system, window, 3),
                    "vlc"     => spawn_on(workspaces, window_system, window, 3),
                    _         => workspaces.clone()
                }
            });

    // Xmobar handling and formatting
    let mut xmobar = spawn_pipe(config, String::from_str("xmobar"),
                                Some(String::from_str("/home/rootnode/.xmonad/xmobar1.hs")));
    let tags = config.general.tags.clone();
    config.set_log_hook(box move |&mut: m, _| {
        let p = &mut xmobar;
        let tags = &tags;
        let workspaces = tags.clone().iter()
            .enumerate()
            .map(|(i, x)| if i as u32 == m.workspaces.current.workspace.id {
                format!("[<fc=#f07746>{}</fc>] ", x)
            } else {
                format!("[{}] ", x)
            })
            .fold(String::from_str(""), |a, x| {
                let mut r = a.clone();
                r.push_str(x.as_slice());
                r
            });

        let content = format!("{} {}", workspaces, m.workspaces.current.workspace.layout.description());
        match p.deref().write().deref_mut().stdin.as_mut() {
            Some(pin) => match pin.write_line(content.as_slice()) {
                _ => ()
            },
            _ => ()
        }
    });
}

<|endoftext|>