<commit_before>use std::net::SocketAddr;
use std::io;

use solicit::frame::*;
use solicit::StreamId;
use solicit::HttpScheme;
use solicit::HttpError;
use solicit::StaticHeader;
use hpack;

use futures;
use futures::Future;
use futures::stream::Stream;

use tokio_core::net::TcpStream;
use tokio_core::io::Io;
use tokio_core::reactor;

use futures_misc::*;

use solicit_async::*;

use http_common::*;
use client_conf::*;

struct HttpClientStream {
    common: HttpStreamCommon,
    response_handler: Option<futures::sync::mpsc::UnboundedSender<ResultOrEof<HttpStreamPart, HttpError>>>,
}

impl HttpStream for HttpClientStream {
    fn common(&self) -> &HttpStreamCommon {
        &self.common
    }

    fn common_mut(&mut self) -> &mut HttpStreamCommon {
        &mut self.common
    }

    fn new_data_chunk(&mut self, data: &[u8], last: bool) {
        if let Some(ref mut response_handler) = self.response_handler {
            response_handler.send(ResultOrEof::Item(HttpStreamPart {
                content: HttpStreamPartContent::Data(data.to_owned()),
                last: last,
            })).unwrap();
        }
    }

    fn closed_remote(&mut self) {
        if let Some(response_handler) = self.response_handler.take() {
            // it is OK to ignore error: handler may be already dead
            drop(response_handler.send(ResultOrEof::Eof));
        }
    }
}

impl HttpClientStream {
}

struct HttpClientSessionState {
    next_stream_id: StreamId,
    decoder: hpack::Decoder<'static>,
    loop_handle: reactor::Handle,
}

struct ClientInner {
    common: LoopInnerCommon<HttpClientStream>,
    to_write_tx: futures::sync::mpsc::UnboundedSender<ClientToWriteMessage>,
    session_state: HttpClientSessionState,
}

impl ClientInner {
    fn insert_stream(&mut self, stream: HttpClientStream) -> StreamId {
        let id = self.session_state.next_stream_id;
        if let Some(..) = self.common.streams.insert(id, stream) {
            panic!("inserted stream that already existed");
        }
        self.session_state.next_stream_id += 2;
        id
    }
}

impl LoopInner for ClientInner {
    type LoopHttpStream = HttpClientStream;

    fn common(&mut self) -> &mut LoopInnerCommon<HttpClientStream> {
        &mut self.common
    }

    fn send_common(&mut self, message: CommonToWriteMessage) {
        self.to_write_tx.send(ClientToWriteMessage::Common(message))
            .expect("read to write common");
    }

    fn process_headers_frame(&mut self, frame: HeadersFrame) {
        let headers = self.session_state.decoder
                               .decode(&frame.header_fragment())
                               .map_err(HttpError::CompressionError).unwrap();
        let headers: Vec<StaticHeader> = headers.into_iter().map(|h| h.into()).collect();

        let mut stream: &mut HttpClientStream = match self.common.get_stream_mut(frame.get_stream_id()) {
            None => {
                // TODO(mlalic): This means that the server's header is not associated to any
                //               request made by the client nor any server-initiated stream (pushed)
                return;
            }
            Some(stream) => stream,
        };
        // TODO: hack
        if headers.len() != 0 {

            if let Some(ref mut response_handler) = stream.response_handler {
                response_handler.send(ResultOrEof::Item(HttpStreamPart {
                    content: HttpStreamPartContent::Headers(headers),
                    last: frame.is_end_of_stream(),
                })).unwrap();
            }
        }
    }
}

pub struct HttpClientConnectionAsync {
    call_tx: futures::sync::mpsc::UnboundedSender<ClientToWriteMessage>,
    command_tx: futures::sync::mpsc::UnboundedSender<ClientCommandMessage>,
    _remote: reactor::Remote,
}

unsafe impl Sync for HttpClientConnectionAsync {}

struct StartRequestMessage {
    headers: Vec<StaticHeader>,
    body: HttpFutureStreamSend<Vec<u8>>,
    response_handler: futures::sync::mpsc::UnboundedSender<ResultOrEof<HttpStreamPart, HttpError>>,
}

struct BodyChunkMessage {
    stream_id: StreamId,
    chunk: Vec<u8>,
}

struct EndRequestMessage {
    stream_id: StreamId,
}

enum ClientToWriteMessage {
    Start(StartRequestMessage),
    BodyChunk(BodyChunkMessage),
    End(EndRequestMessage),
    Common(CommonToWriteMessage),
}

enum ClientCommandMessage {
    DumpState(futures::sync::oneshot::Sender<ConnectionStateSnapshot>),
}

impl<I : Io + Send + 'static> ClientWriteLoop<I> {
    fn process_start(self, start: StartRequestMessage) -> HttpFuture<Self> {
        let StartRequestMessage { headers, body, response_handler } = start;

        let stream_id = self.inner.with(move |inner: &mut ClientInner| {

            let mut stream = HttpClientStream {
                common: HttpStreamCommon::new(),
                response_handler: Some(response_handler),
            };

            stream.common.outgoing.push_back(HttpStreamPartContent::Headers(headers));

            inner.insert_stream(stream)
        });

        let to_write_tx_1 = self.inner.with(|inner| inner.to_write_tx.clone());
        let to_write_tx_2 = to_write_tx_1.clone();

        self.inner.with(|inner: &mut ClientInner| {
            let future = body
                .fold((), move |(), chunk| {
                    to_write_tx_1.send(ClientToWriteMessage::BodyChunk(BodyChunkMessage {
                        stream_id: stream_id,
                        chunk: chunk,
                    })).unwrap();
                    futures::finished::<_, HttpError>(())
                });
            let future = future
                .and_then(move |()| {
                    to_write_tx_2.send(ClientToWriteMessage::End(EndRequestMessage {
                        stream_id: stream_id,
                    })).unwrap();
                    futures::finished::<_, HttpError>(())
                });

            let future = future.map_err(|e| {
                warn!("{:?}", e);
                ()
            });

            inner.session_state.loop_handle.spawn(future);
        });

        self.send_outg_stream(stream_id)
    }

    fn process_body_chunk(self, body_chunk: BodyChunkMessage) -> HttpFuture<Self> {
        let BodyChunkMessage { stream_id, chunk } = body_chunk;

        self.inner.with(move |inner: &mut ClientInner| {
            let stream = inner.common.get_stream_mut(stream_id)
                .expect(&format!("stream not found: {}", stream_id));
            // TODO: check stream state

            stream.common.outgoing.push_front(HttpStreamPartContent::Data(chunk));
        });

        self.send_outg_stream(stream_id)
    }

    fn process_end(self, end: EndRequestMessage) -> HttpFuture<Self> {
        let EndRequestMessage { stream_id } = end;

        self.inner.with(move |inner: &mut ClientInner| {
            let stream = inner.common.get_stream_mut(stream_id)
                .expect(&format!("stream not found: {}", stream_id));

            // TODO: check stream state
            stream.common.outgoing_end = true;
        });

        self.send_outg_stream(stream_id)
    }

    fn process_message(self, message: ClientToWriteMessage) -> HttpFuture<Self> {
        match message {
            ClientToWriteMessage::Start(start) => self.process_start(start),
            ClientToWriteMessage::BodyChunk(body_chunk) => self.process_body_chunk(body_chunk),
            ClientToWriteMessage::End(end) => self.process_end(end),
            ClientToWriteMessage::Common(common) => self.process_common(common),
        }
    }

    fn run(self, requests: HttpFutureStreamSend<ClientToWriteMessage>) -> HttpFuture<()> {
        let requests = requests.map_err(HttpError::from);
        Box::new(requests
            .fold(self, move |wl, message: ClientToWriteMessage| {
                wl.process_message(message)
            })
            .map(|_| ()))
    }
}

type ClientReadLoop<I> = ReadLoopData<I, ClientInner>;
type ClientWriteLoop<I> = WriteLoopData<I, ClientInner>;
type ClientCommandLoop = CommandLoopData<ClientInner>;

impl HttpClientConnectionAsync {
    fn connected<I : Io + Send + 'static>(
        lh: reactor::Handle, connect: HttpFutureSend<I>, _conf: HttpClientConf)
            -> (Self, HttpFuture<()>)
    {
        let (to_write_tx, to_write_rx) = futures::sync::mpsc::unbounded();
        let (command_tx, command_rx) = futures::sync::mpsc::unbounded();

        let to_write_rx = Box::new(to_write_rx.map_err(|()| HttpError::IoError(io::Error::new(io::ErrorKind::Other, "to_write"))));
        let command_rx = Box::new(command_rx.map_err(|()| HttpError::IoError(io::Error::new(io::ErrorKind::Other, "to_write"))));

        let c = HttpClientConnectionAsync {
            _remote: lh.remote().clone(),
            call_tx: to_write_tx.clone(),
            command_tx: command_tx,
        };

        let handshake = connect.and_then(client_handshake);

        let future = handshake.and_then(move |conn| {
            debug!("handshake done");
            let (read, write) = conn.split();

            let inner = TaskRcMut::new(ClientInner {
                common: LoopInnerCommon::new(HttpScheme::Http),
                to_write_tx: to_write_tx.clone(),
                session_state: HttpClientSessionState {
                    next_stream_id: 1,
                    decoder: hpack::Decoder::new(),
                    loop_handle: lh,
                }
            });

            let run_write = ClientWriteLoop { write: write, inner: inner.clone() }.run(to_write_rx);
            let run_read = ClientReadLoop { read: read, inner: inner.clone() }.run();
            let run_command = ClientCommandLoop { inner: inner.clone() }.run(command_rx);

            run_write.join(run_read).join(run_command).map(|_| ())
        });

        (c, Box::new(future))
    }

    pub fn new_plain(lh: reactor::Handle, addr: &SocketAddr, conf: HttpClientConf) -> (Self, HttpFuture<()>) {
        let addr = addr.clone();

        let no_delay = conf.no_delay.unwrap_or(true);

        let connect = TcpStream::connect(&addr, &lh)
            .map(move |socket| {
                info!("connected to {}", addr);

                socket.set_nodelay(no_delay).expect("failed to set TCP_NODELAY");

                socket
            })
            .map_err(|e| e.into());

        HttpClientConnectionAsync::connected(lh, Box::new(connect), conf)
    }

    pub fn new_tls(_lh: reactor::Handle, _addr: &SocketAddr, _conf: HttpClientConf) -> (Self, HttpFuture<()>) {
        unimplemented!()
        /*
        let addr = addr.clone();

        let connect = TcpStream::connect(&addr, &lh)
            .map(move |c| { info!("connected to {}", addr); c })
            .map_err(|e| e.into());

        let tls_conn = connect.and_then(|conn| {
            tokio_tls::ClientContext::new()
                .unwrap()
                .handshake("localhost", conn)
        });

        let tls_conn = tls_conn.map_err(HttpError::from);

        HttpClientConnectionAsync::connected(lh, Box::new(tls_conn))
        */
    }

    pub fn start_request(
        &self,
        headers: Vec<StaticHeader>,
        body: HttpFutureStreamSend<Vec<u8>>)
            -> HttpPartFutureStreamSend
    {
        let (tx, rx) = futures::oneshot();

        let call_tx = self.call_tx.clone();

        let (req_tx, req_rx) = futures::sync::mpsc::unbounded();

        call_tx.send(ClientToWriteMessage::Start(StartRequestMessage {
            headers: headers,
            body: body,
            response_handler: req_tx,
        })).expect("send request to client");

        let req_rx = req_rx.map_err(|()| HttpError::from(io::Error::new(io::ErrorKind::Other, "req")));

        // TODO: future is no longer needed here
        tx.complete(stream_with_eof_and_error(req_rx, || HttpError::from(io::Error::new(io::ErrorKind::Other, "unexpected eof"))));

        let rx = rx.map_err(|_| HttpError::from(io::Error::new(io::ErrorKind::Other, "oneshot canceled")));

        Box::new(rx.flatten_stream())
    }

    /// For tests
    pub fn dump_state(&self) -> HttpFutureSend<ConnectionStateSnapshot> {
        let (tx, rx) = futures::oneshot();

        self.command_tx.clone().send(ClientCommandMessage::DumpState(tx))
            .expect("send request to dump state");

        let rx = rx.map_err(|_| HttpError::from(io::Error::new(io::ErrorKind::Other, "oneshot canceled")));

        Box::new(rx)
    }
}

