<commit_before>//! Welcome to the syntect docs.
//! These are still a work in progress but a lot of the important things have
//! been documented already.
//!
//! Much more info about syntect is available on the [Github Page](https://github.com/trishume/syntect).
//!
//! May I suggest that you start by reading the `Readme.md` file in the main repo.
//! Once you're done with that you can look at the docs for `parsing::SyntaxSet`
//! and for the `easy` module.
//!
//! Almost everything in syntect is divided up into either the `parsing` module
//! for turning text into text annotated with scopes, and the `highlighting` module
//! for turning annotated text into styled/coloured text.
//!
//! Some docs have example code but a good place to look is the `syncat` example as well as the source code
//! for the `easy` module in `easy.rs` as that shows how to plug the various parts together for common use cases.

#![doc(html_root_url = "https://docs.rs/syntect/2.0.1")]

#[cfg(feature = "yaml-load")]
extern crate yaml_rust;
#[cfg(feature = "parsing")]
extern crate onig;
extern crate walkdir;
#[cfg(feature = "parsing")]
extern crate regex_syntax;
#[macro_use]
extern crate lazy_static;
extern crate plist;
#[cfg(any(feature = "dump-load-rs", feature = "dump-load", feature = "dump-create"))]
extern crate bincode;
#[macro_use]
extern crate bitflags;
#[cfg(any(feature = "dump-load", feature = "dump-create", feature = "dump-load-rs", feature = "dump-create-rs"))]
extern crate flate2;
#[cfg(feature = "parsing")]
extern crate fnv;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[cfg(test)]
#[macro_use]
extern crate pretty_assertions;
pub mod highlighting;
pub mod parsing;
pub mod util;
#[cfg(any(feature = "dump-load-rs", feature = "dump-load", feature = "dump-create", feature = "dump-create-rs"))]
pub mod dumps;
#[cfg(feature = "parsing")]
pub mod easy;
#[cfg(feature = "html")]
pub mod html;
#[cfg(feature = "html")]
mod escape;

use std::io::Error as IoError;
use std::error::Error;
use std::fmt;
#[cfg(all(feature = "yaml-load", feature = "parsing"))]
use parsing::ParseSyntaxError;
use highlighting::{ParseThemeError, SettingsError};

/// Common error type used by syntax and theme loading
#[derive(Debug)]
pub enum LoadingError {
    /// error finding all the files in a directory
    WalkDir(walkdir::Error),
    /// error reading a file
    Io(IoError),
    /// a syntax file was invalid in some way
    #[cfg(feature = "yaml-load")]
    ParseSyntax(ParseSyntaxError),
    /// a theme file was invalid in some way
    ParseTheme(ParseThemeError),
    /// a theme's Plist syntax was invalid in some way
    ReadSettings(SettingsError),
    /// A path given to a method was invalid.
    /// Possibly because it didn't reference a file or wasn't UTF-8.
    BadPath,
}

impl From<SettingsError> for LoadingError {
    fn from(error: SettingsError) -> LoadingError {
        LoadingError::ReadSettings(error)
    }
}

impl From<IoError> for LoadingError {
    fn from(error: IoError) -> LoadingError {
        LoadingError::Io(error)
    }
}

impl From<ParseThemeError> for LoadingError {
    fn from(error: ParseThemeError) -> LoadingError {
        LoadingError::ParseTheme(error)
    }
}

#[cfg(all(feature = "yaml-load", feature = "parsing"))]
impl From<ParseSyntaxError> for LoadingError {
    fn from(error: ParseSyntaxError) -> LoadingError {
        LoadingError::ParseSyntax(error)
    }
}

impl fmt::Display for LoadingError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use LoadingError::*;

        match *self {
            WalkDir(ref error) => error.fmt(f),
            Io(ref error) => error.fmt(f),
            #[cfg(feature = "yaml-load")]
            ParseSyntax(_) => write!(f, "Invalid syntax file"),
            ParseTheme(_) => write!(f, "Invalid syntax theme"),
            ReadSettings(_) => write!(f, "Invalid syntax theme settings"),
            BadPath => write!(f, "Invalid path"),
        }
    }
}

impl Error for LoadingError {
    fn description(&self) -> &str {
        use LoadingError::*;

        match *self {
            WalkDir(ref error) => error.description(),
            Io(ref error) => error.description(),
            #[cfg(feature = "yaml-load")]
            ParseSyntax(_) => "Invalid syntax file",
            ParseTheme(_) => "Invalid syntax theme",
            ReadSettings(_) => "Invalid syntax theme settings",
            BadPath => "Invalid path",
        }
    }

    fn cause(&self) -> Option<&Error> {
        use LoadingError::*;

        match *self {
            WalkDir(ref error) => Some(error),
            Io(ref error) => Some(error),
            _ => None,
        }
    }
}
<commit_msg>Implement fmt via description<commit_after>//! Welcome to the syntect docs.
//! These are still a work in progress but a lot of the important things have
//! been documented already.
//!
//! Much more info about syntect is available on the [Github Page](https://github.com/trishume/syntect).
//!
//! May I suggest that you start by reading the `Readme.md` file in the main repo.
//! Once you're done with that you can look at the docs for `parsing::SyntaxSet`
//! and for the `easy` module.
//!
//! Almost everything in syntect is divided up into either the `parsing` module
//! for turning text into text annotated with scopes, and the `highlighting` module
//! for turning annotated text into styled/coloured text.
//!
//! Some docs have example code but a good place to look is the `syncat` example as well as the source code
//! for the `easy` module in `easy.rs` as that shows how to plug the various parts together for common use cases.

#![doc(html_root_url = "https://docs.rs/syntect/2.0.1")]

#[cfg(feature = "yaml-load")]
extern crate yaml_rust;
#[cfg(feature = "parsing")]
extern crate onig;
extern crate walkdir;
#[cfg(feature = "parsing")]
extern crate regex_syntax;
#[macro_use]
extern crate lazy_static;
extern crate plist;
#[cfg(any(feature = "dump-load-rs", feature = "dump-load", feature = "dump-create"))]
extern crate bincode;
#[macro_use]
extern crate bitflags;
#[cfg(any(feature = "dump-load", feature = "dump-create", feature = "dump-load-rs", feature = "dump-create-rs"))]
extern crate flate2;
#[cfg(feature = "parsing")]
extern crate fnv;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[cfg(test)]
#[macro_use]
extern crate pretty_assertions;
pub mod highlighting;
pub mod parsing;
pub mod util;
#[cfg(any(feature = "dump-load-rs", feature = "dump-load", feature = "dump-create", feature = "dump-create-rs"))]
pub mod dumps;
#[cfg(feature = "parsing")]
pub mod easy;
#[cfg(feature = "html")]
pub mod html;
#[cfg(feature = "html")]
mod escape;

use std::io::Error as IoError;
use std::error::Error;
use std::fmt;
#[cfg(all(feature = "yaml-load", feature = "parsing"))]
use parsing::ParseSyntaxError;
use highlighting::{ParseThemeError, SettingsError};

/// Common error type used by syntax and theme loading
#[derive(Debug)]
pub enum LoadingError {
    /// error finding all the files in a directory
    WalkDir(walkdir::Error),
    /// error reading a file
    Io(IoError),
    /// a syntax file was invalid in some way
    #[cfg(feature = "yaml-load")]
    ParseSyntax(ParseSyntaxError),
    /// a theme file was invalid in some way
    ParseTheme(ParseThemeError),
    /// a theme's Plist syntax was invalid in some way
    ReadSettings(SettingsError),
    /// A path given to a method was invalid.
    /// Possibly because it didn't reference a file or wasn't UTF-8.
    BadPath,
}

impl From<SettingsError> for LoadingError {
    fn from(error: SettingsError) -> LoadingError {
        LoadingError::ReadSettings(error)
    }
}

impl From<IoError> for LoadingError {
    fn from(error: IoError) -> LoadingError {
        LoadingError::Io(error)
    }
}

impl From<ParseThemeError> for LoadingError {
    fn from(error: ParseThemeError) -> LoadingError {
        LoadingError::ParseTheme(error)
    }
}

#[cfg(all(feature = "yaml-load", feature = "parsing"))]
impl From<ParseSyntaxError> for LoadingError {
    fn from(error: ParseSyntaxError) -> LoadingError {
        LoadingError::ParseSyntax(error)
    }
}

impl fmt::Display for LoadingError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use LoadingError::*;

        match *self {
            WalkDir(ref error) => error.fmt(f),
            Io(ref error) => error.fmt(f),
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl Error for LoadingError {
    fn description(&self) -> &str {
        use LoadingError::*;

        match *self {
            WalkDir(ref error) => error.description(),
            Io(ref error) => error.description(),
            #[cfg(feature = "yaml-load")]
            ParseSyntax(_) => "Invalid syntax file",
            ParseTheme(_) => "Invalid syntax theme",
            ReadSettings(_) => "Invalid syntax theme settings",
            BadPath => "Invalid path",
        }
    }

    fn cause(&self) -> Option<&Error> {
        use LoadingError::*;

        match *self {
            WalkDir(ref error) => Some(error),
            Io(ref error) => Some(error),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

#[macro_use]
extern crate log;

#[macro_use]
mod macros;

#[cfg(test)]
mod tests;

use std::fmt;

macro_rules! impl_fmt_trait_for_action {
    ( $tr:ty, $frmtr:path ) => {
        impl<'a, UsrEvt: fmt::Debug> $tr for Action<'a, UsrEvt> {
            fn fmt(&self, f:&mut fmt::Formatter) -> Result<(), fmt::Error> {
                match *self {
                    Action::Ignore        => try!($frmtr("Ignore", f)),
                    Action::Transition(x) => try!($frmtr(&format!("Transition({:?})", x), f)),
                };
                Ok(())
            }
        }
    }
}
enum Action<'a, UsrEvt: fmt::Debug> {
    Ignore,
    Transition(&'a State<'a, UsrEvt>)
}
impl_fmt_trait_for_action!(fmt::Display, fmt::Display::fmt);
impl_fmt_trait_for_action!(fmt::Debug,   fmt::Debug::fmt);

#[derive(Debug)]
enum Event<UsrEvt> {
    Enter,
    User(UsrEvt),
    Exit
}

trait Name {
    fn name(&self) -> &'static str;
}

trait Initializer {
    fn new() -> Self;
}

trait State<'a, UsrEvt> where Self: Name {
    fn handle_event(&'a mut self, evt: Event<UsrEvt>) -> Action<'a, UsrEvt>;
}
impl<'a, UsrEvt> fmt::Debug for &'a State<'a, UsrEvt> {
    fn fmt(&self, f:&mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(fmt::Debug::fmt(self.name(), f));
        Ok(())
    }
}

trait StateLookup<UsrStEnum, UsrEvt> {
    fn lookup(&mut self, typ: &UsrStEnum) -> &mut State<UsrEvt>;
}

struct StateMachine<UsrStStr, UsrStEnum, UsrEvt> {
    current  : UsrStEnum,
    states   : UsrStStr,
    _phantom : ::std::marker::PhantomData<UsrEvt>
}
impl<UsrStStr, UsrStEnum, UsrEvt> StateMachine<UsrStStr, UsrStEnum, UsrEvt>
    where UsrStStr  : Initializer + StateLookup<UsrStEnum, UsrEvt>,
          UsrStEnum : fmt::Debug,
          UsrEvt    : fmt::Debug {

    fn new(initial: UsrStEnum) -> Self {
        StateMachine {
            current  : initial,
            states   : UsrStStr::new(),
            _phantom : ::std::marker::PhantomData
        }
    }

    fn input(&mut self, evt: Event<UsrEvt>) {
        info!("input:  {:?}", evt);
        info!("state:  {:?}", self.current);
        let cur_st = self.states.lookup(&self.current);
        let action = cur_st.handle_event(evt);
        info!("action: {:?}", action)

    }
}
<commit_msg>derive Debug for Action, small reorganize<commit_after>#![allow(dead_code)]

#[macro_use]
extern crate log;
#[macro_use]
mod macros;
#[cfg(test)]
mod tests;
use std::fmt;

trait Name {
    fn name(&self) -> &'static str;
}

trait Initializer {
    fn new() -> Self;
}

#[derive(Debug)]
enum Action<'a, UsrEvt: fmt::Debug> {
    Ignore,
    Transition(&'a State<'a, UsrEvt>)
}
impl<'a, UsrEvt: fmt::Debug> fmt::Display for Action<'a, UsrEvt> {
    fn fmt(&self, f:&mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Action::Ignore        => try!(fmt::Display::fmt("Ignore", f)),
            Action::Transition(x) => try!(fmt::Display::fmt(&format!("Transition({:?})", x), f)),
        };
        Ok(())
    }
}

