<commit_before>//! Open URLs in the web browsers available on a platform.
//!
//! Inspired by the [webbrowser](https://docs.python.org/2/library/webbrowser.html) python library.
//!
//! Currently state of platform support is:
//!
//! * macos => default, as well as browsers listed under [Browser](enum.Browser.html)
//! * windows => default browser only
//! * linux => default browser only (uses $BROWSER env var, failing back to xdg-open, gvfs-open and
//! gnome-open, in that order)
//! * android => not supported right now
//! * ios => not supported right now
//!
//! Important note:
//!
//! * This library requires availability of browsers and a graphical environment during runtime
//! * `cargo test` will actually open the browser locally.
//!
//! # Examples
//!
//! ```
//! use webbrowser;
//!
//! if webbrowser::open("http://github.com").is_ok() {
//!     // ...
//! }
//! ```

use std::default::Default;
use std::error;
use std::fmt;
use std::io::{Error, ErrorKind, Result};
use std::process::{Command, Output};
use std::str::FromStr;

#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
/// Browser types available
pub enum Browser {
    ///Operating system's default browser
    Default,

    ///Mozilla Firefox
    Firefox,

    ///Microsoft's Internet Explorer
    InternetExplorer,

    ///Google Chrome
    Chrome,

    ///Opera
    Opera,

    ///Mac OS Safari
    Safari,
}

///The Error type for parsing a string into a Browser.
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
pub struct ParseBrowserError;

impl fmt::Display for ParseBrowserError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("Invalid browser given")
    }
}

impl error::Error for ParseBrowserError {
    fn description(&self) -> &str {
        "invalid browser"
    }
}

impl Default for Browser {
    fn default() -> Self {
        Browser::Default
    }
}

impl fmt::Display for Browser {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Browser::Default => f.write_str("Default"),
            Browser::Firefox => f.write_str("Firefox"),
            Browser::InternetExplorer => f.write_str("Internet Explorer"),
            Browser::Chrome => f.write_str("Chrome"),
            Browser::Opera => f.write_str("Opera"),
            Browser::Safari => f.write_str("Safari"),
        }
    }
}

impl FromStr for Browser {
    type Err = ParseBrowserError;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        match s {
            "firefox" => Ok(Browser::Firefox),
            "default" => Ok(Browser::Default),
            "ie" | "internet explorer" | "internetexplorer" => Ok(Browser::InternetExplorer),
            "chrome" => Ok(Browser::Chrome),
            "opera" => Ok(Browser::Opera),
            "safari" => Ok(Browser::Safari),
            _ => Err(ParseBrowserError),
        }
    }
}

/// Opens the URL on the default browser of this platform
///
/// Returns Ok(..) so long as the browser invocation was successful. An Err(..) is returned only if
/// there was an error in running the command, or if the browser was not found.
///
/// Equivalent to:
/// ```
/// # use webbrowser::{Browser, open_browser};
/// # let url = "http://example.com";
/// open_browser(Browser::Default, url);
/// ```
///
/// # Examples
/// ```
/// use webbrowser;
///
/// if webbrowser::open("http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open(url: &str) -> Result<Output> {
    open_browser(Browser::Default, url)
}

/// Opens the specified URL on the specific browser (if available) requested. Return semantics are
/// the same as for [open](fn.open.html).
///
/// # Examples
/// ```
/// use webbrowser::{open_browser, Browser};
///
/// if open_browser(Browser::Firefox, "http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open_browser(browser: Browser, url: &str) -> Result<Output> {
    open_browser_internal(browser, url)
}

/// Deal with opening of browsers on Windows, using `start` command
#[cfg(target_os = "windows")]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<Output> {
    match browser {
        Browser::Default => Command::new("cmd").arg("/C").arg("start").arg(url).output(),
        _ => Err(Error::new(
            ErrorKind::NotFound,
            "Only the default browser is supported on this platform right now",
        )),
    }
}

/// Deal with opening of browsers on Mac OS X, using `open` command
#[cfg(target_os = "macos")]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<Output> {
    let mut cmd = Command::new("open");
    match browser {
        Browser::Default => cmd.arg(url).output(),
        _ => {
            let app: Option<&str> = match browser {
                Browser::Firefox => Some("Firefox"),
                Browser::Chrome => Some("Google Chrome"),
                Browser::Opera => Some("Opera"),
                Browser::Safari => Some("Safari"),
                _ => None,
            };
            match app {
                Some(name) => cmd.arg("-a").arg(name).arg(url).output(),
                None => Err(Error::new(
                    ErrorKind::NotFound,
                    format!("Unsupported browser {:?}", browser),
                )),
            }
        }
    }
}

/// Deal with opening of browsers on Linux - currently supports only the default browser
///
/// The mechanism of opening the default browser is as follows:
/// 1. Attempt to use $BROWSER env var if available
/// 2. Attempt to open the url via xdg-open, gvfs-open, gnome-open, respectively, whichever works
///    first
#[cfg(target_os = "linux")]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<Output> {
    match browser {
        Browser::Default => open_on_linux_using_browser_env(url)
            .or_else(|_| -> Result<Output> { Command::new("xdg-open").arg(url).output() })
            .or_else(|_| -> Result<Output> { Command::new("gvfs-open").arg(url).output() })
            .or_else(|_| -> Result<Output> { Command::new("gnome-open").arg(url).output() }),
        _ => Err(Error::new(
            ErrorKind::NotFound,
            "Only the default browser is supported on this platform right now",
        )),
    }
}

/// Open on Linux using the $BROWSER env var
#[cfg(target_os = "linux")]
fn open_on_linux_using_browser_env(url: &str) -> Result<Output> {
    let browsers = ::std::env::var("BROWSER").map_err(|_| -> Error {
        Error::new(ErrorKind::NotFound, format!("BROWSER env not set"))
    })?;
    for browser in browsers.split(':') {
        // $BROWSER can contain ':' delimited options, each representing a potential browser command line
        if !browser.is_empty() {
            // each browser command can have %s to represent URL, while %c needs to be replaced
            // with ':' and %% with '%'
            let cmdline = browser
                .replace("%s", url)
                .replace("%c", ":")
                .replace("%%", "%");
            let cmdarr: Vec<&str> = cmdline.split_whitespace().collect();
            let mut cmd = Command::new(&cmdarr[0]);
            if cmdarr.len() > 1 {
                cmd.args(&cmdarr[1..cmdarr.len()]);
            }
            if !browser.contains("%s") {
                // append the url as an argument only if it was not already set via %s
                cmd.arg(url);
            }
            if let Ok(output) = cmd.output() {
                return Ok(output);
            }
        }
    }
    return Err(Error::new(
        ErrorKind::NotFound,
        "No valid command in $BROWSER",
    ));
}

#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
compile_error!("Only Windows, Mac OS and Linux are currently supported");

#[test]
fn test_open_default() {
    assert!(open("http://github.com").is_ok());
}

#[test]
#[cfg(target_os = "macos")]
fn test_open_browser() {
    assert!(open_browser(Browser::Firefox, "http://github.com").is_ok());
}
<commit_msg>Add `no_run`s<commit_after>//! Open URLs in the web browsers available on a platform.
//!
//! Inspired by the [webbrowser](https://docs.python.org/2/library/webbrowser.html) python library.
//!
//! Currently state of platform support is:
//!
//! * macos => default, as well as browsers listed under [Browser](enum.Browser.html)
//! * windows => default browser only
//! * linux => default browser only (uses $BROWSER env var, failing back to xdg-open, gvfs-open and
//! gnome-open, in that order)
//! * android => not supported right now
//! * ios => not supported right now
//!
//! Important note:
//!
//! * This library requires availability of browsers and a graphical environment during runtime
//! * `cargo test` will actually open the browser locally.
//!
//! # Examples
//!
//! ```no_run
//! use webbrowser;
//!
//! if webbrowser::open("http://github.com").is_ok() {
//!     // ...
//! }
//! ```

use std::default::Default;
use std::error;
use std::fmt;
use std::io::{Error, ErrorKind, Result};
use std::process::{Command, Output};
use std::str::FromStr;

#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
/// Browser types available
pub enum Browser {
    ///Operating system's default browser
    Default,

    ///Mozilla Firefox
    Firefox,

    ///Microsoft's Internet Explorer
    InternetExplorer,

    ///Google Chrome
    Chrome,

    ///Opera
    Opera,

    ///Mac OS Safari
    Safari,
}

///The Error type for parsing a string into a Browser.
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
pub struct ParseBrowserError;

impl fmt::Display for ParseBrowserError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("Invalid browser given")
    }
}

impl error::Error for ParseBrowserError {
    fn description(&self) -> &str {
        "invalid browser"
    }
}

impl Default for Browser {
    fn default() -> Self {
        Browser::Default
    }
}

impl fmt::Display for Browser {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Browser::Default => f.write_str("Default"),
            Browser::Firefox => f.write_str("Firefox"),
            Browser::InternetExplorer => f.write_str("Internet Explorer"),
            Browser::Chrome => f.write_str("Chrome"),
            Browser::Opera => f.write_str("Opera"),
            Browser::Safari => f.write_str("Safari"),
        }
    }
}

impl FromStr for Browser {
    type Err = ParseBrowserError;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        match s {
            "firefox" => Ok(Browser::Firefox),
            "default" => Ok(Browser::Default),
            "ie" | "internet explorer" | "internetexplorer" => Ok(Browser::InternetExplorer),
            "chrome" => Ok(Browser::Chrome),
            "opera" => Ok(Browser::Opera),
            "safari" => Ok(Browser::Safari),
            _ => Err(ParseBrowserError),
        }
    }
}

/// Opens the URL on the default browser of this platform
///
/// Returns Ok(..) so long as the browser invocation was successful. An Err(..) is returned only if
/// there was an error in running the command, or if the browser was not found.
///
/// Equivalent to:
/// ```no_run
/// # use webbrowser::{Browser, open_browser};
/// # let url = "http://example.com";
/// open_browser(Browser::Default, url);
/// ```
///
/// # Examples
/// ```no_run
/// use webbrowser;
///
/// if webbrowser::open("http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open(url: &str) -> Result<Output> {
    open_browser(Browser::Default, url)
}

/// Opens the specified URL on the specific browser (if available) requested. Return semantics are
/// the same as for [open](fn.open.html).
///
/// # Examples
/// ```no_run
/// use webbrowser::{open_browser, Browser};
///
/// if open_browser(Browser::Firefox, "http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open_browser(browser: Browser, url: &str) -> Result<Output> {
    open_browser_internal(browser, url)
}

/// Deal with opening of browsers on Windows, using `start` command
#[cfg(target_os = "windows")]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<Output> {
    match browser {
        Browser::Default => Command::new("cmd").arg("/C").arg("start").arg(url).output(),
        _ => Err(Error::new(
            ErrorKind::NotFound,
            "Only the default browser is supported on this platform right now",
        )),
    }
}

/// Deal with opening of browsers on Mac OS X, using `open` command
#[cfg(target_os = "macos")]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<Output> {
    let mut cmd = Command::new("open");
    match browser {
        Browser::Default => cmd.arg(url).output(),
        _ => {
            let app: Option<&str> = match browser {
                Browser::Firefox => Some("Firefox"),
                Browser::Chrome => Some("Google Chrome"),
                Browser::Opera => Some("Opera"),
                Browser::Safari => Some("Safari"),
                _ => None,
            };
            match app {
                Some(name) => cmd.arg("-a").arg(name).arg(url).output(),
                None => Err(Error::new(
                    ErrorKind::NotFound,
                    format!("Unsupported browser {:?}", browser),
                )),
            }
        }
    }
}

