<commit_before>use std::fs::File;
use std::io::{BufReader, Read};
use std::{str, vec, fmt};
use std::path;

use scopes;
use nameres;
use ast;

#[derive(Debug,Clone,PartialEq)]
pub enum MatchType {
    Struct,
    Module,
    MatchArm,
    Function,
    Crate,
    Let,
    IfLet,
    StructField,
    Impl,
    Enum,
    EnumVariant,
    Type,
    FnArg,
    Trait,
    Const,
    Static
}

impl Copy for MatchType {}

#[derive(Debug,Clone)]
pub enum SearchType {
    ExactMatch,
    StartsWith
}

impl Copy for SearchType {}

#[derive(Debug,Clone)]
pub enum Namespace {
    TypeNamespace,
    ValueNamespace,
    BothNamespaces
}

impl Copy for Namespace {}

#[derive(Debug,Clone)]
pub enum CompletionType {
    CompleteField,
    CompletePath
}

impl Copy for CompletionType {}

#[derive(Clone)]
pub struct Match {
    pub matchstr: String,
    pub filepath: path::PathBuf,
    pub point: usize,
    pub local: bool,
    pub mtype: MatchType,
    pub contextstr: String,
    pub generic_args: Vec<String>,
    pub generic_types: Vec<PathSearch>,  // generic types are evaluated lazily
    pub session: Session
}

impl Match {
    pub fn with_generic_types(&self, generic_types: Vec<PathSearch>) -> Match {
        Match {
            matchstr: self.matchstr.clone(),
            filepath: self.filepath.clone(),
            point: self.point,
            local: self.local,
            mtype: self.mtype,
            contextstr: self.contextstr.clone(),
            generic_args: self.generic_args.clone(),
            generic_types: generic_types,
            session: self.session.clone()
        }
    }
}

impl fmt::Debug for Match {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Match [{:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?} |{}|, {:?}]",
               self.matchstr,
               self.filepath.to_str(),
               self.point,
               self.local,
               self.mtype,
               self.generic_args,
               self.generic_types,
               self.contextstr,
               self.session)
    }
}

#[derive(Clone)]
pub struct Scope {
    pub filepath: path::PathBuf,
    pub point: usize,
    pub session: Session
}

impl Scope {
    pub fn from_match(m: &Match) -> Scope {
        Scope{ filepath: m.filepath.clone(), point: m.point, session: m.session.clone() }
    }
}

impl fmt::Debug for Scope {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Scope [{:?}, {:?}, {:?}]",
               self.filepath.to_str(),
               self.point,
               self.session)
    }
}

// Represents a type. Equivilent to rustc's ast::Ty but can be passed across threads
#[derive(Debug,Clone)]
pub enum Ty {
    TyMatch(Match),
    TyPathSearch(Path, Scope),   // A path + the scope to be able to resolve it
    TyTuple(Vec<Ty>),
    TyUnsupported
}

// The racer implementation of an ast::Path. Difference is that it is Send-able
#[derive(Clone)]
pub struct Path {
    pub global: bool,
    pub segments: Vec<PathSegment>
}

impl Path {
    pub fn generic_types(&self) -> ::std::slice::Iter<Path> {
        self.segments[self.segments.len()-1].types.iter()
    }

    pub fn from_vec(global: bool, v: Vec<&str>) -> Path {
        let segs = v
            .iter()
            .map(|x| PathSegment{ name:x.to_string(), types: Vec::new() })
            .collect::<Vec<_>>();
        Path{ global: global, segments: segs }
    }

    pub fn from_svec(global: bool, v: Vec<String>) -> Path {
        let segs = v
            .iter()
            .map(|x| PathSegment{ name:x.clone(), types: Vec::new() })
            .collect::<Vec<_>>();
        Path{ global: global, segments: segs }
    }
}

impl fmt::Debug for Path {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "P["));
        let mut first = true;
        for seg in self.segments.iter() {
            if first {
                try!(write!(f, "{}", seg.name));
                first = false;
            } else {
                try!(write!(f, "::{}", seg.name));
            }

            if !seg.types.is_empty() {
                try!(write!(f, "<"));
                let mut tfirst = true;
                for typath in seg.types.iter() {
                    if tfirst {
                        try!(write!(f, "{:?}", typath));
                        tfirst = false;
                    } else {
                        try!(write!(f, ",{:?}", typath))
                    }
                }
                try!(write!(f, ">"));
            }
        }
        write!(f, "]")
    }
}

#[derive(Debug,Clone)]
pub struct PathSegment {
    pub name: String,
    pub types: Vec<Path>
}

#[derive(Clone)]
pub struct PathSearch {
    pub path: Path,
    pub filepath: path::PathBuf,
    pub point: usize,
    pub session: Session
}

impl fmt::Debug for PathSearch {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Search [{:?}, {:?}, {:?}, {:?}]",
               self.path,
               self.filepath.to_str(),
               self.point,
               self.session)
    }
}

#[derive(Debug,Clone)]
pub struct Session {
    pub query_path: path::PathBuf,            // the input path of the query
    pub substitute_file: path::PathBuf        // the temporary file
}

impl Session {
    pub fn from_path(query_path: &path::Path, substitute_file: &path::Path) -> Session {
        Session {
            query_path: query_path.to_path_buf(),
            substitute_file: substitute_file.to_path_buf()
        }
    }
}

pub fn load_file(filepath: &path::Path) -> String {
    let mut rawbytes = Vec::new();
    if let Ok(f) = File::open(filepath) {
        BufReader::new(f).read_to_end(&mut rawbytes).unwrap();
    } else {
        return "".to_string();
    }

    // skip BOF bytes, if present
    if rawbytes[0..3] == [0xEF, 0xBB, 0xBF] {
        let mut it = rawbytes.into_iter();
        it.next(); it.next(); it.next();
        return String::from_utf8(it.collect::<Vec<_>>()).unwrap();
    } else {
        return String::from_utf8(rawbytes).unwrap();
    }
}

pub fn load_file_and_mask_comments(filepath: &path::Path) -> String {
    let mut filetxt = Vec::new();
    BufReader::new(File::open(filepath).unwrap()).read_to_end(&mut filetxt).unwrap();
    let src = str::from_utf8(&filetxt).unwrap();

    scopes::mask_comments(src)
}

pub fn complete_from_file(src: &str, filepath: &path::Path, pos: usize, session: &Session) -> vec::IntoIter<Match> {
    let start = scopes::get_start_of_search_expr(src, pos);
    let expr = &src[start..pos];

    let (contextstr, searchstr, completetype) = scopes::split_into_context_and_completion(expr);

    debug!("{:?}: contextstr is |{}|, searchstr is |{}|", completetype, contextstr, searchstr);

    let mut out = Vec::new();

    match completetype {
        CompletionType::CompletePath => {
            let mut v = expr.split("::").collect::<Vec<_>>();
            let mut global = false;
            if v[0] == "" {      // i.e. starts with '::' e.g. ::std::old_io::blah
                v.remove(0);
                global = true;
            }

            let path = Path::from_vec(global, v);
            for m in nameres::resolve_path(&path, filepath, pos,
                                         SearchType::StartsWith, Namespace::BothNamespaces,
                                         session) {
                out.push(m);
            }
        },
        CompletionType::CompleteField => {
            let context = ast::get_type_of(contextstr.to_string(), filepath, pos, session);
            debug!("complete_from_file context is {:?}", context);
            context.map(|ty| {
                match ty {
                    Ty::TyMatch(m) => {
                        for m in nameres::search_for_field_or_method(m, searchstr, SearchType::StartsWith) {
                            out.push(m)
                        }
                    }
                    _ => {}
                }
            });
        }
    }
    out.into_iter()
}

pub fn find_definition(src: &str, filepath: &path::Path, pos: usize, session: &Session) -> Option<Match> {
    find_definition_(src, filepath, pos, session)
}

pub fn find_definition_(src: &str, filepath: &path::Path, pos: usize, session: &Session) -> Option<Match> {
    let (start, end) = scopes::expand_search_expr(src, pos);
    let expr = &src[start..end];

    let (contextstr, searchstr, completetype) = scopes::split_into_context_and_completion(expr);

    debug!("find_definition_ for |{:?}| |{:?}| {:?}", contextstr, searchstr, completetype);

    return match completetype {
        CompletionType::CompletePath => {
            let mut v = expr.split("::").collect::<Vec<_>>();
            let mut global = false;
            if v[0] == "" {      // i.e. starts with '::' e.g. ::std::old_io::blah
                v.remove(0);
                global = true;
            }

            let segs = v
                .iter()
                .map(|x| PathSegment{ name: x.to_string(), types: Vec::new() })
                .collect::<Vec<_>>();
            let path = Path{ global: global, segments: segs };

            return nameres::resolve_path(&path, filepath, pos,
                                         SearchType::ExactMatch, Namespace::BothNamespaces,
                                         session).nth(0);
        },
        CompletionType::CompleteField => {
            let context = ast::get_type_of(contextstr.to_string(), filepath, pos, session);
            debug!("context is {:?}", context);

            return context.and_then(|ty| {
                // for now, just handle matches
                match ty {
                    Ty::TyMatch(m) => {
                        return nameres::search_for_field_or_method(m, searchstr, SearchType::ExactMatch).nth(0);
                    }
                    _ => None
                }
            });
        }
    }
}
<commit_msg>fix out-of-bounds panic in BOF handling. Fixes #331<commit_after>use std::fs::File;
use std::io::{BufReader, Read};
use std::{str, vec, fmt};
use std::path;

use scopes;
use nameres;
use ast;

#[derive(Debug,Clone,PartialEq)]
pub enum MatchType {
    Struct,
    Module,
    MatchArm,
    Function,
    Crate,
    Let,
    IfLet,
    StructField,
    Impl,
    Enum,
    EnumVariant,
    Type,
    FnArg,
    Trait,
    Const,
    Static
}

impl Copy for MatchType {}

#[derive(Debug,Clone)]
pub enum SearchType {
    ExactMatch,
    StartsWith
}

impl Copy for SearchType {}

#[derive(Debug,Clone)]
pub enum Namespace {
    TypeNamespace,
    ValueNamespace,
    BothNamespaces
}