impl ClientCommandLoop {
    fn process_dump_state(self, sender: futures::sync::oneshot::Sender<ConnectionStateSnapshot>) -> HttpFuture<Self> {
        // ignore send error, client might be already dead
        drop(sender.complete(self.inner.with(|inner| inner.common.dump_state())));
        Box::new(futures::finished(self))
    }

    fn process_message(self, message: ClientCommandMessage) -> HttpFuture<Self> {
        match message {
            ClientCommandMessage::DumpState(sender) => self.process_dump_state(sender),
        }
    }

    fn run(self, requests: HttpFutureStreamSend<ClientCommandMessage>) -> HttpFuture<()> {
        let requests = requests.map_err(HttpError::from);
        Box::new(requests
            .fold(self, move |l, message: ClientCommandMessage| {
                l.process_message(message)
            })
            .map(|_| ()))
    }
}
<commit_msg>handle http2 client send error<commit_after>use std::net::SocketAddr;
use std::io;

use solicit::frame::*;
use solicit::StreamId;
use solicit::HttpScheme;
use solicit::HttpError;
use solicit::StaticHeader;
use hpack;

use futures;
use futures::Future;
use futures::stream;
use futures::stream::Stream;

use tokio_core::net::TcpStream;
use tokio_core::io::Io;
use tokio_core::reactor;

use futures_misc::*;

use solicit_async::*;

use http_common::*;
use client_conf::*;

struct HttpClientStream {
    common: HttpStreamCommon,
    response_handler: Option<futures::sync::mpsc::UnboundedSender<ResultOrEof<HttpStreamPart, HttpError>>>,
}

impl HttpStream for HttpClientStream {
    fn common(&self) -> &HttpStreamCommon {
        &self.common
    }

    fn common_mut(&mut self) -> &mut HttpStreamCommon {
        &mut self.common
    }

    fn new_data_chunk(&mut self, data: &[u8], last: bool) {
        if let Some(ref mut response_handler) = self.response_handler {
            response_handler.send(ResultOrEof::Item(HttpStreamPart {
                content: HttpStreamPartContent::Data(data.to_owned()),
                last: last,
            })).unwrap();
        }
    }

    fn closed_remote(&mut self) {
        if let Some(response_handler) = self.response_handler.take() {
            // it is OK to ignore error: handler may be already dead
            drop(response_handler.send(ResultOrEof::Eof));
        }
    }
}

impl HttpClientStream {
}

struct HttpClientSessionState {
    next_stream_id: StreamId,
    decoder: hpack::Decoder<'static>,
    loop_handle: reactor::Handle,
}

struct ClientInner {
    common: LoopInnerCommon<HttpClientStream>,
    to_write_tx: futures::sync::mpsc::UnboundedSender<ClientToWriteMessage>,
    session_state: HttpClientSessionState,
}

impl ClientInner {
    fn insert_stream(&mut self, stream: HttpClientStream) -> StreamId {
        let id = self.session_state.next_stream_id;
        if let Some(..) = self.common.streams.insert(id, stream) {
            panic!("inserted stream that already existed");
        }
        self.session_state.next_stream_id += 2;
        id
    }
}

impl LoopInner for ClientInner {
    type LoopHttpStream = HttpClientStream;

    fn common(&mut self) -> &mut LoopInnerCommon<HttpClientStream> {
        &mut self.common
    }

    fn send_common(&mut self, message: CommonToWriteMessage) {
        self.to_write_tx.send(ClientToWriteMessage::Common(message))
            .expect("read to write common");
    }

    fn process_headers_frame(&mut self, frame: HeadersFrame) {
        let headers = self.session_state.decoder
                               .decode(&frame.header_fragment())
                               .map_err(HttpError::CompressionError).unwrap();
        let headers: Vec<StaticHeader> = headers.into_iter().map(|h| h.into()).collect();

        let mut stream: &mut HttpClientStream = match self.common.get_stream_mut(frame.get_stream_id()) {
            None => {
                // TODO(mlalic): This means that the server's header is not associated to any
                //               request made by the client nor any server-initiated stream (pushed)
                return;
            }
            Some(stream) => stream,
        };
        // TODO: hack
        if headers.len() != 0 {

            if let Some(ref mut response_handler) = stream.response_handler {
                response_handler.send(ResultOrEof::Item(HttpStreamPart {
                    content: HttpStreamPartContent::Headers(headers),
                    last: frame.is_end_of_stream(),
                })).unwrap();
            }
        }
    }
}

pub struct HttpClientConnectionAsync {
    call_tx: futures::sync::mpsc::UnboundedSender<ClientToWriteMessage>,
    command_tx: futures::sync::mpsc::UnboundedSender<ClientCommandMessage>,
    _remote: reactor::Remote,
}

unsafe impl Sync for HttpClientConnectionAsync {}

struct StartRequestMessage {
    headers: Vec<StaticHeader>,
    body: HttpFutureStreamSend<Vec<u8>>,
    response_handler: futures::sync::mpsc::UnboundedSender<ResultOrEof<HttpStreamPart, HttpError>>,
}

struct BodyChunkMessage {
    stream_id: StreamId,
    chunk: Vec<u8>,
}

struct EndRequestMessage {
    stream_id: StreamId,
}

enum ClientToWriteMessage {
    Start(StartRequestMessage),
    BodyChunk(BodyChunkMessage),
    End(EndRequestMessage),
    Common(CommonToWriteMessage),
}

enum ClientCommandMessage {
    DumpState(futures::sync::oneshot::Sender<ConnectionStateSnapshot>),
}

impl<I : Io + Send + 'static> ClientWriteLoop<I> {
    fn process_start(self, start: StartRequestMessage) -> HttpFuture<Self> {
        let StartRequestMessage { headers, body, response_handler } = start;

        let stream_id = self.inner.with(move |inner: &mut ClientInner| {

            let mut stream = HttpClientStream {
                common: HttpStreamCommon::new(),
                response_handler: Some(response_handler),
            };

            stream.common.outgoing.push_back(HttpStreamPartContent::Headers(headers));

            inner.insert_stream(stream)
        });

        let to_write_tx_1 = self.inner.with(|inner| inner.to_write_tx.clone());
        let to_write_tx_2 = to_write_tx_1.clone();

        self.inner.with(|inner: &mut ClientInner| {
            let future = body
                .fold((), move |(), chunk| {
                    to_write_tx_1.send(ClientToWriteMessage::BodyChunk(BodyChunkMessage {
                        stream_id: stream_id,
                        chunk: chunk,
                    })).unwrap();
                    futures::finished::<_, HttpError>(())
                });
            let future = future
                .and_then(move |()| {
                    to_write_tx_2.send(ClientToWriteMessage::End(EndRequestMessage {
                        stream_id: stream_id,
                    })).unwrap();
                    futures::finished::<_, HttpError>(())
                });

            let future = future.map_err(|e| {
                warn!("{:?}", e);
                ()
            });

            inner.session_state.loop_handle.spawn(future);
        });

        self.send_outg_stream(stream_id)
    }

    fn process_body_chunk(self, body_chunk: BodyChunkMessage) -> HttpFuture<Self> {
        let BodyChunkMessage { stream_id, chunk } = body_chunk;

        self.inner.with(move |inner: &mut ClientInner| {
            let stream = inner.common.get_stream_mut(stream_id)
                .expect(&format!("stream not found: {}", stream_id));
            // TODO: check stream state

            stream.common.outgoing.push_front(HttpStreamPartContent::Data(chunk));
        });

        self.send_outg_stream(stream_id)
    }

    fn process_end(self, end: EndRequestMessage) -> HttpFuture<Self> {
        let EndRequestMessage { stream_id } = end;

        self.inner.with(move |inner: &mut ClientInner| {
            let stream = inner.common.get_stream_mut(stream_id)
                .expect(&format!("stream not found: {}", stream_id));

            // TODO: check stream state
            stream.common.outgoing_end = true;
        });

        self.send_outg_stream(stream_id)
    }

    fn process_message(self, message: ClientToWriteMessage) -> HttpFuture<Self> {
        match message {
            ClientToWriteMessage::Start(start) => self.process_start(start),
            ClientToWriteMessage::BodyChunk(body_chunk) => self.process_body_chunk(body_chunk),
            ClientToWriteMessage::End(end) => self.process_end(end),
            ClientToWriteMessage::Common(common) => self.process_common(common),
        }
    }

    fn run(self, requests: HttpFutureStreamSend<ClientToWriteMessage>) -> HttpFuture<()> {
        let requests = requests.map_err(HttpError::from);
        Box::new(requests
            .fold(self, move |wl, message: ClientToWriteMessage| {
                wl.process_message(message)
            })
            .map(|_| ()))
    }
}

type ClientReadLoop<I> = ReadLoopData<I, ClientInner>;
type ClientWriteLoop<I> = WriteLoopData<I, ClientInner>;
type ClientCommandLoop = CommandLoopData<ClientInner>;