/// Deal with opening of browsers on Linux - currently supports only the default browser
///
/// The mechanism of opening the default browser is as follows:
/// 1. Attempt to use $BROWSER env var if available
/// 2. Attempt to open the url via xdg-open, gvfs-open, gnome-open, respectively, whichever works
///    first
#[cfg(target_os = "linux")]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<Output> {
    match browser {
        Browser::Default => open_on_linux_using_browser_env(url)
            .or_else(|_| -> Result<Output> { Command::new("xdg-open").arg(url).output() })
            .or_else(|_| -> Result<Output> { Command::new("gvfs-open").arg(url).output() })
            .or_else(|_| -> Result<Output> { Command::new("gnome-open").arg(url).output() }),
        _ => Err(Error::new(
            ErrorKind::NotFound,
            "Only the default browser is supported on this platform right now",
        )),
    }
}

/// Open on Linux using the $BROWSER env var
#[cfg(target_os = "linux")]
fn open_on_linux_using_browser_env(url: &str) -> Result<Output> {
    let browsers = ::std::env::var("BROWSER").map_err(|_| -> Error {
        Error::new(ErrorKind::NotFound, format!("BROWSER env not set"))
    })?;
    for browser in browsers.split(':') {
        // $BROWSER can contain ':' delimited options, each representing a potential browser command line
        if !browser.is_empty() {
            // each browser command can have %s to represent URL, while %c needs to be replaced
            // with ':' and %% with '%'
            let cmdline = browser
                .replace("%s", url)
                .replace("%c", ":")
                .replace("%%", "%");
            let cmdarr: Vec<&str> = cmdline.split_whitespace().collect();
            let mut cmd = Command::new(&cmdarr[0]);
            if cmdarr.len() > 1 {
                cmd.args(&cmdarr[1..cmdarr.len()]);
            }
            if !browser.contains("%s") {
                // append the url as an argument only if it was not already set via %s
                cmd.arg(url);
            }
            if let Ok(output) = cmd.output() {
                return Ok(output);
            }
        }
    }
    return Err(Error::new(
        ErrorKind::NotFound,
        "No valid command in $BROWSER",
    ));
}

#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
compile_error!("Only Windows, Mac OS and Linux are currently supported");

#[test]
fn test_open_default() {
    assert!(open("http://github.com").is_ok());
}

#[test]
#[cfg(target_os = "macos")]
fn test_open_browser() {
    assert!(open_browser(Browser::Firefox, "http://github.com").is_ok());
}
<|endoftext|>


<commit_before>extern crate regex;

use regex::Regex;

pub struct parser;

type ParseResult<'a, T> = Result<(T, &'a[u8]), String>;

trait Parser<T> {

  fn parse<'a>(&self, data: &'a [u8]) -> ParseResult<'a, T>;

  fn and_then<'a, B>(&'a self, next: &'a Parser<B>) -> DualParser<T,B> {
    DualParser{first: self, second: next}
  }
  fn or<'a, B>(&'a self, next: &'a Parser<B>) -> OrParser<T,B> {
    OrParser{a: self, b: next}
  }
}

pub struct CharParser{the_char: u8}

impl CharParser {
  fn new(c: u8) -> CharParser {
    CharParser{the_char: c}
  }
}

impl Parser<char> for CharParser {

  fn parse<'a>(&self, data: &'a [u8]) -> ParseResult<'a, char> {
    if data.len() > 0 {
      if (data[0] == self.the_char) {
        Ok((data[0] as char, data.slice_from(1)))
      } else {
        Err(format!("Expected {}, got {}", self.the_char, data[0]))
      }
    } else {
      Err(format!("No data left"))
    }
  }
}

pub struct RegexParser {
  regex: Regex
}
//TODO: this is all kinds of horrible, had a lot of trouble getting it to work
impl Parser<String> for RegexParser {
  fn parse<'a>(&self, data: &'a [u8]) -> ParseResult<'a, String> {
    let s = String::from_utf8_lossy(data);
    let strdata = s.as_slice();
    match self.regex.find(strdata) {
      Some((0, e)) => Ok((String::from_str(strdata.slice_to(e)), data.slice_from(e))),
      _ => Err(format!("no match or match not on first bye"))
    }
  }
}

pub struct RepParser<'a, T>{
  reps: uint,
  parser: &'a Parser<T> + 'a
}

impl<'a, T> Parser<Vec<T>> for RepParser<'a, T> {
  fn parse<'a>(&self, data: &'a [u8]) -> ParseResult<'a, Vec<T>> {
    let mut v: Vec<T> = Vec::new();
    let mut remain = data;
    for i in range(0, self.reps) {
      match self.parser.parse(remain) {
        Ok((result, rest)) => {
          v.push(result);
          remain = rest;
        }
        Err(err) => {
          return Err(format!("Error on rep #{}: {}", i, err));
        }
      }
    }
    Ok((v, remain))
  }
}

pub struct DualParser<'a, A, B> {
  first: &'a Parser<A> + 'a,
  second: &'a Parser<B> + 'a
}

impl <'a, A, B> Parser<(A,B)> for DualParser<'a, A, B> {

  fn parse<'a>(&self, data: &'a [u8]) -> ParseResult<'a, (A, B)> {
    /*  doesn't work :(
    self.first.parse(data).and_then(
      |(a, d2)| self.second.parse(d2).and_then(
        |(b, remain)| Ok(((a, b), remain))
      )
    )
    */
    match self.first.parse(data) {
      Ok((a, d2)) => match self.second.parse(d2) {
        Ok((b, remain)) => Ok(((a, b), remain)),
        Err(err) => Err(err)
      },
      Err(err) => Err(err)
    }
  }
}

pub enum Or<A,B> {
  OrA(A),
  OrB(B),
}

pub struct OrParser<'a, A, B> {
  a: &'a Parser<A> + 'a,
  b: &'a Parser<B> + 'a
}

impl<'a, A, B> Parser<Or<A,B>> for OrParser<'a, A, B> {
  fn parse<'a>(&self, data: &'a [u8]) -> ParseResult<'a, Or<A, B>> {
    match self.a.parse(data) {
      Ok((a, d2)) => Ok((OrA(a), d2)),
      Err(err) => match self.b.parse(data) {
        Ok((b, remain)) => Ok((OrB(b), remain)),
        Err(err) => Err(err)
      }
    }
  }
}

#[test]
fn test_char() {
  let ch = CharParser::new('v' as u8);
  let data = ['v' as u8, 'b'as u8, 'x' as u8];
  match ch.parse(&data) {
    Ok((c, rest)) => {
      assert!(c == 'v');
      assert!(rest.len() == 2);
      assert!(rest[0] == 'b' as u8);
    }
    Err(err) => {fail!(format!("unepected error: {}", err));}
  }
}

#[test]
fn test_rep() {
  let ch = CharParser::new('v' as u8);
  let rep = RepParser{reps: 3, parser: &ch};
  let data = ['v' as u8, 'v'as u8, 'v' as u8, 'x' as u8];
  match rep.parse(&data) {
    Ok((vec, rest)) => {
      assert!(vec.len() == 3)
      for c in vec.iter() {
        assert!(*c == 'v');
      }
    }
    Err(err) => {fail!(format!("unepected error: {}", err));}
  }
}

#[test]
fn test_and_then() {
  let a = CharParser::new('a' as u8);
  let b = CharParser::new('b' as u8);
  let ab = a.and_then(&b);
  let data = ['a' as u8, 'b'as u8, 'v' as u8, 'x' as u8];
  match ab.parse(data) {
    Ok(((a, b), rem)) => {
      assert!(a == 'a');
      assert!(b == 'b');
      assert!(rem.len() == 2);
    }
    Err(err) => {
      fail!(err);
    }
  }
}

#[test]
fn test_or() {
  let a = CharParser::new('a' as u8);
  let b = CharParser::new('b' as u8);
  let ab = a.or(&b);
  let data = ['a' as u8, 'b'as u8, 'v' as u8, 'x' as u8];
  match ab.parse(data) {
    Ok((OrA('a'), rem)) => {
      match ab.parse(rem) {
        Ok((OrB('b'), rem)) => {
          assert!(rem.len() == 2);
        }
        _ => {fail!("wrong b");}
      }
    }
    _ => {
      fail!("wrong a");
    }
  }
}

<commit_msg>string parsers working<commit_after>#![feature(phase)]
#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

use regex::{Captures, Regex};

pub struct parser;

type ParseResult<'a, T> = Result<(T, &'a str), String>;

trait Parser<'a, T> {

  fn parse(&self, data: &'a str) -> ParseResult<'a, T>;

  fn and_then<B>(&'a self, next: &'a Parser<'a, B>) -> DualParser<'a, T,B> {
    DualParser{first: self, second: next}
  }
  fn or<B>(&'a self, next: &'a Parser<'a, B>) -> OrParser<'a, T,B> {
    OrParser{a: self, b: next}
  }
}

pub struct CharParser{the_char: char}

impl CharParser {
  fn new(c: char) -> CharParser {
    CharParser{the_char: c}
  }
}

impl<'a> Parser<'a, char> for CharParser {

  fn parse(&self, data: &'a str) -> ParseResult<'a, char> {
    if data.len() > 0 {
      if data.char_at(0) == self.the_char {
        Ok((self.the_char, data.slice_from(1)))
      } else {
        Err(format!("Expected {}, got {}", self.the_char, data.char_at(0)))
      }
    } else {
      Err(format!("No data left"))
    }
  }
}

pub struct RegexParser {
  regex: Regex
}

impl<'a> Parser<'a, Captures<'a>> for RegexParser {
  fn parse(&self, data: &'a str) -> ParseResult<'a, Captures<'a>> {
    match self.regex.captures(data) {
      Some(cap) => {
        let start = cap.at(0).len();
        Ok((cap, data.slice_from(start)))
      }
      _ => Err(format!("no match or match not on first bye"))
    }
  }
}

pub struct RepParser<'a, T>{
  reps: uint,
  parser: &'a Parser<'a, T> + 'a
}

impl<'a, T> Parser<'a, Vec<T>> for RepParser<'a, T> {
  fn parse(&self, data: &'a str) -> ParseResult<'a, Vec<T>> {
    let mut v: Vec<T> = Vec::new();
    let mut remain = data;
    for i in range(0, self.reps) {
      match self.parser.parse(remain) {
        Ok((result, rest)) => {
          v.push(result);
          remain = rest;
        }
        Err(err) => {
          return Err(format!("Error on rep #{}: {}", i, err));
        }
      }
    }
    Ok((v, remain))
  }
}

pub struct DualParser<'a, A, B> {
  first: &'a Parser<'a, A> + 'a,
  second: &'a Parser<'a, B> + 'a
}

impl <'a, A, B> Parser<'a, (A,B)> for DualParser<'a, A, B> {

  fn parse(&self, data: &'a str) -> ParseResult<'a, (A, B)> {
    /*  doesn't work :(
    self.first.parse(data).and_then(
      |(a, d2)| self.second.parse(d2).and_then(
        |(b, remain)| Ok(((a, b), remain))
      )
    )
    */
    match self.first.parse(data) {
      Ok((a, d2)) => match self.second.parse(d2) {
        Ok((b, remain)) => Ok(((a, b), remain)),
        Err(err) => Err(err)
      },
      Err(err) => Err(err)
    }
  }
}

pub enum Or<A,B> {
  OrA(A),
  OrB(B),
}

pub struct OrParser<'a, A, B> {
  a: &'a Parser<'a, A> + 'a,
  b: &'a Parser<'a, B> + 'a
}

impl<'a, A, B> Parser<'a, Or<A,B>> for OrParser<'a, A, B> {
  fn parse(&self, data: &'a str) -> ParseResult<'a, Or<A, B>> {
    match self.a.parse(data) {
      Ok((a, d2)) => Ok((OrA(a), d2)),
      Err(err) => match self.b.parse(data) {
        Ok((b, remain)) => Ok((OrB(b), remain)),
        Err(err) => Err(err)
      }
    }
  }
}