#[derive(Debug)]
enum Event<UsrEvt> {
    Enter,
    User(UsrEvt),
    Exit
}

trait State<'a, UsrEvt> where Self: Name {
    fn handle_event(&'a mut self, evt: Event<UsrEvt>) -> Action<'a, UsrEvt>;
}
impl<'a, UsrEvt> fmt::Debug for &'a State<'a, UsrEvt> {
    fn fmt(&self, f:&mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(fmt::Debug::fmt(self.name(), f));
        Ok(())
    }
}

trait StateLookup<UsrStEnum, UsrEvt> {
    fn lookup(&mut self, typ: &UsrStEnum) -> &mut State<UsrEvt>;
}

struct StateMachine<UsrStStr, UsrStEnum, UsrEvt> {
    current  : UsrStEnum,
    states   : UsrStStr,
    _phantom : ::std::marker::PhantomData<UsrEvt>
}
impl<UsrStStr, UsrStEnum, UsrEvt> StateMachine<UsrStStr, UsrStEnum, UsrEvt>
    where UsrStStr  : Initializer + StateLookup<UsrStEnum, UsrEvt>,
          UsrStEnum : fmt::Debug,
          UsrEvt    : fmt::Debug {

    fn new(initial: UsrStEnum) -> Self {
        StateMachine {
            current  : initial,
            states   : UsrStStr::new(),
            _phantom : ::std::marker::PhantomData
        }
    }

    fn input(&mut self, evt: Event<UsrEvt>) {
        info!("input:  {:?}", evt);
        info!("state:  {:?}", self.current);
        let cur_st = self.states.lookup(&self.current);
        let action = cur_st.handle_event(evt);
        info!("action: {:?}", action)

    }
}
<|endoftext|>


<commit_before>//! RethinkDB protocol implementation in Rust

include!(concat!(env!("OUT_DIR"), "/ql2.rs"));
<commit_msg>make crate no_std<commit_after>//! RethinkDB protocol implementation in Rust

#![no_std]

include!(concat!(env!("OUT_DIR"), "/ql2.rs"));
<|endoftext|>


<commit_before>// (c) 2015 Joost Yervante Damad <joost@damad.be>

use std::fmt;
use std::fs::File;
use std::io::Read;

extern crate rustysexp;
use rustysexp::Sexp;
use rustysexp::Atom;

type ERes<T> = Result<T, &'static str>;

fn err<T>(msg: &'static str) -> ERes<T> { Err(msg) }

pub enum Element {
    Layer,
    Descr,
    FpText,
    Pad,
    FpPoly,
    FpLine,
    FpCircle
}

pub struct Module {
    name: String,
    elements: Vec<Element>
}

impl Module {
    fn new(name: &String) -> Module {
        Module { name: name.clone(), elements: vec![] }
    }
}

impl fmt::Display for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "Module({})", self.name)
    }
}

fn parse_module_list(v: Vec<Sexp>) -> ERes<Module> {
    match v[0] {
        Sexp::Atom(Atom::S(ref s)) if s == "module" => {
            match v[1] {
                Sexp::Atom(Atom::S(ref s)) => {
                    Ok(Module::new(s))
                }
                _ => err("expecting module name")
            }
        }
        _ => err("expecting module")
    }
}

fn parse_module(s: Sexp) -> ERes<Module> {
    match s {
        Sexp::List(v) => parse_module_list(v),
        _ => err("expecting top level list")
    }
}

fn parse(s: &str) -> ERes<Module> {
    let s = rustysexp::parse_str(s);
    parse_module(s)
}

fn read_file(name: &str) -> Result<String,std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_str(s: &str) -> Module {
    parse(s).unwrap()
}

pub fn parse_file(name: &str) -> Module {
    let s = read_file(name).unwrap();
    parse(&s[..]).unwrap()
}

<commit_msg>be compatible with newer sexp lib<commit_after>// (c) 2015 Joost Yervante Damad <joost@damad.be>

use std::fmt;
use std::fs::File;
use std::io::Read;

extern crate rustysexp;
use rustysexp::Sexp;
use rustysexp::Atom;

type ERes<T> = Result<T, &'static str>;

fn err<T>(msg: &'static str) -> ERes<T> { Err(msg) }

pub enum Element {
    Layer,
    Descr,
    FpText,
    Pad,
    FpPoly,
    FpLine,
    FpCircle
}

pub struct Module {
    name: String,
    elements: Vec<Element>
}

impl Module {
    fn new(name: &String) -> Module {
        Module { name: name.clone(), elements: vec![] }
    }
}

impl fmt::Display for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "Module({})", self.name)
    }
}

fn parse_module_list(v: Vec<Sexp>) -> ERes<Module> {
    match v[0] {
        Sexp::Atom(Atom::S(ref s)) if s == "module" => {
            match v[1] {
                Sexp::Atom(Atom::S(ref s)) => {
                    Ok(Module::new(s))
                }
                _ => err("expecting module name")
            }
        }
        _ => err("expecting module")
    }
}

fn parse_module(s: Sexp) -> ERes<Module> {
    match s {
        Sexp::List(v) => parse_module_list(v),
        _ => err("expecting top level list")
    }
}

fn parse(s: &str) -> ERes<Module> {
    match rustysexp::parse_str(s) {
        Ok(s) => parse_module(s),
        Err(x) => err("IOError") // TODO...
    }
}

fn read_file(name: &str) -> Result<String,std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_str(s: &str) -> Module {
    parse(s).unwrap()
}

pub fn parse_file(name: &str) -> Module {
    let s = read_file(name).unwrap();
    parse(&s[..]).unwrap()
}

<|endoftext|>


<commit_before>use std::sync::{Arc, Barrier};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::{Duration, Instant};

/// Microbenchmark some simple operation by running it N times
///
/// This simple benchmark harness is meant as a cheap and hackish substitute for
/// cargo benchmarks in Stable Rust. It runs a user-provided operation a certain
/// number of times and measures how much time it takes.
///
/// To use it, write your benchmark as an ignored cargo test, put a call to
/// benchmark() or counting_benchmark() as the last operation, and tell your
/// user to run the benchmarks via:
///
///   $ cargo test --release -- --ignored --nocapture --test-threads=1
///
/// This is a dreadful hack. But for now, it's the best that I've thought of.
///
pub fn benchmark<F: FnMut()>(num_iterations: u32, mut iteration: F) {
    // Run the user-provided operation in a loop
    let start_time = Instant::now();
    for _ in 0..num_iterations {
        iteration()
    }
    let total_duration = start_time.elapsed();

    // Reproducible benchmarks (<10% variance) usually take between a couple of
    // seconds and a couple of minutes, so miliseconds are the right timing unit
    // for the duration of the whole benchmark.
    let total_ms = (total_duration.as_secs() as u32) * 1000 +
                   total_duration.subsec_nanos() / 1_000_000;

    // This tool is designed for microbenchmarking, so iterations are assumed
    // to last from one CPU cycle (a fraction of a nanosecond) to a fraction of
    // a second. Longer durations will require multi-resolution formatting.
    let hundred_iter_duration = total_duration * 100 / num_iterations;
    let iter_duration = hundred_iter_duration / 100;
    assert_eq!(iter_duration.as_secs(), 0);
    let iter_ns = iter_duration.subsec_nanos();
    let iter_ns_fraction = hundred_iter_duration.subsec_nanos() % 100;

    // Display the benchmark results, in a fashion that will fit in the output
    // of cargo test in nocapture mode.
    print!("{} ms ({} iters, ~{}.{} ns/iter): ",
           total_ms,
           num_iterations,
           iter_ns,
           iter_ns_fraction);
}

/// Microbenchmark some operation while another is running in a loop
///
/// For multithreaded code, benchmarking the performance of isolated operations
/// is usually only half of the story. Synchronization and memory contention can
/// also have a large impact on performance.
///
/// For this reason, it is often useful to also measure the performance of one
/// operation as another "antagonist" operation is also running in a background
/// thread. This function implements such concurrent benchmarking.
///
pub fn concurrent_benchmark<F, A>(num_iterations: u32,
                                  iteration_func: F,
                                  mut antagonist_func: A)
    where F: FnMut(),
          A: FnMut() + Send + 'static
{
    // Setup a barrier to synchronize benchmark and antagonist startup
    let barrier = Arc::new(Barrier::new(2));

    // Setup an atomic "continue" flag to shut down the antagonist at
    // the end of the benchmarking procedure
    let run_flag = Arc::new(AtomicBool::new(true));

    // Schedule the antagonist thread
    let (a_barrier, a_run_flag) = (barrier.clone(), run_flag.clone());
    let antagonist = thread::spawn(
        move || {
            a_barrier.wait();
            while a_run_flag.load(Ordering::Relaxed) {
                antagonist_func();
            }
        }
    );

    // Wait for the antagonist to be running, and give it some headstart
    barrier.wait();
    thread::sleep(Duration::from_millis(10));

    // Run the benchmark
    benchmark(num_iterations, iteration_func);

    // Stop the antagonist and check that nothing went wrong on its side
    run_flag.store(false, Ordering::Relaxed);
    antagonist.join().unwrap();
}

/// TODO: Just an usage example, should probably be improved
#[cfg(test)]
mod benchs {
    use std::time::Instant;

    #[test]
    #[ignore]
    fn it_works() {
        let initial = Instant::now();
        ::benchmark(50000000, || { assert!( Instant::now() > initial ) });
    }
}
<commit_msg>Added support for concurrent tests<commit_after>// TODO: Faire doc module + #![deny(missing_docs)]

use std::sync::{Arc, Barrier};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::{Duration, Instant};

/// Test that running two operations concurrently works
///
/// When testing multi-threaded constructs, such as synchronization primitives,
/// checking that the code works when run sequentially is insufficient.
/// Concurrent interactions must also be tested, by running some operations
/// in parallel across multiple threads.
///
/// Ideally, this function would take as input a variable-size set of functors
/// to be run in parallel. Since Rust does not support variadic generics yet,
/// however, multiple versions of this function must be provided, each
/// associated with a different functor tuple size.
///
pub fn concurrent_test_2<F, G>(f1: F, f2: G)
    where F: FnOnce() + Send + 'static,
          G: FnOnce() + Send + 'static
{
    // Setup a barrier to synchronize thread startup
    let barrier1 = Arc::new(Barrier::new(2));
    let barrier2 = barrier1.clone();

    // Start the first task
    let thread1 = thread::spawn(move || {
        barrier1.wait();
        f1();
    });

    // Run the second task
    barrier2.wait();
    f2();

    // Make sure that the first task completed properly
    thread1.join().unwrap();
}

