<commit_before>use chrono::{DateTime, UTC};
use bson::{Array,Bson,Document};
use super::oid::ObjectId;
use std::collections::BTreeMap;
use std::fmt::{Display, Error, Formatter};
use std::iter::{FromIterator, Map};
use std::vec::IntoIter;
use std::slice;

/// Error to indicate that either a value was empty or it contained an unexpected
/// type, for use with the direct getters.
#[derive(Debug,PartialEq)]
pub enum ValueAccessError {
    NotPresent,
    UnexpectedType
}

pub type ValueAccessResult<T> = Result<T, ValueAccessError>;

/// A BSON document represented as an associative BTree Map with insertion ordering.
#[derive(Debug,Clone,PartialEq)]
pub struct OrderedDocument {
    pub keys: Vec<String>,
    document: BTreeMap<String, Bson>,
}

impl Display for OrderedDocument {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        let mut string = "{ ".to_owned();

        for (key, value) in self.iter() {
            if !string.eq("{ ") {
                string.push_str(", ");
            }

            string.push_str(&format!("{}: {}", key, value));
        }

        string.push_str(" }");
        fmt.write_str(&string)
    }
}

/// An iterator over OrderedDocument entries.
pub struct OrderedDocumentIntoIterator {
    vec_iter: IntoIter<String>,
    document: BTreeMap<String, Bson>,
}

/// An owning iterator over OrderedDocument entries.
pub struct OrderedDocumentIterator<'a> {
    vec_iter: slice::Iter<'a, String>,
    document: &'a BTreeMap<String, Bson>,
}

/// An iterator over an OrderedDocument's keys.
pub struct Keys<'a> {
    inner: Map<OrderedDocumentIterator<'a>, fn((&'a String, &'a Bson)) -> &'a String>
}

/// An iterator over an OrderedDocument's values.
pub struct Values<'a> {
    inner: Map<OrderedDocumentIterator<'a>, fn((&'a String, &'a Bson)) -> &'a Bson>
}

impl<'a> Iterator for Keys<'a> {
    type Item = &'a String;
    fn next(&mut self) -> Option<(&'a String)> { self.inner.next() }
}

impl<'a> Iterator for Values<'a> {
    type Item = &'a Bson;
    fn next(&mut self) -> Option<(&'a Bson)> { self.inner.next() }
}

impl IntoIterator for OrderedDocument {
    type Item = (String, Bson);
    type IntoIter = OrderedDocumentIntoIterator;

    fn into_iter(self) -> Self::IntoIter {
        OrderedDocumentIntoIterator {
            document: self.document,
            vec_iter: self.keys.into_iter()
        }
    }
}

impl<'a> IntoIterator for &'a OrderedDocument {
    type Item = (&'a String, &'a Bson);
    type IntoIter = OrderedDocumentIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        let ref keys = self.keys;
        OrderedDocumentIterator {
            vec_iter: keys.into_iter(),
            document: &self.document,
        }
    }
}

impl FromIterator<(String, Bson)> for OrderedDocument {
    fn from_iter<T: IntoIterator<Item=(String, Bson)>>(iter: T) -> Self {
        let mut doc = OrderedDocument::new();
        for (k, v) in iter {
            doc.insert(k, v.to_owned());
        }
        doc
    }
}

impl<'a> Iterator for OrderedDocumentIntoIterator {
    type Item = (String, Bson);
    fn next(&mut self) -> Option<(String, Bson)> {
        match self.vec_iter.next() {
            Some(key) => {
                let val = self.document.remove(&key[..]).unwrap();
                Some((key, val))
            },
            None => None,
        }
    }
}

impl<'a> Iterator for OrderedDocumentIterator<'a> {
    type Item = (&'a String, &'a Bson);
    fn next(&mut self) -> Option<(&'a String, &'a Bson)> {
        match self.vec_iter.next() {
            Some(key) => {
                let val = self.document.get(&key[..]).unwrap();
                Some((&key, val))
            },
            None => None,
        }
    }
}

impl OrderedDocument {
    /// Creates a new empty OrderedDocument.
    pub fn new() -> OrderedDocument {
        OrderedDocument {
            keys: Vec::new(),
            document: BTreeMap::new(),
        }
    }