#[test]
fn test_char() {
  let ch = CharParser::new('v');
  let data = "vbx";
  match ch.parse(data) {
    Ok((c, rest)) => {
      assert!(c == 'v');
      assert!(rest.len() == 2);
      assert!(rest.char_at(0) == 'b');
    }
    Err(err) => {fail!(format!("unepected error: {}", err));}
  }
}

#[test]
fn test_regex() {
  let reg = regex!("ab[cd]");
  let parser_a = RegexParser{regex: reg};
  let data = "abdabc";
  assert!(parser_a.parse(data) == Ok(("abd", "abc")));
}

#[test]
fn test_rep() {
  let ch = CharParser::new('v');
  let rep = RepParser{reps: 3, parser: &ch};
  let data = "vvvx";
  match rep.parse(data) {
    Ok((vec, rest)) => {
      assert!(vec.len() == 3)
      for c in vec.iter() {
        assert!(*c == 'v');
      }
    }
    Err(err) => {fail!(format!("unepected error: {}", err));}
  }
}

#[test]
fn test_and_then() {
  let a = CharParser::new('a' );
  let b = CharParser::new('b' );
  let ab = a.and_then(&b);
  let data = "abvx";
  match ab.parse(data) {
    Ok(((a, b), rem)) => {
      assert!(a == 'a');
      assert!(b == 'b');
      assert!(rem.len() == 2);
    }
    Err(err) => {
      fail!(err);
    }
  }
}

#[test]
fn test_or() {
  let a = CharParser::new('a' );
  let b = CharParser::new('b' );
  let ab = a.or(&b);
  let data = "abvx";
  match ab.parse(data) {
    Ok((OrA('a'), rem)) => {
      match ab.parse(rem) {
        Ok((OrB('b'), rem)) => {
          assert!(rem.len() == 2);
        }
        _ => {fail!("wrong b");}
      }
    }
    _ => {
      fail!("wrong a");
    }
  }
}

<|endoftext|>


<commit_before>extern crate base64;
extern crate crypto;
extern crate hyper;
extern crate hyper_native_tls;
extern crate rand;
extern crate serde_json;
extern crate time;
extern crate url;

use std::io::Read;
use std::collections::{HashMap, BTreeMap};

