<commit_before>// Copyright 2016 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.

#![allow(dead_code)]

use server::Node;
use server::transport::{ServerRaftStoreRouter, RaftStoreRouter};
use raftstore::store::{Transport, Peekable};
use raftstore::errors::Error as RaftServerError;
use raftstore::coprocessor::RegionSnapshot;
use util::HandyRwLock;
use kvproto::raft_cmdpb::{RaftCmdRequest, RaftCmdResponse, RaftRequestHeader, Request, Response,
                          GetRequest, CmdType, SeekRequest, DeleteRequest, PutRequest};
use kvproto::errorpb;
use kvproto::kvrpcpb::Context;

use pd::PdClient;
use uuid::Uuid;
use std::sync::{Arc, RwLock};
use std::fmt::{self, Formatter, Debug};
use std::io::Error as IoError;
use std::time::Duration;
use std::result;
use rocksdb::DB;
use protobuf::RepeatedField;

use storage::engine;
use super::{Engine, Modify, Snapshot};
use util::event::Event;
use storage::{Key, Value, KvPair};

const DEFAULT_TIMEOUT_SECS: u64 = 5;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        RequestFailed(e: errorpb::Error) {
            from()
            description(e.get_message())
        }
        Io(e: IoError) {
            from()
            cause(e)
            description(e.description())
        }
        RocksDb(reason: String) {
            description(reason)
        }
        Server(e: RaftServerError) {
            from()
            cause(e)
            description(e.description())
        }
        InvalidResponse(reason: String) {
            description(reason)
        }
        InvalidRequest(reason: String) {
            description(reason)
        }
        Timeout(d: Duration) {
            description("request timeout")
            display("timeout after {:?}", d)
        }
    }
}

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

impl From<Error> for engine::Error {
    fn from(e: Error) -> engine::Error {
        match e {
            Error::RequestFailed(e) => engine::Error::Request(e),
            e => box_err!(e),
        }
    }
}

/// RaftKv is a storage engine base on RaftKvServer.
pub struct RaftKv<T: PdClient + 'static, Trans: Transport + 'static> {
    node: Node<T, Trans>,
    db: Arc<DB>,
    router: Arc<RwLock<ServerRaftStoreRouter>>,
}

impl<T: PdClient, Trans: Transport> RaftKv<T, Trans> {
    /// Create a RaftKv using specified configuration.
    pub fn new(node: Node<T, Trans>, db: Arc<DB>) -> RaftKv<T, Trans> {
        let router = node.raft_store_router();
        RaftKv {
            node: node,
            db: db,
            router: router,
        }
    }

    pub fn call_command(&self, request: RaftCmdRequest) -> Result<Event<RaftCmdResponse>> {
        let finished = Event::new();
        let finished2 = finished.clone();
        let timeout = Duration::from_secs(DEFAULT_TIMEOUT_SECS);

        try!(self.router.rl().send_command(request,
                                           box move |resp| {
                                               finished2.set(resp);
                                               // Wait for response to be consumed or `finished` is
                                               // dropped.
                                               finished2.wait_clear(None);
                                               Ok(())
                                           }));

        if finished.wait_timeout(Some(timeout)) {
            return Ok(finished);
        }

        Err(Error::Timeout(timeout))
    }

    fn exec_cmd_request(&self, req: RaftCmdRequest) -> Result<Event<RaftCmdResponse>> {
        let uuid = req.get_header().get_uuid().to_vec();
        let l = req.get_requests().len();

        let resp = try!(self.call_command(req));
        try!(resp.apply(|resp| {
                     if resp.get_header().get_uuid() != &*uuid {
                         return Err(Error::InvalidResponse("response is not correct!!!"
                                                               .to_owned()));
                     }
                     if resp.get_header().has_error() {
                         return Err(Error::RequestFailed(resp.take_header().take_error()));
                     }
                     if l != resp.get_responses().len() {
                         return Err(Error::InvalidResponse("response count is not equal to \
                                                            requests, something must go wrong."
                                                               .to_owned()));
                     }
                     Ok(())
                 })
                 .unwrap());
        Ok(resp)
    }

    fn new_request_header(&self, ctx: &Context) -> RaftRequestHeader {
        let mut header = RaftRequestHeader::new();
        header.set_region_id(ctx.get_region_id());
        header.set_region_epoch(ctx.get_region_epoch().clone());
        header.set_uuid(Uuid::new_v4().as_bytes().to_vec());
        header
    }

    fn exec_requests(&self, ctx: &Context, reqs: Vec<Request>) -> Result<Vec<Response>> {
        let header = self.new_request_header(ctx);
        let mut cmd = RaftCmdRequest::new();
        cmd.set_header(header);
        cmd.set_requests(RepeatedField::from_vec(reqs));
        let resp = try!(self.exec_cmd_request(cmd));
        // notice: raft thread will be woken up after the take method is called.
        Ok(resp.take().unwrap().take_responses().to_vec())
    }

    fn exec_request(&self, ctx: &Context, req: Request) -> Result<Response> {
        let resps = self.exec_requests(ctx, vec![req]);
        resps.map(|mut v| v.remove(0))
    }
}

fn invalid_resp_type(exp: CmdType, act: CmdType) -> engine::Error {
    Error::InvalidResponse(format!("cmd type not match, want {:?}, got {:?}!", exp, act)).into()
}

impl<T: PdClient, Trans: Transport> Debug for RaftKv<T, Trans> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "RaftKv")
    }
}

impl<T: PdClient, Trans: Transport> Engine for RaftKv<T, Trans> {
    fn get(&self, ctx: &Context, key: &Key) -> engine::Result<Option<Value>> {
        let mut get = GetRequest::new();
        get.set_key(key.raw().clone());
        let mut req = Request::new();
        req.set_cmd_type(CmdType::Get);
        req.set_get(get);
        let mut resp = try!(self.exec_request(ctx, req));
        if resp.get_cmd_type() != CmdType::Get {
            return Err(invalid_resp_type(CmdType::Get, resp.get_cmd_type()));
        }
        let get_resp = resp.mut_get();
        if get_resp.has_value() {
            Ok(Some(get_resp.take_value()))
        } else {
            Ok(None)
        }
    }

    fn seek(&self, ctx: &Context, key: &Key) -> engine::Result<Option<KvPair>> {
        let mut seek = SeekRequest::new();
        seek.set_key(key.raw().clone());
        let mut req = Request::new();
        req.set_cmd_type(CmdType::Seek);
        req.set_seek(seek);
        let mut resp = try!(self.exec_request(ctx, req));
        if resp.get_cmd_type() != CmdType::Seek {
            return Err(invalid_resp_type(CmdType::Seek, resp.get_cmd_type()));
        }
        let seek_resp = resp.mut_seek();
        if seek_resp.has_key() {
            Ok(Some((seek_resp.take_key(), seek_resp.take_value())))
        } else {
            Ok(None)
        }
    }

    fn write(&self, ctx: &Context, mut modifies: Vec<Modify>) -> engine::Result<()> {
        if modifies.len() == 0 {
            return Ok(());
        }
        let mut reqs = Vec::with_capacity(modifies.len());
        while !modifies.is_empty() {
            let m = modifies.pop().unwrap();
            let mut req = Request::new();
            match m {
                Modify::Delete(k) => {
                    let mut delete = DeleteRequest::new();
                    delete.set_key(k.raw().clone());
                    req.set_cmd_type(CmdType::Delete);
                    req.set_delete(delete);
                }
                Modify::Put((k, v)) => {
                    let mut put = PutRequest::new();
                    put.set_key(k.raw().clone());
                    put.set_value(v);
                    req.set_cmd_type(CmdType::Put);
                    req.set_put(put);
                }
            }
            reqs.push(req);
        }
        try!(self.exec_requests(ctx, reqs));
        Ok(())
    }

    fn snapshot<'a>(&'a self, ctx: &Context) -> engine::Result<Box<Snapshot + 'a>> {
        let mut req = Request::new();
        req.set_cmd_type(CmdType::Snap);

        let header = self.new_request_header(ctx);
        let mut cmd = RaftCmdRequest::new();
        cmd.set_header(header);
        cmd.mut_requests().push(req);

        // notice: the raft thread will be woken up after resp is dropped
        let resp = try!(self.exec_cmd_request(cmd));
        let region = try!(resp.apply(|resp| {
                                  let mut resp = resp.take_responses().remove(0);
                                  if resp.get_cmd_type() != CmdType::Snap {
                                      return Err(invalid_resp_type(CmdType::Snap,
                                                                   resp.get_cmd_type()));
                                  }
                                  Ok(resp.take_snap().take_region().clone())
                              })
                              .unwrap());

        let snap = RegionSnapshot::from_raw(self.db.as_ref(), region);
        Ok(box snap)
    }
}

impl<'a> Snapshot for RegionSnapshot<'a> {
    fn get(&self, key: &Key) -> engine::Result<Option<Value>> {
        let v = box_try!(self.get_value(key.raw()));
        Ok(v.map(|v| v.to_vec()))
    }

    fn seek(&self, key: &Key) -> engine::Result<Option<KvPair>> {
        let pair = box_try!(self.seek(key.raw()));
        Ok(pair)
    }

    fn reverse_seek(&self, key: &Key) -> engine::Result<Option<KvPair>> {
        let pair = box_try!(self.reverse_seek(key.raw()));
        Ok(pair)
    }
}
<commit_msg>raftkv: move read outside of raft thread. (#552)<commit_after>// Copyright 2016 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.

#![allow(dead_code)]

use server::Node;
use server::transport::{ServerRaftStoreRouter, RaftStoreRouter};
use raftstore::store::{Transport, Peekable};
use raftstore::errors::Error as RaftServerError;
use raftstore::coprocessor::RegionSnapshot;
use util::HandyRwLock;
use kvproto::raft_cmdpb::{RaftCmdRequest, RaftCmdResponse, RaftRequestHeader, Request, Response,
                          CmdType, DeleteRequest, PutRequest};
use kvproto::errorpb;
use kvproto::kvrpcpb::Context;

use pd::PdClient;
use uuid::Uuid;
use std::sync::{Arc, RwLock};
use std::fmt::{self, Formatter, Debug};
use std::io::Error as IoError;
use std::time::Duration;
use std::result;
use rocksdb::DB;
use protobuf::RepeatedField;

use storage::engine;
use super::{Engine, Modify, Snapshot};
use util::event::Event;
use storage::{Key, Value, KvPair};

const DEFAULT_TIMEOUT_SECS: u64 = 5;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        RequestFailed(e: errorpb::Error) {
            from()
            description(e.get_message())
        }
        Io(e: IoError) {
            from()
            cause(e)
            description(e.description())
        }
        RocksDb(reason: String) {
            description(reason)
        }
        Server(e: RaftServerError) {
            from()
            cause(e)
            description(e.description())
        }
        InvalidResponse(reason: String) {
            description(reason)
        }
        InvalidRequest(reason: String) {
            description(reason)
        }
        Timeout(d: Duration) {
            description("request timeout")
            display("timeout after {:?}", d)
        }
    }
}

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

impl From<Error> for engine::Error {
    fn from(e: Error) -> engine::Error {
        match e {
            Error::RequestFailed(e) => engine::Error::Request(e),
            e => box_err!(e),
        }
    }
}

