<commit_before>#![allow(dead_code, unused_variables)]

use std::collections::HashSet;
use std::io::Result;

use crate::proto::{Capability, MessageKind, RawMessage};
use crate::socket::IRCWriter;

enum AuthKind {
    SaslPlain(String, String),
    Pass(String),
    None,
}

#[derive(Debug, Copy, Clone)]
enum ConnectionState {
    Initial,
    CapabilityNegotiation,
    Authentication,
    Registration,
    Registered,
}

/// Represents Birch <-> IRC network connection
pub struct NetworkConnection<'a> {
    nick: String,
    caps_pending: usize,
    caps: HashSet<Capability>,
    auth: AuthKind,

    state: ConnectionState,

    writer: &'a mut dyn IRCWriter,
    // user_fanout: &'a mut dyn IRCWriter,
}

impl<'a> NetworkConnection<'a> {
    pub fn new(nick: &str, writer: &'a mut dyn IRCWriter) -> Self {
        Self {
            nick: nick.to_string(),
            caps_pending: 0,
            caps: HashSet::new(),
            auth: AuthKind::None,

            state: ConnectionState::Initial,

            writer,
        }
    }

    pub fn initialize(&mut self) -> Result<()> {
        self.transition_state(ConnectionState::Initial)
    }

    fn register(&mut self) -> Result<()> {
        let msgs = vec![
            RawMessage::new("NICK", &[&self.nick]),
            RawMessage::new("USER", &[&self.nick, "0", "*", &self.nick]),
        ];

        for m in msgs.iter() {
            self.writer.write_message(&m)?;
        }

        Ok(())
    }

    fn write_network(&mut self, command: &str, params: &[&str]) -> Result<()> {
        self.writer.write_message(&RawMessage::new(command, params))
    }

    fn transition_state(&mut self, next: ConnectionState) -> Result<()> {
        match &next {
            ConnectionState::Initial => {
                self.transition_state(ConnectionState::CapabilityNegotiation)?;
            }

            ConnectionState::CapabilityNegotiation => {
                self.write_network("CAP", &["LS", "302"])?;
            }

            ConnectionState::Authentication => match self.auth {
                AuthKind::SaslPlain(ref _user, ref _pass) => unimplemented!(),
                AuthKind::Pass(ref _pass) => unimplemented!(),
                AuthKind::None => {
                    self.transition_state(ConnectionState::Registration)?;
                }
            },

            ConnectionState::Registration => {
                // TODO: prevent unnecessary clone
                let nick = self.nick.clone();

                self.write_network("NICK", &[&nick])?;
                self.write_network("USER", &[&nick, "0", "*", &nick])?;

                self.transition_state(ConnectionState::Registered)?;
            }

            ConnectionState::Registered => (),
        }

        Ok(())
    }

    fn handle_cap_message(&mut self, msg: &RawMessage) -> Result<()> {
        let cmd = msg.param(1).unwrap_or("");
        match cmd {
            "LS" => {
                let caps = msg.trailing().unwrap_or("").split_whitespace();

                for cap_str in caps {
                    if let Some(cap) = Capability::from(cap_str) {
                        self.write_network("CAP", &["REQ", cap_str])?;
                        self.caps_pending += 1;
                    }
                }
            }

            "ACK" | "NAK" => {
                let cap = msg.trailing().and_then(Capability::from);

                if let Some(cap) = cap {
                    if cmd == "ACK" {
                        println!("CAP {:?} enabled", cap);
                        self.caps.insert(cap);
                    }
                }

                self.caps_pending -= 1;

                if self.caps_pending == 0 {
                    self.write_network("CAP", &["END"])?;
                    self.transition_state(ConnectionState::Authentication)?;
                }
            }

            "NEW" | "DEL" => unimplemented!(),

            _ => println!("ignoring unknown cap command: {}", msg),
        }

        Ok(())
    }

    pub fn handle(&mut self, msg: &RawMessage) -> Result<()> {
        let kind = MessageKind::from(msg);
        let should_forward = match kind {
            MessageKind::Ping => {
                let param = msg.param(0).unwrap_or("");
                self.write_network("PONG", &[param])?;
                false
            }

            MessageKind::Capability => {
                self.handle_cap_message(msg)?;

                // We have our own caps, don't send the servers.
                false
            }

            MessageKind::Numeric(code) => self.handle_numeric(code, msg)?,

            // MessageKind::Privmsg => true,
            // MessageKind::Notice => true,

            // MessageKind::Join => true,
            // MessageKind::Part => true,
            // MessageKind::Quit => true,

            // MessageKind::Kick => true,

            // MessageKind::Mode => true,
            _ => {
                println!("Unhandled message: {:?}", msg);

                true
            }
        };

        if should_forward {
            // TODO: send message to user_fanout
        }

        Ok(())
    }

    fn handle_numeric(&mut self, code: u16, msg: &RawMessage) -> Result<bool> {
        let should_forward = match code {
            // :server 001 nick :welcome message
            1 => false,

            // ISUPPORT
            5 => false,

            2 |      // Your host
            3 |      // Server created at
            4 |      // Server info
            250 |    // Highest user count
            251 |    // User count
            252 |    // Oper count
            253 |    // Unknown connections
            254 |    // Channel count
            255 |    // Client count
            265 |    // Local users
            266 => { // Global users
                // TODO: Update network buffer state
                false
            },

            305 => { // Clear AWAY
                false
            }

            306 => { // Set AWAY
                false
            }

            329 => { // :server.com 329 nick #chan <epoch chan creation>
                false
            }

            // :server.com 331 nick #chan :no topic is set
            331 => {
                false
            }

            // :server.com 332 nick #chan :channel topic
            332 => {
                false
            }

            // :server.com 333 nick #chan who_set <epochtime>
            333 => {
                false
            }

            353 |    // :server.com 353 nick @ #chan :nick1 nick2
            366 => { // :server.com 366 nick #chan :End of /NAMES
                false
            }

            375 |    // Begin MOTD
            422 => { // MOTD file is missing
                // TODO: Clear MOTD
                false
            }

            372 |    // MOTD
            376 => { // End MOTD
                // TODO: MOTD
                false
            }

            432 |
            433 => { // :irc.server.com 432 * nick :Erroneous Nickname
                false
            }

            // Multiple possible:
            //
            // :irc.server.net 437 * badnick :Nick is temporarily unavailable
            // :irc.server.net 437 nick badnick :Nick is temporarily unavailable
            // :irc.server.net 437 nick badnick :Cannot change nick while banned on channel
            //
            // Only want to try an alt nick in the first case.
            437 => {
                false
            }

            _ => {
                println!("unhandled numeric: {}", code);

                true
            }
        };

        Ok(should_forward)
    }
}
<commit_msg>Remove unused register()<commit_after>#![allow(dead_code, unused_variables)]

use std::collections::HashSet;
use std::io::Result;

use crate::proto::{Capability, MessageKind, RawMessage};
use crate::socket::IRCWriter;

enum AuthKind {
    SaslPlain(String, String),
    Pass(String),
    None,
}

#[derive(Debug, Copy, Clone)]
enum ConnectionState {
    Initial,
    CapabilityNegotiation,
    Authentication,
    Registration,
    Registered,
}

/// Represents Birch <-> IRC network connection
pub struct NetworkConnection<'a> {
    nick: String,
    caps_pending: usize,
    caps: HashSet<Capability>,
    auth: AuthKind,

    state: ConnectionState,

    writer: &'a mut dyn IRCWriter,
    // user_fanout: &'a mut dyn IRCWriter,
}

impl<'a> NetworkConnection<'a> {
    pub fn new(nick: &str, writer: &'a mut dyn IRCWriter) -> Self {
        Self {
            nick: nick.to_string(),
            caps_pending: 0,
            caps: HashSet::new(),
            auth: AuthKind::None,

            state: ConnectionState::Initial,

            writer,
        }
    }

    pub fn initialize(&mut self) -> Result<()> {
        self.transition_state(ConnectionState::Initial)
    }

    fn write_network(&mut self, command: &str, params: &[&str]) -> Result<()> {
        self.writer.write_message(&RawMessage::new(command, params))
    }

    fn transition_state(&mut self, next: ConnectionState) -> Result<()> {
        match &next {
            ConnectionState::Initial => {
                self.transition_state(ConnectionState::CapabilityNegotiation)?;
            }

            ConnectionState::CapabilityNegotiation => {
                self.write_network("CAP", &["LS", "302"])?;
            }

            ConnectionState::Authentication => match self.auth {
                AuthKind::SaslPlain(ref _user, ref _pass) => unimplemented!(),
                AuthKind::Pass(ref _pass) => unimplemented!(),
                AuthKind::None => {
                    self.transition_state(ConnectionState::Registration)?;
                }
            },

            ConnectionState::Registration => {
                // TODO: prevent unnecessary clone
                let nick = self.nick.clone();

                self.write_network("NICK", &[&nick])?;
                self.write_network("USER", &[&nick, "0", "*", &nick])?;

                self.transition_state(ConnectionState::Registered)?;
            }

            ConnectionState::Registered => (),
        }

        Ok(())
    }

    fn handle_cap_message(&mut self, msg: &RawMessage) -> Result<()> {
        let cmd = msg.param(1).unwrap_or("");
        match cmd {
            "LS" => {
                let caps = msg.trailing().unwrap_or("").split_whitespace();

                for cap_str in caps {
                    if let Some(cap) = Capability::from(cap_str) {
                        self.write_network("CAP", &["REQ", cap_str])?;
                        self.caps_pending += 1;
                    }
                }
            }

            "ACK" | "NAK" => {
                let cap = msg.trailing().and_then(Capability::from);

                if let Some(cap) = cap {
                    if cmd == "ACK" {
                        println!("CAP {:?} enabled", cap);
                        self.caps.insert(cap);
                    }
                }

                self.caps_pending -= 1;

                if self.caps_pending == 0 {
                    self.write_network("CAP", &["END"])?;
                    self.transition_state(ConnectionState::Authentication)?;
                }
            }

            "NEW" | "DEL" => unimplemented!(),

            _ => println!("ignoring unknown cap command: {}", msg),
        }

        Ok(())
    }

    pub fn handle(&mut self, msg: &RawMessage) -> Result<()> {
        let kind = MessageKind::from(msg);
        let should_forward = match kind {
            MessageKind::Ping => {
                let param = msg.param(0).unwrap_or("");
                self.write_network("PONG", &[param])?;
                false
            }

            MessageKind::Capability => {
                self.handle_cap_message(msg)?;

                // We have our own caps, don't send the servers.
                false
            }

            MessageKind::Numeric(code) => self.handle_numeric(code, msg)?,

            // MessageKind::Privmsg => true,
            // MessageKind::Notice => true,

            // MessageKind::Join => true,
            // MessageKind::Part => true,
            // MessageKind::Quit => true,

            // MessageKind::Kick => true,

            // MessageKind::Mode => true,
            _ => {
                println!("Unhandled message: {:?}", msg);

                true
            }
        };

        if should_forward {
            // TODO: send message to user_fanout
        }

        Ok(())
    }