use crypto::sha1::Sha1;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use hyper::header::{Headers, Authorization, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;
use rand::Rng;
use url::Url;
use url::percent_encoding::{EncodeSet, percent_encode};

#[derive(Copy, Clone)]
struct StrictEncodeSet;

impl EncodeSet for StrictEncodeSet {
    fn contains(&self, byte: u8) -> bool {
        !((byte >= "0".as_bytes()[0] && byte <= "9".as_bytes()[0]) ||
            (byte >= "a".as_bytes()[0] && byte <= "z".as_bytes()[0]) ||
            (byte >= "A".as_bytes()[0] && byte <= "Z".as_bytes()[0]) ||
            (byte == "-".as_bytes()[0]) ||
            (byte == ".".as_bytes()[0]) ||
            (byte == "_".as_bytes()[0]) ||
            (byte == "~".as_bytes()[0])
        )
    }
}

#[derive(Clone, Debug)]
pub struct Client {
    pub consumer_key: Option<String>,
    pub consumer_secret: Option<String>,
    pub access_token: Option<String>,
    pub access_token_secret: Option<String>
}

impl Client {
    pub fn new(ck: Option<String>, cs: Option<String>, at: Option<String>, ats: Option<String>) -> Client {
        Client {
            consumer_key: ck,
            consumer_secret: cs,
            access_token: at,
            access_token_secret: ats
        }
    }

    pub fn get_request_url(&mut self) -> String {
        let (request_token, request_token_secret) = get_request_token(&self).unwrap();
        let mut request_url = Url::parse("http://api.twitter.com/oauth/authorize").unwrap();
        request_url.query_pairs_mut().append_pair("oauth_token", &request_token);
        request_url.query_pairs_mut().append_pair("oauth_token_secret", &request_token_secret);

        self.access_token = Some(request_token);
        self.access_token_secret = Some(request_token_secret);
        request_url.to_string()
    }

    pub fn set_access_token(&mut self, verifier: &str) {
        let url = "https://api.twitter.com/oauth/access_token";

        let token = self.access_token.clone().unwrap();
        let token_secret = self.access_token_secret.clone().unwrap();

        let mut params: BTreeMap<&str, &str> = BTreeMap::new();
        params.insert("oauth_token", &token);
        params.insert("oauth_verifier", verifier);
        let (header, _) = build_request(&self, "POST", url, params, &token_secret);

        let (oauth_token, oauth_token_secret) = get_oauth_token(get_token(url, &header)).unwrap();
        self.access_token = Some(oauth_token);
        self.access_token_secret = Some(oauth_token_secret);
    }

    pub fn post(&self, endpoint: &str, param: BTreeMap<&str, &str>) -> serde_json::Value {
        let url = format!("https://api.twitter.com/1.1/{}", endpoint);
        let token = self.access_token.clone().unwrap();
        let token_secret = self.access_token_secret.clone().unwrap();

        let mut param = param;
        param.insert("oauth_token", &token);

        let (header, body) = build_request(&self, "POST", &url, param, &token_secret);

        let mut headers = Headers::new();
        headers.set(Authorization(header));
        headers.set(ContentType(Mime(TopLevel::Application, SubLevel::WwwFormUrlEncoded, vec![(Attr::Charset, Value::Utf8)])));
        let client = hyper::Client::with_connector(HttpsConnector::new(NativeTlsClient::new().unwrap()));
        let mut res = client.post(&url)
            .headers(headers)
            .body(&body)
            .send()
            .unwrap();
        let mut response_body = String::new();
        res.read_to_string(&mut response_body).unwrap();

        match serde_json::from_str::<serde_json::Value>(&response_body) {
            Ok(json) => json,
            Err(..) => panic!("Err"),
        }
    }

    pub fn get(&self, endpoint: &str, param: BTreeMap<&str, &str>) -> serde_json::Value {
        let url = format!("https://api.twitter.com/1.1/{}", endpoint);
        let token = self.access_token.clone().unwrap();
        let token_secret = self.access_token_secret.clone().unwrap();

        let mut param = param;
        param.insert("oauth_token", &token);

        let (header, _) = build_request(&self, "GET", &url, param, &token_secret);

        let mut headers = Headers::new();
        headers.set(Authorization(header));
        let client = hyper::Client::with_connector(HttpsConnector::new(NativeTlsClient::new().unwrap()));
        let mut res = client.get(&url)
            .headers(headers)
            .send()
            .unwrap();
        let mut response_body = String::new();
        res.read_to_string(&mut response_body).unwrap();

        match serde_json::from_str::<serde_json::Value>(&response_body) {
            Ok(json) => json,
            Err(..) => panic!("Err"),
        }
    }
}

fn encode(s: &str) -> String {
    percent_encode(s.as_bytes(), StrictEncodeSet).collect::<String>()
}

fn build_request(
    oauth: &Client,
    method: &str,
    url: &str,
    append_params: BTreeMap<&str, &str>,
    oauth_token_secret: &str
) -> (String, String) {
    let nonce = rand::thread_rng().gen_ascii_chars().take(32).collect::<String>();
    let now_time = time::now().to_timespec().sec.to_string();
    let key = oauth.consumer_key.clone().unwrap();
    let key_secret = oauth.consumer_secret.clone().unwrap();

    let mut params: BTreeMap<&str, &str> = BTreeMap::new();
    params.insert("oauth_consumer_key", &key);
    params.insert("oauth_nonce", &nonce);
    params.insert("oauth_signature_method", "HMAC-SHA1");
    params.insert("oauth_timestamp", &now_time);
    params.insert("oauth_version", "1.0a");

    for (k, v) in append_params {
        params.insert(k, v);
    }

    let param = params
        .iter()
        .map(|(k, v)| format!("{}={}", k, encode(v)))
        .collect::<Vec<_>>()
        .join("&");

    let oauth_signature = {
        let signature_param = format!("{}&{}&{}", encode(method.to_uppercase().as_str()), encode(url), encode(&param));
        let key = format!("{}&{}", encode(&key_secret), encode(oauth_token_secret));
        let mut hmac = Hmac::new(Sha1::new(), key.as_bytes());
        hmac.input(signature_param.as_bytes());
        base64::encode(hmac.result().code())
    };

    let mut values = params;
    values.insert("oauth_signature", &oauth_signature);

    (build_header(&values), build_body(&values))
}

fn build_header(params: &BTreeMap<&str, &str>) -> String {
    let header = params
        .iter()
        .filter(|&(k, _)| k.starts_with("oauth_"))
        .map(|(k, v)| format!("{}=\"{}\"", k, encode(v)))
        .collect::<Vec<_>>()
        .join(", ");
    format!("OAuth {}", header)
}

fn build_body(params: &BTreeMap<&str, &str>) -> String {
    params
        .iter()
        .filter(|&(k, _)| !k.starts_with("oauth_"))
        .map(|(k, v)| format!("{}={}", k, encode(v)))
        .collect::<Vec<_>>()
        .join("&")
}

fn get_token(url: &str, header_value: &str) -> String {
    let client = hyper::Client::with_connector(HttpsConnector::new(NativeTlsClient::new().unwrap()));
    let mut headers = Headers::new();
    headers.set(Authorization(header_value.to_string()));
    let mut res = client
        .post(url)
        .headers(headers)
        .send()
        .unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    body
}

fn get_request_token(oauth: &Client) -> Result<(String, String), String> {
    let url = "https://api.twitter.com/oauth/request_token";

    let mut params = BTreeMap::new();
    params.insert("oauth_callback", "oob");
    let (header, _) = build_request(&oauth, "POST", url, params, "");

    get_oauth_token(get_token(url, &header))
}

fn get_oauth_token(body: String) -> Result<(String, String), String> {
    let query = match serde_json::from_str::<serde_json::Value>(&body) {
        Ok(json) => return Err(json["errors"][0]["message"].to_string()),
        Err(..) => body,
    };

    let mut parsed_url = Url::parse("http://example.com").unwrap();
    parsed_url.set_query(Some(&query));
    let hash_query: HashMap<_, _> = parsed_url.query_pairs().into_owned().collect();

    Ok((hash_query["oauth_token"].to_string(), hash_query["oauth_token_secret"].to_string()))
}
<commit_msg>newメソッドの引数を変更<commit_after>extern crate base64;
extern crate crypto;
extern crate hyper;
extern crate hyper_native_tls;
extern crate rand;
extern crate serde_json;
extern crate time;
extern crate url;

use std::io::Read;
use std::collections::{HashMap, BTreeMap};

use crypto::sha1::Sha1;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use hyper::header::{Headers, Authorization, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;
use rand::Rng;
use url::Url;
use url::percent_encoding::{EncodeSet, percent_encode};

#[derive(Copy, Clone)]
struct StrictEncodeSet;

impl EncodeSet for StrictEncodeSet {
    fn contains(&self, byte: u8) -> bool {
        !((byte >= "0".as_bytes()[0] && byte <= "9".as_bytes()[0]) ||
            (byte >= "a".as_bytes()[0] && byte <= "z".as_bytes()[0]) ||
            (byte >= "A".as_bytes()[0] && byte <= "Z".as_bytes()[0]) ||
            (byte == "-".as_bytes()[0]) ||
            (byte == ".".as_bytes()[0]) ||
            (byte == "_".as_bytes()[0]) ||
            (byte == "~".as_bytes()[0])
        )
    }
}

#[derive(Clone, Debug)]
pub struct Client {
    pub consumer_key: Option<String>,
    pub consumer_secret: Option<String>,
    pub access_token: Option<String>,
    pub access_token_secret: Option<String>
}

impl Client {
    pub fn new(ck: Option<String>, cs: Option<String>) -> Client {
        Client {
            consumer_key: ck,
            consumer_secret: cs,
            access_token: None,
            access_token_secret: None
        }
    }

    pub fn get_request_url(&mut self) -> String {
        let (request_token, request_token_secret) = get_request_token(&self).unwrap();
        let mut request_url = Url::parse("http://api.twitter.com/oauth/authorize").unwrap();
        request_url.query_pairs_mut().append_pair("oauth_token", &request_token);
        request_url.query_pairs_mut().append_pair("oauth_token_secret", &request_token_secret);

        self.access_token = Some(request_token);
        self.access_token_secret = Some(request_token_secret);
        request_url.to_string()
    }

    pub fn set_access_token(&mut self, verifier: &str) {
        let url = "https://api.twitter.com/oauth/access_token";

        let token = self.access_token.clone().unwrap();
        let token_secret = self.access_token_secret.clone().unwrap();

        let mut params: BTreeMap<&str, &str> = BTreeMap::new();
        params.insert("oauth_token", &token);
        params.insert("oauth_verifier", verifier);
        let (header, _) = build_request(&self, "POST", url, params, &token_secret);

        let (oauth_token, oauth_token_secret) = get_oauth_token(get_token(url, &header)).unwrap();
        self.access_token = Some(oauth_token);
        self.access_token_secret = Some(oauth_token_secret);
    }

    pub fn post(&self, endpoint: &str, param: BTreeMap<&str, &str>) -> serde_json::Value {
        let url = format!("https://api.twitter.com/1.1/{}", endpoint);
        let token = self.access_token.clone().unwrap();
        let token_secret = self.access_token_secret.clone().unwrap();

        let mut param = param;
        param.insert("oauth_token", &token);

        let (header, body) = build_request(&self, "POST", &url, param, &token_secret);

        let mut headers = Headers::new();
        headers.set(Authorization(header));
        headers.set(ContentType(Mime(TopLevel::Application, SubLevel::WwwFormUrlEncoded, vec![(Attr::Charset, Value::Utf8)])));
        let client = hyper::Client::with_connector(HttpsConnector::new(NativeTlsClient::new().unwrap()));
        let mut res = client.post(&url)
            .headers(headers)
            .body(&body)
            .send()
            .unwrap();
        let mut response_body = String::new();
        res.read_to_string(&mut response_body).unwrap();

        match serde_json::from_str::<serde_json::Value>(&response_body) {
            Ok(json) => json,
            Err(..) => panic!("Err"),
        }
    }

    pub fn get(&self, endpoint: &str, param: BTreeMap<&str, &str>) -> serde_json::Value {
        let url = format!("https://api.twitter.com/1.1/{}", endpoint);
        let token = self.access_token.clone().unwrap();
        let token_secret = self.access_token_secret.clone().unwrap();

        let mut param = param;
        param.insert("oauth_token", &token);

        let (header, _) = build_request(&self, "GET", &url, param, &token_secret);

        let mut headers = Headers::new();
        headers.set(Authorization(header));
        let client = hyper::Client::with_connector(HttpsConnector::new(NativeTlsClient::new().unwrap()));
        let mut res = client.get(&url)
            .headers(headers)
            .send()
            .unwrap();
        let mut response_body = String::new();
        res.read_to_string(&mut response_body).unwrap();

        match serde_json::from_str::<serde_json::Value>(&response_body) {
            Ok(json) => json,
            Err(..) => panic!("Err"),
        }
    }
}

fn encode(s: &str) -> String {
    percent_encode(s.as_bytes(), StrictEncodeSet).collect::<String>()
}

fn build_request(
    oauth: &Client,
    method: &str,
    url: &str,
    append_params: BTreeMap<&str, &str>,
    oauth_token_secret: &str
) -> (String, String) {
    let nonce = rand::thread_rng().gen_ascii_chars().take(32).collect::<String>();
    let now_time = time::now().to_timespec().sec.to_string();
    let key = oauth.consumer_key.clone().unwrap();
    let key_secret = oauth.consumer_secret.clone().unwrap();

    let mut params: BTreeMap<&str, &str> = BTreeMap::new();
    params.insert("oauth_consumer_key", &key);
    params.insert("oauth_nonce", &nonce);
    params.insert("oauth_signature_method", "HMAC-SHA1");
    params.insert("oauth_timestamp", &now_time);
    params.insert("oauth_version", "1.0a");

    for (k, v) in append_params {
        params.insert(k, v);
    }

    let param = params
        .iter()
        .map(|(k, v)| format!("{}={}", k, encode(v)))
        .collect::<Vec<_>>()
        .join("&");

    let oauth_signature = {
        let signature_param = format!("{}&{}&{}", encode(method.to_uppercase().as_str()), encode(url), encode(&param));
        let key = format!("{}&{}", encode(&key_secret), encode(oauth_token_secret));
        let mut hmac = Hmac::new(Sha1::new(), key.as_bytes());
        hmac.input(signature_param.as_bytes());
        base64::encode(hmac.result().code())
    };

    let mut values = params;
    values.insert("oauth_signature", &oauth_signature);

    (build_header(&values), build_body(&values))
}

fn build_header(params: &BTreeMap<&str, &str>) -> String {
    let header = params
        .iter()
        .filter(|&(k, _)| k.starts_with("oauth_"))
        .map(|(k, v)| format!("{}=\"{}\"", k, encode(v)))
        .collect::<Vec<_>>()
        .join(", ");
    format!("OAuth {}", header)
}

fn build_body(params: &BTreeMap<&str, &str>) -> String {
    params
        .iter()
        .filter(|&(k, _)| !k.starts_with("oauth_"))
        .map(|(k, v)| format!("{}={}", k, encode(v)))
        .collect::<Vec<_>>()
        .join("&")
}

fn get_token(url: &str, header_value: &str) -> String {
    let client = hyper::Client::with_connector(HttpsConnector::new(NativeTlsClient::new().unwrap()));
    let mut headers = Headers::new();
    headers.set(Authorization(header_value.to_string()));
    let mut res = client
        .post(url)
        .headers(headers)
        .send()
        .unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    body
}

fn get_request_token(oauth: &Client) -> Result<(String, String), String> {
    let url = "https://api.twitter.com/oauth/request_token";

    let mut params = BTreeMap::new();
    params.insert("oauth_callback", "oob");
    let (header, _) = build_request(&oauth, "POST", url, params, "");

    get_oauth_token(get_token(url, &header))
}

fn get_oauth_token(body: String) -> Result<(String, String), String> {
    let query = match serde_json::from_str::<serde_json::Value>(&body) {
        Ok(json) => return Err(json["errors"][0]["message"].to_string()),
        Err(..) => body,
    };

    let mut parsed_url = Url::parse("http://example.com").unwrap();
    parsed_url.set_query(Some(&query));
    let hash_query: HashMap<_, _> = parsed_url.query_pairs().into_owned().collect();

    Ok((hash_query["oauth_token"].to_string(), hash_query["oauth_token_secret"].to_string()))
}
<|endoftext|>


<commit_before>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! This library provides implementations of `Mutex`, `RwLock`, `Condvar` and
//! `Once` that are smaller, faster and more flexible than those in the Rust
//! standard library. It also exposes a low-level API for creating your own
//! efficient synchronization primitives.
//!
//! When tested on x86_64 Linux, `parking_lot::Mutex` was found to be 1.5x
//! faster than `std::sync::Mutex` when uncontended, and up to 5x faster when
//! contended from multiple threads. The numbers for `RwLock` vary depending on
//! the number of reader and writer threads, but are almost always faster than
//! the standard library `RwLock`, and even up to 50x faster in some cases.
//!
//! # Features
//!
//! The primitives provided by this library have several advantages over those
//! in the Rust standard library:
//!
//! 1. `Mutex` and `Once` only require 1 byte of storage space, while `Condvar`
//!    and `RwLock` only requires 1 word of storage space. On the other hand the
//!    standard library primitives require a dynamically allocated `Box` to hold
//!    OS-specific synchronization primitives. The small size of `Mutex` in
//!    particular encourages the use of fine-grained locks to increase
//!    parallelism.
//! 2. Since they consist of just a single atomic variable, have constant
//!    initializers and don't need destructors, these primitives can be used as
//!     `static` global variables. The standard library primitives require
//!    dynamic initialization and thus need to be lazily initialized with
//!    `lazy_static!`.
//! 3. Uncontended lock acquisition and release is done through fast inline
//!    paths which only require a single atomic operation.
//! 4. Microcontention (a contended lock with a short critical section) is
//!    efficiently handled by spinning a few times while trying to acquire a
//!    lock.
//! 5. The locks are adaptive and will suspend a thread after a few failed spin
//!    attempts. This makes the locks suitable for both long and short critical
//!    sections.
//! 6. `Condvar`, `RwLock` and `Once` work on Windows XP, unlike the standard
//!    library versions of those types.
//! 7. `RwLock` takes advantage of hardware lock elision on processors that
//!    support it, which can lead to huge performance wins with many readers.
//! 8. `MutexGuard` (and the `RwLock` equivalents) is `Send`, which means it can
//!    be unlocked by a different thread than the one that locked it.
//! 9. `RwLock` will prefer writers, whereas the standard library version makes
//!    no guarantees as to whether readers or writers are given priority.
//! 10. `Condvar` is guaranteed not to produce spurious wakeups. A thread will
//!     only be woken up if it timed out or it was woken up by a notification.
//! 11. `Condvar::notify_all` will only wake up a single thread and requeue the
//!     rest to wait on the associated `Mutex`. This avoids a thundering herd
//!     problem where all threads try to acquire the lock at the same time.
//! 12. `RwLock` supports atomically downgrading a write lock into a read lock.
//! 13. `Mutex<()>` and `RwLock<()>` allow raw locking and unlocking without a
//!     RAII guard object.
//!
//! # The parking lot
//!
//! To keep these primitives small, all thread queuing and suspending
//! functionality is offloaded to the *parking lot*. The idea behind this is
//! based on the Webkit [`WTF::ParkingLot`]
//! (https://webkit.org/blog/6161/locking-in-webkit/) class, which essentially
//! consists of a hash table mapping of lock addresses to queues of parked
//! (sleeping) threads. The Webkit parking lot was itself inspired by Linux
//! [futexes](http://man7.org/linux/man-pages/man2/futex.2.html), but it is more
//! powerful since it allows invoking callbacks while holding a queue lock.
//!
//! *Parking* refers to suspending the thread while simultaneously enqueuing it
//! on a queue keyed by some address. *Unparking* refers to dequeuing a thread
//! from a queue keyed by some address and resuming it. The parking lot API
//! consists of just 4 functions:
//!
//! ```rust,ignore
//! unsafe fn park(key: usize,
//!                validate: &mut FnMut() -> bool,
//!                before_sleep: &mut FnMut(),
//!                timed_out: &mut FnMut(usize, UnparkResult),
//!                timeout: Option<Instant>)
//!                -> bool
//! ```
//!
//! This function performs the following steps:
//!
//! 1. Lock the queue associated with `key`.
//! 2. Call `validate`, if it returns `false`, unlock the queue and return.
//! 3. Add the current thread to the queue.
//! 4. Unlock the queue.
//! 5. Call `before_sleep`.
//! 6. Sleep until we are unparked or `timeout` is reached.
//! 7. If the park timed out, call `timed_out`.
//! 8. Return `true` if we were unparked by another thread, `false` otherwise.
//!
//! ```rust,ignore
//! unsafe fn unpark_one(key: usize,
//!                      callback: &mut FnMut(UnparkResult))
//!                      -> UnparkResult
//! ```
//!
//! This function will unpark a single thread from the queue associated with
//! `key`. The `callback` function is invoked while holding the queue lock but
//! before the thread is unparked. The `UnparkResult` indicates whether the
//! queue was empty and, if not, whether there are still threads remaining in
//! the queue.
//!
//! ```rust,ignore
//! unsafe fn unpark_all(key: usize) -> usize
//! ```
//!
//! This function will unpark all threads in the queue associated with `key`. It
//! returns the number of threads that were unparked.
//!
//! ```rust,ignore
//! unsafe fn unpark_requeue(key_from: usize,
//!                          key_to: usize,
//!                          validate: &mut FnMut() -> RequeueOp,
//!                          callback: &mut FnMut(RequeueOp, usize))
//!                          -> usize
//! ```
//!
//! This function will remove all threads from the queue associated with
//! `key_from`, optionally unpark the first one and move the rest to the queue
//! associated with `key_to`. The `validate` function is invoked while holding
//! both queue locks and can choose whether to abort the operation and whether
//! to unpark one thread from the queue. The `callback` function is then called
//! with the result of `validate` and the number of threads that were in the
//! original queue.
//!
//! # Building custom synchronization primitives
//!
//! Building custom synchronization primitives is very simple since
//! `parking_lot` takes care of all the hard parts for you. The most commmon
//! case for a custom primitive would be to integrate a `Mutex` inside another
//! data type. Since a mutex only requires 2 bits, it can share space with other
//! data. For example, one could create an `ArcMutex` type that combines the
//! atomic reference count and the two mutex bits in the same atomic word.

#![warn(missing_docs)]
#![cfg_attr(feature = "nightly", feature(extended_compare_and_swap))]
#![cfg_attr(feature = "nightly", feature(const_fn))]
#![cfg_attr(feature = "nightly", feature(integer_atomics))]
#![cfg_attr(feature = "nightly", feature(asm))]

extern crate smallvec;

#[cfg(test)]
#[macro_use]
extern crate lazy_static;

#[cfg(unix)]
extern crate libc;

#[cfg(windows)]
extern crate winapi;
#[cfg(windows)]
extern crate kernel32;

#[cfg(all(feature = "nightly", target_os = "linux"))]
#[path = "thread_parker/linux.rs"]
mod thread_parker;
#[cfg(all(unix, not(all(feature = "nightly", target_os = "linux"))))]
#[path = "thread_parker/unix.rs"]
mod thread_parker;
#[cfg(windows)]
#[path = "thread_parker/windows.rs"]
mod thread_parker;
#[cfg(not(any(windows, unix)))]
#[path = "thread_parker/generic.rs"]
mod thread_parker;

#[cfg(not(feature = "nightly"))]
mod stable;
mod spinwait;
mod word_lock;
mod parking_lot;
mod elision;
mod raw_mutex;
mod raw_rwlock;
mod condvar;
mod mutex;
mod rwlock;
mod once;

pub use once::{Once, ONCE_INIT, OnceState};
pub use parking_lot::{UnparkResult, RequeueOp, park, unpark_one, unpark_all, unpark_requeue};
pub use mutex::{Mutex, MutexGuard};
pub use condvar::{Condvar, WaitTimeoutResult};
pub use rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
<commit_msg>Remove unneeded feature on nightly<commit_after>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! This library provides implementations of `Mutex`, `RwLock`, `Condvar` and
//! `Once` that are smaller, faster and more flexible than those in the Rust
//! standard library. It also exposes a low-level API for creating your own
//! efficient synchronization primitives.
//!
//! When tested on x86_64 Linux, `parking_lot::Mutex` was found to be 1.5x
//! faster than `std::sync::Mutex` when uncontended, and up to 5x faster when
//! contended from multiple threads. The numbers for `RwLock` vary depending on
//! the number of reader and writer threads, but are almost always faster than
//! the standard library `RwLock`, and even up to 50x faster in some cases.
//!
//! # Features
//!
//! The primitives provided by this library have several advantages over those
//! in the Rust standard library:
//!
//! 1. `Mutex` and `Once` only require 1 byte of storage space, while `Condvar`
//!    and `RwLock` only requires 1 word of storage space. On the other hand the
//!    standard library primitives require a dynamically allocated `Box` to hold
//!    OS-specific synchronization primitives. The small size of `Mutex` in
//!    particular encourages the use of fine-grained locks to increase
//!    parallelism.
//! 2. Since they consist of just a single atomic variable, have constant
//!    initializers and don't need destructors, these primitives can be used as
//!     `static` global variables. The standard library primitives require
//!    dynamic initialization and thus need to be lazily initialized with
//!    `lazy_static!`.
//! 3. Uncontended lock acquisition and release is done through fast inline
//!    paths which only require a single atomic operation.
//! 4. Microcontention (a contended lock with a short critical section) is
//!    efficiently handled by spinning a few times while trying to acquire a
//!    lock.
//! 5. The locks are adaptive and will suspend a thread after a few failed spin
//!    attempts. This makes the locks suitable for both long and short critical
//!    sections.
//! 6. `Condvar`, `RwLock` and `Once` work on Windows XP, unlike the standard
//!    library versions of those types.
//! 7. `RwLock` takes advantage of hardware lock elision on processors that
//!    support it, which can lead to huge performance wins with many readers.
//! 8. `MutexGuard` (and the `RwLock` equivalents) is `Send`, which means it can
//!    be unlocked by a different thread than the one that locked it.
//! 9. `RwLock` will prefer writers, whereas the standard library version makes
//!    no guarantees as to whether readers or writers are given priority.
//! 10. `Condvar` is guaranteed not to produce spurious wakeups. A thread will
//!     only be woken up if it timed out or it was woken up by a notification.
//! 11. `Condvar::notify_all` will only wake up a single thread and requeue the
//!     rest to wait on the associated `Mutex`. This avoids a thundering herd
//!     problem where all threads try to acquire the lock at the same time.
//! 12. `RwLock` supports atomically downgrading a write lock into a read lock.
//! 13. `Mutex<()>` and `RwLock<()>` allow raw locking and unlocking without a
//!     RAII guard object.
//!
//! # The parking lot
//!
//! To keep these primitives small, all thread queuing and suspending
//! functionality is offloaded to the *parking lot*. The idea behind this is
//! based on the Webkit [`WTF::ParkingLot`]
//! (https://webkit.org/blog/6161/locking-in-webkit/) class, which essentially
//! consists of a hash table mapping of lock addresses to queues of parked
//! (sleeping) threads. The Webkit parking lot was itself inspired by Linux
//! [futexes](http://man7.org/linux/man-pages/man2/futex.2.html), but it is more
//! powerful since it allows invoking callbacks while holding a queue lock.
//!
//! *Parking* refers to suspending the thread while simultaneously enqueuing it
//! on a queue keyed by some address. *Unparking* refers to dequeuing a thread
//! from a queue keyed by some address and resuming it. The parking lot API
//! consists of just 4 functions:
//!
//! ```rust,ignore
//! unsafe fn park(key: usize,
//!                validate: &mut FnMut() -> bool,
//!                before_sleep: &mut FnMut(),
//!                timed_out: &mut FnMut(usize, UnparkResult),
//!                timeout: Option<Instant>)
//!                -> bool
//! ```
//!
//! This function performs the following steps:
//!
//! 1. Lock the queue associated with `key`.
//! 2. Call `validate`, if it returns `false`, unlock the queue and return.
//! 3. Add the current thread to the queue.
//! 4. Unlock the queue.
//! 5. Call `before_sleep`.
//! 6. Sleep until we are unparked or `timeout` is reached.
//! 7. If the park timed out, call `timed_out`.
//! 8. Return `true` if we were unparked by another thread, `false` otherwise.
//!
//! ```rust,ignore
//! unsafe fn unpark_one(key: usize,
//!                      callback: &mut FnMut(UnparkResult))
//!                      -> UnparkResult
//! ```
//!
//! This function will unpark a single thread from the queue associated with
//! `key`. The `callback` function is invoked while holding the queue lock but
//! before the thread is unparked. The `UnparkResult` indicates whether the
//! queue was empty and, if not, whether there are still threads remaining in
//! the queue.
//!
//! ```rust,ignore
//! unsafe fn unpark_all(key: usize) -> usize
//! ```
//!
//! This function will unpark all threads in the queue associated with `key`. It
//! returns the number of threads that were unparked.
//!
//! ```rust,ignore
//! unsafe fn unpark_requeue(key_from: usize,
//!                          key_to: usize,
//!                          validate: &mut FnMut() -> RequeueOp,
//!                          callback: &mut FnMut(RequeueOp, usize))
//!                          -> usize
//! ```
//!
//! This function will remove all threads from the queue associated with
//! `key_from`, optionally unpark the first one and move the rest to the queue
//! associated with `key_to`. The `validate` function is invoked while holding
//! both queue locks and can choose whether to abort the operation and whether
//! to unpark one thread from the queue. The `callback` function is then called
//! with the result of `validate` and the number of threads that were in the
//! original queue.
//!
//! # Building custom synchronization primitives
//!
//! Building custom synchronization primitives is very simple since
//! `parking_lot` takes care of all the hard parts for you. The most commmon
//! case for a custom primitive would be to integrate a `Mutex` inside another
//! data type. Since a mutex only requires 2 bits, it can share space with other
//! data. For example, one could create an `ArcMutex` type that combines the
//! atomic reference count and the two mutex bits in the same atomic word.

#![warn(missing_docs)]
#![cfg_attr(feature = "nightly", feature(const_fn))]
#![cfg_attr(feature = "nightly", feature(integer_atomics))]
#![cfg_attr(feature = "nightly", feature(asm))]

extern crate smallvec;

#[cfg(test)]
#[macro_use]
extern crate lazy_static;

#[cfg(unix)]
extern crate libc;

#[cfg(windows)]
extern crate winapi;
#[cfg(windows)]
extern crate kernel32;

#[cfg(all(feature = "nightly", target_os = "linux"))]
#[path = "thread_parker/linux.rs"]
mod thread_parker;
#[cfg(all(unix, not(all(feature = "nightly", target_os = "linux"))))]
#[path = "thread_parker/unix.rs"]
mod thread_parker;
#[cfg(windows)]
#[path = "thread_parker/windows.rs"]
mod thread_parker;
#[cfg(not(any(windows, unix)))]
#[path = "thread_parker/generic.rs"]
mod thread_parker;

#[cfg(not(feature = "nightly"))]
mod stable;
mod spinwait;
mod word_lock;
mod parking_lot;
mod elision;
mod raw_mutex;
mod raw_rwlock;
mod condvar;
mod mutex;
mod rwlock;
mod once;

pub use once::{Once, ONCE_INIT, OnceState};
pub use parking_lot::{UnparkResult, RequeueOp, park, unpark_one, unpark_all, unpark_requeue};
pub use mutex::{Mutex, MutexGuard};
pub use condvar::{Condvar, WaitTimeoutResult};
pub use rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
<|endoftext|>


<commit_before>//! # The Rust MessagePack Library
//!
//! RMP is a pure Rust [MessagePack](http://msgpack.org) implementation.
//!
//! MessagePack is an efficient binary serialization format.
//!
//! **Warning** this library is still in rapid development and everything may change until 1.0 comes.
//!
//! ## Usage
//!
//! To use `rmp`, first add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies.rmp]
//! rmp = "0.2.0"
//! ```
//!
//! Then, add this to your crate root:
//!
//! ```rust
//! extern crate rmp as msgpack;
//! ```
//!
//! ## Features
//!
//! - **Convenient API**
//!
//!   RMP is designed to be lightweight and straightforward. There are low-level API, which gives you
//!   full control on data encoding/decoding process and makes no heap allocations. On the other hand
//!   there are high-level API, which provides you convenient interface using Rust standard library and
//!   compiler reflection, allowing to encode/decode structures using `derive` attribute.
//!
//! - **Clear error handling**
//!
//!   RMP's error system guarantees that you never receive an error enum with unreachable variant.
//!
//! - **Robust and tested**
//!
//!   This project is developed using TDD and CI, so any found bugs will be fixed without breaking
//!   existing functionality.
//!
//! ## Examples
//!
//! Let's try to encode a tuple of int and string.
//!
//! ```rust
//! extern crate rmp as msgpack;
//! extern crate rustc_serialize;
//!
//! use rustc_serialize::Encodable;
//! use msgpack::Encoder;
//!
//! fn main() {
//!     let val = (42u8, "the Answer");
//!
//!     // The encoder borrows the bytearray buffer.
//!     let mut buf = [0u8; 13];
//!
//!     val.encode(&mut Encoder::new(&mut &mut buf[..]));
//!
//!     assert_eq!([0x92, 0x2a, 0xaa, 0x74, 0x68, 0x65, 0x20, 0x41, 0x6e, 0x73, 0x77, 0x65, 0x72], buf);
//! }
//! ```
//!
//! RMP also allows to automatically serialize/deserialize custom structures using rustc_serialize
//! reflection. To enable this feature, derive RustcEncodable and RustcDecodable attributes as
//! shown in the following example:
//!
//! ```rust
//! extern crate rmp as msgpack;
//! extern crate rustc_serialize;
//!
//! use rustc_serialize::Encodable;
//! use msgpack::Encoder;
//!
//! #[derive(RustcEncodable)]
//! struct Custom {
//!     id: u32,
//!     key: String,
//! }
//!
//! fn main() {
//!     let val = Custom { id: 42u32, key: "the Answer".to_string() };
//!
//!     let mut buf = [0u8; 13];
//!
//!     val.encode(&mut Encoder::new(&mut &mut buf[..]));
//!
//!     assert_eq!([0x92, 0x2a, 0xaa, 0x74, 0x68, 0x65, 0x20, 0x41, 0x6e, 0x73, 0x77, 0x65, 0x72], buf);
//! }
//! ```
//!
//! ## Limitations and plans
//!
//! - Non-owning `ValueRef` variant, which can be created from `[u8]`, `Cursor<[u8]>` etc. and
//!   borrows data from it, which makes it absolute zero-copy.
//! - Enum serialization/deserialization.

extern crate byteorder;
extern crate rustc_serialize as serialize;

pub const MSGPACK_VERSION : u32 = 5;

pub use init::Marker;

pub use decode::serialize::{
    Decoder,
};

pub use encode::serialize::{
    Encoder,
};

mod init;
pub mod encode;
pub mod decode;

// TODO: Not ready yet.
mod value;

// Suppressed due to instability.
// #[cfg(test)]
// mod bench;
<commit_msg>[Common] Export Value struct, cause it's ready.<commit_after>//! # The Rust MessagePack Library
//!
//! RMP is a pure Rust [MessagePack](http://msgpack.org) implementation.
//!
//! MessagePack is an efficient binary serialization format.
//!
//! **Warning** this library is still in rapid development and everything may change until 1.0 comes.
//!
//! ## Usage
//!
//! To use `rmp`, first add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies.rmp]
//! rmp = "0.2.0"
//! ```
//!
//! Then, add this to your crate root:
//!
//! ```rust
//! extern crate rmp as msgpack;
//! ```
//!
//! ## Features
//!
//! - **Convenient API**
//!
//!   RMP is designed to be lightweight and straightforward. There are low-level API, which gives you
//!   full control on data encoding/decoding process and makes no heap allocations. On the other hand
//!   there are high-level API, which provides you convenient interface using Rust standard library and
//!   compiler reflection, allowing to encode/decode structures using `derive` attribute.
//!
//! - **Clear error handling**
//!
//!   RMP's error system guarantees that you never receive an error enum with unreachable variant.
//!
//! - **Robust and tested**
//!
//!   This project is developed using TDD and CI, so any found bugs will be fixed without breaking
//!   existing functionality.
//!
//! ## Examples
//!
//! Let's try to encode a tuple of int and string.
//!
//! ```rust
//! extern crate rmp as msgpack;
//! extern crate rustc_serialize;
//!
//! use rustc_serialize::Encodable;
//! use msgpack::Encoder;
//!
//! fn main() {
//!     let val = (42u8, "the Answer");
//!
//!     // The encoder borrows the bytearray buffer.
//!     let mut buf = [0u8; 13];
//!
//!     val.encode(&mut Encoder::new(&mut &mut buf[..]));
//!
//!     assert_eq!([0x92, 0x2a, 0xaa, 0x74, 0x68, 0x65, 0x20, 0x41, 0x6e, 0x73, 0x77, 0x65, 0x72], buf);
//! }
//! ```
//!
//! RMP also allows to automatically serialize/deserialize custom structures using rustc_serialize
//! reflection. To enable this feature, derive RustcEncodable and RustcDecodable attributes as
//! shown in the following example:
//!
//! ```rust
//! extern crate rmp as msgpack;
//! extern crate rustc_serialize;
//!
//! use rustc_serialize::Encodable;
//! use msgpack::Encoder;
//!
//! #[derive(RustcEncodable)]
//! struct Custom {
//!     id: u32,
//!     key: String,
//! }
//!
//! fn main() {
//!     let val = Custom { id: 42u32, key: "the Answer".to_string() };
//!
//!     let mut buf = [0u8; 13];
//!
//!     val.encode(&mut Encoder::new(&mut &mut buf[..]));
//!
//!     assert_eq!([0x92, 0x2a, 0xaa, 0x74, 0x68, 0x65, 0x20, 0x41, 0x6e, 0x73, 0x77, 0x65, 0x72], buf);
//! }
//! ```
//!
//! ## Limitations and plans
//!
//! - Non-owning `ValueRef` variant, which can be created from `[u8]`, `Cursor<[u8]>` etc. and
//!   borrows data from it, which makes it absolute zero-copy.
//! - Enum serialization/deserialization.

extern crate byteorder;
extern crate rustc_serialize as serialize;

pub const MSGPACK_VERSION : u32 = 5;

pub use init::Marker;

pub use decode::serialize::{
    Decoder,
};

pub use encode::serialize::{
    Encoder,
};

mod init;
pub mod encode;
pub mod decode;

// TODO: Not ready yet.
mod value;

pub use value::Value;

// Suppressed due to instability.
// #[cfg(test)]
// mod bench;
<|endoftext|>


<commit_before>#![cfg_attr(not(feature = "clippy"), allow(unknown_lints))]
#![allow(dead_code)]

extern crate chrono;
extern crate core;
extern crate crypto_hash;
extern crate easy_process;
extern crate hex;
extern crate parse_duration;
extern crate rand;
extern crate reqwest;
extern crate serde;
extern crate serde_ini;
extern crate walkdir;

#[macro_use]
extern crate failure;
#[macro_use]
extern crate failure_derive;

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;
#[cfg(not(test))]
extern crate serde_json;

#[cfg(test)]
extern crate mockito;
#[cfg(test)]
extern crate tempfile;
#[cfg(test)]
#[macro_use]
extern crate serde_json;

mod build_info;
mod client;
mod firmware;
mod runtime_settings;
mod serde_helpers;
mod settings;
mod states;
mod update_package;

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

pub use settings::Settings;

pub use build_info::version;
pub use states::run;
<commit_msg>lib: Add missing license header<commit_after>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

#![cfg_attr(not(feature = "clippy"), allow(unknown_lints))]
#![allow(dead_code)]

extern crate chrono;
extern crate core;
extern crate crypto_hash;
extern crate easy_process;
extern crate hex;
extern crate parse_duration;
extern crate rand;
extern crate reqwest;
extern crate serde;
extern crate serde_ini;
extern crate walkdir;

#[macro_use]
extern crate failure;
#[macro_use]
extern crate failure_derive;

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;
#[cfg(not(test))]
extern crate serde_json;

#[cfg(test)]
extern crate mockito;
#[cfg(test)]
extern crate tempfile;
#[cfg(test)]
#[macro_use]
extern crate serde_json;

mod build_info;
mod client;
mod firmware;
mod runtime_settings;
mod serde_helpers;
mod settings;
mod states;
mod update_package;

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

pub use settings::Settings;

pub use build_info::version;
pub use states::run;
<|endoftext|>


<commit_before>//! This crate provides high level SCTP networking.
//! Currently it only supports basic SCTP features like multi-homing
//! in one-to-one and one-to-many associations.
//! SCTP notifications and working directly on association is not supported yet
//! but is in the TODO list.

extern crate sctp_sys;
extern crate libc;

mod sctpsock;
use sctpsock::{SctpSocket, BindOp, RawSocketAddr};
use sctp_sys::{SOCK_SEQPACKET, SOL_SCTP};

use std::io::prelude::*;
use std::io::{Result, Error, ErrorKind};
use std::net::{ToSocketAddrs, SocketAddr, Shutdown};

#[cfg(target_os="linux")]
use std::os::unix::io::{AsRawFd, RawFd, FromRawFd};
#[cfg(target_os="windows")]
use std::os::windows::io::{AsRawHandle, RawHandle, FromRawHandle};

/// Socket direction
pub enum SoDirection {
	/// RCV direction
	Receive,
	/// SND direction
	Send
}

impl SoDirection {
	fn buffer_opt(&self) -> libc::c_int {
		return match *self {
			SoDirection::Receive => libc::SO_RCVBUF,
			SoDirection::Send => libc::SO_SNDBUF
		};
	}

	fn timeout_opt(&self) -> libc::c_int {
		return match *self {
			SoDirection::Receive => libc::SO_RCVTIMEO,
			SoDirection::Send => libc::SO_SNDTIMEO
		};
	}
}

/// One-to-one SCTP connected stream which behaves like a TCP stream.
/// A `SctpStream` can be obtained either actively by connecting to a SCTP endpoint with the
/// `connect` constructor, or passively from a `SctpListener` which accepts new connections
pub struct SctpStream(SctpSocket);

impl SctpStream {

	/// Create a new stream by connecting it to a remote endpoint
	pub fn connect<A: ToSocketAddrs>(address: A) -> Result<SctpStream> {
		let raw_addr = try!(SocketAddr::from_addr(&address));
		let sock = try!(SctpSocket::new(raw_addr.family(), libc::SOCK_STREAM));
		try!(sock.connect(raw_addr));
		return Ok(SctpStream(sock));
	}

	/// Create a new stream by connecting it to a remote endpoint having multiple addresses
	pub fn connectx<A: ToSocketAddrs>(addresses: &[A]) -> Result<SctpStream> {
		if addresses.len() == 0 { return Err(Error::new(ErrorKind::InvalidInput, "No addresses given")); }
		let mut vec = Vec::with_capacity(addresses.len());
		let mut family = libc::AF_INET;
		for address in addresses {
			let a = try!(SocketAddr::from_addr(address));
			if a.family() == libc::AF_INET6 { family = libc::AF_INET6; }
			vec.push(a);
		}

		let sock = try!(SctpSocket::new(family, libc::SOCK_STREAM));
		try!(sock.connectx(&vec));
		return Ok(SctpStream(sock));
	}

	/// Send bytes on the specified SCTP stream. On success, returns the
	/// quantity of bytes read
	pub fn sendmsg(&self, msg: &[u8], stream: u16) -> Result<usize> {
		return self.0.sendmsg::<SocketAddr>(msg, None, stream, 0);
	}

	/// Read bytes. On success, return a tulpe with the quantity of
	/// bytes received and the stream they were recived on
	pub fn recvmsg(&self, msg: &mut [u8]) -> Result<(usize, u16)> {
		let (size, stream, _) = try!(self.0.recvmsg(msg));
		return Ok((size, stream));
	}

	/// Return the list of local socket addresses for this stream
	pub fn local_addrs(&self) -> Result<Vec<SocketAddr>> {
		return self.0.local_addrs(0);
	}

	/// Return the list of socket addresses for the peer this stream is connected to
	pub fn peer_addrs(&self) -> Result<Vec<SocketAddr>> {
		return self.0.peer_addrs(0);
	}

	/// Shuts down the read, write, or both halves of this connection
	pub fn shutdown(&self, how: Shutdown) -> Result<()> {
		return self.0.shutdown(how);
	}

	/// Set or unset SCTP_NODELAY option
	pub fn set_nodelay(&self, nodelay: bool) -> Result<()> {
		let val: libc::c_int = if nodelay { 1 } else { 0 };
		return self.0.setsockopt(SOL_SCTP, sctp_sys::SCTP_NODELAY, &val);
	}

	/// Verify if SCTP_NODELAY option is activated for this socket
	pub fn has_nodelay(&self) -> Result<bool> {
		let val: libc::c_int = try!(self.0.sctp_opt_info(sctp_sys::SCTP_NODELAY, 0));
		return Ok(val == 1);
	}

	/// Set the socket buffer size for the direction specified by `dir`.
	/// Linux systems will double the provided size
	pub fn set_buffer_size(&self, dir: SoDirection, size: usize) -> Result<()> {
		return self.0.setsockopt(libc::SOL_SOCKET, dir.buffer_opt(), &(size as libc::c_int));
	}

	/// Get the socket buffer size for the direction specified by `dir`
	pub fn get_buffer_size(&self, dir: SoDirection) -> Result<(usize)> {
		let val: u32 = try!(self.0.getsockopt(libc::SOL_SOCKET, dir.buffer_opt()));
		return Ok(val as usize);
	}

	/// Set `timeout` in seconds for operation `dir` (either receive or send)
	pub fn set_timeout(&self, dir: SoDirection, timeout: i32) -> Result<()> {
		let tval = libc::timeval { tv_sec: timeout as libc::c_int, tv_usec: 0 };
		return self.0.setsockopt(libc::SOL_SOCKET, dir.timeout_opt(), &tval);
	}

	/// Try to clone the SctpStream. On success, returns a new stream
	/// wrapping a new socket handler
	pub fn try_clone(&self) -> Result<SctpStream> {
		return Ok(SctpStream(try!(self.0.try_clone())));
	}
}

impl Read for SctpStream {
	fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
		return self.0.recv(buf);
	}
}

impl Write for SctpStream {
	fn write(&mut self, buf: &[u8]) -> Result<usize> {
		return self.0.send(buf);
	}

	fn flush(&mut self) -> Result<()> {
		return Ok(());
	}
}

#[cfg(target_os="windows")]
impl AsRawHandle for SctpStream {
	fn as_raw_handle(&self) -> RawHandle {
		return return self.0.as_raw_handle();
	}
}

#[cfg(target_os="windows")]
impl FromRawHandle for SctpStream {
	unsafe fn from_raw_handle(hdl: RawHandle) -> SctpStream {
		return SctpStream(SctpSocket::from_raw_handle(hdl));
	}
}

#[cfg(target_os="linux")]
impl AsRawFd for SctpStream {
	fn as_raw_fd(&self) -> RawFd {
		return self.0.as_raw_fd();
	}
}

#[cfg(target_os="linux")]
impl FromRawFd for SctpStream {
	unsafe fn from_raw_fd(fd: RawFd) -> SctpStream {
		return SctpStream(SctpSocket::from_raw_fd(fd));
	}
}

/// One-to-many SCTP endpoint.
pub struct SctpEndpoint(SctpSocket);

impl SctpEndpoint {

	/// Create a one-to-many SCTP endpoint bound to a single address
	pub fn bind<A: ToSocketAddrs>(address: A) -> Result<SctpEndpoint> {
		let raw_addr = try!(SocketAddr::from_addr(&address));
		let sock = try!(SctpSocket::new(raw_addr.family(), libc::SOCK_STREAM));
		try!(sock.bind(raw_addr));
		return Ok(SctpEndpoint(sock));
	}

	/// Create a one-to-many SCTP endpoint bound to a multiple addresses. Requires at least one address
	pub fn bindx<A: ToSocketAddrs>(addresses: &[A]) -> Result<SctpEndpoint> {
		if addresses.len() == 0 { return Err(Error::new(ErrorKind::InvalidInput, "No addresses given")); }
		let mut vec = Vec::with_capacity(addresses.len());
		let mut family = libc::AF_INET;
		for address in addresses {
			let a = try!(SocketAddr::from_addr(address));
			if a.family() == libc::AF_INET6 { family = libc::AF_INET6; }
			vec.push(a);
		}

		let sock = try!(SctpSocket::new(family, SOCK_SEQPACKET));
		try!(sock.bindx(&vec, BindOp::AddAddr));
		try!(sock.listen(-1));
		return Ok(SctpEndpoint(sock));
	}

	/// Wait for data to be received. On success, returns a triplet containing
	/// the quantity of bytes received, the sctp stream id on which data were received, and
	/// the socket address used by the peer to send the data
	pub fn recv_from(&self, msg: &mut [u8]) -> Result<(usize, u16, SocketAddr)> {
		return self.0.recvmsg(msg);
	}

	/// Send data in Sctp style, to the provided address on the stream `stream`.
	/// On success, returns the quantity on bytes sent
	pub fn send_to<A: ToSocketAddrs>(&self, msg: &mut [u8], address: A, stream: u16) -> Result<usize> {
		return self.0.sendmsg(msg, Some(address), stream, 0);
	}

	/// Get local socket addresses on which this socket is bound
	pub fn local_addrs(&self) -> Result<Vec<SocketAddr>> {
		return self.0.local_addrs(0);
	}

	/// Try to clone this socket
	pub fn try_clone(&self) -> Result<SctpEndpoint> {
		return Ok(SctpEndpoint(try!(self.0.try_clone())));
	}
}

#[cfg(target_os="windows")]
impl AsRawHandle for SctpEndpoint {
	fn as_raw_handle(&self) -> RawHandle {
		return return self.0.as_raw_handle();
	}
}

#[cfg(target_os="windows")]
impl FromRawHandle for SctpEndpoint {
	unsafe fn from_raw_handle(hdl: RawHandle) -> SctpEndpoint {
		return SctpEndpoint(SctpSocket::from_raw_handle(hdl));
	}
}

#[cfg(target_os="linux")]
impl AsRawFd for SctpEndpoint {
	fn as_raw_fd(&self) -> RawFd {
		return self.0.as_raw_fd();
	}
}

#[cfg(target_os="linux")]
impl FromRawFd for SctpEndpoint {
	unsafe fn from_raw_fd(fd: RawFd) -> SctpEndpoint {
		return SctpEndpoint(SctpSocket::from_raw_fd(fd));
	}
}

/// Iterator over incoming connections on `SctpListener`
pub struct Incoming<'a>(&'a SctpListener);