/// RaftKv is a storage engine base on RaftKvServer.
pub struct RaftKv<T: PdClient + 'static, Trans: Transport + 'static> {
    node: Node<T, Trans>,
    db: Arc<DB>,
    router: Arc<RwLock<ServerRaftStoreRouter>>,
}

impl<T: PdClient, Trans: Transport> RaftKv<T, Trans> {
    /// Create a RaftKv using specified configuration.
    pub fn new(node: Node<T, Trans>, db: Arc<DB>) -> RaftKv<T, Trans> {
        let router = node.raft_store_router();
        RaftKv {
            node: node,
            db: db,
            router: router,
        }
    }

    pub fn call_command(&self, request: RaftCmdRequest) -> Result<Event<RaftCmdResponse>> {
        let finished = Event::new();
        let finished2 = finished.clone();
        let timeout = Duration::from_secs(DEFAULT_TIMEOUT_SECS);

        try!(self.router.rl().send_command(request,
                                           box move |resp| {
                                               finished2.set(resp);
                                               // Wait for response to be consumed or `finished` is
                                               // dropped.
                                               finished2.wait_clear(None);
                                               Ok(())
                                           }));

        if finished.wait_timeout(Some(timeout)) {
            return Ok(finished);
        }

        Err(Error::Timeout(timeout))
    }

    fn exec_cmd_request(&self, req: RaftCmdRequest) -> Result<Event<RaftCmdResponse>> {
        let uuid = req.get_header().get_uuid().to_vec();
        let l = req.get_requests().len();

        let resp = try!(self.call_command(req));
        try!(resp.apply(|resp| {
                     if resp.get_header().get_uuid() != &*uuid {
                         return Err(Error::InvalidResponse("response is not correct!!!"
                                                               .to_owned()));
                     }
                     if resp.get_header().has_error() {
                         return Err(Error::RequestFailed(resp.take_header().take_error()));
                     }
                     if l != resp.get_responses().len() {
                         return Err(Error::InvalidResponse("response count is not equal to \
                                                            requests, something must go wrong."
                                                               .to_owned()));
                     }
                     Ok(())
                 })
                 .unwrap());
        Ok(resp)
    }

    fn new_request_header(&self, ctx: &Context) -> RaftRequestHeader {
        let mut header = RaftRequestHeader::new();
        header.set_region_id(ctx.get_region_id());
        header.set_region_epoch(ctx.get_region_epoch().clone());
        header.set_uuid(Uuid::new_v4().as_bytes().to_vec());
        header
    }

    fn exec_requests(&self, ctx: &Context, reqs: Vec<Request>) -> Result<Vec<Response>> {
        let header = self.new_request_header(ctx);
        let mut cmd = RaftCmdRequest::new();
        cmd.set_header(header);
        cmd.set_requests(RepeatedField::from_vec(reqs));
        let resp = try!(self.exec_cmd_request(cmd));
        // notice: raft thread will be woken up after the take method is called.
        Ok(resp.take().unwrap().take_responses().to_vec())
    }

    fn exec_request(&self, ctx: &Context, req: Request) -> Result<Response> {
        let resps = self.exec_requests(ctx, vec![req]);
        resps.map(|mut v| v.remove(0))
    }
}

fn invalid_resp_type(exp: CmdType, act: CmdType) -> engine::Error {
    Error::InvalidResponse(format!("cmd type not match, want {:?}, got {:?}!", exp, act)).into()
}

impl<T: PdClient, Trans: Transport> Debug for RaftKv<T, Trans> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "RaftKv")
    }
}

impl<T: PdClient, Trans: Transport> Engine for RaftKv<T, Trans> {
    fn get(&self, ctx: &Context, key: &Key) -> engine::Result<Option<Value>> {
        let snap = self.snapshot(ctx).unwrap();
        snap.get(key)
    }

    fn seek(&self, ctx: &Context, key: &Key) -> engine::Result<Option<KvPair>> {
        let snap = self.snapshot(ctx).unwrap();
        snap.seek(key)
    }

    fn write(&self, ctx: &Context, mut modifies: Vec<Modify>) -> engine::Result<()> {
        if modifies.len() == 0 {
            return Ok(());
        }
        let mut reqs = Vec::with_capacity(modifies.len());
        while !modifies.is_empty() {
            let m = modifies.pop().unwrap();
            let mut req = Request::new();
            match m {
                Modify::Delete(k) => {
                    let mut delete = DeleteRequest::new();
                    delete.set_key(k.raw().clone());
                    req.set_cmd_type(CmdType::Delete);
                    req.set_delete(delete);
                }
                Modify::Put((k, v)) => {
                    let mut put = PutRequest::new();
                    put.set_key(k.raw().clone());
                    put.set_value(v);
                    req.set_cmd_type(CmdType::Put);
                    req.set_put(put);
                }
            }
            reqs.push(req);
        }
        try!(self.exec_requests(ctx, reqs));
        Ok(())
    }

    fn snapshot<'a>(&'a self, ctx: &Context) -> engine::Result<Box<Snapshot + 'a>> {
        let mut req = Request::new();
        req.set_cmd_type(CmdType::Snap);

        let header = self.new_request_header(ctx);
        let mut cmd = RaftCmdRequest::new();
        cmd.set_header(header);
        cmd.mut_requests().push(req);

        // notice: the raft thread will be woken up after resp is dropped
        let resp = try!(self.exec_cmd_request(cmd));
        let region = try!(resp.apply(|resp| {
                                  let mut resp = resp.take_responses().remove(0);
                                  if resp.get_cmd_type() != CmdType::Snap {
                                      return Err(invalid_resp_type(CmdType::Snap,
                                                                   resp.get_cmd_type()));
                                  }
                                  Ok(resp.take_snap().take_region().clone())
                              })
                              .unwrap());

        let snap = RegionSnapshot::from_raw(self.db.as_ref(), region);
        Ok(box snap)
    }
}

impl<'a> Snapshot for RegionSnapshot<'a> {
    fn get(&self, key: &Key) -> engine::Result<Option<Value>> {
        let v = box_try!(self.get_value(key.raw()));
        Ok(v.map(|v| v.to_vec()))
    }

    fn seek(&self, key: &Key) -> engine::Result<Option<KvPair>> {
        let pair = box_try!(self.seek(key.raw()));
        Ok(pair)
    }

    fn reverse_seek(&self, key: &Key) -> engine::Result<Option<KvPair>> {
        let pair = box_try!(self.reverse_seek(key.raw()));
        Ok(pair)
    }
}
<|endoftext|>


<commit_before>#![unstable(reason = "not public", issue = "none", feature = "fd")]

use crate::cmp;
use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
use crate::mem;
use crate::sys::cvt;
use crate::sys_common::AsInner;

use libc::{c_int, c_void};

#[derive(Debug)]
pub struct FileDesc {
    fd: c_int,
}

// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
// with the man page quoting that if the count of bytes to read is
// greater than `SSIZE_MAX` the result is "unspecified".
//
// On macOS, however, apparently the 64-bit libc is either buggy or
// intentionally showing odd behavior by rejecting any read with a size
// larger than or equal to INT_MAX. To handle both of these the read
// size is capped on both platforms.
#[cfg(target_os = "macos")]
const READ_LIMIT: usize = c_int::MAX as usize - 1;
#[cfg(not(target_os = "macos"))]
const READ_LIMIT: usize = libc::ssize_t::MAX as usize;

impl FileDesc {
    pub fn new(fd: c_int) -> FileDesc {
        FileDesc { fd }
    }

    pub fn raw(&self) -> c_int {
        self.fd
    }

    /// Extracts the actual file descriptor without closing it.
    pub fn into_raw(self) -> c_int {
        let fd = self.fd;
        mem::forget(self);
        fd
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
        })?;
        Ok(ret as usize)
    }

    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::readv(
                self.fd,
                bufs.as_ptr() as *const libc::iovec,
                cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
            )
        })?;
        Ok(ret as usize)
    }

    #[inline]
    pub fn is_read_vectored(&self) -> bool {
        true
    }

    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
        let mut me = self;
        (&mut me).read_to_end(buf)
    }

    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
        #[cfg(target_os = "android")]
        use super::android::cvt_pread64;

        #[cfg(not(target_os = "android"))]
        unsafe fn cvt_pread64(
            fd: c_int,
            buf: *mut c_void,
            count: usize,
            offset: i64,
        ) -> io::Result<isize> {
            #[cfg(not(target_os = "linux"))]
            use libc::pread as pread64;
            #[cfg(target_os = "linux")]
            use libc::pread64;
            cvt(pread64(fd, buf, count, offset))
        }

        unsafe {
            cvt_pread64(
                self.fd,
                buf.as_mut_ptr() as *mut c_void,
                cmp::min(buf.len(), READ_LIMIT),
                offset as i64,
            )
            .map(|n| n as usize)
        }
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
        })?;
        Ok(ret as usize)
    }

    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::writev(
                self.fd,
                bufs.as_ptr() as *const libc::iovec,
                cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
            )
        })?;
        Ok(ret as usize)
    }

    #[inline]
    pub fn is_write_vectored(&self) -> bool {
        true
    }

    pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
        #[cfg(target_os = "android")]
        use super::android::cvt_pwrite64;

        #[cfg(not(target_os = "android"))]
        unsafe fn cvt_pwrite64(
            fd: c_int,
            buf: *const c_void,
            count: usize,
            offset: i64,
        ) -> io::Result<isize> {
            #[cfg(not(target_os = "linux"))]
            use libc::pwrite as pwrite64;
            #[cfg(target_os = "linux")]
            use libc::pwrite64;
            cvt(pwrite64(fd, buf, count, offset))
        }

        unsafe {
            cvt_pwrite64(
                self.fd,
                buf.as_ptr() as *const c_void,
                cmp::min(buf.len(), READ_LIMIT),
                offset as i64,
            )
            .map(|n| n as usize)
        }
    }

    #[cfg(target_os = "linux")]
    pub fn get_cloexec(&self) -> io::Result<bool> {
        unsafe { Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) }
    }

    #[cfg(not(any(
        target_env = "newlib",
        target_os = "solaris",
        target_os = "illumos",
        target_os = "emscripten",
        target_os = "fuchsia",
        target_os = "l4re",
        target_os = "linux",
        target_os = "haiku",
        target_os = "redox"
    )))]
    pub fn set_cloexec(&self) -> io::Result<()> {
        unsafe {
            cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
            Ok(())
        }
    }
    #[cfg(any(
        target_env = "newlib",
        target_os = "solaris",
        target_os = "illumos",
        target_os = "emscripten",
        target_os = "fuchsia",
        target_os = "l4re",
        target_os = "linux",
        target_os = "haiku",
        target_os = "redox"
    ))]
    pub fn set_cloexec(&self) -> io::Result<()> {
        unsafe {
            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
            let new = previous | libc::FD_CLOEXEC;
            if new != previous {
                cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?;
            }
            Ok(())
        }
    }

    #[cfg(target_os = "linux")]
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        unsafe {
            let v = nonblocking as c_int;
            cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?;
            Ok(())
        }
    }

    #[cfg(not(target_os = "linux"))]
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        unsafe {
            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?;
            let new = if nonblocking {
                previous | libc::O_NONBLOCK
            } else {
                previous & !libc::O_NONBLOCK
            };
            if new != previous {
                cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
            }
            Ok(())
        }
    }

    pub fn duplicate(&self) -> io::Result<FileDesc> {
        // We want to atomically duplicate this file descriptor and set the
        // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
        // is a POSIX flag that was added to Linux in 2.6.24.
        let fd = cvt(unsafe { libc::fcntl(self.raw(), libc::F_DUPFD_CLOEXEC, 0) })?;
        Ok(FileDesc::new(fd))
    }
}