    fn handle_numeric(&mut self, code: u16, msg: &RawMessage) -> Result<bool> {
        let should_forward = match code {
            // :server 001 nick :welcome message
            1 => false,

            // ISUPPORT
            5 => false,

            2 |      // Your host
            3 |      // Server created at
            4 |      // Server info
            250 |    // Highest user count
            251 |    // User count
            252 |    // Oper count
            253 |    // Unknown connections
            254 |    // Channel count
            255 |    // Client count
            265 |    // Local users
            266 => { // Global users
                // TODO: Update network buffer state
                false
            },

            305 => { // Clear AWAY
                false
            }

            306 => { // Set AWAY
                false
            }

            329 => { // :server.com 329 nick #chan <epoch chan creation>
                false
            }

            // :server.com 331 nick #chan :no topic is set
            331 => {
                false
            }

            // :server.com 332 nick #chan :channel topic
            332 => {
                false
            }

            // :server.com 333 nick #chan who_set <epochtime>
            333 => {
                false
            }

            353 |    // :server.com 353 nick @ #chan :nick1 nick2
            366 => { // :server.com 366 nick #chan :End of /NAMES
                false
            }

            375 |    // Begin MOTD
            422 => { // MOTD file is missing
                // TODO: Clear MOTD
                false
            }

            372 |    // MOTD
            376 => { // End MOTD
                // TODO: MOTD
                false
            }

            432 |
            433 => { // :irc.server.com 432 * nick :Erroneous Nickname
                false
            }

            // Multiple possible:
            //
            // :irc.server.net 437 * badnick :Nick is temporarily unavailable
            // :irc.server.net 437 nick badnick :Nick is temporarily unavailable
            // :irc.server.net 437 nick badnick :Cannot change nick while banned on channel
            //
            // Only want to try an alt nick in the first case.
            437 => {
                false
            }

            _ => {
                println!("unhandled numeric: {}", code);

                true
            }
        };

        Ok(should_forward)
    }
}
<|endoftext|>


<commit_before>#![allow(unused_must_use)]
use std::io;

fn main() {
    let mut stderr = io::stderr();
    stderr.write_str("Hello stderr\n");
}
<commit_msg>temporary fix for rust stderr example<commit_after>#![allow(unstable)]
#![allow(unused_must_use)]
use std::io;

fn main() {
    let mut stderr = io::stderr();
    stderr.write_str("Hello stderr\n");
}
<|endoftext|>


<commit_before>// First attempt: No explicit lifetimes
// Error! Compiler needs explicit lifetime
//struct Singleton {
    //one: &mut int,
//}
// TODO ^ Try uncommenting this struct

// Second attempt: Add lifetimes to all the references
struct Pair<'a, 'b> {
    one: &'a mut i32,
    two: &'b mut i32,
}

fn main() {
    // Let's say that `one` has lifetime `o`
    let mut one = 1;

    {
        // And that `two` has lifetime `t`
        // `two` has a shorter (and different) lifetime than `one` (`'t < 'o`)
        let mut two = 2;

        println!("Before: ({}, {})", one, two);

        // `Pair` gets specialized for `'a = 'o` and `'b = 't`
        let pair = Pair { one: &mut one, two: &mut two };

        *pair.one = 2;
        *pair.two = 1;

        println!("After: ({}, {})", pair.one, pair.two);
    }
}
<commit_msg>lifetime/struct: Change int to i32<commit_after>// First attempt: No explicit lifetimes
// Error! Compiler needs explicit lifetime
//struct Singleton {
    //one: &mut i32,
//}
// TODO ^ Try uncommenting this struct

// Second attempt: Add lifetimes to all the references
struct Pair<'a, 'b> {
    one: &'a mut i32,
    two: &'b mut i32,
}

fn main() {
    // Let's say that `one` has lifetime `o`
    let mut one = 1;

    {
        // And that `two` has lifetime `t`
        // `two` has a shorter (and different) lifetime than `one` (`'t < 'o`)
        let mut two = 2;

        println!("Before: ({}, {})", one, two);

        // `Pair` gets specialized for `'a = 'o` and `'b = 't`
        let pair = Pair { one: &mut one, two: &mut two };

        *pair.one = 2;
        *pair.two = 1;

        println!("After: ({}, {})", pair.one, pair.two);
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

use toml::Value;

use libimagstore::storeid::StoreId;
use libimagstore::hook::Hook;
use libimagstore::hook::result::HookResult;
use libimagstore::hook::position::HookPosition;
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
use libimagstore::hook::accessor::StoreIdAccessor;

#[derive(Debug)]
pub struct CreateHook<'a> {
    storepath: &'a PathBuf,

    position: HookPosition,
    config: Option<Value>,
}

impl<'a> CreateHook<'a> {

    pub fn new(storepath: &'a PathBuf, p: HookPosition) -> CreateHook<'a> {
        CreateHook {
            storepath: storepath,
            position: p,
            config: None,
        }
    }

}

impl<'a> Hook for CreateHook<'a> {

    fn name(&self) -> &'static str {
        "stdhook_git_create"
    }

    fn set_config(&mut self, config: &Value) {
        self.config = Some(config.clone());
    }

}

impl<'a> HookDataAccessorProvider for CreateHook<'a> {

    fn accessor(&self) -> HookDataAccessor {
        HookDataAccessor::StoreIdAccess(self)
    }
}

impl<'a> StoreIdAccessor for CreateHook<'a> {

    fn access(&self, id: &StoreId) -> HookResult<()> {
        debug!("[GIT CREATE HOOK]: {:?}", id);
        Ok(())
    }

}

<commit_msg>Impl Debug for CreateHook<commit_after>use std::path::PathBuf;
use std::fmt::{Debug, Formatter, Error as FmtError};

use toml::Value;

use libimagstore::storeid::StoreId;
use libimagstore::hook::Hook;
use libimagstore::hook::result::HookResult;
use libimagstore::hook::position::HookPosition;
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
use libimagstore::hook::accessor::StoreIdAccessor;

pub struct CreateHook<'a> {
    storepath: &'a PathBuf,

    position: HookPosition,
    config: Option<Value>,
}

impl<'a> CreateHook<'a> {

    pub fn new(storepath: &'a PathBuf, p: HookPosition) -> CreateHook<'a> {
        CreateHook {
            storepath: storepath,
            position: p,
            config: None,
        }
    }

}

impl<'a> Debug for CreateHook<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        write!(fmt, "CreateHook(storepath={:?}, repository={}, pos={:?}, cfg={:?}",
               self.storepath,
               (if self.repository.is_some() { "Some(_)" } else { "None" }),
               self.position,
               self.config)
    }
}

impl<'a> Hook for CreateHook<'a> {

    fn name(&self) -> &'static str {
        "stdhook_git_create"
    }

    fn set_config(&mut self, config: &Value) {
        self.config = Some(config.clone());
    }

}

impl<'a> HookDataAccessorProvider for CreateHook<'a> {

    fn accessor(&self) -> HookDataAccessor {
        HookDataAccessor::StoreIdAccess(self)
    }
}

impl<'a> StoreIdAccessor for CreateHook<'a> {

    fn access(&self, id: &StoreId) -> HookResult<()> {
        debug!("[GIT CREATE HOOK]: {:?}", id);
        Ok(())
    }

}

<|endoftext|>


<commit_before>pub struct BitVector {
    value: u64,
}

impl BitVector {
    pub fn new() -> Self {
        BitVector { value: 0 }
    }

    pub fn set(&mut self, i: usize) {
        self.value |= 1 << i;
    }

    pub fn has(&self, i: usize) -> bool {
        self.value&(1<<i) != 0
    }

    pub fn intersect(&self, other: &Self) -> Self {
        BitVector { value: self.value & other.value }
    }

    pub fn is_empty(&self) -> bool {
        self.value == 0
    }

    pub fn to_vec(&self) -> Vec<usize> {
        let mut vec = vec![];
        for i in 0..64 {
            if self.has(i) {
                vec.push(i);
            }
        }
        vec
    }
}

impl Clone for BitVector {
    fn clone(&self) -> Self {
        BitVector { value: self.value }
    }
}
<commit_msg>[independent_set/rust] Fix formatting<commit_after>pub struct BitVector {
    value: u64,
}

impl BitVector {
    pub fn new() -> Self {
        BitVector { value: 0 }
    }

    pub fn set(&mut self, i: usize) {
        self.value |= 1 << i;
    }

    pub fn has(&self, i: usize) -> bool {
        self.value & 1 << i != 0
    }

    pub fn intersect(&self, other: &Self) -> Self {
        BitVector { value: self.value & other.value }
    }

    pub fn is_empty(&self) -> bool {
        self.value == 0
    }

    pub fn to_vec(&self) -> Vec<usize> {
        let mut vec = vec![];
        for i in 0..64 {
            if self.has(i) {
                vec.push(i);
            }
        }
        vec
    }
}

impl Clone for BitVector {
    fn clone(&self) -> Self {
        BitVector { value: self.value }
    }
}
<|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::vec::IntoIter;
use byteorder::{BigEndian, ReadBytesExt};

use kvproto::coprocessor::KeyRange;
use tipb::executor::IndexScan;
use tipb::schema::ColumnInfo;

use coprocessor::codec::{datum, mysql, table};
use coprocessor::metrics::*;
use coprocessor::{Error, Result};
use storage::{SnapshotStore, Statistics};

use super::{Executor, Row};
use super::scanner::{ScanOn, Scanner};

pub struct IndexScanExecutor {
    store: SnapshotStore,
    desc: bool,
    col_ids: Vec<i64>,
    pk_col: Option<ColumnInfo>,
    key_ranges: IntoIter<KeyRange>,
    scanner: Option<Scanner>,
}

impl IndexScanExecutor {
    pub fn new(
        mut meta: IndexScan,
        mut key_ranges: Vec<KeyRange>,
        store: SnapshotStore,
    ) -> IndexScanExecutor {
        let mut pk_col = None;
        let desc = meta.get_desc();
        if desc {
            key_ranges.reverse();
        }
        let cols = meta.mut_columns();
        if cols.last().map_or(false, |c| c.get_pk_handle()) {
            pk_col = Some(cols.pop().unwrap());
        }
        let col_ids = cols.iter().map(|c| c.get_column_id()).collect();

        COPR_EXECUTOR_COUNT.with_label_values(&["idxscan"]).inc();
        IndexScanExecutor {
            store: store,
            desc: desc,
            col_ids: col_ids,
            pk_col: pk_col,
            key_ranges: key_ranges.into_iter(),
            scanner: None,
        }
    }

    pub fn new_with_cols_len(
        cols: i64,
        key_ranges: Vec<KeyRange>,
        store: SnapshotStore,
    ) -> IndexScanExecutor {
        let col_ids: Vec<i64> = (0..cols).collect();
        COPR_EXECUTOR_COUNT.with_label_values(&["idxscan"]).inc();
        IndexScanExecutor {
            store: store,
            desc: false,
            col_ids: col_ids,
            pk_col: None,
            key_ranges: key_ranges.into_iter(),
            scanner: None,
        }
    }