impl HttpClientConnectionAsync {
    fn connected<I : Io + Send + 'static>(
        lh: reactor::Handle, connect: HttpFutureSend<I>, _conf: HttpClientConf)
            -> (Self, HttpFuture<()>)
    {
        let (to_write_tx, to_write_rx) = futures::sync::mpsc::unbounded();
        let (command_tx, command_rx) = futures::sync::mpsc::unbounded();

        let to_write_rx = Box::new(to_write_rx.map_err(|()| HttpError::IoError(io::Error::new(io::ErrorKind::Other, "to_write"))));
        let command_rx = Box::new(command_rx.map_err(|()| HttpError::IoError(io::Error::new(io::ErrorKind::Other, "to_write"))));

        let c = HttpClientConnectionAsync {
            _remote: lh.remote().clone(),
            call_tx: to_write_tx.clone(),
            command_tx: command_tx,
        };

        let handshake = connect.and_then(client_handshake);

        let future = handshake.and_then(move |conn| {
            debug!("handshake done");
            let (read, write) = conn.split();

            let inner = TaskRcMut::new(ClientInner {
                common: LoopInnerCommon::new(HttpScheme::Http),
                to_write_tx: to_write_tx.clone(),
                session_state: HttpClientSessionState {
                    next_stream_id: 1,
                    decoder: hpack::Decoder::new(),
                    loop_handle: lh,
                }
            });

            let run_write = ClientWriteLoop { write: write, inner: inner.clone() }.run(to_write_rx);
            let run_read = ClientReadLoop { read: read, inner: inner.clone() }.run();
            let run_command = ClientCommandLoop { inner: inner.clone() }.run(command_rx);

            run_write.join(run_read).join(run_command).map(|_| ())
        });

        (c, Box::new(future))
    }

    pub fn new_plain(lh: reactor::Handle, addr: &SocketAddr, conf: HttpClientConf) -> (Self, HttpFuture<()>) {
        let addr = addr.clone();

        let no_delay = conf.no_delay.unwrap_or(true);

        let connect = TcpStream::connect(&addr, &lh)
            .map(move |socket| {
                info!("connected to {}", addr);

                socket.set_nodelay(no_delay).expect("failed to set TCP_NODELAY");

                socket
            })
            .map_err(|e| e.into());

        HttpClientConnectionAsync::connected(lh, Box::new(connect), conf)
    }

    pub fn new_tls(_lh: reactor::Handle, _addr: &SocketAddr, _conf: HttpClientConf) -> (Self, HttpFuture<()>) {
        unimplemented!()
        /*
        let addr = addr.clone();

        let connect = TcpStream::connect(&addr, &lh)
            .map(move |c| { info!("connected to {}", addr); c })
            .map_err(|e| e.into());

        let tls_conn = connect.and_then(|conn| {
            tokio_tls::ClientContext::new()
                .unwrap()
                .handshake("localhost", conn)
        });

        let tls_conn = tls_conn.map_err(HttpError::from);

        HttpClientConnectionAsync::connected(lh, Box::new(tls_conn))
        */
    }

    pub fn start_request(
        &self,
        headers: Vec<StaticHeader>,
        body: HttpFutureStreamSend<Vec<u8>>)
            -> HttpPartFutureStreamSend
    {
        let (tx, rx) = futures::oneshot();

        let call_tx = self.call_tx.clone();

        let (req_tx, req_rx) = futures::sync::mpsc::unbounded();

        if let Err(e) = call_tx.send(ClientToWriteMessage::Start(StartRequestMessage {
            headers: headers,
            body: body,
            response_handler: req_tx,
        })) {
            return Box::new(stream::once(Err(HttpError::Other(format!("send request to client {:?}", e).into()))));
        }

        let req_rx = req_rx.map_err(|()| HttpError::from(io::Error::new(io::ErrorKind::Other, "req")));

        // TODO: future is no longer needed here
        tx.complete(stream_with_eof_and_error(req_rx, || HttpError::from(io::Error::new(io::ErrorKind::Other, "unexpected eof"))));

        let rx = rx.map_err(|_| HttpError::from(io::Error::new(io::ErrorKind::Other, "oneshot canceled")));

        Box::new(rx.flatten_stream())
    }

    /// For tests
    pub fn dump_state(&self) -> HttpFutureSend<ConnectionStateSnapshot> {
        let (tx, rx) = futures::oneshot();

        self.command_tx.clone().send(ClientCommandMessage::DumpState(tx))
            .expect("send request to dump state");

        let rx = rx.map_err(|_| HttpError::from(io::Error::new(io::ErrorKind::Other, "oneshot canceled")));

        Box::new(rx)
    }
}

impl ClientCommandLoop {
    fn process_dump_state(self, sender: futures::sync::oneshot::Sender<ConnectionStateSnapshot>) -> HttpFuture<Self> {
        // ignore send error, client might be already dead
        drop(sender.complete(self.inner.with(|inner| inner.common.dump_state())));
        Box::new(futures::finished(self))
    }

    fn process_message(self, message: ClientCommandMessage) -> HttpFuture<Self> {
        match message {
            ClientCommandMessage::DumpState(sender) => self.process_dump_state(sender),
        }
    }

    fn run(self, requests: HttpFutureStreamSend<ClientCommandMessage>) -> HttpFuture<()> {
        let requests = requests.map_err(HttpError::from);
        Box::new(requests
            .fold(self, move |l, message: ClientCommandMessage| {
                l.process_message(message)
            })
            .map(|_| ()))
    }
}
<|endoftext|>


<commit_before>use libimagrt::runtime::Runtime;

pub fn list(rt: &Runtime) {
    unimplemented!();
}
<commit_msg>Start implementing "list"<commit_after>use libimagrt::runtime::Runtime;

pub fn list(rt: &Runtime) {
    rt.cli()
        .subcommand_matches("list")
        .map(|scmd| {
            debug!("Found 'list' subcommand...");

        });
}
<|endoftext|>


<commit_before>use super::*;

#[get("/count/entries")]
pub fn get_count_entries(db: DbConn) -> Result<usize> {
    let entries = db.all_entries()?;
    Ok(Json(entries.len()))
}

#[get("/count/tags")]
pub fn get_count_tags(db: DbConn) -> Result<usize> {
    Ok(Json(db.all_tags()?.len()))
}
<commit_msg>Add TODO comments<commit_after>use super::*;

#[get("/count/entries")]
pub fn get_count_entries(db: DbConn) -> Result<usize> {
    // TODO: Replace with count query
    let entries = db.all_entries()?;
    Ok(Json(entries.len()))
}

#[get("/count/tags")]
pub fn get_count_tags(db: DbConn) -> Result<usize> {
    // TODO: Replace with count query
    Ok(Json(db.all_tags()?.len()))
}
<|endoftext|>


<commit_before>import std::time;
import result::{result, ok, err};
import libc::*;
<commit_msg>cleanup<commit_after><|endoftext|>


<commit_before>//! Beginning with MacOS 10.3, `utimensat` is supported by the MacOS, so here, we check if the symbol exists
//! and if not, we fallabck to `utimes`.
use crate::FileTime;
use libc::{c_char, c_int, timespec};
use std::ffi::CString;
use std::fs::File;
use std::os::unix::prelude::*;
use std::path::Path;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::atomic::{AtomicBool, AtomicUsize};
use std::{io, mem};

pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> {
    set_times(p, Some(atime), Some(mtime), false)
}

pub fn set_file_mtime(p: &Path, mtime: FileTime) -> io::Result<()> {
    set_times(p, None, Some(mtime), false)
}

pub fn set_file_atime(p: &Path, atime: FileTime) -> io::Result<()> {
    set_times(p, Some(atime), None, false)
}

pub fn set_file_handle_times(
    f: &File,
    atime: Option<FileTime>,
    mtime: Option<FileTime>,
) -> io::Result<()> {
    // Attempt to use the `futimens` syscall, but if it's not supported by the
    // current kernel then fall back to an older syscall.
    static INVALID: AtomicBool = AtomicBool::new(false);
    if !INVALID.load(SeqCst) {
        if let Some(func) = futimens() {
            let times = [super::to_timespec(&atime), super::to_timespec(&mtime)];
            let rc = unsafe { func(f.as_raw_fd(), times.as_ptr()) };
            if rc == 0 {
                return Ok(());
            } else {
                return Err(io::Error::last_os_error());
            }
        } else {
            INVALID.store(true, SeqCst);
        }
    }

    super::utimes::set_file_handle_times(f, atime, mtime)
}

pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> {
    set_times(p, Some(atime), Some(mtime), true)
}

fn set_times(
    p: &Path,
    atime: Option<FileTime>,
    mtime: Option<FileTime>,
    symlink: bool,
) -> io::Result<()> {
    // Attempt to use the `utimensat` syscall, but if it's not supported by the
    // current kernel then fall back to an older syscall.
    static INVALID: AtomicBool = AtomicBool::new(false);
    if !INVALID.load(SeqCst) {
        if let Some(func) = utimensat() {
            let flags = if symlink {
                libc::AT_SYMLINK_NOFOLLOW
            } else {
                0
            };

            let p = CString::new(p.as_os_str().as_bytes())?;
            let times = [super::to_timespec(&atime), super::to_timespec(&mtime)];
            let rc = unsafe { func(libc::AT_FDCWD, p.as_ptr(), times.as_ptr(), flags) };
            if rc == 0 {
                return Ok(());
            } else {
                return Err(io::Error::last_os_error());
            }
        } else {
            INVALID.store(true, SeqCst);
        }
    }

    super::utimes::set_times(p, atime, mtime, symlink)
}

fn utimensat() -> Option<unsafe extern "C" fn(c_int, *const c_char, *const timespec, c_int) -> c_int>
{
    static ADDR: AtomicUsize = AtomicUsize::new(0);
    unsafe {
        match ADDR.load(SeqCst) {
            0 => {}
            1 => return None,
            n => return Some(mem::transmute(n)),
        }
        let name = b"utimensat\0";
        let sym = libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _);
        let (val, ret) = if sym.is_null() {
            (1, None)
        } else {
            (sym as usize, Some(mem::transmute(sym)))
        };
        ADDR.store(val, SeqCst);
        return ret;
    }
}

fn futimens() -> Option<unsafe extern "C" fn(c_int, *const timespec) -> c_int> {
    static ADDR: AtomicUsize = AtomicUsize::new(0);
    unsafe {
        match ADDR.load(SeqCst) {
            0 => {}
            1 => return None,
            n => return Some(mem::transmute(n)),
        }
        let name = b"futimens\0";
        let sym = libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _);
        let (val, ret) = if sym.is_null() {
            (1, None)
        } else {
            (sym as usize, Some(mem::transmute(sym)))
        };
        ADDR.store(val, SeqCst);
        return ret;
    }
}
<commit_msg>Skip second `INVALID` static<commit_after>//! Beginning with MacOS 10.3, `utimensat` is supported by the MacOS, so here, we check if the symbol exists
//! and if not, we fallabck to `utimes`.
use crate::FileTime;
use libc::{c_char, c_int, timespec};
use std::ffi::CString;
use std::fs::File;
use std::os::unix::prelude::*;
use std::path::Path;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::atomic::AtomicUsize;
use std::{io, mem};

pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> {
    set_times(p, Some(atime), Some(mtime), false)
}

pub fn set_file_mtime(p: &Path, mtime: FileTime) -> io::Result<()> {
    set_times(p, None, Some(mtime), false)
}

pub fn set_file_atime(p: &Path, atime: FileTime) -> io::Result<()> {
    set_times(p, Some(atime), None, false)
}

pub fn set_file_handle_times(
    f: &File,
    atime: Option<FileTime>,
    mtime: Option<FileTime>,
) -> io::Result<()> {
    // Attempt to use the `futimens` syscall, but if it's not supported by the
    // current kernel then fall back to an older syscall.
    if let Some(func) = futimens() {
        let times = [super::to_timespec(&atime), super::to_timespec(&mtime)];
        let rc = unsafe { func(f.as_raw_fd(), times.as_ptr()) };
        if rc == 0 {
            return Ok(());
        } else {
            return Err(io::Error::last_os_error());
        }
    }

    super::utimes::set_file_handle_times(f, atime, mtime)
}

pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> {
    set_times(p, Some(atime), Some(mtime), true)
}

fn set_times(
    p: &Path,
    atime: Option<FileTime>,
    mtime: Option<FileTime>,
    symlink: bool,
) -> io::Result<()> {
    // Attempt to use the `utimensat` syscall, but if it's not supported by the
    // current kernel then fall back to an older syscall.
    if let Some(func) = utimensat() {
        let flags = if symlink {
            libc::AT_SYMLINK_NOFOLLOW
        } else {
            0
        };

        let p = CString::new(p.as_os_str().as_bytes())?;
        let times = [super::to_timespec(&atime), super::to_timespec(&mtime)];
        let rc = unsafe { func(libc::AT_FDCWD, p.as_ptr(), times.as_ptr(), flags) };
        if rc == 0 {
            return Ok(());
        } else {
            return Err(io::Error::last_os_error());
        }
    }

    super::utimes::set_times(p, atime, mtime, symlink)
}