impl Copy for Namespace {}

#[derive(Debug,Clone)]
pub enum CompletionType {
    CompleteField,
    CompletePath
}

impl Copy for CompletionType {}

#[derive(Clone)]
pub struct Match {
    pub matchstr: String,
    pub filepath: path::PathBuf,
    pub point: usize,
    pub local: bool,
    pub mtype: MatchType,
    pub contextstr: String,
    pub generic_args: Vec<String>,
    pub generic_types: Vec<PathSearch>,  // generic types are evaluated lazily
    pub session: Session
}

impl Match {
    pub fn with_generic_types(&self, generic_types: Vec<PathSearch>) -> Match {
        Match {
            matchstr: self.matchstr.clone(),
            filepath: self.filepath.clone(),
            point: self.point,
            local: self.local,
            mtype: self.mtype,
            contextstr: self.contextstr.clone(),
            generic_args: self.generic_args.clone(),
            generic_types: generic_types,
            session: self.session.clone()
        }
    }
}

impl fmt::Debug for Match {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Match [{:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?} |{}|, {:?}]",
               self.matchstr,
               self.filepath.to_str(),
               self.point,
               self.local,
               self.mtype,
               self.generic_args,
               self.generic_types,
               self.contextstr,
               self.session)
    }
}

#[derive(Clone)]
pub struct Scope {
    pub filepath: path::PathBuf,
    pub point: usize,
    pub session: Session
}

impl Scope {
    pub fn from_match(m: &Match) -> Scope {
        Scope{ filepath: m.filepath.clone(), point: m.point, session: m.session.clone() }
    }
}

impl fmt::Debug for Scope {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Scope [{:?}, {:?}, {:?}]",
               self.filepath.to_str(),
               self.point,
               self.session)
    }
}

// Represents a type. Equivilent to rustc's ast::Ty but can be passed across threads
#[derive(Debug,Clone)]
pub enum Ty {
    TyMatch(Match),
    TyPathSearch(Path, Scope),   // A path + the scope to be able to resolve it
    TyTuple(Vec<Ty>),
    TyUnsupported
}

// The racer implementation of an ast::Path. Difference is that it is Send-able
#[derive(Clone)]
pub struct Path {
    pub global: bool,
    pub segments: Vec<PathSegment>
}

impl Path {
    pub fn generic_types(&self) -> ::std::slice::Iter<Path> {
        self.segments[self.segments.len()-1].types.iter()
    }

    pub fn from_vec(global: bool, v: Vec<&str>) -> Path {
        let segs = v
            .iter()
            .map(|x| PathSegment{ name:x.to_string(), types: Vec::new() })
            .collect::<Vec<_>>();
        Path{ global: global, segments: segs }
    }

    pub fn from_svec(global: bool, v: Vec<String>) -> Path {
        let segs = v
            .iter()
            .map(|x| PathSegment{ name:x.clone(), types: Vec::new() })
            .collect::<Vec<_>>();
        Path{ global: global, segments: segs }
    }
}

impl fmt::Debug for Path {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "P["));
        let mut first = true;
        for seg in self.segments.iter() {
            if first {
                try!(write!(f, "{}", seg.name));
                first = false;
            } else {
                try!(write!(f, "::{}", seg.name));
            }

            if !seg.types.is_empty() {
                try!(write!(f, "<"));
                let mut tfirst = true;
                for typath in seg.types.iter() {
                    if tfirst {
                        try!(write!(f, "{:?}", typath));
                        tfirst = false;
                    } else {
                        try!(write!(f, ",{:?}", typath))
                    }
                }
                try!(write!(f, ">"));
            }
        }
        write!(f, "]")
    }
}

#[derive(Debug,Clone)]
pub struct PathSegment {
    pub name: String,
    pub types: Vec<Path>
}

#[derive(Clone)]
pub struct PathSearch {
    pub path: Path,
    pub filepath: path::PathBuf,
    pub point: usize,
    pub session: Session
}

impl fmt::Debug for PathSearch {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Search [{:?}, {:?}, {:?}, {:?}]",
               self.path,
               self.filepath.to_str(),
               self.point,
               self.session)
    }
}

#[derive(Debug,Clone)]
pub struct Session {
    pub query_path: path::PathBuf,            // the input path of the query
    pub substitute_file: path::PathBuf        // the temporary file
}

impl Session {
    pub fn from_path(query_path: &path::Path, substitute_file: &path::Path) -> Session {
        Session {
            query_path: query_path.to_path_buf(),
            substitute_file: substitute_file.to_path_buf()
        }
    }
}

pub fn load_file(filepath: &path::Path) -> String {
    let mut rawbytes = Vec::new();
    if let Ok(f) = File::open(filepath) {
        BufReader::new(f).read_to_end(&mut rawbytes).unwrap();
    } else {
        return "".to_string();
    }

    // skip BOF bytes, if present
    if rawbytes.len() > 2 && rawbytes[0..3] == [0xEF, 0xBB, 0xBF] {
        let mut it = rawbytes.into_iter();
        it.next(); it.next(); it.next();
        return String::from_utf8(it.collect::<Vec<_>>()).unwrap();
    } else {
        return String::from_utf8(rawbytes).unwrap();
    }
}

pub fn load_file_and_mask_comments(filepath: &path::Path) -> String {
    let mut filetxt = Vec::new();
    BufReader::new(File::open(filepath).unwrap()).read_to_end(&mut filetxt).unwrap();
    let src = str::from_utf8(&filetxt).unwrap();

    scopes::mask_comments(src)
}

pub fn complete_from_file(src: &str, filepath: &path::Path, pos: usize, session: &Session) -> vec::IntoIter<Match> {
    let start = scopes::get_start_of_search_expr(src, pos);
    let expr = &src[start..pos];

    let (contextstr, searchstr, completetype) = scopes::split_into_context_and_completion(expr);

    debug!("{:?}: contextstr is |{}|, searchstr is |{}|", completetype, contextstr, searchstr);

    let mut out = Vec::new();

    match completetype {
        CompletionType::CompletePath => {
            let mut v = expr.split("::").collect::<Vec<_>>();
            let mut global = false;
            if v[0] == "" {      // i.e. starts with '::' e.g. ::std::old_io::blah
                v.remove(0);
                global = true;
            }

            let path = Path::from_vec(global, v);
            for m in nameres::resolve_path(&path, filepath, pos,
                                         SearchType::StartsWith, Namespace::BothNamespaces,
                                         session) {
                out.push(m);
            }
        },
        CompletionType::CompleteField => {
            let context = ast::get_type_of(contextstr.to_string(), filepath, pos, session);
            debug!("complete_from_file context is {:?}", context);
            context.map(|ty| {
                match ty {
                    Ty::TyMatch(m) => {
                        for m in nameres::search_for_field_or_method(m, searchstr, SearchType::StartsWith) {
                            out.push(m)
                        }
                    }
                    _ => {}
                }
            });
        }
    }
    out.into_iter()
}

pub fn find_definition(src: &str, filepath: &path::Path, pos: usize, session: &Session) -> Option<Match> {
    find_definition_(src, filepath, pos, session)
}

pub fn find_definition_(src: &str, filepath: &path::Path, pos: usize, session: &Session) -> Option<Match> {
    let (start, end) = scopes::expand_search_expr(src, pos);
    let expr = &src[start..end];

    let (contextstr, searchstr, completetype) = scopes::split_into_context_and_completion(expr);

    debug!("find_definition_ for |{:?}| |{:?}| {:?}", contextstr, searchstr, completetype);

    return match completetype {
        CompletionType::CompletePath => {
            let mut v = expr.split("::").collect::<Vec<_>>();
            let mut global = false;
            if v[0] == "" {      // i.e. starts with '::' e.g. ::std::old_io::blah
                v.remove(0);
                global = true;
            }

            let segs = v
                .iter()
                .map(|x| PathSegment{ name: x.to_string(), types: Vec::new() })
                .collect::<Vec<_>>();
            let path = Path{ global: global, segments: segs };

            return nameres::resolve_path(&path, filepath, pos,
                                         SearchType::ExactMatch, Namespace::BothNamespaces,
                                         session).nth(0);
        },
        CompletionType::CompleteField => {
            let context = ast::get_type_of(contextstr.to_string(), filepath, pos, session);
            debug!("context is {:?}", context);

            return context.and_then(|ty| {
                // for now, just handle matches
                match ty {
                    Ty::TyMatch(m) => {
                        return nameres::search_for_field_or_method(m, searchstr, SearchType::ExactMatch).nth(0);
                    }
                    _ => None
                }
            });
        }
    }
}
<|endoftext|>


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

#[cfg(feature = "nightly")]
use std::sync::atomic::{AtomicUsize, Ordering};
#[cfg(not(feature = "nightly"))]
use stable::{AtomicUsize, Ordering};
use std::thread;
use parking_lot::{self, UnparkResult};
use SPIN_LIMIT;

const SHARED_PARKED_BIT: usize = 1;
const EXCLUSIVE_PARKED_BIT: usize = 2;
const EXCLUSIVE_LOCKED_BIT: usize = 4;
const SHARED_COUNT_MASK: usize = !7;
const SHARED_COUNT_INC: usize = 8;

pub struct RawRwLock {
    state: AtomicUsize,
}

impl RawRwLock {
    #[cfg(feature = "nightly")]
    #[inline]
    pub const fn new() -> RawRwLock {
        RawRwLock { state: AtomicUsize::new(0) }
    }
    #[cfg(not(feature = "nightly"))]
    #[inline]
    pub fn new() -> RawRwLock {
        RawRwLock { state: AtomicUsize::new(0) }
    }

    #[inline]
    pub fn lock_exclusive(&self) {
        if self.state
            .compare_exchange_weak(0,
                                   EXCLUSIVE_LOCKED_BIT,
                                   Ordering::Acquire,
                                   Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.lock_exclusive_slow();
    }

    #[inline]
    pub fn try_lock_exclusive(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & (EXCLUSIVE_LOCKED_BIT | SHARED_COUNT_MASK) != 0 {
                return false;
            }
            match self.state.compare_exchange_weak(state,
                                                   state | EXCLUSIVE_LOCKED_BIT,
                                                   Ordering::Acquire,
                                                   Ordering::Relaxed) {
                Ok(_) => return true,
                Err(x) => state = x,
            }
        }
    }