    fn get_row_from_range_scanner(&mut self) -> Result<Option<Row>> {
        if self.scanner.is_none() {
            return Ok(None);
        }
        COPR_GET_OR_SCAN_COUNT.with_label_values(&["range"]).inc();

        let scanner = self.scanner.as_mut().unwrap();
        let (key, value) = match scanner.next_row()? {
            Some((key, value)) => (key, value),
            None => return Ok(None),
        };

        let (mut values, handle) = box_try!(table::cut_idx_key(key, &self.col_ids));
        let handle = match handle {
            None => box_try!(value.as_slice().read_i64::<BigEndian>()),
            Some(h) => h,
        };

        if let Some(ref pk_col) = self.pk_col {
            let handle_datum = if mysql::has_unsigned_flag(pk_col.get_flag() as u64) {
                // PK column is unsigned
                datum::Datum::U64(handle as u64)
            } else {
                datum::Datum::I64(handle)
            };
            let mut bytes = box_try!(datum::encode_key(&[handle_datum]));
            values.append(pk_col.get_column_id(), &mut bytes);
        }
        Ok(Some(Row::new(handle, values)))
    }

    fn new_scanner(&self, range: KeyRange) -> Result<Scanner> {
        Scanner::new(&self.store, ScanOn::Index, self.desc, false, range).map_err(Error::from)
    }
}

impl Executor for IndexScanExecutor {
    fn next(&mut self) -> Result<Option<Row>> {
        loop {
            if let Some(row) = self.get_row_from_range_scanner()? {
                return Ok(Some(row));
            }
            if let Some(range) = self.key_ranges.next() {
                self.scanner = match self.scanner.take() {
                    Some(mut scanner) => {
                        box_try!(scanner.reset_range(range, &self.store));
                        Some(scanner)
                    }
                    None => Some(self.new_scanner(range)?),
                };
                continue;
            }
            return Ok(None);
        }
    }

    fn collect_statistics_into(&mut self, statistics: &mut Statistics) {
        if let Some(scanner) = self.scanner.take() {
            scanner.collect_statistics_into(statistics);
        }
    }
}

#[cfg(test)]
mod test {
    use std::i64;

    use kvproto::kvrpcpb::IsolationLevel;
    use protobuf::RepeatedField;
    use tipb::schema::ColumnInfo;

    use coprocessor::codec::mysql::types;
    use coprocessor::codec::datum::{self, Datum};
    use util::codec::number::NumberEncoder;
    use util::collections::HashMap;
    use storage::SnapshotStore;

    use super::*;
    use super::super::scanner::test::{new_col_info, Data, TestStore};

    const TABLE_ID: i64 = 1;
    const INDEX_ID: i64 = 1;
    const KEY_NUMBER: usize = 10;

    #[inline]
    pub fn get_idx_range(table_id: i64, idx_id: i64, start: i64, end: i64) -> KeyRange {
        let mut start_buf = Vec::with_capacity(8);
        start_buf.encode_i64(start).unwrap();
        let mut end_buf = Vec::with_capacity(8);
        end_buf.encode_i64(end).unwrap();
        let mut key_range = KeyRange::new();
        key_range.set_start(table::encode_index_seek_key(table_id, idx_id, &start_buf));
        key_range.set_end(table::encode_index_seek_key(table_id, idx_id, &end_buf));
        key_range
    }

    pub fn prepare_index_data(key_number: usize, table_id: i64, index_id: i64) -> Data {
        let cols = vec![
            new_col_info(1, types::LONG_LONG),
            new_col_info(2, types::VARCHAR),
            new_col_info(3, types::NEW_DECIMAL),
        ];

        let mut kv_data = Vec::new();
        let mut expect_rows = Vec::new();

        for handle in 0..key_number {
            let indice = vec![
                (2, Datum::Bytes(b"abc".to_vec())),
                (3, Datum::Dec(handle.into())),
            ];
            let mut expect_row = HashMap::default();
            let mut v: Vec<_> = indice
                .iter()
                .map(|&(ref cid, ref value)| {
                    expect_row.insert(*cid, datum::encode_key(&[value.clone()]).unwrap());
                    value.clone()
                })
                .collect();
            let h = Datum::I64(handle as i64);
            v.push(h);
            let encoded = datum::encode_key(&v).unwrap();
            let idx_key = table::encode_index_seek_key(table_id, index_id, &encoded);
            expect_rows.push(expect_row);
            kv_data.push((idx_key, vec![0]));
        }
        Data {
            kv_data: kv_data,
            expect_rows: expect_rows,
            cols: cols,
        }
    }

    struct IndexTestWrapper {
        data: Data,
        store: TestStore,
        scan: IndexScan,
        ranges: Vec<KeyRange>,
        cols: Vec<ColumnInfo>,
    }

    impl IndexTestWrapper {
        fn include_pk_cols() -> IndexTestWrapper {
            let mut wrapper = IndexTestWrapper::default();
            let mut cols = wrapper.data.get_index_cols();
            cols.push(wrapper.data.get_col_pk());
            wrapper
                .scan
                .set_columns(RepeatedField::from_vec(cols.clone()));
            wrapper.cols = cols;
            wrapper
        }
    }

    impl Default for IndexTestWrapper {
        fn default() -> IndexTestWrapper {
            let test_data = prepare_index_data(KEY_NUMBER, TABLE_ID, INDEX_ID);
            let test_store = TestStore::new(&test_data.kv_data);
            let mut scan = IndexScan::new();
            // prepare cols
            let cols = test_data.get_index_cols();
            let col_req = RepeatedField::from_vec(cols.clone());
            scan.set_columns(col_req);
            // prepare range
            let range = get_idx_range(TABLE_ID, INDEX_ID, i64::MIN, i64::MAX);
            let key_ranges = vec![range];
            IndexTestWrapper {
                data: test_data,
                store: test_store,
                scan: scan,
                ranges: key_ranges,
                cols: cols,
            }
        }
    }

    #[test]
    fn test_multiple_ranges() {
        let mut wrapper = IndexTestWrapper::default();
        let (ref start_key, _) = wrapper.data.kv_data[0];
        let (ref split_key, _) = wrapper.data.kv_data[KEY_NUMBER / 3];
        let (ref end_key, _) = wrapper.data.kv_data[KEY_NUMBER / 2];
        let mut r1 = KeyRange::new();
        r1.set_start(start_key.clone());
        r1.set_end(split_key.clone());
        let mut r2 = KeyRange::new();
        r2.set_start(split_key.clone());
        r2.set_end(end_key.clone());
        wrapper.ranges = vec![r1, r2];
        let (snapshot, start_ts) = wrapper.store.get_snapshot();
        let store = SnapshotStore::new(snapshot, start_ts, IsolationLevel::SI, true);

        let mut scanner = IndexScanExecutor::new(wrapper.scan, wrapper.ranges, store);

        for handle in 0..KEY_NUMBER / 2 {
            let row = scanner.next().unwrap().unwrap();
            assert_eq!(row.handle, handle as i64);
            assert_eq!(row.data.len(), wrapper.cols.len());
            let expect_row = &wrapper.data.expect_rows[handle];
            for col in &wrapper.cols {
                let cid = col.get_column_id();
                let v = row.data.get(cid).unwrap();
                assert_eq!(expect_row[&cid], v.to_vec());
            }
        }
        assert!(scanner.next().unwrap().is_none());
    }

    #[test]
    fn test_reverse_scan() {
        let mut wrapper = IndexTestWrapper::default();
        wrapper.scan.set_desc(true);

        let r1 = get_idx_range(TABLE_ID, INDEX_ID, i64::MIN, 0);
        let r2 = get_idx_range(TABLE_ID, INDEX_ID, 0, (KEY_NUMBER / 2) as i64);
        let r3 = get_idx_range(TABLE_ID, INDEX_ID, (KEY_NUMBER / 2) as i64, i64::MAX);
        wrapper.ranges = vec![r1, r2, r3];

        let (snapshot, start_ts) = wrapper.store.get_snapshot();
        let store = SnapshotStore::new(snapshot, start_ts, IsolationLevel::SI, true);

        let mut scanner = IndexScanExecutor::new(wrapper.scan, wrapper.ranges, store);

        for tid in 0..KEY_NUMBER {
            let handle = KEY_NUMBER - tid - 1;
            let row = scanner.next().unwrap().unwrap();
            assert_eq!(row.handle, handle as i64);
            assert_eq!(row.data.len(), 2);
            let expect_row = &wrapper.data.expect_rows[handle];
            for col in &wrapper.cols {
                let cid = col.get_column_id();
                let v = row.data.get(cid).unwrap();
                assert_eq!(expect_row[&cid], v.to_vec());
            }
        }
        assert!(scanner.next().unwrap().is_none());
    }