impl <'a> std::iter::Iterator for Incoming<'a> {
	type Item = Result<SctpStream>;

	fn next(&mut self) -> Option<Result<SctpStream>> {
		return match self.0.accept() {
			Ok((stream, _)) => Some(Ok(stream)),
			Err(e) => Some(Err(e))
		};
	}
}

/// SCTP listener which behaves like a `TcpListener`.
/// A SCTP listener is used to wait for and accept one-to-one SCTP connections.
/// An accepted connection is represented by `SctpStream`.
pub struct SctpListener(SctpSocket);

impl SctpListener {

	/// Create a listener bound to a single address
	pub fn bind<A: ToSocketAddrs>(address: A) -> Result<SctpListener> {
		let raw_addr = try!(SocketAddr::from_addr(&address));
		let sock = try!(SctpSocket::new(raw_addr.family(), libc::SOCK_STREAM));
		try!(sock.bind(raw_addr));
		return Ok(SctpListener(sock));
	}

	/// Create a listener bound to multiple addresses. Requires at least one address
	pub fn bindx<A: ToSocketAddrs>(addresses: &[A]) -> Result<SctpListener> {
		if addresses.len() == 0 { return Err(Error::new(ErrorKind::InvalidInput, "No addresses given")); }
		let mut vec = Vec::with_capacity(addresses.len());
		let mut family = libc::AF_INET;
		for address in addresses {
			let a = try!(SocketAddr::from_addr(address));
			if a.family() == libc::AF_INET6 { family = libc::AF_INET6; }
			vec.push(a);
		}

		let sock = try!(SctpSocket::new(family, libc::SOCK_STREAM));
		try!(sock.bindx(&vec, BindOp::AddAddr));
		try!(sock.listen(-1));
		return Ok(SctpListener(sock));
	}