    #[inline]
    pub fn unlock_exclusive(&self) {
        if self.state
            .compare_exchange_weak(EXCLUSIVE_LOCKED_BIT,
                                   0,
                                   Ordering::Release,
                                   Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.unlock_exclusive_slow();
    }

    #[inline]
    pub fn lock_shared(&self) {
        let state = self.state.load(Ordering::Relaxed);
        if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) == 0 &&
           self.state
            .compare_exchange_weak(state,
                                   state.checked_add(SHARED_COUNT_INC)
                                       .expect("RwLock shared count overflow"),
                                   Ordering::Acquire,
                                   Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.lock_shared_slow();
    }

    #[inline]
    pub fn try_lock_shared(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) != 0 {
                return false;
            }
            match self.state.compare_exchange_weak(state,
                                                   state.checked_add(SHARED_COUNT_INC)
                                                       .expect("RwLock shared count overflow"),
                                                   Ordering::Acquire,
                                                   Ordering::Relaxed) {
                Ok(_) => return true,
                Err(x) => state = x,
            }
        }
    }

    #[inline]
    pub fn unlock_shared(&self) {
        let state = self.state.load(Ordering::Relaxed);
        if (state & EXCLUSIVE_PARKED_BIT == 0 || state & SHARED_COUNT_MASK != SHARED_COUNT_INC) &&
           self.state
            .compare_exchange_weak(state,
                                   state - SHARED_COUNT_INC,
                                   Ordering::Release,
                                   Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.unlock_shared_slow();
    }

    #[cold]
    #[inline(never)]
    fn lock_exclusive_slow(&self) {
        let mut spin_count = 0;
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Grab the lock if it isn't locked, even if there are other
            // threads parked.
            if state & (EXCLUSIVE_LOCKED_BIT | SHARED_COUNT_MASK) == 0 {
                match self.state
                    .compare_exchange_weak(state,
                                           state | EXCLUSIVE_LOCKED_BIT,
                                           Ordering::Acquire,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there are no parked exclusive threads, try spinning a few
            // times
            if state & EXCLUSIVE_PARKED_BIT == 0 && spin_count < SPIN_LIMIT {
                spin_count += 1;
                thread::yield_now();
                state = self.state.load(Ordering::Relaxed);
                continue;
            }

            // Set the parked bit
            if state & EXCLUSIVE_PARKED_BIT == 0 {
                if let Err(x) = self.state.compare_exchange_weak(state,
                                                                 state | EXCLUSIVE_PARKED_BIT,
                                                                 Ordering::Relaxed,
                                                                 Ordering::Relaxed) {
                    state = x;
                    continue;
                }
            }

            // Park our thread until we are woken up by an unlock
            unsafe {
                let addr = self as *const _ as usize;
                let validate = &mut || {
                    self.state.load(Ordering::Relaxed) &
                    (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) ==
                    EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT
                };
                let before_sleep = &mut || {};
                let timed_out = &mut |_, _| unreachable!();
                if parking_lot::park(addr, validate, before_sleep, timed_out, None) {
                    // If we successfully parked then the lock will be handed
                    // off to us.
                    return;
                }
            }

            // Loop back and try locking again
            state = self.state.load(Ordering::Relaxed);
        }
    }

    #[cold]
    #[inline(never)]
    fn unlock_exclusive_slow(&self) {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Unlock directly if there are no parked threads
            if state & (EXCLUSIVE_PARKED_BIT | SHARED_PARKED_BIT) == 0 {
                match self.state
                    .compare_exchange_weak(EXCLUSIVE_LOCKED_BIT,
                                           0,
                                           Ordering::Release,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there are exclusive parked threads, hand off the lock to one
            // of them without unlocking it. This is needed to avoid writer
            // starvation.
            if state & EXCLUSIVE_PARKED_BIT != 0 {
                unsafe {
                    let addr = self as *const _ as usize;
                    let callback = &mut |result| {
                        // Clear the exclusive parked bit if this was the last
                        // thread
                        if result != UnparkResult::UnparkedNotLast {
                            self.state.fetch_and(!EXCLUSIVE_PARKED_BIT, Ordering::Relaxed);
                        }
                    };
                    if parking_lot::unpark_one(addr, callback) != UnparkResult::NoParkedThreads {
                        // We successfully unparked an exclusive thread and the
                        // lock has been handed off to it.
                        return;
                    }
                }
            }

            // Release the exclusive lock and clear the shared parked bit
            if let Err(x) = self.state
                .compare_exchange_weak(EXCLUSIVE_LOCKED_BIT | SHARED_PARKED_BIT,
                                       0,
                                       Ordering::Release,
                                       Ordering::Relaxed) {
                state = x;
                continue;
            }

            // Unpark all waiting shared threads.
            unsafe {
                let addr = self as *const _ as usize;
                parking_lot::unpark_all(addr + 1);
            }
            break;
        }
    }

    #[cold]
    #[inline(never)]
    fn lock_shared_slow(&self) {
        let mut spin_count = 0;
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Grab the lock if there are no exclusive threads locked or waiting
            if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) == 0 {
                match self.state
                    .compare_exchange_weak(state,
                                           state.checked_add(SHARED_COUNT_INC)
                                               .expect("RwLock shared count overflow"),
                                           Ordering::Acquire,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there are no parked exclusive threads, try spinning a few
            // times
            if state & EXCLUSIVE_PARKED_BIT == 0 && spin_count < SPIN_LIMIT {
                spin_count += 1;
                thread::yield_now();
                state = self.state.load(Ordering::Relaxed);
                continue;
            }

            // Set the shared parked bit
            if state & SHARED_PARKED_BIT == 0 {
                if let Err(x) = self.state.compare_exchange_weak(state,
                                                                 state | SHARED_PARKED_BIT,
                                                                 Ordering::Relaxed,
                                                                 Ordering::Relaxed) {
                    state = x;
                    continue;
                }
            }

            // Park our thread until we are woken up by an unlock
            unsafe {
                let addr = self as *const _ as usize;
                let validate = &mut || {
                    self.state.load(Ordering::Relaxed) &
                    (EXCLUSIVE_LOCKED_BIT | SHARED_PARKED_BIT) ==
                    EXCLUSIVE_LOCKED_BIT | SHARED_PARKED_BIT
                };
                let before_sleep = &mut || {};
                let timed_out = &mut |_, _| unreachable!();
                parking_lot::park(addr + 1, validate, before_sleep, timed_out, None);
            }

            // Loop back and try locking again
            state = self.state.load(Ordering::Relaxed);
        }
    }

    #[cold]
    #[inline(never)]
    fn unlock_shared_slow(&self) {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Unlock directly if there are no parked threads or if there are
            // still remaining shared threads
            if state & EXCLUSIVE_PARKED_BIT == 0 || state & SHARED_COUNT_MASK != SHARED_COUNT_INC {
                match self.state
                    .compare_exchange_weak(state,
                                           state - SHARED_COUNT_INC,
                                           Ordering::Release,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // At this point we are the last shared thread and we need to wake
            // up one exclusive thread to pass the lock to.
            unsafe {
                let addr = self as *const _ as usize;
                let callback = &mut |result| {
                    // Clear the exclusive parked bit if this was the last
                    // thread
                    if result != UnparkResult::UnparkedNotLast {
                        self.state.fetch_and(!EXCLUSIVE_PARKED_BIT, Ordering::Relaxed);
                    }
                };
                if parking_lot::unpark_one(addr, callback) != UnparkResult::NoParkedThreads {
                    // We successfully unparked an exclusive thread and the lock
                    // has been handed off to it.
                    return;
                }
            }

            // There was no exclusive thread to wake up, so just loop back again
            // and try to release the lock normally.
            state = self.state.load(Ordering::Relaxed);
        }
    }
}
<commit_msg>New RwLock algorithm which should scale much better<commit_after>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

#[cfg(feature = "nightly")]
use std::sync::atomic::{AtomicUsize, Ordering};
#[cfg(not(feature = "nightly"))]
use stable::{AtomicUsize, Ordering};
use std::thread;
use parking_lot::{self, UnparkResult};
use SPIN_LIMIT;

const SHARED_PARKED_BIT: usize = 1;
const EXCLUSIVE_PARKED_BIT: usize = 2;
const EXCLUSIVE_LOCKED_BIT: usize = 4;
const SHARED_COUNT_MASK: usize = !7;
const SHARED_COUNT_INC: usize = 8;

pub struct RawRwLock {
    state: AtomicUsize,
}

impl RawRwLock {
    #[cfg(feature = "nightly")]
    #[inline]
    pub const fn new() -> RawRwLock {
        RawRwLock { state: AtomicUsize::new(0) }
    }
    #[cfg(not(feature = "nightly"))]
    #[inline]
    pub fn new() -> RawRwLock {
        RawRwLock { state: AtomicUsize::new(0) }
    }

    #[inline]
    pub fn lock_exclusive(&self) {
        if self.state
            .compare_exchange_weak(0,
                                   EXCLUSIVE_LOCKED_BIT,
                                   Ordering::Acquire,
                                   Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.lock_exclusive_slow();
    }

    #[inline]
    pub fn try_lock_exclusive(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & (EXCLUSIVE_LOCKED_BIT | SHARED_COUNT_MASK) != 0 {
                return false;
            }
            match self.state.compare_exchange_weak(state,
                                                   state | EXCLUSIVE_LOCKED_BIT,
                                                   Ordering::Acquire,
                                                   Ordering::Relaxed) {
                Ok(_) => return true,
                Err(x) => state = x,
            }
        }
    }

    #[inline]
    pub fn unlock_exclusive(&self) {
        if self.state
            .compare_exchange_weak(EXCLUSIVE_LOCKED_BIT,
                                   0,
                                   Ordering::Release,
                                   Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.unlock_exclusive_slow();
    }

    #[inline]
    pub fn lock_shared(&self) {
        let state = self.state.load(Ordering::Relaxed);
        if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) == 0 &&
           self.state
            .compare_exchange_weak(state,
                                   state.checked_add(SHARED_COUNT_INC)
                                       .expect("RwLock shared count overflow"),
                                   Ordering::Acquire,
                                   Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.lock_shared_slow();
    }

    #[inline]
    pub fn try_lock_shared(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) != 0 {
                return false;
            }
            match self.state.compare_exchange_weak(state,
                                                   state.checked_add(SHARED_COUNT_INC)
                                                       .expect("RwLock shared count overflow"),
                                                   Ordering::Acquire,
                                                   Ordering::Relaxed) {
                Ok(_) => return true,
                Err(x) => state = x,
            }
        }
    }

    #[inline]
    pub fn unlock_shared(&self) {
        let state = self.state.load(Ordering::Relaxed);
        if (state & EXCLUSIVE_PARKED_BIT == 0 || state & SHARED_COUNT_MASK != SHARED_COUNT_INC) &&
           self.state
            .compare_exchange_weak(state,
                                   state - SHARED_COUNT_INC,
                                   Ordering::Release,
                                   Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.unlock_shared_slow();
    }

    #[cold]
    #[inline(never)]
    fn lock_exclusive_slow(&self) {
        let mut spin_count = 0;
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Grab the lock if it isn't locked, even if there are other
            // threads parked.
            if state & (EXCLUSIVE_LOCKED_BIT | SHARED_COUNT_MASK) == 0 {
                match self.state
                    .compare_exchange_weak(state,
                                           state | EXCLUSIVE_LOCKED_BIT,
                                           Ordering::Acquire,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there are no parked exclusive threads and only one reader or
            // writer, try spinning a few times.
            if state & EXCLUSIVE_PARKED_BIT == 0 &&
               (state & EXCLUSIVE_LOCKED_BIT != 0 ||
                state & SHARED_COUNT_MASK == SHARED_COUNT_INC) &&
               spin_count < SPIN_LIMIT {
                spin_count += 1;
                thread::yield_now();
                state = self.state.load(Ordering::Relaxed);
                continue;
            }

            // Set the parked bit
            if state & EXCLUSIVE_PARKED_BIT == 0 {
                if let Err(x) = self.state.compare_exchange_weak(state,
                                                                 state | EXCLUSIVE_PARKED_BIT,
                                                                 Ordering::Relaxed,
                                                                 Ordering::Relaxed) {
                    state = x;
                    continue;
                }
            }

            // Park our thread until we are woken up by an unlock
            unsafe {
                let addr = self as *const _ as usize;
                let validate = &mut || {
                    let state = self.state.load(Ordering::Relaxed);
                    state & EXCLUSIVE_PARKED_BIT != 0 &&
                    state & (EXCLUSIVE_LOCKED_BIT | SHARED_COUNT_MASK) != 0
                };
                let before_sleep = &mut || {};
                let timed_out = &mut |_, _| unreachable!();
                parking_lot::park(addr, validate, before_sleep, timed_out, None);
            }

            // Loop back and try locking again
            state = self.state.load(Ordering::Relaxed);
        }
    }

    #[cold]
    #[inline(never)]
    fn unlock_exclusive_slow(&self) {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Unlock directly if there are no parked threads
            if state & (EXCLUSIVE_PARKED_BIT | SHARED_PARKED_BIT) == 0 {
                match self.state
                    .compare_exchange_weak(EXCLUSIVE_LOCKED_BIT,
                                           0,
                                           Ordering::Release,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there are exclusive parked threads, wake one of them up.
            if state & EXCLUSIVE_PARKED_BIT != 0 {
                unsafe {
                    let addr = self as *const _ as usize;
                    let callback = &mut |result| {
                        // Clear the exclusive parked bit if this was the last
                        // exclusive thread. Also clear the locked bit if we
                        // successfully unparked a thread.
                        match result {
                            UnparkResult::UnparkedNotLast => {
                                self.state.fetch_and(!EXCLUSIVE_LOCKED_BIT, Ordering::Release)
                            }
                            UnparkResult::UnparkedLast => {
                                self.state
                                    .fetch_and(!(EXCLUSIVE_PARKED_BIT | EXCLUSIVE_LOCKED_BIT),
                                               Ordering::Release)
                            }
                            UnparkResult::NoParkedThreads => {
                                self.state.fetch_and(!EXCLUSIVE_PARKED_BIT, Ordering::Relaxed)
                            }
                        };
                    };
                    if parking_lot::unpark_one(addr, callback) != UnparkResult::NoParkedThreads {
                        // If we successfully unparked an exclusive thread,
                        // stop here.
                        return;
                    }
                }
            }

            // Release the exclusive lock and clear the shared parked bit
            if let Err(x) = self.state
                .compare_exchange_weak(EXCLUSIVE_LOCKED_BIT | SHARED_PARKED_BIT,
                                       0,
                                       Ordering::Release,
                                       Ordering::Relaxed) {
                state = x;
                continue;
            }

            // Unpark all waiting shared threads.
            unsafe {
                let addr = self as *const _ as usize;
                parking_lot::unpark_all(addr + 1);
            }
            break;
        }
    }

    #[cold]
    #[inline(never)]
    fn lock_shared_slow(&self) {
        let mut spin_count = 0;
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Grab the lock if there are no exclusive threads locked or waiting
            if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) == 0 {
                match self.state
                    .compare_exchange_weak(state,
                                           state.checked_add(SHARED_COUNT_INC)
                                               .expect("RwLock shared count overflow"),
                                           Ordering::Acquire,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there are no parked exclusive threads, try spinning a few
            // times
            if state & EXCLUSIVE_PARKED_BIT == 0 && spin_count < SPIN_LIMIT {
                spin_count += 1;
                thread::yield_now();
                state = self.state.load(Ordering::Relaxed);
                continue;
            }

            // Set the shared parked bit
            if state & SHARED_PARKED_BIT == 0 {
                if let Err(x) = self.state.compare_exchange_weak(state,
                                                                 state | SHARED_PARKED_BIT,
                                                                 Ordering::Relaxed,
                                                                 Ordering::Relaxed) {
                    state = x;
                    continue;
                }
            }

            // Park our thread until we are woken up by an unlock
            unsafe {
                let addr = self as *const _ as usize;
                let validate = &mut || {
                    let state = self.state.load(Ordering::Relaxed);
                    state & SHARED_PARKED_BIT != 0 &&
                    state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) != 0
                };
                let before_sleep = &mut || {};
                let timed_out = &mut |_, _| unreachable!();
                parking_lot::park(addr + 1, validate, before_sleep, timed_out, None);
            }

            // Loop back and try locking again
            state = self.state.load(Ordering::Relaxed);
        }
    }

    #[cold]
    #[inline(never)]
    fn unlock_shared_slow(&self) {
        // Decrement the shared lock count
        let mut state = self.state.fetch_sub(SHARED_COUNT_INC, Ordering::Release) -
                        SHARED_COUNT_INC;

        // If this was the last shared thread and there are exclusive parked
        // threads then wake one up.
        if state & EXCLUSIVE_PARKED_BIT != 0 && state & SHARED_COUNT_MASK == 0 {
            unsafe {
                let addr = self as *const _ as usize;
                let callback = &mut |result| {
                    // Clear the exclusive parked bit if this was the last
                    // exclusive thread
                    if result != UnparkResult::UnparkedNotLast {
                        self.state.fetch_and(!EXCLUSIVE_PARKED_BIT, Ordering::Relaxed);
                    }
                };
                if parking_lot::unpark_one(addr, callback) != UnparkResult::NoParkedThreads {
                    // If we successfully unparked an exclusive thread,
                    // stop here.
                    return;
                }

                state = self.state.load(Ordering::Relaxed);
            }
        }

        // If there are any shared parked threads and no parked exclusive
        // threads then unparked all shared threads.
        if state & EXCLUSIVE_PARKED_BIT == 0 && state & SHARED_PARKED_BIT != 0 {
            if self.state.fetch_and(!SHARED_PARKED_BIT, Ordering::Relaxed) & SHARED_PARKED_BIT !=
               0 {
                unsafe {
                    let addr = self as *const _ as usize;
                    parking_lot::unpark_all(addr + 1);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std;
use std::io::prelude::*;
use std::net::UdpSocket;
use std::fmt;

use log;
use log::{Log, LogRecord, LogLevel, LogMetadata, LogLevelFilter};
use flate2::Compression;
use flate2::write::GzEncoder;
use chrono::{DateTime, UTC};
use serde_json;

pub struct GraylogLogger<'a> {
    server: &'a str,
    sock: UdpSocket,
    level: LogLevel,
    hostname: String,
}

#[derive(Serialize, Deserialize)]
struct Gelf {
    version: String,
    host: String,
    short_message: String,
    full_message: Option<String>,
    timestamp: Option<i64>,
    level: Option<u8>,
}

#[derive(Debug)]
pub enum GraylogError {
    SetLoggerError(log::SetLoggerError),
    Io(std::io::Error),
    JsonError(serde_json::Error),
}

impl fmt::Display for GraylogError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GraylogError::SetLoggerError(ref err) => err.fmt(f),
            GraylogError::Io(ref err) => err.fmt(f),
            GraylogError::JsonError(ref err) => err.fmt(f),
        }
    }
}

impl std::error::Error for GraylogError {
    fn description(&self) -> &str {
        match *self {
            GraylogError::SetLoggerError(ref err) => err.description(),
            GraylogError::Io(ref err) => err.description(),
            GraylogError::JsonError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            GraylogError::SetLoggerError(ref err) => Some(err),
            GraylogError::Io(ref err) => Some(err),
            GraylogError::JsonError(ref err) => Some(err),
        }
    }
}

impl From<log::SetLoggerError> for GraylogError {
    fn from(err: log::SetLoggerError) -> GraylogError {
        GraylogError::SetLoggerError(err)
    }
}

impl From<std::io::Error> for GraylogError {
    fn from(err: std::io::Error) -> GraylogError {
        GraylogError::Io(err)
    }
}

impl From<serde_json::Error> for GraylogError {
    fn from(err: serde_json::Error) -> GraylogError {
        GraylogError::JsonError(err)
    }
}

impl<'a> GraylogLogger<'a> {
    pub fn init() -> Result<(), GraylogError> {
        use log;
        use std::process::Command;
        let sock = try!(UdpSocket::bind("0.0.0.0:0"));

        try!(log::set_logger(|max_log_level| {
            max_log_level.set(LogLevelFilter::Debug);
            let hostname = Command::new("hostname")
                .arg("-f")
                .output()
                .map(|out| String::from_utf8_lossy(&out.stdout).into_owned())
                .unwrap_or("unknown".to_string());

            Box::new(GraylogLogger {
                level: LogLevel::Debug,
                server: "192.168.99.100:5555",
                sock: sock,
                hostname: hostname,
            })
        }));
        Ok(())
    }

    fn send_as_gelf(&self, record: &LogRecord) -> Result<usize, GraylogError> {
        let mut e = GzEncoder::new(Vec::new(), Compression::Default);
        let utc: DateTime<UTC> = UTC::now();

        let gelf = Gelf {
            version: "1.1".to_string(),
            short_message: format!("{}", record.args()),
            full_message: None,
            timestamp: Some(utc.timestamp()),
            level: None,
            host: self.hostname.clone(),
        };

        let json = try!(serde_json::to_string(&gelf));
        // println!("gelf json:\n {}", json);
        try!(e.write(json.as_bytes()));

        let compressed_bytes = try!(e.finish());
        self.send(&compressed_bytes)
    }

    fn send(&self, buffer: &[u8]) -> Result<usize, GraylogError> {
        let s = try!(self.sock.send_to(buffer, self.server).or_else(|e| {
            println!("Error writing to Graylog: {}", e);
            Err(e)
        }));
        Ok(s)
    }
}

impl<'a> Log for GraylogLogger<'a> {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            if self.send_as_gelf(record).is_err() {
                println!("{} {} - {}", UTC::now(), record.level(), record.args());
            };
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_it_works() {
        assert!(true);
    }
}
<commit_msg>moves the init call to the module level <commit_after>use std;
use std::io::prelude::*;
use std::net::UdpSocket;
use std::fmt;

use log;
use log::{Log, LogRecord, LogLevel, LogMetadata, LogLevelFilter};
use flate2::Compression;
use flate2::write::GzEncoder;
use chrono::{DateTime, UTC};
use serde_json;

pub struct GraylogLogger<'a> {
    server: &'a str,
    sock: UdpSocket,
    level: LogLevel,
    hostname: String,
}

#[derive(Serialize, Deserialize)]
struct Gelf {
    version: String,
    host: String,
    short_message: String,
    full_message: Option<String>,
    timestamp: Option<i64>,
    level: Option<u8>,
}

#[derive(Debug)]
pub enum GraylogError {
    SetLoggerError(log::SetLoggerError),
    Io(std::io::Error),
    JsonError(serde_json::Error),
}

impl fmt::Display for GraylogError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GraylogError::SetLoggerError(ref err) => err.fmt(f),
            GraylogError::Io(ref err) => err.fmt(f),
            GraylogError::JsonError(ref err) => err.fmt(f),
        }
    }
}

impl std::error::Error for GraylogError {
    fn description(&self) -> &str {
        match *self {
            GraylogError::SetLoggerError(ref err) => err.description(),
            GraylogError::Io(ref err) => err.description(),
            GraylogError::JsonError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            GraylogError::SetLoggerError(ref err) => Some(err),
            GraylogError::Io(ref err) => Some(err),
            GraylogError::JsonError(ref err) => Some(err),
        }
    }
}

impl From<log::SetLoggerError> for GraylogError {
    fn from(err: log::SetLoggerError) -> GraylogError {
        GraylogError::SetLoggerError(err)
    }
}

impl From<std::io::Error> for GraylogError {
    fn from(err: std::io::Error) -> GraylogError {
        GraylogError::Io(err)
    }
}

impl From<serde_json::Error> for GraylogError {
    fn from(err: serde_json::Error) -> GraylogError {
        GraylogError::JsonError(err)
    }
}

pub fn init() -> Result<(), GraylogError> {
    use log;
    use std::process::Command;
    let sock = try!(UdpSocket::bind("0.0.0.0:0"));

    try!(log::set_logger(|max_log_level| {
        max_log_level.set(LogLevelFilter::Debug);
        let hostname = Command::new("hostname")
            .arg("-f")
            .output()
            .map(|out| String::from_utf8_lossy(&out.stdout).into_owned())
            .unwrap_or("unknown".to_string());

        Box::new(GraylogLogger {
            level: LogLevel::Debug,
            server: "192.168.99.100:5555",
            sock: sock,
            hostname: hostname,
        })
    }));
    Ok(())
}

impl<'a> GraylogLogger<'a> {
    fn send_as_gelf(&self, record: &LogRecord) -> Result<usize, GraylogError> {
        let mut e = GzEncoder::new(Vec::new(), Compression::Default);
        let utc: DateTime<UTC> = UTC::now();

        let gelf = Gelf {
            version: "1.1".to_string(),
            short_message: format!("{}", record.args()),
            full_message: None,
            timestamp: Some(utc.timestamp()),
            level: None,
            host: self.hostname.clone(),
        };

        let json = try!(serde_json::to_string(&gelf));
        // println!("gelf json:\n {}", json);
        try!(e.write(json.as_bytes()));

        let compressed_bytes = try!(e.finish());
        self.send(&compressed_bytes)
    }

    fn send(&self, buffer: &[u8]) -> Result<usize, GraylogError> {
        let s = try!(self.sock.send_to(buffer, self.server).or_else(|e| {
            println!("Error writing to Graylog: {}", e);
            Err(e)
        }));
        Ok(s)
    }
}

impl<'a> Log for GraylogLogger<'a> {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            if self.send_as_gelf(record).is_err() {
                println!("{} {} - {}", UTC::now(), record.level(), record.args());
            };
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_it_works() {
        assert!(true);
    }
}
<|endoftext|>


<commit_before>/// Macro that generates a `struct` implementation of a specified trait.
///
/// This macro generates a `struct` that implements the traits `Clone`, `Debug`
/// and `Default`. Create instances of the mock object by calling the `struct`'s
/// `default()` method.
///
/// The `struct` has a field for each method of the `trait`, which manages their
/// respective method's behaviour and call expectations. For example, if one
/// defines a mock like so:
///
/// ```
/// # #[macro_use] extern crate double;
///
/// mock_trait!(
///     MockTaskManager,
///     max_threads(()) -> u32,
///     set_max_threads(u32) -> ()
/// );
///
/// # fn main() {
///     // only here to make `cargo test` happy
/// }
/// ```
///
/// Then the following code is generated:
///
/// ```
/// #[derive(Debug, Clone)]
/// struct MockTaskManager {
///     max_threads: double::Mock<(), u32>,
///     set_max_threads: double::Mock<(u32), ()>,
/// }
///
/// impl Default for MockTaskManager {
///     fn default() -> Self {
///         MockTaskManager {
///             max_threads: double::Mock::default(),
///             set_max_threads: double::Mock::default(),
///         }
///     }
/// }
/// ```
///
/// Note that just defining this macro is not enough. This macro is used to
/// generate the necessary boilerplate, but the generated struct *does not*
/// implement the desired `trait`. To do that, use `double`'s `mock_method`
/// macro.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate double;
///
/// trait TaskManager {
///    fn max_threads(&self) -> u32;
///    fn set_max_threads(&mut self, max_threads: u32);
/// }
///
/// mock_trait!(
///     MockTaskManager,
///     max_threads(()) -> u32,
///     set_max_threads(u32) -> ()
/// );
///
/// # fn main() {
/// let mock = MockTaskManager::default();
/// mock.max_threads.return_value(42u32);
/// assert_eq!(42, mock.max_threads.call(()));
/// mock.set_max_threads.call(9001u32);
/// assert!(mock.set_max_threads.called_with(9001u32));
/// # }
/// ```
#[macro_export]
macro_rules! mock_trait {
    ($mock_name:ident $(, $method:ident($($arg_type:ty),* ) -> $retval:ty )* ) => (
        #[derive(Debug, Clone)]
        struct $mock_name {
            $(
                $method: double::Mock<(($($arg_type),*)), $retval>
            ),*
        }

        impl Default for $mock_name {
            fn default() -> Self {
                $mock_name {
                    $(
                        $method: double::Mock::default()
                    ),*
                }
            }
        }
    );

    (pub $mock_name:ident $(, $method:ident($($arg_type:ty),* ) -> $retval:ty )* ) => (
        #[derive(Debug, Clone)]
        pub struct $mock_name {
            $(
                $method: double::Mock<(($($arg_type),*)), $retval>
            ),*
        }

        impl Default for $mock_name {
            fn default() -> Self {
                $mock_name {
                    $(
                        $method: double::Mock::default()
                    ),*
                }
            }
        }
    );
}

/// Macro that generates a mock implementation of a `trait` method.
///
/// This should be used to implement a `trait` on a mock type generated by
/// `double`'s `mock_trait` macro. If one has generated a mock `struct` using
/// `mock_trait`, then the actual *implementation* of the desired trait can be
/// auto-generated using `mock_method`, like so:
///
/// ```
/// # #[macro_use] extern crate double;
///
/// trait TaskManager {
///    fn max_threads(&self) -> u32;
///    fn set_max_threads(&mut self, max_threads: u32);
/// }
///
/// mock_trait!(
///     MockTaskManager,
///     max_threads(()) -> u32,
///     set_max_threads(u32) -> ()
/// );
///
/// // Actually implement the trait that should be mocked
/// impl TaskManager for MockTaskManager {
///     mock_method!(max_threads(&self) -> u32);
///     mock_method!(set_max_threads(&mut self, max_threads: u32));
/// }
///
/// # fn main() {
/// let mut mock = MockTaskManager::default();
/// mock.max_threads.return_value(42u32);
/// assert_eq!(42, mock.max_threads());
/// assert!(mock.max_threads.called_with(()));
/// mock.set_max_threads(9001u32);
/// assert!(mock.set_max_threads.called_with(9001u32));
/// # }
/// ```
///
/// There are many different variants of `mock_method`. In total there are 12
/// variants. 8 variants provides a combination of the following:
///
/// 1. const method (`&self`) **or** mutable method (`&mut self`)
/// 2. return value (`fn foo(&self) -> bool`) **or** no return value (`fn foo(&self)`)
/// 3. automatically generated method body **or** custom method body
///
/// (1) allows both constant and mutable methods tobe mocked, like in the
/// `MockTaskManager` example above.
///
/// (2) is for convenience. It means one doesn't have to specify `-> ()`
/// explicitly for mocked methods that don't return values. This can also be
/// shown in the `MockTaskManager` example. Notice how the return type is not
/// specified when generating the `set_max_threads()` mock.
///
/// (3) is useful when the stored call arguments' types (defined by the
/// `mock_trait()` macro) are different to the mocked method. There are cases
/// where type differences in the stored args and the actual method args are
/// required. For example, suppose you had the following trait:
///
/// ```
/// trait TextStreamWriter {
///     fn write(text: &str);
/// }
/// ```
///
/// A mock can't _store_ received `text` arguments as `&str` because the mock
/// needs to the _own_ the given arguments (and `&str` is a non-owning
/// reference). Therefore, the mock trait has to be specified like so:
///
/// ```
/// # #[macro_use] extern crate double;
///
/// trait TextStreamWriter {
///     fn write(&mut self, text: &str);
/// }
///
/// mock_trait!(
///     MockTextStreamWriter,
///     // have to use `String`, not `&str` here, since `&str` is a reference
///     write(String) -> ()
/// );
///
/// impl TextStreamWriter for MockTextStreamWriter {
///     mock_method!(write(&mut self, text: &str), self, {
///         // manually convert the reference to an owned `String` before
///         // passing it to the underlying mock object
///         self.write.call(text.to_owned())
///     });
/// }
/// # fn main() {
///     // only here to make `cargo test` happy
/// }
/// ```
///
/// Using variant (3) of `mock_method` means we specify the body of the
/// generated function manually. The custom body simply converts the `&str`
/// argument to an owned string and passes it into the underlying `write` `Mock`
/// object manually. (normally auto-generated bodies do this for you).
///
/// The name of the underlying mock object is always the same as the mocked
/// method's name.
///
/// `&str` parameters are common. It can be inconvenient haven't to manually
/// specify the body each time they appear. There are plans to add a macro to
/// generate a body that calls `to_owned()` automatically.
/// (TODO: implement the macro)
///
/// ### Type Parameters
///
/// There are an additional 4 variants to handle method type parameters
/// (e.g. `fn foo<T: Eq>(&self, a: &T)`). These variants allow one to generate
/// mock methods which take some generic type parameters.
///
/// For example, suppose one had a `Comparator` trait that was responsible for
/// comparing any two values in the program. It might look something like this:
///
/// ```
/// trait Comparator {
///    fn is_equal<T: Eq>(&self, a: &T, b: &T) -> bool;
/// }
/// ```
///
/// `T` can be multiple types. Currently, we cannot store call arguments that
/// have generic types in the underlying `Mock` objects. Therefore, one has to
/// convert the generic types to a different, common representation. One way
/// to get around this limitation is converting each generic type to a `String`.
/// e.g. for the `Comparator` trait:
///
/// ```
/// # #[macro_use] extern crate double;
///
/// use std::string::ToString;
///
/// trait Comparator {
///    fn is_equal<T: Eq + ToString>(&self, a: &T, b: &T) -> bool;
/// }
///
/// mock_trait!(
///     MockComparator,
///     // store all passed in call args as strings
///     is_equal((String, String)) -> bool
/// );
///
/// impl Comparator for MockComparator {
///     mock_method!(is_equal<(T: Eq + ToString)>(&self, a: &T, b: &T) -> bool, self, {
///         // Convert both arguments to strings and manually pass to underlying
///         // mock object.
///         // Notice how the both arguments as passed as a single tuple. The
///         // underlying mock object always expects a single tuple.
///         self.is_equal.call((a.to_string(), b.to_string()))
///     });
/// }
/// # fn main() {
///     // only here to make `cargo test` happy
/// }
/// ```
///
/// If the `to_string` conversions for all `T` are not lossy, then our mock
/// expectations can be exact. If the `to_string` conversions _are_ lossy, then
/// this mechanism can still be used, providing all the properties of the passed
/// in objects are captured in the resultant `String`s.
///
/// This approach requires the writer to ensure the code under test adds the
/// `ToString` trait to the `trait`'s type argument constraints. This limitation
/// forces test writers to modify production code to use `double` for mocking.
///
/// Despite this, there is still value in using `double` for mocking generic
/// methods with type arguments. Despite adding boilerplate to production code
/// and manually implementing mock method bodies being cumbersome, the value add
/// is that all argument matching, expectations, calling test functions, etc.
/// are all still handled by `double`. Arguably, reimplenting those features is
/// more cumbersome than the small amount of boilerplate required to mock
/// methods with type arguments.
#[macro_export]
macro_rules! mock_method {

    // immutable, no return value, no type parameter, no body
    ( $method:ident(&self $(,$arg_name:ident: $arg_type:ty)*)) => (
        fn $method(&self $(,$arg_name: $arg_type)*) {
            self.$method.call(($($arg_name.clone()),*))
        }
    );

    // immutable, no return value, no type parameter, body
    ( $method:ident(&self $(,$arg_name:ident: $arg_type:ty)*), $sel:ident, $body:tt ) => (
        fn $method(&$sel $(,$arg_name: $arg_type)*) $body
    );

    // immutable, no return value, type parameter, no body
    // not provided, since type parameters need a custom body 99% of the time

    // immutable, no return value, type parameter, body
    ( $method:ident<($($type_params: tt)*)>(&self $(,$arg_name:ident: $arg_type:ty)*),
        $sel:ident, $body:tt) => (
            fn $method<$($type_params)*>(&$sel $(,$arg_name: $arg_type)*) $body
    );

    // immutable, return value, no type parameter, no body
    ( $method:ident(&self $(,$arg_name:ident: $arg_type:ty)*) -> $retval:ty ) => (
        fn $method(&self $(,$arg_name: $arg_type)*) -> $retval {
            self.$method.call(($($arg_name.clone()),*))
        }
    );

    // immutable, return value, no type parameter, body
    ( $method:ident(&self $(,$arg_name:ident: $arg_type:ty)*) -> $retval:ty, $sel:ident, $body:tt ) => (
        fn $method(&$sel $(,$arg_name: $arg_type)*) -> $retval $body
    );

    // immutable, return value, type parameter, no body
    // not provided, since type parameters need a custom body 99% of the time

    // immutable, return value, type parameter, body
    ( $method:ident<($($type_params: tt)*)>(&self $(,$arg_name:ident: $arg_type:ty)*)
        -> $retval:ty, $sel:ident, $body:tt ) => (
            fn $method<$($type_params)*>(&$sel $(,$arg_name: $arg_type)*) -> $retval $body
    );

    // mutable, no return value, no type parameter, no body
    ( $method:ident(&mut self $(,$arg_name:ident: $arg_type:ty)*)) => (
        fn $method(&mut self $(,$arg_name: $arg_type),*) {
            self.$method.call(($($arg_name.clone()),*))
        }
    );

    // mutable, no return value, no type parameter, body
    ( $method:ident(&mut self $(,$arg_name:ident: $arg_type:ty)*), $sel:ident, $body:tt ) => (
        fn $method(&mut $sel $(,$arg_name: $arg_type)*) $body
    );

    // mutable, no return value, type parameter, no body
    // not provided, since type parameters need a custom body 99% of the time

    // mutable, no return value, type parameter, body
    ( $method:ident<($($type_params: tt)*)>(&mut self $(,$arg_name:ident: $arg_type:ty)*),
        $sel:ident, $body:tt) => (
            fn $method<$($type_params)*>(&mut $sel $(,$arg_name: $arg_type)*) $body
    );

    // mutable, return value, no type parameter, no body
    ( $method:ident(&mut self $(,$arg_name:ident: $arg_type:ty)*) -> $retval:ty ) => (
        fn $method(&mut self $(,$arg_name: $arg_type),*) -> $retval {
            self.$method.call(($($arg_name.clone()),*))
        }
    );

    // mutable, return value, no type parameter, body
    ( $method:ident(&mut self $(,$arg_name:ident: $arg_type:ty)*) -> $retval:ty, $sel:ident, $body:tt ) => (
        fn $method(&mut $sel $(,$arg_name: $arg_type)*) -> $retval $body
    );

    // mutable, return value, type parameter, no body
    // not provided, since type parameters need a custom body 99% of the time

    // mutable, return value, type parameter, body
    ( $method:ident<($($type_params: tt)*)>(&mut self $(,$arg_name:ident: $arg_type:ty)*)
        -> $retval:ty, $sel:ident, $body:tt ) => (
            fn $method<$($type_params)*>(&mut $sel $(,$arg_name: $arg_type)*) -> $retval $body
    );

}
<commit_msg>Remove extra commas in mock_method!<commit_after>/// Macro that generates a `struct` implementation of a specified trait.
///
/// This macro generates a `struct` that implements the traits `Clone`, `Debug`
/// and `Default`. Create instances of the mock object by calling the `struct`'s
/// `default()` method.
///
/// The `struct` has a field for each method of the `trait`, which manages their
/// respective method's behaviour and call expectations. For example, if one
/// defines a mock like so:
///
/// ```
/// # #[macro_use] extern crate double;
///
/// mock_trait!(
///     MockTaskManager,
///     max_threads(()) -> u32,
///     set_max_threads(u32) -> ()
/// );
///
/// # fn main() {
///     // only here to make `cargo test` happy
/// }
/// ```
///
/// Then the following code is generated:
///
/// ```
/// #[derive(Debug, Clone)]
/// struct MockTaskManager {
///     max_threads: double::Mock<(), u32>,
///     set_max_threads: double::Mock<(u32), ()>,
/// }
///
/// impl Default for MockTaskManager {
///     fn default() -> Self {
///         MockTaskManager {
///             max_threads: double::Mock::default(),
///             set_max_threads: double::Mock::default(),
///         }
///     }
/// }
/// ```
///
/// Note that just defining this macro is not enough. This macro is used to
/// generate the necessary boilerplate, but the generated struct *does not*
/// implement the desired `trait`. To do that, use `double`'s `mock_method`
/// macro.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate double;
///
/// trait TaskManager {
///    fn max_threads(&self) -> u32;
///    fn set_max_threads(&mut self, max_threads: u32);
/// }
///
/// mock_trait!(
///     MockTaskManager,
///     max_threads(()) -> u32,
///     set_max_threads(u32) -> ()
/// );
///
/// # fn main() {
/// let mock = MockTaskManager::default();
/// mock.max_threads.return_value(42u32);
/// assert_eq!(42, mock.max_threads.call(()));
/// mock.set_max_threads.call(9001u32);
/// assert!(mock.set_max_threads.called_with(9001u32));
/// # }
/// ```
#[macro_export]
macro_rules! mock_trait {
    ($mock_name:ident $(, $method:ident($($arg_type:ty),* ) -> $retval:ty )* ) => (
        #[derive(Debug, Clone)]
        struct $mock_name {
            $(
                $method: double::Mock<(($($arg_type),*)), $retval>
            ),*
        }

        impl Default for $mock_name {
            fn default() -> Self {
                $mock_name {
                    $(
                        $method: double::Mock::default()
                    ),*
                }
            }
        }
    );

    (pub $mock_name:ident $(, $method:ident($($arg_type:ty),* ) -> $retval:ty )* ) => (
        #[derive(Debug, Clone)]
        pub struct $mock_name {
            $(
                $method: double::Mock<(($($arg_type),*)), $retval>
            ),*
        }

        impl Default for $mock_name {
            fn default() -> Self {
                $mock_name {
                    $(
                        $method: double::Mock::default()
                    ),*
                }
            }
        }
    );
}

/// Macro that generates a mock implementation of a `trait` method.
///
/// This should be used to implement a `trait` on a mock type generated by
/// `double`'s `mock_trait` macro. If one has generated a mock `struct` using
/// `mock_trait`, then the actual *implementation* of the desired trait can be
/// auto-generated using `mock_method`, like so:
///
/// ```
/// # #[macro_use] extern crate double;
///
/// trait TaskManager {
///    fn max_threads(&self) -> u32;
///    fn set_max_threads(&mut self, max_threads: u32);
/// }
///
/// mock_trait!(
///     MockTaskManager,
///     max_threads(()) -> u32,
///     set_max_threads(u32) -> ()
/// );
///
/// // Actually implement the trait that should be mocked
/// impl TaskManager for MockTaskManager {
///     mock_method!(max_threads(&self) -> u32);
///     mock_method!(set_max_threads(&mut self, max_threads: u32));
/// }
///
/// # fn main() {
/// let mut mock = MockTaskManager::default();
/// mock.max_threads.return_value(42u32);
/// assert_eq!(42, mock.max_threads());
/// assert!(mock.max_threads.called_with(()));
/// mock.set_max_threads(9001u32);
/// assert!(mock.set_max_threads.called_with(9001u32));
/// # }
/// ```
///
/// There are many different variants of `mock_method`. In total there are 12
/// variants. 8 variants provides a combination of the following:
///
/// 1. const method (`&self`) **or** mutable method (`&mut self`)
/// 2. return value (`fn foo(&self) -> bool`) **or** no return value (`fn foo(&self)`)
/// 3. automatically generated method body **or** custom method body
///
/// (1) allows both constant and mutable methods tobe mocked, like in the
/// `MockTaskManager` example above.
///
/// (2) is for convenience. It means one doesn't have to specify `-> ()`
/// explicitly for mocked methods that don't return values. This can also be
/// shown in the `MockTaskManager` example. Notice how the return type is not
/// specified when generating the `set_max_threads()` mock.
///
/// (3) is useful when the stored call arguments' types (defined by the
/// `mock_trait()` macro) are different to the mocked method. There are cases
/// where type differences in the stored args and the actual method args are
/// required. For example, suppose you had the following trait:
///
/// ```
/// trait TextStreamWriter {
///     fn write(text: &str);
/// }
/// ```
///
/// A mock can't _store_ received `text` arguments as `&str` because the mock
/// needs to the _own_ the given arguments (and `&str` is a non-owning
/// reference). Therefore, the mock trait has to be specified like so:
///
/// ```
/// # #[macro_use] extern crate double;
///
/// trait TextStreamWriter {
///     fn write(&mut self, text: &str);
/// }
///
/// mock_trait!(
///     MockTextStreamWriter,
///     // have to use `String`, not `&str` here, since `&str` is a reference
///     write(String) -> ()
/// );
///
/// impl TextStreamWriter for MockTextStreamWriter {
///     mock_method!(write(&mut self, text: &str), self, {
///         // manually convert the reference to an owned `String` before
///         // passing it to the underlying mock object
///         self.write.call(text.to_owned())
///     });
/// }
/// # fn main() {
///     // only here to make `cargo test` happy
/// }
/// ```
///
/// Using variant (3) of `mock_method` means we specify the body of the
/// generated function manually. The custom body simply converts the `&str`
/// argument to an owned string and passes it into the underlying `write` `Mock`
/// object manually. (normally auto-generated bodies do this for you).
///
/// The name of the underlying mock object is always the same as the mocked
/// method's name.
///
/// `&str` parameters are common. It can be inconvenient haven't to manually
/// specify the body each time they appear. There are plans to add a macro to
/// generate a body that calls `to_owned()` automatically.
/// (TODO: implement the macro)
///
/// ### Type Parameters
///
/// There are an additional 4 variants to handle method type parameters
/// (e.g. `fn foo<T: Eq>(&self, a: &T)`). These variants allow one to generate
/// mock methods which take some generic type parameters.
///
/// For example, suppose one had a `Comparator` trait that was responsible for
/// comparing any two values in the program. It might look something like this:
///
/// ```
/// trait Comparator {
///    fn is_equal<T: Eq>(&self, a: &T, b: &T) -> bool;
/// }
/// ```
///
/// `T` can be multiple types. Currently, we cannot store call arguments that
/// have generic types in the underlying `Mock` objects. Therefore, one has to
/// convert the generic types to a different, common representation. One way
/// to get around this limitation is converting each generic type to a `String`.
/// e.g. for the `Comparator` trait:
///
/// ```
/// # #[macro_use] extern crate double;
///
/// use std::string::ToString;
///
/// trait Comparator {
///    fn is_equal<T: Eq + ToString>(&self, a: &T, b: &T) -> bool;
/// }
///
/// mock_trait!(
///     MockComparator,
///     // store all passed in call args as strings
///     is_equal((String, String)) -> bool
/// );
///
/// impl Comparator for MockComparator {
///     mock_method!(is_equal<(T: Eq + ToString)>(&self, a: &T, b: &T) -> bool, self, {
///         // Convert both arguments to strings and manually pass to underlying
///         // mock object.
///         // Notice how the both arguments as passed as a single tuple. The
///         // underlying mock object always expects a single tuple.
///         self.is_equal.call((a.to_string(), b.to_string()))
///     });
/// }
/// # fn main() {
///     // only here to make `cargo test` happy
/// }
/// ```
///
/// If the `to_string` conversions for all `T` are not lossy, then our mock
/// expectations can be exact. If the `to_string` conversions _are_ lossy, then
/// this mechanism can still be used, providing all the properties of the passed
/// in objects are captured in the resultant `String`s.
///
/// This approach requires the writer to ensure the code under test adds the
/// `ToString` trait to the `trait`'s type argument constraints. This limitation
/// forces test writers to modify production code to use `double` for mocking.
///
/// Despite this, there is still value in using `double` for mocking generic
/// methods with type arguments. Despite adding boilerplate to production code
/// and manually implementing mock method bodies being cumbersome, the value add
/// is that all argument matching, expectations, calling test functions, etc.
/// are all still handled by `double`. Arguably, reimplenting those features is
/// more cumbersome than the small amount of boilerplate required to mock
/// methods with type arguments.
#[macro_export]
macro_rules! mock_method {

    // immutable, no return value, no type parameter, no body
    ( $method:ident(&self $(,$arg_name:ident: $arg_type:ty)*)) => (
        fn $method(&self $(,$arg_name: $arg_type)*) {
            self.$method.call(($($arg_name.clone()),*))
        }
    );

    // immutable, no return value, no type parameter, body
    ( $method:ident(&self $(,$arg_name:ident: $arg_type:ty)*), $sel:ident, $body:tt ) => (
        fn $method(&$sel $(,$arg_name: $arg_type)*) $body
    );

    // immutable, no return value, type parameter, no body
    // not provided, since type parameters need a custom body 99% of the time

    // immutable, no return value, type parameter, body
    ( $method:ident<($($type_params: tt)*)>(&self $(,$arg_name:ident: $arg_type:ty)*),
        $sel:ident, $body:tt) => (
            fn $method<$($type_params)*>(&$sel $(,$arg_name: $arg_type)*) $body
    );

    // immutable, return value, no type parameter, no body
    ( $method:ident(&self $(,$arg_name:ident: $arg_type:ty)*) -> $retval:ty ) => (
        fn $method(&self $(,$arg_name: $arg_type)*) -> $retval {
            self.$method.call(($($arg_name.clone()),*))
        }
    );

    // immutable, return value, no type parameter, body
    ( $method:ident(&self $(,$arg_name:ident: $arg_type:ty)*) -> $retval:ty, $sel:ident, $body:tt ) => (
        fn $method(&$sel $(,$arg_name: $arg_type)*) -> $retval $body
    );

    // immutable, return value, type parameter, no body
    // not provided, since type parameters need a custom body 99% of the time

    // immutable, return value, type parameter, body
    ( $method:ident<($($type_params: tt)*)>(&self $(,$arg_name:ident: $arg_type:ty)*)
        -> $retval:ty, $sel:ident, $body:tt ) => (
            fn $method<$($type_params)*>(&$sel $(,$arg_name: $arg_type)*) -> $retval $body
    );

    // mutable, no return value, no type parameter, no body
    ( $method:ident(&mut self $(,$arg_name:ident: $arg_type:ty)*)) => (
        fn $method(&mut self $(,$arg_name: $arg_type)*) {
            self.$method.call(($($arg_name.clone()),*))
        }
    );

    // mutable, no return value, no type parameter, body
    ( $method:ident(&mut self $(,$arg_name:ident: $arg_type:ty)*), $sel:ident, $body:tt ) => (
        fn $method(&mut $sel $(,$arg_name: $arg_type)*) $body
    );

    // mutable, no return value, type parameter, no body
    // not provided, since type parameters need a custom body 99% of the time

    // mutable, no return value, type parameter, body
    ( $method:ident<($($type_params: tt)*)>(&mut self $(,$arg_name:ident: $arg_type:ty)*),
        $sel:ident, $body:tt) => (
            fn $method<$($type_params)*>(&mut $sel $(,$arg_name: $arg_type)*) $body
    );

    // mutable, return value, no type parameter, no body
    ( $method:ident(&mut self $(,$arg_name:ident: $arg_type:ty)*) -> $retval:ty ) => (
        fn $method(&mut self $(,$arg_name: $arg_type)*) -> $retval {
            self.$method.call(($($arg_name.clone()),*))
        }
    );

    // mutable, return value, no type parameter, body
    ( $method:ident(&mut self $(,$arg_name:ident: $arg_type:ty)*) -> $retval:ty, $sel:ident, $body:tt ) => (
        fn $method(&mut $sel $(,$arg_name: $arg_type)*) -> $retval $body
    );

    // mutable, return value, type parameter, no body
    // not provided, since type parameters need a custom body 99% of the time

    // mutable, return value, type parameter, body
    ( $method:ident<($($type_params: tt)*)>(&mut self $(,$arg_name:ident: $arg_type:ty)*)
        -> $retval:ty, $sel:ident, $body:tt ) => (
            fn $method<$($type_params)*>(&mut $sel $(,$arg_name: $arg_type)*) -> $retval $body
    );

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

include!("../relm-state/src/macros.rs");
<commit_msg>Temporary fix to publish the crate<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/// Connect events to sending a message.
///
/// ## Rules
/// 1. Send `$msg` to `$other_component` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Optionally send `$msg.0` when the GTK+ `$event` is emitted on `$widget`.
/// Return `$msg.1` in the GTK+ callback.
/// This variant gives more control to the caller since it expects a `$msg` returning `(Option<MSG>,
/// ReturnValue)` where the `ReturnValue` is the value to return in the GTK+ callback.
/// Option<MSG> can be None if no message needs to be emitted.
///
/// 3. Send `$msg` when the GTK+ `$event` is emitted on `$widget`.
///
/// 4. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect {
    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_component:expr, $msg:expr) => {
        connect_stream!($widget, $event($($args),*), $other_component.stream(), $msg);
    };

    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), return $msg:expr) => {{
        connect_stream!(return $relm.stream(), $widget, $event($($args),*), $msg);
    }};

    // Connect to a GTK+ widget event.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $relm.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    }};

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_component:ident @ $message:pat, $dst_component:expr, $msg:expr) => {
        let stream = $src_component.stream().clone();
        connect_stream!(stream@$message, $dst_component.stream(), $msg);
    };
}