/// Test that running three operations concurrently works
///
/// This is a variant of concurrent_test_2 that works with three functors
/// instead of two. It is hoped that future evolutions of Rust will render this
/// code duplication obsolete, in favor of some variadic generic design.
///
pub fn concurrent_test_3<F, G, H>(f1: F, f2: G, f3: H)
    where F: FnOnce() + Send + 'static,
          G: FnOnce() + Send + 'static,
          H: FnOnce() + Send + 'static
{
    // Setup a barrier to synchronize thread startup
    let barrier1 = Arc::new(Barrier::new(3));
    let barrier2 = barrier1.clone();
    let barrier3 = barrier1.clone();

    // Start the first task
    let thread1 = thread::spawn(move || {
        barrier1.wait();
        f1();
    });

    // Start the second task
    let thread2 = thread::spawn(move || {
        barrier2.wait();
        f2();
    });

    // Run the third task
    barrier3.wait();
    f3();

    // Make sure that the first two tasks completed properly
    thread1.join().unwrap();
    thread2.join().unwrap();
}

/// Microbenchmark some simple operation by running it N times
///
/// This simple benchmark harness is meant as a cheap and hackish substitute for
/// cargo benchmarks in Stable Rust. It runs a user-provided operation a certain
/// number of times and measures how much time it takes.
///
/// To use it, write your benchmark as an ignored cargo test, put a call to
/// benchmark() or counting_benchmark() as the last operation, and tell your
/// user to run the benchmarks via:
///
///   $ cargo test --release -- --ignored --nocapture --test-threads=1
///
/// This is a dreadful hack. But for now, it's the best that I've thought of.
///
pub fn benchmark<F: FnMut()>(num_iterations: u32, mut iteration: F) {
    // Run the user-provided operation in a loop
    let start_time = Instant::now();
    for _ in 0..num_iterations {
        iteration()
    }
    let total_duration = start_time.elapsed();

    // Reproducible benchmarks (<10% variance) usually take between a couple of
    // seconds and a couple of minutes, so miliseconds are the right timing unit
    // for the duration of the whole benchmark.
    let total_ms = (total_duration.as_secs() as u32) * 1000 +
                   total_duration.subsec_nanos() / 1_000_000;

    // This tool is designed for microbenchmarking, so iterations are assumed
    // to last from one CPU cycle (a fraction of a nanosecond) to a fraction of
    // a second. Longer durations will require multi-resolution formatting.
    let hundred_iter_duration = total_duration * 100 / num_iterations;
    let iter_duration = hundred_iter_duration / 100;
    assert_eq!(iter_duration.as_secs(), 0);
    let iter_ns = iter_duration.subsec_nanos();
    let iter_ns_fraction = hundred_iter_duration.subsec_nanos() % 100;

    // Display the benchmark results, in a fashion that will fit in the output
    // of cargo test in nocapture mode.
    print!("{} ms ({} iters, ~{}.{} ns/iter): ",
           total_ms,
           num_iterations,
           iter_ns,
           iter_ns_fraction);
}

/// Microbenchmark some operation while another is running in a loop
///
/// For multithreaded code, benchmarking the performance of isolated operations
/// is usually only half of the story. Synchronization and memory contention can
/// also have a large impact on performance.
///
/// For this reason, it is often useful to also measure the performance of one
/// operation as another "antagonist" operation is also running in a background
/// thread. This function implements such concurrent benchmarking.
///
pub fn concurrent_benchmark<F, A>(num_iterations: u32,
                                  iteration_func: F,
                                  mut antagonist_func: A)
    where F: FnMut(),
          A: FnMut() + Send + 'static
{
    // Setup a barrier to synchronize benchmark and antagonist startup
    let barrier = Arc::new(Barrier::new(2));

    // Setup an atomic "continue" flag to shut down the antagonist at
    // the end of the benchmarking procedure
    let run_flag = Arc::new(AtomicBool::new(true));

    // Schedule the antagonist thread
    let (a_barrier, a_run_flag) = (barrier.clone(), run_flag.clone());
    let antagonist = thread::spawn(
        move || {
            a_barrier.wait();
            while a_run_flag.load(Ordering::Relaxed) {
                antagonist_func();
            }
        }
    );

    // Wait for the antagonist to be running, and give it some headstart
    barrier.wait();
    thread::sleep(Duration::from_millis(10));

    // Run the benchmark
    benchmark(num_iterations, iteration_func);

    // Stop the antagonist and check that nothing went wrong on its side
    run_flag.store(false, Ordering::Relaxed);
    antagonist.join().unwrap();
}

/// TODO: Just an usage example, should probably be improved
#[cfg(test)]
mod benchs {
    use std::time::Instant;

    #[test]
    #[ignore]
    fn it_works() {
        let initial = Instant::now();
        ::benchmark(50000000, || { assert!( Instant::now() > initial ) });
    }
}
<|endoftext|>


<commit_before>//! Crate ruma_events contains serializable types for the events in the [Matrix](https://matrix.org)
//! specification that can be shared by client and server code.

#![feature(proc_macro)]
#![deny(missing_docs)]

extern crate ruma_identifiers;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

use std::fmt::{Debug, Display, Formatter, Error as FmtError};

use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{Deserialize, Deserializer, Error as SerdeError, Serialize, Serializer};
use serde::de::Visitor;
use serde_json::Value;

#[macro_use] mod macros;

pub mod call;
pub mod presence;
pub mod receipt;
pub mod room;
pub mod stripped;
pub mod tag;
pub mod typing;

/// An error when attempting to convert a string to an enum that only accepts certain values.
#[derive(Clone, Copy, Debug)]
pub struct ParseError;

/// The type of an event.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum EventType {
    /// m.call.answer
    CallAnswer,
    /// m.call.candidates
    CallCandidates,
    /// m.call.hangup
    CallHangup,
    /// m.call.invite
    CallInvite,
    /// m.presence
    Presence,
    /// m.receipt
    Receipt,
    /// m.room.aliases
    RoomAliases,
    /// m.room.avatar
    RoomAvatar,
    /// m.room.canonical_alias
    RoomCanonicalAlias,
    /// m.room.create
    RoomCreate,
    /// m.room.guest_access
    RoomGuestAccess,
    /// m.room.history_visibility
    RoomHistoryVisibility,
    /// m.room.join_rules
    RoomJoinRules,
    /// m.room.member
    RoomMember,
    /// m.room.message
    RoomMessage,
    /// m.room.name
    RoomName,
    /// m.room.power_levels
    RoomPowerLevels,
    /// m.room.redaction
    RoomRedaction,
    /// m.room.third_party_invite
    RoomThirdPartyInvite,
    /// m.room.topic
    RoomTopic,
    /// m.tag
    Tag,
    /// m.typing
    Typing,
    /// Any event that is not part of the specification.
    Custom(String),
}

/// A basic event.
pub trait Event: Debug + Deserialize + Serialize {
    /// The event-type-specific payload this event carries.
    type Content: Debug + Deserialize + Serialize;

    /// The event's content.
    fn content(&self) -> &Self::Content;

    /// The type of the event.
    fn event_type(&self) -> &EventType;
}

/// An event within the context of a room.
pub trait RoomEvent: Event {
    /// The unique identifier for the event.
    fn event_id(&self) -> &EventId;

    /// The unique identifier for the room associated with this event.
    fn room_id(&self) -> &RoomId;

    /// Additional key-value pairs not signed by the homeserver.
    fn unsigned(&self) -> Option<&Value>;

    /// The unique identifier for the user associated with this event.
    fn user_id(&self) -> &UserId;
}

/// An event that describes persistent state about a room.
pub trait StateEvent: RoomEvent {
    /// The previous content for this state key, if any.
    fn prev_content(&self) -> Option<&Self::Content>;

    /// A key that determines which piece of room state the event represents.
    fn state_key(&self) -> &str;
}

event! {
    /// A custom basic event not covered by the Matrix specification.
    pub struct CustomEvent(Value) {}
}

room_event! {
    /// A custom room event not covered by the Matrix specification.
    pub struct CustomRoomEvent(Value) {}
}

state_event! {
    /// A custom state event not covered by the Matrix specification.
    pub struct CustomStateEvent(Value) {}
}

impl Display for EventType {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        let event_type_str = match *self {
            EventType::CallAnswer => "m.call.answer",
            EventType::CallCandidates => "m.call.candidates",
            EventType::CallHangup => "m.call.hangup",
            EventType::CallInvite => "m.call.invite",
            EventType::Presence => "m.presence",
            EventType::Receipt => "m.receipt",
            EventType::RoomAliases => "m.room.aliases",
            EventType::RoomAvatar => "m.room.avatar",
            EventType::RoomCanonicalAlias => "m.room.canonical_alias",
            EventType::RoomCreate => "m.room.create",
            EventType::RoomGuestAccess => "m.room.guest_access",
            EventType::RoomHistoryVisibility => "m.room.history_visibility",
            EventType::RoomJoinRules => "m.room.join_rules",
            EventType::RoomMember => "m.room.member",
            EventType::RoomMessage => "m.room.message",
            EventType::RoomName => "m.room.name",
            EventType::RoomPowerLevels => "m.room.power_levels",
            EventType::RoomRedaction => "m.room.redaction",
            EventType::RoomThirdPartyInvite => "m.room.third_party_invite",
            EventType::RoomTopic => "m.room.topic",
            EventType::Tag => "m.tag",
            EventType::Typing => "m.typing",
            EventType::Custom(ref event_type) => event_type,
        };

        write!(f, "{}", event_type_str)
    }
}

impl<'a> From<&'a str> for EventType {
    fn from(s: &'a str) -> EventType {
        match s {
            "m.call.answer" => EventType::CallAnswer,
            "m.call.candidates" => EventType::CallCandidates,
            "m.call.hangup" => EventType::CallHangup,
            "m.call.invite" => EventType::CallInvite,
            "m.presence" => EventType::Presence,
            "m.receipt" => EventType::Receipt,
            "m.room.aliases" => EventType::RoomAliases,
            "m.room.avatar" => EventType::RoomAvatar,
            "m.room.canonical_alias" => EventType::RoomCanonicalAlias,
            "m.room.create" => EventType::RoomCreate,
            "m.room.guest_access" => EventType::RoomGuestAccess,
            "m.room.history_visibility" => EventType::RoomHistoryVisibility,
            "m.room.join_rules" => EventType::RoomJoinRules,
            "m.room.member" => EventType::RoomMember,
            "m.room.message" => EventType::RoomMessage,
            "m.room.name" => EventType::RoomName,
            "m.room.power_levels" => EventType::RoomPowerLevels,
            "m.room.redaction" => EventType::RoomRedaction,
            "m.room.third_party_invite" => EventType::RoomThirdPartyInvite,
            "m.room.topic" => EventType::RoomTopic,
            "m.tag" => EventType::Tag,
            "m.typing" => EventType::Typing,
            event_type => EventType::Custom(event_type.to_string()),
        }
    }
}

impl Serialize for EventType {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        serializer.serialize_str(&self.to_string())
    }
}

impl Deserialize for EventType {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: Deserializer {
        struct EventTypeVisitor;

        impl Visitor for EventTypeVisitor {
            type Value = EventType;

            fn visit_str<E>(&mut self, v: &str) -> Result<Self::Value, E> where E: SerdeError {
                Ok(EventType::from(v))
            }
        }

        deserializer.deserialize_str(EventTypeVisitor)
    }
}

#[cfg(test)]
mod tests {
    use serde_json::{from_str, to_string};

    use super::EventType;

    #[test]
    fn event_types_serialize_to_display_form() {
        assert_eq!(
            to_string(&EventType::RoomCreate).unwrap(),
            r#""m.room.create""#
        );
    }

    #[test]
    fn custom_event_types_serialize_to_display_form() {
        assert_eq!(
            to_string(&EventType::Custom("io.ruma.test".to_string())).unwrap(),
            r#""io.ruma.test""#
        );
    }