impl<'a> Read for &'a FileDesc {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}

impl AsInner<c_int> for FileDesc {
    fn as_inner(&self) -> &c_int {
        &self.fd
    }
}

impl Drop for FileDesc {
    fn drop(&mut self) {
        // Note that errors are ignored when closing a file descriptor. The
        // reason for this is that if an error occurs we don't actually know if
        // the file descriptor was closed or not, and if we retried (for
        // something like EINTR), we might close another valid file descriptor
        // opened after we closed ours.
        let _ = unsafe { libc::close(self.fd) };
    }
}
<commit_msg>Query maximum vector count on Linux and macOS<commit_after>#![unstable(reason = "not public", issue = "none", feature = "fd")]

use crate::cmp;
use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
use crate::mem;
use crate::sys::cvt;
use crate::sys_common::AsInner;

use libc::{c_int, c_void};

#[derive(Debug)]
pub struct FileDesc {
    fd: c_int,
}

// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
// with the man page quoting that if the count of bytes to read is
// greater than `SSIZE_MAX` the result is "unspecified".
//
// On macOS, however, apparently the 64-bit libc is either buggy or
// intentionally showing odd behavior by rejecting any read with a size
// larger than or equal to INT_MAX. To handle both of these the read
// size is capped on both platforms.
#[cfg(target_os = "macos")]
const READ_LIMIT: usize = c_int::MAX as usize - 1;
#[cfg(not(target_os = "macos"))]
const READ_LIMIT: usize = libc::ssize_t::MAX as usize;

#[cfg(any(target_os = "linux", target_os = "macos"))]
fn max_iov() -> c_int {
    let ret = unsafe {
        libc::sysconf(
            #[cfg(target_os = "linux")]
            libc::_SC_IOV_MAX,
            #[cfg(target_os = "macos")]
            libc::_SC_UIO_MAXIOV,
        )
    };

    // 1024 is the default value on modern Linux systems
    // and hopefully more useful than `c_int::MAX`.
    if ret > 0 { ret as c_int } else { 1024 }
}

#[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn max_iov() -> c_int {
    c_int::MAX
}

impl FileDesc {
    pub fn new(fd: c_int) -> FileDesc {
        FileDesc { fd }
    }

    pub fn raw(&self) -> c_int {
        self.fd
    }

    /// Extracts the actual file descriptor without closing it.
    pub fn into_raw(self) -> c_int {
        let fd = self.fd;
        mem::forget(self);
        fd
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
        })?;
        Ok(ret as usize)
    }

    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::readv(
                self.fd,
                bufs.as_ptr() as *const libc::iovec,
                cmp::min(bufs.len(), max_iov() as usize) as c_int,
            )
        })?;
        Ok(ret as usize)
    }

    #[inline]
    pub fn is_read_vectored(&self) -> bool {
        true
    }

    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
        let mut me = self;
        (&mut me).read_to_end(buf)
    }

    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
        #[cfg(target_os = "android")]
        use super::android::cvt_pread64;

        #[cfg(not(target_os = "android"))]
        unsafe fn cvt_pread64(
            fd: c_int,
            buf: *mut c_void,
            count: usize,
            offset: i64,
        ) -> io::Result<isize> {
            #[cfg(not(target_os = "linux"))]
            use libc::pread as pread64;
            #[cfg(target_os = "linux")]
            use libc::pread64;
            cvt(pread64(fd, buf, count, offset))
        }

        unsafe {
            cvt_pread64(
                self.fd,
                buf.as_mut_ptr() as *mut c_void,
                cmp::min(buf.len(), READ_LIMIT),
                offset as i64,
            )
            .map(|n| n as usize)
        }
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
        })?;
        Ok(ret as usize)
    }

    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::writev(
                self.fd,
                bufs.as_ptr() as *const libc::iovec,
                cmp::min(bufs.len(), max_iov() as usize) as c_int,
            )
        })?;
        Ok(ret as usize)
    }

    #[inline]
    pub fn is_write_vectored(&self) -> bool {
        true
    }

    pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
        #[cfg(target_os = "android")]
        use super::android::cvt_pwrite64;

        #[cfg(not(target_os = "android"))]
        unsafe fn cvt_pwrite64(
            fd: c_int,
            buf: *const c_void,
            count: usize,
            offset: i64,
        ) -> io::Result<isize> {
            #[cfg(not(target_os = "linux"))]
            use libc::pwrite as pwrite64;
            #[cfg(target_os = "linux")]
            use libc::pwrite64;
            cvt(pwrite64(fd, buf, count, offset))
        }

        unsafe {
            cvt_pwrite64(
                self.fd,
                buf.as_ptr() as *const c_void,
                cmp::min(buf.len(), READ_LIMIT),
                offset as i64,
            )
            .map(|n| n as usize)
        }
    }

    #[cfg(target_os = "linux")]
    pub fn get_cloexec(&self) -> io::Result<bool> {
        unsafe { Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) }
    }

    #[cfg(not(any(
        target_env = "newlib",
        target_os = "solaris",
        target_os = "illumos",
        target_os = "emscripten",
        target_os = "fuchsia",
        target_os = "l4re",
        target_os = "linux",
        target_os = "haiku",
        target_os = "redox"
    )))]
    pub fn set_cloexec(&self) -> io::Result<()> {
        unsafe {
            cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
            Ok(())
        }
    }
    #[cfg(any(
        target_env = "newlib",
        target_os = "solaris",
        target_os = "illumos",
        target_os = "emscripten",
        target_os = "fuchsia",
        target_os = "l4re",
        target_os = "linux",
        target_os = "haiku",
        target_os = "redox"
    ))]
    pub fn set_cloexec(&self) -> io::Result<()> {
        unsafe {
            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
            let new = previous | libc::FD_CLOEXEC;
            if new != previous {
                cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?;
            }
            Ok(())
        }
    }

    #[cfg(target_os = "linux")]
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        unsafe {
            let v = nonblocking as c_int;
            cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?;
            Ok(())
        }
    }

    #[cfg(not(target_os = "linux"))]
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        unsafe {
            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?;
            let new = if nonblocking {
                previous | libc::O_NONBLOCK
            } else {
                previous & !libc::O_NONBLOCK
            };
            if new != previous {
                cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
            }
            Ok(())
        }
    }

    pub fn duplicate(&self) -> io::Result<FileDesc> {
        // We want to atomically duplicate this file descriptor and set the
        // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
        // is a POSIX flag that was added to Linux in 2.6.24.
        let fd = cvt(unsafe { libc::fcntl(self.raw(), libc::F_DUPFD_CLOEXEC, 0) })?;
        Ok(FileDesc::new(fd))
    }
}

impl<'a> Read for &'a FileDesc {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}

impl AsInner<c_int> for FileDesc {
    fn as_inner(&self) -> &c_int {
        &self.fd
    }
}

impl Drop for FileDesc {
    fn drop(&mut self) {
        // Note that errors are ignored when closing a file descriptor. The
        // reason for this is that if an error occurs we don't actually know if
        // the file descriptor was closed or not, and if we retried (for
        // something like EINTR), we might close another valid file descriptor
        // opened after we closed ours.
        let _ = unsafe { libc::close(self.fd) };
    }
}

#[cfg(test)]
mod tests {
    use super::{FileDesc, IoSlice};