    #[test]
    fn test_include_pk() {
        let mut wrapper = IndexTestWrapper::include_pk_cols();
        let (snapshot, start_ts) = wrapper.store.get_snapshot();
        let store = SnapshotStore::new(snapshot, start_ts, IsolationLevel::SI, true);

        let mut scanner = IndexScanExecutor::new(wrapper.scan, wrapper.ranges, store);

        for handle in 0..KEY_NUMBER {
            let row = scanner.next().unwrap().unwrap();
            assert_eq!(row.handle, handle as i64);
            assert_eq!(row.data.len(), wrapper.cols.len());
            let expect_row = &wrapper.data.expect_rows[handle];
            let handle_datum = datum::Datum::I64(handle as i64);
            let pk = datum::encode_key(&[handle_datum]).unwrap();
            for col in &wrapper.cols {
                let cid = col.get_column_id();
                let v = row.data.get(cid).unwrap();
                if col.get_pk_handle() {
                    assert_eq!(pk, v.to_vec());
                    continue;
                }
                assert_eq!(expect_row[&cid], v.to_vec());
            }
        }
        assert!(scanner.next().unwrap().is_none());
    }
}
<commit_msg>index_scan/test :fix bug in generate key range for index (#2527)<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::vec::IntoIter;
use byteorder::{BigEndian, ReadBytesExt};

use kvproto::coprocessor::KeyRange;
use tipb::executor::IndexScan;
use tipb::schema::ColumnInfo;

use coprocessor::codec::{datum, mysql, table};
use coprocessor::metrics::*;
use coprocessor::{Error, Result};
use storage::{SnapshotStore, Statistics};

use super::{Executor, Row};
use super::scanner::{ScanOn, Scanner};

pub struct IndexScanExecutor {
    store: SnapshotStore,
    desc: bool,
    col_ids: Vec<i64>,
    pk_col: Option<ColumnInfo>,
    key_ranges: IntoIter<KeyRange>,
    scanner: Option<Scanner>,
}

impl IndexScanExecutor {
    pub fn new(
        mut meta: IndexScan,
        mut key_ranges: Vec<KeyRange>,
        store: SnapshotStore,
    ) -> IndexScanExecutor {
        let mut pk_col = None;
        let desc = meta.get_desc();
        if desc {
            key_ranges.reverse();
        }
        let cols = meta.mut_columns();
        if cols.last().map_or(false, |c| c.get_pk_handle()) {
            pk_col = Some(cols.pop().unwrap());
        }
        let col_ids = cols.iter().map(|c| c.get_column_id()).collect();

        COPR_EXECUTOR_COUNT.with_label_values(&["idxscan"]).inc();
        IndexScanExecutor {
            store: store,
            desc: desc,
            col_ids: col_ids,
            pk_col: pk_col,
            key_ranges: key_ranges.into_iter(),
            scanner: None,
        }
    }

    pub fn new_with_cols_len(
        cols: i64,
        key_ranges: Vec<KeyRange>,
        store: SnapshotStore,
    ) -> IndexScanExecutor {
        let col_ids: Vec<i64> = (0..cols).collect();
        COPR_EXECUTOR_COUNT.with_label_values(&["idxscan"]).inc();
        IndexScanExecutor {
            store: store,
            desc: false,
            col_ids: col_ids,
            pk_col: None,
            key_ranges: key_ranges.into_iter(),
            scanner: None,
        }
    }

    fn get_row_from_range_scanner(&mut self) -> Result<Option<Row>> {
        if self.scanner.is_none() {
            return Ok(None);
        }
        COPR_GET_OR_SCAN_COUNT.with_label_values(&["range"]).inc();

        let scanner = self.scanner.as_mut().unwrap();
        let (key, value) = match scanner.next_row()? {
            Some((key, value)) => (key, value),
            None => return Ok(None),
        };

        let (mut values, handle) = box_try!(table::cut_idx_key(key, &self.col_ids));
        let handle = match handle {
            None => box_try!(value.as_slice().read_i64::<BigEndian>()),
            Some(h) => h,
        };

        if let Some(ref pk_col) = self.pk_col {
            let handle_datum = if mysql::has_unsigned_flag(pk_col.get_flag() as u64) {
                // PK column is unsigned
                datum::Datum::U64(handle as u64)
            } else {
                datum::Datum::I64(handle)
            };
            let mut bytes = box_try!(datum::encode_key(&[handle_datum]));
            values.append(pk_col.get_column_id(), &mut bytes);
        }
        Ok(Some(Row::new(handle, values)))
    }

    fn new_scanner(&self, range: KeyRange) -> Result<Scanner> {
        Scanner::new(&self.store, ScanOn::Index, self.desc, false, range).map_err(Error::from)
    }
}

impl Executor for IndexScanExecutor {
    fn next(&mut self) -> Result<Option<Row>> {
        loop {
            if let Some(row) = self.get_row_from_range_scanner()? {
                return Ok(Some(row));
            }
            if let Some(range) = self.key_ranges.next() {
                self.scanner = match self.scanner.take() {
                    Some(mut scanner) => {
                        box_try!(scanner.reset_range(range, &self.store));
                        Some(scanner)
                    }
                    None => Some(self.new_scanner(range)?),
                };
                continue;
            }
            return Ok(None);
        }
    }

    fn collect_statistics_into(&mut self, statistics: &mut Statistics) {
        if let Some(scanner) = self.scanner.take() {
            scanner.collect_statistics_into(statistics);
        }
    }
}

#[cfg(test)]
mod test {
    use std::i64;
    use byteorder::{BigEndian, WriteBytesExt};

    use kvproto::kvrpcpb::IsolationLevel;
    use protobuf::RepeatedField;
    use tipb::schema::ColumnInfo;

    use coprocessor::codec::mysql::types;
    use coprocessor::codec::datum::{self, Datum};
    use util::collections::HashMap;
    use storage::SnapshotStore;

    use super::*;
    use super::super::scanner::test::{new_col_info, Data, TestStore};

    const TABLE_ID: i64 = 1;
    const INDEX_ID: i64 = 1;
    const KEY_NUMBER: usize = 10;

    // get_idx_range get range for index in [("abc",start),("abc", end))
    pub fn get_idx_range(table_id: i64, idx_id: i64, start: i64, end: i64) -> KeyRange {
        let (_, start_key) = generate_index_data(table_id, idx_id, start);
        let (_, end_key) = generate_index_data(table_id, idx_id, end);
        let mut key_range = KeyRange::new();
        key_range.set_start(start_key);
        key_range.set_end(end_key);
        key_range
    }

    pub fn generate_index_data(
        table_id: i64,
        index_id: i64,
        handle: i64,
    ) -> (HashMap<i64, Vec<u8>>, Vec<u8>) {
        let indice = vec![
            (2, Datum::Bytes(b"abc".to_vec())),
            (3, Datum::Dec(handle.into())),
        ];
        let mut expect_row = HashMap::default();
        let v: Vec<_> = indice
            .iter()
            .map(|&(ref cid, ref value)| {
                expect_row.insert(*cid, datum::encode_key(&[value.clone()]).unwrap());
                value.clone()
            })
            .collect();
        let encoded = datum::encode_key(&v).unwrap();
        let idx_key = table::encode_index_seek_key(table_id, index_id, &encoded);
        (expect_row, idx_key)
    }

    pub fn prepare_index_data(key_number: usize, table_id: i64, index_id: i64) -> Data {
        let cols = vec![
            new_col_info(1, types::LONG_LONG),
            new_col_info(2, types::VARCHAR),
            new_col_info(3, types::NEW_DECIMAL),
        ];

        let mut kv_data = Vec::new();
        let mut expect_rows = Vec::new();

        for handle in 0..key_number {
            let (expect_row, idx_key) = generate_index_data(table_id, index_id, handle as i64);
            expect_rows.push(expect_row);
            let mut value = Vec::with_capacity(8);
            value.write_i64::<BigEndian>(handle as i64).unwrap();
            kv_data.push((idx_key, value));
        }
        Data {
            kv_data: kv_data,
            expect_rows: expect_rows,
            cols: cols,
        }
    }

    struct IndexTestWrapper {
        data: Data,
        store: TestStore,
        scan: IndexScan,
        ranges: Vec<KeyRange>,
        cols: Vec<ColumnInfo>,
    }

    impl IndexTestWrapper {
        fn include_pk_cols() -> IndexTestWrapper {
            let mut wrapper = IndexTestWrapper::default();
            let mut cols = wrapper.data.get_index_cols();
            cols.push(wrapper.data.get_col_pk());
            wrapper
                .scan
                .set_columns(RepeatedField::from_vec(cols.clone()));
            wrapper.cols = cols;
            wrapper
        }
    }

    impl Default for IndexTestWrapper {
        fn default() -> IndexTestWrapper {
            let test_data = prepare_index_data(KEY_NUMBER, TABLE_ID, INDEX_ID);
            let test_store = TestStore::new(&test_data.kv_data);
            let mut scan = IndexScan::new();
            // prepare cols
            let cols = test_data.get_index_cols();
            let col_req = RepeatedField::from_vec(cols.clone());
            scan.set_columns(col_req);
            // prepare range
            let range = get_idx_range(TABLE_ID, INDEX_ID, 0, i64::MAX);
            let key_ranges = vec![range];
            IndexTestWrapper {
                data: test_data,
                store: test_store,
                scan: scan,
                ranges: key_ranges,
                cols: cols,
            }
        }
    }

    #[test]
    fn test_multiple_ranges() {
        let mut wrapper = IndexTestWrapper::default();
        let r1 = get_idx_range(TABLE_ID, INDEX_ID, 0, (KEY_NUMBER / 3) as i64);
        let r2 = get_idx_range(
            TABLE_ID,
            INDEX_ID,
            (KEY_NUMBER / 3) as i64,
            (KEY_NUMBER / 2) as i64,
        );
        wrapper.ranges = vec![r1, r2];
        let (snapshot, start_ts) = wrapper.store.get_snapshot();
        let store = SnapshotStore::new(snapshot, start_ts, IsolationLevel::SI, true);

        let mut scanner = IndexScanExecutor::new(wrapper.scan, wrapper.ranges, store);

        for handle in 0..KEY_NUMBER / 2 {
            let row = scanner.next().unwrap().unwrap();
            assert_eq!(row.handle, handle as i64);
            assert_eq!(row.data.len(), wrapper.cols.len());
            let expect_row = &wrapper.data.expect_rows[handle];
            for col in &wrapper.cols {
                let cid = col.get_column_id();
                let v = row.data.get(cid).unwrap();
                assert_eq!(expect_row[&cid], v.to_vec());
            }
        }
        assert!(scanner.next().unwrap().is_none());
    }

    #[test]
    fn test_reverse_scan() {
        let mut wrapper = IndexTestWrapper::default();
        wrapper.scan.set_desc(true);

        let r1 = get_idx_range(TABLE_ID, INDEX_ID, i64::MIN, 0);
        let r2 = get_idx_range(TABLE_ID, INDEX_ID, 0, (KEY_NUMBER / 2) as i64);
        let r3 = get_idx_range(TABLE_ID, INDEX_ID, (KEY_NUMBER / 2) as i64, i64::MAX);
        wrapper.ranges = vec![r1, r2, r3];

        let (snapshot, start_ts) = wrapper.store.get_snapshot();
        let store = SnapshotStore::new(snapshot, start_ts, IsolationLevel::SI, true);

        let mut scanner = IndexScanExecutor::new(wrapper.scan, wrapper.ranges, store);

        for tid in 0..KEY_NUMBER {
            let handle = KEY_NUMBER - tid - 1;
            let row = scanner.next().unwrap().unwrap();
            assert_eq!(row.handle, handle as i64);
            assert_eq!(row.data.len(), 2);
            let expect_row = &wrapper.data.expect_rows[handle];
            for col in &wrapper.cols {
                let cid = col.get_column_id();
                let v = row.data.get(cid).unwrap();
                assert_eq!(expect_row[&cid], v.to_vec());
            }
        }
        assert!(scanner.next().unwrap().is_none());
    }

    #[test]
    fn test_include_pk() {
        let mut wrapper = IndexTestWrapper::include_pk_cols();
        let (snapshot, start_ts) = wrapper.store.get_snapshot();
        let store = SnapshotStore::new(snapshot, start_ts, IsolationLevel::SI, true);

        let mut scanner = IndexScanExecutor::new(wrapper.scan, wrapper.ranges, store);

        for handle in 0..KEY_NUMBER {
            let row = scanner.next().unwrap().unwrap();
            assert_eq!(row.handle, handle as i64);
            assert_eq!(row.data.len(), wrapper.cols.len());
            let expect_row = &wrapper.data.expect_rows[handle];
            let handle_datum = datum::Datum::I64(handle as i64);
            let pk = datum::encode_key(&[handle_datum]).unwrap();
            for col in &wrapper.cols {
                let cid = col.get_column_id();
                let v = row.data.get(cid).unwrap();
                if col.get_pk_handle() {
                    assert_eq!(pk, v.to_vec());
                    continue;
                }
                assert_eq!(expect_row[&cid], v.to_vec());
            }
        }
        assert!(scanner.next().unwrap().is_none());
    }
}
<|endoftext|>


<commit_before>//! Errors, type aliases, and functions related to working with `Result`.

use std::convert::From;
use std::error::Error as StdError;
use std::fmt::{self, Display};
use std::ffi::NulError;

#[derive(Debug)]
#[cfg_attr(feature = "clippy", allow(enum_variant_names))]
/// The generic "things can fail in a myriad of ways" enum.
///
/// This type is not intended to be exhaustively matched, and new variants may
/// be added in the future without a major version bump.
pub enum Error {
    /// The query contained a nul byte.
    InvalidCString(NulError),
    /// The database returned an error.
    ///
    /// While Diesel prevents almost all sources of runtime errors at compile
    /// time, it does not attempt to prevent 100% of them. Typically this error
    /// will occur from insert or update statements due to a constraint
    /// violation.
    DatabaseError(
        DatabaseErrorKind,
        Box<DatabaseErrorInformation + Send + Sync>,
    ),
    /// No rows were returned by a query expected to return at least one row.
    ///
    /// This variant is only returned by [`get_result`] and [`first`]. [`load`]
    /// does not treat 0 rows as an error. If you would like to allow either 0
    /// or 1 rows, call [`optional`] on the result.
    ///
    /// [`get_result`]: ../prelude/trait.LoadDsl.html#method.get_result
    /// [`first`]: ../prelude/trait.FirstDsl.html#method.first
    /// [`load`]: ../prelude/trait.LoadDsl.html#method.load
    /// [`optional`]: trait.OptionalExtension.html#tymethod.optional
    NotFound,
    /// The query could not be constructed
    ///
    /// An example of when this error could occur is if you are attempting to
    /// construct an update statement with no changes (e.g. all fields on the
    /// struct are `None`).
    QueryBuilderError(Box<StdError + Send + Sync>),
    /// An error occurred deserializing the data being sent to the database.
    ///
    /// Typically this error means that the stated type of the query is
    /// incorrect. An example of when this error might occur in normal usage is
    /// attempting to deserialize an infinite date into chrono.
    DeserializationError(Box<StdError + Send + Sync>),
    /// An error occurred serializing the data being sent to the database.
    ///
    /// An example of when this error would be returned is if you attempted to
    /// serialize a `chrono::NaiveDate` earlier than the earliest date supported
    /// by PostgreSQL.
    SerializationError(Box<StdError + Send + Sync>),
    /// Roll back the current transaction.
    ///
    /// You can return this variant inside of a transaction when you want to
    /// roll it back, but have no actual error to return. Diesel will never
    /// return this variant unless you gave it to us, and it can be safely
    /// ignored in error handling.
    RollbackTransaction,
    #[doc(hidden)] __Nonexhaustive,
}

#[derive(Debug, Clone, Copy)]
/// The kind of database error that occurred.
///
/// This is not meant to exhaustively cover all possible errors, but is used to
/// identify errors which are commonly recovered from programatically. This enum
/// is not intended to be exhaustively matched, and new variants may be added in
/// the future without a major version bump.
pub enum DatabaseErrorKind {
    /// A unique constraint was violated.
    UniqueViolation,
    /// A foreign key constraint was violated.
    ForeignKeyViolation,
    /// The query could not be sent to the database due to a protocol violation.
    ///
    /// An example of a case where this would occur is if you attempted to send
    /// a query with more than 65000 bind parameters using PostgreSQL.
    UnableToSendCommand,
    #[doc(hidden)] __Unknown, // Match against _ instead, more variants may be added in the future
}

/// Information about an error that was returned by the database.
pub trait DatabaseErrorInformation {
    /// The primary human-readable error message. Typically one line.
    fn message(&self) -> &str;

    /// An optional secondary error message providing more details about the
    /// problem, if it was provided by the database. Might span multiple lines.
    fn details(&self) -> Option<&str>;

    /// An optional suggestion of what to do about the problem, if one was
    /// provided by the database.
    fn hint(&self) -> Option<&str>;

    /// The name of the table the error was associated with, if the error was
    /// associated with a specific table and the backend supports retrieving
    /// that information.
    ///
    /// Currently this method will return `None` for all backends other than
    /// PostgreSQL.
    fn table_name(&self) -> Option<&str>;

    /// The name of the column the error was associated with, if the error was
    /// associated with a specific column and the backend supports retrieving
    /// that information.
    ///
    /// Currently this method will return `None` for all backends other than
    /// PostgreSQL.
    fn column_name(&self) -> Option<&str>;

    /// The constraint that was violated if this error is a constraint violation
    /// and the backend supports retrieving that information.
    ///
    /// Currently this method will return `None` for all backends other than
    /// PostgreSQL.
    fn constraint_name(&self) -> Option<&str>;
}

impl fmt::Debug for DatabaseErrorInformation + Send + Sync {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.message(), f)
    }
}