    #[test]
    fn event_types_deserialize_from_display_form() {
        assert_eq!(
            from_str::<EventType>(r#""m.room.create""#).unwrap(),
            EventType::RoomCreate
        );
    }

    #[test]
    fn custom_event_types_deserialize_from_display_form() {
        assert_eq!(
            from_str::<EventType>(r#""io.ruma.test""#).unwrap(),
            EventType::Custom("io.ruma.test".to_string())
        )
    }
}
<commit_msg>Add extra_content method for events.<commit_after>//! Crate ruma_events contains serializable types for the events in the [Matrix](https://matrix.org)
//! specification that can be shared by client and server code.

#![feature(proc_macro)]
#![deny(missing_docs)]

extern crate ruma_identifiers;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

use std::fmt::{Debug, Display, Formatter, Error as FmtError};

use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{Deserialize, Deserializer, Error as SerdeError, Serialize, Serializer};
use serde::de::Visitor;
use serde_json::Value;

#[macro_use] mod macros;

pub mod call;
pub mod presence;
pub mod receipt;
pub mod room;
pub mod stripped;
pub mod tag;
pub mod typing;

/// An error when attempting to convert a string to an enum that only accepts certain values.
#[derive(Clone, Copy, Debug)]
pub struct ParseError;

/// The type of an event.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum EventType {
    /// m.call.answer
    CallAnswer,
    /// m.call.candidates
    CallCandidates,
    /// m.call.hangup
    CallHangup,
    /// m.call.invite
    CallInvite,
    /// m.presence
    Presence,
    /// m.receipt
    Receipt,
    /// m.room.aliases
    RoomAliases,
    /// m.room.avatar
    RoomAvatar,
    /// m.room.canonical_alias
    RoomCanonicalAlias,
    /// m.room.create
    RoomCreate,
    /// m.room.guest_access
    RoomGuestAccess,
    /// m.room.history_visibility
    RoomHistoryVisibility,
    /// m.room.join_rules
    RoomJoinRules,
    /// m.room.member
    RoomMember,
    /// m.room.message
    RoomMessage,
    /// m.room.name
    RoomName,
    /// m.room.power_levels
    RoomPowerLevels,
    /// m.room.redaction
    RoomRedaction,
    /// m.room.third_party_invite
    RoomThirdPartyInvite,
    /// m.room.topic
    RoomTopic,
    /// m.tag
    Tag,
    /// m.typing
    Typing,
    /// Any event that is not part of the specification.
    Custom(String),
}

/// A basic event.
pub trait Event: Debug + Deserialize + Serialize {
    /// The event-type-specific payload this event carries.
    type Content: Debug + Deserialize + Serialize;

    /// The event's content.
    fn content(&self) -> &Self::Content;

    /// The type of the event.
    fn event_type(&self) -> &EventType;

    /// Extra top-level key-value pairs specific to this event type, but that are not under the
    /// `content` field.
    fn extra_content(&self) -> Option<Value> {
        None
    }
}

/// An event within the context of a room.
pub trait RoomEvent: Event {
    /// The unique identifier for the event.
    fn event_id(&self) -> &EventId;

    /// The unique identifier for the room associated with this event.
    fn room_id(&self) -> &RoomId;

    /// Additional key-value pairs not signed by the homeserver.
    fn unsigned(&self) -> Option<&Value>;

    /// The unique identifier for the user associated with this event.
    fn user_id(&self) -> &UserId;
}

/// An event that describes persistent state about a room.
pub trait StateEvent: RoomEvent {
    /// The previous content for this state key, if any.
    fn prev_content(&self) -> Option<&Self::Content>;

    /// A key that determines which piece of room state the event represents.
    fn state_key(&self) -> &str;
}

event! {
    /// A custom basic event not covered by the Matrix specification.
    pub struct CustomEvent(Value) {}
}

room_event! {
    /// A custom room event not covered by the Matrix specification.
    pub struct CustomRoomEvent(Value) {}
}

state_event! {
    /// A custom state event not covered by the Matrix specification.
    pub struct CustomStateEvent(Value) {}
}

impl Display for EventType {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        let event_type_str = match *self {
            EventType::CallAnswer => "m.call.answer",
            EventType::CallCandidates => "m.call.candidates",
            EventType::CallHangup => "m.call.hangup",
            EventType::CallInvite => "m.call.invite",
            EventType::Presence => "m.presence",
            EventType::Receipt => "m.receipt",
            EventType::RoomAliases => "m.room.aliases",
            EventType::RoomAvatar => "m.room.avatar",
            EventType::RoomCanonicalAlias => "m.room.canonical_alias",
            EventType::RoomCreate => "m.room.create",
            EventType::RoomGuestAccess => "m.room.guest_access",
            EventType::RoomHistoryVisibility => "m.room.history_visibility",
            EventType::RoomJoinRules => "m.room.join_rules",
            EventType::RoomMember => "m.room.member",
            EventType::RoomMessage => "m.room.message",
            EventType::RoomName => "m.room.name",
            EventType::RoomPowerLevels => "m.room.power_levels",
            EventType::RoomRedaction => "m.room.redaction",
            EventType::RoomThirdPartyInvite => "m.room.third_party_invite",
            EventType::RoomTopic => "m.room.topic",
            EventType::Tag => "m.tag",
            EventType::Typing => "m.typing",
            EventType::Custom(ref event_type) => event_type,
        };

        write!(f, "{}", event_type_str)
    }
}

impl<'a> From<&'a str> for EventType {
    fn from(s: &'a str) -> EventType {
        match s {
            "m.call.answer" => EventType::CallAnswer,
            "m.call.candidates" => EventType::CallCandidates,
            "m.call.hangup" => EventType::CallHangup,
            "m.call.invite" => EventType::CallInvite,
            "m.presence" => EventType::Presence,
            "m.receipt" => EventType::Receipt,
            "m.room.aliases" => EventType::RoomAliases,
            "m.room.avatar" => EventType::RoomAvatar,
            "m.room.canonical_alias" => EventType::RoomCanonicalAlias,
            "m.room.create" => EventType::RoomCreate,
            "m.room.guest_access" => EventType::RoomGuestAccess,
            "m.room.history_visibility" => EventType::RoomHistoryVisibility,
            "m.room.join_rules" => EventType::RoomJoinRules,
            "m.room.member" => EventType::RoomMember,
            "m.room.message" => EventType::RoomMessage,
            "m.room.name" => EventType::RoomName,
            "m.room.power_levels" => EventType::RoomPowerLevels,
            "m.room.redaction" => EventType::RoomRedaction,
            "m.room.third_party_invite" => EventType::RoomThirdPartyInvite,
            "m.room.topic" => EventType::RoomTopic,
            "m.tag" => EventType::Tag,
            "m.typing" => EventType::Typing,
            event_type => EventType::Custom(event_type.to_string()),
        }
    }
}

impl Serialize for EventType {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        serializer.serialize_str(&self.to_string())
    }
}

impl Deserialize for EventType {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: Deserializer {
        struct EventTypeVisitor;

        impl Visitor for EventTypeVisitor {
            type Value = EventType;

            fn visit_str<E>(&mut self, v: &str) -> Result<Self::Value, E> where E: SerdeError {
                Ok(EventType::from(v))
            }
        }

        deserializer.deserialize_str(EventTypeVisitor)
    }
}

#[cfg(test)]
mod tests {
    use serde_json::{from_str, to_string};

    use super::EventType;

    #[test]
    fn event_types_serialize_to_display_form() {
        assert_eq!(
            to_string(&EventType::RoomCreate).unwrap(),
            r#""m.room.create""#
        );
    }

    #[test]
    fn custom_event_types_serialize_to_display_form() {
        assert_eq!(
            to_string(&EventType::Custom("io.ruma.test".to_string())).unwrap(),
            r#""io.ruma.test""#
        );
    }

    #[test]
    fn event_types_deserialize_from_display_form() {
        assert_eq!(
            from_str::<EventType>(r#""m.room.create""#).unwrap(),
            EventType::RoomCreate
        );
    }

    #[test]
    fn custom_event_types_deserialize_from_display_form() {
        assert_eq!(
            from_str::<EventType>(r#""io.ruma.test""#).unwrap(),
            EventType::Custom("io.ruma.test".to_string())
        )
    }
}
<|endoftext|>


<commit_before>#![feature(default_type_params)]

extern crate url;
extern crate openssl;
extern crate serialize;
extern crate "rust-crypto" as crypto;

#[cfg(test)]
extern crate test;

#[cfg(test)]
use test::Bencher;

use url::Url;
use std::io;
use std::io::{Buffer, Reader, Writer, IoResult, BufferedStream, standard_error};
use std::io::net::tcp::TcpStream;
use std::io::net::ip::{SocketAddr, Ipv4Addr};
use std::io::net::get_host_addresses;
use std::rand::Rng;
use std::rand;
use std::collections::TreeMap;
use serialize::base64::ToBase64;
use serialize::base64;
use serialize::json::{Json, ToJson};
use crypto::sha1::Sha1;
use crypto::digest::Digest;
use openssl::ssl;
use openssl::ssl::{SslStream, SslContext};

enum NetworkStream {
    NormalStream(TcpStream),
    SslProtectedStream(SslStream<TcpStream>)
}

impl Reader for NetworkStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match *self {
            NormalStream(ref mut s) => s.read(buf),
            SslProtectedStream(ref mut s) => s.read(buf)
        }
    }
}

impl Writer for NetworkStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match *self {
            NormalStream(ref mut s) => s.write(buf),
            SslProtectedStream(ref mut s) => s.write(buf)
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        match *self {
            NormalStream(ref mut s) => s.flush(),
            SslProtectedStream(ref mut s) => s.flush()
        }
    }
}

static WEBSOCKET_GUID: &'static [u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

fn generate_nonce() -> String {
    let mut nonce = [0u8, ..10];
    rand::task_rng().fill_bytes(nonce);
    nonce.to_base64(base64::STANDARD)
}

fn encode_nonce(nonce: &str) -> String {
    let mut sha1 = Sha1::new();
    let mut result = [0u8, ..20];
    sha1.input(nonce.as_bytes());
    sha1.input(WEBSOCKET_GUID);
    sha1.result(result);
    result.to_base64(base64::STANDARD)
}

bitflags! {
    #[deriving(Show)] flags WSHeader: u16 {
        static WS_FIN     = 0b1000000000000000,
        static WS_OPCODE  = 0b0000111100000000,
        static WS_MASK    = 0b0000000010000000,
        static WS_LEN     = 0b0000000001111111,

        static WS_LEN16   = 0b0000000001111110,
        static WS_LEN64   = 0b0000000001111111,

        static WS_OPCONT  = 0b0000000000000000,
        static WS_OPTEXT  = 0b0000000100000000,
        static WS_OPBIN   = 0b0000001000000000,
        static WS_OPTERM  = 0b0000100000000000,
        static WS_OPPING  = 0b0000100100000000,
        static WS_OPPONG  = 0b0000101000000000,
    }
}

#[allow(visible_private_types)]
#[allow(dead_code)]
pub struct WebSocket<S = NetworkStream> {
    stream: Option<BufferedStream<S>>,
    handshake_finished: bool,
    pub remote_addr: Option<SocketAddr>,
    pub url: Url,
    use_ssl: bool,
}