    #[test]
    fn limit_vector_count() {
        let stdout = FileDesc { fd: 1 };
        let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::<Vec<_>>();

        assert!(stdout.write_vectored(&bufs).is_ok());
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate quote;

extern crate proc_macro;
extern crate syn;

mod ast;
mod parser;
mod scanner;
mod token;

use proc_macro::TokenStream;

use ast::Ast;
use std::fs::File;
use std::io::prelude::*;

impl<'a> token::Name<'a> {
    pub fn resolve(&self, scope_depth: u32) -> String {
        let root = match self.leading_dots {
            0 => "self".to_owned(),
            x => format!("_s{}", scope_depth.checked_sub(x).expect("Too many dots")),
        };

        let mut buf = root;
        for ref segment in &self.segments {
            buf.push('.');
            buf.push_str(segment);
        }

        buf
    }
}

fn generate(node: Ast, scope_level: u32) -> quote::Tokens {
    use Ast::*;
    match node {
        Sequence(seq) => {
            let items = seq.into_iter().map(|node| generate(node, scope_level));
            quote! { #(#items)* }
        },
        Literal(text) => {
            quote! { f.write_str(#text)?; }
        },
        Interpolation(name) => {
            let name = syn::Ident::new(name.resolve(scope_level));
            quote! { _bart::DisplayHtmlSafe::safe_fmt(&#name, f)?; }
        },
        UnescapedInterpolation(name) => {
            let name = syn::Ident::new(name.resolve(scope_level));
            quote! { ::std::fmt::Display::fmt(&#name, f)?; }
        },
        Iteration { name, nested } => {
            let name = syn::Ident::new(name.resolve(scope_level));
            let scope_variable = syn::Ident::new(format!("_s{}", scope_level));
            let nested_generated = generate(*nested, scope_level + 1);
            quote! {
                for ref #scope_variable in (&#name).into_iter() {
                    #nested_generated
                }
            }
        },
        Conditional { name, nested } => {
            let name = syn::Ident::new(name.resolve(scope_level));
            let scope_variable = syn::Ident::new(format!("_s{}", scope_level));
            let nested_generated = generate(*nested, scope_level + 1);
            quote! {
                if _bart::Conditional::val(&#name) {
                    let ref #scope_variable = #name;
                    #nested_generated
                }
            }
        },
        NegativeConditional { name, nested } => {
            let name = syn::Ident::new(name.resolve(scope_level));
            let scope_variable = syn::Ident::new(format!("_s{}", scope_level));
            let nested_generated = generate(*nested, scope_level + 1);
            quote! {
                if !_bart::Conditional::val(&#name) {
                    let ref #scope_variable = #name;
                    #nested_generated
                }
            }
        },
        Scope { name, nested } => {
            let name = syn::Ident::new(name.resolve(scope_level));
            let scope_variable = syn::Ident::new(format!("_s{}", scope_level));
            let nested_generated = generate(*nested, scope_level + 1);
            quote! {
                {
                    let ref #scope_variable = #name;
                    #nested_generated
                }
            }
        },
        _ => unimplemented!()
    }
}

fn find_attr<'a>(attrs: &'a Vec<syn::Attribute>, name: &str) -> Option<&'a str> {
    attrs.iter()
        .find(|&x| x.name() == name)
        .and_then(|ref attr| match &attr.value {
            &syn::MetaItem::NameValue(_, syn::Lit::Str(ref template, _)) => Some(template),
            _ => None
        })
        .map(|x| x.as_ref())
}

fn buf_file(filename: &str) -> String {
    let mut f = File::open(filename)
        .expect("Unable to open file for reading");
    let mut buf = String::new();
    f.read_to_string(&mut buf)
        .expect("Unable to read file");

    buf
}

fn parse_str(input: &str) -> Result<Ast, parser::Error> {
    parser::parse(scanner::sequence(input).unwrap())
}

#[proc_macro_derive(BartDisplay, attributes(template, template_string))]
pub fn bart_display(input: TokenStream) -> TokenStream {
    use std::env;

    let s = input.to_string();
    let ast = syn::parse_macro_input(&s).unwrap();

    let user_crate_root = env::current_dir().expect("Unable to get current directory");

    let mut dependencies = Vec::<String>::new();

    let filename_opt = find_attr(&ast.attrs, "template");

    let template =
        filename_opt.map(buf_file)
            .or_else(||
                find_attr(&ast.attrs, "template_string").map(|x| x.to_owned())
            )
        .expect("#[derive(BartDisplay)] requires #[template = \"(filename)\"] or  #[template_string = \"...\"]");

    if let Some(filename) = filename_opt {
        dependencies.push(user_crate_root.join(filename).to_str().unwrap().to_owned());
    }

    let parsed = parse_str(&template).unwrap();
    let generated = generate(parsed, 1);

    let name = &ast.ident;
    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();

    let dummy_const = syn::Ident::new(format!("_IMPL_BART_DISPLAY_FOR_{}", &name));

    let gen = quote! {
        #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
        const #dummy_const: () = {
            extern crate bart as _bart;

            #[automatically_derived]
            impl #impl_generics ::std::fmt::Display for #name #ty_generics #where_clause {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    #(
                        let _ = include_bytes!(#dependencies);
                    )*

                    let ref _s0 = self;

                    #generated

                    Ok(())
                }
            }
        };
    };

    gen.parse().unwrap()
}
<commit_msg>Generate code for negative iteration #9<commit_after>#[macro_use] extern crate quote;

extern crate proc_macro;
extern crate syn;

mod ast;
mod parser;
mod scanner;
mod token;

use proc_macro::TokenStream;

use ast::Ast;
use std::fs::File;
use std::io::prelude::*;

impl<'a> token::Name<'a> {
    pub fn resolve(&self, scope_depth: u32) -> String {
        let root = match self.leading_dots {
            0 => "self".to_owned(),
            x => format!("_s{}", scope_depth.checked_sub(x).expect("Too many dots")),
        };

        let mut buf = root;
        for ref segment in &self.segments {
            buf.push('.');
            buf.push_str(segment);
        }

        buf
    }
}

fn generate(node: Ast, scope_level: u32) -> quote::Tokens {
    use Ast::*;
    match node {
        Sequence(seq) => {
            let items = seq.into_iter().map(|node| generate(node, scope_level));
            quote! { #(#items)* }
        },
        Literal(text) => {
            quote! { f.write_str(#text)?; }
        },
        Interpolation(name) => {
            let name = syn::Ident::new(name.resolve(scope_level));
            quote! { _bart::DisplayHtmlSafe::safe_fmt(&#name, f)?; }
        },
        UnescapedInterpolation(name) => {
            let name = syn::Ident::new(name.resolve(scope_level));
            quote! { ::std::fmt::Display::fmt(&#name, f)?; }
        },
        Iteration { name, nested } => {
            let name = syn::Ident::new(name.resolve(scope_level));
            let scope_variable = syn::Ident::new(format!("_s{}", scope_level));
            let nested_generated = generate(*nested, scope_level + 1);
            quote! {
                for ref #scope_variable in (&#name).into_iter() {
                    #nested_generated
                }
            }
        },
        NegativeIteration { name, nested } => {
            let name = syn::Ident::new(name.resolve(scope_level));
            let scope_variable = syn::Ident::new(format!("_s{}", scope_level));
            let nested_generated = generate(*nested, scope_level + 1);
            quote! {
                for ref #scope_variable in _bart::NegativeIterator::neg_iter(&#name) {
                    #nested_generated
                }
            }
        },
        Conditional { name, nested } => {
            let name = syn::Ident::new(name.resolve(scope_level));
            let scope_variable = syn::Ident::new(format!("_s{}", scope_level));
            let nested_generated = generate(*nested, scope_level + 1);
            quote! {
                if _bart::Conditional::val(&#name) {
                    let ref #scope_variable = #name;
                    #nested_generated
                }
            }
        },
        NegativeConditional { name, nested } => {
            let name = syn::Ident::new(name.resolve(scope_level));
            let scope_variable = syn::Ident::new(format!("_s{}", scope_level));
            let nested_generated = generate(*nested, scope_level + 1);
            quote! {
                if !_bart::Conditional::val(&#name) {
                    let ref #scope_variable = #name;
                    #nested_generated
                }
            }
        },
        Scope { name, nested } => {
            let name = syn::Ident::new(name.resolve(scope_level));
            let scope_variable = syn::Ident::new(format!("_s{}", scope_level));
            let nested_generated = generate(*nested, scope_level + 1);
            quote! {
                {
                    let ref #scope_variable = #name;
                    #nested_generated
                }
            }
        },
    }
}

fn find_attr<'a>(attrs: &'a Vec<syn::Attribute>, name: &str) -> Option<&'a str> {
    attrs.iter()
        .find(|&x| x.name() == name)
        .and_then(|ref attr| match &attr.value {
            &syn::MetaItem::NameValue(_, syn::Lit::Str(ref template, _)) => Some(template),
            _ => None
        })
        .map(|x| x.as_ref())
}

fn buf_file(filename: &str) -> String {
    let mut f = File::open(filename)
        .expect("Unable to open file for reading");
    let mut buf = String::new();
    f.read_to_string(&mut buf)
        .expect("Unable to read file");

    buf
}

fn parse_str(input: &str) -> Result<Ast, parser::Error> {
    parser::parse(scanner::sequence(input).unwrap())
}

#[proc_macro_derive(BartDisplay, attributes(template, template_string))]
pub fn bart_display(input: TokenStream) -> TokenStream {
    use std::env;

    let s = input.to_string();
    let ast = syn::parse_macro_input(&s).unwrap();

    let user_crate_root = env::current_dir().expect("Unable to get current directory");

    let mut dependencies = Vec::<String>::new();

    let filename_opt = find_attr(&ast.attrs, "template");

    let template =
        filename_opt.map(buf_file)
            .or_else(||
                find_attr(&ast.attrs, "template_string").map(|x| x.to_owned())
            )
        .expect("#[derive(BartDisplay)] requires #[template = \"(filename)\"] or  #[template_string = \"...\"]");

    if let Some(filename) = filename_opt {
        dependencies.push(user_crate_root.join(filename).to_str().unwrap().to_owned());
    }

    let parsed = parse_str(&template).unwrap();
    let generated = generate(parsed, 1);

    let name = &ast.ident;
    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();

    let dummy_const = syn::Ident::new(format!("_IMPL_BART_DISPLAY_FOR_{}", &name));

    let gen = quote! {
        #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
        const #dummy_const: () = {
            extern crate bart as _bart;

            #[automatically_derived]
            impl #impl_generics ::std::fmt::Display for #name #ty_generics #where_clause {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    #(
                        let _ = include_bytes!(#dependencies);
                    )*

                    let ref _s0 = self;

                    #generated

                    Ok(())
                }
            }
        };
    };

    gen.parse().unwrap()
}
<|endoftext|>


<commit_before>// ignore-test the unsized enum no longer compiles

enum A {
    B(char),
    C([Box<A>]),
}

fn c(c:char) {
    A::B(c);
    //~^ ERROR cannot move a value of type A: the size of A cannot be statically determined
}

pub fn main() {}
<commit_msg>Remove unsized enum test<commit_after><|endoftext|>


<commit_before>use crate::query_builder::BindCollector;
use crate::serialize::{IsNull, Output};
use crate::sql_types::HasSqlType;
use crate::sqlite::{Sqlite, SqliteType};
use crate::QueryResult;

#[derive(Debug)]
pub struct SqliteBindCollector<'a> {
    pub(in crate::sqlite) binds: Vec<(InternalSqliteBindValue<'a>, SqliteType)>,
}

impl SqliteBindCollector<'_> {
    pub(in crate::sqlite) fn new() -> Self {
        Self { binds: Vec::new() }
    }
}

/// This type represents a value bound to
/// an sqlite prepared statement
///
/// It can be constructed via the various `From<T>` implemenations
#[derive(Debug)]
pub struct SqliteBindValue<'a> {
    pub(in crate::sqlite) inner: InternalSqliteBindValue<'a>,
}

impl<'a> From<i32> for SqliteBindValue<'a> {
    fn from(i: i32) -> Self {
        Self {
            inner: InternalSqliteBindValue::I32(i),
        }
    }
}

impl<'a> From<i64> for SqliteBindValue<'a> {
    fn from(i: i64) -> Self {
        Self {
            inner: InternalSqliteBindValue::I64(i),
        }
    }
}

impl<'a> From<f64> for SqliteBindValue<'a> {
    fn from(f: f64) -> Self {
        Self {
            inner: InternalSqliteBindValue::F64(f),
        }
    }
}

impl<'a, T> From<Option<T>> for SqliteBindValue<'a>
where
    T: Into<SqliteBindValue<'a>>,
{
    fn from(o: Option<T>) -> Self {
        match o {
            Some(v) => v.into(),
            None => Self {
                inner: InternalSqliteBindValue::Null,
            },
        }
    }
}

impl<'a> From<&'a str> for SqliteBindValue<'a> {
    fn from(s: &'a str) -> Self {
        Self {
            inner: InternalSqliteBindValue::BorrowedString(s),
        }
    }
}

impl<'a> From<String> for SqliteBindValue<'a> {
    fn from(s: String) -> Self {
        Self {
            inner: InternalSqliteBindValue::String(s.into_boxed_str()),
        }
    }
}

impl<'a> From<Vec<u8>> for SqliteBindValue<'a> {
    fn from(b: Vec<u8>) -> Self {
        Self {
            inner: InternalSqliteBindValue::Binary(b.into_boxed_slice()),
        }
    }
}

impl<'a> From<&'a [u8]> for SqliteBindValue<'a> {
    fn from(b: &'a [u8]) -> Self {
        Self {
            inner: InternalSqliteBindValue::BorrowedBinary(b),
        }
    }
}

#[derive(Debug)]
pub enum InternalSqliteBindValue<'a> {
    BorrowedString(&'a str),
    String(Box<str>),
    BorrowedBinary(&'a [u8]),
    Binary(Box<[u8]>),
    I32(i32),
    I64(i64),
    F64(f64),
    Null,
}

impl std::fmt::Display for InternalSqliteBindValue<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let n = match self {
            InternalSqliteBindValue::BorrowedString(_) | InternalSqliteBindValue::String(_) => {
                "Text"
            }
            InternalSqliteBindValue::BorrowedBinary(_) | InternalSqliteBindValue::Binary(_) => {
                "Binary"
            }
            InternalSqliteBindValue::I32(_) | InternalSqliteBindValue::I64(_) => "Integer",
            InternalSqliteBindValue::F64(_) => "Float",
            InternalSqliteBindValue::Null => "Null",
        };
        f.write_str(n)
    }
}