	/// Accept a new connection
	pub fn accept(&self) -> Result<(SctpStream, SocketAddr)> {
		let (sock, addr) = try!(self.0.accept());
		return Ok((SctpStream(sock), addr));
	}

	/// Iterate over new connections.
	pub fn incoming(&self) -> Incoming {
		return Incoming(self);
	}

	/// Get the listener ocal addresses
	pub fn local_addrs(&self) -> Result<Vec<SocketAddr>> {
		return self.0.local_addrs(0);
	}

	/// Try to clone this listener
	pub fn try_clone(&self) -> Result<SctpListener> {
		return Ok(SctpListener(try!(self.0.try_clone())));
	}
}

#[cfg(target_os="windows")]
impl AsRawHandle for SctpListener {
	fn as_raw_handle(&self) -> RawHandle {
		return return self.0.as_raw_handle();
	}
}

#[cfg(target_os="windows")]
impl FromRawHandle for SctpListener {
	unsafe fn from_raw_handle(hdl: RawHandle) -> SctpListener {
		return SctpListener(SctpSocket::from_raw_handle(hdl));
	}
}

#[cfg(target_os="linux")]
impl AsRawFd for SctpListener {
	fn as_raw_fd(&self) -> RawFd {
		return self.0.as_raw_fd();
	}
}