#[allow(dead_code)]
impl WebSocket {
    fn new(url: Url) -> IoResult<WebSocket> {
        let addr = match try!(url.domain()
            .map(|h| get_host_addresses(h)
                 .map(|v| v.move_iter().find(|&a| {
                     match a {
                         Ipv4Addr(..) => true,
                         _ => false
                     }
                 })))
            .unwrap_or(Err(standard_error(io::InvalidInput)))) {
                Some(a) => a,
                None => return Err(standard_error(io::FileNotFound))
            };

        let use_ssl = url.scheme.as_slice() == "wss";

        let port = match url.port() {
            Some(p) => p,
            None if use_ssl => 443,
            _ => 80
        };

        Ok(WebSocket {
            stream: None,
            handshake_finished: false,
            remote_addr: Some(SocketAddr{ ip: addr, port: port }),
            url: url,
            use_ssl: use_ssl,
        })
    }

    #[allow(unused_variable)]
    fn connect(&mut self) -> IoResult<()> {
        let s = try!(self.remote_addr.map(|ref a| TcpStream::connect(format!("{}", a.ip).as_slice(), a.port)).unwrap_or_else(|| Err(standard_error(io::InvalidInput))));
        self.stream = Some(BufferedStream::new(
            if self.use_ssl {
                SslProtectedStream(try!(SslStream::new(&try!(SslContext::new(ssl::Sslv23).map_err(|e| standard_error(io::OtherIoError))), s)
                                        .map_err(|e| standard_error(io::OtherIoError))))
            } else {
                NormalStream(s)
            }));
        Ok(())
    }

    fn send_headers(&mut self, nonce: &str) -> IoResult<()> {
        let s = match self.stream { Some(ref mut s) => s, None => return Err(standard_error(io::NotConnected)) };
        try!(s.write(format!("GET {} HTTP/1.1\r\n", self.url.serialize_path().unwrap_or("/".to_string())).as_bytes()));
        try!(s.write(format!("Host: {}\r\n", self.url.host().unwrap()).as_bytes()));
        try!(s.write("Upgrade: websocket\r\n".as_bytes()));
        try!(s.write("Connection: Upgrade\r\n".as_bytes()));
        try!(s.write(format!("Origin: {}\r\n", self.url.serialize_no_fragment()).as_bytes()));
        try!(s.write("Sec-WebSocket-Protocol: char, superchat\r\n".as_bytes()));
        try!(s.write("Sec-WebSocket-Version: 13\r\n".as_bytes()));
        try!(s.write(format!("Sec-WebSocket-Key: {}\r\n", nonce).as_bytes()));
        try!(s.write("\r\n".as_bytes()));
        s.flush()
    }

    fn read_response(&mut self, nonce: &str) -> IoResult<()> {
        let spaces: &[_] = &[' ', '\t', '\r', '\n'];
        let s = match self.stream { Some(ref mut s) => s, None => return Err(standard_error(io::NotConnected)) };
        let status = try!(s.read_line()).as_slice().splitn(2, ' ').nth(1).and_then(|s| from_str::<uint>(s));

        match status {
            Some(101) => (),
            _ => return Err(standard_error(io::InvalidInput))
        }

        let headers = s.lines().map(|r| r.unwrap_or("\r\n".to_string())) .take_while(|l| l.as_slice() != "\r\n")
            .map(|s| s.as_slice().splitn(1, ':').map(|s| s.trim_chars(spaces).to_string()).collect::<Vec<String>>())
            .map(|p| (p[0].to_string(), p[1].to_string()))
            .collect::<TreeMap<String, String>>();

        try!(s.flush());

        let response = headers.find(&"Sec-WebSocket-Accept".to_string());
        match response {
            Some(r) if nonce == r.as_slice() => (),
            _ => return Err(standard_error(io::InvalidInput))
        }

        Ok(())
    }

    fn handshake(&mut self) -> IoResult<()> {
        let nonce = generate_nonce();

        try!(self.connect()
             .and_then(|()| self.send_headers(nonce.as_slice()))
             .and_then(|()| self.read_response(encode_nonce(nonce.as_slice()).as_slice())));

        self.handshake_finished = true;

        Ok(())
    }

    fn read_header(&mut self) -> IoResult<WSHeader> {
        // XXX: this is a bug, WSHeader should accept u16
        Ok(WSHeader { bits: try!(self.read_be_u16()) as u32 })
    }

    fn read_length(&mut self, header: &WSHeader) -> IoResult<uint> {
        match header & WS_LEN {
            WS_LEN16 => self.read_be_u16().map(|v| v as uint),
            WS_LEN64 => self.read_be_u64().map(|v| v as uint),
            len => Ok(len.bits as uint)
        }
    }

    fn read_message(&mut self) -> IoResult<WSMessage> {
        let header = try!(self.read_header());
        let len = try!(self.read_length(&header));

        let data = if header.contains(WS_MASK) {
            WebSocket::unmask_data(try!(self.read_exact(len)), try!(self.read_be_u32()))
        } else {
            try!(self.read_exact(len))
        };

        Ok(WSMessage { header: header, data: data })
    }

    fn unmask_data(data: Vec<u8>, mask: u32) -> Vec<u8> {
        data.iter().enumerate().map(|(i, b)| b ^ (mask >> ((i % 4) << 3) & 0xff) as u8).collect::<Vec<u8>>()
    }

    // TODO: send_message(&mut self, &WSMessage) -> IoResult<()>

    fn iter(&mut self) -> WSMessages {
        WSMessages { sock: self }
    }
}

#[deriving(Show)]
struct WSMessage {
    header: WSHeader,
    data: Vec<u8>
}

impl WSMessage {
    fn to_string(&self) -> String {
        String::from_utf8_lossy(self.data.as_slice()).into_string()
    }
}

impl ToJson for WSMessage {
    fn to_json(&self) -> Json {
        from_str::<Json>(self.to_string().as_slice()).unwrap()
    }
}

#[allow(dead_code)]
struct WSMessages<'a> {
    sock: &'a mut WebSocket
}

impl<'a> Iterator<WSMessage> for WSMessages<'a> {
    fn next(&mut self) -> Option<WSMessage> {
        self.sock.read_message().ok()
    }
}

impl Reader for WebSocket {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match self.stream {
            Some(ref mut s) => s.read(buf),
            None => Err(standard_error(io::NotConnected))
        }
    }
}

impl Buffer for WebSocket {
    fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> {
        match self.stream {
            Some(ref mut s) => s.fill_buf(),
            None => Err(standard_error(io::NotConnected))
        }
    }

    fn consume(&mut self, amt: uint) {
        match self.stream {
            Some(ref mut s) => s.consume(amt),
            None => ()
        }
    }
}

#[bench]
#[allow(dead_code)]
fn test_connect(b: &mut Bencher) {
    let url = Url::parse("wss://stream.pushbullet.com/websocket/").unwrap();
    let mut ws = WebSocket::new(url).unwrap();

    match ws.handshake() {
        Err(e) => fail!("error: {}", e),
        _ => ()
    }
    let msg = ws.read_message().unwrap();
    println!("received: {} {} {}", msg, msg.to_string(), msg.to_json());
    for msg in ws.iter() {
        println!("{}", msg.to_string());
    }
}
<commit_msg>factor out nonce into struct<commit_after>#![feature(default_type_params)]

extern crate url;
extern crate openssl;
extern crate serialize;
extern crate "rust-crypto" as crypto;

#[cfg(test)]
extern crate test;

#[cfg(test)]
use test::Bencher;

use url::Url;
use std::io;
use std::io::{Buffer, Reader, Writer, IoResult, BufferedStream, standard_error};
use std::io::net::tcp::TcpStream;
use std::io::net::ip::{SocketAddr, Ipv4Addr};
use std::io::net::get_host_addresses;
use std::rand::Rng;
use std::rand;
use std::collections::TreeMap;
use serialize::base64::ToBase64;
use serialize::base64;
use serialize::json::{Json, ToJson};
use crypto::sha1::Sha1;
use crypto::digest::Digest;
use openssl::ssl;
use openssl::ssl::{SslStream, SslContext};

enum NetworkStream {
    NormalStream(TcpStream),
    SslProtectedStream(SslStream<TcpStream>)
}

impl Reader for NetworkStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match *self {
            NormalStream(ref mut s) => s.read(buf),
            SslProtectedStream(ref mut s) => s.read(buf)
        }
    }
}

impl Writer for NetworkStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match *self {
            NormalStream(ref mut s) => s.write(buf),
            SslProtectedStream(ref mut s) => s.write(buf)
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        match *self {
            NormalStream(ref mut s) => s.flush(),
            SslProtectedStream(ref mut s) => s.flush()
        }
    }
}

static WEBSOCKET_GUID: &'static [u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

bitflags! {
    #[deriving(Show)] flags WSHeader: u16 {
        static WS_FIN     = 0b1000000000000000,
        static WS_OPCODE  = 0b0000111100000000,
        static WS_MASK    = 0b0000000010000000,
        static WS_LEN     = 0b0000000001111111,

        static WS_LEN16   = 0b0000000001111110,
        static WS_LEN64   = 0b0000000001111111,

        static WS_OPCONT  = 0b0000000000000000,
        static WS_OPTEXT  = 0b0000000100000000,
        static WS_OPBIN   = 0b0000001000000000,
        static WS_OPTERM  = 0b0000100000000000,
        static WS_OPPING  = 0b0000100100000000,
        static WS_OPPONG  = 0b0000101000000000,
    }
}

#[allow(visible_private_types)]
#[allow(dead_code)]
pub struct WebSocket<S = NetworkStream> {
    stream: Option<BufferedStream<S>>,
    handshake_finished: bool,
    pub remote_addr: Option<SocketAddr>,
    pub url: Url,
    use_ssl: bool,
}

struct Nonce(String);

impl Nonce {
    fn new() -> Nonce {
        Nonce::generate(&mut rand::task_rng())
    }

    fn generate(r: &mut Rng) -> Nonce {
        let mut nonce = [0u8, ..10];
        r.fill_bytes(nonce);
        Nonce(nonce.to_base64(base64::STANDARD))
    }

    fn encode(self) -> Nonce {
        let n = match self { Nonce(n) => n };
        let mut sha1 = Sha1::new();
        let mut result = [0u8, ..20];
        sha1.input(n.as_bytes());
        sha1.input(WEBSOCKET_GUID);
        sha1.result(result);
        Nonce(result.to_base64(base64::STANDARD))
    }
}

impl<'a> Str for Nonce {
    fn as_slice<'a>(&'a self) -> &'a str {
        match *self { Nonce(ref n) => n.as_slice() }
    }
}

#[allow(dead_code)]
impl WebSocket {
    fn new(url: Url) -> IoResult<WebSocket> {
        let addr = match try!(url.domain()
            .map(|h| get_host_addresses(h)
                 .map(|v| v.move_iter().find(|&a| {
                     match a {
                         Ipv4Addr(..) => true,
                         _ => false
                     }
                 })))
            .unwrap_or(Err(standard_error(io::InvalidInput)))) {
                Some(a) => a,
                None => return Err(standard_error(io::FileNotFound))
            };

        let use_ssl = url.scheme.as_slice() == "wss";

        let port = match url.port() {
            Some(p) => p,
            None if use_ssl => 443,
            _ => 80
        };

        Ok(WebSocket {
            stream: None,
            handshake_finished: false,
            remote_addr: Some(SocketAddr{ ip: addr, port: port }),
            url: url,
            use_ssl: use_ssl,
        })
    }

    #[allow(unused_variable)]
    fn connect(&mut self) -> IoResult<()> {
        let s = try!(self.remote_addr.map(|ref a| TcpStream::connect(format!("{}", a.ip).as_slice(), a.port)).unwrap_or_else(|| Err(standard_error(io::InvalidInput))));
        self.stream = Some(BufferedStream::new(
            if self.use_ssl {
                SslProtectedStream(try!(SslStream::new(&try!(SslContext::new(ssl::Sslv23).map_err(|e| standard_error(io::OtherIoError))), s)
                                        .map_err(|e| standard_error(io::OtherIoError))))
            } else {
                NormalStream(s)
            }));
        Ok(())
    }