impl InternalSqliteBindValue<'_> {
    pub(in crate::sqlite) fn result_of(self, ctx: &mut libsqlite3_sys::sqlite3_context) {
        use libsqlite3_sys as ffi;
        use std::os::raw as libc;
        // This unsafe block assumes the following invariants:
        //
        // - `ctx` points to valid memory
        unsafe {
            match self {
                InternalSqliteBindValue::BorrowedString(s) => ffi::sqlite3_result_text(
                    ctx,
                    s.as_ptr() as *const libc::c_char,
                    s.len() as libc::c_int,
                    ffi::SQLITE_TRANSIENT(),
                ),
                InternalSqliteBindValue::String(s) => ffi::sqlite3_result_text(
                    ctx,
                    s.as_ptr() as *const libc::c_char,
                    s.len() as libc::c_int,
                    ffi::SQLITE_TRANSIENT(),
                ),
                InternalSqliteBindValue::Binary(b) => ffi::sqlite3_result_blob(
                    ctx,
                    b.as_ptr() as *const libc::c_void,
                    b.len() as libc::c_int,
                    ffi::SQLITE_TRANSIENT(),
                ),
                InternalSqliteBindValue::BorrowedBinary(b) => ffi::sqlite3_result_blob(
                    ctx,
                    b.as_ptr() as *const libc::c_void,
                    b.len() as libc::c_int,
                    ffi::SQLITE_TRANSIENT(),
                ),
                InternalSqliteBindValue::I32(i) => ffi::sqlite3_result_int(ctx, i as libc::c_int),
                InternalSqliteBindValue::I64(l) => ffi::sqlite3_result_int64(ctx, l),
                InternalSqliteBindValue::F64(d) => {
                    ffi::sqlite3_result_double(ctx, d as libc::c_double)
                }
                InternalSqliteBindValue::Null => ffi::sqlite3_result_null(ctx),
            }
        }
    }
}

impl<'a> BindCollector<'a, Sqlite> for SqliteBindCollector<'a> {
    type Buffer = SqliteBindValue<'a>;

    fn push_bound_value<T, U>(&mut self, bind: &'a U, metadata_lookup: &mut ()) -> QueryResult<()>
    where
        Sqlite: crate::sql_types::HasSqlType<T>,
        U: crate::serialize::ToSql<T, Sqlite>,
    {
        let value = SqliteBindValue {
            inner: InternalSqliteBindValue::Null,
        };
        let mut to_sql_output = Output::new(value, metadata_lookup);
        let is_null = bind
            .to_sql(&mut to_sql_output)
            .map_err(crate::result::Error::SerializationError)?;
        let bind = to_sql_output.into_inner();
        let metadata = Sqlite::metadata(metadata_lookup);
        self.binds.push((
            match is_null {
                IsNull::No => bind.inner,
                IsNull::Yes => InternalSqliteBindValue::Null,
            },
            metadata,
        ));
        Ok(())
    }
}
<commit_msg>Update diesel/src/sqlite/connection/bind_collector.rs<commit_after>use crate::query_builder::BindCollector;
use crate::serialize::{IsNull, Output};
use crate::sql_types::HasSqlType;
use crate::sqlite::{Sqlite, SqliteType};
use crate::QueryResult;

#[derive(Debug)]
pub struct SqliteBindCollector<'a> {
    pub(in crate::sqlite) binds: Vec<(InternalSqliteBindValue<'a>, SqliteType)>,
}

impl SqliteBindCollector<'_> {
    pub(in crate::sqlite) fn new() -> Self {
        Self { binds: Vec::new() }
    }
}

/// This type represents a value bound to
/// an sqlite prepared statement
///
/// It can be constructed via the various `From<T>` implementations
#[derive(Debug)]
pub struct SqliteBindValue<'a> {
    pub(in crate::sqlite) inner: InternalSqliteBindValue<'a>,
}

impl<'a> From<i32> for SqliteBindValue<'a> {
    fn from(i: i32) -> Self {
        Self {
            inner: InternalSqliteBindValue::I32(i),
        }
    }
}

impl<'a> From<i64> for SqliteBindValue<'a> {
    fn from(i: i64) -> Self {
        Self {
            inner: InternalSqliteBindValue::I64(i),
        }
    }
}

impl<'a> From<f64> for SqliteBindValue<'a> {
    fn from(f: f64) -> Self {
        Self {
            inner: InternalSqliteBindValue::F64(f),
        }
    }
}

impl<'a, T> From<Option<T>> for SqliteBindValue<'a>
where
    T: Into<SqliteBindValue<'a>>,
{
    fn from(o: Option<T>) -> Self {
        match o {
            Some(v) => v.into(),
            None => Self {
                inner: InternalSqliteBindValue::Null,
            },
        }
    }
}

impl<'a> From<&'a str> for SqliteBindValue<'a> {
    fn from(s: &'a str) -> Self {
        Self {
            inner: InternalSqliteBindValue::BorrowedString(s),
        }
    }
}

impl<'a> From<String> for SqliteBindValue<'a> {
    fn from(s: String) -> Self {
        Self {
            inner: InternalSqliteBindValue::String(s.into_boxed_str()),
        }
    }
}

impl<'a> From<Vec<u8>> for SqliteBindValue<'a> {
    fn from(b: Vec<u8>) -> Self {
        Self {
            inner: InternalSqliteBindValue::Binary(b.into_boxed_slice()),
        }
    }
}

impl<'a> From<&'a [u8]> for SqliteBindValue<'a> {
    fn from(b: &'a [u8]) -> Self {
        Self {
            inner: InternalSqliteBindValue::BorrowedBinary(b),
        }
    }
}

#[derive(Debug)]
pub enum InternalSqliteBindValue<'a> {
    BorrowedString(&'a str),
    String(Box<str>),
    BorrowedBinary(&'a [u8]),
    Binary(Box<[u8]>),
    I32(i32),
    I64(i64),
    F64(f64),
    Null,
}

impl std::fmt::Display for InternalSqliteBindValue<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let n = match self {
            InternalSqliteBindValue::BorrowedString(_) | InternalSqliteBindValue::String(_) => {
                "Text"
            }
            InternalSqliteBindValue::BorrowedBinary(_) | InternalSqliteBindValue::Binary(_) => {
                "Binary"
            }
            InternalSqliteBindValue::I32(_) | InternalSqliteBindValue::I64(_) => "Integer",
            InternalSqliteBindValue::F64(_) => "Float",
            InternalSqliteBindValue::Null => "Null",
        };
        f.write_str(n)
    }
}

impl InternalSqliteBindValue<'_> {
    pub(in crate::sqlite) fn result_of(self, ctx: &mut libsqlite3_sys::sqlite3_context) {
        use libsqlite3_sys as ffi;
        use std::os::raw as libc;
        // This unsafe block assumes the following invariants:
        //
        // - `ctx` points to valid memory
        unsafe {
            match self {
                InternalSqliteBindValue::BorrowedString(s) => ffi::sqlite3_result_text(
                    ctx,
                    s.as_ptr() as *const libc::c_char,
                    s.len() as libc::c_int,
                    ffi::SQLITE_TRANSIENT(),
                ),
                InternalSqliteBindValue::String(s) => ffi::sqlite3_result_text(
                    ctx,
                    s.as_ptr() as *const libc::c_char,
                    s.len() as libc::c_int,
                    ffi::SQLITE_TRANSIENT(),
                ),
                InternalSqliteBindValue::Binary(b) => ffi::sqlite3_result_blob(
                    ctx,
                    b.as_ptr() as *const libc::c_void,
                    b.len() as libc::c_int,
                    ffi::SQLITE_TRANSIENT(),
                ),
                InternalSqliteBindValue::BorrowedBinary(b) => ffi::sqlite3_result_blob(
                    ctx,
                    b.as_ptr() as *const libc::c_void,
                    b.len() as libc::c_int,
                    ffi::SQLITE_TRANSIENT(),
                ),
                InternalSqliteBindValue::I32(i) => ffi::sqlite3_result_int(ctx, i as libc::c_int),
                InternalSqliteBindValue::I64(l) => ffi::sqlite3_result_int64(ctx, l),
                InternalSqliteBindValue::F64(d) => {
                    ffi::sqlite3_result_double(ctx, d as libc::c_double)
                }
                InternalSqliteBindValue::Null => ffi::sqlite3_result_null(ctx),
            }
        }
    }
}