impl DatabaseErrorInformation for String {
    fn message(&self) -> &str {
        self
    }

    fn details(&self) -> Option<&str> {
        None
    }
    fn hint(&self) -> Option<&str> {
        None
    }
    fn table_name(&self) -> Option<&str> {
        None
    }
    fn column_name(&self) -> Option<&str> {
        None
    }
    fn constraint_name(&self) -> Option<&str> {
        None
    }
}

/// Errors which can occur during [`Connection::establish`]
///
/// [`Connection::establish`]: ../connection/trait.Connection.html?search=#tymethod.establish
#[derive(Debug)]
pub enum ConnectionError {
    /// The connection URL contained a `NUL` byte.
    InvalidCString(NulError),
    /// The database returned an error.
    BadConnection(String),
    /// The connection URL could not be parsed.
    InvalidConnectionUrl(String),
    /// Diesel could not configure the database connection.
    ///
    /// Diesel may try to automatically set session specific configuration
    /// values, such as UTF8 encoding, or enabling the `||` operator on MySQL.
    /// This variant is returned if an error occurred executing the query to set
    /// those options. Diesel will never affect global configuration.
    CouldntSetupConfiguration(Error),
    #[doc(hidden)] __Nonexhaustive, // Match against _ instead, more variants may be added in the future
}

/// A specialized result type for queries.
///
/// This type is exported by `diesel::prelude`, and is generally used by any
/// code which is interacting with Diesel. This type exists to avoid writing out
/// `diesel::result::Error`, and is otherwise a direct mapping to `Result`.
pub type QueryResult<T> = Result<T, Error>;

/// A specialized result type for establishing connections.
///
/// This type exists to avoid writing out `diesel::result::ConnectionError`, and
/// is otherwise a direct mapping to `Result`.
pub type ConnectionResult<T> = Result<T, ConnectionError>;

/// See the [method documentation](#tymethod.optional).
pub trait OptionalExtension<T> {
    /// Converts a `QueryResult<T>` into a `QueryResult<Option<T>>`.
    ///
    /// By default, Diesel treats 0 rows being returned from a query that is expected to return 1
    /// row as an error (e.g. the return value of [`get_result`] or [`first`]). This method will
    /// handle that error, and give you back an `Option<T>` instead.
    ///
    /// [`get_result`]: ../prelude/trait.LoadDsl.html#method.get_result
    /// [`first`]: ../prelude/trait.FirstDsl.html#method.first
    ///
    /// # Example
    ///
    /// ```rust
    /// use diesel::result::{QueryResult, Error};
    /// use diesel::OptionalExtension;
    ///
    /// let result: QueryResult<i32> = Ok(1);
    /// assert_eq!(Ok(Some(1)), result.optional());
    ///
    /// let result: QueryResult<i32> = Err(Error::NotFound);
    /// assert_eq!(Ok(None), result.optional());
    /// ```
    fn optional(self) -> Result<Option<T>, Error>;
}

impl<T> OptionalExtension<T> for QueryResult<T> {
    fn optional(self) -> Result<Option<T>, Error> {
        match self {
            Ok(value) => Ok(Some(value)),
            Err(Error::NotFound) => Ok(None),
            Err(e) => Err(e),
        }
    }
}

impl From<NulError> for ConnectionError {
    fn from(e: NulError) -> Self {
        ConnectionError::InvalidCString(e)
    }
}

impl From<NulError> for Error {
    fn from(e: NulError) -> Self {
        Error::InvalidCString(e)
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::InvalidCString(ref nul_err) => nul_err.fmt(f),
            Error::DatabaseError(_, ref e) => write!(f, "{}", e.message()),
            Error::NotFound => f.write_str("NotFound"),
            Error::QueryBuilderError(ref e) => e.fmt(f),
            Error::DeserializationError(ref e) => e.fmt(f),
            Error::SerializationError(ref e) => e.fmt(f),
            Error::RollbackTransaction => write!(f, "{}", self.description()),
            Error::__Nonexhaustive => unreachable!(),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::InvalidCString(ref nul_err) => nul_err.description(),
            Error::DatabaseError(_, ref e) => e.message(),
            Error::NotFound => "Record not found",
            Error::QueryBuilderError(ref e) => e.description(),
            Error::DeserializationError(ref e) => e.description(),
            Error::SerializationError(ref e) => e.description(),
            Error::RollbackTransaction => "The current transaction was aborted",
            Error::__Nonexhaustive => unreachable!(),
        }
    }
}

impl Display for ConnectionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ConnectionError::InvalidCString(ref nul_err) => nul_err.fmt(f),
            ConnectionError::BadConnection(ref s) => write!(f, "{}", s),
            ConnectionError::InvalidConnectionUrl(ref s) => write!(f, "{}", s),
            ConnectionError::CouldntSetupConfiguration(ref e) => e.fmt(f),
            ConnectionError::__Nonexhaustive => unreachable!(),
        }
    }
}

impl StdError for ConnectionError {
    fn description(&self) -> &str {
        match *self {
            ConnectionError::InvalidCString(ref nul_err) => nul_err.description(),
            ConnectionError::BadConnection(ref s) => s,
            ConnectionError::InvalidConnectionUrl(ref s) => s,
            ConnectionError::CouldntSetupConfiguration(ref e) => e.description(),
            ConnectionError::__Nonexhaustive => unreachable!(),
        }
    }
}

impl PartialEq for Error {
    fn eq(&self, other: &Error) -> bool {
        match (self, other) {
            (&Error::InvalidCString(ref a), &Error::InvalidCString(ref b)) => a == b,
            (&Error::DatabaseError(_, ref a), &Error::DatabaseError(_, ref b)) => {
                a.message() == b.message()
            }
            (&Error::NotFound, &Error::NotFound) => true,
            _ => false,
        }
    }
}

#[cfg(test)]
#[allow(warnings)]
fn error_impls_send() {
    let err: Error = unimplemented!();
    let x: &Send = &err;
}

pub(crate) fn first_or_not_found<T>(records: QueryResult<Vec<T>>) -> QueryResult<T> {
    records?.into_iter().next().ok_or(Error::NotFound)
}
<commit_msg>Implement `std::error::Error::cause` for our error types<commit_after>//! Errors, type aliases, and functions related to working with `Result`.

use std::convert::From;
use std::error::Error as StdError;
use std::fmt::{self, Display};
use std::ffi::NulError;

#[derive(Debug)]
#[cfg_attr(feature = "clippy", allow(enum_variant_names))]
/// The generic "things can fail in a myriad of ways" enum.
///
/// This type is not intended to be exhaustively matched, and new variants may
/// be added in the future without a major version bump.
pub enum Error {
    /// The query contained a nul byte.
    InvalidCString(NulError),
    /// The database returned an error.
    ///
    /// While Diesel prevents almost all sources of runtime errors at compile
    /// time, it does not attempt to prevent 100% of them. Typically this error
    /// will occur from insert or update statements due to a constraint
    /// violation.
    DatabaseError(
        DatabaseErrorKind,
        Box<DatabaseErrorInformation + Send + Sync>,
    ),
    /// No rows were returned by a query expected to return at least one row.
    ///
    /// This variant is only returned by [`get_result`] and [`first`]. [`load`]
    /// does not treat 0 rows as an error. If you would like to allow either 0
    /// or 1 rows, call [`optional`] on the result.
    ///
    /// [`get_result`]: ../prelude/trait.LoadDsl.html#method.get_result
    /// [`first`]: ../prelude/trait.FirstDsl.html#method.first
    /// [`load`]: ../prelude/trait.LoadDsl.html#method.load
    /// [`optional`]: trait.OptionalExtension.html#tymethod.optional
    NotFound,
    /// The query could not be constructed
    ///
    /// An example of when this error could occur is if you are attempting to
    /// construct an update statement with no changes (e.g. all fields on the
    /// struct are `None`).
    QueryBuilderError(Box<StdError + Send + Sync>),
    /// An error occurred deserializing the data being sent to the database.
    ///
    /// Typically this error means that the stated type of the query is
    /// incorrect. An example of when this error might occur in normal usage is
    /// attempting to deserialize an infinite date into chrono.
    DeserializationError(Box<StdError + Send + Sync>),
    /// An error occurred serializing the data being sent to the database.
    ///
    /// An example of when this error would be returned is if you attempted to
    /// serialize a `chrono::NaiveDate` earlier than the earliest date supported
    /// by PostgreSQL.
    SerializationError(Box<StdError + Send + Sync>),
    /// Roll back the current transaction.
    ///
    /// You can return this variant inside of a transaction when you want to
    /// roll it back, but have no actual error to return. Diesel will never
    /// return this variant unless you gave it to us, and it can be safely
    /// ignored in error handling.
    RollbackTransaction,
    #[doc(hidden)] __Nonexhaustive,
}