fn utimensat() -> Option<unsafe extern "C" fn(c_int, *const c_char, *const timespec, c_int) -> c_int>
{
    static ADDR: AtomicUsize = AtomicUsize::new(0);
    unsafe {
        match ADDR.load(SeqCst) {
            0 => {}
            1 => return None,
            n => return Some(mem::transmute(n)),
        }
        let name = b"utimensat\0";
        let sym = libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _);
        let (val, ret) = if sym.is_null() {
            (1, None)
        } else {
            (sym as usize, Some(mem::transmute(sym)))
        };
        ADDR.store(val, SeqCst);
        return ret;
    }
}

fn futimens() -> Option<unsafe extern "C" fn(c_int, *const timespec) -> c_int> {
    static ADDR: AtomicUsize = AtomicUsize::new(0);
    unsafe {
        match ADDR.load(SeqCst) {
            0 => {}
            1 => return None,
            n => return Some(mem::transmute(n)),
        }
        let name = b"futimens\0";
        let sym = libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _);
        let (val, ret) = if sym.is_null() {
            (1, None)
        } else {
            (sym as usize, Some(mem::transmute(sym)))
        };
        ADDR.store(val, SeqCst);
        return ret;
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;

use crate::pod::{bytes_of, bytes_of_slice, Pod};

/// Trait for writable buffer.
#[allow(clippy::len_without_is_empty)]
pub trait WritableBuffer {
    /// Returns position/offset for data to be written at.
    fn len(&self) -> usize;

    /// Reserves specified number of bytes in the buffer.
    fn reserve(&mut self, additional: usize) -> Result<(), ()>;

    /// Writes zero bytes at the end of the buffer until the buffer
    /// has the specified length.
    fn resize(&mut self, new_len: usize);

    /// Writes the specified slice of bytes at the end of the buffer.
    fn write_bytes(&mut self, val: &[u8]);

    /// Writes the specified `Pod` type at the end of the buffer.
    fn write_pod<T: Pod>(&mut self, val: &T)
    where
        Self: Sized,
    {
        self.write_bytes(bytes_of(val))
    }

    /// Writes the specified `Pod` slice at the end of the buffer.
    fn write_pod_slice<T: Pod>(&mut self, val: &[T])
    where
        Self: Sized,
    {
        self.write_bytes(bytes_of_slice(val))
    }
}

impl<'a> dyn WritableBuffer + 'a {
    /// Writes the specified `Pod` type at the end of the buffer.
    pub fn write<T: Pod>(&mut self, val: &T) {
        self.write_bytes(bytes_of(val))
    }

    /// Writes the specified `Pod` slice at the end of the buffer.
    pub fn write_slice<T: Pod>(&mut self, val: &[T]) {
        self.write_bytes(bytes_of_slice(val))
    }
}

impl WritableBuffer for Vec<u8> {
    #[inline]
    fn len(&self) -> usize {
        self.len()
    }

    #[inline]
    fn reserve(&mut self, additional: usize) -> Result<(), ()> {
        self.reserve(additional);
        Ok(())
    }

    #[inline]
    fn resize(&mut self, new_len: usize) {
        debug_assert!(new_len >= self.len());
        self.resize(new_len, 0);
    }

    #[inline]
    fn write_bytes(&mut self, val: &[u8]) {
        self.extend_from_slice(val)
    }
}

/// A trait for mutable byte slices.
///
/// It provides convenience methods for `Pod` types.
pub(crate) trait BytesMut {
    fn write_at<T: Pod>(self, offset: usize, val: &T) -> Result<(), ()>;
}

impl<'a> BytesMut for &'a mut [u8] {
    #[inline]
    fn write_at<T: Pod>(self, offset: usize, val: &T) -> Result<(), ()> {
        let src = bytes_of(val);
        let dest = self.get_mut(offset..).ok_or(())?;
        let dest = dest.get_mut(..src.len()).ok_or(())?;
        dest.copy_from_slice(src);
        Ok(())
    }
}

pub(crate) fn align(offset: usize, size: usize) -> usize {
    (offset + (size - 1)) & !(size - 1)
}

#[allow(dead_code)]
pub(crate) fn align_u64(offset: u64, size: u64) -> u64 {
    (offset + (size - 1)) & !(size - 1)
}

pub(crate) fn write_align(buffer: &mut dyn WritableBuffer, size: usize) {
    let new_len = align(buffer.len(), size);
    buffer.resize(new_len);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn bytes_mut() {
        let data = vec![0x01, 0x23, 0x45, 0x67];

        let mut bytes = data.clone();
        bytes.extend_from_slice(bytes_of(&u16::to_be(0x89ab)));
        assert_eq!(bytes, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab]);

        let mut bytes = data.clone();
        assert_eq!(bytes.write_at(0, &u16::to_be(0x89ab)), Ok(()));
        assert_eq!(bytes, [0x89, 0xab, 0x45, 0x67]);

        let mut bytes = data.clone();
        assert_eq!(bytes.write_at(2, &u16::to_be(0x89ab)), Ok(()));
        assert_eq!(bytes, [0x01, 0x23, 0x89, 0xab]);

        assert_eq!(bytes.write_at(3, &u16::to_be(0x89ab)), Err(()));
        assert_eq!(bytes.write_at(4, &u16::to_be(0x89ab)), Err(()));
        assert_eq!(vec![].write_at(0, &u32::to_be(0x89ab)), Err(()));
    }
}
<commit_msg>Better document api contract for WritableBuffer<commit_after>use std::vec::Vec;

use crate::pod::{bytes_of, bytes_of_slice, Pod};

/// Trait for writable buffer.
#[allow(clippy::len_without_is_empty)]
pub trait WritableBuffer {
    /// Returns position/offset for data to be written at.
    ///
    /// Should only be used in debug assertions
    fn len(&self) -> usize;

    /// Reserves specified number of bytes in the buffer.
    ///
    /// This will be called exactly once before writing anything to the buffer,
    /// and the given size is the exact total number of bytes that will be written.
    fn reserve(&mut self, size: usize) -> Result<(), ()>;

    /// Writes zero bytes at the end of the buffer until the buffer
    /// has the specified length.
    fn resize(&mut self, new_len: usize);

    /// Writes the specified slice of bytes at the end of the buffer.
    fn write_bytes(&mut self, val: &[u8]);

    /// Writes the specified `Pod` type at the end of the buffer.
    fn write_pod<T: Pod>(&mut self, val: &T)
    where
        Self: Sized,
    {
        self.write_bytes(bytes_of(val))
    }

    /// Writes the specified `Pod` slice at the end of the buffer.
    fn write_pod_slice<T: Pod>(&mut self, val: &[T])
    where
        Self: Sized,
    {
        self.write_bytes(bytes_of_slice(val))
    }
}

impl<'a> dyn WritableBuffer + 'a {
    /// Writes the specified `Pod` type at the end of the buffer.
    pub fn write<T: Pod>(&mut self, val: &T) {
        self.write_bytes(bytes_of(val))
    }

    /// Writes the specified `Pod` slice at the end of the buffer.
    pub fn write_slice<T: Pod>(&mut self, val: &[T]) {
        self.write_bytes(bytes_of_slice(val))
    }
}

impl WritableBuffer for Vec<u8> {
    #[inline]
    fn len(&self) -> usize {
        self.len()
    }

    #[inline]
    fn reserve(&mut self, size: usize) -> Result<(), ()> {
        debug_assert!(self.is_empty());
        self.reserve(size);
        Ok(())
    }

    #[inline]
    fn resize(&mut self, new_len: usize) {
        debug_assert!(new_len >= self.len());
        self.resize(new_len, 0);
    }

    #[inline]
    fn write_bytes(&mut self, val: &[u8]) {
        debug_assert!(self.len() + val.len() <= self.capacity());
        self.extend_from_slice(val)
    }
}

/// A trait for mutable byte slices.
///
/// It provides convenience methods for `Pod` types.
pub(crate) trait BytesMut {
    fn write_at<T: Pod>(self, offset: usize, val: &T) -> Result<(), ()>;
}

impl<'a> BytesMut for &'a mut [u8] {
    #[inline]
    fn write_at<T: Pod>(self, offset: usize, val: &T) -> Result<(), ()> {
        let src = bytes_of(val);
        let dest = self.get_mut(offset..).ok_or(())?;
        let dest = dest.get_mut(..src.len()).ok_or(())?;
        dest.copy_from_slice(src);
        Ok(())
    }
}

pub(crate) fn align(offset: usize, size: usize) -> usize {
    (offset + (size - 1)) & !(size - 1)
}

#[allow(dead_code)]
pub(crate) fn align_u64(offset: u64, size: u64) -> u64 {
    (offset + (size - 1)) & !(size - 1)
}

pub(crate) fn write_align(buffer: &mut dyn WritableBuffer, size: usize) {
    let new_len = align(buffer.len(), size);
    buffer.resize(new_len);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn bytes_mut() {
        let data = vec![0x01, 0x23, 0x45, 0x67];

        let mut bytes = data.clone();
        bytes.extend_from_slice(bytes_of(&u16::to_be(0x89ab)));
        assert_eq!(bytes, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab]);

        let mut bytes = data.clone();
        assert_eq!(bytes.write_at(0, &u16::to_be(0x89ab)), Ok(()));
        assert_eq!(bytes, [0x89, 0xab, 0x45, 0x67]);

        let mut bytes = data.clone();
        assert_eq!(bytes.write_at(2, &u16::to_be(0x89ab)), Ok(()));
        assert_eq!(bytes, [0x01, 0x23, 0x89, 0xab]);

        assert_eq!(bytes.write_at(3, &u16::to_be(0x89ab)), Err(()));
        assert_eq!(bytes.write_at(4, &u16::to_be(0x89ab)), Err(()));
        assert_eq!(vec![].write_at(0, &u32::to_be(0x89ab)), Err(()));
    }
}
<|endoftext|>


<commit_before>use ast::*;
use name::*;
use security_attributes::*;

named!(pub expr<&[u8], Expr>,
  alt_complete!(
    context
    | level_range
    | category_range
    | logical_or_expr
  )
);

macro_rules! binexp {
  ($name:ident, $next: ident, $op:path, $tag:expr) => {
    named!(pub $name<&[u8], Expr>,
      ws!(do_parse!(
        a: $next >>
        n: alt!(
          ws!(do_parse!(
            tag!($tag) >>
            b: $name >>
            (Expr::Binary(Box::new(a.clone()), $op, Box::new(b)))
          )) |
          value!(a)
        ) >>
        (n)
      ))
    );
  }
}

binexp!(
    logical_or_expr,
    logical_xor_expr,
    BinaryOp::ConditionalOr,
    "||"
);

binexp!(
    logical_xor_expr,
    logical_and_expr,
    BinaryOp::ConditionalXor,
    "^^"
);

binexp!(
    logical_and_expr,
    logical_not_expr,
    BinaryOp::ConditionalAnd,
    "&&"
);

named!(logical_not_expr<&[u8], Expr>,
    ws!(
        alt!(
            do_parse!(
                tag!("!") >>
                expr: expr >>

                (Expr::Unary(UnaryOp::ConditionalNot, Box::new(expr)))
            ) |
            primary_expr
        )
    )
);