    fn send_headers(&mut self, nonce: &str) -> IoResult<()> {
        let s = match self.stream { Some(ref mut s) => s, None => return Err(standard_error(io::NotConnected)) };
        try!(s.write(format!("GET {} HTTP/1.1\r\n", self.url.serialize_path().unwrap_or("/".to_string())).as_bytes()));
        try!(s.write(format!("Host: {}\r\n", self.url.host().unwrap()).as_bytes()));
        try!(s.write("Upgrade: websocket\r\n".as_bytes()));
        try!(s.write("Connection: Upgrade\r\n".as_bytes()));
        try!(s.write(format!("Origin: {}\r\n", self.url.serialize_no_fragment()).as_bytes()));
        try!(s.write("Sec-WebSocket-Protocol: char, superchat\r\n".as_bytes()));
        try!(s.write("Sec-WebSocket-Version: 13\r\n".as_bytes()));
        try!(s.write(format!("Sec-WebSocket-Key: {}\r\n", nonce).as_bytes()));
        try!(s.write("\r\n".as_bytes()));
        s.flush()
    }

    fn read_response(&mut self, nonce: &str) -> IoResult<()> {
        let spaces: &[_] = &[' ', '\t', '\r', '\n'];
        let s = match self.stream { Some(ref mut s) => s, None => return Err(standard_error(io::NotConnected)) };
        let status = try!(s.read_line()).as_slice().splitn(2, ' ').nth(1).and_then(|s| from_str::<uint>(s));

        match status {
            Some(101) => (),
            _ => return Err(standard_error(io::InvalidInput))
        }

        let headers = s.lines().map(|r| r.unwrap_or("\r\n".to_string())) .take_while(|l| l.as_slice() != "\r\n")
            .map(|s| s.as_slice().splitn(1, ':').map(|s| s.trim_chars(spaces).to_string()).collect::<Vec<String>>())
            .map(|p| (p[0].to_string(), p[1].to_string()))
            .collect::<TreeMap<String, String>>();

        try!(s.flush());

        let response = headers.find(&"Sec-WebSocket-Accept".to_string());
        match response {
            Some(r) if nonce == r.as_slice() => (),
            _ => return Err(standard_error(io::InvalidInput))
        }

        Ok(())
    }

    fn handshake(&mut self) -> IoResult<()> {
        let mut nonce = Nonce::new();

        try!(self.connect());
        try!(self.send_headers(nonce.as_slice()));

        nonce = nonce.encode();
        try!(self.read_response(nonce.as_slice()));

        self.handshake_finished = true;

        Ok(())
    }

    fn read_header(&mut self) -> IoResult<WSHeader> {
        // XXX: this is a bug, WSHeader should accept u16
        Ok(WSHeader { bits: try!(self.read_be_u16()) as u32 })
    }

    fn read_length(&mut self, header: &WSHeader) -> IoResult<uint> {
        match header & WS_LEN {
            WS_LEN16 => self.read_be_u16().map(|v| v as uint),
            WS_LEN64 => self.read_be_u64().map(|v| v as uint),
            len => Ok(len.bits as uint)
        }
    }

    fn read_message(&mut self) -> IoResult<WSMessage> {
        let header = try!(self.read_header());
        let len = try!(self.read_length(&header));

        let data = if header.contains(WS_MASK) {
            WebSocket::unmask_data(try!(self.read_exact(len)), try!(self.read_be_u32()))
        } else {
            try!(self.read_exact(len))
        };

        Ok(WSMessage { header: header, data: data })
    }

    fn unmask_data(data: Vec<u8>, mask: u32) -> Vec<u8> {
        data.iter().enumerate().map(|(i, b)| b ^ (mask >> ((i % 4) << 3) & 0xff) as u8).collect::<Vec<u8>>()
    }

    // TODO: send_message(&mut self, &WSMessage) -> IoResult<()>

    fn iter(&mut self) -> WSMessages {
        WSMessages { sock: self }
    }
}

#[deriving(Show)]
struct WSMessage {
    header: WSHeader,
    data: Vec<u8>
}

impl WSMessage {
    fn to_string(&self) -> String {
        String::from_utf8_lossy(self.data.as_slice()).into_string()
    }
}

impl ToJson for WSMessage {
    fn to_json(&self) -> Json {
        from_str::<Json>(self.to_string().as_slice()).unwrap()
    }
}

#[allow(dead_code)]
struct WSMessages<'a> {
    sock: &'a mut WebSocket
}

impl<'a> Iterator<WSMessage> for WSMessages<'a> {
    fn next(&mut self) -> Option<WSMessage> {
        self.sock.read_message().ok()
    }
}

impl Reader for WebSocket {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match self.stream {
            Some(ref mut s) => s.read(buf),
            None => Err(standard_error(io::NotConnected))
        }
    }
}

impl Buffer for WebSocket {
    fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> {
        match self.stream {
            Some(ref mut s) => s.fill_buf(),
            None => Err(standard_error(io::NotConnected))
        }
    }

    fn consume(&mut self, amt: uint) {
        match self.stream {
            Some(ref mut s) => s.consume(amt),
            None => ()
        }
    }
}

#[bench]
#[allow(dead_code)]
fn test_connect(b: &mut Bencher) {
    let url = Url::parse("wss://stream.pushbullet.com/websocket/").unwrap();
    let mut ws = WebSocket::new(url).unwrap();

    match ws.handshake() {
        Err(e) => fail!("error: {}", e),
        _ => ()
    }
    let msg = ws.read_message().unwrap();
    println!("received: {} {} {}", msg, msg.to_string(), msg.to_json());
    for msg in ws.iter() {
        println!("{}", msg.to_string());
    }
}
<|endoftext|>


<commit_before>#![feature(custom_derive, custom_attribute, collections, plugin)]
#![plugin(serde_macros)]

extern crate serde;
extern crate hyper;
extern crate regex;

mod domanager;
#[macro_use]
mod macros;

pub mod request;
pub mod response;

pub use domanager::DoManager;
pub use request::RequestBuilder;
pub use request::DoRequest;

#[cfg(test)]
mod tests{
}
<commit_msg>fix: fixes to compile on latest nightly<commit_after>#![feature(custom_derive, custom_attribute, append, plugin)]
#![plugin(serde_macros)]

extern crate serde;
extern crate hyper;
extern crate regex;

mod domanager;
#[macro_use]
mod macros;

pub mod request;
pub mod response;

pub use domanager::DoManager;
pub use request::RequestBuilder;
pub use request::DoRequest;

#[cfg(test)]
mod tests{
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate json;

pub mod request;
pub mod response;

pub use request::{get, post, put, head, delete};
pub use response::Response;

pub type RequestsResult = hyper::Result<Response>;
<commit_msg>Re-export hyper::error::Error as RequestsError<commit_after>extern crate hyper;
extern crate json;

pub mod request;
pub mod response;

pub use request::{get, post, put, head, delete};
pub use response::Response;

pub type RequestsResult = hyper::Result<Response>;
pub type RequestsError = hyper::error::Error;
<|endoftext|>


<commit_before>// TODO: deny missing docs
#![allow(missing_docs)]
// for mem::discriminant_value
#![feature(discriminant_value)]

#[macro_use]
extern crate error_chain;
extern crate futures;
extern crate tokio_core;
extern crate trust_dns;

use futures::Future;
use futures::future::join_all;
use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
use std::time::Duration;
use tokio_core::reactor::Handle;
use trust_dns::client::{ClientFuture, ClientHandle};
use trust_dns::rr::domain;
use trust_dns::rr::{DNSClass, Record, RecordType};
use trust_dns::udp::UdpClientStream;

#[derive(Debug, Copy, Clone)]
pub struct DnsQuery<'a> {
    domain_name: &'a str,
    record_type: RecordType,
    timeout: Duration,
}