#[cfg(target_os="linux")]
impl FromRawFd for SctpListener {
	unsafe fn from_raw_fd(fd: RawFd) -> SctpListener {
		return SctpListener(SctpSocket::from_raw_fd(fd));
	}
}
<commit_msg>Fixed linux build issue<commit_after>//! This crate provides high level SCTP networking.
//! Currently it only supports basic SCTP features like multi-homing
//! in one-to-one and one-to-many associations.
//! SCTP notifications and working directly on association is not supported yet
//! but is in the TODO list.

extern crate sctp_sys;
extern crate libc;

mod sctpsock;
use sctpsock::{SctpSocket, BindOp, RawSocketAddr};
use sctp_sys::{SOCK_SEQPACKET, SOL_SCTP};

use std::io::prelude::*;
use std::io::{Result, Error, ErrorKind};
use std::net::{ToSocketAddrs, SocketAddr, Shutdown};

#[cfg(target_os="linux")]
use std::os::unix::io::{AsRawFd, RawFd, FromRawFd};
#[cfg(target_os="windows")]
use std::os::windows::io::{AsRawHandle, RawHandle, FromRawHandle};

/// Socket direction
pub enum SoDirection {
	/// RCV direction
	Receive,
	/// SND direction
	Send
}

impl SoDirection {
	fn buffer_opt(&self) -> libc::c_int {
		return match *self {
			SoDirection::Receive => libc::SO_RCVBUF,
			SoDirection::Send => libc::SO_SNDBUF
		};
	}

	fn timeout_opt(&self) -> libc::c_int {
		return match *self {
			SoDirection::Receive => libc::SO_RCVTIMEO,
			SoDirection::Send => libc::SO_SNDTIMEO
		};
	}
}

/// One-to-one SCTP connected stream which behaves like a TCP stream.
/// A `SctpStream` can be obtained either actively by connecting to a SCTP endpoint with the
/// `connect` constructor, or passively from a `SctpListener` which accepts new connections
pub struct SctpStream(SctpSocket);

impl SctpStream {

	/// Create a new stream by connecting it to a remote endpoint
	pub fn connect<A: ToSocketAddrs>(address: A) -> Result<SctpStream> {
		let raw_addr = try!(SocketAddr::from_addr(&address));
		let sock = try!(SctpSocket::new(raw_addr.family(), libc::SOCK_STREAM));
		try!(sock.connect(raw_addr));
		return Ok(SctpStream(sock));
	}