named!(primary_expr<&[u8], Expr>, alt!(variable));<commit_msg>Add tests for logical expression parsing<commit_after>use ast::*;
use name::*;
use security_attributes::*;

named!(pub expr<&[u8], Expr>,
  alt_complete!(
    context
    | level_range
    | category_range
    | logical_or_expr
  )
);

macro_rules! binexp {
  ($name:ident, $next: ident, $op:path, $tag:expr) => {
    named!(pub $name<&[u8], Expr>,
      ws!(do_parse!(
        a: $next >>
        n: alt_complete!(
          ws!(do_parse!(
            tag!($tag) >>
            b: $name >>
            (Expr::Binary(Box::new(a.clone()), $op, Box::new(b)))
          )) |
          value!(a)
        ) >>
        (n)
      ))
    );
  }
}

binexp!(
    logical_or_expr,
    logical_xor_expr,
    BinaryOp::ConditionalOr,
    "||"
);

binexp!(
    logical_xor_expr,
    logical_and_expr,
    BinaryOp::ConditionalXor,
    "^^"
);

binexp!(
    logical_and_expr,
    logical_not_expr,
    BinaryOp::ConditionalAnd,
    "&&"
);

named!(logical_not_expr<&[u8], Expr>,
    ws!(
        alt!(
            do_parse!(
                tag!("!") >>
                expr: primary_expr >>

                (Expr::Unary(UnaryOp::ConditionalNot, Box::new(expr)))
            ) |
            primary_expr
        )
    )
);

named!(primary_expr<&[u8], Expr>, alt!(variable));

#[cfg(test)]
mod tests {

    use super::*;
    use testing::parse;

    #[test]
    pub fn parse_unary_with_binary_expr() {
        let expected = Expr::Binary(
            Box::from(Expr::Unary(
                UnaryOp::ConditionalNot,
                Box::from(Expr::var("a")),
            )),
            BinaryOp::ConditionalOr,
            Box::from(Expr::var("b")),
        );

        let result = parse::<Expr, _>("!a || b", expr);
        assert_eq!(expected, result);
    }

    #[test]
    pub fn parse_logical_not_expr() {
        let expected = Expr::Unary(UnaryOp::ConditionalNot, Box::from(Expr::var("a")));
        let result = parse::<Expr, _>("!a", expr);

        assert_eq!(expected, result);
    }

    #[test]
    pub fn parse_logical_xor_expr() {
        let expected = Expr::Binary(
            Box::from(Expr::var("a")),
            BinaryOp::ConditionalXor,
            Box::from(Expr::var("b")),
        );

        let result = parse::<Expr, _>("a ^^ b", expr);
        assert_eq!(expected, result);
    }

    #[test]
    pub fn parse_logical_or_expr() {
        let expected = Expr::Binary(
            Box::from(Expr::var("a")),
            BinaryOp::ConditionalOr,
            Box::from(Expr::var("b")),
        );

        let result = parse::<Expr, _>("a || b", expr);
        assert_eq!(expected, result);
    }

    #[test]
    pub fn parse_logical_and_expr() {
        let expected = Expr::Binary(
            Box::from(Expr::var("a")),
            BinaryOp::ConditionalAnd,
            Box::from(Expr::var("b")),
        );

        let result = parse::<Expr, _>("a && b", expr);
        assert_eq!(expected, result);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate dialoguer;
extern crate duct;
#[macro_use]
extern crate error_chain;
extern crate serde;
extern crate serde_json;
extern crate snapshot;
extern crate walkdir;

use std::ffi::OsStr;
use std::fs::File;
use std::io::BufReader;

use clap::{Arg, SubCommand};
use dialoguer::{Checkboxes, Select};
use duct::cmd;
use snapshot::SnapFileContents;
use walkdir::WalkDir;

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

    foreign_links {
        Io(::std::io::Error);
    }
}

quick_main!(run);

fn run() -> SnapResult<()> {
    let input = app_from_crate!()
        .subcommand(
            SubCommand::with_name("update")
                .about("Update snapshots.")
                .arg(Arg::with_name("all").short("a").long("all").help(
                    "Unconditionally update all snapshots, including unrecorded ones.",
                )),
        )
        .get_matches();

    if let Some(update_matches) = input.subcommand_matches("update") {
        if update_matches.is_present("all") {
            let output = cmd("cargo", &["test"])
                .env("UPDATE_SNAPSHOTS", "1")
                .stdout_capture()
                .stderr_capture()
                .run()
                .chain_err(|| "unable to execute cargo")?;

            if !output.status.success() {
                // TODO(dikaiosune) print what failed
                bail!("unable to update all snapshots!");
            }
        } else {
            interactive_process()?;
        }
        println!("\nAll updates processed!");
    } else {
        panic!("unsupported command");
    }

    Ok(())
}

fn interactive_process() -> SnapResult<()> {
    let test_function_names = find_existing_snapshot_test_names()?;
    let mut failed_tests = Vec::new();

    println!("Checking for out of date snapshot tests...");
    for test_fn in test_function_names {
        let first_run = cmd("cargo", &["test", &test_fn.0])
            .stdout_capture()
            .stderr_capture()
            .run()
            .chain_err(|| "unable to execute cargo")?;

        if !first_run.status.success() {
            failed_tests.push(test_fn);
        }
    }

    if failed_tests.is_empty() {
        println!("\nNo snapshot tests require an update!");
        ::std::process::exit(0);
    } else {
        println!("\nPlease select which snapshot tests should be updated:");
        println!("  <Space> to select, <Enter> to submit\n");

        let mut menu = Checkboxes::new();
        for failed in &failed_tests {
            menu.item(&failed.0);
        }
        let all_to_update = menu.interact().expect("error accepting user selections");

        for fn_idx in all_to_update {
            let fn_to_update = &failed_tests[fn_idx];
            println!("Updating {}...", &fn_to_update.0);

            let mut run_test = true;
            while run_test {
                let run_output = cmd("cargo", &["test", &fn_to_update.0])
                    .env("UPDATE_SNAPSHOTS", "1")
                    .stdout_capture()
                    .stderr_capture()
                    .run()
                    .chain_err(|| "unable to execute cargo")?;

                if run_output.status.success() {
                    run_test = false;
                } else {
                    println!("\nUpdating {} failed! What would you like to do?",
                             &fn_to_update.0);

                    match capture_failure_selection()? {
                        TestFailureSelection::Retry => continue,
                        TestFailureSelection::Skip => break,
                        TestFailureSelection::Abort => {
                            println!("\nExiting...");
                            ::std::process::exit(1);
                        }
                    }
                }
            }
        }

        Ok(())
    }
}

struct FnName(String);

fn find_existing_snapshot_test_names() -> SnapResult<Vec<FnName>> {
    let cwd = ::std::env::current_dir()
        .chain_err(|| "unable to read cwd")?;

    let mut existing: Vec<SnapFileContents> = Vec::new();

    let snap_extension = OsStr::new("snap");
    for walk_result in WalkDir::new(cwd) {
        let entry = walk_result
            .chain_err(|| "unable to traverse project directory")?;

        if entry.path().extension() == Some(snap_extension) {
            let rdr = BufReader::new(File::open(entry.path())
                                         .chain_err(|| "unable to open snapshot file")?);
            let contents = serde_json::from_reader(rdr)
                .chain_err(|| "unable to parse snapshot file")?;
            existing.push(contents);
        }
    }

    let mut test_function_names = Vec::new();
    for snap_file in existing {
        for fun in snap_file.keys() {
            // now we need to strip crate name from the string
            let mut test_fn_chunks = fun.splitn(2, "::");

            match test_fn_chunks.next() {
                Some(_) => (),
                None => bail!("malformed test fn name: empty"),
            }

            let real_test_fn = match test_fn_chunks.next() {
                Some(n) => n,
                None => bail!("malformed test fn name: only had crate name"),
            };

            test_function_names.push(FnName(real_test_fn.to_owned()));
        }
    }
    Ok(test_function_names)
}

enum TestFailureSelection {
    Retry,
    Skip,
    Abort,
}

fn capture_failure_selection() -> SnapResult<TestFailureSelection> {
    let options = ["Retry", "Skip", "Abort"];

    let selection = Select::new()
        .items(&options)
        .interact()
        .chain_err(|| "unable to retrieve user input")?;

    if options[selection] == "Retry" {
        Ok(TestFailureSelection::Retry)
    } else if options[selection] == "Skip" {
        Ok(TestFailureSelection::Skip)
    } else if options[selection] == "Abort" {
        Ok(TestFailureSelection::Abort)
    } else {
        bail!("invalid menu selection")
    }
}
<commit_msg>The test function should be able to describe its state.<commit_after>#[macro_use]
extern crate clap;
extern crate dialoguer;
extern crate duct;
#[macro_use]
extern crate error_chain;
extern crate serde;
extern crate serde_json;
extern crate snapshot;
extern crate walkdir;

use std::ffi::OsStr;
use std::fs::File;
use std::io::BufReader;

use clap::{Arg, SubCommand};
use dialoguer::{Checkboxes, Select};
use duct::cmd;
use snapshot::SnapFileContents;
use walkdir::WalkDir;

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

    foreign_links {
        Io(::std::io::Error);
    }
}

quick_main!(run);

fn run() -> SnapResult<()> {
    let input = app_from_crate!()
        .subcommand(
            SubCommand::with_name("update")
                .about("Update snapshots.")
                .arg(Arg::with_name("all").short("a").long("all").help(
                    "Unconditionally update all snapshots, including unrecorded ones.",
                )),
        )
        .get_matches();

    if let Some(update_matches) = input.subcommand_matches("update") {
        if update_matches.is_present("all") {
            let output = cmd("cargo", &["test"])
                .env("UPDATE_SNAPSHOTS", "1")
                .stdout_capture()
                .stderr_capture()
                .run()
                .chain_err(|| "unable to execute cargo")?;

            if !output.status.success() {
                // TODO(dikaiosune) print what failed
                bail!("unable to update all snapshots!");
            }
        } else {
            interactive_process()?;
        }
        println!("\nAll updates processed!");
    } else {
        panic!("unsupported command");
    }

    Ok(())
}

fn interactive_process() -> SnapResult<()> {
    let test_function_names = find_existing_snapshot_test_names()?;
    let mut failed_tests = Vec::new();

    println!("Checking for out of date snapshot tests...");
    for test_fn in &test_function_names {
        if !test_fn.success()? {
            failed_tests.push(test_fn);
        }
    }

    if failed_tests.is_empty() {
        println!("\nNo snapshot tests require an update!");
        ::std::process::exit(0);
    } else {
        println!("\nPlease select which snapshot tests should be updated:");
        println!("  <Space> to select, <Enter> to submit\n");

        let mut menu = Checkboxes::new();
        for failed in &failed_tests {
            menu.item(&failed.0);
        }
        let all_to_update = menu.interact().expect("error accepting user selections");

        for fn_idx in all_to_update {
            let fn_to_update = &failed_tests[fn_idx];
            println!("Updating {}...", &fn_to_update.0);

            let mut run_test = true;
            while run_test {
                let run_output = cmd("cargo", &["test", &fn_to_update.0])
                    .env("UPDATE_SNAPSHOTS", "1")
                    .stdout_capture()
                    .stderr_capture()
                    .run()
                    .chain_err(|| "unable to execute cargo")?;

                if run_output.status.success() {
                    run_test = false;
                } else {
                    println!("\nUpdating {} failed! What would you like to do?",
                             &fn_to_update.0);

                    match capture_failure_selection()? {
                        TestFailureSelection::Retry => continue,
                        TestFailureSelection::Skip => break,
                        TestFailureSelection::Abort => {
                            println!("\nExiting...");
                            ::std::process::exit(1);
                        }
                    }
                }
            }
        }

        Ok(())
    }
}