impl<'a> BindCollector<'a, Sqlite> for SqliteBindCollector<'a> {
    type Buffer = SqliteBindValue<'a>;

    fn push_bound_value<T, U>(&mut self, bind: &'a U, metadata_lookup: &mut ()) -> QueryResult<()>
    where
        Sqlite: crate::sql_types::HasSqlType<T>,
        U: crate::serialize::ToSql<T, Sqlite>,
    {
        let value = SqliteBindValue {
            inner: InternalSqliteBindValue::Null,
        };
        let mut to_sql_output = Output::new(value, metadata_lookup);
        let is_null = bind
            .to_sql(&mut to_sql_output)
            .map_err(crate::result::Error::SerializationError)?;
        let bind = to_sql_output.into_inner();
        let metadata = Sqlite::metadata(metadata_lookup);
        self.binds.push((
            match is_null {
                IsNull::No => bind.inner,
                IsNull::Yes => InternalSqliteBindValue::Null,
            },
            metadata,
        ));
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::io::{BufRead, Error, ErrorKind, Result};

use crossbeam_channel::{unbounded, Receiver, Sender};
use mio::net::TcpStream;

use crate::proto::RawMessage;

pub trait IrcWriter {
    fn write_message(&mut self, msg: &RawMessage) -> Result<()>;
}

pub trait IrcReader {
    fn read_message(&mut self) -> Result<RawMessage>;
}

impl<T: Write> IrcWriter for T {
    fn write_message(&mut self, msg: &RawMessage) -> Result<()> {
        let msg_str = msg.to_string();
        self.write_all(msg_str.as_bytes())?;
        self.write_all(b"\r\n")?;

        Ok(())
    }
}

impl<T: BufRead> IrcReader for T {
    fn read_message(&mut self) -> Result<RawMessage> {
        let mut buf = String::new();
        self.read_line(&mut buf)?;

        let line = buf.trim_end_matches(|c| c == '\r' || c == '\n');
        RawMessage::parse(line).ok_or_else(|| {
            Error::new(ErrorKind::Other, "failed to parse message from line")
        })
    }
}

#[derive(Clone)]
pub struct IrcChannel(pub Sender<RawMessage>);

impl IrcChannel {
    pub fn new() -> (Self, Receiver<RawMessage>) {
        let (sender, receiver) = unbounded();
        (IrcChannel(sender), receiver)
    }
}

impl IrcWriter for IrcChannel {
    fn write_message(&mut self, msg: &RawMessage) -> Result<()> {
        if let Err(err) = self.0.send(msg.clone()) {
            println!("Failed to write to client: {:?}", err);
            return Err(Error::new(ErrorKind::Other, "other end disconnected"));
        }
        Ok(())
    }
}

#[derive(Clone)]
pub struct IrcSocketConfig {
    // TODO: stop being lazy, make this &str
    pub addr: String,
    pub max_retries: Option<usize>,
}

pub enum SocketEvent {
    Connected,
    Disconnected,
    Received(RawMessage),
}

// TODO: ReconnectingIrcSocket, PersistentIrcSocket, something to that
// effect.
pub struct IrcSocket {
    config: IrcSocketConfig,

    to_network: (Sender<RawMessage>, Receiver<RawMessage>),
    from_network: Sender<SocketEvent>,
}

impl IrcSocket {
    pub fn new(config: IrcSocketConfig, from_network: Sender<SocketEvent>) -> Self {
        let to_network = unbounded();

        Self {
            config,
            to_network,
            from_network,
        }
    }

    pub fn network_channel(&self) -> Sender<RawMessage> {
        self.to_network.0.clone()
    }

    /// Repeatedly (up to the configured maximum retries) try to
    /// establish a connection to the specied address.
    ///
    /// Eventually this is will include a sleep / exponential backoff
    /// (TODO: that)
    fn try_create_stream(&self) -> Result<TcpStream> {
        let max_retries = self.config.max_retries;

        let mut i = 0;
        loop {
            let stream = std::net::TcpStream::connect(&self.config.addr);
            let over_max_tries = max_retries.map(|max| i > max).unwrap_or(false);

            match stream {
                Ok(stream) => return TcpStream::from_stream(stream),
                Err(err) => {
                    if over_max_tries {
                        return Err(err);
                    }
                }
            }

            i += 1
        }
    }

    /// On connection close, return `true` when the connection should
    /// be restarted, and false otherwise. If there is a
    /// non-recoverable exception, return the error.
    ///
    /// TODO: Need to come up with the clean exit concept.
    fn connect(&mut self) -> Result<bool> {
        // TODO: reimplement this
        Ok(true)
    }

    pub fn start_loop(&mut self) -> Result<()> {
        loop {
            match self.connect() {
                Ok(true) => println!("connection terminated, restarting"),
                Ok(false) => break,
                Err(err) => {
                    println!("connection failed: {:?}", err);
                    return Err(err);
                }
            }
        }
        Ok(())
    }
}
<commit_msg>Remove dead code from socket.rs<commit_after>use std::io::prelude::*;
use std::io::{BufRead, Error, ErrorKind, Result};

use crossbeam_channel::{Receiver, Sender};
use mio::net::TcpStream;

use crate::proto::RawMessage;

pub trait IrcWriter {
    fn write_message(&mut self, msg: &RawMessage) -> Result<()>;
}

pub trait IrcReader {
    fn read_message(&mut self) -> Result<RawMessage>;
}

impl<T: Write> IrcWriter for T {
    fn write_message(&mut self, msg: &RawMessage) -> Result<()> {
        let msg_str = msg.to_string();
        self.write_all(msg_str.as_bytes())?;
        self.write_all(b"\r\n")?;

        Ok(())
    }
}

impl<T: BufRead> IrcReader for T {
    fn read_message(&mut self) -> Result<RawMessage> {
        let mut buf = String::new();
        self.read_line(&mut buf)?;

        let line = buf.trim_end_matches(|c| c == '\r' || c == '\n');
        RawMessage::parse(line).ok_or_else(|| {
            Error::new(ErrorKind::Other, "failed to parse message from line")
        })
    }
}

#[derive(Clone)]
pub struct IrcSocketConfig {
    // TODO: stop being lazy, make this &str
    pub addr: String,
    pub max_retries: Option<usize>,
}

pub struct IrcSocket {
    config: IrcSocketConfig,
    to_network: (Sender<RawMessage>, Receiver<RawMessage>),
}

impl IrcSocket {
    /// establish a connection to the specied address.
    ///
    /// Eventually this is will include a sleep / exponential backoff
    /// (TODO: that)
    fn try_create_stream(&self) -> Result<TcpStream> {
        let max_retries = self.config.max_retries;

        let mut i = 0;
        loop {
            let stream = std::net::TcpStream::connect(&self.config.addr);
            let over_max_tries = max_retries.map(|max| i > max).unwrap_or(false);

            match stream {
                Ok(stream) => return TcpStream::from_stream(stream),
                Err(err) => {
                    if over_max_tries {
                        return Err(err);
                    }
                }
            }

            i += 1
        }
    }
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use std::{
    env,
    ffi::OsStr,
    ops,
    path::{Path, PathBuf},
    process::Command,
};

use anyhow::{Context, Result};
use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId};
use ra_arena::{Arena, Idx};
use ra_db::Edition;
use rustc_hash::FxHashMap;

/// `CargoWorkspace` represents the logical structure of, well, a Cargo
/// workspace. It pretty closely mirrors `cargo metadata` output.
///
/// Note that internally, rust analyzer uses a different structure:
/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
/// while this knows about `Packages` & `Targets`: purely cargo-related
/// concepts.
#[derive(Debug, Clone)]
pub struct CargoWorkspace {
    packages: Arena<PackageData>,
    targets: Arena<TargetData>,
    workspace_root: PathBuf,
}

impl ops::Index<Package> for CargoWorkspace {
    type Output = PackageData;
    fn index(&self, index: Package) -> &PackageData {
        &self.packages[index]
    }
}

impl ops::Index<Target> for CargoWorkspace {
    type Output = TargetData;
    fn index(&self, index: Target) -> &TargetData {
        &self.targets[index]
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RustcConfig {
    pub default_target: Option<String>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CargoConfig {
    /// Do not activate the `default` feature.
    pub no_default_features: bool,

    /// Activate all available features
    pub all_features: bool,

    /// List of features to activate.
    /// This will be ignored if `cargo_all_features` is true.
    pub features: Vec<String>,

    /// Runs cargo check on launch to figure out the correct values of OUT_DIR
    pub load_out_dirs_from_check: bool,

    /// rustc target
    pub default_target: Option<String>,
}

impl Default for CargoConfig {
    fn default() -> Self {
        CargoConfig {
            no_default_features: false,
            all_features: true,
            features: Vec::new(),
            load_out_dirs_from_check: false,
            default_target: None,
        }
    }
}

pub type Package = Idx<PackageData>;

pub type Target = Idx<TargetData>;

#[derive(Debug, Clone)]
pub struct PackageData {
    pub version: String,
    pub name: String,
    pub manifest: PathBuf,
    pub targets: Vec<Target>,
    pub is_member: bool,
    pub dependencies: Vec<PackageDependency>,
    pub edition: Edition,
    pub features: Vec<String>,
    pub out_dir: Option<PathBuf>,
    pub proc_macro_dylib_path: Option<PathBuf>,
}

#[derive(Debug, Clone)]
pub struct PackageDependency {
    pub pkg: Package,
    pub name: String,
}

#[derive(Debug, Clone)]
pub struct TargetData {
    pub package: Package,
    pub name: String,
    pub root: PathBuf,
    pub kind: TargetKind,
    pub is_proc_macro: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetKind {
    Bin,
    /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...).
    Lib,
    Example,
    Test,
    Bench,
    Other,
}

impl TargetKind {
    fn new(kinds: &[String]) -> TargetKind {
        for kind in kinds {
            return match kind.as_str() {
                "bin" => TargetKind::Bin,
                "test" => TargetKind::Test,
                "bench" => TargetKind::Bench,
                "example" => TargetKind::Example,
                "proc-macro" => TargetKind::Lib,
                _ if kind.contains("lib") => TargetKind::Lib,
                _ => continue,
            };
        }
        TargetKind::Other
    }
}

impl PackageData {
    pub fn root(&self) -> &Path {
        self.manifest.parent().unwrap()
    }
}

impl CargoWorkspace {
    pub fn from_cargo_metadata(
        cargo_toml: &Path,
        cargo_features: &CargoConfig,
    ) -> Result<CargoWorkspace> {
        let _ = Command::new(cargo_binary())
            .arg("--version")
            .output()
            .context("failed to run `cargo --version`, is `cargo` in PATH?")?;

        let mut meta = MetadataCommand::new();
        meta.manifest_path(cargo_toml);
        if cargo_features.all_features {
            meta.features(CargoOpt::AllFeatures);
        } else if cargo_features.no_default_features {
            // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
            // https://github.com/oli-obk/cargo_metadata/issues/79
            meta.features(CargoOpt::NoDefaultFeatures);
        } else if !cargo_features.features.is_empty() {
            meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone()));
        }
        if let Some(parent) = cargo_toml.parent() {
            meta.current_dir(parent);
        }
        if let Some(target) = cargo_features.default_target.as_ref() {
            meta.other_options(&[String::from("--filter-platform"), target.clone()]);
        }
        let meta = meta.exec().with_context(|| {
            format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display())
        })?;

        let mut out_dir_by_id = FxHashMap::default();
        let mut proc_macro_dylib_paths = FxHashMap::default();
        if cargo_features.load_out_dirs_from_check {
            let resources = load_extern_resources(cargo_toml, cargo_features)?;
            out_dir_by_id = resources.out_dirs;
            proc_macro_dylib_paths = resources.proc_dylib_paths;
        }

        let mut pkg_by_id = FxHashMap::default();
        let mut packages = Arena::default();
        let mut targets = Arena::default();

        let ws_members = &meta.workspace_members;

        for meta_pkg in meta.packages {
            let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } =
                meta_pkg;
            let is_member = ws_members.contains(&id);
            let edition = edition
                .parse::<Edition>()
                .with_context(|| format!("Failed to parse edition {}", edition))?;
            let pkg = packages.alloc(PackageData {
                name,
                version: version.to_string(),
                manifest: manifest_path,
                targets: Vec::new(),
                is_member,
                edition,
                dependencies: Vec::new(),
                features: Vec::new(),
                out_dir: out_dir_by_id.get(&id).cloned(),
                proc_macro_dylib_path: proc_macro_dylib_paths.get(&id).cloned(),
            });
            let pkg_data = &mut packages[pkg];
            pkg_by_id.insert(id, pkg);
            for meta_tgt in meta_pkg.targets {
                let is_proc_macro = meta_tgt.kind.as_slice() == ["proc-macro"];
                let tgt = targets.alloc(TargetData {
                    package: pkg,
                    name: meta_tgt.name,
                    root: meta_tgt.src_path.clone(),
                    kind: TargetKind::new(meta_tgt.kind.as_slice()),
                    is_proc_macro,
                });
                pkg_data.targets.push(tgt);
            }
        }
        let resolve = meta.resolve.expect("metadata executed with deps");
        for node in resolve.nodes {
            let source = match pkg_by_id.get(&node.id) {
                Some(&src) => src,
                // FIXME: replace this and a similar branch below with `.unwrap`, once
                // https://github.com/rust-lang/cargo/issues/7841
                // is fixed and hits stable (around 1.43-is probably?).
                None => {
                    log::error!("Node id do not match in cargo metadata, ignoring {}", node.id);
                    continue;
                }
            };
            for dep_node in node.deps {
                let pkg = match pkg_by_id.get(&dep_node.pkg) {
                    Some(&pkg) => pkg,
                    None => {
                        log::error!(
                            "Dep node id do not match in cargo metadata, ignoring {}",
                            dep_node.pkg
                        );
                        continue;
                    }
                };
                let dep = PackageDependency { name: dep_node.name, pkg };
                packages[source].dependencies.push(dep);
            }
            packages[source].features.extend(node.features);
        }

        Ok(CargoWorkspace { packages, targets, workspace_root: meta.workspace_root })
    }

    pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a {
        self.packages.iter().map(|(id, _pkg)| id)
    }

    pub fn target_by_root(&self, root: &Path) -> Option<Target> {
        self.packages()
            .filter_map(|pkg| self[pkg].targets.iter().find(|&&it| self[it].root == root))
            .next()
            .copied()
    }

    pub fn workspace_root(&self) -> &Path {
        &self.workspace_root
    }

    pub fn package_flag(&self, package: &PackageData) -> String {
        if self.is_unique(&*package.name) {
            package.name.clone()
        } else {
            format!("{}:{}", package.name, package.version)
        }
    }

    fn is_unique(&self, name: &str) -> bool {
        self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
    }
}

#[derive(Debug, Clone, Default)]
pub struct ExternResources {
    out_dirs: FxHashMap<PackageId, PathBuf>,
    proc_dylib_paths: FxHashMap<PackageId, PathBuf>,
}

pub fn load_extern_resources(
    cargo_toml: &Path,
    cargo_features: &CargoConfig,
) -> Result<ExternResources> {
    let mut cmd = Command::new(cargo_binary());
    cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml);
    if cargo_features.all_features {
        cmd.arg("--all-features");
    } else if cargo_features.no_default_features {
        // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
        // https://github.com/oli-obk/cargo_metadata/issues/79
        cmd.arg("--no-default-features");
    } else {
        cmd.args(&cargo_features.features);
    }

    let output = cmd.output()?;

    let mut res = ExternResources::default();

    for message in cargo_metadata::parse_messages(output.stdout.as_slice()) {
        if let Ok(message) = message {
            match message {
                Message::BuildScriptExecuted(BuildScript { package_id, out_dir, .. }) => {
                    res.out_dirs.insert(package_id, out_dir);
                }

                Message::CompilerArtifact(message) => {
                    if message.target.kind.contains(&"proc-macro".to_string()) {
                        let package_id = message.package_id;
                        // Skip rmeta file
                        if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name))
                        {
                            res.proc_dylib_paths.insert(package_id, filename.clone());
                        }
                    }
                }
                Message::CompilerMessage(_) => (),
                Message::Unknown => (),
            }
        }
    }
    Ok(res)
}