#[derive(Debug, Clone, Copy)]
/// The kind of database error that occurred.
///
/// This is not meant to exhaustively cover all possible errors, but is used to
/// identify errors which are commonly recovered from programatically. This enum
/// is not intended to be exhaustively matched, and new variants may be added in
/// the future without a major version bump.
pub enum DatabaseErrorKind {
    /// A unique constraint was violated.
    UniqueViolation,
    /// A foreign key constraint was violated.
    ForeignKeyViolation,
    /// The query could not be sent to the database due to a protocol violation.
    ///
    /// An example of a case where this would occur is if you attempted to send
    /// a query with more than 65000 bind parameters using PostgreSQL.
    UnableToSendCommand,
    #[doc(hidden)] __Unknown, // Match against _ instead, more variants may be added in the future
}

/// Information about an error that was returned by the database.
pub trait DatabaseErrorInformation {
    /// The primary human-readable error message. Typically one line.
    fn message(&self) -> &str;

    /// An optional secondary error message providing more details about the
    /// problem, if it was provided by the database. Might span multiple lines.
    fn details(&self) -> Option<&str>;

    /// An optional suggestion of what to do about the problem, if one was
    /// provided by the database.
    fn hint(&self) -> Option<&str>;

    /// The name of the table the error was associated with, if the error was
    /// associated with a specific table and the backend supports retrieving
    /// that information.
    ///
    /// Currently this method will return `None` for all backends other than
    /// PostgreSQL.
    fn table_name(&self) -> Option<&str>;

    /// The name of the column the error was associated with, if the error was
    /// associated with a specific column and the backend supports retrieving
    /// that information.
    ///
    /// Currently this method will return `None` for all backends other than
    /// PostgreSQL.
    fn column_name(&self) -> Option<&str>;

    /// The constraint that was violated if this error is a constraint violation
    /// and the backend supports retrieving that information.
    ///
    /// Currently this method will return `None` for all backends other than
    /// PostgreSQL.
    fn constraint_name(&self) -> Option<&str>;
}

impl fmt::Debug for DatabaseErrorInformation + Send + Sync {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.message(), f)
    }
}

impl DatabaseErrorInformation for String {
    fn message(&self) -> &str {
        self
    }

    fn details(&self) -> Option<&str> {
        None
    }
    fn hint(&self) -> Option<&str> {
        None
    }
    fn table_name(&self) -> Option<&str> {
        None
    }
    fn column_name(&self) -> Option<&str> {
        None
    }
    fn constraint_name(&self) -> Option<&str> {
        None
    }
}

/// Errors which can occur during [`Connection::establish`]
///
/// [`Connection::establish`]: ../connection/trait.Connection.html?search=#tymethod.establish
#[derive(Debug)]
pub enum ConnectionError {
    /// The connection URL contained a `NUL` byte.
    InvalidCString(NulError),
    /// The database returned an error.
    BadConnection(String),
    /// The connection URL could not be parsed.
    InvalidConnectionUrl(String),
    /// Diesel could not configure the database connection.
    ///
    /// Diesel may try to automatically set session specific configuration
    /// values, such as UTF8 encoding, or enabling the `||` operator on MySQL.
    /// This variant is returned if an error occurred executing the query to set
    /// those options. Diesel will never affect global configuration.
    CouldntSetupConfiguration(Error),
    #[doc(hidden)] __Nonexhaustive, // Match against _ instead, more variants may be added in the future
}

/// A specialized result type for queries.
///
/// This type is exported by `diesel::prelude`, and is generally used by any
/// code which is interacting with Diesel. This type exists to avoid writing out
/// `diesel::result::Error`, and is otherwise a direct mapping to `Result`.
pub type QueryResult<T> = Result<T, Error>;

/// A specialized result type for establishing connections.
///
/// This type exists to avoid writing out `diesel::result::ConnectionError`, and
/// is otherwise a direct mapping to `Result`.
pub type ConnectionResult<T> = Result<T, ConnectionError>;

/// See the [method documentation](#tymethod.optional).
pub trait OptionalExtension<T> {
    /// Converts a `QueryResult<T>` into a `QueryResult<Option<T>>`.
    ///
    /// By default, Diesel treats 0 rows being returned from a query that is expected to return 1
    /// row as an error (e.g. the return value of [`get_result`] or [`first`]). This method will
    /// handle that error, and give you back an `Option<T>` instead.
    ///
    /// [`get_result`]: ../prelude/trait.LoadDsl.html#method.get_result
    /// [`first`]: ../prelude/trait.FirstDsl.html#method.first
    ///
    /// # Example
    ///
    /// ```rust
    /// use diesel::result::{QueryResult, Error};
    /// use diesel::OptionalExtension;
    ///
    /// let result: QueryResult<i32> = Ok(1);
    /// assert_eq!(Ok(Some(1)), result.optional());
    ///
    /// let result: QueryResult<i32> = Err(Error::NotFound);
    /// assert_eq!(Ok(None), result.optional());
    /// ```
    fn optional(self) -> Result<Option<T>, Error>;
}

impl<T> OptionalExtension<T> for QueryResult<T> {
    fn optional(self) -> Result<Option<T>, Error> {
        match self {
            Ok(value) => Ok(Some(value)),
            Err(Error::NotFound) => Ok(None),
            Err(e) => Err(e),
        }
    }
}

impl From<NulError> for ConnectionError {
    fn from(e: NulError) -> Self {
        ConnectionError::InvalidCString(e)
    }
}

impl From<NulError> for Error {
    fn from(e: NulError) -> Self {
        Error::InvalidCString(e)
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::InvalidCString(ref nul_err) => nul_err.fmt(f),
            Error::DatabaseError(_, ref e) => write!(f, "{}", e.message()),
            Error::NotFound => f.write_str("NotFound"),
            Error::QueryBuilderError(ref e) => e.fmt(f),
            Error::DeserializationError(ref e) => e.fmt(f),
            Error::SerializationError(ref e) => e.fmt(f),
            Error::RollbackTransaction => write!(f, "{}", self.description()),
            Error::__Nonexhaustive => unreachable!(),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::InvalidCString(ref nul_err) => nul_err.description(),
            Error::DatabaseError(_, ref e) => e.message(),
            Error::NotFound => "Record not found",
            Error::QueryBuilderError(ref e) => e.description(),
            Error::DeserializationError(ref e) => e.description(),
            Error::SerializationError(ref e) => e.description(),
            Error::RollbackTransaction => "The current transaction was aborted",
            Error::__Nonexhaustive => unreachable!(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Error::InvalidCString(ref e) => Some(e),
            Error::QueryBuilderError(ref e) => Some(&**e),
            Error::DeserializationError(ref e) => Some(&**e),
            Error::SerializationError(ref e) => Some(&**e),
            _ => None,
        }
    }
}

impl Display for ConnectionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ConnectionError::InvalidCString(ref nul_err) => nul_err.fmt(f),
            ConnectionError::BadConnection(ref s) => write!(f, "{}", s),
            ConnectionError::InvalidConnectionUrl(ref s) => write!(f, "{}", s),
            ConnectionError::CouldntSetupConfiguration(ref e) => e.fmt(f),
            ConnectionError::__Nonexhaustive => unreachable!(),
        }
    }
}