struct FnName(String);

impl FnName {
    fn success(&self) -> SnapResult<bool> {
        Ok(cmd("cargo", &["test", &self.0])
               .stdout_capture()
               .stderr_capture()
               .run()
               .chain_err(|| "unable to execute cargo")?
               .status
               .success())
    }
}

fn find_existing_snapshot_test_names() -> SnapResult<Vec<FnName>> {
    let cwd = ::std::env::current_dir()
        .chain_err(|| "unable to read cwd")?;

    let mut existing: Vec<SnapFileContents> = Vec::new();

    let snap_extension = OsStr::new("snap");
    for walk_result in WalkDir::new(cwd) {
        let entry = walk_result
            .chain_err(|| "unable to traverse project directory")?;

        if entry.path().extension() == Some(snap_extension) {
            let rdr = BufReader::new(File::open(entry.path())
                                         .chain_err(|| "unable to open snapshot file")?);
            let contents = serde_json::from_reader(rdr)
                .chain_err(|| "unable to parse snapshot file")?;
            existing.push(contents);
        }
    }

    let mut test_function_names = Vec::new();
    for snap_file in existing {
        for fun in snap_file.keys() {
            // now we need to strip crate name from the string
            let mut test_fn_chunks = fun.splitn(2, "::");

            match test_fn_chunks.next() {
                Some(_) => (),
                None => bail!("malformed test fn name: empty"),
            }

            let real_test_fn = match test_fn_chunks.next() {
                Some(n) => n,
                None => bail!("malformed test fn name: only had crate name"),
            };

            test_function_names.push(FnName(real_test_fn.to_owned()));
        }
    }
    Ok(test_function_names)
}

enum TestFailureSelection {
    Retry,
    Skip,
    Abort,
}

fn capture_failure_selection() -> SnapResult<TestFailureSelection> {
    let options = ["Retry", "Skip", "Abort"];

    let selection = Select::new()
        .items(&options)
        .interact()
        .chain_err(|| "unable to retrieve user input")?;

    if options[selection] == "Retry" {
        Ok(TestFailureSelection::Retry)
    } else if options[selection] == "Skip" {
        Ok(TestFailureSelection::Skip)
    } else if options[selection] == "Abort" {
        Ok(TestFailureSelection::Abort)
    } else {
        bail!("invalid menu selection")
    }
}
<|endoftext|>


<commit_before>/// Extended C Types range 4000 and above. Range of -100 thru 200 is reserved by Driver Manager.
/// `SQL_C_TYPES_EXTENDED`.
pub const C_TYPES_EXTENDED: i16 = 0x04000;

/// The C data type is specified in the SQLBindCol and SQLGetData functions with the TargetType
/// argument and in the SQLBindParameter function with the ValueType argument.
#[repr(i16)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CDataType {
    UTinyInty = -28,
    UBigInt = -27,
    STinyInt = -26,
    SBigInt = -25,

    ULong = -18,
    UShort = -17,
    SLong = -16,
    SShort = -15,

    #[cfg(feature = "odbc_version_3_50")]
    Guid = -11,

    WChar = -8,

    Bit = -7,
    // deprecated
    // SQL_C_TINYINT = -6,
    Binary = -2,
    /// `SQLCHAR` - CHAR, VARCHAR, DECIMAL, NUMERIC
    Char = 1,
    Numeric = 2,

    // deprecated
    // SQL_C_LONG = 4,
    // SQL_C_SHORT = 5,
    Float = 7,
    Double = 8,

    // Used in Odbc2.x Odbc3.x uses TypeDate instead.
    Date = 9,
    // Used in Odbc2.x Odbc3.x uses TypeTime instead.
    Time = 10,
    // Used in Odbc2.x Odbc3.x uses TypeTimeTimestamp instead.
    TimeStamp = 11,

    /// SQL_TYPE_DATE
    TypeDate = 91,
    /// SQL_TYPE_TIME
    TypeTime = 92,
    /// SQL_TYPE_TIMESTAMP
    TypeTimestamp = 93,
    #[cfg(feature = "odbc_version_4")]
    TypeTimeWithTimezone = 94,
    #[cfg(feature = "odbc_version_4")]
    TypeTimestampWithTimzone = 95,

    Default = 99,

    IntervalYear = 101,
    IntervalMonth = 102,
    IntervalDay = 103,
    IntervalHour = 104,
    IntervalMinute = 105,
    IntervalSecond = 106,
    IntervalYearToMonth = 107,
    IntervalDayToHour = 108,
    IntervalDayToMinute = 109,
    IntervalDayToSecond = 110,
    IntervalHourToMinute = 111,
    IntervalHourToSecond = 112,
    IntervalMinuteToSecond = 113,

    SsTime2 = C_TYPES_EXTENDED + 0,
    SsTimestampOffset = C_TYPES_EXTENDED + 1,
}

#[cfg(windows)]
pub use CDataType::ULong as UBigInt;
#[cfg(not(windows))]
pub use CDataType::ULong as Bookmark;
<commit_msg>add Ard and Apd to CDataType<commit_after>/// Extended C Types range 4000 and above. Range of -100 thru 200 is reserved by Driver Manager.
/// `SQL_C_TYPES_EXTENDED`.
pub const C_TYPES_EXTENDED: i16 = 0x04000;

/// The C data type is specified in the SQLBindCol and SQLGetData functions with the TargetType
/// argument and in the SQLBindParameter function with the ValueType argument.
#[repr(i16)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CDataType {

    /// SQL_ARD_TYPE
    Ard = -99,

    /// SQL_APD_TYPE
    Apd = -100,

    UTinyInty = -28,
    UBigInt = -27,
    STinyInt = -26,
    SBigInt = -25,

    ULong = -18,
    UShort = -17,
    SLong = -16,
    SShort = -15,

    #[cfg(feature = "odbc_version_3_50")]
    Guid = -11,

    WChar = -8,

    Bit = -7,
    // deprecated
    // SQL_C_TINYINT = -6,
    Binary = -2,
    /// `SQLCHAR` - CHAR, VARCHAR, DECIMAL, NUMERIC
    Char = 1,
    Numeric = 2,

    // deprecated
    // SQL_C_LONG = 4,
    // SQL_C_SHORT = 5,
    Float = 7,
    Double = 8,

    // Used in Odbc2.x Odbc3.x uses TypeDate instead.
    Date = 9,
    // Used in Odbc2.x Odbc3.x uses TypeTime instead.
    Time = 10,
    // Used in Odbc2.x Odbc3.x uses TypeTimeTimestamp instead.
    TimeStamp = 11,

    /// SQL_TYPE_DATE
    TypeDate = 91,
    /// SQL_TYPE_TIME
    TypeTime = 92,
    /// SQL_TYPE_TIMESTAMP
    TypeTimestamp = 93,
    #[cfg(feature = "odbc_version_4")]
    TypeTimeWithTimezone = 94,
    #[cfg(feature = "odbc_version_4")]
    TypeTimestampWithTimzone = 95,

    Default = 99,

    IntervalYear = 101,
    IntervalMonth = 102,
    IntervalDay = 103,
    IntervalHour = 104,
    IntervalMinute = 105,
    IntervalSecond = 106,
    IntervalYearToMonth = 107,
    IntervalDayToHour = 108,
    IntervalDayToMinute = 109,
    IntervalDayToSecond = 110,
    IntervalHourToMinute = 111,
    IntervalHourToSecond = 112,
    IntervalMinuteToSecond = 113,

    SsTime2 = C_TYPES_EXTENDED + 0,
    SsTimestampOffset = C_TYPES_EXTENDED + 1,
}

#[cfg(windows)]
pub use CDataType::ULong as UBigInt;
#[cfg(not(windows))]
pub use CDataType::ULong as Bookmark;
<|endoftext|>


<commit_before>use platform::vga::Color;
use kernel::stdio::StdioWriter;
use core::fmt::Write;
use core::panic::PanicInfo;

#[no_mangle]
pub fn entry() -> !
{
    ::platform::cpu::setup();
    ::platform::mmu::setup();
    ::platform::cpu::enable_interrupts();
    main();
    loop { ::platform::cpu::idle(); }
}

fn main()
{
    let mut printer = StdioWriter::new();
    printer.bg = Color::Red;
    printer.fg = Color::Yellow;
    printer.clear_screen();
    printer.fg = Color::White;
    printer.go_to(3, 3);
    printer.print_screen("Hello, World!");
}

#[panic_implementation]
#[no_mangle]
pub fn panic(info: &PanicInfo) -> !
{
    let mut printer = StdioWriter::new();
    printer.bg = Color::Black;
    printer.fg = Color::Red;

    printer.print_screen("RUST FAIL");
    printer.crlf();

    match info.message() {
        Some(args) => { let _ = printer.write_fmt(*args); },
        None => { printer.print_screen("<No message provided>"); },
    };

    match info.location() {
        Some(location) => {
            printer.crlf();
            printer.print_screen(location.file());
            printer.print_char(':');
            printer.print_dec(location.line());
            printer.print_char(':');
            printer.print_dec(location.column());
        },
        None => {},
    }

    ::platform::cpu::halt();
}
<commit_msg>Rename panic_implementation to panic_handler<commit_after>use platform::vga::Color;
use kernel::stdio::StdioWriter;
use core::fmt::Write;
use core::panic::PanicInfo;

#[no_mangle]
pub fn entry() -> !
{
    ::platform::cpu::setup();
    ::platform::mmu::setup();
    ::platform::cpu::enable_interrupts();
    main();
    loop { ::platform::cpu::idle(); }
}

fn main()
{
    let mut printer = StdioWriter::new();
    printer.bg = Color::Red;
    printer.fg = Color::Yellow;
    printer.clear_screen();
    printer.fg = Color::White;
    printer.go_to(3, 3);
    printer.print_screen("Hello, World!");
}

#[panic_handler]
#[no_mangle]
pub fn panic(info: &PanicInfo) -> !
{
    let mut printer = StdioWriter::new();
    printer.bg = Color::Black;
    printer.fg = Color::Red;

    printer.print_screen("RUST FAIL");
    printer.crlf();

    match info.message() {
        Some(args) => { let _ = printer.write_fmt(*args); },
        None => { printer.print_screen("<No message provided>"); },
    };

    match info.location() {
        Some(location) => {
            printer.crlf();
            printer.print_screen(location.file());
            printer.print_char(':');
            printer.print_dec(location.line());
            printer.print_char(':');
            printer.print_dec(location.column());
        },
        None => {},
    }

    ::platform::cpu::halt();
}
<|endoftext|>


<commit_before>type iterable<A> = fn@(fn(A));

fn iterate<A>(coll: iterable<A>, blk: fn(A)) {
    coll(blk);
}

fn enumerate<A>(self: iterable<A>, blk: fn(uint, A)) {
    let i = 0u;
    iterate(self) {|a|
        blk(i, a);
        i += 1u;
    }
}

// Here: we have to use fn@ for predicates and map functions, because
// we will be binding them up into a closure.  Disappointing.  A true
// region type system might be able to do better than this.