// FIXME: File a better way to know if it is a dylib
fn is_dylib(path: &Path) -> bool {
    match path.extension().and_then(OsStr::to_str).map(|it| it.to_string().to_lowercase()) {
        None => false,
        Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"),
    }
}

fn cargo_binary() -> String {
    env::var("CARGO").unwrap_or_else(|_| "cargo".to_string())
}
<commit_msg>[config] remove RustcConfig<commit_after>//! FIXME: write short doc here

use std::{
    env,
    ffi::OsStr,
    ops,
    path::{Path, PathBuf},
    process::Command,
};

use anyhow::{Context, Result};
use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId};
use ra_arena::{Arena, Idx};
use ra_db::Edition;
use rustc_hash::FxHashMap;

/// `CargoWorkspace` represents the logical structure of, well, a Cargo
/// workspace. It pretty closely mirrors `cargo metadata` output.
///
/// Note that internally, rust analyzer uses a different structure:
/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
/// while this knows about `Packages` & `Targets`: purely cargo-related
/// concepts.
#[derive(Debug, Clone)]
pub struct CargoWorkspace {
    packages: Arena<PackageData>,
    targets: Arena<TargetData>,
    workspace_root: PathBuf,
}

impl ops::Index<Package> for CargoWorkspace {
    type Output = PackageData;
    fn index(&self, index: Package) -> &PackageData {
        &self.packages[index]
    }
}

impl ops::Index<Target> for CargoWorkspace {
    type Output = TargetData;
    fn index(&self, index: Target) -> &TargetData {
        &self.targets[index]
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CargoConfig {
    /// Do not activate the `default` feature.
    pub no_default_features: bool,

    /// Activate all available features
    pub all_features: bool,

    /// List of features to activate.
    /// This will be ignored if `cargo_all_features` is true.
    pub features: Vec<String>,

    /// Runs cargo check on launch to figure out the correct values of OUT_DIR
    pub load_out_dirs_from_check: bool,

    /// rustc target
    pub default_target: Option<String>,
}

impl Default for CargoConfig {
    fn default() -> Self {
        CargoConfig {
            no_default_features: false,
            all_features: true,
            features: Vec::new(),
            load_out_dirs_from_check: false,
            default_target: None,
        }
    }
}

pub type Package = Idx<PackageData>;

pub type Target = Idx<TargetData>;

#[derive(Debug, Clone)]
pub struct PackageData {
    pub version: String,
    pub name: String,
    pub manifest: PathBuf,
    pub targets: Vec<Target>,
    pub is_member: bool,
    pub dependencies: Vec<PackageDependency>,
    pub edition: Edition,
    pub features: Vec<String>,
    pub out_dir: Option<PathBuf>,
    pub proc_macro_dylib_path: Option<PathBuf>,
}

#[derive(Debug, Clone)]
pub struct PackageDependency {
    pub pkg: Package,
    pub name: String,
}

#[derive(Debug, Clone)]
pub struct TargetData {
    pub package: Package,
    pub name: String,
    pub root: PathBuf,
    pub kind: TargetKind,
    pub is_proc_macro: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetKind {
    Bin,
    /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...).
    Lib,
    Example,
    Test,
    Bench,
    Other,
}

impl TargetKind {
    fn new(kinds: &[String]) -> TargetKind {
        for kind in kinds {
            return match kind.as_str() {
                "bin" => TargetKind::Bin,
                "test" => TargetKind::Test,
                "bench" => TargetKind::Bench,
                "example" => TargetKind::Example,
                "proc-macro" => TargetKind::Lib,
                _ if kind.contains("lib") => TargetKind::Lib,
                _ => continue,
            };
        }
        TargetKind::Other
    }
}

impl PackageData {
    pub fn root(&self) -> &Path {
        self.manifest.parent().unwrap()
    }
}

impl CargoWorkspace {
    pub fn from_cargo_metadata(
        cargo_toml: &Path,
        cargo_features: &CargoConfig,
    ) -> Result<CargoWorkspace> {
        let _ = Command::new(cargo_binary())
            .arg("--version")
            .output()
            .context("failed to run `cargo --version`, is `cargo` in PATH?")?;

        let mut meta = MetadataCommand::new();
        meta.manifest_path(cargo_toml);
        if cargo_features.all_features {
            meta.features(CargoOpt::AllFeatures);
        } else if cargo_features.no_default_features {
            // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
            // https://github.com/oli-obk/cargo_metadata/issues/79
            meta.features(CargoOpt::NoDefaultFeatures);
        } else if !cargo_features.features.is_empty() {
            meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone()));
        }
        if let Some(parent) = cargo_toml.parent() {
            meta.current_dir(parent);
        }
        if let Some(target) = cargo_features.default_target.as_ref() {
            meta.other_options(&[String::from("--filter-platform"), target.clone()]);
        }
        let meta = meta.exec().with_context(|| {
            format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display())
        })?;

        let mut out_dir_by_id = FxHashMap::default();
        let mut proc_macro_dylib_paths = FxHashMap::default();
        if cargo_features.load_out_dirs_from_check {
            let resources = load_extern_resources(cargo_toml, cargo_features)?;
            out_dir_by_id = resources.out_dirs;
            proc_macro_dylib_paths = resources.proc_dylib_paths;
        }

        let mut pkg_by_id = FxHashMap::default();
        let mut packages = Arena::default();
        let mut targets = Arena::default();

        let ws_members = &meta.workspace_members;

        for meta_pkg in meta.packages {
            let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } =
                meta_pkg;
            let is_member = ws_members.contains(&id);
            let edition = edition
                .parse::<Edition>()
                .with_context(|| format!("Failed to parse edition {}", edition))?;
            let pkg = packages.alloc(PackageData {
                name,
                version: version.to_string(),
                manifest: manifest_path,
                targets: Vec::new(),
                is_member,
                edition,
                dependencies: Vec::new(),
                features: Vec::new(),
                out_dir: out_dir_by_id.get(&id).cloned(),
                proc_macro_dylib_path: proc_macro_dylib_paths.get(&id).cloned(),
            });
            let pkg_data = &mut packages[pkg];
            pkg_by_id.insert(id, pkg);
            for meta_tgt in meta_pkg.targets {
                let is_proc_macro = meta_tgt.kind.as_slice() == ["proc-macro"];
                let tgt = targets.alloc(TargetData {
                    package: pkg,
                    name: meta_tgt.name,
                    root: meta_tgt.src_path.clone(),
                    kind: TargetKind::new(meta_tgt.kind.as_slice()),
                    is_proc_macro,
                });
                pkg_data.targets.push(tgt);
            }
        }
        let resolve = meta.resolve.expect("metadata executed with deps");
        for node in resolve.nodes {
            let source = match pkg_by_id.get(&node.id) {
                Some(&src) => src,
                // FIXME: replace this and a similar branch below with `.unwrap`, once
                // https://github.com/rust-lang/cargo/issues/7841
                // is fixed and hits stable (around 1.43-is probably?).
                None => {
                    log::error!("Node id do not match in cargo metadata, ignoring {}", node.id);
                    continue;
                }
            };
            for dep_node in node.deps {
                let pkg = match pkg_by_id.get(&dep_node.pkg) {
                    Some(&pkg) => pkg,
                    None => {
                        log::error!(
                            "Dep node id do not match in cargo metadata, ignoring {}",
                            dep_node.pkg
                        );
                        continue;
                    }
                };
                let dep = PackageDependency { name: dep_node.name, pkg };
                packages[source].dependencies.push(dep);
            }
            packages[source].features.extend(node.features);
        }

        Ok(CargoWorkspace { packages, targets, workspace_root: meta.workspace_root })
    }

    pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a {
        self.packages.iter().map(|(id, _pkg)| id)
    }

    pub fn target_by_root(&self, root: &Path) -> Option<Target> {
        self.packages()
            .filter_map(|pkg| self[pkg].targets.iter().find(|&&it| self[it].root == root))
            .next()
            .copied()
    }

    pub fn workspace_root(&self) -> &Path {
        &self.workspace_root
    }

    pub fn package_flag(&self, package: &PackageData) -> String {
        if self.is_unique(&*package.name) {
            package.name.clone()
        } else {
            format!("{}:{}", package.name, package.version)
        }
    }

    fn is_unique(&self, name: &str) -> bool {
        self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
    }
}

#[derive(Debug, Clone, Default)]
pub struct ExternResources {
    out_dirs: FxHashMap<PackageId, PathBuf>,
    proc_dylib_paths: FxHashMap<PackageId, PathBuf>,
}