impl StdError for ConnectionError {
    fn description(&self) -> &str {
        match *self {
            ConnectionError::InvalidCString(ref nul_err) => nul_err.description(),
            ConnectionError::BadConnection(ref s) => s,
            ConnectionError::InvalidConnectionUrl(ref s) => s,
            ConnectionError::CouldntSetupConfiguration(ref e) => e.description(),
            ConnectionError::__Nonexhaustive => unreachable!(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            ConnectionError::InvalidCString(ref e) => Some(e),
            ConnectionError::CouldntSetupConfiguration(ref e) => Some(e),
            _ => None,
        }
    }
}

impl PartialEq for Error {
    fn eq(&self, other: &Error) -> bool {
        match (self, other) {
            (&Error::InvalidCString(ref a), &Error::InvalidCString(ref b)) => a == b,
            (&Error::DatabaseError(_, ref a), &Error::DatabaseError(_, ref b)) => {
                a.message() == b.message()
            }
            (&Error::NotFound, &Error::NotFound) => true,
            _ => false,
        }
    }
}

#[cfg(test)]
#[allow(warnings)]
fn error_impls_send() {
    let err: Error = unimplemented!();
    let x: &Send = &err;
}

pub(crate) fn first_or_not_found<T>(records: QueryResult<Vec<T>>) -> QueryResult<T> {
    records?.into_iter().next().ok_or(Error::NotFound)
}
<|endoftext|>


<commit_before>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// This is meant to be a comprehensive test of invocations with/without
// trailing commas (or other, similar optionally-trailing separators).
// Every macro is accounted for, even those not tested in this file.
// (There will be a note indicating why).

// std and core are both tested because they may contain separate
// implementations for some macro_rules! macros as an implementation
// detail.

// compile-flags: --test -C debug_assertions=yes
// revisions: std core

#![cfg_attr(core, no_std)]

#![feature(concat_idents)]

#[cfg(std)] use std::fmt;
#[cfg(core)] use core::fmt;

#[test]
fn assert() {
    assert!(true);
    assert!(true,);
    assert!(true, "hello");
    assert!(true, "hello",);
    assert!(true, "hello {}", "world");
    assert!(true, "hello {}", "world",);
}

#[test]
fn assert_eq() {
    assert_eq!(1, 1);
    assert_eq!(1, 1,);
    assert_eq!(1, 1, "hello");
    assert_eq!(1, 1, "hello",);
    assert_eq!(1, 1, "hello {}", "world");
    assert_eq!(1, 1, "hello {}", "world",);
}

#[test]
fn assert_ne() {
    assert_ne!(1, 2);
    assert_ne!(1, 2,);
    assert_ne!(1, 2, "hello");
    assert_ne!(1, 2, "hello",);
    assert_ne!(1, 2, "hello {}", "world");
    assert_ne!(1, 2, "hello {}", "world",);
}

#[test]
fn cfg() {
    let _ = cfg!(pants);
    let _ = cfg!(pants,);
    let _ = cfg!(pants = "pants");
    let _ = cfg!(pants = "pants",);
    let _ = cfg!(all(pants));
    let _ = cfg!(all(pants),);
    let _ = cfg!(all(pants,));
    let _ = cfg!(all(pants,),);
}

#[test]
fn column() {
    let _ = column!();
}

// compile_error! is in a companion to this test in compile-fail

#[test]
fn concat() {
    let _ = concat!();
    let _ = concat!("hello");
    let _ = concat!("hello",);
    let _ = concat!("hello", " world");
    let _ = concat!("hello", " world",);
}

#[test]
fn concat_idents() {
    fn foo() {}
    fn foobar() {}

    concat_idents!(foo)();
    concat_idents!(foo,)();
    concat_idents!(foo, bar)();
    concat_idents!(foo, bar,)();
}

#[test]
fn debug_assert() {
    debug_assert!(true);
    debug_assert!(true, );
    debug_assert!(true, "hello");
    debug_assert!(true, "hello",);
    debug_assert!(true, "hello {}", "world");
    debug_assert!(true, "hello {}", "world",);
}

#[test]
fn debug_assert_eq() {
    debug_assert_eq!(1, 1);
    debug_assert_eq!(1, 1,);
    debug_assert_eq!(1, 1, "hello");
    debug_assert_eq!(1, 1, "hello",);
    debug_assert_eq!(1, 1, "hello {}", "world");
    debug_assert_eq!(1, 1, "hello {}", "world",);
}

#[test]
fn debug_assert_ne() {
    debug_assert_ne!(1, 2);
    debug_assert_ne!(1, 2,);
    debug_assert_ne!(1, 2, "hello");
    debug_assert_ne!(1, 2, "hello",);
    debug_assert_ne!(1, 2, "hello {}", "world");
    debug_assert_ne!(1, 2, "hello {}", "world",);
}

#[test]
fn env() {
    let _ = env!("PATH");
    let _ = env!("PATH",);
    let _ = env!("PATH", "not found");
    let _ = env!("PATH", "not found",);
}

#[cfg(std)]
#[test]
fn eprint() {
    eprint!("hello");
    eprint!("hello",);
    eprint!("hello {}", "world");
    eprint!("hello {}", "world",);
}

#[cfg(std)]
#[test]
fn eprintln() {
    eprintln!();
    eprintln!("hello");
    eprintln!("hello",);
    eprintln!("hello {}", "world");
    eprintln!("hello {}", "world",);
}

#[test]
fn file() {
    let _ = file!();
}

#[cfg(std)]
#[test]
fn format() {
    let _ = format!("hello");
    let _ = format!("hello",);
    let _ = format!("hello {}", "world");
    let _ = format!("hello {}", "world",);
}

#[test]
fn format_args() {
    let _ = format_args!("hello");
    let _ = format_args!("hello",);
    let _ = format_args!("hello {}", "world");
    let _ = format_args!("hello {}", "world",);
}

#[test]
fn include() {
    let _ = include!("auxiliary/macro-comma-support.rs");
    let _ = include!("auxiliary/macro-comma-support.rs",);
}

#[test]
fn include_bytes() {
    let _ = include_bytes!("auxiliary/macro-comma-support.rs");
    let _ = include_bytes!("auxiliary/macro-comma-support.rs",);
}

#[test]
fn include_str() {
    let _ = include_str!("auxiliary/macro-comma-support.rs");
    let _ = include_str!("auxiliary/macro-comma-support.rs",);
}

#[test]
fn line() {
    let _ = line!();
}

#[test]
fn module_path() {
    let _ = module_path!();
}

#[test]
fn option_env() {
    let _ = option_env!("PATH");
    let _ = option_env!("PATH",);
}

#[test]
fn panic() {
    // prevent 'unreachable code' warnings
    let falsum = || false;

    if falsum() { panic!(); }
    if falsum() { panic!("hello"); }
    if falsum() { panic!("hello",); }
    if falsum() { panic!("hello {}", "world"); }
    if falsum() { panic!("hello {}", "world",); }
}

#[cfg(std)]
#[test]
fn print() {
    print!("hello");
    print!("hello",);
    print!("hello {}", "world");
    print!("hello {}", "world",);
}

#[cfg(std)]
#[test]
fn println() {
    println!();
    println!("hello");
    println!("hello",);
    println!("hello {}", "world");
    println!("hello {}", "world",);
}

// select! is too troublesome and unlikely to be stabilized

// stringify! is N/A

#[cfg(std)]
#[test]
fn thread_local() {
    // this has an optional trailing *semicolon*
    thread_local! {
        #[allow(unused)] pub static A: () = ()
    }

    thread_local! {
        #[allow(unused)] pub static AA: () = ();
    }

    thread_local! {
        #[allow(unused)] pub static AAA: () = ();
        #[allow(unused)] pub static AAAA: () = ()
    }

    thread_local! {
        #[allow(unused)] pub static AAAAG: () = ();
        #[allow(unused)] pub static AAAAGH: () = ();
    }
}

#[test]
fn try() {
    fn inner() -> Result<(), ()> {
        try!(Ok(()));
        try!(Ok(()),);
        Ok(())
    }

    inner().unwrap();
}

#[test]
fn unimplemented() {
    // prevent 'unreachable code' warnings
    let falsum = || false;

    if falsum() { unimplemented!(); }
    if falsum() { unimplemented!("hello"); }
    if falsum() { unimplemented!("hello",); }
    if falsum() { unimplemented!("hello {}", "world"); }
    if falsum() { unimplemented!("hello {}", "world",); }
}

#[test]
fn unreachable() {
    // prevent 'unreachable code' warnings
    let falsum = || false;

    if falsum() { unreachable!(); }
    if falsum() { unreachable!("hello"); }
    if falsum() { unreachable!("hello",); }
    if falsum() { unreachable!("hello {}", "world"); }
    if falsum() { unreachable!("hello {}", "world",); }
}

#[cfg(std)]
#[test]
fn vec() {
    let _: Vec<()> = vec![];
    let _ = vec![0];
    let _ = vec![0,];
    let _ = vec![0, 1];
    let _ = vec![0, 1,];
}

// give a test body access to a fmt::Formatter, which seems
// to be the easiest way to use 'write!' on core.
macro_rules! test_with_formatter {
    (
        #[test]
        fn $fname:ident($f:ident: &mut fmt::Formatter) $block:block
    ) => {
        #[test]
        fn $fname() {
            struct Struct;
            impl fmt::Display for Struct {
                fn fmt(&self, $f: &mut fmt::Formatter) -> fmt::Result {
                    Ok($block)
                }
            }

            // suppress "unused"
            assert!(true, "{}", Struct);
        }
    };
}

test_with_formatter! {
    #[test]
    fn write(f: &mut fmt::Formatter) {
        let _ = write!(f, "hello");
        let _ = write!(f, "hello",);
        let _ = write!(f, "hello {}", "world");
        let _ = write!(f, "hello {}", "world",);
    }
}

test_with_formatter! {
    #[test]
    fn writeln(f: &mut fmt::Formatter) {
        let _ = writeln!(f);
        let _ = writeln!(f,);
        let _ = writeln!(f, "hello");
        let _ = writeln!(f, "hello",);
        let _ = writeln!(f, "hello {}", "world");
        let _ = writeln!(f, "hello {}", "world",);
    }
}
<commit_msg>ignore-pretty for the macro-comma-support test<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// This is meant to be a comprehensive test of invocations with/without
// trailing commas (or other, similar optionally-trailing separators).
// Every macro is accounted for, even those not tested in this file.
// (There will be a note indicating why).

// std and core are both tested because they may contain separate
// implementations for some macro_rules! macros as an implementation
// detail.

// ignore-pretty issue #37195

// compile-flags: --test -C debug_assertions=yes
// revisions: std core

#![cfg_attr(core, no_std)]

#![feature(concat_idents)]

#[cfg(std)] use std::fmt;
#[cfg(core)] use core::fmt;

#[test]
fn assert() {
    assert!(true);
    assert!(true,);
    assert!(true, "hello");
    assert!(true, "hello",);
    assert!(true, "hello {}", "world");
    assert!(true, "hello {}", "world",);
}

#[test]
fn assert_eq() {
    assert_eq!(1, 1);
    assert_eq!(1, 1,);
    assert_eq!(1, 1, "hello");
    assert_eq!(1, 1, "hello",);
    assert_eq!(1, 1, "hello {}", "world");
    assert_eq!(1, 1, "hello {}", "world",);
}

#[test]
fn assert_ne() {
    assert_ne!(1, 2);
    assert_ne!(1, 2,);
    assert_ne!(1, 2, "hello");
    assert_ne!(1, 2, "hello",);
    assert_ne!(1, 2, "hello {}", "world");
    assert_ne!(1, 2, "hello {}", "world",);
}

#[test]
fn cfg() {
    let _ = cfg!(pants);
    let _ = cfg!(pants,);
    let _ = cfg!(pants = "pants");
    let _ = cfg!(pants = "pants",);
    let _ = cfg!(all(pants));
    let _ = cfg!(all(pants),);
    let _ = cfg!(all(pants,));
    let _ = cfg!(all(pants,),);
}

#[test]
fn column() {
    let _ = column!();
}

// compile_error! is in a companion to this test in compile-fail

#[test]
fn concat() {
    let _ = concat!();
    let _ = concat!("hello");
    let _ = concat!("hello",);
    let _ = concat!("hello", " world");
    let _ = concat!("hello", " world",);
}

#[test]
fn concat_idents() {
    fn foo() {}
    fn foobar() {}

    concat_idents!(foo)();
    concat_idents!(foo,)();
    concat_idents!(foo, bar)();
    concat_idents!(foo, bar,)();
}

#[test]
fn debug_assert() {
    debug_assert!(true);
    debug_assert!(true, );
    debug_assert!(true, "hello");
    debug_assert!(true, "hello",);
    debug_assert!(true, "hello {}", "world");
    debug_assert!(true, "hello {}", "world",);
}

#[test]
fn debug_assert_eq() {
    debug_assert_eq!(1, 1);
    debug_assert_eq!(1, 1,);
    debug_assert_eq!(1, 1, "hello");
    debug_assert_eq!(1, 1, "hello",);
    debug_assert_eq!(1, 1, "hello {}", "world");
    debug_assert_eq!(1, 1, "hello {}", "world",);
}

#[test]
fn debug_assert_ne() {
    debug_assert_ne!(1, 2);
    debug_assert_ne!(1, 2,);
    debug_assert_ne!(1, 2, "hello");
    debug_assert_ne!(1, 2, "hello",);
    debug_assert_ne!(1, 2, "hello {}", "world");
    debug_assert_ne!(1, 2, "hello {}", "world",);
}

#[test]
fn env() {
    let _ = env!("PATH");
    let _ = env!("PATH",);
    let _ = env!("PATH", "not found");
    let _ = env!("PATH", "not found",);
}

#[cfg(std)]
#[test]
fn eprint() {
    eprint!("hello");
    eprint!("hello",);
    eprint!("hello {}", "world");
    eprint!("hello {}", "world",);
}

#[cfg(std)]
#[test]
fn eprintln() {
    eprintln!();
    eprintln!("hello");
    eprintln!("hello",);
    eprintln!("hello {}", "world");
    eprintln!("hello {}", "world",);
}

#[test]
fn file() {
    let _ = file!();
}

#[cfg(std)]
#[test]
fn format() {
    let _ = format!("hello");
    let _ = format!("hello",);
    let _ = format!("hello {}", "world");
    let _ = format!("hello {}", "world",);
}

#[test]
fn format_args() {
    let _ = format_args!("hello");
    let _ = format_args!("hello",);
    let _ = format_args!("hello {}", "world");
    let _ = format_args!("hello {}", "world",);
}

#[test]
fn include() {
    let _ = include!("auxiliary/macro-comma-support.rs");
    let _ = include!("auxiliary/macro-comma-support.rs",);
}

#[test]
fn include_bytes() {
    let _ = include_bytes!("auxiliary/macro-comma-support.rs");
    let _ = include_bytes!("auxiliary/macro-comma-support.rs",);
}

#[test]
fn include_str() {
    let _ = include_str!("auxiliary/macro-comma-support.rs");
    let _ = include_str!("auxiliary/macro-comma-support.rs",);
}

#[test]
fn line() {
    let _ = line!();
}

#[test]
fn module_path() {
    let _ = module_path!();
}

#[test]
fn option_env() {
    let _ = option_env!("PATH");
    let _ = option_env!("PATH",);
}

#[test]
fn panic() {
    // prevent 'unreachable code' warnings
    let falsum = || false;

    if falsum() { panic!(); }
    if falsum() { panic!("hello"); }
    if falsum() { panic!("hello",); }
    if falsum() { panic!("hello {}", "world"); }
    if falsum() { panic!("hello {}", "world",); }
}

#[cfg(std)]
#[test]
fn print() {
    print!("hello");
    print!("hello",);
    print!("hello {}", "world");
    print!("hello {}", "world",);
}

#[cfg(std)]
#[test]
fn println() {
    println!();
    println!("hello");
    println!("hello",);
    println!("hello {}", "world");
    println!("hello {}", "world",);
}

// select! is too troublesome and unlikely to be stabilized

// stringify! is N/A

#[cfg(std)]
#[test]
fn thread_local() {
    // this has an optional trailing *semicolon*
    thread_local! {
        #[allow(unused)] pub static A: () = ()
    }

    thread_local! {
        #[allow(unused)] pub static AA: () = ();
    }

    thread_local! {
        #[allow(unused)] pub static AAA: () = ();
        #[allow(unused)] pub static AAAA: () = ()
    }

    thread_local! {
        #[allow(unused)] pub static AAAAG: () = ();
        #[allow(unused)] pub static AAAAGH: () = ();
    }
}

#[test]
fn try() {
    fn inner() -> Result<(), ()> {
        try!(Ok(()));
        try!(Ok(()),);
        Ok(())
    }

    inner().unwrap();
}

#[test]
fn unimplemented() {
    // prevent 'unreachable code' warnings
    let falsum = || false;

    if falsum() { unimplemented!(); }
    if falsum() { unimplemented!("hello"); }
    if falsum() { unimplemented!("hello",); }
    if falsum() { unimplemented!("hello {}", "world"); }
    if falsum() { unimplemented!("hello {}", "world",); }
}

#[test]
fn unreachable() {
    // prevent 'unreachable code' warnings
    let falsum = || false;

    if falsum() { unreachable!(); }
    if falsum() { unreachable!("hello"); }
    if falsum() { unreachable!("hello",); }
    if falsum() { unreachable!("hello {}", "world"); }
    if falsum() { unreachable!("hello {}", "world",); }
}

#[cfg(std)]
#[test]
fn vec() {
    let _: Vec<()> = vec![];
    let _ = vec![0];
    let _ = vec![0,];
    let _ = vec![0, 1];
    let _ = vec![0, 1,];
}

// give a test body access to a fmt::Formatter, which seems
// to be the easiest way to use 'write!' on core.
macro_rules! test_with_formatter {
    (
        #[test]
        fn $fname:ident($f:ident: &mut fmt::Formatter) $block:block
    ) => {
        #[test]
        fn $fname() {
            struct Struct;
            impl fmt::Display for Struct {
                fn fmt(&self, $f: &mut fmt::Formatter) -> fmt::Result {
                    Ok($block)
                }
            }

            // suppress "unused"
            assert!(true, "{}", Struct);
        }
    };
}

test_with_formatter! {
    #[test]
    fn write(f: &mut fmt::Formatter) {
        let _ = write!(f, "hello");
        let _ = write!(f, "hello",);
        let _ = write!(f, "hello {}", "world");
        let _ = write!(f, "hello {}", "world",);
    }
}

test_with_formatter! {
    #[test]
    fn writeln(f: &mut fmt::Formatter) {
        let _ = writeln!(f);
        let _ = writeln!(f,);
        let _ = writeln!(f, "hello");
        let _ = writeln!(f, "hello",);
        let _ = writeln!(f, "hello {}", "world");
        let _ = writeln!(f, "hello {}", "world",);
    }
}
<|endoftext|>


<commit_before>use super::{Open, Sink};
use libc;
use libpulse_sys::*;
use std::ffi::CStr;
use std::ffi::CString;
use std::io;
use std::mem;
use std::ptr::{null, null_mut};

pub struct PulseAudioSink {
    s: *mut pa_simple,
    ss: pa_sample_spec,
    name: CString,
    desc: CString,
}

fn call_pulseaudio<T, F, FailCheck>(f: F, fail_check: FailCheck, kind: io::ErrorKind) -> io::Result<T>
where
    T: Copy,
    F: Fn(*mut libc::c_int) -> T,
    FailCheck: Fn(T) -> bool,
{
    let mut error: libc::c_int = 0;
    let ret = f(&mut error);
    if fail_check(ret) {
        let err_cstr = unsafe { CStr::from_ptr(pa_strerror(error)) };
        let errstr = err_cstr.to_string_lossy().into_owned();
        Err(io::Error::new(kind, errstr))
    } else {
        Ok(ret)
    }
}

impl PulseAudioSink {
    fn free_connection(&mut self) {
        if self.s != null_mut() {
            unsafe {
                pa_simple_free(self.s);
            }
            self.s = null_mut();
        }
    }
}

impl Drop for PulseAudioSink {
    fn drop(&mut self) {
        self.free_connection();
    }
}

impl Open for PulseAudioSink {
    fn open(device: Option<String>) -> PulseAudioSink {
        debug!("Using PulseAudio sink");

        if device.is_some() {
            panic!("pulseaudio sink does not support specifying a device name");
        }

        let ss = pa_sample_spec {
            format: PA_SAMPLE_S16LE,
            channels: 2, // stereo
            rate: 44100,
        };

        let name = CString::new("librespot").unwrap();
        let description = CString::new("Spotify endpoint").unwrap();

        PulseAudioSink {
            s: null_mut(),
            ss: ss,
            name: name,
            desc: description,
        }
    }
}

impl Sink for PulseAudioSink {
    fn start(&mut self) -> io::Result<()> {
        if self.s == null_mut() {
            self.s = call_pulseaudio(
                |err| unsafe {
                    pa_simple_new(
                        null(),             // Use the default server.
                        self.name.as_ptr(), // Our application's name.
                        PA_STREAM_PLAYBACK,
                        null(),             // Use the default device.
                        self.desc.as_ptr(), // desc of our stream.
                        &self.ss,           // Our sample format.
                        null(),             // Use default channel map
                        null(),             // Use default buffering attributes.
                        err,
                    )
                },
                |ptr| ptr == null_mut(),
                io::ErrorKind::ConnectionRefused,
            )?;
        }
        Ok(())
    }