fn filter<A>(self: iterable<A>, prd: fn@(A) -> bool, blk: fn(A)) {
    iterate(self) {|a|
        if prd(a) { blk(a) }
    }
}

fn map<A,B>(self: iterable<A>, cnv: fn@(A) -> B, blk: fn(B)) {
    iterate(self) {|a|
        let b = cnv(a);
        blk(b);
    }
}

fn filter_map<A,B>(self: iterable<A>, cnv: fn@(A) -> option<B>, blk: fn(B)) {
    iterate(self) {|a|
        alt cnv(a) {
          some(b) { blk(b) }
          none { /* no action */ }
        }
    }
}

fn foldl<A,B:copy>(self: iterable<A>, b0: B, blk: fn@(B, A) -> B) -> B {
    let b = b0;
    iterate(self) {|a|
        b = blk(b, a);
    }
    ret b;
}

fn to_list<A:copy>(self: iterable<A>) -> [A] {
    foldl(self, [], {|r, a| r + [a]})
}

#[test]
fn test_enumerate() {
    enumerate(bind vec::iter([0u, 1u, 2u], _)) {|i,j|
        assert i == j;
    }
}

#[test]
fn test_to_list() {
    let a = bind vec::iter([0, 1, 2], _);
    let b = bind map(a, {|i| i*2}, _);
    let c = to_list(b);
    assert c == [0, 2, 4];
}<commit_msg>convert over to using iface and impl, at least partly.<commit_after>iface iterable<A> {
    fn iter(blk: fn(A));
}

impl<A> of iterable<A> for fn@(fn(A)) {
    fn iter(blk: fn(A)) {
        self(blk);
    }
}

impl<A> of iterable<A> for [A] {
    fn iter(blk: fn(A)) {
        vec::iter(self, blk)
    }
}

impl<A> of iterable<A> for option<A> {
    fn iter(blk: fn(A)) {
        option::may(self, blk)
    }
}

fn enumerate<A,IA:iterable<A>>(self: IA, blk: fn(uint, A)) {
    let i = 0u;
    self.iter {|a|
        blk(i, a);
        i += 1u;
    }
}

// Here: we have to use fn@ for predicates and map functions, because
// we will be binding them up into a closure.  Disappointing.  A true
// region type system might be able to do better than this.

fn filter<A,IA:iterable<A>>(self: IA, prd: fn@(A) -> bool, blk: fn(A)) {
    self.iter {|a|
        if prd(a) { blk(a) }
    }
}

fn map<A,B,IA:iterable<A>>(self: IA, cnv: fn@(A) -> B, blk: fn(B)) {
    self.iter {|a|
        let b = cnv(a);
        blk(b);
    }
}

fn flat_map<A,B,IA:iterable<A>,IB:iterable<B>>(
    self: IA, cnv: fn@(A) -> IB, blk: fn(B)) {
    self.iter {|a|
        cnv(a).iter(blk)
    }
}

fn foldl<A,B:copy,IA:iterable<A>>(self: IA, b0: B, blk: fn(B, A) -> B) -> B {
    let b = b0;
    self.iter {|a|
        b = blk(b, a);
    }
    ret b;
}

fn to_list<A:copy,IA:iterable<A>>(self: IA) -> [A] {
    foldl::<A,[A],IA>(self, [], {|r, a| r + [a]})
}

#[test]
fn test_enumerate() {
    enumerate(bind vec::iter([0u, 1u, 2u], _)) {|i,j|
        assert i == j;
    }
}

#[test]
fn test_map_and_to_list() {
    let a = bind vec::iter([0, 1, 2], _);
    let b = bind map(a, {|i| i*2}, _);
    let c = to_list(b);
    assert c == [0, 2, 4];
}

#[test]
fn test_flat_map_with_option() {
    fn if_even(&&i: int) -> option<int> {
        if (i % 2) == 0 { some(i) }
        else { none }
    }

    let a = bind vec::iter([0, 1, 2], _);
    let b = bind flat_map(a, if_even, _);
    let c = to_list(b);
    assert c == [0, 2];
}

#[test]
fn test_flat_map_with_list() {
    fn repeat(&&i: int) -> [int] {
        let r = [];
        int::range(0, i) {|_j| r += [i]; }
        r
    }

    let a = bind vec::iter([0, 1, 2, 3], _);
    let b = bind flat_map(a, repeat, _);
    let c = to_list(b);
    #debug["c = %?", c];
    assert c == [1, 2, 2, 3, 3, 3];
}<|endoftext|>


<commit_before>use std::convert::From;

use binding::class::{define_class, new_instance, define_method, define_singleton_method};
use binding::global::rb_cObject;
use binding::util::get_constant;
use types::{Callback, Value};
use util::create_arguments;

use super::any_object::AnyObject;
use super::traits::Object;

pub struct Class {
    value: Value
}

impl Class {
    // TODO: replace rb_cObject with optional superclass
    pub fn new(name: &str) -> Self {
        Class {
            value: define_class(name, rb_cObject)
        }
    }

    // TODO: replace rb_cObject with optional class/module value
    pub fn from_existing(name: &str) -> Self {
        Class {
            value: get_constant(name, rb_cObject)
        }
    }

    pub fn new_instance(&self, arguments: Vec<AnyObject>) -> AnyObject {
        let (argc, argv) = create_arguments(arguments);
        let instance = new_instance(self.value(), argc, argv);

        AnyObject::from(instance)
    }

    pub fn define<F: Fn(&Self)>(&self, f: F) -> &Self {
        f(&self);

        self
    }

    pub fn define_method<T: Object>(&self, name: &str, callback: Callback<T>) {
        define_method::<T>(self.value, name, callback);
    }

    pub fn define_singleton_method<T: Object>(&self, name: &str, callback: Callback<T>) {
        define_singleton_method(self.value, name, callback);
    }

    pub fn def<T: Object>(&self, name: &str, callback: Callback<T>) {
        self.define_method(name, callback);
    }

    pub fn def_self<T: Object>(&self, name: &str, callback: Callback<T>) {
        self.define_singleton_method(name, callback);
    }
}

impl From<Value> for Class {
    fn from(value: Value) -> Self {
        Class {
            value: value
        }
    }
}

impl Object for Class {
    fn value(&self) -> Value {
        self.value
    }
}
<commit_msg>Update Class functions to use mutable self<commit_after>use std::convert::From;

use binding::class::{define_class, new_instance, define_method, define_singleton_method};
use binding::global::rb_cObject;
use binding::util::get_constant;
use types::{Callback, Value};
use util::create_arguments;

use super::any_object::AnyObject;
use super::traits::Object;

pub struct Class {
    value: Value
}

impl Class {
    // TODO: replace rb_cObject with optional superclass
    pub fn new(name: &str) -> Self {
        Class {
            value: define_class(name, rb_cObject)
        }
    }

    // TODO: replace rb_cObject with optional class/module value
    pub fn from_existing(name: &str) -> Self {
        Class {
            value: get_constant(name, rb_cObject)
        }
    }

    pub fn new_instance(&self, arguments: Vec<AnyObject>) -> AnyObject {
        let (argc, argv) = create_arguments(arguments);
        let instance = new_instance(self.value(), argc, argv);

        AnyObject::from(instance)
    }

    pub fn define<F: Fn(&mut Self)>(&mut self, f: F) -> &Self {
        f(self);

        self
    }

    pub fn define_method<T: Object>(&mut self, name: &str, callback: Callback<T>) {
        define_method::<T>(self.value, name, callback);
    }

    pub fn define_singleton_method<T: Object>(&mut self, name: &str, callback: Callback<T>) {
        define_singleton_method(self.value, name, callback);
    }

    pub fn def<T: Object>(&mut self, name: &str, callback: Callback<T>) {
        self.define_method(name, callback);
    }

    pub fn def_self<T: Object>(&mut self, name: &str, callback: Callback<T>) {
        self.define_singleton_method(name, callback);
    }
}

impl From<Value> for Class {
    fn from(value: Value) -> Self {
        Class {
            value: value
        }
    }
}

impl Object for Class {
    fn value(&self) -> Value {
        self.value
    }
}
<|endoftext|>


<commit_before>// spell-checker:ignore regfile
use crate::common::util::*;

static GIBBERISH: &str = "supercalifragilisticexpialidocious";

#[cfg(not(windows))]
static NOT_A_DIRECTORY: &str = "Not a directory";
#[cfg(windows)]
static NOT_A_DIRECTORY: &str = "The directory name is invalid.";

#[test]
fn test_resolve() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.touch("foo");
    at.symlink_file("foo", "bar");

    scene.ucmd().arg("bar").succeeds().stdout_contains("foo\n");
}

#[test]
fn test_canonicalize() {
    let (at, mut ucmd) = at_and_ucmd!();
    let actual = ucmd.arg("-f").arg(".").run().stdout_move_str();
    let expect = at.root_dir_resolved() + "\n";
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_canonicalize_existing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let actual = ucmd.arg("-e").arg(".").run().stdout_move_str();
    let expect = at.root_dir_resolved() + "\n";
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_canonicalize_missing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let actual = ucmd.arg("-m").arg(GIBBERISH).run().stdout_move_str();
    let expect = path_concat!(at.root_dir_resolved(), GIBBERISH) + "\n";
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_long_redirection_to_current_dir() {
    let (at, mut ucmd) = at_and_ucmd!();
    // Create a 256-character path to current directory
    let dir = path_concat!(".", ..128);
    let actual = ucmd.arg("-n").arg("-m").arg(dir).run().stdout_move_str();
    let expect = at.root_dir_resolved();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_long_redirection_to_root() {
    // Create a 255-character path to root
    let dir = path_concat!("..", ..85);
    let actual = new_ucmd!()
        .arg("-n")
        .arg("-m")
        .arg(dir)
        .run()
        .stdout_move_str();
    let expect = get_root_path();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_symlink_to_itself_verbose() {
    let (at, mut ucmd) = at_and_ucmd!();
    at.relative_symlink_file("a", "a");
    ucmd.args(&["-ev", "a"])
        .fails()
        .code_is(1)
        .stderr_contains("Too many levels of symbolic links");
}

#[test]
fn test_trailing_slash_regular_file() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.touch("regfile");
    scene
        .ucmd()
        .args(&["-ev", "./regfile/"])
        .fails()
        .code_is(1)
        .stderr_contains(NOT_A_DIRECTORY)
        .no_stdout();
    scene
        .ucmd()
        .args(&["-e", "./regfile"])
        .succeeds()
        .stdout_contains("regfile");
}

#[test]
fn test_trailing_slash_symlink_to_regular_file() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.touch("regfile");
    at.relative_symlink_file("regfile", "link");
    scene
        .ucmd()
        .args(&["-ev", "./link/"])
        .fails()
        .code_is(1)
        .stderr_contains(NOT_A_DIRECTORY)
        .no_stdout();
    scene
        .ucmd()
        .args(&["-e", "./link"])
        .succeeds()
        .stdout_contains("regfile");
    scene
        .ucmd()
        .args(&["-e", "./link/more"])
        .fails()
        .code_is(1)
        .no_stdout();
}

#[test]
fn test_trailing_slash_directory() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("directory");
    for query in ["./directory", "./directory/"] {
        scene
            .ucmd()
            .args(&["-e", query])
            .succeeds()
            .stdout_contains("directory");
    }
}