impl<'a> DnsQuery<'a> {
    pub fn new(domain_name: &'a str, record_type: RecordType, timeout: Duration) -> DnsQuery<'a> {
        DnsQuery { domain_name, record_type, timeout }
    }
}

#[derive(Debug)]
pub struct DnsResponse {
    pub server: IpAddr,
    pub answers: Vec<Record>,
}

/// Lookup a domain name against a single DNS server
///
/// The return type is special here. `Future<Item=Result<DnsResponse>, Error=()`. This Future is not supposed to fail
/// in future::futures::Err way, but rather propagate errors as part of the Future's successful execution.
/// In this way, `multiple_lookup` does not abort when lookups fail, but wait for all queries / Futures to finish.
/// The library user than can distinguish between successful and failed lookups.
///
/// See also `multiple_lookup`.
pub fn lookup<T: Into<SocketAddr>>(
    loop_handle: &Handle,
    query: DnsQuery,
    server: T
) -> Box<Future<Item=Result<DnsResponse>, Error=()>> {
    let socket_addr = server.into();
    let domain_name = domain::Name::from_str(query.domain_name).unwrap();

    let (stream, sender) = UdpClientStream::new(socket_addr, loop_handle);
    let mut client = ClientFuture::with_timeout(stream, sender, loop_handle, query.timeout, None);

    Box::new(
        client
            .query(domain_name, DNSClass::IN, query.record_type)
            .map(move |mut response| {
                Ok(DnsResponse { server: socket_addr.ip(), answers: response.take_answers() })
            })
            .or_else(move |e| {
                Ok(Err(Error::with_chain(e, ErrorKind::QueryError)))
            })
    )
}

pub fn multiple_lookup<T: Into<SocketAddr>>(
    loop_handle: &Handle,
    query: DnsQuery,
    servers: Vec<T>,
) -> Box<Future<Item=Vec<Result<DnsResponse>>, Error=()>> {
    let futures: Vec<_> = servers
        .into_iter()
        .map(|server| lookup(loop_handle, query, server))
        .collect();

    Box::new(join_all(futures))
}

error_chain! {
    types {
        Error, ErrorKind, ResultExt, Result;
    }

    errors {
        QueryError {
            description("Query failed")
            display("Query failed")
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::mem;
    use std::net::Ipv4Addr;
    use tokio_core::reactor::Core;
    use trust_dns::rr::{RData, RecordType};

    #[test]
    fn lookup_with_google() {
        let mut io_loop = Core::new().unwrap();
        let query = DnsQuery::new("example.com", RecordType::A, Duration::from_secs(5));
        let server = (Ipv4Addr::from_str("8.8.8.8").unwrap(), 53);

        let lookup = lookup(&io_loop.handle(), query, server);
        let result = io_loop.run(lookup).unwrap();
        let response: DnsResponse = result.unwrap();

        assert_eq!(response.server, Ipv4Addr::from_str("8.8.8.8").unwrap());
        assert_eq!(response.answers.len(), 1);
        assert!(is_A_record(response.answers[0].rdata()));
        if let RData::A(ip) = *response.answers[0].rdata() {
            assert_eq!(ip, Ipv4Addr::new(93, 184, 216, 34));
        }
    }

    #[test]
    fn multiple_lookup_with_google_ok() {
        let mut io_loop = Core::new().unwrap();
        let query = DnsQuery::new("example.com", RecordType::A, Duration::from_secs(5));
        let servers = vec![
            (Ipv4Addr::from_str("8.8.8.8").unwrap(), 53),
            (Ipv4Addr::from_str("8.8.4.4").unwrap(), 53),
        ];

        let lookup = multiple_lookup(&io_loop.handle(), query, servers);
        let mut responses: Vec<_> = io_loop.run(lookup).unwrap();
        assert_eq!(responses.len(), 2);

        let response = responses.pop().unwrap().unwrap();
        assert_eq!(response.server, Ipv4Addr::from_str("8.8.4.4").unwrap());
        assert_eq!(response.answers.len(), 1);
        assert!(is_A_record(response.answers[0].rdata()));
        if let RData::A(ip) = *response.answers[0].rdata() {
            assert_eq!(ip, Ipv4Addr::new(93, 184, 216, 34));
        }

        let response = responses.pop().unwrap().unwrap();
        assert_eq!(response.server, Ipv4Addr::from_str("8.8.8.8").unwrap());
        assert_eq!(response.answers.len(), 1);
        assert!(is_A_record(response.answers[0].rdata()));
        if let RData::A(ip) = *response.answers[0].rdata() {
            assert_eq!(ip, Ipv4Addr::new(93, 184, 216, 34));
        }
    }

    #[test]
    fn multiple_lookup_with_google_fail_1() {
        let mut io_loop = Core::new().unwrap();
        // short timeout, because we won't the test to take too long, Google is fast enough to answer in time
        let query = DnsQuery::new("example.com", RecordType::A, Duration::from_millis(500));
        let servers = vec![
            (Ipv4Addr::from_str("8.8.8.8").unwrap(), 53),
            // This one does not exists and should lead to a timeout
            (Ipv4Addr::from_str("8.8.5.5").unwrap(), 53),
        ];

        let lookup = multiple_lookup(&io_loop.handle(), query, servers);
        let mut responses: Vec<_> = io_loop.run(lookup).unwrap();
        assert_eq!(responses.len(), 2);

        let response = responses.pop().unwrap();
        assert!(response.is_err());

        let response = responses.pop().unwrap().unwrap();
        assert_eq!(response.server, Ipv4Addr::from_str("8.8.8.8").unwrap());
        assert_eq!(response.answers.len(), 1);
        assert!(is_A_record(response.answers[0].rdata()));
        if let RData::A(ip) = *response.answers[0].rdata() {
            assert_eq!(ip, Ipv4Addr::new(93, 184, 216, 34));
        }
    }

    #[allow(non_snake_case)]
    fn is_A_record(rdata: &RData) -> bool {
        mem::discriminant(rdata) == mem::discriminant(&RData::A(Ipv4Addr::new(127, 0, 0, 1)))
    }
}
<commit_msg>Refactoring<commit_after>// TODO: deny missing docs
#![allow(missing_docs)]
// for mem::discriminant_value
#![feature(discriminant_value)]

#[macro_use]
extern crate error_chain;
extern crate futures;
extern crate tokio_core;
extern crate trust_dns;

use futures::Future;
use futures::future::join_all;
use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
use std::time::Duration;
use tokio_core::reactor::Handle;
use trust_dns::client::{ClientFuture, ClientHandle};
use trust_dns::rr::domain;
use trust_dns::rr::{DNSClass, Record, RecordType};
use trust_dns::udp::UdpClientStream;

#[derive(Debug, Copy, Clone)]
pub struct DnsQuery<'a> {
    domain_name: &'a str,
    record_type: RecordType,
    timeout: Duration,
}

impl<'a> DnsQuery<'a> {
    pub fn new(domain_name: &'a str, record_type: RecordType, timeout: Duration) -> DnsQuery<'a> {
        DnsQuery { domain_name, record_type, timeout }
    }
}

#[derive(Debug)]
pub struct DnsResponse {
    pub server: IpAddr,
    pub answers: Vec<Record>,
}

/// Lookup a domain name against a single DNS server
///
/// The return type is special here. `Future<Item=Result<DnsResponse>, Error=()`. This Future is not supposed to fail
/// in future::futures::Err way, but rather propagate errors as part of the Future's successful execution.
/// In this way, `multiple_lookup` does not abort when lookups fail, but wait for all queries / Futures to finish.
/// The library user than can distinguish between successful and failed lookups.
///
/// See also `multiple_lookup`.
pub fn lookup<T: Into<SocketAddr>>(
    loop_handle: &Handle,
    query: DnsQuery,
    server: T
) -> Box<Future<Item=DnsResponse, Error=Error>> {
    let socket_addr = server.into();
    let domain_name = domain::Name::from_str(query.domain_name).unwrap();

    let (stream, sender) = UdpClientStream::new(socket_addr, loop_handle);
    let mut client = ClientFuture::with_timeout(stream, sender, loop_handle, query.timeout, None);

    Box::new(
        client
            .query(domain_name, DNSClass::IN, query.record_type)
            .map(move |mut response|
                DnsResponse { server: socket_addr.ip(), answers: response.take_answers() }
            )
            .map_err(move |e| Error::with_chain(e, ErrorKind::QueryError) )
    )
}

pub fn multiple_lookup<T: Into<SocketAddr>>(
    loop_handle: &Handle,
    query: DnsQuery,
    servers: Vec<T>,
) -> Box<Future<Item=Vec<Result<DnsResponse>>, Error=()>> {
    let futures: Vec<_> = servers
        .into_iter()
        .map(|server| {
            lookup(loop_handle, query, server)
                .map(|response| Ok(response) )
                .or_else(|e| Ok(Err(e)) )
        })
        .collect();

    Box::new(join_all(futures))
}

error_chain! {
    types {
        Error, ErrorKind, ResultExt, Result;
    }

    errors {
        QueryError {
            description("Query failed")
            display("Query failed")
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::mem;
    use std::net::Ipv4Addr;
    use tokio_core::reactor::Core;
    use trust_dns::rr::{RData, RecordType};

    #[test]
    fn multi_record_type_lookup() {
        let mut io_loop = Core::new().unwrap();
        let server = (Ipv4Addr::from_str("8.8.8.7").unwrap(), 53);

        let record_types = vec![RecordType::A, RecordType::AAAA, RecordType::MX];

        let lookups: Vec<_> = record_types
            .into_iter()
            .map(|rt| {
                let query = DnsQuery::new("example.com", rt, Duration::from_secs(5));
                lookup(&io_loop.handle(), query, server)
            })
            .collect();
        let all = join_all(lookups)
            .and_then(|lookups| {
                let res = lookups
                    .into_iter()
                    .fold(Vec::new(), |mut acc, mut lookup: DnsResponse| {
                        acc.append(&mut lookup.answers);
                        acc
                    });
                futures::future::ok(res)
            });

        let result = io_loop.run(all);

        eprintln!("result = {:?}", result);
    }

    #[test]
    fn lookup_with_google() {
        let mut io_loop = Core::new().unwrap();
        let query = DnsQuery::new("example.com", RecordType::A, Duration::from_secs(5));
        let server = (Ipv4Addr::from_str("8.8.8.8").unwrap(), 53);

        let lookup = lookup(&io_loop.handle(), query, server);
        let result = io_loop.run(lookup).unwrap();
        let response: DnsResponse = result;

        assert_eq!(response.server, Ipv4Addr::from_str("8.8.8.8").unwrap());
        assert_eq!(response.answers.len(), 1);
        assert!(is_A_record(response.answers[0].rdata()));
        if let RData::A(ip) = *response.answers[0].rdata() {
            assert_eq!(ip, Ipv4Addr::new(93, 184, 216, 34));
        }
    }

    #[test]
    fn multiple_lookup_with_google_ok() {
        let mut io_loop = Core::new().unwrap();
        let query = DnsQuery::new("example.com", RecordType::A, Duration::from_secs(5));
        let servers = vec![
            (Ipv4Addr::from_str("8.8.8.8").unwrap(), 53),
            (Ipv4Addr::from_str("8.8.4.4").unwrap(), 53),
        ];

        let lookup = multiple_lookup(&io_loop.handle(), query, servers);
        let mut responses: Vec<_> = io_loop.run(lookup).unwrap();
        assert_eq!(responses.len(), 2);

        let response = responses.pop().unwrap().unwrap();
        assert_eq!(response.server, Ipv4Addr::from_str("8.8.4.4").unwrap());
        assert_eq!(response.answers.len(), 1);
        assert!(is_A_record(response.answers[0].rdata()));
        if let RData::A(ip) = *response.answers[0].rdata() {
            assert_eq!(ip, Ipv4Addr::new(93, 184, 216, 34));
        }

        let response = responses.pop().unwrap().unwrap();
        assert_eq!(response.server, Ipv4Addr::from_str("8.8.8.8").unwrap());
        assert_eq!(response.answers.len(), 1);
        assert!(is_A_record(response.answers[0].rdata()));
        if let RData::A(ip) = *response.answers[0].rdata() {
            assert_eq!(ip, Ipv4Addr::new(93, 184, 216, 34));
        }
    }

    #[test]
    fn multiple_lookup_with_google_fail_1() {
        let mut io_loop = Core::new().unwrap();
        // short timeout, because we won't the test to take too long, Google is fast enough to answer in time
        let query = DnsQuery::new("example.com", RecordType::A, Duration::from_millis(500));
        let servers = vec![
            (Ipv4Addr::from_str("8.8.8.8").unwrap(), 53),
            // This one does not exists and should lead to a timeout
            (Ipv4Addr::from_str("8.8.5.5").unwrap(), 53),
        ];

        let lookup = multiple_lookup(&io_loop.handle(), query, servers);
        let mut responses: Vec<_> = io_loop.run(lookup).unwrap();
        assert_eq!(responses.len(), 2);

        let response = responses.pop().unwrap();
        assert!(response.is_err());

        let response = responses.pop().unwrap().unwrap();
        assert_eq!(response.server, Ipv4Addr::from_str("8.8.8.8").unwrap());
        assert_eq!(response.answers.len(), 1);
        assert!(is_A_record(response.answers[0].rdata()));
        if let RData::A(ip) = *response.answers[0].rdata() {
            assert_eq!(ip, Ipv4Addr::new(93, 184, 216, 34));
        }
    }

    #[allow(non_snake_case)]
    fn is_A_record(rdata: &RData) -> bool {
        mem::discriminant(rdata) == mem::discriminant(&RData::A(Ipv4Addr::new(127, 0, 0, 1)))
    }
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]
extern crate serialize;
extern crate chrono;

//use std::collections::HashMap;
use serialize::json;
use serialize::json::{
    Json,
    String,
    F64,
    U64,
    I64,
    List,
    Null,
};
use std::io;
use chrono::NaiveDateTime;

#[deriving(Show)]
pub struct Event {
    client: Client,
    check: Check,
    occurences: Vec<i32>,
    action: String,
}

#[deriving(Show)]
pub struct Client {
    name: String,
    address: String,
    subscriptions: Vec<String>,
    timestamp: NaiveDateTime,
    additional: Json
}

#[deriving(Show)]
pub struct Check {
    name: String,
    issued: NaiveDateTime,
    output: String,
    status: i8,
    command: String,
    subscribers: Vec<String>,
    interval: i32,
    handler: Option<String>,
    handlers: Option<Vec<String>>,
    history: Vec<i8>,
    flapping: bool,
    additional: Json
}

#[deriving(Show)]
pub enum SensuError {
    InitError(String),
    EventError(String)
}

macro_rules! jk(
    ($j:ident->$k:expr $p:ident) => (
        match $j.find($k) {
            Some(value) => match value {
                &$p(ref v) => v.clone(),
                _ => return Err(EventError(format!("Wrong type for key: {}", value)))
            },
            None => return Err(EventError(format!("couldn't find {} in event", $k)))
        }
    )
)

pub fn read_stdin() -> Result<String, SensuError> {
    match io::stdin().read_to_end() {
        Ok(input) => Ok(input.to_string()),
        Err(e) => return Err(InitError(format!("couldn't read stdin: {}", e)))
    }
}

pub fn read_event(input: &str) -> Result<Client, SensuError> {
    let event = match json::from_str(input) {
        Ok(v) => v,
        Err(e) => return Err(InitError(format!("couldn't parse json: {}", e)))
    };

    let client = try!(read_client(event));
    Ok(client)
}

fn read_client(input: Json) -> Result<Client, SensuError> {
    let event = match input.find("client") {
        Some(client) => client,
        None => return Err(InitError("No client in event".into_string()))
    };

    let unverified_subs = jk!(event->"subscriptions" List);
    let mut subs: Vec<String> = Vec::new();
    for sub in unverified_subs.iter() {
        match *sub {
            json::String(ref s) => subs.push(s.clone()),
            _ => return Err(EventError(format!("Invalid subscription type {}", sub)))
        }
    }

    let client = Client {
        name: jk!(event->"name" String),
        address: jk!(event->"address" String),
        subscriptions: subs,
        timestamp: NaiveDateTime::from_num_seconds_from_unix_epoch(
            match event.find("timestamp") {
                Some(value) => match value {
                    &I64(ref v) => v.clone(),
                    &U64(ref v) => v.clone() as i64,
                    &F64(ref v) => v.clone() as i64,
                    _ => return Err(EventError(format!("Wrong type for key: {}", value)))
                },
                None => return Err(EventError("couldn't find timestamp in event".into_string()))
            }, 0),
        additional: Null
    };
    Ok(client)
}

#[cfg(test)]
mod build_objects {
    use serialize::json;
    use super::read_client;

    #[test]
    fn can_build_client() {
        let event = json::from_str(r#"{
            "client": {
                "name": "hello",
                "address": "192.168.1.1",
                "subscriptions": ["one", "two"],
                "timestamp": 127897
            }
        }"#).unwrap();
        let client = read_client(event);
        match client {
            Ok(cl) => println!("Parsed: {}", cl),
            Err(e) => panic!("ERROR: {}", e)
        }
    }
}
<commit_msg>Don't put early returns into struct-building parts<commit_after>#![feature(macro_rules)]
extern crate serialize;
extern crate chrono;

//use std::collections::HashMap;
use serialize::json;
use serialize::json::{
    Json,
    String,
    F64,
    U64,
    I64,
    List,
    Null,
};
use std::io;
use chrono::NaiveDateTime;

#[deriving(Show)]
pub struct Event {
    client: Client,
    check: Check,
    occurences: Vec<i32>,
    action: String,
}

#[deriving(Show)]
pub struct Client {
    name: String,
    address: String,
    subscriptions: Vec<String>,
    timestamp: NaiveDateTime,
    additional: Json
}

#[deriving(Show)]
pub struct Check {
    name: String,
    issued: NaiveDateTime,
    output: String,
    status: i8,
    command: String,
    subscribers: Vec<String>,
    interval: i32,
    handler: Option<String>,
    handlers: Option<Vec<String>>,
    history: Vec<i8>,
    flapping: bool,
    additional: Json
}

#[deriving(Show)]
pub enum SensuError {
    InitError(String),
    EventError(String)
}

macro_rules! jk(
    ($j:ident->$k:expr $p:ident) => (
        match $j.find($k) {
            Some(value) => match value {
                &$p(ref v) => v.clone(),
                _ => return Err(EventError(format!("Wrong type for key: {}", value)))
            },
            None => return Err(EventError(format!("couldn't find {} in event", $k)))
        }
    )
)

pub fn read_stdin() -> Result<String, SensuError> {
    match io::stdin().read_to_end() {
        Ok(input) => Ok(input.to_string()),
        Err(e) => return Err(InitError(format!("couldn't read stdin: {}", e)))
    }
}

pub fn read_event(input: &str) -> Result<Client, SensuError> {
    let event = match json::from_str(input) {
        Ok(v) => v,
        Err(e) => return Err(InitError(format!("couldn't parse json: {}", e)))
    };

    let client = try!(read_client(event));
    Ok(client)
}

fn read_client(input: Json) -> Result<Client, SensuError> {
    let event = match input.find("client") {
        Some(client) => client,
        None => return Err(InitError("No client in event".into_string()))
    };

    let unverified_subs = jk!(event->"subscriptions" List);
    let mut subs: Vec<String> = Vec::new();
    for sub in unverified_subs.iter() {
        match *sub {
            json::String(ref s) => subs.push(s.clone()),
            _ => return Err(EventError(format!("Invalid subscription type {}", sub)))
        }
    }
    let ts = match event.find("timestamp") {
        Some(value) => match value {
            &I64(ref v) => v.clone(),
            &U64(ref v) => v.clone() as i64,
            &F64(ref v) => v.clone() as i64,
            _ => return Err(EventError(format!("Wrong type for key: {}", value)))
        },
        None => return Err(EventError("couldn't find timestamp in event".into_string()))
    };
    let ts = NaiveDateTime::from_num_seconds_from_unix_epoch(ts, 0);

    let client = Client {
        name: jk!(event->"name" String),
        address: jk!(event->"address" String),
        subscriptions: subs,
        timestamp: ts,
        additional: Null
    };
    Ok(client)
}

#[cfg(test)]
mod build_objects {
    use serialize::json;
    use super::read_client;

    #[test]
    fn can_build_client() {
        let event = json::from_str(r#"{
            "client": {
                "name": "hello",
                "address": "192.168.1.1",
                "subscriptions": ["one", "two"],
                "timestamp": 127897
            }
        }"#).unwrap();
        let client = read_client(event);
        match client {
            Ok(cl) => println!("Parsed: {}", cl),
            Err(e) => panic!("ERROR: {}", e)
        }
    }
}
<|endoftext|>


<commit_before>extern crate chrono;
extern crate colored;
extern crate janus_plugin_sys as internal;

use chrono::Local;
use colored::{Color, Colorize};
use std::fmt;
use std::ffi::CString;
use std::os::raw::{c_char, c_int};
pub use internal::JANUS_PLUGIN_API_VERSION as API_VERSION;
pub use internal::janus_callbacks as PluginCallbacks;
pub use internal::janus_plugin as Plugin;
pub use internal::janus_plugin_result as PluginResult;
pub use internal::janus_plugin_result_type as PluginResultType;
pub use internal::janus_plugin_session as PluginSession;
pub use internal::json_t as Json;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum LogLevel {
    Fatal,
    Err,
    Warn,
    Info,
    Verb,
    Huge,
    Dbg,
}

impl LogLevel {
    fn color(&self) -> Option<Color> {
        match *self {
            LogLevel::Fatal => Some(Color::Magenta),
            LogLevel::Err => Some(Color::Red),
            LogLevel::Warn => Some(Color::Yellow),
            _ => None,
        }
    }
}

impl fmt::Display for LogLevel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = format!("[{:?}]", self).to_uppercase();
        match self.color() {
            Some(c) => name.color(c).fmt(f),
            None => f.write_str(&name),
        }
    }
}

pub fn log(level: LogLevel, message: &str) {
    let mut parts = Vec::<String>::new();
    if unsafe { internal::janus_log_timestamps == 1 } {
        parts.push(format!("{}", Local::now().format("[%a %b %e %T %Y]")))
    }
    if level >= LogLevel::Warn {
        parts.push(format!("{}", level));
    }
    parts.push(message.to_owned());
    let output = CString::new(parts.join(" ")).unwrap();
    unsafe { internal::janus_vprintf(output.as_ptr()) }
}

/// Represents metadata about this plugin which Janus can query at runtime.
pub struct PluginMetadata {
    pub version: c_int,
    pub version_str: *const c_char,
    pub description: *const c_char,
    pub name: *const c_char,
    pub author: *const c_char,
    pub package: *const c_char,
}

/// Helper macro to define a library as containing a Janus plugin. Should be called with
/// a PluginMetadata instance and a series of exported plugin event handlers.
#[macro_export]
macro_rules! export_plugin {
    ($md:expr, $($cb:ident),*) => {
        extern fn get_api_compatibility() -> c_int { $crate::API_VERSION }
        extern fn get_version() -> c_int { $md.version }
        extern fn get_version_string() -> *const c_char { $md.version_str }
        extern fn get_description() -> *const c_char { $md.description }
        extern fn get_name() -> *const c_char { $md.name }
        extern fn get_author() -> *const c_char { $md.author }
        extern fn get_package() -> *const c_char { $md.package }
        const PLUGIN: $crate::Plugin = $crate::Plugin {
            get_api_compatibility,
            get_version,
            get_version_string,
            get_description,
            get_name,
            get_author,
            get_package,
            $($cb,)*
        };

        /// Called by Janus to create an instance of this plugin, using the provided callbacks to dispatch events.
        #[no_mangle]
        pub extern "C" fn create() -> *const $crate::Plugin { &PLUGIN }
    }
}
<commit_msg>Fix, improve logging<commit_after>extern crate chrono;
extern crate colored;
extern crate janus_plugin_sys as internal;

use chrono::Local;
use colored::{Color, Colorize};
use std::fmt;
use std::fmt::Write;
use std::ffi::CString;
use std::os::raw::{c_char, c_int};
pub use internal::JANUS_PLUGIN_API_VERSION as API_VERSION;
pub use internal::janus_callbacks as PluginCallbacks;
pub use internal::janus_plugin as Plugin;
pub use internal::janus_plugin_result as PluginResult;
pub use internal::janus_plugin_result_type as PluginResultType;
pub use internal::janus_plugin_session as PluginSession;
pub use internal::json_t as Json;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum LogLevel {
    Dbg,
    Huge,
    Verb,
    Info,
    Warn,
    Err,
    Fatal
}

impl LogLevel {
    fn color(&self) -> Option<Color> {
        match *self {
            LogLevel::Fatal => Some(Color::Magenta),
            LogLevel::Err => Some(Color::Red),
            LogLevel::Warn => Some(Color::Yellow),
            _ => None,
        }
    }
}

impl fmt::Display for LogLevel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = format!("[{:?}]", self).to_uppercase();
        match self.color() {
            Some(c) => name.color(c).fmt(f),
            None => f.write_str(&name),
        }
    }
}

pub fn log(level: LogLevel, message: &str) {
    let mut output = String::new();
    if unsafe { internal::janus_log_timestamps == 1 } {
        write!(output, "{} ", Local::now().format("[%a %b %e %T %Y]")).unwrap()
    }
    if level >= LogLevel::Warn {
        write!(output, "{} ", level).unwrap();
    }
    output.push_str(message);
    unsafe { internal::janus_vprintf(CString::new(output).unwrap().as_ptr()) }
}

/// Represents metadata about this plugin which Janus can query at runtime.
pub struct PluginMetadata {
    pub version: c_int,
    pub version_str: *const c_char,
    pub description: *const c_char,
    pub name: *const c_char,
    pub author: *const c_char,
    pub package: *const c_char,
}

/// Helper macro to define a library as containing a Janus plugin. Should be called with
/// a PluginMetadata instance and a series of exported plugin event handlers.
#[macro_export]
macro_rules! export_plugin {
    ($md:expr, $($cb:ident),*) => {
        extern fn get_api_compatibility() -> c_int { $crate::API_VERSION }
        extern fn get_version() -> c_int { $md.version }
        extern fn get_version_string() -> *const c_char { $md.version_str }
        extern fn get_description() -> *const c_char { $md.description }
        extern fn get_name() -> *const c_char { $md.name }
        extern fn get_author() -> *const c_char { $md.author }
        extern fn get_package() -> *const c_char { $md.package }
        const PLUGIN: $crate::Plugin = $crate::Plugin {
            get_api_compatibility,
            get_version,
            get_version_string,
            get_description,
            get_name,
            get_author,
            get_package,
            $($cb,)*
        };

        /// Called by Janus to create an instance of this plugin, using the provided callbacks to dispatch events.
        #[no_mangle]
        pub extern "C" fn create() -> *const $crate::Plugin { &PLUGIN }
    }
}
<|endoftext|>