    fn stop(&mut self) -> io::Result<()> {
        self.free_connection();
        Ok(())
    }

    fn write(&mut self, data: &[i16]) -> io::Result<()> {
        if self.s == null_mut() {
            Err(io::Error::new(
                io::ErrorKind::NotConnected,
                "Not connected to pulseaudio",
            ))
        } else {
            let ptr = data.as_ptr() as *const libc::c_void;
            let len = data.len() as usize * mem::size_of::<i16>();
            call_pulseaudio(
                |err| unsafe { pa_simple_write(self.s, ptr, len, err) },
                |ret| ret < 0,
                io::ErrorKind::BrokenPipe,
            )?;
            Ok(())
        }
    }
}
<commit_msg>playback: pulseaudio: Panic in write if data is empty<commit_after>use super::{Open, Sink};
use libc;
use libpulse_sys::*;
use std::ffi::CStr;
use std::ffi::CString;
use std::io;
use std::mem;
use std::ptr::{null, null_mut};

pub struct PulseAudioSink {
    s: *mut pa_simple,
    ss: pa_sample_spec,
    name: CString,
    desc: CString,
}

fn call_pulseaudio<T, F, FailCheck>(f: F, fail_check: FailCheck, kind: io::ErrorKind) -> io::Result<T>
where
    T: Copy,
    F: Fn(*mut libc::c_int) -> T,
    FailCheck: Fn(T) -> bool,
{
    let mut error: libc::c_int = 0;
    let ret = f(&mut error);
    if fail_check(ret) {
        let err_cstr = unsafe { CStr::from_ptr(pa_strerror(error)) };
        let errstr = err_cstr.to_string_lossy().into_owned();
        Err(io::Error::new(kind, errstr))
    } else {
        Ok(ret)
    }
}

impl PulseAudioSink {
    fn free_connection(&mut self) {
        if self.s != null_mut() {
            unsafe {
                pa_simple_free(self.s);
            }
            self.s = null_mut();
        }
    }
}

impl Drop for PulseAudioSink {
    fn drop(&mut self) {
        self.free_connection();
    }
}

impl Open for PulseAudioSink {
    fn open(device: Option<String>) -> PulseAudioSink {
        debug!("Using PulseAudio sink");

        if device.is_some() {
            panic!("pulseaudio sink does not support specifying a device name");
        }

        let ss = pa_sample_spec {
            format: PA_SAMPLE_S16LE,
            channels: 2, // stereo
            rate: 44100,
        };

        let name = CString::new("librespot").unwrap();
        let description = CString::new("Spotify endpoint").unwrap();

        PulseAudioSink {
            s: null_mut(),
            ss: ss,
            name: name,
            desc: description,
        }
    }
}

impl Sink for PulseAudioSink {
    fn start(&mut self) -> io::Result<()> {
        if self.s == null_mut() {
            self.s = call_pulseaudio(
                |err| unsafe {
                    pa_simple_new(
                        null(),             // Use the default server.
                        self.name.as_ptr(), // Our application's name.
                        PA_STREAM_PLAYBACK,
                        null(),             // Use the default device.
                        self.desc.as_ptr(), // desc of our stream.
                        &self.ss,           // Our sample format.
                        null(),             // Use default channel map
                        null(),             // Use default buffering attributes.
                        err,
                    )
                },
                |ptr| ptr == null_mut(),
                io::ErrorKind::ConnectionRefused,
            )?;
        }
        Ok(())
    }

    fn stop(&mut self) -> io::Result<()> {
        self.free_connection();
        Ok(())
    }

    fn write(&mut self, data: &[i16]) -> io::Result<()> {
        if self.s == null_mut() {
            Err(io::Error::new(
                io::ErrorKind::NotConnected,
                "Not connected to pulseaudio",
            ))
        } else {
            let ptr = data.as_ptr() as *const libc::c_void;
            let len = data.len() as usize * mem::size_of::<i16>();
            assert!(len > 0);
            call_pulseaudio(
                |err| unsafe { pa_simple_write(self.s, ptr, len, err) },
                |ret| ret < 0,
                io::ErrorKind::BrokenPipe,
            )?;
            Ok(())
        }
    }
}
<|endoftext|>