#[test]
fn test_trailing_slash_symlink_to_directory() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("directory");
    at.relative_symlink_dir("directory", "link");
    for query in ["./link", "./link/"] {
        scene
            .ucmd()
            .args(&["-e", query])
            .succeeds()
            .stdout_contains("directory");
    }
    scene
        .ucmd()
        .args(&["-ev", "./link/more"])
        .fails()
        .code_is(1)
        .stderr_contains("No such file or directory");
}

#[test]
fn test_trailing_slash_symlink_to_missing() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("subdir");
    at.relative_symlink_file("missing", "link");
    at.relative_symlink_file("subdir/missing", "link2");
    for query in [
        "missing",
        "./missing/",
        "link",
        "./link/",
        "link/more",
        "link2",
        "./link2/",
        "link2/more",
    ] {
        scene
            .ucmd()
            .args(&["-ev", query])
            .fails()
            .code_is(1)
            .stderr_contains("No such file or directory");
    }
}

#[test]
fn test_canonicalize_trailing_slash_regfile() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.touch("regfile");
    at.relative_symlink_file("regfile", "link1");
    for name in ["regfile", "link1"] {
        scene
            .ucmd()
            .args(&["-f", name])
            .succeeds()
            .stdout_contains("regfile");
        scene
            .ucmd()
            .args(&["-fv", &format!("./{}/", name)])
            .fails()
            .code_is(1)
            .stderr_contains(NOT_A_DIRECTORY);
        scene
            .ucmd()
            .args(&["-fv", &format!("{}/more", name)])
            .fails()
            .code_is(1)
            .stderr_contains(NOT_A_DIRECTORY);
        scene
            .ucmd()
            .args(&["-fv", &format!("./{}/more/", name)])
            .fails()
            .code_is(1)
            .stderr_contains(NOT_A_DIRECTORY);
    }
}

#[test]
fn test_canonicalize_trailing_slash_subdir() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("subdir");
    at.relative_symlink_dir("subdir", "link2");
    for name in ["subdir", "link2"] {
        scene
            .ucmd()
            .args(&["-f", name])
            .succeeds()
            .stdout_contains("subdir");
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/", name)])
            .succeeds()
            .stdout_contains("subdir");
        scene
            .ucmd()
            .args(&["-f", &format!("{}/more", name)])
            .succeeds()
            .stdout_contains(path_concat!("subdir", "more"));
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/more/", name)])
            .succeeds()
            .stdout_contains(path_concat!("subdir", "more"));
        scene
            .ucmd()
            .args(&["-f", &format!("{}/more/more2", name)])
            .fails()
            .code_is(1);
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/more/more2/", name)])
            .fails()
            .code_is(1);
    }
}

#[test]
fn test_canonicalize_trailing_slash_missing() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.relative_symlink_file("missing", "link3");
    for name in ["missing", "link3"] {
        scene
            .ucmd()
            .args(&["-f", name])
            .succeeds()
            .stdout_contains("missing");
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/", name)])
            .succeeds()
            .stdout_contains("missing");
        scene
            .ucmd()
            .args(&["-f", &format!("{}/more", name)])
            .fails()
            .code_is(1);
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/more/", name)])
            .fails()
            .code_is(1);
    }
}

#[test]
fn test_canonicalize_trailing_slash_subdir_missing() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("subdir");
    at.relative_symlink_file("subdir/missing", "link4");
    let name = "link4";
    scene
        .ucmd()
        .args(&["-f", name])
        .succeeds()
        .stdout_contains(path_concat!("subdir", "missing"));
    scene
        .ucmd()
        .args(&["-f", &format!("./{}/", name)])
        .succeeds()
        .stdout_contains(path_concat!("subdir", "missing"));
    scene
        .ucmd()
        .args(&["-f", &format!("{}/more", name)])
        .fails()
        .code_is(1);
    scene
        .ucmd()
        .args(&["-f", &format!("./{}/more/", name)])
        .fails()
        .code_is(1);
}

#[test]
fn test_canonicalize_trailing_slash_symlink_loop() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    let name = "link5";
    at.relative_symlink_file(name, name);
    scene.ucmd().args(&["-f", name]).fails().code_is(1);
    scene
        .ucmd()
        .args(&["-f", &format!("./{}/", name)])
        .fails()
        .code_is(1);
    scene
        .ucmd()
        .args(&["-f", &format!("{}/more", name)])
        .fails()
        .code_is(1);
    scene
        .ucmd()
        .args(&["-f", &format!("./{}/more/", name)])
        .fails()
        .code_is(1);
}
<commit_msg>tests/readlink: refactor added tests<commit_after>// spell-checker:ignore regfile
use crate::common::util::*;

static GIBBERISH: &str = "supercalifragilisticexpialidocious";

#[cfg(not(windows))]
static NOT_A_DIRECTORY: &str = "Not a directory";
#[cfg(windows)]
static NOT_A_DIRECTORY: &str = "The directory name is invalid.";

#[test]
fn test_resolve() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.touch("foo");
    at.symlink_file("foo", "bar");

    scene.ucmd().arg("bar").succeeds().stdout_contains("foo\n");
}

#[test]
fn test_canonicalize() {
    let (at, mut ucmd) = at_and_ucmd!();
    let actual = ucmd.arg("-f").arg(".").run().stdout_move_str();
    let expect = at.root_dir_resolved() + "\n";
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_canonicalize_existing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let actual = ucmd.arg("-e").arg(".").run().stdout_move_str();
    let expect = at.root_dir_resolved() + "\n";
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_canonicalize_missing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let actual = ucmd.arg("-m").arg(GIBBERISH).run().stdout_move_str();
    let expect = path_concat!(at.root_dir_resolved(), GIBBERISH) + "\n";
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_long_redirection_to_current_dir() {
    let (at, mut ucmd) = at_and_ucmd!();
    // Create a 256-character path to current directory
    let dir = path_concat!(".", ..128);
    let actual = ucmd.arg("-n").arg("-m").arg(dir).run().stdout_move_str();
    let expect = at.root_dir_resolved();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_long_redirection_to_root() {
    // Create a 255-character path to root
    let dir = path_concat!("..", ..85);
    let actual = new_ucmd!()
        .arg("-n")
        .arg("-m")
        .arg(dir)
        .run()
        .stdout_move_str();
    let expect = get_root_path();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_symlink_to_itself_verbose() {
    let (at, mut ucmd) = at_and_ucmd!();
    at.relative_symlink_file("a", "a");
    ucmd.args(&["-ev", "a"])
        .fails()
        .code_is(1)
        .stderr_contains("Too many levels of symbolic links");
}

#[test]
fn test_trailing_slash_regular_file() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.touch("regfile");
    scene
        .ucmd()
        .args(&["-ev", "./regfile/"])
        .fails()
        .code_is(1)
        .stderr_contains(NOT_A_DIRECTORY)
        .no_stdout();
    scene
        .ucmd()
        .args(&["-e", "./regfile"])
        .succeeds()
        .stdout_contains("regfile");
}

#[test]
fn test_trailing_slash_symlink_to_regular_file() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.touch("regfile");
    at.relative_symlink_file("regfile", "link");
    scene
        .ucmd()
        .args(&["-ev", "./link/"])
        .fails()
        .code_is(1)
        .stderr_contains(NOT_A_DIRECTORY)
        .no_stdout();
    scene
        .ucmd()
        .args(&["-e", "./link"])
        .succeeds()
        .stdout_contains("regfile");
    scene
        .ucmd()
        .args(&["-e", "./link/more"])
        .fails()
        .code_is(1)
        .no_stdout();
}

#[test]
fn test_trailing_slash_directory() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("directory");
    for query in ["./directory", "./directory/"] {
        scene
            .ucmd()
            .args(&["-e", query])
            .succeeds()
            .stdout_contains("directory");
    }
}

#[test]
fn test_trailing_slash_symlink_to_directory() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("directory");
    at.relative_symlink_dir("directory", "link");
    for query in ["./link", "./link/"] {
        scene
            .ucmd()
            .args(&["-e", query])
            .succeeds()
            .stdout_contains("directory");
    }
    scene
        .ucmd()
        .args(&["-ev", "./link/more"])
        .fails()
        .code_is(1)
        .stderr_contains("No such file or directory")
        .no_stdout();
}

#[test]
fn test_trailing_slash_symlink_to_missing() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("subdir");
    at.relative_symlink_file("missing", "link");
    at.relative_symlink_file("subdir/missing", "link2");
    for query in [
        "missing",
        "./missing/",
        "link",
        "./link/",
        "link/more",
        "link2",
        "./link2/",
        "link2/more",
    ] {
        scene
            .ucmd()
            .args(&["-ev", query])
            .fails()
            .code_is(1)
            .stderr_contains("No such file or directory")
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_regfile() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.touch("regfile");
    at.relative_symlink_file("regfile", "link1");
    for name in ["regfile", "link1"] {
        scene
            .ucmd()
            .args(&["-f", name])
            .succeeds()
            .stdout_contains("regfile");
        scene
            .ucmd()
            .args(&["-fv", &format!("./{}/", name)])
            .fails()
            .code_is(1)
            .stderr_contains(NOT_A_DIRECTORY)
            .no_stdout();
        scene
            .ucmd()
            .args(&["-fv", &format!("{}/more", name)])
            .fails()
            .code_is(1)
            .stderr_contains(NOT_A_DIRECTORY)
            .no_stdout();
        scene
            .ucmd()
            .args(&["-fv", &format!("./{}/more/", name)])
            .fails()
            .code_is(1)
            .stderr_contains(NOT_A_DIRECTORY)
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_subdir() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("subdir");
    at.relative_symlink_dir("subdir", "link2");
    for name in ["subdir", "link2"] {
        scene
            .ucmd()
            .args(&["-f", name])
            .succeeds()
            .stdout_contains("subdir");
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/", name)])
            .succeeds()
            .stdout_contains("subdir");
        scene
            .ucmd()
            .args(&["-f", &format!("{}/more", name)])
            .succeeds()
            .stdout_contains(path_concat!("subdir", "more"));
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/more/", name)])
            .succeeds()
            .stdout_contains(path_concat!("subdir", "more"));
        scene
            .ucmd()
            .args(&["-f", &format!("{}/more/more2", name)])
            .fails()
            .code_is(1)
            .no_stdout();
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/more/more2/", name)])
            .fails()
            .code_is(1)
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_missing() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.relative_symlink_file("missing", "link3");
    for name in ["missing", "link3"] {
        scene
            .ucmd()
            .args(&["-f", name])
            .succeeds()
            .stdout_contains("missing");
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/", name)])
            .succeeds()
            .stdout_contains("missing");
        scene
            .ucmd()
            .args(&["-f", &format!("{}/more", name)])
            .fails()
            .code_is(1)
            .no_stdout();
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/more/", name)])
            .fails()
            .code_is(1)
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_subdir_missing() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("subdir");
    at.relative_symlink_file("subdir/missing", "link4");
    for query in ["link4", "./link4/"] {
        scene
            .ucmd()
            .args(&["-f", query])
            .succeeds()
            .stdout_contains(path_concat!("subdir", "missing"));
    }
    for query in ["link4/more", "./link4/more/"] {
        scene
            .ucmd()
            .args(&["-f", query])
            .fails()
            .code_is(1)
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_symlink_loop() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.relative_symlink_file("link5", "link5");
    for query in ["link5", "./link5/", "link5/more", "./link5/more/"] {
        scene
            .ucmd()
            .args(&["-f", query])
            .fails()
            .code_is(1)
            .no_stdout();
    }
}
<|endoftext|>