/// Connect events to sending a message.
/// Similar to `connect!` but wants a stream instead of a component.
///
/// ## Rules
/// 1. Send `$msg` to `$other_stream` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect_stream {
    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    (return $stream:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let (msg, return_value) = $crate::IntoPair::into_pair($msg);
            let msg: Option<_> = $crate::IntoOption::into_option(msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
            return_value
        });
    }};

    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_stream:expr, $msg:expr) => {
        let stream = $other_stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    };

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_stream:ident @ $message:pat, $dst_stream:expr, $msg:expr) => {
        let stream = $dst_stream.clone();
        $src_stream.observe(move |msg| {
            #[allow(unreachable_patterns)]
            match msg {
                &$message =>  {
                    let msg: Option<_> = $crate::IntoOption::into_option($msg);
                    if let Some(msg) = msg {
                        stream.emit(msg);
                    }
                },
                _ => (),
            }
        });
    };
}

/// Connect an asynchronous method call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async {
    ($object:expr, $async_method:ident, $relm:expr, $msg:ident) => {
        connect_async!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:ident) => {{
        use ::futures::Sink;
        let (tx, rx) = ::futures::sync::mpsc::unbounded();
        let tx = ::std::sync::Mutex::new(tx);
        $object.$async_method($($args,)* None, move |result| {
            if let Ok(result) = result {
                let mut tx = tx.lock().unwrap();
                if let Ok(::futures::AsyncSink::Ready) = tx.start_send(result) {
                    tx.poll_complete().unwrap();
                } else {
                    eprintln!("Unable to send message to sender");
                }
            }
        });
        $relm.connect_exec_ignore_err(rx, $msg);
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:ident, $fail_msg:ident) => {
        connect_async!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:ident, $fail_msg:ident) => {{
        use ::futures::{Sink, Stream};
        let (tx, rx) = ::futures::sync::mpsc::unbounded();
        let tx = ::std::sync::Mutex::new(tx);
        $object.$async_method($($args,)* None, move |result| {
            let mut tx = tx.lock().unwrap();
            if let Ok(::futures::AsyncSink::Ready) = tx.start_send(result) {
                tx.poll_complete().unwrap();
            } else {
                eprintln!("Unable to send message to sender");
            }
        });

        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        let future =
            rx.for_each(move |result| {
                match result {
                    Ok(value) => event_stream.emit($msg(value)),
                    Err(error) => fail_event_stream.emit($fail_msg(error)),
                }
                Ok(())
            });
        $relm.exec(future);
    }};
}