pub fn load_extern_resources(
    cargo_toml: &Path,
    cargo_features: &CargoConfig,
) -> Result<ExternResources> {
    let mut cmd = Command::new(cargo_binary());
    cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml);
    if cargo_features.all_features {
        cmd.arg("--all-features");
    } else if cargo_features.no_default_features {
        // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
        // https://github.com/oli-obk/cargo_metadata/issues/79
        cmd.arg("--no-default-features");
    } else {
        cmd.args(&cargo_features.features);
    }

    let output = cmd.output()?;

    let mut res = ExternResources::default();

    for message in cargo_metadata::parse_messages(output.stdout.as_slice()) {
        if let Ok(message) = message {
            match message {
                Message::BuildScriptExecuted(BuildScript { package_id, out_dir, .. }) => {
                    res.out_dirs.insert(package_id, out_dir);
                }

                Message::CompilerArtifact(message) => {
                    if message.target.kind.contains(&"proc-macro".to_string()) {
                        let package_id = message.package_id;
                        // Skip rmeta file
                        if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name))
                        {
                            res.proc_dylib_paths.insert(package_id, filename.clone());
                        }
                    }
                }
                Message::CompilerMessage(_) => (),
                Message::Unknown => (),
            }
        }
    }
    Ok(res)
}

// FIXME: File a better way to know if it is a dylib
fn is_dylib(path: &Path) -> bool {
    match path.extension().and_then(OsStr::to_str).map(|it| it.to_string().to_lowercase()) {
        None => false,
        Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"),
    }
}

fn cargo_binary() -> String {
    env::var("CARGO").unwrap_or_else(|_| "cargo".to_string())
}
<|endoftext|>


<commit_before>use std;
use boyermoore;
use meow;

fn main() {
   let bible = meow::bible();
   let phrase = "And leik, dont think ur all hot soup cuz you just read the FAQ.";
   //let phrase2 = "And leik, dont think ur all hot soup cuz you just read the BANANAS.";
   let phrase2 = "x-ray-banana";

   //let ref = bind str::find_str(_, phrase);
   //let new = bind boyermoore::find_str(_, phrase);

   //meow::compare_sweep_strings("ref^2", ref, ref, 0u, 500000u);
   //meow::compare_sweep_strings("ref vs. new", ref, new, 0u, 500000u);

   meow::time("simple ref", {|| str::find_str(phrase+phrase, phrase)});
   meow::time("simple new", {|| boyermoore::find_str(phrase+phrase, phrase)});

   meow::time("bible ref", {|| str::find_str(bible, phrase)});
   meow::time("bible new", {|| boyermoore::find_str(bible, phrase)});

   let ii = 0u;
   let N = 40u;
   let bibleN = "";
   str::reserve(bibleN, N * str::len(bibleN) + 1u);
   while ii < N {
      bibleN += bible;
      ii += 1u;
   }

   meow::time("bibleN ref", {|| str::find_str(        bibleN, phrase2)});
   meow::time("bibleN new", {|| boyermoore::find_str(bibleN, phrase2)});

   let ii = 0u;
   let N = 80u;
   let bibleN = "";
   str::reserve(bibleN, N * str::len(bibleN) + 1u);
   while ii < N {
      bibleN += bible;
      ii += 1u;
   }

   meow::time("bibleN ref", {|| str::find_str(        bibleN, phrase2)});
   meow::time("bibleN new", {|| boyermoore::find_str(bibleN, phrase2)});

   let ii = 0u;
   let N = 160u;
   let bibleN = "";
   str::reserve(bibleN, N * str::len(bibleN) + 1u);
   while ii < N {
      bibleN += bible;
      ii += 1u;
   }

   meow::time("bibleN ref", {|| str::find_str(        bibleN, phrase2)});
   meow::time("bibleN new", {|| boyermoore::find_str(bibleN, phrase2)});
}

<commit_msg>experimenting<commit_after>use std;
use boyermoore;
use meow;

fn main() {
   let bible = meow::bible();
   //let phrase = "And leik, dont think ur all hot soup cuz you just read the FAQ.";
   let phrase = "And leik, dont think ur all hot soup cuz you just read the BANANAS.";
   let phrase2 = "x-ray-banana";

   //let ref = bind str::find_str(_, phrase);
   //let new = bind boyermoore::find_str(_, phrase);

   //meow::compare_sweep_strings("ref^2", ref, ref, 0u, 500000u);
   //meow::compare_sweep_strings("ref vs. new", ref, new, 0u, 500000u);

   meow::time("a0 ref", {||        str::find_str("hello", phrase)});
   meow::time("a0 new", {|| boyermoore::find_str("hello", phrase)});

   let xx = phrase+phrase;

   meow::time("a1 ref", {||        str::find_str(xx, "")});
   meow::time("a1 new", {|| boyermoore::find_str(xx, "")});

   let _xx = boyermoore::find_str(xx, phrase);

   let xx = phrase;

   meow::time("a3 ref", {||        str::find_str(xx, xx)});
   meow::time("a3 new", {|| boyermoore::find_str(xx, xx)});  // larger needle, slower start

   meow::time("a4 ref", {||        str::find_str("hello", "hello")});
   meow::time("a4 new", {|| boyermoore::find_str("hello", "hello")});

   let yy = "superxpalidocious exxpeealidocious";
   meow::time("a5 ref", {||        str::find_str(yy, yy)});
   meow::time("a5 new", {|| boyermoore::find_str(yy, yy)});  // larger needle, slower start

   meow::time("a ref", {||        str::find_str(xx, phrase2)});
   meow::time("a new", {|| boyermoore::find_str(xx, phrase2)});

   meow::time("b ref", {||        str::find_str(bible, "lulz")});
   meow::time("b new", {|| boyermoore::find_str(bible, "lulz")});

   meow::time("c ref", {||        str::find_str(bible, phrase)});
   meow::time("c new", {|| boyermoore::find_str(bible, phrase)});

   let yy = "superxpalidocious exxpeealidocioussuperxpalidocious exxpeealidocioussuperxpalidocious exxpeealidocious";
   meow::time("c1 ref", {||        str::find_str(bible, yy)});
   meow::time("c1 new", {|| boyermoore::find_str(bible, yy)});

   let ii = 0u;
   let N = 40u;
   let bibleN = "";
   str::reserve(bibleN, N * str::len(bibleN) + 1u);
   while ii < N {
      bibleN += bible;
      ii += 1u;
   }

   meow::time("d ref", {||        str::find_str(bibleN, phrase2)});
   meow::time("d new", {|| boyermoore::find_str(bibleN, phrase2)});

   let ii = 0u;
   let N = 80u;
   let bibleN = "";
   str::reserve(bibleN, N * str::len(bibleN) + 1u);
   while ii < N {
      bibleN += bible;
      ii += 1u;
   }

   meow::time("e ref", {||        str::find_str(bibleN, phrase2)});
   meow::time("e new", {|| boyermoore::find_str(bibleN, phrase2)});

   let ii = 0u;
   let N = 160u;
   let bibleN = "";
   str::reserve(bibleN, N * str::len(bibleN) + 1u);
   while ii < N {
      bibleN += bible;
      ii += 1u;
   }

   meow::time("f ref", {||        str::find_str(bibleN, phrase2)});
   meow::time("f new", {|| boyermoore::find_str(bibleN, phrase2)});
   meow::time("f2 ref", {||        str::find_str(bibleN, phrase)});
   meow::time("f2 new", {|| boyermoore::find_str(bibleN, phrase)});
}

<|endoftext|>


<commit_before>// Copyright 2015-2017 Intecture Developers.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! A library for configuring your servers.
//!
//! The library is organised into a set of endpoints, which are
//! the building blocks for creating complex configurations.

#![recursion_limit = "1024"]

extern crate bytes;
extern crate erased_serde;
#[macro_use] extern crate error_chain;
extern crate futures;
extern crate hostname;
extern crate ipnetwork;
#[macro_use] extern crate log;
extern crate pnet;
extern crate regex;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_proto;
extern crate tokio_service;

pub mod command;
pub mod errors;
pub mod host;
pub mod prelude {
    pub use command;
    pub use host::Host;
    pub use host::remote::{self, RemoteHost};
    pub use host::local::{self, Local};
    pub use telemetry::{self, Cpu, FsMount, Os, OsFamily, OsPlatform, Telemetry};
}
mod target;
pub mod telemetry;

use errors::*;
use erased_serde::Serialize;
use futures::Future;

#[doc(hidden)]
pub trait Executable {
    fn exec(self) -> Box<Future<Item = Box<Serialize>, Error = Error>>;
}

#[doc(hidden)]
#[derive(Serialize, Deserialize)]
pub enum Runnable {
    Command(command::CommandRunnable),
    Telemetry(telemetry::TelemetryRunnable),
}

impl Executable for Runnable {
    fn exec(self) -> Box<Future<Item = Box<Serialize>, Error = Error>> {
        match self {
            Runnable::Command(p) => p.exec(),
            Runnable::Telemetry(p) => p.exec(),
        }
    }
}
<commit_msg>Add remote::Plain to prelude<commit_after>// Copyright 2015-2017 Intecture Developers.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! A library for configuring your servers.
//!
//! The library is organised into a set of endpoints, which are
//! the building blocks for creating complex configurations.

#![recursion_limit = "1024"]

extern crate bytes;
extern crate erased_serde;
#[macro_use] extern crate error_chain;
extern crate futures;
extern crate hostname;
extern crate ipnetwork;
#[macro_use] extern crate log;
extern crate pnet;
extern crate regex;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_proto;
extern crate tokio_service;

pub mod command;
pub mod errors;
pub mod host;
pub mod prelude {
    pub use command;
    pub use host::Host;
    pub use host::remote::{self, Plain, RemoteHost};
    pub use host::local::{self, Local};
    pub use telemetry::{self, Cpu, FsMount, Os, OsFamily, OsPlatform, Telemetry};
}
mod target;
pub mod telemetry;

use errors::*;
use erased_serde::Serialize;
use futures::Future;

#[doc(hidden)]
pub trait Executable {
    fn exec(self) -> Box<Future<Item = Box<Serialize>, Error = Error>>;
}

#[doc(hidden)]
#[derive(Serialize, Deserialize)]
pub enum Runnable {
    Command(command::CommandRunnable),
    Telemetry(telemetry::TelemetryRunnable),
}

impl Executable for Runnable {
    fn exec(self) -> Box<Future<Item = Box<Serialize>, Error = Error>> {
        match self {
            Runnable::Command(p) => p.exec(),
            Runnable::Telemetry(p) => p.exec(),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 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.

pub enum IpAddr {
    Ipv4(u8, u8, u8, u8, u16),
    Ipv6
}
<commit_msg>added Eq and TotalEq instances for IpAddr<commit_after>// Copyright 2013 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.

use std::cmp::{Eq, TotalEq, eq};

pub enum IpAddr {
    Ipv4(u8, u8, u8, u8, u16),
    Ipv6
}

impl Eq for IpAddr {
    fn eq(&self, other: &IpAddr) -> bool {
        match (*self, *other) {
            (Ipv4(a,b,c,d,e), Ipv4(f,g,h,i,j)) => a == f && b == g && c == h && d == i && e == j,
            (Ipv6, Ipv6) => fail!(),
            _ => false
        }
    }
    fn ne(&self, other: &IpAddr) -> bool {
        !eq(self, other)
    }
}

impl TotalEq for IpAddr {
    fn equals(&self, other: &IpAddr) -> bool {
        *self == *other
    }
}
<|endoftext|>