	/// Create a new stream by connecting it to a remote endpoint having multiple addresses
	pub fn connectx<A: ToSocketAddrs>(addresses: &[A]) -> Result<SctpStream> {
		if addresses.len() == 0 { return Err(Error::new(ErrorKind::InvalidInput, "No addresses given")); }
		let mut vec = Vec::with_capacity(addresses.len());
		let mut family = libc::AF_INET;
		for address in addresses {
			let a = try!(SocketAddr::from_addr(address));
			if a.family() == libc::AF_INET6 { family = libc::AF_INET6; }
			vec.push(a);
		}

		let sock = try!(SctpSocket::new(family, libc::SOCK_STREAM));
		try!(sock.connectx(&vec));
		return Ok(SctpStream(sock));
	}

	/// Send bytes on the specified SCTP stream. On success, returns the
	/// quantity of bytes read
	pub fn sendmsg(&self, msg: &[u8], stream: u16) -> Result<usize> {
		return self.0.sendmsg::<SocketAddr>(msg, None, stream, 0);
	}

	/// Read bytes. On success, return a tulpe with the quantity of
	/// bytes received and the stream they were recived on
	pub fn recvmsg(&self, msg: &mut [u8]) -> Result<(usize, u16)> {
		let (size, stream, _) = try!(self.0.recvmsg(msg));
		return Ok((size, stream));
	}

	/// Return the list of local socket addresses for this stream
	pub fn local_addrs(&self) -> Result<Vec<SocketAddr>> {
		return self.0.local_addrs(0);
	}

	/// Return the list of socket addresses for the peer this stream is connected to
	pub fn peer_addrs(&self) -> Result<Vec<SocketAddr>> {
		return self.0.peer_addrs(0);
	}

	/// Shuts down the read, write, or both halves of this connection
	pub fn shutdown(&self, how: Shutdown) -> Result<()> {
		return self.0.shutdown(how);
	}

	/// Set or unset SCTP_NODELAY option
	pub fn set_nodelay(&self, nodelay: bool) -> Result<()> {
		let val: libc::c_int = if nodelay { 1 } else { 0 };
		return self.0.setsockopt(SOL_SCTP, sctp_sys::SCTP_NODELAY, &val);
	}

	/// Verify if SCTP_NODELAY option is activated for this socket
	pub fn has_nodelay(&self) -> Result<bool> {
		let val: libc::c_int = try!(self.0.sctp_opt_info(sctp_sys::SCTP_NODELAY, 0));
		return Ok(val == 1);
	}

	/// Set the socket buffer size for the direction specified by `dir`.
	/// Linux systems will double the provided size
	pub fn set_buffer_size(&self, dir: SoDirection, size: usize) -> Result<()> {
		return self.0.setsockopt(libc::SOL_SOCKET, dir.buffer_opt(), &(size as libc::c_int));
	}

	/// Get the socket buffer size for the direction specified by `dir`
	pub fn get_buffer_size(&self, dir: SoDirection) -> Result<(usize)> {
		let val: u32 = try!(self.0.getsockopt(libc::SOL_SOCKET, dir.buffer_opt()));
		return Ok(val as usize);
	}

	/// Set `timeout` in seconds for operation `dir` (either receive or send)
	pub fn set_timeout(&self, dir: SoDirection, timeout: i32) -> Result<()> {
		// Workaround: Use onf long instead of time_t which does not compile in windows x86_64
		let tval = libc::timeval { tv_sec: timeout as libc::c_long, tv_usec: 0 };
		return self.0.setsockopt(libc::SOL_SOCKET, dir.timeout_opt(), &tval);
	}

	/// Try to clone the SctpStream. On success, returns a new stream
	/// wrapping a new socket handler
	pub fn try_clone(&self) -> Result<SctpStream> {
		return Ok(SctpStream(try!(self.0.try_clone())));
	}
}

impl Read for SctpStream {
	fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
		return self.0.recv(buf);
	}
}

impl Write for SctpStream {
	fn write(&mut self, buf: &[u8]) -> Result<usize> {
		return self.0.send(buf);
	}

	fn flush(&mut self) -> Result<()> {
		return Ok(());
	}
}

#[cfg(target_os="windows")]
impl AsRawHandle for SctpStream {
	fn as_raw_handle(&self) -> RawHandle {
		return return self.0.as_raw_handle();
	}
}

#[cfg(target_os="windows")]
impl FromRawHandle for SctpStream {
	unsafe fn from_raw_handle(hdl: RawHandle) -> SctpStream {
		return SctpStream(SctpSocket::from_raw_handle(hdl));
	}
}

#[cfg(target_os="linux")]
impl AsRawFd for SctpStream {
	fn as_raw_fd(&self) -> RawFd {
		return self.0.as_raw_fd();
	}
}

#[cfg(target_os="linux")]
impl FromRawFd for SctpStream {
	unsafe fn from_raw_fd(fd: RawFd) -> SctpStream {
		return SctpStream(SctpSocket::from_raw_fd(fd));
	}
}

/// One-to-many SCTP endpoint.
pub struct SctpEndpoint(SctpSocket);

impl SctpEndpoint {

	/// Create a one-to-many SCTP endpoint bound to a single address
	pub fn bind<A: ToSocketAddrs>(address: A) -> Result<SctpEndpoint> {
		let raw_addr = try!(SocketAddr::from_addr(&address));
		let sock = try!(SctpSocket::new(raw_addr.family(), libc::SOCK_STREAM));
		try!(sock.bind(raw_addr));
		return Ok(SctpEndpoint(sock));
	}

	/// Create a one-to-many SCTP endpoint bound to a multiple addresses. Requires at least one address
	pub fn bindx<A: ToSocketAddrs>(addresses: &[A]) -> Result<SctpEndpoint> {
		if addresses.len() == 0 { return Err(Error::new(ErrorKind::InvalidInput, "No addresses given")); }
		let mut vec = Vec::with_capacity(addresses.len());
		let mut family = libc::AF_INET;
		for address in addresses {
			let a = try!(SocketAddr::from_addr(address));
			if a.family() == libc::AF_INET6 { family = libc::AF_INET6; }
			vec.push(a);
		}

		let sock = try!(SctpSocket::new(family, SOCK_SEQPACKET));
		try!(sock.bindx(&vec, BindOp::AddAddr));
		try!(sock.listen(-1));
		return Ok(SctpEndpoint(sock));
	}

	/// Wait for data to be received. On success, returns a triplet containing
	/// the quantity of bytes received, the sctp stream id on which data were received, and
	/// the socket address used by the peer to send the data
	pub fn recv_from(&self, msg: &mut [u8]) -> Result<(usize, u16, SocketAddr)> {
		return self.0.recvmsg(msg);
	}

	/// Send data in Sctp style, to the provided address on the stream `stream`.
	/// On success, returns the quantity on bytes sent
	pub fn send_to<A: ToSocketAddrs>(&self, msg: &mut [u8], address: A, stream: u16) -> Result<usize> {
		return self.0.sendmsg(msg, Some(address), stream, 0);
	}

	/// Get local socket addresses on which this socket is bound
	pub fn local_addrs(&self) -> Result<Vec<SocketAddr>> {
		return self.0.local_addrs(0);
	}

	/// Try to clone this socket
	pub fn try_clone(&self) -> Result<SctpEndpoint> {
		return Ok(SctpEndpoint(try!(self.0.try_clone())));
	}
}

#[cfg(target_os="windows")]
impl AsRawHandle for SctpEndpoint {
	fn as_raw_handle(&self) -> RawHandle {
		return return self.0.as_raw_handle();
	}
}

#[cfg(target_os="windows")]
impl FromRawHandle for SctpEndpoint {
	unsafe fn from_raw_handle(hdl: RawHandle) -> SctpEndpoint {
		return SctpEndpoint(SctpSocket::from_raw_handle(hdl));
	}
}

#[cfg(target_os="linux")]
impl AsRawFd for SctpEndpoint {
	fn as_raw_fd(&self) -> RawFd {
		return self.0.as_raw_fd();
	}
}

#[cfg(target_os="linux")]
impl FromRawFd for SctpEndpoint {
	unsafe fn from_raw_fd(fd: RawFd) -> SctpEndpoint {
		return SctpEndpoint(SctpSocket::from_raw_fd(fd));
	}
}

/// Iterator over incoming connections on `SctpListener`
pub struct Incoming<'a>(&'a SctpListener);

impl <'a> std::iter::Iterator for Incoming<'a> {
	type Item = Result<SctpStream>;

	fn next(&mut self) -> Option<Result<SctpStream>> {
		return match self.0.accept() {
			Ok((stream, _)) => Some(Ok(stream)),
			Err(e) => Some(Err(e))
		};
	}
}

/// SCTP listener which behaves like a `TcpListener`.
/// A SCTP listener is used to wait for and accept one-to-one SCTP connections.
/// An accepted connection is represented by `SctpStream`.
pub struct SctpListener(SctpSocket);

impl SctpListener {

	/// Create a listener bound to a single address
	pub fn bind<A: ToSocketAddrs>(address: A) -> Result<SctpListener> {
		let raw_addr = try!(SocketAddr::from_addr(&address));
		let sock = try!(SctpSocket::new(raw_addr.family(), libc::SOCK_STREAM));
		try!(sock.bind(raw_addr));
		return Ok(SctpListener(sock));
	}

	/// Create a listener bound to multiple addresses. Requires at least one address
	pub fn bindx<A: ToSocketAddrs>(addresses: &[A]) -> Result<SctpListener> {
		if addresses.len() == 0 { return Err(Error::new(ErrorKind::InvalidInput, "No addresses given")); }
		let mut vec = Vec::with_capacity(addresses.len());
		let mut family = libc::AF_INET;
		for address in addresses {
			let a = try!(SocketAddr::from_addr(address));
			if a.family() == libc::AF_INET6 { family = libc::AF_INET6; }
			vec.push(a);
		}

		let sock = try!(SctpSocket::new(family, libc::SOCK_STREAM));
		try!(sock.bindx(&vec, BindOp::AddAddr));
		try!(sock.listen(-1));
		return Ok(SctpListener(sock));
	}

	/// Accept a new connection
	pub fn accept(&self) -> Result<(SctpStream, SocketAddr)> {
		let (sock, addr) = try!(self.0.accept());
		return Ok((SctpStream(sock), addr));
	}

	/// Iterate over new connections.
	pub fn incoming(&self) -> Incoming {
		return Incoming(self);
	}

	/// Get the listener ocal addresses
	pub fn local_addrs(&self) -> Result<Vec<SocketAddr>> {
		return self.0.local_addrs(0);
	}

	/// Try to clone this listener
	pub fn try_clone(&self) -> Result<SctpListener> {
		return Ok(SctpListener(try!(self.0.try_clone())));
	}
}

#[cfg(target_os="windows")]
impl AsRawHandle for SctpListener {
	fn as_raw_handle(&self) -> RawHandle {
		return return self.0.as_raw_handle();
	}
}

#[cfg(target_os="windows")]
impl FromRawHandle for SctpListener {
	unsafe fn from_raw_handle(hdl: RawHandle) -> SctpListener {
		return SctpListener(SctpSocket::from_raw_handle(hdl));
	}
}

#[cfg(target_os="linux")]
impl AsRawFd for SctpListener {
	fn as_raw_fd(&self) -> RawFd {
		return self.0.as_raw_fd();
	}
}

#[cfg(target_os="linux")]
impl FromRawFd for SctpListener {
	unsafe fn from_raw_fd(fd: RawFd) -> SctpListener {
		return SctpListener(SctpSocket::from_raw_fd(fd));
	}
}
<|endoftext|>