/// Connect an asynchronous function call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async_func {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:ident) => {
        connect_async!($async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:ident) => {{
        use ::futures::Sink;
        let (tx, rx) = ::futures::sync::mpsc::unbounded();
        let tx = ::std::sync::Mutex::new(tx);
        $class::$async_func($($args,)* None, move |result| {
            if let Ok(result) = result {
                let mut tx = tx.lock().unwrap();
                if let Ok(::futures::AsyncSink::Ready) = tx.start_send(result) {
                    tx.poll_complete().unwrap();
                } else {
                    eprintln!("Unable to send message to sender");
                }
            }
        });
        $relm.connect_exec_ignore_err(rx, $msg);
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:ident, $fail_msg:ident) => {
        connect_async!($async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:ident, $fail_msg:ident) => {{
        use ::futures::{Sink, Stream};
        let (tx, rx) = ::futures::sync::mpsc::unbounded();
        let tx = ::std::sync::Mutex::new(tx);
        $class::$async_func($($args,)* None, move |result| {
            let mut tx = tx.lock().unwrap();
            if let Ok(::futures::AsyncSink::Ready) = tx.start_send(result) {
                tx.poll_complete().unwrap();
            } else {
                eprintln!("Unable to send message to sender");
            }
        });

        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        let future =
            rx.for_each(move |result| {
                match result {
                    Ok(value) => event_stream.emit($msg(value)),
                    Err(error) => fail_event_stream.emit($fail_msg(error)),
                }
                Ok(())
            });
        $relm.exec(future);
    }};
}

/// Like `connect_async!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_full {
    ($object:expr, $async_method:ident, $relm:expr, $msg:ident) => {
        connect_async_full!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:ident) => {{
        let cancellable = ::gio::Cancellable::new();
        use ::futures::Sink;
        let (tx, rx) = ::futures::sync::mpsc::unbounded();
        let tx = ::std::sync::Mutex::new(tx);
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                let mut tx = tx.lock().unwrap();
                if let Ok(::futures::AsyncSink::Ready) = tx.start_send(result) {
                    tx.poll_complete().unwrap();
                } else {
                    eprintln!("Unable to send message to sender");
                }
            }
        });
        $relm.connect_exec_ignore_err(rx, $msg);
        cancellable
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:ident, $fail_msg:ident) => {
        connect_async_full!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:ident, $fail_msg:ident) => {{
        let cancellable = ::gio::Cancellable::new();
        use ::futures::{Sink, Stream};
        let (tx, rx) = ::futures::sync::mpsc::unbounded();
        let tx = ::std::sync::Mutex::new(tx);
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            let mut tx = tx.lock().unwrap();
            if let Ok(::futures::AsyncSink::Ready) = tx.start_send(result) {
                tx.poll_complete().unwrap();
            } else {
                eprintln!("Unable to send message to sender");
            }
        });

        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        let future =
            rx.for_each(move |result| {
                match result {
                    Ok(value) => event_stream.emit($msg(value)),
                    Err(error) => fail_event_stream.emit($fail_msg(error)),
                }
                Ok(())
            });
        $relm.exec(future);
        cancellable
    }};
}