    /// Gets an iterator over the entries of the map.
    pub fn iter<'a>(&'a self) -> OrderedDocumentIterator<'a> {
        self.into_iter()
    }

    /// Clears the document, removing all values.
    pub fn clear(&mut self) {
        self.keys.clear();
        self.document.clear();
    }

    /// Returns a reference to the Bson corresponding to the key.
    pub fn get(&self, key: &str) -> Option<&Bson> {
        self.document.get(key)
    }

    /// Gets a mutable reference to the Bson corresponding to the key
    pub fn get_mut(&mut self, key: &str) -> Option<&mut Bson> {
        self.document.get_mut(key)
    }

    /// Get a floating point value for this key if it exists and has
    /// the correct type.
    pub fn get_f64(&self, key: &str) -> ValueAccessResult<f64> {
        match self.get(key) {
            Some(&Bson::FloatingPoint(v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get a string slice this key if it exists and has the correct type.
    pub fn get_str(&self, key: &str) -> ValueAccessResult<&str> {
        match self.get(key) {
            Some(&Bson::String(ref v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get a reference to an array for this key if it exists and has
    /// the correct type.
    pub fn get_array(&self, key: &str) -> ValueAccessResult<&Array> {
        match self.get(key) {
            Some(&Bson::Array(ref v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get a reference to a document for this key if it exists and has
    /// the correct type.
    pub fn get_document(&self, key: &str) -> ValueAccessResult<&Document> {
        match self.get(key) {
            Some(&Bson::Document(ref v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get a bool value for this key if it exists and has the correct type.
    pub fn get_bool(&self, key: &str) -> ValueAccessResult<bool> {
        match self.get(key) {
            Some(&Bson::Boolean(v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Returns wether this key has a null value
    pub fn is_null(&self, key: &str) -> bool {
        self.get(key) == Some(&Bson::Null)
    }

    /// Get an i32 value for this key if it exists and has the correct type.
    pub fn get_i32(&self, key: &str) -> ValueAccessResult<i32> {
        match self.get(key) {
            Some(&Bson::I32(v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get an i64 value for this key if it exists and has the correct type.
    pub fn get_i64(&self, key: &str) -> ValueAccessResult<i64> {
        match self.get(key) {
            Some(&Bson::I64(v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get a time stamp value for this key if it exists and has the correct type.
    pub fn get_time_stamp(&self, key: &str) -> ValueAccessResult<i64> {
        match self.get(key) {
            Some(&Bson::TimeStamp(v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get an object id value for this key if it exists and has the correct type.
    pub fn get_object_id(&self, key: &str) -> ValueAccessResult<&ObjectId> {
        match self.get(key) {
            Some(&Bson::ObjectId(ref v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get a UTC datetime value for this key if it exists and has the correct type.
    pub fn get_utc_datetime(&self, key: &str) -> ValueAccessResult<&DateTime<UTC>> {
        match self.get(key) {
            Some(&Bson::UtcDatetime(ref v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Returns true if the map contains a value for the specified key.
    pub fn contains_key(&self, key: &str) -> bool {
        self.document.contains_key(key)
    }

    /// Returns the position of the key in the ordered vector, if it exists.
    pub fn position(&self, key: &str) -> Option<usize> {
        self.keys.iter().position(|x| x == key)
    }

    /// Gets a collection of all keys in the document.
    pub fn keys<'a>(&'a self) -> Keys<'a> {
        fn first<A, B>((a, _): (A, B)) -> A { a }
        let first: fn((&'a String, &'a Bson)) -> &'a String = first;

        Keys { inner: self.iter().map(first) }
    }

    /// Gets a collection of all values in the document.
    pub fn values<'a>(&'a self) -> Values<'a> {
        fn second<A, B>((_, b): (A, B)) -> B { b }
        let second: fn((&'a String, &'a Bson)) -> &'a Bson = second;

        Values { inner: self.iter().map(second) }
    }

    /// Returns the number of elements in the document.
    pub fn len(&self) -> usize {
        self.keys.len()
    }

    /// Returns true if the document contains no elements
    pub fn is_empty(&self) -> bool {
        self.document.is_empty()
    }

    /// Sets the value of the entry with the OccupiedEntry's key,
    /// and returns the entry's old value. Accepts any type that
    /// can be converted into Bson.
    pub fn insert<KT: Into<String>, BT: Into<Bson>>(&mut self, key: KT, val: BT) -> Option<Bson> {
        self.insert_bson(key.into(), val.into())
    }

    /// Sets the value of the entry with the OccupiedEntry's key,
    /// and returns the entry's old value.
    pub fn insert_bson(&mut self, key: String, val: Bson) -> Option<Bson> {
        {
            let key_slice = &key[..];
            if self.contains_key(key_slice) {
                let position = self.position(key_slice).unwrap();
                self.keys.remove(position);
            }
        }

        self.keys.push(key.to_owned());
        self.document.insert(key, val)
    }

    /// Takes the value of the entry out of the document, and returns it.
    pub fn remove(&mut self, key: &str) -> Option<Bson> {
        let position = self.position(key);
        if position.is_some() {
            self.keys.remove(position.unwrap());
        }
        self.document.remove(key)
    }
}
<commit_msg>Implement Debug, Display and Error for ValueAccessError<commit_after>use chrono::{DateTime, UTC};
use bson::{Array,Bson,Document};
use super::oid::ObjectId;
use std::collections::BTreeMap;
use std::error;
use std::fmt;
use std::fmt::{Debug, Display, Error, Formatter};
use std::iter::{FromIterator, Map};
use std::vec::IntoIter;
use std::slice;

/// Error to indicate that either a value was empty or it contained an unexpected
/// type, for use with the direct getters.
#[derive(PartialEq)]
pub enum ValueAccessError {
    NotPresent,
    UnexpectedType
}

pub type ValueAccessResult<T> = Result<T, ValueAccessError>;

impl Debug for ValueAccessError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            ValueAccessError::NotPresent => write!(f, "ValueAccessError: field is not present"),
            ValueAccessError::UnexpectedType => write!(f, "ValueAccessError: field does not have the expected type")
        }
    }
}

impl Display for ValueAccessError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            ValueAccessError::NotPresent => write!(f, "field is not present"),
            ValueAccessError::UnexpectedType => write!(f, "field does not have the expected type")
        }
    }
}

impl error::Error for ValueAccessError {
    fn description(&self) -> &str {
        "Error to indicate that either a value was empty or it contained an unexpected type"
    }
}

/// A BSON document represented as an associative BTree Map with insertion ordering.
#[derive(Debug,Clone,PartialEq)]
pub struct OrderedDocument {
    pub keys: Vec<String>,
    document: BTreeMap<String, Bson>,
}

impl Display for OrderedDocument {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        let mut string = "{ ".to_owned();

        for (key, value) in self.iter() {
            if !string.eq("{ ") {
                string.push_str(", ");
            }

            string.push_str(&format!("{}: {}", key, value));
        }

        string.push_str(" }");
        fmt.write_str(&string)
    }
}

/// An iterator over OrderedDocument entries.
pub struct OrderedDocumentIntoIterator {
    vec_iter: IntoIter<String>,
    document: BTreeMap<String, Bson>,
}

/// An owning iterator over OrderedDocument entries.
pub struct OrderedDocumentIterator<'a> {
    vec_iter: slice::Iter<'a, String>,
    document: &'a BTreeMap<String, Bson>,
}

/// An iterator over an OrderedDocument's keys.
pub struct Keys<'a> {
    inner: Map<OrderedDocumentIterator<'a>, fn((&'a String, &'a Bson)) -> &'a String>
}

/// An iterator over an OrderedDocument's values.
pub struct Values<'a> {
    inner: Map<OrderedDocumentIterator<'a>, fn((&'a String, &'a Bson)) -> &'a Bson>
}

impl<'a> Iterator for Keys<'a> {
    type Item = &'a String;
    fn next(&mut self) -> Option<(&'a String)> { self.inner.next() }
}

impl<'a> Iterator for Values<'a> {
    type Item = &'a Bson;
    fn next(&mut self) -> Option<(&'a Bson)> { self.inner.next() }
}

impl IntoIterator for OrderedDocument {
    type Item = (String, Bson);
    type IntoIter = OrderedDocumentIntoIterator;

    fn into_iter(self) -> Self::IntoIter {
        OrderedDocumentIntoIterator {
            document: self.document,
            vec_iter: self.keys.into_iter()
        }
    }
}

impl<'a> IntoIterator for &'a OrderedDocument {
    type Item = (&'a String, &'a Bson);
    type IntoIter = OrderedDocumentIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        let ref keys = self.keys;
        OrderedDocumentIterator {
            vec_iter: keys.into_iter(),
            document: &self.document,
        }
    }
}

impl FromIterator<(String, Bson)> for OrderedDocument {
    fn from_iter<T: IntoIterator<Item=(String, Bson)>>(iter: T) -> Self {
        let mut doc = OrderedDocument::new();
        for (k, v) in iter {
            doc.insert(k, v.to_owned());
        }
        doc
    }
}

impl<'a> Iterator for OrderedDocumentIntoIterator {
    type Item = (String, Bson);
    fn next(&mut self) -> Option<(String, Bson)> {
        match self.vec_iter.next() {
            Some(key) => {
                let val = self.document.remove(&key[..]).unwrap();
                Some((key, val))
            },
            None => None,
        }
    }
}

impl<'a> Iterator for OrderedDocumentIterator<'a> {
    type Item = (&'a String, &'a Bson);
    fn next(&mut self) -> Option<(&'a String, &'a Bson)> {
        match self.vec_iter.next() {
            Some(key) => {
                let val = self.document.get(&key[..]).unwrap();
                Some((&key, val))
            },
            None => None,
        }
    }
}

impl OrderedDocument {
    /// Creates a new empty OrderedDocument.
    pub fn new() -> OrderedDocument {
        OrderedDocument {
            keys: Vec::new(),
            document: BTreeMap::new(),
        }
    }

    /// Gets an iterator over the entries of the map.
    pub fn iter<'a>(&'a self) -> OrderedDocumentIterator<'a> {
        self.into_iter()
    }

    /// Clears the document, removing all values.
    pub fn clear(&mut self) {
        self.keys.clear();
        self.document.clear();
    }

    /// Returns a reference to the Bson corresponding to the key.
    pub fn get(&self, key: &str) -> Option<&Bson> {
        self.document.get(key)
    }

    /// Gets a mutable reference to the Bson corresponding to the key
    pub fn get_mut(&mut self, key: &str) -> Option<&mut Bson> {
        self.document.get_mut(key)
    }

    /// Get a floating point value for this key if it exists and has
    /// the correct type.
    pub fn get_f64(&self, key: &str) -> ValueAccessResult<f64> {
        match self.get(key) {
            Some(&Bson::FloatingPoint(v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get a string slice this key if it exists and has the correct type.
    pub fn get_str(&self, key: &str) -> ValueAccessResult<&str> {
        match self.get(key) {
            Some(&Bson::String(ref v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get a reference to an array for this key if it exists and has
    /// the correct type.
    pub fn get_array(&self, key: &str) -> ValueAccessResult<&Array> {
        match self.get(key) {
            Some(&Bson::Array(ref v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get a reference to a document for this key if it exists and has
    /// the correct type.
    pub fn get_document(&self, key: &str) -> ValueAccessResult<&Document> {
        match self.get(key) {
            Some(&Bson::Document(ref v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get a bool value for this key if it exists and has the correct type.
    pub fn get_bool(&self, key: &str) -> ValueAccessResult<bool> {
        match self.get(key) {
            Some(&Bson::Boolean(v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Returns wether this key has a null value
    pub fn is_null(&self, key: &str) -> bool {
        self.get(key) == Some(&Bson::Null)
    }

    /// Get an i32 value for this key if it exists and has the correct type.
    pub fn get_i32(&self, key: &str) -> ValueAccessResult<i32> {
        match self.get(key) {
            Some(&Bson::I32(v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get an i64 value for this key if it exists and has the correct type.
    pub fn get_i64(&self, key: &str) -> ValueAccessResult<i64> {
        match self.get(key) {
            Some(&Bson::I64(v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get a time stamp value for this key if it exists and has the correct type.
    pub fn get_time_stamp(&self, key: &str) -> ValueAccessResult<i64> {
        match self.get(key) {
            Some(&Bson::TimeStamp(v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get an object id value for this key if it exists and has the correct type.
    pub fn get_object_id(&self, key: &str) -> ValueAccessResult<&ObjectId> {
        match self.get(key) {
            Some(&Bson::ObjectId(ref v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Get a UTC datetime value for this key if it exists and has the correct type.
    pub fn get_utc_datetime(&self, key: &str) -> ValueAccessResult<&DateTime<UTC>> {
        match self.get(key) {
            Some(&Bson::UtcDatetime(ref v)) => Ok(v),
            Some(_) => Err(ValueAccessError::UnexpectedType),
            None => Err(ValueAccessError::NotPresent)
        }
    }

    /// Returns true if the map contains a value for the specified key.
    pub fn contains_key(&self, key: &str) -> bool {
        self.document.contains_key(key)
    }

    /// Returns the position of the key in the ordered vector, if it exists.
    pub fn position(&self, key: &str) -> Option<usize> {
        self.keys.iter().position(|x| x == key)
    }

    /// Gets a collection of all keys in the document.
    pub fn keys<'a>(&'a self) -> Keys<'a> {
        fn first<A, B>((a, _): (A, B)) -> A { a }
        let first: fn((&'a String, &'a Bson)) -> &'a String = first;

        Keys { inner: self.iter().map(first) }
    }

    /// Gets a collection of all values in the document.
    pub fn values<'a>(&'a self) -> Values<'a> {
        fn second<A, B>((_, b): (A, B)) -> B { b }
        let second: fn((&'a String, &'a Bson)) -> &'a Bson = second;

        Values { inner: self.iter().map(second) }
    }

    /// Returns the number of elements in the document.
    pub fn len(&self) -> usize {
        self.keys.len()
    }

    /// Returns true if the document contains no elements
    pub fn is_empty(&self) -> bool {
        self.document.is_empty()
    }

    /// Sets the value of the entry with the OccupiedEntry's key,
    /// and returns the entry's old value. Accepts any type that
    /// can be converted into Bson.
    pub fn insert<KT: Into<String>, BT: Into<Bson>>(&mut self, key: KT, val: BT) -> Option<Bson> {
        self.insert_bson(key.into(), val.into())
    }

    /// Sets the value of the entry with the OccupiedEntry's key,
    /// and returns the entry's old value.
    pub fn insert_bson(&mut self, key: String, val: Bson) -> Option<Bson> {
        {
            let key_slice = &key[..];
            if self.contains_key(key_slice) {
                let position = self.position(key_slice).unwrap();
                self.keys.remove(position);
            }
        }

        self.keys.push(key.to_owned());
        self.document.insert(key, val)
    }

    /// Takes the value of the entry out of the document, and returns it.
    pub fn remove(&mut self, key: &str) -> Option<Bson> {
        let position = self.position(key);
        if position.is_some() {
            self.keys.remove(position.unwrap());
        }
        self.document.remove(key)
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::result;
use std::sync::Arc;
use std::sync::RwLock;
use std::time::Duration;
use std::time::Instant;
use util::collections::HashSet;

use futures::future::{loop_fn, ok, Loop};
use futures::sync::mpsc::UnboundedSender;
use futures::task::Task;
use futures::{task, Async, Future, Poll, Stream};
use grpc::{
    CallOption, ChannelBuilder, ClientDuplexReceiver, ClientDuplexSender, Environment,
    Result as GrpcResult,
};
use kvproto::pdpb::{
    ErrorType, GetMembersRequest, GetMembersResponse, Member, RegionHeartbeatRequest,
    RegionHeartbeatResponse, ResponseHeader,
};
use kvproto::pdpb_grpc::PdClient;
use tokio_timer::timer::Handle;

use super::{Config, Error, PdFuture, Result, REQUEST_TIMEOUT};
use util::security::SecurityManager;
use util::timer::GLOBAL_TIMER_HANDLE;
use util::{Either, HandyRwLock};

pub struct Inner {
    env: Arc<Environment>,
    pub hb_sender: Either<
        Option<ClientDuplexSender<RegionHeartbeatRequest>>,
        UnboundedSender<RegionHeartbeatRequest>,
    >,
    pub hb_receiver: Either<Option<ClientDuplexReceiver<RegionHeartbeatResponse>>, Task>,
    pub client: PdClient,
    members: GetMembersResponse,
    security_mgr: Arc<SecurityManager>,
    on_reconnect: Option<Box<Fn() + Sync + Send + 'static>>,

    last_update: Instant,
}

pub struct HeartbeatReceiver {
    receiver: Option<ClientDuplexReceiver<RegionHeartbeatResponse>>,
    inner: Arc<RwLock<Inner>>,
}

impl Stream for HeartbeatReceiver {
    type Item = RegionHeartbeatResponse;
    type Error = Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Error> {
        loop {
            if let Some(ref mut receiver) = self.receiver {
                match receiver.poll() {
                    Ok(Async::Ready(Some(item))) => return Ok(Async::Ready(Some(item))),
                    Ok(Async::NotReady) => return Ok(Async::NotReady),
                    // If it's None or there's error, we need to update receiver.
                    _ => {}
                }
            }

            self.receiver.take();

            let mut inner = self.inner.wl();
            let mut receiver = None;
            if let Either::Left(ref mut recv) = inner.hb_receiver {
                receiver = recv.take();
            }
            if receiver.is_some() {
                info!("heartbeat receiver is refreshed.");
                self.receiver = receiver;
            } else {
                inner.hb_receiver = Either::Right(task::current());
                return Ok(Async::NotReady);
            }
        }
    }
}

/// A leader client doing requests asynchronous.
pub struct LeaderClient {
    timer: Handle,
    inner: Arc<RwLock<Inner>>,
}

impl LeaderClient {
    pub fn new(
        env: Arc<Environment>,
        security_mgr: Arc<SecurityManager>,
        client: PdClient,
        members: GetMembersResponse,
    ) -> LeaderClient {
        let (tx, rx) = client.region_heartbeat().unwrap();
        LeaderClient {
            timer: GLOBAL_TIMER_HANDLE.clone(),
            inner: Arc::new(RwLock::new(Inner {
                env,
                hb_sender: Either::Left(Some(tx)),
                hb_receiver: Either::Left(Some(rx)),
                client,
                members,
                security_mgr,
                on_reconnect: None,

                last_update: Instant::now(),
            })),
        }
    }

    pub fn handle_region_heartbeat_response<F>(&self, f: F) -> PdFuture<()>
    where
        F: Fn(RegionHeartbeatResponse) + Send + 'static,
    {
        let recv = HeartbeatReceiver {
            receiver: None,
            inner: Arc::clone(&self.inner),
        };
        Box::new(
            recv.for_each(move |resp| {
                f(resp);
                Ok(())
            }).map_err(|e| panic!("unexpected error: {:?}", e)),
        )
    }

    pub fn on_reconnect(&self, f: Box<Fn() + Sync + Send + 'static>) {
        let mut inner = self.inner.wl();
        inner.on_reconnect = Some(f);
    }

    pub fn request<Req, Resp, F>(&self, req: Req, func: F, retry: usize) -> Request<Req, Resp, F>
    where
        Req: Clone + 'static,
        F: FnMut(&RwLock<Inner>, Req) -> PdFuture<Resp> + Send + 'static,
    {
        Request {
            reconnect_count: retry,
            request_sent: 0,
            client: LeaderClient {
                timer: self.timer.clone(),
                inner: Arc::clone(&self.inner),
            },
            req,
            resp: None,
            func,
        }
    }

    pub fn get_leader(&self) -> Member {
        self.inner.rl().members.get_leader().clone()
    }

    // Re-establish connection with PD leader in synchronized fashion.
    pub fn reconnect(&self) -> Result<()> {
        let ((client, members), start) = {
            let inner = self.inner.rl();
            if inner.last_update.elapsed() < Duration::from_secs(RECONNECT_INTERVAL_SEC) {
                // Avoid unnecessary updating.
                return Ok(());
            }

            let start = Instant::now();
            (
                try_connect_leader(Arc::clone(&inner.env), &inner.security_mgr, &inner.members)?,
                start,
            )
        };

        {
            let mut inner = self.inner.wl();
            let (tx, rx) = client.region_heartbeat().unwrap();
            warn!("heartbeat sender and receiver are stale, refreshing..");

            // Try to cancel an unused heartbeat sender.
            if let Either::Left(Some(ref mut r)) = inner.hb_sender {
                info!("cancel region heartbeat sender");
                r.cancel();
            }
            inner.hb_sender = Either::Left(Some(tx));
            if let Either::Right(ref mut task) = inner.hb_receiver {
                task.notify();
            }
            inner.hb_receiver = Either::Left(Some(rx));
            inner.client = client;
            inner.members = members;
            inner.last_update = Instant::now();
            if let Some(ref on_reconnect) = inner.on_reconnect {
                on_reconnect();
            }
        }
        warn!("updating PD client done, spent {:?}", start.elapsed());
        Ok(())
    }
}

pub const RECONNECT_INTERVAL_SEC: u64 = 1; // 1s

/// The context of sending requets.
pub struct Request<Req, Resp, F> {
    reconnect_count: usize,
    request_sent: usize,

    client: LeaderClient,

    req: Req,
    resp: Option<Result<Resp>>,
    func: F,
}

const MAX_REQUEST_COUNT: usize = 3;

impl<Req, Resp, F> Request<Req, Resp, F>
where
    Req: Clone + Send + 'static,
    Resp: Send + 'static,
    F: FnMut(&RwLock<Inner>, Req) -> PdFuture<Resp> + Send + 'static,
{
    fn reconnect_if_needed(mut self) -> Box<Future<Item = Self, Error = Self> + Send> {
        debug!("reconnect remains: {}", self.reconnect_count);

        if self.request_sent < MAX_REQUEST_COUNT {
            return Box::new(ok(self));
        }

        // Updating client.
        self.reconnect_count -= 1;

        // FIXME: should not block the core.
        warn!("updating PD client, block the tokio core");
        match self.client.reconnect() {
            Ok(_) => {
                self.request_sent = 0;
                Box::new(ok(self))
            }
            Err(_) => Box::new(
                self.client
                    .timer
                    .delay(Instant::now() + Duration::from_secs(RECONNECT_INTERVAL_SEC))
                    .then(|_| Err(self)),
            ),
        }
    }

    fn send_and_receive(mut self) -> Box<Future<Item = Self, Error = Self> + Send> {
        self.request_sent += 1;
        debug!("request sent: {}", self.request_sent);
        let r = self.req.clone();

        Box::new(ok(self).and_then(|mut ctx| {
            let req = (ctx.func)(&ctx.client.inner, r);
            req.then(|resp| match resp {
                Ok(resp) => {
                    ctx.resp = Some(Ok(resp));
                    Ok(ctx)
                }
                Err(err) => {
                    error!("request failed: {:?}", err);
                    Err(ctx)
                }
            })
        }))
    }

    fn break_or_continue(ctx: result::Result<Self, Self>) -> Result<Loop<Self, Self>> {
        let ctx = match ctx {
            Ok(ctx) | Err(ctx) => ctx,
        };
        let done = ctx.reconnect_count == 0 || ctx.resp.is_some();
        if done {
            Ok(Loop::Break(ctx))
        } else {
            Ok(Loop::Continue(ctx))
        }
    }

    fn post_loop(ctx: Result<Self>) -> Result<Resp> {
        let ctx = ctx.expect("end loop with Ok(_)");
        ctx.resp.unwrap_or_else(|| Err(box_err!("fail to request")))
    }

    /// Returns a Future, it is resolves once a future returned by the closure
    /// is resolved successfully, otherwise it repeats `retry` times.
    pub fn execute(self) -> PdFuture<Resp> {
        let ctx = self;
        Box::new(
            loop_fn(ctx, |ctx| {
                ctx.reconnect_if_needed()
                    .and_then(Self::send_and_receive)
                    .then(Self::break_or_continue)
            }).then(Self::post_loop),
        )
    }
}

/// Do a request in synchronized fashion.
pub fn sync_request<F, R>(client: &LeaderClient, retry: usize, func: F) -> Result<R>
where
    F: Fn(&PdClient) -> GrpcResult<R>,
{
    for _ in 0..retry {
        // DO NOT put any lock operation in match statement, or it will cause dead lock!
        let ret = { func(&client.inner.rl().client).map_err(Error::Grpc) };
        match ret {
            Ok(r) => {
                return Ok(r);
            }
            Err(e) => {
                error!("fail to request: {:?}", e);
                if let Err(e) = client.reconnect() {
                    error!("fail to reconnect: {:?}", e);
                }
            }
        }
    }

    Err(box_err!("fail to request"))
}

pub fn validate_endpoints(
    env: Arc<Environment>,
    cfg: &Config,
    security_mgr: &SecurityManager,
) -> Result<(PdClient, GetMembersResponse)> {
    let len = cfg.endpoints.len();
    let mut endpoints_set = HashSet::with_capacity_and_hasher(len, Default::default());

    let mut members = None;
    let mut cluster_id = None;
    for ep in &cfg.endpoints {
        if !endpoints_set.insert(ep) {
            return Err(box_err!("duplicate PD endpoint {}", ep));
        }

        let (_, resp) = match connect(Arc::clone(&env), security_mgr, ep) {
            Ok(resp) => resp,
            // Ignore failed PD node.
            Err(e) => {
                error!("PD endpoint {} failed to respond: {:?}", ep, e);
                continue;
            }
        };

        // Check cluster ID.
        let cid = resp.get_header().get_cluster_id();
        if let Some(sample) = cluster_id {
            if sample != cid {
                return Err(box_err!(
                    "PD response cluster_id mismatch, want {}, got {}",
                    sample,
                    cid
                ));
            }
        } else {
            cluster_id = Some(cid);
        }
        // TODO: check all fields later?

        if members.is_none() {
            members = Some(resp);
        }
    }

    match members {
        Some(members) => {
            let (client, members) = try_connect_leader(Arc::clone(&env), security_mgr, &members)?;
            info!("All PD endpoints are consistent: {:?}", cfg.endpoints);
            Ok((client, members))
        }
        _ => Err(box_err!("PD cluster failed to respond")),
    }
}

fn connect(
    env: Arc<Environment>,
    security_mgr: &SecurityManager,
    addr: &str,
) -> Result<(PdClient, GetMembersResponse)> {
    info!("connect to PD endpoint: {:?}", addr);
    let addr = addr
        .trim_left_matches("http://")
        .trim_left_matches("https://");
    let cb = ChannelBuilder::new(env)
        .keepalive_time(Duration::from_secs(10))
        .keepalive_timeout(Duration::from_secs(3));

    let channel = security_mgr.connect(cb, addr);
    let client = PdClient::new(channel);
    let option = CallOption::default().timeout(Duration::from_secs(REQUEST_TIMEOUT));
    match client.get_members_opt(&GetMembersRequest::new(), option) {
        Ok(resp) => Ok((client, resp)),
        Err(e) => Err(Error::Grpc(e)),
    }
}

pub fn try_connect_leader(
    env: Arc<Environment>,
    security_mgr: &SecurityManager,
    previous: &GetMembersResponse,
) -> Result<(PdClient, GetMembersResponse)> {
    let previous_leader = previous.get_leader();
    let members = previous.get_members();
    let cluster_id = previous.get_header().get_cluster_id();
    let mut resp = None;
    // Try to connect to other members, then the previous leader.
    'outer: for m in members
        .into_iter()
        .filter(|m| *m != previous_leader)
        .chain(&[previous_leader.clone()])
    {
        for ep in m.get_client_urls() {
            match connect(Arc::clone(&env), security_mgr, ep.as_str()) {
                Ok((_, r)) => {
                    let new_cluster_id = r.get_header().get_cluster_id();
                    if new_cluster_id == cluster_id {
                        resp = Some(r);
                        break 'outer;
                    } else {
                        panic!(
                            "{} no longer belongs to cluster {}, it is in {}",
                            ep, cluster_id, new_cluster_id
                        );
                    }
                }
                Err(e) => {
                    error!("failed to connect to {}, {:?}", ep, e);
                    continue;
                }
            }
        }
    }

    // Then try to connect the PD cluster leader.
    if let Some(resp) = resp {
        let leader = resp.get_leader().clone();
        for ep in leader.get_client_urls() {
            if let Ok((client, _)) = connect(Arc::clone(&env), security_mgr, ep.as_str()) {
                info!("connect to PD leader {:?}", ep);
                return Ok((client, resp));
            }
        }
    }

    Err(box_err!("failed to connect to {:?}", members))
}

pub fn check_resp_header(header: &ResponseHeader) -> Result<()> {
    if !header.has_error() {
        return Ok(());
    }
    // TODO: translate more error types
    let err = header.get_error();
    match err.get_field_type() {
        ErrorType::ALREADY_BOOTSTRAPPED => Err(Error::ClusterBootstrapped(header.get_cluster_id())),
        ErrorType::NOT_BOOTSTRAPPED => Err(Error::ClusterNotBootstrapped(header.get_cluster_id())),
        _ => Err(box_err!(err.get_message())),
    }
}
<commit_msg>use verb tense to indicate connection state (#3416)<commit_after>// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::result;
use std::sync::Arc;
use std::sync::RwLock;
use std::time::Duration;
use std::time::Instant;
use util::collections::HashSet;

use futures::future::{loop_fn, ok, Loop};
use futures::sync::mpsc::UnboundedSender;
use futures::task::Task;
use futures::{task, Async, Future, Poll, Stream};
use grpc::{
    CallOption, ChannelBuilder, ClientDuplexReceiver, ClientDuplexSender, Environment,
    Result as GrpcResult,
};
use kvproto::pdpb::{
    ErrorType, GetMembersRequest, GetMembersResponse, Member, RegionHeartbeatRequest,
    RegionHeartbeatResponse, ResponseHeader,
};
use kvproto::pdpb_grpc::PdClient;
use tokio_timer::timer::Handle;

use super::{Config, Error, PdFuture, Result, REQUEST_TIMEOUT};
use util::security::SecurityManager;
use util::timer::GLOBAL_TIMER_HANDLE;
use util::{Either, HandyRwLock};

pub struct Inner {
    env: Arc<Environment>,
    pub hb_sender: Either<
        Option<ClientDuplexSender<RegionHeartbeatRequest>>,
        UnboundedSender<RegionHeartbeatRequest>,
    >,
    pub hb_receiver: Either<Option<ClientDuplexReceiver<RegionHeartbeatResponse>>, Task>,
    pub client: PdClient,
    members: GetMembersResponse,
    security_mgr: Arc<SecurityManager>,
    on_reconnect: Option<Box<Fn() + Sync + Send + 'static>>,

    last_update: Instant,
}

pub struct HeartbeatReceiver {
    receiver: Option<ClientDuplexReceiver<RegionHeartbeatResponse>>,
    inner: Arc<RwLock<Inner>>,
}

impl Stream for HeartbeatReceiver {
    type Item = RegionHeartbeatResponse;
    type Error = Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Error> {
        loop {
            if let Some(ref mut receiver) = self.receiver {
                match receiver.poll() {
                    Ok(Async::Ready(Some(item))) => return Ok(Async::Ready(Some(item))),
                    Ok(Async::NotReady) => return Ok(Async::NotReady),
                    // If it's None or there's error, we need to update receiver.
                    _ => {}
                }
            }

            self.receiver.take();

            let mut inner = self.inner.wl();
            let mut receiver = None;
            if let Either::Left(ref mut recv) = inner.hb_receiver {
                receiver = recv.take();
            }
            if receiver.is_some() {
                info!("heartbeat receiver is refreshed.");
                self.receiver = receiver;
            } else {
                inner.hb_receiver = Either::Right(task::current());
                return Ok(Async::NotReady);
            }
        }
    }
}

/// A leader client doing requests asynchronous.
pub struct LeaderClient {
    timer: Handle,
    inner: Arc<RwLock<Inner>>,
}

impl LeaderClient {
    pub fn new(
        env: Arc<Environment>,
        security_mgr: Arc<SecurityManager>,
        client: PdClient,
        members: GetMembersResponse,
    ) -> LeaderClient {
        let (tx, rx) = client.region_heartbeat().unwrap();
        LeaderClient {
            timer: GLOBAL_TIMER_HANDLE.clone(),
            inner: Arc::new(RwLock::new(Inner {
                env,
                hb_sender: Either::Left(Some(tx)),
                hb_receiver: Either::Left(Some(rx)),
                client,
                members,
                security_mgr,
                on_reconnect: None,

                last_update: Instant::now(),
            })),
        }
    }

    pub fn handle_region_heartbeat_response<F>(&self, f: F) -> PdFuture<()>
    where
        F: Fn(RegionHeartbeatResponse) + Send + 'static,
    {
        let recv = HeartbeatReceiver {
            receiver: None,
            inner: Arc::clone(&self.inner),
        };
        Box::new(
            recv.for_each(move |resp| {
                f(resp);
                Ok(())
            }).map_err(|e| panic!("unexpected error: {:?}", e)),
        )
    }

    pub fn on_reconnect(&self, f: Box<Fn() + Sync + Send + 'static>) {
        let mut inner = self.inner.wl();
        inner.on_reconnect = Some(f);
    }

    pub fn request<Req, Resp, F>(&self, req: Req, func: F, retry: usize) -> Request<Req, Resp, F>
    where
        Req: Clone + 'static,
        F: FnMut(&RwLock<Inner>, Req) -> PdFuture<Resp> + Send + 'static,
    {
        Request {
            reconnect_count: retry,
            request_sent: 0,
            client: LeaderClient {
                timer: self.timer.clone(),
                inner: Arc::clone(&self.inner),
            },
            req,
            resp: None,
            func,
        }
    }

    pub fn get_leader(&self) -> Member {
        self.inner.rl().members.get_leader().clone()
    }

    // Re-establish connection with PD leader in synchronized fashion.
    pub fn reconnect(&self) -> Result<()> {
        let ((client, members), start) = {
            let inner = self.inner.rl();
            if inner.last_update.elapsed() < Duration::from_secs(RECONNECT_INTERVAL_SEC) {
                // Avoid unnecessary updating.
                return Ok(());
            }

            let start = Instant::now();
            (
                try_connect_leader(Arc::clone(&inner.env), &inner.security_mgr, &inner.members)?,
                start,
            )
        };

        {
            let mut inner = self.inner.wl();
            let (tx, rx) = client.region_heartbeat().unwrap();
            warn!("heartbeat sender and receiver are stale, refreshing..");

            // Try to cancel an unused heartbeat sender.
            if let Either::Left(Some(ref mut r)) = inner.hb_sender {
                info!("cancel region heartbeat sender");
                r.cancel();
            }
            inner.hb_sender = Either::Left(Some(tx));
            if let Either::Right(ref mut task) = inner.hb_receiver {
                task.notify();
            }
            inner.hb_receiver = Either::Left(Some(rx));
            inner.client = client;
            inner.members = members;
            inner.last_update = Instant::now();
            if let Some(ref on_reconnect) = inner.on_reconnect {
                on_reconnect();
            }
        }
        warn!("updating PD client done, spent {:?}", start.elapsed());
        Ok(())
    }
}

pub const RECONNECT_INTERVAL_SEC: u64 = 1; // 1s

/// The context of sending requets.
pub struct Request<Req, Resp, F> {
    reconnect_count: usize,
    request_sent: usize,

    client: LeaderClient,

    req: Req,
    resp: Option<Result<Resp>>,
    func: F,
}

const MAX_REQUEST_COUNT: usize = 3;

impl<Req, Resp, F> Request<Req, Resp, F>
where
    Req: Clone + Send + 'static,
    Resp: Send + 'static,
    F: FnMut(&RwLock<Inner>, Req) -> PdFuture<Resp> + Send + 'static,
{
    fn reconnect_if_needed(mut self) -> Box<Future<Item = Self, Error = Self> + Send> {
        debug!("reconnect remains: {}", self.reconnect_count);

        if self.request_sent < MAX_REQUEST_COUNT {
            return Box::new(ok(self));
        }

        // Updating client.
        self.reconnect_count -= 1;

        // FIXME: should not block the core.
        warn!("updating PD client, block the tokio core");
        match self.client.reconnect() {
            Ok(_) => {
                self.request_sent = 0;
                Box::new(ok(self))
            }
            Err(_) => Box::new(
                self.client
                    .timer
                    .delay(Instant::now() + Duration::from_secs(RECONNECT_INTERVAL_SEC))
                    .then(|_| Err(self)),
            ),
        }
    }

    fn send_and_receive(mut self) -> Box<Future<Item = Self, Error = Self> + Send> {
        self.request_sent += 1;
        debug!("request sent: {}", self.request_sent);
        let r = self.req.clone();

        Box::new(ok(self).and_then(|mut ctx| {
            let req = (ctx.func)(&ctx.client.inner, r);
            req.then(|resp| match resp {
                Ok(resp) => {
                    ctx.resp = Some(Ok(resp));
                    Ok(ctx)
                }
                Err(err) => {
                    error!("request failed: {:?}", err);
                    Err(ctx)
                }
            })
        }))
    }

    fn break_or_continue(ctx: result::Result<Self, Self>) -> Result<Loop<Self, Self>> {
        let ctx = match ctx {
            Ok(ctx) | Err(ctx) => ctx,
        };
        let done = ctx.reconnect_count == 0 || ctx.resp.is_some();
        if done {
            Ok(Loop::Break(ctx))
        } else {
            Ok(Loop::Continue(ctx))
        }
    }

    fn post_loop(ctx: Result<Self>) -> Result<Resp> {
        let ctx = ctx.expect("end loop with Ok(_)");
        ctx.resp.unwrap_or_else(|| Err(box_err!("fail to request")))
    }

    /// Returns a Future, it is resolves once a future returned by the closure
    /// is resolved successfully, otherwise it repeats `retry` times.
    pub fn execute(self) -> PdFuture<Resp> {
        let ctx = self;
        Box::new(
            loop_fn(ctx, |ctx| {
                ctx.reconnect_if_needed()
                    .and_then(Self::send_and_receive)
                    .then(Self::break_or_continue)
            }).then(Self::post_loop),
        )
    }
}

/// Do a request in synchronized fashion.
pub fn sync_request<F, R>(client: &LeaderClient, retry: usize, func: F) -> Result<R>
where
    F: Fn(&PdClient) -> GrpcResult<R>,
{
    for _ in 0..retry {
        // DO NOT put any lock operation in match statement, or it will cause dead lock!
        let ret = { func(&client.inner.rl().client).map_err(Error::Grpc) };
        match ret {
            Ok(r) => {
                return Ok(r);
            }
            Err(e) => {
                error!("fail to request: {:?}", e);
                if let Err(e) = client.reconnect() {
                    error!("fail to reconnect: {:?}", e);
                }
            }
        }
    }

    Err(box_err!("fail to request"))
}

pub fn validate_endpoints(
    env: Arc<Environment>,
    cfg: &Config,
    security_mgr: &SecurityManager,
) -> Result<(PdClient, GetMembersResponse)> {
    let len = cfg.endpoints.len();
    let mut endpoints_set = HashSet::with_capacity_and_hasher(len, Default::default());

    let mut members = None;
    let mut cluster_id = None;
    for ep in &cfg.endpoints {
        if !endpoints_set.insert(ep) {
            return Err(box_err!("duplicate PD endpoint {}", ep));
        }

        let (_, resp) = match connect(Arc::clone(&env), security_mgr, ep) {
            Ok(resp) => resp,
            // Ignore failed PD node.
            Err(e) => {
                error!("PD endpoint {} failed to respond: {:?}", ep, e);
                continue;
            }
        };

        // Check cluster ID.
        let cid = resp.get_header().get_cluster_id();
        if let Some(sample) = cluster_id {
            if sample != cid {
                return Err(box_err!(
                    "PD response cluster_id mismatch, want {}, got {}",
                    sample,
                    cid
                ));
            }
        } else {
            cluster_id = Some(cid);
        }
        // TODO: check all fields later?

        if members.is_none() {
            members = Some(resp);
        }
    }

    match members {
        Some(members) => {
            let (client, members) = try_connect_leader(Arc::clone(&env), security_mgr, &members)?;
            info!("All PD endpoints are consistent: {:?}", cfg.endpoints);
            Ok((client, members))
        }
        _ => Err(box_err!("PD cluster failed to respond")),
    }
}

fn connect(
    env: Arc<Environment>,
    security_mgr: &SecurityManager,
    addr: &str,
) -> Result<(PdClient, GetMembersResponse)> {
    info!("connecting to PD endpoint: {:?}", addr);
    let addr = addr
        .trim_left_matches("http://")
        .trim_left_matches("https://");
    let cb = ChannelBuilder::new(env)
        .keepalive_time(Duration::from_secs(10))
        .keepalive_timeout(Duration::from_secs(3));

    let channel = security_mgr.connect(cb, addr);
    let client = PdClient::new(channel);
    let option = CallOption::default().timeout(Duration::from_secs(REQUEST_TIMEOUT));
    match client.get_members_opt(&GetMembersRequest::new(), option) {
        Ok(resp) => Ok((client, resp)),
        Err(e) => Err(Error::Grpc(e)),
    }
}

pub fn try_connect_leader(
    env: Arc<Environment>,
    security_mgr: &SecurityManager,
    previous: &GetMembersResponse,
) -> Result<(PdClient, GetMembersResponse)> {
    let previous_leader = previous.get_leader();
    let members = previous.get_members();
    let cluster_id = previous.get_header().get_cluster_id();
    let mut resp = None;
    // Try to connect to other members, then the previous leader.
    'outer: for m in members
        .into_iter()
        .filter(|m| *m != previous_leader)
        .chain(&[previous_leader.clone()])
    {
        for ep in m.get_client_urls() {
            match connect(Arc::clone(&env), security_mgr, ep.as_str()) {
                Ok((_, r)) => {
                    let new_cluster_id = r.get_header().get_cluster_id();
                    if new_cluster_id == cluster_id {
                        resp = Some(r);
                        break 'outer;
                    } else {
                        panic!(
                            "{} no longer belongs to cluster {}, it is in {}",
                            ep, cluster_id, new_cluster_id
                        );
                    }
                }
                Err(e) => {
                    error!("failed to connect to {}, {:?}", ep, e);
                    continue;
                }
            }
        }
    }

    // Then try to connect the PD cluster leader.
    if let Some(resp) = resp {
        let leader = resp.get_leader().clone();
        for ep in leader.get_client_urls() {
            if let Ok((client, _)) = connect(Arc::clone(&env), security_mgr, ep.as_str()) {
                info!("connected to PD leader {:?}", ep);
                return Ok((client, resp));
            }
        }
    }

    Err(box_err!("failed to connect to {:?}", members))
}

pub fn check_resp_header(header: &ResponseHeader) -> Result<()> {
    if !header.has_error() {
        return Ok(());
    }
    // TODO: translate more error types
    let err = header.get_error();
    match err.get_field_type() {
        ErrorType::ALREADY_BOOTSTRAPPED => Err(Error::ClusterBootstrapped(header.get_cluster_id())),
        ErrorType::NOT_BOOTSTRAPPED => Err(Error::ClusterNotBootstrapped(header.get_cluster_id())),
        _ => Err(box_err!(err.get_message())),
    }
}
<|endoftext|>


<commit_before>use rustc::mir::repr as mir;

use error::{EvalError, EvalResult};
use memory::Pointer;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PrimVal {
    Bool(bool),
    I8(i8), I16(i16), I32(i32), I64(i64),
    U8(u8), U16(u16), U32(u32), U64(u64),

    AbstractPtr(Pointer),
    FnPtr(Pointer),
    IntegerPtr(u64),
    Char(char),

    F32(f32), F64(f64),
}

/// returns the result of the operation and whether the operation overflowed
pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResult<'tcx, (PrimVal, bool)> {
    use rustc::mir::repr::BinOp::*;
    use self::PrimVal::*;

    macro_rules! overflow {
        ($v:ident, $v2:ident, $l:ident, $op:ident, $r:ident) => ({
            let (val, of) = $l.$op($r);
            if of {
                return Ok(($v(val), true));
            } else {
                $v(val)
            }
        })
    }

    macro_rules! int_binops {
        ($v:ident, $l:ident, $r:ident) => ({
            match bin_op {
                Add    => overflow!($v, $v, $l, overflowing_add, $r),
                Sub    => overflow!($v, $v, $l, overflowing_sub, $r),
                Mul    => overflow!($v, $v, $l, overflowing_mul, $r),
                Div    => overflow!($v, $v, $l, overflowing_div, $r),
                Rem    => overflow!($v, $v, $l, overflowing_rem, $r),
                BitXor => $v($l ^ $r),
                BitAnd => $v($l & $r),
                BitOr  => $v($l | $r),

                // these have already been handled
                Shl => unreachable!(),
                Shr => unreachable!(),

                Eq => Bool($l == $r),
                Ne => Bool($l != $r),
                Lt => Bool($l < $r),
                Le => Bool($l <= $r),
                Gt => Bool($l > $r),
                Ge => Bool($l >= $r),
            }
        })
    }

    macro_rules! float_binops {
        ($v:ident, $l:ident, $r:ident) => ({
            match bin_op {
                Add    => $v($l + $r),
                Sub    => $v($l - $r),
                Mul    => $v($l * $r),
                Div    => $v($l / $r),
                Rem    => $v($l % $r),

                // invalid float ops
                BitXor => unreachable!(),
                BitAnd => unreachable!(),
                BitOr  => unreachable!(),
                Shl => unreachable!(),
                Shr => unreachable!(),

                // directly comparing floats is questionable
                // miri could forbid it, or at least miri as rust const eval should forbid it
                Eq => Bool($l == $r),
                Ne => Bool($l != $r),
                Lt => Bool($l < $r),
                Le => Bool($l <= $r),
                Gt => Bool($l > $r),
                Ge => Bool($l >= $r),
            }
        })
    }

    fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp) -> EvalResult<'tcx, PrimVal> {
        use rustc::mir::repr::BinOp::*;
        match bin_op {
            Eq => Ok(Bool(false)),
            Ne => Ok(Bool(true)),
            Lt | Le | Gt | Ge => Err(EvalError::InvalidPointerMath),
            _ => unimplemented!(),
        }
    }

    match bin_op {
        // can have rhs with a different numeric type
        Shl | Shr => {
            // these numbers are the maximum number a bitshift rhs could possibly have
            // e.g. u16 can be bitshifted by 0..16, so masking with 0b1111 (16 - 1) will ensure we are in that range
            let type_bits: u32 = match left {
                I8(_) | U8(_) => 8,
                I16(_) | U16(_) => 16,
                I32(_) | U32(_) => 32,
                I64(_) | U64(_) => 64,
                _ => unreachable!(),
            };
            assert!(type_bits.is_power_of_two());
            // turn into `u32` because `overflowing_sh{l,r}` only take `u32`
            let r = match right {
                I8(i) => i as u32,
                I16(i) => i as u32,
                I32(i) => i as u32,
                I64(i) => i as u32,
                U8(i) => i as u32,
                U16(i) => i as u32,
                U32(i) => i as u32,
                U64(i) => i as u32,
                _ => panic!("bad MIR: bitshift rhs is not integral"),
            };
            // apply mask
            let r = r & (type_bits - 1);
            macro_rules! shift {
                ($v:ident, $l:ident, $r:ident) => ({
                    match bin_op {
                        Shl => overflow!($v, U32, $l, overflowing_shl, $r),
                        Shr => overflow!($v, U32, $l, overflowing_shr, $r),
                        _ => unreachable!(),
                    }
                })
            }
            let val = match left {
                I8(l) => shift!(I8, l, r),
                I16(l) => shift!(I16, l, r),
                I32(l) => shift!(I32, l, r),
                I64(l) => shift!(I64, l, r),
                U8(l) => shift!(U8, l, r),
                U16(l) => shift!(U16, l, r),
                U32(l) => shift!(U32, l, r),
                U64(l) => shift!(U64, l, r),
                _ => unreachable!(),
            };
            return Ok((val, false));
        },
        _ => {},
    }

    let val = match (left, right) {
        (I8(l),  I8(r))  => int_binops!(I8, l, r),
        (I16(l), I16(r)) => int_binops!(I16, l, r),
        (I32(l), I32(r)) => int_binops!(I32, l, r),
        (I64(l), I64(r)) => int_binops!(I64, l, r),
        (U8(l),  U8(r))  => int_binops!(U8, l, r),
        (U16(l), U16(r)) => int_binops!(U16, l, r),
        (U32(l), U32(r)) => int_binops!(U32, l, r),
        (U64(l), U64(r)) => int_binops!(U64, l, r),
        (F32(l), F32(r)) => float_binops!(F32, l, r),
        (F64(l), F64(r)) => float_binops!(F64, l, r),
        (Char(l), Char(r)) => match bin_op {
            Eq => Bool(l == r),
            Ne => Bool(l != r),
            Lt => Bool(l < r),
            Le => Bool(l <= r),
            Gt => Bool(l > r),
            Ge => Bool(l >= r),
            _ => panic!("invalid char op: {:?}", bin_op),
        },

        (Bool(l), Bool(r)) => {
            Bool(match bin_op {
                Eq => l == r,
                Ne => l != r,
                Lt => l < r,
                Le => l <= r,
                Gt => l > r,
                Ge => l >= r,
                BitOr => l | r,
                BitXor => l ^ r,
                BitAnd => l & r,
                Add | Sub | Mul | Div | Rem | Shl | Shr => return Err(EvalError::InvalidBoolOp(bin_op)),
            })
        }

        (IntegerPtr(l), IntegerPtr(r)) => int_binops!(IntegerPtr, l, r),

        (AbstractPtr(_), IntegerPtr(_)) |
        (IntegerPtr(_), AbstractPtr(_)) |
        (FnPtr(_), AbstractPtr(_)) |
        (AbstractPtr(_), FnPtr(_)) |
        (FnPtr(_), IntegerPtr(_)) |
        (IntegerPtr(_), FnPtr(_)) =>
            unrelated_ptr_ops(bin_op)?,

        (FnPtr(l_ptr), FnPtr(r_ptr)) => match bin_op {
            Eq => Bool(l_ptr == r_ptr),
            Ne => Bool(l_ptr != r_ptr),
            _ => return Err(EvalError::Unimplemented(format!("unimplemented fn ptr comparison: {:?}", bin_op))),
        },

        (AbstractPtr(l_ptr), AbstractPtr(r_ptr)) => {
            if l_ptr.alloc_id != r_ptr.alloc_id {
                return Ok((unrelated_ptr_ops(bin_op)?, false));
            }

            let l = l_ptr.offset;
            let r = r_ptr.offset;

            match bin_op {
                Eq => Bool(l == r),
                Ne => Bool(l != r),
                Lt => Bool(l < r),
                Le => Bool(l <= r),
                Gt => Bool(l > r),
                Ge => Bool(l >= r),
                _ => return Err(EvalError::Unimplemented(format!("unimplemented ptr op: {:?}", bin_op))),
            }
        }

        (l, r) => return Err(EvalError::Unimplemented(format!("unimplemented binary op: {:?}, {:?}, {:?}", l, r, bin_op))),
    };

    Ok((val, false))
}

pub fn unary_op<'tcx>(un_op: mir::UnOp, val: PrimVal) -> EvalResult<'tcx, PrimVal> {
    use rustc::mir::repr::UnOp::*;
    use self::PrimVal::*;
    match (un_op, val) {
        (Not, Bool(b)) => Ok(Bool(!b)),
        (Not, I8(n))  => Ok(I8(!n)),
        (Neg, I8(n))  => Ok(I8(-n)),
        (Not, I16(n)) => Ok(I16(!n)),
        (Neg, I16(n)) => Ok(I16(-n)),
        (Not, I32(n)) => Ok(I32(!n)),
        (Neg, I32(n)) => Ok(I32(-n)),
        (Not, I64(n)) => Ok(I64(!n)),
        (Neg, I64(n)) => Ok(I64(-n)),
        (Not, U8(n))  => Ok(U8(!n)),
        (Not, U16(n)) => Ok(U16(!n)),
        (Not, U32(n)) => Ok(U32(!n)),
        (Not, U64(n)) => Ok(U64(!n)),

        (Neg, F64(n)) => Ok(F64(-n)),
        (Neg, F32(n)) => Ok(F32(-n)),
        _ => Err(EvalError::Unimplemented(format!("unimplemented unary op: {:?}, {:?}", un_op, val))),
    }
}
<commit_msg>comparing floats is necessary in rare cases<commit_after>use rustc::mir::repr as mir;

use error::{EvalError, EvalResult};
use memory::Pointer;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PrimVal {
    Bool(bool),
    I8(i8), I16(i16), I32(i32), I64(i64),
    U8(u8), U16(u16), U32(u32), U64(u64),

    AbstractPtr(Pointer),
    FnPtr(Pointer),
    IntegerPtr(u64),
    Char(char),

    F32(f32), F64(f64),
}

/// returns the result of the operation and whether the operation overflowed
pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResult<'tcx, (PrimVal, bool)> {
    use rustc::mir::repr::BinOp::*;
    use self::PrimVal::*;

    macro_rules! overflow {
        ($v:ident, $v2:ident, $l:ident, $op:ident, $r:ident) => ({
            let (val, of) = $l.$op($r);
            if of {
                return Ok(($v(val), true));
            } else {
                $v(val)
            }
        })
    }

    macro_rules! int_binops {
        ($v:ident, $l:ident, $r:ident) => ({
            match bin_op {
                Add    => overflow!($v, $v, $l, overflowing_add, $r),
                Sub    => overflow!($v, $v, $l, overflowing_sub, $r),
                Mul    => overflow!($v, $v, $l, overflowing_mul, $r),
                Div    => overflow!($v, $v, $l, overflowing_div, $r),
                Rem    => overflow!($v, $v, $l, overflowing_rem, $r),
                BitXor => $v($l ^ $r),
                BitAnd => $v($l & $r),
                BitOr  => $v($l | $r),

                // these have already been handled
                Shl => unreachable!(),
                Shr => unreachable!(),

                Eq => Bool($l == $r),
                Ne => Bool($l != $r),
                Lt => Bool($l < $r),
                Le => Bool($l <= $r),
                Gt => Bool($l > $r),
                Ge => Bool($l >= $r),
            }
        })
    }

    macro_rules! float_binops {
        ($v:ident, $l:ident, $r:ident) => ({
            match bin_op {
                Add    => $v($l + $r),
                Sub    => $v($l - $r),
                Mul    => $v($l * $r),
                Div    => $v($l / $r),
                Rem    => $v($l % $r),

                // invalid float ops
                BitXor => unreachable!(),
                BitAnd => unreachable!(),
                BitOr  => unreachable!(),
                Shl => unreachable!(),
                Shr => unreachable!(),

                Eq => Bool($l == $r),
                Ne => Bool($l != $r),
                Lt => Bool($l < $r),
                Le => Bool($l <= $r),
                Gt => Bool($l > $r),
                Ge => Bool($l >= $r),
            }
        })
    }

    fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp) -> EvalResult<'tcx, PrimVal> {
        use rustc::mir::repr::BinOp::*;
        match bin_op {
            Eq => Ok(Bool(false)),
            Ne => Ok(Bool(true)),
            Lt | Le | Gt | Ge => Err(EvalError::InvalidPointerMath),
            _ => unimplemented!(),
        }
    }

    match bin_op {
        // can have rhs with a different numeric type
        Shl | Shr => {
            // these numbers are the maximum number a bitshift rhs could possibly have
            // e.g. u16 can be bitshifted by 0..16, so masking with 0b1111 (16 - 1) will ensure we are in that range
            let type_bits: u32 = match left {
                I8(_) | U8(_) => 8,
                I16(_) | U16(_) => 16,
                I32(_) | U32(_) => 32,
                I64(_) | U64(_) => 64,
                _ => unreachable!(),
            };
            assert!(type_bits.is_power_of_two());
            // turn into `u32` because `overflowing_sh{l,r}` only take `u32`
            let r = match right {
                I8(i) => i as u32,
                I16(i) => i as u32,
                I32(i) => i as u32,
                I64(i) => i as u32,
                U8(i) => i as u32,
                U16(i) => i as u32,
                U32(i) => i as u32,
                U64(i) => i as u32,
                _ => panic!("bad MIR: bitshift rhs is not integral"),
            };
            // apply mask
            let r = r & (type_bits - 1);
            macro_rules! shift {
                ($v:ident, $l:ident, $r:ident) => ({
                    match bin_op {
                        Shl => overflow!($v, U32, $l, overflowing_shl, $r),
                        Shr => overflow!($v, U32, $l, overflowing_shr, $r),
                        _ => unreachable!(),
                    }
                })
            }
            let val = match left {
                I8(l) => shift!(I8, l, r),
                I16(l) => shift!(I16, l, r),
                I32(l) => shift!(I32, l, r),
                I64(l) => shift!(I64, l, r),
                U8(l) => shift!(U8, l, r),
                U16(l) => shift!(U16, l, r),
                U32(l) => shift!(U32, l, r),
                U64(l) => shift!(U64, l, r),
                _ => unreachable!(),
            };
            return Ok((val, false));
        },
        _ => {},
    }

    let val = match (left, right) {
        (I8(l),  I8(r))  => int_binops!(I8, l, r),
        (I16(l), I16(r)) => int_binops!(I16, l, r),
        (I32(l), I32(r)) => int_binops!(I32, l, r),
        (I64(l), I64(r)) => int_binops!(I64, l, r),
        (U8(l),  U8(r))  => int_binops!(U8, l, r),
        (U16(l), U16(r)) => int_binops!(U16, l, r),
        (U32(l), U32(r)) => int_binops!(U32, l, r),
        (U64(l), U64(r)) => int_binops!(U64, l, r),
        (F32(l), F32(r)) => float_binops!(F32, l, r),
        (F64(l), F64(r)) => float_binops!(F64, l, r),
        (Char(l), Char(r)) => match bin_op {
            Eq => Bool(l == r),
            Ne => Bool(l != r),
            Lt => Bool(l < r),
            Le => Bool(l <= r),
            Gt => Bool(l > r),
            Ge => Bool(l >= r),
            _ => panic!("invalid char op: {:?}", bin_op),
        },

        (Bool(l), Bool(r)) => {
            Bool(match bin_op {
                Eq => l == r,
                Ne => l != r,
                Lt => l < r,
                Le => l <= r,
                Gt => l > r,
                Ge => l >= r,
                BitOr => l | r,
                BitXor => l ^ r,
                BitAnd => l & r,
                Add | Sub | Mul | Div | Rem | Shl | Shr => return Err(EvalError::InvalidBoolOp(bin_op)),
            })
        }

        (IntegerPtr(l), IntegerPtr(r)) => int_binops!(IntegerPtr, l, r),

        (AbstractPtr(_), IntegerPtr(_)) |
        (IntegerPtr(_), AbstractPtr(_)) |
        (FnPtr(_), AbstractPtr(_)) |
        (AbstractPtr(_), FnPtr(_)) |
        (FnPtr(_), IntegerPtr(_)) |
        (IntegerPtr(_), FnPtr(_)) =>
            unrelated_ptr_ops(bin_op)?,

        (FnPtr(l_ptr), FnPtr(r_ptr)) => match bin_op {
            Eq => Bool(l_ptr == r_ptr),
            Ne => Bool(l_ptr != r_ptr),
            _ => return Err(EvalError::Unimplemented(format!("unimplemented fn ptr comparison: {:?}", bin_op))),
        },

        (AbstractPtr(l_ptr), AbstractPtr(r_ptr)) => {
            if l_ptr.alloc_id != r_ptr.alloc_id {
                return Ok((unrelated_ptr_ops(bin_op)?, false));
            }

            let l = l_ptr.offset;
            let r = r_ptr.offset;

            match bin_op {
                Eq => Bool(l == r),
                Ne => Bool(l != r),
                Lt => Bool(l < r),
                Le => Bool(l <= r),
                Gt => Bool(l > r),
                Ge => Bool(l >= r),
                _ => return Err(EvalError::Unimplemented(format!("unimplemented ptr op: {:?}", bin_op))),
            }
        }

        (l, r) => return Err(EvalError::Unimplemented(format!("unimplemented binary op: {:?}, {:?}, {:?}", l, r, bin_op))),
    };

    Ok((val, false))
}

pub fn unary_op<'tcx>(un_op: mir::UnOp, val: PrimVal) -> EvalResult<'tcx, PrimVal> {
    use rustc::mir::repr::UnOp::*;
    use self::PrimVal::*;
    match (un_op, val) {
        (Not, Bool(b)) => Ok(Bool(!b)),
        (Not, I8(n))  => Ok(I8(!n)),
        (Neg, I8(n))  => Ok(I8(-n)),
        (Not, I16(n)) => Ok(I16(!n)),
        (Neg, I16(n)) => Ok(I16(-n)),
        (Not, I32(n)) => Ok(I32(!n)),
        (Neg, I32(n)) => Ok(I32(-n)),
        (Not, I64(n)) => Ok(I64(!n)),
        (Neg, I64(n)) => Ok(I64(-n)),
        (Not, U8(n))  => Ok(U8(!n)),
        (Not, U16(n)) => Ok(U16(!n)),
        (Not, U32(n)) => Ok(U32(!n)),
        (Not, U64(n)) => Ok(U64(!n)),

        (Neg, F64(n)) => Ok(F64(-n)),
        (Neg, F32(n)) => Ok(F32(-n)),
        _ => Err(EvalError::Unimplemented(format!("unimplemented unary op: {:?}, {:?}", un_op, val))),
    }
}
<|endoftext|>


<commit_before>//! Raw access to the `Termios` structure and its flags

#[allow(dead_code, missing_docs, non_camel_case_types)]
mod ffi;

use std::fmt;

pub use self::ffi::cc_t;
pub use self::ffi::speed_t;
pub use self::ffi::tcflag_t;

pub use self::ffi::Struct_termios as Termios;

pub use self::ffi::{
    cfgetispeed,
    cfgetospeed,
    cfmakeraw,
    cfsetispeed,
    cfsetospeed,
    cfsetspeed,
    tcdrain,
    tcflow,
    tcflush,
    tcgetattr,
    tcsendbreak,
    tcsetattr,
};

#[cfg(target_os = "freebsd")]
pub use self::ffi::{
    cfmakesane,
    tcgetsid,
    tcsetsid,
};

#[cfg(target_os = "linux")]
pub use self::ffi::{
    tcgetsid,
};

// XXX (Debug) Formatting may change
impl fmt::Debug for Termios {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(f, "iflag:\t{:?}", self.c_iflag));
        try!(writeln!(f, "oflag:\t{:?}", self.c_oflag));
        try!(writeln!(f, "cflag:\t{:?}", self.c_cflag));
        try!(writeln!(f, "lflag:\t{:?}", self.c_lflag));
        try!(writeln!(f, "cc:\t{:?}", self.c_cc));
        try!(writeln!(f, "ispeed:\t{:?}", self.c_ispeed));
        try!(write!(f, "ospeed:\t{:?}", self.c_ospeed));
        Ok(())
    }
}

// FIXME (concat_idents!) All these macros should use only one input

macro_rules! cc {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

cc! {
    NCCS_ = NCCS,
    VDISCARD_ = VDISCARD,
    VEOF_ = VEOF,
    VEOL2_ = VEOL2,
    VEOL_ = VEOL,
    VERASE_ = VERASE,
    VINTR_ = VINTR,
    VKILL_ = VKILL,
    VLNEXT_ = VLNEXT,
    VMIN_ = VMIN,
    VQUIT_ = VQUIT,
    VREPRINT_ = VREPRINT,
    VSTART_ = VSTART,
    VSTOP_ = VSTOP,
    VSUSP_ = VSUSP,
    VTIME_ = VTIME,
    VWERASE_ = VWERASE,
}

#[cfg(target_os = "freebsd")]
cc! {
    VDSUSP_ = VDSUSP,
    VERASE2_ = VERASE2,
    VSTATUS_ = VSTATUS,
}

#[cfg(target_os = "linux")]
cc! {
    VSWTC_ = VSWTC,
}

#[cfg(target_os = "macos")]
cc! {
    VDSUSP_ = VDSUSP,
    VSTATUS_ = VSTATUS,
}

macro_rules! iflag {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

iflag! {
    BRKINT_ = BRKINT,
    ICRNL_ = ICRNL,
    IGNBRK_ = IGNBRK,
    IGNCR_ = IGNCR,
    IGNPAR_ = IGNPAR,
    IMAXBEL_ = IMAXBEL,
    INLCR_ = INLCR,
    INPCK_ = INPCK,
    ISTRIP_ = ISTRIP,
    IXANY_ = IXANY,
    IXOFF_ = IXOFF,
    IXON_ = IXON,
    PARMRK_ = PARMRK,
}

#[cfg(target_os = "linux")]
iflag! {
    IUCLC_ = IUCLC,
    IUTF8_ = IUTF8,
}

#[cfg(target_os = "macos")]
iflag! {
    IUTF8_ = IUTF8,
}

macro_rules! oflag {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

oflag! {
    OCRNL_ = OCRNL,
    ONLCR_ = ONLCR,
    ONLRET_ = ONLRET,
    ONOCR_ = ONOCR,
    OPOST_ = OPOST,
}

#[cfg(target_os = "freebsd")]
oflag! {
    ONOEOT_ = ONOEOT,
    TAB0_ = TAB0,
    TAB3_ = TAB3,
    TABDLY_ = TABDLY,
}

#[cfg(target_os = "linux")]
oflag! {
    OFDEL_ = OFDEL,
    OFILL_ = OFILL,
    OLCUC_ = OLCUC,
}

#[cfg(target_os = "macos")]
oflag! {
    BSDLY_ = BSDLY,
    CRDLY_ = CRDLY,
    FFDLY_ = FFDLY,
    NLDLY_ = NLDLY,
    OFDEL_ = OFDEL,
    OFILL_ = OFILL,
    ONOEOT_ = ONOEOT,
    OXTABS_ = OXTABS,
    TABDLY_ = TABDLY,
    VTDLY_ = VTDLY,
}

macro_rules! cflag {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

cflag! {
    CLOCAL_ = CLOCAL,
    CREAD_ = CREAD,
    CRTSCTS_ = CRTSCTS,
    CS5_ = CS5,
    CS6_ = CS6,
    CS7_ = CS7,
    CS8_ = CS8,
    CSIZE_ = CSIZE,
    CSTOPB_ = CSTOPB,
    HUPCL_ = HUPCL,
    PARENB_ = PARENB,
    PARODD_ = PARODD,
}

#[cfg(target_os = "freebsd")]
cflag! {
    CCAR_OFLOW_ = CCAR_OFLOW,
    CCTS_OFLOW_ = CCTS_OFLOW,
    CDSR_OFLOW_ = CDSR_OFLOW,
    CDTR_IFLOW_ = CDTR_IFLOW,
    CIGNORE_ = CIGNORE,
    CRTS_IFLOW_ = CRTS_IFLOW,
}

#[cfg(target_os = "linux")]
cflag! {
    CIBAUD_ = CIBAUD,
    CMSPAR_ = CMSPAR,
}

#[cfg(target_os = "macos")]
cflag! {
    CCAR_OFLOW_ = CCAR_OFLOW,
    CCTS_OFLOW_ = CCTS_OFLOW,
    CDSR_OFLOW_ = CDSR_OFLOW,
    CDTR_IFLOW_ = CDTR_IFLOW,
    CIGNORE_ = CIGNORE,
    CRTS_IFLOW_ = CRTS_IFLOW,
    MDMBUF_ = MDMBUF,
}

macro_rules! lflag {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

lflag! {
    ECHOCTL_ = ECHOCTL,
    ECHOE_ = ECHOE,
    ECHOKE_ = ECHOKE,
    ECHOK_ = ECHOK,
    ECHONL_ = ECHONL,
    ECHOPRT_ = ECHOPRT,
    ECHO_ = ECHO,
    EXTPROC_ = EXTPROC,
    FLUSHO_ = FLUSHO,
    ICANON_ = ICANON,
    IEXTEN_ = IEXTEN,
    ISIG_ = ISIG,
    NOFLSH_ = NOFLSH,
    PENDIN_ = PENDIN,
    TOSTOP_ = TOSTOP,
}

#[cfg(target_os = "freebsd")]
lflag! {
    ALTWERASE_ = ALTWERASE,
    NOKERNINFO_ = NOKERNINFO,
}

#[cfg(target_os = "linux")]
lflag! {
    XCASE_ = XCASE,
}

#[cfg(target_os = "macos")]
lflag! {
    ALTWERASE_ = ALTWERASE,
    NOKERNINFO_ = NOKERNINFO,
}

macro_rules! tcflow {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

tcflow! {
    TCIOFF_ = TCIOFF,
    TCION_ = TCION,
    TCOOFF_ = TCOOFF,
    TCOON_ = TCOON,
}

macro_rules! tcflush {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

tcflush! {
    TCIFLUSH_ = TCIFLUSH,
    TCIOFLUSH_ = TCIOFLUSH,
    TCOFLUSH_ = TCOFLUSH,
}

macro_rules! tcsetattr {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

tcsetattr! {
    TCSADRAIN_ = TCSADRAIN,
    TCSAFLUSH_ = TCSAFLUSH,
    TCSANOW_ = TCSANOW,
}

#[cfg(target_os = "freebsd")]
tcsetattr! {
    TCSASOFT_ = TCSASOFT,
}

#[cfg(target_os = "macos")]
tcsetattr! {
    TCSASOFT_ = TCSASOFT,
}

macro_rules! baud {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

baud! {
    B0_ = B0,
    B110_ = B110,
    B115200_ = B115200,
    B1200_ = B1200,
    B134_ = B134,
    B150_ = B150,
    B1800_ = B1800,
    B19200_ = B19200,
    B200_ = B200,
    B230400_ = B230400,
    B2400_ = B2400,
    B300_ = B300,
    B38400_ = B38400,
    B4800_ = B4800,
    B50_ = B50,
    B57600_ = B57600,
    B600_ = B600,
    B75_ = B75,
    B9600_ = B9600,
    EXTA_ = EXTA,
    EXTB_ = EXTB,
}

#[cfg(target_os = "freebsd")]
baud! {
    B14400_ = B14400,
    B28800_ = B28800,
    B460800_ = B460800,
    B7200_ = B7200,
    B76800_ = B76800,
    B921600_ = B921600,
}

#[cfg(target_os = "linux")]
baud! {
    B1000000_ = B1000000,
    B1152000_ = B1152000,
    B1500000_ = B1500000,
    B2000000_ = B2000000,
    B2500000_ = B2500000,
    B3000000_ = B3000000,
    B3500000_ = B3500000,
    B4000000_ = B4000000,
    B460800_ = B460800,
    B500000_ = B500000,
    B576000_ = B576000,
    B921600_ = B921600,
}

#[cfg(target_os = "macos")]
baud! {
    B14400_ = B14400,
    B28800_ = B28800,
    B7200_ = B7200,
    B76800_ = B76800,
}
<commit_msg>fix: tcgetsid doesn't seem to be available in glibc-2.15<commit_after>//! Raw access to the `Termios` structure and its flags

#[allow(dead_code, missing_docs, non_camel_case_types)]
mod ffi;

use std::fmt;

pub use self::ffi::cc_t;
pub use self::ffi::speed_t;
pub use self::ffi::tcflag_t;

pub use self::ffi::Struct_termios as Termios;

pub use self::ffi::{
    cfgetispeed,
    cfgetospeed,
    cfmakeraw,
    cfsetispeed,
    cfsetospeed,
    cfsetspeed,
    tcdrain,
    tcflow,
    tcflush,
    tcgetattr,
    tcsendbreak,
    tcsetattr,
};

#[cfg(target_os = "freebsd")]
pub use self::ffi::{
    cfmakesane,
    tcgetsid,
    tcsetsid,
};

// XXX (Debug) Formatting may change
impl fmt::Debug for Termios {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(f, "iflag:\t{:?}", self.c_iflag));
        try!(writeln!(f, "oflag:\t{:?}", self.c_oflag));
        try!(writeln!(f, "cflag:\t{:?}", self.c_cflag));
        try!(writeln!(f, "lflag:\t{:?}", self.c_lflag));
        try!(writeln!(f, "cc:\t{:?}", self.c_cc));
        try!(writeln!(f, "ispeed:\t{:?}", self.c_ispeed));
        try!(write!(f, "ospeed:\t{:?}", self.c_ospeed));
        Ok(())
    }
}

// FIXME (concat_idents!) All these macros should use only one input

macro_rules! cc {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

cc! {
    NCCS_ = NCCS,
    VDISCARD_ = VDISCARD,
    VEOF_ = VEOF,
    VEOL2_ = VEOL2,
    VEOL_ = VEOL,
    VERASE_ = VERASE,
    VINTR_ = VINTR,
    VKILL_ = VKILL,
    VLNEXT_ = VLNEXT,
    VMIN_ = VMIN,
    VQUIT_ = VQUIT,
    VREPRINT_ = VREPRINT,
    VSTART_ = VSTART,
    VSTOP_ = VSTOP,
    VSUSP_ = VSUSP,
    VTIME_ = VTIME,
    VWERASE_ = VWERASE,
}

#[cfg(target_os = "freebsd")]
cc! {
    VDSUSP_ = VDSUSP,
    VERASE2_ = VERASE2,
    VSTATUS_ = VSTATUS,
}

#[cfg(target_os = "linux")]
cc! {
    VSWTC_ = VSWTC,
}

#[cfg(target_os = "macos")]
cc! {
    VDSUSP_ = VDSUSP,
    VSTATUS_ = VSTATUS,
}

macro_rules! iflag {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

iflag! {
    BRKINT_ = BRKINT,
    ICRNL_ = ICRNL,
    IGNBRK_ = IGNBRK,
    IGNCR_ = IGNCR,
    IGNPAR_ = IGNPAR,
    IMAXBEL_ = IMAXBEL,
    INLCR_ = INLCR,
    INPCK_ = INPCK,
    ISTRIP_ = ISTRIP,
    IXANY_ = IXANY,
    IXOFF_ = IXOFF,
    IXON_ = IXON,
    PARMRK_ = PARMRK,
}

#[cfg(target_os = "linux")]
iflag! {
    IUCLC_ = IUCLC,
    IUTF8_ = IUTF8,
}

#[cfg(target_os = "macos")]
iflag! {
    IUTF8_ = IUTF8,
}

macro_rules! oflag {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

oflag! {
    OCRNL_ = OCRNL,
    ONLCR_ = ONLCR,
    ONLRET_ = ONLRET,
    ONOCR_ = ONOCR,
    OPOST_ = OPOST,
}

#[cfg(target_os = "freebsd")]
oflag! {
    ONOEOT_ = ONOEOT,
    TAB0_ = TAB0,
    TAB3_ = TAB3,
    TABDLY_ = TABDLY,
}

#[cfg(target_os = "linux")]
oflag! {
    OFDEL_ = OFDEL,
    OFILL_ = OFILL,
    OLCUC_ = OLCUC,
}

#[cfg(target_os = "macos")]
oflag! {
    BSDLY_ = BSDLY,
    CRDLY_ = CRDLY,
    FFDLY_ = FFDLY,
    NLDLY_ = NLDLY,
    OFDEL_ = OFDEL,
    OFILL_ = OFILL,
    ONOEOT_ = ONOEOT,
    OXTABS_ = OXTABS,
    TABDLY_ = TABDLY,
    VTDLY_ = VTDLY,
}

macro_rules! cflag {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

cflag! {
    CLOCAL_ = CLOCAL,
    CREAD_ = CREAD,
    CRTSCTS_ = CRTSCTS,
    CS5_ = CS5,
    CS6_ = CS6,
    CS7_ = CS7,
    CS8_ = CS8,
    CSIZE_ = CSIZE,
    CSTOPB_ = CSTOPB,
    HUPCL_ = HUPCL,
    PARENB_ = PARENB,
    PARODD_ = PARODD,
}

#[cfg(target_os = "freebsd")]
cflag! {
    CCAR_OFLOW_ = CCAR_OFLOW,
    CCTS_OFLOW_ = CCTS_OFLOW,
    CDSR_OFLOW_ = CDSR_OFLOW,
    CDTR_IFLOW_ = CDTR_IFLOW,
    CIGNORE_ = CIGNORE,
    CRTS_IFLOW_ = CRTS_IFLOW,
}

#[cfg(target_os = "linux")]
cflag! {
    CIBAUD_ = CIBAUD,
    CMSPAR_ = CMSPAR,
}

#[cfg(target_os = "macos")]
cflag! {
    CCAR_OFLOW_ = CCAR_OFLOW,
    CCTS_OFLOW_ = CCTS_OFLOW,
    CDSR_OFLOW_ = CDSR_OFLOW,
    CDTR_IFLOW_ = CDTR_IFLOW,
    CIGNORE_ = CIGNORE,
    CRTS_IFLOW_ = CRTS_IFLOW,
    MDMBUF_ = MDMBUF,
}

macro_rules! lflag {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

lflag! {
    ECHOCTL_ = ECHOCTL,
    ECHOE_ = ECHOE,
    ECHOKE_ = ECHOKE,
    ECHOK_ = ECHOK,
    ECHONL_ = ECHONL,
    ECHOPRT_ = ECHOPRT,
    ECHO_ = ECHO,
    EXTPROC_ = EXTPROC,
    FLUSHO_ = FLUSHO,
    ICANON_ = ICANON,
    IEXTEN_ = IEXTEN,
    ISIG_ = ISIG,
    NOFLSH_ = NOFLSH,
    PENDIN_ = PENDIN,
    TOSTOP_ = TOSTOP,
}

#[cfg(target_os = "freebsd")]
lflag! {
    ALTWERASE_ = ALTWERASE,
    NOKERNINFO_ = NOKERNINFO,
}

#[cfg(target_os = "linux")]
lflag! {
    XCASE_ = XCASE,
}

#[cfg(target_os = "macos")]
lflag! {
    ALTWERASE_ = ALTWERASE,
    NOKERNINFO_ = NOKERNINFO,
}

macro_rules! tcflow {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

tcflow! {
    TCIOFF_ = TCIOFF,
    TCION_ = TCION,
    TCOOFF_ = TCOOFF,
    TCOON_ = TCOON,
}

macro_rules! tcflush {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

tcflush! {
    TCIFLUSH_ = TCIFLUSH,
    TCIOFLUSH_ = TCIOFLUSH,
    TCOFLUSH_ = TCOFLUSH,
}

macro_rules! tcsetattr {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

tcsetattr! {
    TCSADRAIN_ = TCSADRAIN,
    TCSAFLUSH_ = TCSAFLUSH,
    TCSANOW_ = TCSANOW,
}

#[cfg(target_os = "freebsd")]
tcsetattr! {
    TCSASOFT_ = TCSASOFT,
}

#[cfg(target_os = "macos")]
tcsetattr! {
    TCSASOFT_ = TCSASOFT,
}

macro_rules! baud {
    ($($ffi:ident = $ident:ident,)+) => {
        $(
            pub use self::ffi::$ffi as $ident;
        )+
    }
}

baud! {
    B0_ = B0,
    B110_ = B110,
    B115200_ = B115200,
    B1200_ = B1200,
    B134_ = B134,
    B150_ = B150,
    B1800_ = B1800,
    B19200_ = B19200,
    B200_ = B200,
    B230400_ = B230400,
    B2400_ = B2400,
    B300_ = B300,
    B38400_ = B38400,
    B4800_ = B4800,
    B50_ = B50,
    B57600_ = B57600,
    B600_ = B600,
    B75_ = B75,
    B9600_ = B9600,
    EXTA_ = EXTA,
    EXTB_ = EXTB,
}

#[cfg(target_os = "freebsd")]
baud! {
    B14400_ = B14400,
    B28800_ = B28800,
    B460800_ = B460800,
    B7200_ = B7200,
    B76800_ = B76800,
    B921600_ = B921600,
}

#[cfg(target_os = "linux")]
baud! {
    B1000000_ = B1000000,
    B1152000_ = B1152000,
    B1500000_ = B1500000,
    B2000000_ = B2000000,
    B2500000_ = B2500000,
    B3000000_ = B3000000,
    B3500000_ = B3500000,
    B4000000_ = B4000000,
    B460800_ = B460800,
    B500000_ = B500000,
    B576000_ = B576000,
    B921600_ = B921600,
}

#[cfg(target_os = "macos")]
baud! {
    B14400_ = B14400,
    B28800_ = B28800,
    B7200_ = B7200,
    B76800_ = B76800,
}
<|endoftext|>


<commit_before>#[macro_use] extern crate clap;
extern crate names;

use clap::{App, Arg};
use names::{Generator, Name};

fn main() {
    let matches = App::new("names")
        .version(&crate_version!()[..])
        .author("Fletcher Nichol <fnichol@nichol.ca>")
        .about("Random name generator")
        .arg(Arg::with_name("AMOUNT")
             .help("Number of names to generate (default: 1)")
             .index(1)
        )
        .arg(Arg::with_name("number")
             .short("n")
             .long("number")
             .help("Adds a random number to the name(s)")
        )
        .get_matches();

    let amount = value_t!(matches.value_of("AMOUNT"), usize).unwrap_or(1);
    let naming = if matches.is_present("number") {
        Name::Numbered
    } else {
        Name::Plain
    };

    let mut generator = Generator::default(naming);
    for _ in 0..amount {
        println!("{}", generator.next().unwrap());
    }
}
<commit_msg>Update usage output.<commit_after>#[macro_use] extern crate clap;
extern crate names;

use clap::{App, Arg};
use names::{Generator, Name};

fn main() {
    let matches = App::new("names")
        .version(&crate_version!()[..])
        .author("\nAuthor: Fletcher Nichol <fnichol@nichol.ca>\n")
        .about("A random name generator with results like `delirious-pail'.")
        .arg(Arg::with_name("amount")
             .help("Number of names to generate (default: 1)")
             .index(1)
        )
        .arg(Arg::with_name("number")
             .short("n")
             .long("number")
             .help("Adds a random number to the name(s)")
        )
        .get_matches();

    let amount = value_t!(matches.value_of("amount"), usize).unwrap_or(1);
    let naming = if matches.is_present("number") {
        Name::Numbered
    } else {
        Name::Plain
    };

    let mut generator = Generator::default(naming);
    for _ in 0..amount {
        println!("{}", generator.next().unwrap());
    }
}
<|endoftext|>