/// Like `connect_async_func!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_func_full {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:ident) => {
        connect_async!($async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:ident) => {{
        let cancellable = ::gio::Cancellable::new();
        use ::futures::Sink;
        let (tx, rx) = ::futures::sync::mpsc::unbounded();
        let tx = ::std::sync::Mutex::new(tx);
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                let mut tx = tx.lock().unwrap();
                if let Ok(::futures::AsyncSink::Ready) = tx.start_send(result) {
                    tx.poll_complete().unwrap();
                } else {
                    eprintln!("Unable to send message to sender");
                }
            }
        });
        $relm.connect_exec_ignore_err(rx, $msg);
        cancellable
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:ident, $fail_msg:ident) => {
        connect_async!($async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:ident, $fail_msg:ident) => {{
        let cancellable = ::gio::Cancellable::new();
        use ::futures::{Sink, Stream};
        let (tx, rx) = ::futures::sync::mpsc::unbounded();
        let tx = ::std::sync::Mutex::new(tx);
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            let mut tx = tx.lock().unwrap();
            if let Ok(::futures::AsyncSink::Ready) = tx.start_send(result) {
                tx.poll_complete().unwrap();
            } else {
                eprintln!("Unable to send message to sender");
            }
        });

        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        let future =
            rx.for_each(move |result| {
                match result {
                    Ok(value) => event_stream.emit($msg(value)),
                    Err(error) => fail_event_stream.emit($fail_msg(error)),
                }
                Ok(())
            });
        $relm.exec(future);
        cancellable
    }};
}
<|endoftext|>