<commit_before>//! Single client connection

use std::result::Result as std_Result;
use std::net::SocketAddr;
use std::sync::Arc;
use std::io;

use error;
use error::Error;
use result;

use solicit::StreamId;
use solicit::header::*;
use solicit::connection::EndStream;
use solicit::frame::settings::*;
use solicit::DEFAULT_SETTINGS;

use service::Service;

use futures::future;
use futures::future::Future;
use futures::stream::Stream;
use futures::sync::oneshot;
use futures::sync::mpsc::unbounded;
use futures::sync::mpsc::UnboundedSender;

use native_tls::TlsConnector;

use tokio_core::net::TcpStream;
use tokio_core::reactor;
use tokio_timer::Timer;
use tokio_io::AsyncWrite;
use tokio_io::AsyncRead;
use tokio_tls::TlsConnectorExt;

use futures_misc::*;

use solicit_async::*;

use common::*;
use stream_part::*;
use client_conf::*;
use client_tls::*;

use rc_mut::*;

struct ClientTypes;

impl Types for ClientTypes {
    type HttpStream = ClientStream;
    type HttpStreamSpecific = ClientStreamData;
    type ConnDataSpecific = ClientConnData;
    type ToWriteMessage = ClientToWriteMessage;

    fn first_id() -> StreamId {
        1
    }
}

pub struct ClientStreamData {
}

impl HttpStreamDataSpecific for ClientStreamData {
}

type ClientStream = HttpStreamCommon<ClientTypes>;

impl HttpStream for ClientStream {
    type Types = ClientTypes;
}

pub struct ClientConnData {
    callbacks: Box<ClientConnectionCallbacks>,
}

impl ConnDataSpecific for ClientConnData {
}

type ClientInner = ConnData<ClientTypes>;

impl ClientInner {
    fn insert_stream(&mut self, stream: ClientStream) -> StreamId {
        let id = self.next_local_stream_id();
        self.streams.insert(id, stream);
        id
    }
}

impl ConnInner for ClientInner {
    type Types = ClientTypes;

    fn process_headers(&mut self, _self_rc: RcMut<Self>, stream_id: StreamId, end_stream: EndStream, headers: Headers)
        -> result::Result<Option<HttpStreamRef<ClientTypes>>>
    {
        if let Some(mut stream) = self.get_stream_or_send_stream_closed(stream_id)? {
            if let Some(ref mut response_handler) = stream.stream().peer_tx {
                drop(response_handler.send(ResultOrEof::Item(HttpStreamPart {
                    content: HttpStreamPartContent::Headers(headers),
                    last: end_stream == EndStream::Yes,
                })));
            } else {
                // TODO: reset stream
            }

            Ok(Some(stream))
        } else {
            Ok(None)
        }
    }

    fn goaway_received(&mut self, stream_id: StreamId, raw_error_code: u32) {
        self.specific.callbacks.goaway(stream_id, raw_error_code);
    }
}

pub struct ClientConnection {
    write_tx: UnboundedSender<ClientToWriteMessage>,
    command_tx: UnboundedSender<ClientCommandMessage>,
}

unsafe impl Sync for ClientConnection {}

pub struct StartRequestMessage {
    pub headers: Headers,
    pub body: HttpPartStream,
    pub resp_tx: UnboundedSender<ResultOrEof<HttpStreamPart, Error>>,
}

enum ClientToWriteMessage {
    Start(StartRequestMessage),
    Common(CommonToWriteMessage),
}

impl From<CommonToWriteMessage> for ClientToWriteMessage {
    fn from(m: CommonToWriteMessage) -> Self {
        ClientToWriteMessage::Common(m)
    }
}

enum ClientCommandMessage {
    DumpState(oneshot::Sender<ConnectionStateSnapshot>),
    WaitForHandshake(oneshot::Sender<result::Result<()>>),
}

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

        let inner_rc = self.inner.clone();

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

            let (latch_ctr, latch) = latch();

            // TODO
            latch_ctr.open();

            let mut stream = HttpStreamCommon::new(
                inner.conn.peer_settings.initial_window_size,
                resp_tx,
                latch_ctr,
                ClientStreamData { });

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

            let stream_id = inner.insert_stream(stream);

            inner.pump_stream_to_write_loop(inner_rc, stream_id, body, latch);

            stream_id
        });

        self.send_outg_stream(stream_id)
    }

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

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

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

pub trait ClientConnectionCallbacks : 'static {
    // called at most once
    fn goaway(&self, stream_id: StreamId, raw_error_code: u32);
}

impl ClientConnection {
    fn connected<I, C>(
        lh: reactor::Handle, connect: HttpFutureSend<I>,
        conf: ClientConf,
        callbacks: C)
            -> (Self, HttpFuture<()>)
        where
            I : AsyncWrite + AsyncRead + Send + 'static,
            C : ClientConnectionCallbacks,
    {
        let (to_write_tx, to_write_rx) = unbounded();
        let (command_tx, command_rx) = unbounded();

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

        let c = ClientConnection {
            write_tx: to_write_tx.clone(),
            command_tx: command_tx,
        };

        let settings_frame = SettingsFrame::from_settings(vec![ HttpSetting::EnablePush(false) ]);
        let mut settings = DEFAULT_SETTINGS;
        settings.apply_from_frame(&settings_frame);

        let handshake = connect.and_then(|conn| client_handshake(conn, settings_frame));

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

            let inner = RcMut::new(ConnData::new(
                lh,
                ClientConnData {
                    callbacks: Box::new(callbacks),
                },
                conf.common,
                settings,
                to_write_tx.clone()));

            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<C>(
        lh: reactor::Handle,
        addr: &SocketAddr,
        tls: ClientTlsOption,
        conf: ClientConf,
        callbacks: C)
            -> (Self, HttpFuture<()>)
        where C : ClientConnectionCallbacks
    {
        match tls {
            ClientTlsOption::Plain =>
                ClientConnection::new_plain(lh, addr, conf, callbacks),
            ClientTlsOption::Tls(domain, connector) =>
                ClientConnection::new_tls(lh, &domain, connector, addr, conf, callbacks),
        }
    }

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

        let no_delay = conf.no_delay.unwrap_or(true);
        let connect = TcpStream::connect(&addr, &lh).map_err(Into::into);
        let map_callback = move |socket: TcpStream| {
            info!("connected to {}", addr);

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

            socket
        };

        let connect = if let Some(timeout) = conf.connection_timeout {
            let timer = Timer::default();
            timer.timeout(connect, timeout).map(map_callback).boxed()
        } else {
            connect.map(map_callback).boxed()
        };

        ClientConnection::connected(lh, connect, conf, callbacks)
    }

    pub fn new_tls<C>(
        lh: reactor::Handle,
        domain: &str,
        connector: Arc<TlsConnector>,
        addr: &SocketAddr,
        conf: ClientConf,
        callbacks: C)
            -> (Self, HttpFuture<()>)
        where C : ClientConnectionCallbacks
    {
        let domain = domain.to_owned();
        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(move |conn| {
            connector.connect_async(&domain, conn).map_err(|e| {
                Error::IoError(io::Error::new(io::ErrorKind::Other, e))
            })
        });

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

        ClientConnection::connected(lh, Box::new(tls_conn), conf, callbacks)
    }

    pub fn start_request_with_resp_sender(
        &self,
        start: StartRequestMessage)
            -> Result<(), StartRequestMessage>
    {
        self.write_tx.send(ClientToWriteMessage::Start(start))
            .map_err(|send_error| {
                match send_error.into_inner() {
                    ClientToWriteMessage::Start(start) => start,
                    _ => unreachable!(),
                }
            })
    }

    pub fn dump_state_with_resp_sender(&self, tx: oneshot::Sender<ConnectionStateSnapshot>) {
        // ignore error
        drop(self.command_tx.send(ClientCommandMessage::DumpState(tx)));
    }

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

        self.dump_state_with_resp_sender(tx);

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

        Box::new(rx)
    }

    pub fn wait_for_connect_with_resp_sender(&self, tx: oneshot::Sender<result::Result<()>>)
        -> std_Result<(), oneshot::Sender<result::Result<()>>>
    {
        self.command_tx.send(ClientCommandMessage::WaitForHandshake(tx))
            .map_err(|send_error| {
                match send_error.into_inner() {
                    ClientCommandMessage::WaitForHandshake(tx) => tx,
                    _ => unreachable!(),
                }
            })
    }
}

impl Service for ClientConnection {
    fn start_request(
        &self,
        headers: Headers,
        body: HttpPartStream)
            -> Response
    {
        let (resp_tx, resp_rx) = unbounded();

        let start = StartRequestMessage {
            headers: headers,
            body: body,
            resp_tx: resp_tx,
        };

        if let Err(_) = self.start_request_with_resp_sender(start) {
            return Response::err(error::Error::Other("client died"));
        }

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

        let req_rx = stream_with_eof_and_error(req_rx, || error::Error::Other("client is likely died"));

        Response::from_stream(req_rx)
    }
}

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

    fn process_message(self, message: ClientCommandMessage) -> HttpFuture<Self> {
        match message {
            ClientCommandMessage::DumpState(sender) => self.process_dump_state(sender),
            ClientCommandMessage::WaitForHandshake(tx) => {
                // ignore error
                drop(tx.send(Ok(())));
                Box::new(future::ok(self))
            },
        }
    }

    fn run(self, requests: HttpFutureStreamSend<ClientCommandMessage>) -> HttpFuture<()> {
        let requests = requests.map_err(Error::from);
        Box::new(requests
            .fold(self, move |l, message: ClientCommandMessage| {
                l.process_message(message)
            })
            .map(|_| ()))
    }
}
<commit_msg>Unnecessary flush<commit_after>//! Single client connection

use std::result::Result as std_Result;
use std::net::SocketAddr;
use std::sync::Arc;
use std::io;

use error;
use error::Error;
use result;

use solicit::StreamId;
use solicit::header::*;
use solicit::connection::EndStream;
use solicit::frame::settings::*;
use solicit::DEFAULT_SETTINGS;

use service::Service;

use futures::future;
use futures::future::Future;
use futures::stream::Stream;
use futures::sync::oneshot;
use futures::sync::mpsc::unbounded;
use futures::sync::mpsc::UnboundedSender;

use native_tls::TlsConnector;

use tokio_core::net::TcpStream;
use tokio_core::reactor;
use tokio_timer::Timer;
use tokio_io::AsyncWrite;
use tokio_io::AsyncRead;
use tokio_tls::TlsConnectorExt;

use futures_misc::*;

use solicit_async::*;

use common::*;
use stream_part::*;
use client_conf::*;
use client_tls::*;

use rc_mut::*;

struct ClientTypes;

impl Types for ClientTypes {
    type HttpStream = ClientStream;
    type HttpStreamSpecific = ClientStreamData;
    type ConnDataSpecific = ClientConnData;
    type ToWriteMessage = ClientToWriteMessage;

    fn first_id() -> StreamId {
        1
    }
}

pub struct ClientStreamData {
}

impl HttpStreamDataSpecific for ClientStreamData {
}

type ClientStream = HttpStreamCommon<ClientTypes>;

impl HttpStream for ClientStream {
    type Types = ClientTypes;
}

pub struct ClientConnData {
    callbacks: Box<ClientConnectionCallbacks>,
}

impl ConnDataSpecific for ClientConnData {
}

type ClientInner = ConnData<ClientTypes>;

impl ClientInner {
    fn insert_stream(&mut self, stream: ClientStream) -> StreamId {
        let id = self.next_local_stream_id();
        self.streams.insert(id, stream);
        id
    }
}

impl ConnInner for ClientInner {
    type Types = ClientTypes;

    fn process_headers(&mut self, _self_rc: RcMut<Self>, stream_id: StreamId, end_stream: EndStream, headers: Headers)
        -> result::Result<Option<HttpStreamRef<ClientTypes>>>
    {
        if let Some(mut stream) = self.get_stream_or_send_stream_closed(stream_id)? {
            if let Some(ref mut response_handler) = stream.stream().peer_tx {
                drop(response_handler.send(ResultOrEof::Item(HttpStreamPart {
                    content: HttpStreamPartContent::Headers(headers),
                    last: end_stream == EndStream::Yes,
                })));
            } else {
                // TODO: reset stream
            }

            Ok(Some(stream))
        } else {
            Ok(None)
        }
    }

    fn goaway_received(&mut self, stream_id: StreamId, raw_error_code: u32) {
        self.specific.callbacks.goaway(stream_id, raw_error_code);
    }
}

pub struct ClientConnection {
    write_tx: UnboundedSender<ClientToWriteMessage>,
    command_tx: UnboundedSender<ClientCommandMessage>,
}

unsafe impl Sync for ClientConnection {}

pub struct StartRequestMessage {
    pub headers: Headers,
    pub body: HttpPartStream,
    pub resp_tx: UnboundedSender<ResultOrEof<HttpStreamPart, Error>>,
}

enum ClientToWriteMessage {
    Start(StartRequestMessage),
    Common(CommonToWriteMessage),
}

impl From<CommonToWriteMessage> for ClientToWriteMessage {
    fn from(m: CommonToWriteMessage) -> Self {
        ClientToWriteMessage::Common(m)
    }
}

enum ClientCommandMessage {
    DumpState(oneshot::Sender<ConnectionStateSnapshot>),
    WaitForHandshake(oneshot::Sender<result::Result<()>>),
}

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

        let inner_rc = self.inner.clone();

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

            let (latch_ctr, latch) = latch();

            // TODO
            latch_ctr.open();

            let mut stream = HttpStreamCommon::new(
                inner.conn.peer_settings.initial_window_size,
                resp_tx,
                latch_ctr,
                ClientStreamData { });

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

            let stream_id = inner.insert_stream(stream);

            inner.pump_stream_to_write_loop(inner_rc, stream_id, body, latch);
        });

        Box::new(future::ok(self))
    }

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

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

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

pub trait ClientConnectionCallbacks : 'static {
    // called at most once
    fn goaway(&self, stream_id: StreamId, raw_error_code: u32);
}

impl ClientConnection {
    fn connected<I, C>(
        lh: reactor::Handle, connect: HttpFutureSend<I>,
        conf: ClientConf,
        callbacks: C)
            -> (Self, HttpFuture<()>)
        where
            I : AsyncWrite + AsyncRead + Send + 'static,
            C : ClientConnectionCallbacks,
    {
        let (to_write_tx, to_write_rx) = unbounded();
        let (command_tx, command_rx) = unbounded();

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

        let c = ClientConnection {
            write_tx: to_write_tx.clone(),
            command_tx: command_tx,
        };

        let settings_frame = SettingsFrame::from_settings(vec![ HttpSetting::EnablePush(false) ]);
        let mut settings = DEFAULT_SETTINGS;
        settings.apply_from_frame(&settings_frame);

        let handshake = connect.and_then(|conn| client_handshake(conn, settings_frame));

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

            let inner = RcMut::new(ConnData::new(
                lh,
                ClientConnData {
                    callbacks: Box::new(callbacks),
                },
                conf.common,
                settings,
                to_write_tx.clone()));

            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<C>(
        lh: reactor::Handle,
        addr: &SocketAddr,
        tls: ClientTlsOption,
        conf: ClientConf,
        callbacks: C)
            -> (Self, HttpFuture<()>)
        where C : ClientConnectionCallbacks
    {
        match tls {
            ClientTlsOption::Plain =>
                ClientConnection::new_plain(lh, addr, conf, callbacks),
            ClientTlsOption::Tls(domain, connector) =>
                ClientConnection::new_tls(lh, &domain, connector, addr, conf, callbacks),
        }
    }

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

        let no_delay = conf.no_delay.unwrap_or(true);
        let connect = TcpStream::connect(&addr, &lh).map_err(Into::into);
        let map_callback = move |socket: TcpStream| {
            info!("connected to {}", addr);

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

            socket
        };

        let connect = if let Some(timeout) = conf.connection_timeout {
            let timer = Timer::default();
            timer.timeout(connect, timeout).map(map_callback).boxed()
        } else {
            connect.map(map_callback).boxed()
        };

        ClientConnection::connected(lh, connect, conf, callbacks)
    }

    pub fn new_tls<C>(
        lh: reactor::Handle,
        domain: &str,
        connector: Arc<TlsConnector>,
        addr: &SocketAddr,
        conf: ClientConf,
        callbacks: C)
            -> (Self, HttpFuture<()>)
        where C : ClientConnectionCallbacks
    {
        let domain = domain.to_owned();
        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(move |conn| {
            connector.connect_async(&domain, conn).map_err(|e| {
                Error::IoError(io::Error::new(io::ErrorKind::Other, e))
            })
        });

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

        ClientConnection::connected(lh, Box::new(tls_conn), conf, callbacks)
    }

    pub fn start_request_with_resp_sender(
        &self,
        start: StartRequestMessage)
            -> Result<(), StartRequestMessage>
    {
        self.write_tx.send(ClientToWriteMessage::Start(start))
            .map_err(|send_error| {
                match send_error.into_inner() {
                    ClientToWriteMessage::Start(start) => start,
                    _ => unreachable!(),
                }
            })
    }

    pub fn dump_state_with_resp_sender(&self, tx: oneshot::Sender<ConnectionStateSnapshot>) {
        // ignore error
        drop(self.command_tx.send(ClientCommandMessage::DumpState(tx)));
    }

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

        self.dump_state_with_resp_sender(tx);

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

        Box::new(rx)
    }

    pub fn wait_for_connect_with_resp_sender(&self, tx: oneshot::Sender<result::Result<()>>)
        -> std_Result<(), oneshot::Sender<result::Result<()>>>
    {
        self.command_tx.send(ClientCommandMessage::WaitForHandshake(tx))
            .map_err(|send_error| {
                match send_error.into_inner() {
                    ClientCommandMessage::WaitForHandshake(tx) => tx,
                    _ => unreachable!(),
                }
            })
    }
}

impl Service for ClientConnection {
    fn start_request(
        &self,
        headers: Headers,
        body: HttpPartStream)
            -> Response
    {
        let (resp_tx, resp_rx) = unbounded();

        let start = StartRequestMessage {
            headers: headers,
            body: body,
            resp_tx: resp_tx,
        };

        if let Err(_) = self.start_request_with_resp_sender(start) {
            return Response::err(error::Error::Other("client died"));
        }

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

        let req_rx = stream_with_eof_and_error(req_rx, || error::Error::Other("client is likely died"));

        Response::from_stream(req_rx)
    }
}

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

    fn process_message(self, message: ClientCommandMessage) -> HttpFuture<Self> {
        match message {
            ClientCommandMessage::DumpState(sender) => self.process_dump_state(sender),
            ClientCommandMessage::WaitForHandshake(tx) => {
                // ignore error
                drop(tx.send(Ok(())));
                Box::new(future::ok(self))
            },
        }
    }

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


<commit_before>//! JIT Compiler to generate code fragments in runtime.

extern crate libc;
extern crate llvm_sys;

#[macro_use]
mod macros;
mod block;
mod buffer;
mod builder;
mod util;
mod types;
mod value;

use std::mem;
use std::ptr;

use llvm_sys::analysis;
use llvm_sys::core;
use llvm_sys::prelude::{
  LLVMContextRef,
  LLVMModuleRef
};
use llvm_sys::bit_reader::LLVMParseBitcodeInContext;
use llvm_sys::execution_engine::{
  LLVMExecutionEngineRef,
  LLVMLinkInMCJIT,
  LLVMMCJITCompilerOptions,
  LLVMCreateMCJITCompilerForModule
};
use llvm_sys::linker;
use llvm_sys::transforms::pass_manager_builder as pass;
use llvm_sys::target::{
  LLVM_InitializeNativeTarget,
  LLVM_InitializeNativeAsmPrinter
};
use llvm_sys::target_machine::LLVMCodeModel;

use libc::{c_char, c_uint};

use buffer::MemoryBuffer;
use builder::Builder;
use value::{GlobalValue, Value, ValueIter};
use types::Ty;
use util::chars;

pub const JIT_OPT_LVEL: usize = 2;

#[repr(C)]
#[derive(Copy, Clone)]
pub enum AddressSpace
{
  Generic = 0,
  Global = 1,
  Shared = 3,
  Const = 4,
  Local = 5,
}

fn new_module(ctx: LLVMContextRef, name: &str) -> LLVMModuleRef
{
  let c_name = util::chars::from_str(name);
  unsafe {
  	core::LLVMModuleCreateWithNameInContext(c_name, ctx)
  }
}
fn new_module_from_bc(ctx: LLVMContextRef, path: &str) -> Result<LLVMModuleRef, String>
{
  unsafe {
    let mut out: LLVMModuleRef = mem::uninitialized();
    let mut err: *mut c_char   = mem::uninitialized();
    let buf = try!(MemoryBuffer::from_file(path));

    let ret = LLVMParseBitcodeInContext(ctx,
                                        buf.as_ptr(),
    	                                  &mut out,
    	                                  &mut err);
    llvm_ret!(ret, out, err)
  }
}

fn new_jit_ee(m: LLVMModuleRef, opt_lv: usize) -> Result<LLVMExecutionEngineRef, String>
{
  unsafe {
    let mut ee : LLVMExecutionEngineRef = mem::uninitialized();
    let mut err: *mut c_char = mem::uninitialized();

    LLVMLinkInMCJIT();
    expect_noerr!(LLVM_InitializeNativeTarget(), "failed to initialize native target");
    expect_noerr!(LLVM_InitializeNativeAsmPrinter(), "failed to initialize native asm printer");

    let mut opts = new_mcjit_compiler_options(opt_lv);
    let opts_size = mem::size_of::<LLVMMCJITCompilerOptions>();

    let ret = LLVMCreateMCJITCompilerForModule(&mut ee,
      		                                     m,
      		                                     &mut opts,
      		                                     opts_size as u64,
      		                                     &mut err);
    llvm_ret!(ret, ee, err)
  }
}

fn new_mcjit_compiler_options(opt_lv: usize) -> LLVMMCJITCompilerOptions
{
  LLVMMCJITCompilerOptions {
    OptLevel: opt_lv as c_uint,
    CodeModel: LLVMCodeModel::LLVMCodeModelJITDefault,
    NoFramePointerElim: 0,
    EnableFastISel: 1,
    MCJMM: ptr::null_mut()
  }
}

pub struct JitCompiler
{
  ctx    : LLVMContextRef,
  module : LLVMModuleRef,
  ee     : LLVMExecutionEngineRef,
  //builder: Builder // internal use
}

impl JitCompiler {

  pub fn new(module_name: &str) -> Result<JitCompiler, String>
  {
    let ctx     = unsafe { core::LLVMContextCreate() };
    let module  = new_module(ctx, module_name);
    JitCompiler::new_internal(ctx, module)
  }

  pub fn new_from_bc(bitcode_path: &str) -> Result<JitCompiler, String>
  {
    let ctx     = unsafe { core::LLVMContextCreate() };
    let module  = try!(new_module_from_bc(ctx, bitcode_path));
    JitCompiler::new_internal(ctx, module)
  }

  fn new_internal(ctx: LLVMContextRef, module: LLVMModuleRef) -> Result<JitCompiler, String>
  {
    let ee      = try!(new_jit_ee(module, JIT_OPT_LVEL));
    //let builder = Builder(unsafe { core::LLVMCreateBuilderInContext(ctx) });

    Ok(JitCompiler {
      ctx    : ctx,
      module : module,
      ee     : ee,
      //builder: builder
    })
  }

  pub fn context(&self) -> LLVMContextRef { self.ctx }
  pub fn module(&self) -> LLVMModuleRef { self.module }
  pub fn engine(&self) -> LLVMExecutionEngineRef { self.ee }

  /// Returns the target data of the base module represented as a string
  pub fn get_target(&self) -> &str
  {
    unsafe {
      let target = core::LLVMGetTarget(self.module);
      chars::to_str(target)
    }
  }

  /// Get the data layout of the base module
  pub fn get_data_layout(&self) -> &str
  {
  	unsafe {
  		let layout = core::LLVMGetDataLayout(self.module);
  		chars::to_str(layout as *mut c_char)
  	}
  }

  /// Add an external global to the module with the given type and name.
  pub fn add_global(&self, name: &str, ty: &Ty) -> GlobalValue
  {
    let c_name = chars::from_str(name);
    GlobalValue(
      unsafe {
        core::LLVMAddGlobal(self.module, ty.0, c_name)
      }
    )
  }

  /// Add a global in the given address space to the module with the given type and name.
  pub fn add_global_in_addr_space(&self,
  	                              name: &str,
  	                              ty: &Ty,
  	                              sp: AddressSpace) -> GlobalValue
  {
    let c_name = chars::from_str(name);
    GlobalValue(
      unsafe {
        core::LLVMAddGlobalInAddressSpace(self.module, ty.0, c_name, sp as c_uint)
      }
    )
  }

  /// Add a constant global to the module with the given type, name and value.
  pub fn add_global_constant(&self, name: &str, val: &Value) -> GlobalValue
  {
    let c_name = chars::from_str(name);
    GlobalValue(
      unsafe {
        let global = core::LLVMAddGlobal(self.module, val.ty().0, c_name);
        core::LLVMSetInitializer (global, val.0);
        global
      }
    )
  }

  /// Get the global with the name given, or `None` if no global with that name exists.
  pub fn get_global(&self, name: &str) -> Option<GlobalValue>
  {
    let c_name = chars::from_str(name);
    unsafe {
      let ptr = core::LLVMGetNamedGlobal(self.module, c_name);
      if ptr.is_null() {
        None
      } else {
        Some(GlobalValue(ptr))
      }
    }
  }

  /// Get an iterator of global values
  pub fn global_values(&self) -> ValueIter<GlobalValue>
  {
  	ValueIter::new(
 			unsafe { core::LLVMGetFirstGlobal(self.module) },
 			core::LLVMGetNextGlobal
 		)
  }

  /// Link a module into this module, returning an error string if an error occurs.
  ///
  /// This *does not* destroy the source module.
  pub fn link(&self, module: LLVMModuleRef) -> Result<(), String>
  {
    unsafe {
      let mut error = mem::uninitialized();
      let ret = linker::LLVMLinkModules(self.module, module,
      	                                linker::LLVMLinkerMode::LLVMLinkerPreserveSource,
      	                                &mut error);
      llvm_ret!(ret, (), error)
    }
  }

  /// Link a module into this module, returning an error string if an error occurs.
  ///
  /// This *does* destroy the source module.
  pub fn link_destroy(&self, module: LLVMModuleRef) -> Result<(), String>
  {
    unsafe {
      let mut error = mem::uninitialized();
      let ret = linker::LLVMLinkModules(self.module, module,
      	                                linker::LLVMLinkerMode::LLVMLinkerDestroySource,
      	                                &mut error);
      llvm_ret!(ret, (), error)
    }
  }

  /// Optimize this module with the given optimization level and size level.
  ///
  /// This runs passes depending on the levels given.
  pub fn optimize(&self, opt_level: usize, size_level: usize) {
    unsafe {
      let builder = pass::LLVMPassManagerBuilderCreate();
      pass::LLVMPassManagerBuilderSetOptLevel(builder, opt_level as c_uint);
      pass::LLVMPassManagerBuilderSetSizeLevel(builder, size_level as c_uint);
      let pass_manager = core::LLVMCreatePassManager();
      pass::LLVMPassManagerBuilderPopulateModulePassManager(builder, pass_manager);
      pass::LLVMPassManagerBuilderDispose(builder);
      core::LLVMRunPassManager(pass_manager, self.module);
    }
  }

  /// Verify that the module is safe to run, returning a string detailing the error
  /// when an error occurs.
  pub fn verify(&self) -> Result<(), String>
  {
    unsafe {
      let mut error = mem::uninitialized();
      let action = analysis::LLVMVerifierFailureAction::LLVMReturnStatusAction;
      let ret = analysis::LLVMVerifyModule(self.module, action, &mut error);

      llvm_ret!(ret, (), error)
    }
  }

  pub fn new_builder(&self) -> Builder
  {
    Builder(unsafe { core::LLVMCreateBuilderInContext(self.ctx) })
  }
}

impl Drop for JitCompiler {
  fn drop(&mut self) {
    unsafe {
      core::LLVMDisposeModule(self.module);
      core::LLVMContextDispose(self.ctx);
    }
  }
}

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

  #[test]
  fn test_ctor() {
    let jit = JitCompiler::new("target/test-ir/test-module.bc").ok().unwrap();
  }
}<commit_msg>Add dump() for module to JitCompiler.<commit_after>//! JIT Compiler to generate code fragments in runtime.

extern crate libc;
extern crate llvm_sys;

#[macro_use]
mod macros;
mod block;
mod buffer;
mod builder;
mod util;
mod types;
mod value;

use std::mem;
use std::ptr;

use llvm_sys::analysis;
use llvm_sys::core;
use llvm_sys::prelude::{
  LLVMContextRef,
  LLVMModuleRef
};
use llvm_sys::bit_reader::LLVMParseBitcodeInContext;
use llvm_sys::execution_engine::{
  LLVMExecutionEngineRef,
  LLVMLinkInMCJIT,
  LLVMMCJITCompilerOptions,
  LLVMCreateMCJITCompilerForModule
};
use llvm_sys::linker;
use llvm_sys::transforms::pass_manager_builder as pass;
use llvm_sys::target::{
  LLVM_InitializeNativeTarget,
  LLVM_InitializeNativeAsmPrinter
};
use llvm_sys::target_machine::LLVMCodeModel;

use libc::{c_char, c_uint};

use buffer::MemoryBuffer;
use builder::Builder;
use value::{GlobalValue, Value, ValueIter};
use types::Ty;
use util::chars;

pub const JIT_OPT_LVEL: usize = 2;

#[repr(C)]
#[derive(Copy, Clone)]
pub enum AddressSpace
{
  Generic = 0,
  Global = 1,
  Shared = 3,
  Const = 4,
  Local = 5,
}

fn new_module(ctx: LLVMContextRef, name: &str) -> LLVMModuleRef
{
  let c_name = util::chars::from_str(name);
  unsafe {
  	core::LLVMModuleCreateWithNameInContext(c_name, ctx)
  }
}
fn new_module_from_bc(ctx: LLVMContextRef, path: &str) -> Result<LLVMModuleRef, String>
{
  unsafe {
    let mut out: LLVMModuleRef = mem::uninitialized();
    let mut err: *mut c_char   = mem::uninitialized();
    let buf = try!(MemoryBuffer::from_file(path));

    let ret = LLVMParseBitcodeInContext(ctx,
                                        buf.as_ptr(),
    	                                  &mut out,
    	                                  &mut err);
    llvm_ret!(ret, out, err)
  }
}

fn new_jit_ee(m: LLVMModuleRef, opt_lv: usize) -> Result<LLVMExecutionEngineRef, String>
{
  unsafe {
    let mut ee : LLVMExecutionEngineRef = mem::uninitialized();
    let mut err: *mut c_char = mem::uninitialized();

    LLVMLinkInMCJIT();
    expect_noerr!(LLVM_InitializeNativeTarget(), "failed to initialize native target");
    expect_noerr!(LLVM_InitializeNativeAsmPrinter(), "failed to initialize native asm printer");

    let mut opts = new_mcjit_compiler_options(opt_lv);
    let opts_size = mem::size_of::<LLVMMCJITCompilerOptions>();

    let ret = LLVMCreateMCJITCompilerForModule(&mut ee,
      		                                     m,
      		                                     &mut opts,
      		                                     opts_size as u64,
      		                                     &mut err);
    llvm_ret!(ret, ee, err)
  }
}

fn new_mcjit_compiler_options(opt_lv: usize) -> LLVMMCJITCompilerOptions
{
  LLVMMCJITCompilerOptions {
    OptLevel: opt_lv as c_uint,
    CodeModel: LLVMCodeModel::LLVMCodeModelJITDefault,
    NoFramePointerElim: 0,
    EnableFastISel: 1,
    MCJMM: ptr::null_mut()
  }
}

pub struct JitCompiler
{
  ctx    : LLVMContextRef,
  module : LLVMModuleRef,
  ee     : LLVMExecutionEngineRef,
  //builder: Builder // internal use
}

impl JitCompiler {

  pub fn new(module_name: &str) -> Result<JitCompiler, String>
  {
    let ctx     = unsafe { core::LLVMContextCreate() };
    let module  = new_module(ctx, module_name);
    JitCompiler::new_internal(ctx, module)
  }

  pub fn new_from_bc(bitcode_path: &str) -> Result<JitCompiler, String>
  {
    let ctx     = unsafe { core::LLVMContextCreate() };
    let module  = try!(new_module_from_bc(ctx, bitcode_path));
    JitCompiler::new_internal(ctx, module)
  }

  fn new_internal(ctx: LLVMContextRef, module: LLVMModuleRef) -> Result<JitCompiler, String>
  {
    let ee      = try!(new_jit_ee(module, JIT_OPT_LVEL));
    //let builder = Builder(unsafe { core::LLVMCreateBuilderInContext(ctx) });

    Ok(JitCompiler {
      ctx    : ctx,
      module : module,
      ee     : ee,
      //builder: builder
    })
  }

  pub fn context(&self) -> LLVMContextRef { self.ctx }
  pub fn module(&self) -> LLVMModuleRef { self.module }
  pub fn engine(&self) -> LLVMExecutionEngineRef { self.ee }

  /// Returns the target data of the base module represented as a string
  pub fn get_target(&self) -> &str
  {
    unsafe {
      let target = core::LLVMGetTarget(self.module);
      chars::to_str(target)
    }
  }

  /// Get the data layout of the base module
  pub fn get_data_layout(&self) -> &str
  {
  	unsafe {
  		let layout = core::LLVMGetDataLayout(self.module);
  		chars::to_str(layout as *mut c_char)
  	}
  }

  /// Add an external global to the module with the given type and name.
  pub fn add_global(&self, name: &str, ty: &Ty) -> GlobalValue
  {
    let c_name = chars::from_str(name);
    GlobalValue(
      unsafe {
        core::LLVMAddGlobal(self.module, ty.0, c_name)
      }
    )
  }

  /// Add a global in the given address space to the module with the given type and name.
  pub fn add_global_in_addr_space(&self,
  	                              name: &str,
  	                              ty: &Ty,
  	                              sp: AddressSpace) -> GlobalValue
  {
    let c_name = chars::from_str(name);
    GlobalValue(
      unsafe {
        core::LLVMAddGlobalInAddressSpace(self.module, ty.0, c_name, sp as c_uint)
      }
    )
  }

  /// Add a constant global to the module with the given type, name and value.
  pub fn add_global_constant(&self, name: &str, val: &Value) -> GlobalValue
  {
    let c_name = chars::from_str(name);
    GlobalValue(
      unsafe {
        let global = core::LLVMAddGlobal(self.module, val.ty().0, c_name);
        core::LLVMSetInitializer (global, val.0);
        global
      }
    )
  }

  /// Get the global with the name given, or `None` if no global with that name exists.
  pub fn get_global(&self, name: &str) -> Option<GlobalValue>
  {
    let c_name = chars::from_str(name);
    unsafe {
      let ptr = core::LLVMGetNamedGlobal(self.module, c_name);
      if ptr.is_null() {
        None
      } else {
        Some(GlobalValue(ptr))
      }
    }
  }

  /// Get an iterator of global values
  pub fn global_values(&self) -> ValueIter<GlobalValue>
  {
  	ValueIter::new(
 			unsafe { core::LLVMGetFirstGlobal(self.module) },
 			core::LLVMGetNextGlobal
 		)
  }

  /// Link a module into this module, returning an error string if an error occurs.
  ///
  /// This *does not* destroy the source module.
  pub fn link(&self, module: LLVMModuleRef) -> Result<(), String>
  {
    unsafe {
      let mut error = mem::uninitialized();
      let ret = linker::LLVMLinkModules(self.module, module,
      	                                linker::LLVMLinkerMode::LLVMLinkerPreserveSource,
      	                                &mut error);
      llvm_ret!(ret, (), error)
    }
  }

  /// Link a module into this module, returning an error string if an error occurs.
  ///
  /// This *does* destroy the source module.
  pub fn link_destroy(&self, module: LLVMModuleRef) -> Result<(), String>
  {
    unsafe {
      let mut error = mem::uninitialized();
      let ret = linker::LLVMLinkModules(self.module, module,
      	                                linker::LLVMLinkerMode::LLVMLinkerDestroySource,
      	                                &mut error);
      llvm_ret!(ret, (), error)
    }
  }

  /// Optimize this module with the given optimization level and size level.
  ///
  /// This runs passes depending on the levels given.
  pub fn optimize(&self, opt_level: usize, size_level: usize) {
    unsafe {
      let builder = pass::LLVMPassManagerBuilderCreate();
      pass::LLVMPassManagerBuilderSetOptLevel(builder, opt_level as c_uint);
      pass::LLVMPassManagerBuilderSetSizeLevel(builder, size_level as c_uint);
      let pass_manager = core::LLVMCreatePassManager();
      pass::LLVMPassManagerBuilderPopulateModulePassManager(builder, pass_manager);
      pass::LLVMPassManagerBuilderDispose(builder);
      core::LLVMRunPassManager(pass_manager, self.module);
    }
  }

  /// Verify that the module is safe to run, returning a string detailing the error
  /// when an error occurs.
  pub fn verify(&self) -> Result<(), String>
  {
    unsafe {
      let mut error = mem::uninitialized();
      let action = analysis::LLVMVerifierFailureAction::LLVMReturnStatusAction;
      let ret = analysis::LLVMVerifyModule(self.module, action, &mut error);

      llvm_ret!(ret, (), error)
    }
  }

  /// Dump the module to stderr (for debugging).
  pub fn dump(&self)
  {
  	unsafe { core::LLVMDumpModule(self.module); }
  }

  pub fn new_builder(&self) -> Builder
  {
    Builder(unsafe { core::LLVMCreateBuilderInContext(self.ctx) })
  }
}

impl Drop for JitCompiler {
  fn drop(&mut self) {
    unsafe {
      core::LLVMDisposeModule(self.module);
      core::LLVMContextDispose(self.ctx);
    }
  }
}

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

  #[test]
  fn test_ctor() {
    let jit = JitCompiler::new("target/test-ir/test-module.bc").ok().unwrap();
  }
}<|endoftext|>


<commit_before>use cpu::{Flag, Register8, Register16};
use GameBoy;

/// Iterate the ROM
pub fn decode(gb: &mut GameBoy) {
    for i in 0..gb.cartridge.size() {
        opcode_router(gb.cartridge.read_byte(i as u16), gb);
    }
    println!("{:?}", gb.cpu);
}

/// Map Opcode to function
fn opcode_router(opcode: u8, gb: &mut GameBoy) {
    match opcode {
        0x00 => {},
        0x01 => { ld_bc_nn(gb) },
        0x02 => { ld_bcp_a(gb) },
        0x03 => { inc_bc(gb) },
        0x04 => { inc_bc(gb) },
        0x05 => { unimplemented!() },
        0x06 => { unimplemented!() },
        0x07 => { unimplemented!() },
        0x08 => { unimplemented!() },
        0x09 => { unimplemented!() },
        0x0a => { unimplemented!() },
        0x0b => { unimplemented!() },
        0x0c => { unimplemented!() },
        0x0d => { unimplemented!() },
        0x0e => { unimplemented!() },
        0x0f => { unimplemented!() },
        0x10 => { unimplemented!() },
        0x11 => { unimplemented!() },
        0x12 => { unimplemented!() },
        0x13 => { unimplemented!() },
        0x14 => { unimplemented!() },
        0x15 => { unimplemented!() },
        0x16 => { unimplemented!() },
        0x17 => { unimplemented!() },
        0x18 => { unimplemented!() },
        0x19 => { unimplemented!() },
        0x1a => { unimplemented!() },
        0x1b => { unimplemented!() },
        0x1c => { unimplemented!() },
        0x1d => { unimplemented!() },
        0x1e => { unimplemented!() },
        0x1f => { unimplemented!() },
        0x20 => { unimplemented!() },
        0x21 => { unimplemented!() },
        0x22 => { unimplemented!() },
        0x23 => { unimplemented!() },
        0x24 => { unimplemented!() },
        0x25 => { unimplemented!() },
        0x26 => { unimplemented!() },
        0x27 => { unimplemented!() },
        0x28 => { unimplemented!() },
        0x29 => { unimplemented!() },
        0x2a => { unimplemented!() },
        0x2b => { unimplemented!() },
        0x2c => { unimplemented!() },
        0x2d => { unimplemented!() },
        0x2e => { unimplemented!() },
        0x2f => { unimplemented!() },
        0x30 => { unimplemented!() },
        0x31 => { ld_sp_nn(gb) },
        0x32 => { unimplemented!() },
        0x33 => { unimplemented!() },
        0x34 => { unimplemented!() },
        0x35 => { unimplemented!() },
        0x36 => { unimplemented!() },
        0x37 => { unimplemented!() },
        0x38 => { unimplemented!() },
        0x39 => { unimplemented!() },
        0x3a => { unimplemented!() },
        0x3b => { unimplemented!() },
        0x3c => { unimplemented!() },
        0x3d => { unimplemented!() },
        0x3e => { unimplemented!() },
        0x3f => { unimplemented!() },
        0x40 => { unimplemented!() },
        0x41 => { unimplemented!() },
        0x42 => { unimplemented!() },
        0x43 => { unimplemented!() },
        0x44 => { unimplemented!() },
        0x45 => { unimplemented!() },
        0x46 => { unimplemented!() },
        0x47 => { unimplemented!() },
        0x48 => { unimplemented!() },
        0x49 => { unimplemented!() },
        0x4a => { unimplemented!() },
        0x4b => { unimplemented!() },
        0x4c => { unimplemented!() },
        0x4d => { unimplemented!() },
        0x4e => { unimplemented!() },
        0x4f => { unimplemented!() },
        0x50 => { unimplemented!() },
        0x51 => { unimplemented!() },
        0x52 => { unimplemented!() },
        0x53 => { unimplemented!() },
        0x54 => { unimplemented!() },
        0x55 => { unimplemented!() },
        0x56 => { unimplemented!() },
        0x57 => { unimplemented!() },
        0x58 => { unimplemented!() },
        0x59 => { unimplemented!() },
        0x5a => { unimplemented!() },
        0x5b => { unimplemented!() },
        0x5c => { unimplemented!() },
        0x5d => { unimplemented!() },
        0x5e => { unimplemented!() },
        0x5f => { unimplemented!() },
        0x60 => { unimplemented!() },
        0x61 => { unimplemented!() },
        0x62 => { unimplemented!() },
        0x63 => { unimplemented!() },
        0x64 => { unimplemented!() },
        0x65 => { unimplemented!() },
        0x66 => { unimplemented!() },
        0x67 => { unimplemented!() },
        0x68 => { unimplemented!() },
        0x69 => { unimplemented!() },
        0x6a => { unimplemented!() },
        0x6b => { unimplemented!() },
        0x6c => { unimplemented!() },
        0x6d => { unimplemented!() },
        0x6e => { unimplemented!() },
        0x6f => { unimplemented!() },
        0x70 => { unimplemented!() },
        0x71 => { unimplemented!() },
        0x72 => { unimplemented!() },
        0x73 => { unimplemented!() },
        0x74 => { unimplemented!() },
        0x75 => { unimplemented!() },
        0x76 => { unimplemented!() },
        0x77 => { unimplemented!() },
        0x78 => { unimplemented!() },
        0x79 => { unimplemented!() },
        0x7a => { unimplemented!() },
        0x7b => { unimplemented!() },
        0x7c => { unimplemented!() },
        0x7d => { unimplemented!() },
        0x7e => { unimplemented!() },
        0x7f => { unimplemented!() },
        0x80 => { unimplemented!() },
        0x81 => { unimplemented!() },
        0x82 => { unimplemented!() },
        0x83 => { unimplemented!() },
        0x84 => { unimplemented!() },
        0x85 => { unimplemented!() },
        0x86 => { unimplemented!() },
        0x87 => { unimplemented!() },
        0x88 => { unimplemented!() },
        0x89 => { unimplemented!() },
        0x8a => { unimplemented!() },
        0x8b => { unimplemented!() },
        0x8c => { unimplemented!() },
        0x8d => { unimplemented!() },
        0x8e => { unimplemented!() },
        0x8f => { unimplemented!() },
        0x90 => { unimplemented!() },
        0x91 => { unimplemented!() },
        0x92 => { unimplemented!() },
        0x93 => { unimplemented!() },
        0x94 => { unimplemented!() },
        0x95 => { unimplemented!() },
        0x96 => { unimplemented!() },
        0x97 => { unimplemented!() },
        0x98 => { unimplemented!() },
        0x99 => { unimplemented!() },
        0x9a => { unimplemented!() },
        0x9b => { unimplemented!() },
        0x9c => { unimplemented!() },
        0x9d => { unimplemented!() },
        0x9e => { unimplemented!() },
        0x9f => { unimplemented!() },
        0xa0 => { unimplemented!() },
        0xa1 => { unimplemented!() },
        0xa2 => { unimplemented!() },
        0xa3 => { unimplemented!() },
        0xa4 => { unimplemented!() },
        0xa5 => { unimplemented!() },
        0xa6 => { unimplemented!() },
        0xa7 => { unimplemented!() },
        0xa8 => { unimplemented!() },
        0xa9 => { unimplemented!() },
        0xaa => { unimplemented!() },
        0xab => { unimplemented!() },
        0xac => { unimplemented!() },
        0xad => { unimplemented!() },
        0xae => { unimplemented!() },
        0xaf => { xor(gb, Register8::A) }
        0xb0 => { unimplemented!() },
        0xb1 => { unimplemented!() },
        0xb2 => { unimplemented!() },
        0xb3 => { unimplemented!() },
        0xb4 => { unimplemented!() },
        0xb5 => { unimplemented!() },
        0xb6 => { unimplemented!() },
        0xb7 => { unimplemented!() },
        0xb8 => { unimplemented!() },
        0xb9 => { unimplemented!() },
        0xba => { unimplemented!() },
        0xbb => { unimplemented!() },
        0xbc => { unimplemented!() },
        0xbd => { unimplemented!() },
        0xbe => { unimplemented!() },
        0xbf => { unimplemented!() },
        0xc0 => { unimplemented!() },
        0xc1 => { unimplemented!() },
        0xc2 => { unimplemented!() },
        0xc3 => { unimplemented!() },
        0xc4 => { unimplemented!() },
        0xc5 => { unimplemented!() },
        0xc6 => { unimplemented!() },
        0xc7 => { unimplemented!() },
        0xc8 => { unimplemented!() },
        0xc9 => { unimplemented!() },
        0xca => { unimplemented!() },
        0xcb => { unimplemented!() },
        0xcc => { unimplemented!() },
        0xcd => { unimplemented!() },
        0xce => { unimplemented!() },
        0xcf => { unimplemented!() },
        0xd0 => { unimplemented!() },
        0xd1 => { unimplemented!() },
        0xd2 => { unimplemented!() },
        0xd3 => { unimplemented!() },
        0xd4 => { unimplemented!() },
        0xd5 => { unimplemented!() },
        0xd6 => { unimplemented!() },
        0xd7 => { unimplemented!() },
        0xd8 => { unimplemented!() },
        0xd9 => { unimplemented!() },
        0xda => { unimplemented!() },
        0xdb => { unimplemented!() },
        0xdc => { unimplemented!() },
        0xdd => { unimplemented!() },
        0xde => { unimplemented!() },
        0xdf => { unimplemented!() },
        0xe0 => { unimplemented!() },
        0xe1 => { unimplemented!() },
        0xe2 => { unimplemented!() },
        0xe3 => { unimplemented!() },
        0xe4 => { unimplemented!() },
        0xe5 => { unimplemented!() },
        0xe6 => { unimplemented!() },
        0xe7 => { unimplemented!() },
        0xe8 => { unimplemented!() },
        0xe9 => { unimplemented!() },
        0xea => { unimplemented!() },
        0xeb => { unimplemented!() },
        0xec => { unimplemented!() },
        0xed => { unimplemented!() },
        0xee => { unimplemented!() },
        0xef => { unimplemented!() },
        0xf0 => { unimplemented!() },
        0xf1 => { unimplemented!() },
        0xf2 => { unimplemented!() },
        0xf3 => { unimplemented!() },
        0xf4 => { unimplemented!() },
        0xf5 => { unimplemented!() },
        0xf6 => { unimplemented!() },
        0xf7 => { unimplemented!() },
        0xf8 => { unimplemented!() },
        0xf9 => { unimplemented!() },
        0xfa => { unimplemented!() },
        0xfb => { unimplemented!() },
        0xfc => { unimplemented!() },
        0xfd => { unimplemented!() },
        0xfe => { unimplemented!() },
        0xff => { unimplemented!() },
        _ => {}
    }
}

/// XOR generic function
fn xor(gb: &mut GameBoy, reg: Register8) {
    let mut acc = gb.cpu.get_8(Register8::A);
    acc ^= gb.cpu.get_8(reg);
    gb.cpu.set_8(Register8::A, acc);
    gb.cpu.reset_flags();
    match acc {
        0 => gb.cpu.set_flag(Flag::Z, true),
        _ => gb.cpu.set_flag(Flag::Z, false),
    }
    gb.cpu.inc_pc(1);
}

/// OR generic function
fn or(gb: &mut GameBoy, reg: Register8) {
    let mut acc = gb.cpu.get_8(Register8::A);
    acc |= gb.cpu.get_8(reg);
    gb.cpu.set_8(Register8::A, acc);
    gb.cpu.reset_flags();
    match acc {
        0 => gb.cpu.set_flag(Flag::Z, true),
        _ => gb.cpu.set_flag(Flag::Z, false),
    }
    gb.cpu.inc_pc(1);
}

/// AND generic function
fn and(gb: &mut GameBoy, reg: Register8) {
    let mut acc = gb.cpu.get_8(Register8::A);
    acc &= gb.cpu.get_8(reg);
    gb.cpu.set_8(Register8::A, acc);
    gb.cpu.reset_flags();
    match acc {
        0 => gb.cpu.set_flag(Flag::Z, true),
        _ => gb.cpu.set_flag(Flag::Z, false),
    }
    gb.cpu.inc_pc(1);
}

/// LD BC, nn 0x01
fn ld_bc_nn(gb: &mut GameBoy) {
    let v: u16 = gb.cartridge.read_word(gb.cpu.get_16(Register16::PC) + 1);
    gb.cpu.set_16(Register16::BC, v);
    gb.cpu.inc_pc(3);

}

/// LD (BC), a 0x02
fn ld_bcp_a(gb: &mut GameBoy) {
    gb.mem.write_byte(gb.cpu.get_16(Register16::BC), gb.cpu.get_8(Register8::A));
    gb.cpu.inc_pc(1);
}

/// INC BC, 0x03
fn inc_bc(gb: &mut GameBoy) {
    gb.cpu.inc_16(Register16::BC);
    gb.cpu.inc_pc(1);
}

/// INC B, 0x04
fn inc_b(gb: &mut GameBoy) {
    gb.cpu.inc_8(Register8::B);
    gb.cpu.inc_pc(1);
}

/// LD SP, nn 0x31
fn ld_sp_nn(gb: &mut GameBoy) {
    let v: u16 = gb.cartridge.read_word(gb.cpu.get_16(Register16::PC) + 1);
    gb.cpu.set_16(Register16::SP, v);
    gb.cpu.inc_pc(3);
}
<commit_msg>Oups ! Can't debug with unimplemented!()<commit_after>use cpu::{Flag, Register8, Register16};
use GameBoy;

/// Iterate the ROM
pub fn decode(gb: &mut GameBoy) {
    for i in 0..gb.cartridge.size() {
        opcode_router(gb.cartridge.read_byte(i as u16), gb);
    }
    println!("{:?}", gb.cpu);
}

/// Map Opcode to function
fn opcode_router(opcode: u8, gb: &mut GameBoy) {
    match opcode {
        0x00 => {},
        0x01 => { ld_bc_nn(gb) },
        0x02 => { ld_bcp_a(gb) },
        0x03 => { inc_bc(gb) },
        0x04 => { inc_bc(gb) },
        0x05 => {  },
        0x06 => {  },
        0x07 => {  },
        0x08 => {  },
        0x09 => {  },
        0x0a => {  },
        0x0b => {  },
        0x0c => {  },
        0x0d => {  },
        0x0e => {  },
        0x0f => {  },
        0x10 => {  },
        0x11 => {  },
        0x12 => {  },
        0x13 => {  },
        0x14 => {  },
        0x15 => {  },
        0x16 => {  },
        0x17 => {  },
        0x18 => {  },
        0x19 => {  },
        0x1a => {  },
        0x1b => {  },
        0x1c => {  },
        0x1d => {  },
        0x1e => {  },
        0x1f => {  },
        0x20 => {  },
        0x21 => {  },
        0x22 => {  },
        0x23 => {  },
        0x24 => {  },
        0x25 => {  },
        0x26 => {  },
        0x27 => {  },
        0x28 => {  },
        0x29 => {  },
        0x2a => {  },
        0x2b => {  },
        0x2c => {  },
        0x2d => {  },
        0x2e => {  },
        0x2f => {  },
        0x30 => {  },
        0x31 => { ld_sp_nn(gb) },
        0x32 => {  },
        0x33 => {  },
        0x34 => {  },
        0x35 => {  },
        0x36 => {  },
        0x37 => {  },
        0x38 => {  },
        0x39 => {  },
        0x3a => {  },
        0x3b => {  },
        0x3c => {  },
        0x3d => {  },
        0x3e => {  },
        0x3f => {  },
        0x40 => {  },
        0x41 => {  },
        0x42 => {  },
        0x43 => {  },
        0x44 => {  },
        0x45 => {  },
        0x46 => {  },
        0x47 => {  },
        0x48 => {  },
        0x49 => {  },
        0x4a => {  },
        0x4b => {  },
        0x4c => {  },
        0x4d => {  },
        0x4e => {  },
        0x4f => {  },
        0x50 => {  },
        0x51 => {  },
        0x52 => {  },
        0x53 => {  },
        0x54 => {  },
        0x55 => {  },
        0x56 => {  },
        0x57 => {  },
        0x58 => {  },
        0x59 => {  },
        0x5a => {  },
        0x5b => {  },
        0x5c => {  },
        0x5d => {  },
        0x5e => {  },
        0x5f => {  },
        0x60 => {  },
        0x61 => {  },
        0x62 => {  },
        0x63 => {  },
        0x64 => {  },
        0x65 => {  },
        0x66 => {  },
        0x67 => {  },
        0x68 => {  },
        0x69 => {  },
        0x6a => {  },
        0x6b => {  },
        0x6c => {  },
        0x6d => {  },
        0x6e => {  },
        0x6f => {  },
        0x70 => {  },
        0x71 => {  },
        0x72 => {  },
        0x73 => {  },
        0x74 => {  },
        0x75 => {  },
        0x76 => {  },
        0x77 => {  },
        0x78 => {  },
        0x79 => {  },
        0x7a => {  },
        0x7b => {  },
        0x7c => {  },
        0x7d => {  },
        0x7e => {  },
        0x7f => {  },
        0x80 => {  },
        0x81 => {  },
        0x82 => {  },
        0x83 => {  },
        0x84 => {  },
        0x85 => {  },
        0x86 => {  },
        0x87 => {  },
        0x88 => {  },
        0x89 => {  },
        0x8a => {  },
        0x8b => {  },
        0x8c => {  },
        0x8d => {  },
        0x8e => {  },
        0x8f => {  },
        0x90 => {  },
        0x91 => {  },
        0x92 => {  },
        0x93 => {  },
        0x94 => {  },
        0x95 => {  },
        0x96 => {  },
        0x97 => {  },
        0x98 => {  },
        0x99 => {  },
        0x9a => {  },
        0x9b => {  },
        0x9c => {  },
        0x9d => {  },
        0x9e => {  },
        0x9f => {  },
        0xa0 => {  },
        0xa1 => {  },
        0xa2 => {  },
        0xa3 => {  },
        0xa4 => {  },
        0xa5 => {  },
        0xa6 => {  },
        0xa7 => {  },
        0xa8 => {  },
        0xa9 => {  },
        0xaa => {  },
        0xab => {  },
        0xac => {  },
        0xad => {  },
        0xae => {  },
        0xaf => { xor(gb, Register8::A) }
        0xb0 => {  },
        0xb1 => {  },
        0xb2 => {  },
        0xb3 => {  },
        0xb4 => {  },
        0xb5 => {  },
        0xb6 => {  },
        0xb7 => {  },
        0xb8 => {  },
        0xb9 => {  },
        0xba => {  },
        0xbb => {  },
        0xbc => {  },
        0xbd => {  },
        0xbe => {  },
        0xbf => {  },
        0xc0 => {  },
        0xc1 => {  },
        0xc2 => {  },
        0xc3 => {  },
        0xc4 => {  },
        0xc5 => {  },
        0xc6 => {  },
        0xc7 => {  },
        0xc8 => {  },
        0xc9 => {  },
        0xca => {  },
        0xcb => {  },
        0xcc => {  },
        0xcd => {  },
        0xce => {  },
        0xcf => {  },
        0xd0 => {  },
        0xd1 => {  },
        0xd2 => {  },
        0xd3 => {  },
        0xd4 => {  },
        0xd5 => {  },
        0xd6 => {  },
        0xd7 => {  },
        0xd8 => {  },
        0xd9 => {  },
        0xda => {  },
        0xdb => {  },
        0xdc => {  },
        0xdd => {  },
        0xde => {  },
        0xdf => {  },
        0xe0 => {  },
        0xe1 => {  },
        0xe2 => {  },
        0xe3 => {  },
        0xe4 => {  },
        0xe5 => {  },
        0xe6 => {  },
        0xe7 => {  },
        0xe8 => {  },
        0xe9 => {  },
        0xea => {  },
        0xeb => {  },
        0xec => {  },
        0xed => {  },
        0xee => {  },
        0xef => {  },
        0xf0 => {  },
        0xf1 => {  },
        0xf2 => {  },
        0xf3 => {  },
        0xf4 => {  },
        0xf5 => {  },
        0xf6 => {  },
        0xf7 => {  },
        0xf8 => {  },
        0xf9 => {  },
        0xfa => {  },
        0xfb => {  },
        0xfc => {  },
        0xfd => {  },
        0xfe => {  },
        0xff => {  },
        _ => {}
    }
}

/// XOR generic function
fn xor(gb: &mut GameBoy, reg: Register8) {
    let mut acc = gb.cpu.get_8(Register8::A);
    acc ^= gb.cpu.get_8(reg);
    gb.cpu.set_8(Register8::A, acc);
    gb.cpu.reset_flags();
    match acc {
        0 => gb.cpu.set_flag(Flag::Z, true),
        _ => gb.cpu.set_flag(Flag::Z, false),
    }
    gb.cpu.inc_pc(1);
}

/// OR generic function
fn or(gb: &mut GameBoy, reg: Register8) {
    let mut acc = gb.cpu.get_8(Register8::A);
    acc |= gb.cpu.get_8(reg);
    gb.cpu.set_8(Register8::A, acc);
    gb.cpu.reset_flags();
    match acc {
        0 => gb.cpu.set_flag(Flag::Z, true),
        _ => gb.cpu.set_flag(Flag::Z, false),
    }
    gb.cpu.inc_pc(1);
}

/// AND generic function
fn and(gb: &mut GameBoy, reg: Register8) {
    let mut acc = gb.cpu.get_8(Register8::A);
    acc &= gb.cpu.get_8(reg);
    gb.cpu.set_8(Register8::A, acc);
    gb.cpu.reset_flags();
    match acc {
        0 => gb.cpu.set_flag(Flag::Z, true),
        _ => gb.cpu.set_flag(Flag::Z, false),
    }
    gb.cpu.inc_pc(1);
}

/// LD BC, nn 0x01
fn ld_bc_nn(gb: &mut GameBoy) {
    let v: u16 = gb.cartridge.read_word(gb.cpu.get_16(Register16::PC) + 1);
    gb.cpu.set_16(Register16::BC, v);
    gb.cpu.inc_pc(3);

}

/// LD (BC), a 0x02
fn ld_bcp_a(gb: &mut GameBoy) {
    gb.mem.write_byte(gb.cpu.get_16(Register16::BC), gb.cpu.get_8(Register8::A));
    gb.cpu.inc_pc(1);
}

/// INC BC, 0x03
fn inc_bc(gb: &mut GameBoy) {
    gb.cpu.inc_16(Register16::BC);
    gb.cpu.inc_pc(1);
}

/// INC B, 0x04
fn inc_b(gb: &mut GameBoy) {
    gb.cpu.inc_8(Register8::B);
    gb.cpu.inc_pc(1);
}

/// LD SP, nn 0x31
fn ld_sp_nn(gb: &mut GameBoy) {
    let v: u16 = gb.cartridge.read_word(gb.cpu.get_16(Register16::PC) + 1);
    gb.cpu.set_16(Register16::SP, v);
    gb.cpu.inc_pc(3);
}
<|endoftext|>


<commit_before>// Find Cargo's source cache directory for a crate
use super::es;
use std::fs;
use es::traits::*;
use std::env;
use std::path::{Path,PathBuf};
use std::collections::HashMap;

lazy_static! {
    pub static ref RUSTUP_LIB: String = shell("rustc --print sysroot") + "/lib";
    pub static ref UNSTABLE: bool = RUSTUP_LIB.find("stable").is_none();
}

pub fn shell(cmd: &str) -> String {
    let o = ::std::process::Command::new(if cfg!(windows) {"cmd.exe"} else {"sh"})
     .arg(if cfg!(windows) {"/c"} else {"-c"})
     .arg(&format!("{} 2>&1",cmd))
     .output()
     .expect("failed to execute shell");
    String::from_utf8(o.stdout).expect("not UTF-8 output").trim_right_matches('\n').to_string()
}

pub fn proper_crate_name(crate_name: &str) -> String {
    crate_name.replace('-',"_")
}

pub fn path_file_name(p: &Path) -> String {
    if let Some(file_name) = p.file_name() {
        file_name.to_string_lossy().to_string()
    } else
    if let Ok(full_path) = p.canonicalize() {
        path_file_name(&full_path)
    } else {
        p.to_string_lossy().to_string()
    }
}

// there's a Crate for This...
fn semver_i (s: &str) -> u64 {
    let v = s.split('.').filter_map(|s| s.parse::<u64>().ok()).to_vec();
    (((v[0] << 8) + v[1]) << 8) + v[2]
}

pub fn cargo_home() -> PathBuf {
    if let Ok(home) = env::var("CARGO_HOME") { // set in cargo runs
        home.into()
    } else {
        env::home_dir().or_die("no home!").join(".cargo")
    }
}

pub fn cache_path(crate_name: &str) -> PathBuf {
    let home = cargo_home();
    let crate_root = PathBuf::from(home.join("registry/src"));
    // actual crate source is in some fairly arbitrary subdirectory of this
    let mut crate_dir = crate_root.clone();
    crate_dir.push(es::files(&crate_root).next().or_die("no crate cache directory"));

    let mut crates = Vec::new();
    for (p,d) in es::paths(&crate_dir) {
        if ! d.is_dir() { continue; }
        let filename = path_file_name(&p);
        if let Some(endc) = filename.rfind('-') {
            if &filename[0..endc] == crate_name {
                crates.push((p,semver_i(&filename[endc+1..])));
            }
        }
    }
    // crate versions in ascending order by semver rules
    crates.sort_by(|a,b| a.1.cmp(&b.1));
    crates.pop().or_die(&format!("no such crate: {}",crate_name)).0
}

// Very hacky stuff - we want the ACTUAL crate name, not the project name
// So look just past [package] and scrape the name...
fn crate_name(cargo_toml: &Path) -> String {
    let name_line = es::lines(es::open(cargo_toml))
        .skip_while(|line| line.trim() != "[package]")
        .skip(1)
        .skip_while(|line| ! line.starts_with("name "))
        .next().or_die("totally fked Cargo.toml");
    let idx = name_line.find('"').or_die("no name?");
    (&name_line[(idx+1)..(name_line.len()-1)]).into()

}

pub fn crate_path(file: &Path, first_arg: &str) -> Result<(PathBuf,String),String> {
    if file.exists() {
        if file.is_dir() { // assumed to be Cargo directory
            let cargo_toml = file.join("Cargo.toml");
            if ! cargo_toml.exists() {
                return Err(format!("not a Cargo project directory: {}",file.display()));
            }
            Ok((file.join("src").join("lib.rs"), crate_name(&cargo_toml)))
        } else { // should be just a Rust source file
            if file.extension().or_die("expecting extension") != "rs" {
                return Err("expecting Rust source file".into());
            }
            let name = path_file_name(&file.with_extension(""));
            Ok((file.to_path_buf(), name))
        }
    } else {
        let project_dir = cache_path(first_arg);
        let cargo_toml = project_dir.join("Cargo.toml");
        Ok((project_dir.join("src").join("lib.rs"), crate_name(&cargo_toml)))
    }
}

pub fn full_crate_name(deps: &Path, crate_name: &str) -> Option<String> {
    let mut res = Vec::new();
    let patt = format!("lib{}-",crate_name);
    for entry in fs::read_dir(deps).or_die("cannot access dependencies dir") {
        let entry = entry.or_die("cannot access deps entry");
        let path = entry.path();
        if let Some(f) = path.file_name() {
            let name = f.to_string_lossy();
            //println!("got {}",name);
            if name.starts_with(&patt) {
                let cname = &name[3..(name.len()-5) ];
                res.push(cname.to_string());
            }
        }
    }
    res.pop()
}

pub type Crates = HashMap<String,Vec<PathBuf>>;

pub fn get_cache_deps(deps: &Path) ->  Crates {
    let mut res: Crates = HashMap::new();
    for entry in fs::read_dir(deps).or_die("cannot access dependencies dir") {
        let entry = entry.or_die("cannot access deps entry");
        let path = entry.path();
        if let Some(f) = path.file_name() {
            let rlib = f.to_string_lossy();
            // pull out the crate name
            if let Some(idx) = rlib.rfind('-') {
                let name = &rlib[3..idx];
                let v = res.entry(name.into())
                    .or_insert_with(|| Vec::new());
                v.push(path.clone());
            }
        }
    }
    res
}

pub fn remove_duplicates(crates: Crates, do_clean: bool) {
    for (name,paths) in crates {
        if paths.len() > 1 {
            // Sort the paths in ascending time of modification
            let mut mpaths: Vec<_> = paths.into_iter()
                .map(|p| {
                    let time = p.metadata().unwrap().modified().unwrap();
                    (p,time)
                }).collect();
            mpaths.sort_by(|a,b| a.1.cmp(&b.1));

            // ignore the latest, and delete the rest

            if do_clean {
                mpaths.pop();
                println!("crate {} removing {} items",name,mpaths.len());
                for (p,_) in mpaths {
                    fs::remove_file(&p).expect("can't remove rlib");
                }
            } else {
                println!("crate {} has {} items",name,mpaths.len());
                for (p,_) in mpaths {
                    println!("{:?}",p);
                }
            }
        }
    }
}

pub fn remove_duplicate_cache_deps(deps: &Path, do_clean: bool) {
    let deps = get_cache_deps(deps);
    remove_duplicates(deps,do_clean);
}

fn inside_quotes(s: &str) -> String {
    s.chars()
        .skip_while(|&c| c != '"').skip(1)
        .take_while(|&c| c != '"').collect()
}

pub fn show_deps(stat_cache: &Path) {
    let cargo_lock = stat_cache.join("Cargo.lock");

    let f = es::open(cargo_lock);
    let res = es::lines(f)
        .skip_while(|line| ! line.starts_with("dependencies"))
        .skip(1)
        .take_while(|line| ! line.starts_with(']'))
        .map(|line| {
           let line = inside_quotes(&line);
           let toks = line.split_whitespace().take(2).to_vec();
           (toks[0].to_string(), toks[1].to_string())
         })
        .to_vec();

    for (name,vs) in res {
        println!("{} - {}",name,vs);
    }
}
<commit_msg>we track stable/unstable and use semver to find source cache dir of latest version<commit_after>// Find Cargo's source cache directory for a crate
use super::es;

use std::env;
use std::path::{Path,PathBuf};

use es::traits::*;
use semver::Version;

lazy_static! {
    pub static ref RUSTUP_LIB: String = es::shell("rustc --print sysroot") + "/lib";
    pub static ref UNSTABLE: bool = RUSTUP_LIB.find("stable").is_none();
}

pub fn proper_crate_name(crate_name: &str) -> String {
    crate_name.replace('-',"_")
}

pub fn path_file_name(p: &Path) -> String {
    if let Some(file_name) = p.file_name() {
        file_name.to_string_lossy().to_string()
    } else
    if let Ok(full_path) = p.canonicalize() {
        path_file_name(&full_path)
    } else {
        p.to_string_lossy().to_string()
    }
}

pub fn cargo_home() -> PathBuf {
    if let Ok(home) = env::var("CARGO_HOME") { // set in cargo runs
        home.into()
    } else {
        env::home_dir().or_die("no home!").join(".cargo")
    }
}

// looks at the Cargo source cache and returns the directory
// of the _latest_ version of a crate.
pub fn cache_path(crate_name: &str) -> PathBuf {
    let home = cargo_home();
    let crate_root = PathBuf::from(home.join("registry/src"));
    // actual crate source is in some fairly arbitrary subdirectory of this
    let mut crate_dir = crate_root.clone();
    crate_dir.push(es::files(&crate_root).next().or_die("no crate cache directory"));

    let mut crates = Vec::new();
    for (p,d) in es::paths(&crate_dir) {
        if ! d.is_dir() { continue; }
        let filename = path_file_name(&p);
        if let Some(endc) = filename.rfind('-') {
            if &filename[0..endc] == crate_name {
                let vs = Version::parse(&filename[endc+1..]).or_die("bad semver");
                crates.push((p,vs));
            }
        }
    }
    // crate versions in ascending order by semver rules
    crates.sort_by(|a,b| a.1.cmp(&b.1));
    crates.pop().or_die(&format!("no such crate: {}",crate_name)).0
}

// Very hacky stuff - we want the ACTUAL crate name, not the directory/repo name
// So look just past [package] and scrape the name...
fn crate_name(cargo_toml: &Path) -> String {
    let name_line = es::lines(es::open(cargo_toml))
        .skip_while(|line| line.trim() != "[package]")
        .skip(1)
        .skip_while(|line| ! line.starts_with("name "))
        .next().or_die("totally fked Cargo.toml");
    let idx = name_line.find('"').or_die("no name?");
    (&name_line[(idx+1)..(name_line.len()-1)]).into()
}

pub fn crate_path(file: &Path, first_arg: &str) -> Result<(PathBuf,String),String> {
    if file.exists() {
        if file.is_dir() { // assumed to be Cargo directory
            let cargo_toml = file.join("Cargo.toml");
            if ! cargo_toml.exists() {
                return Err(format!("not a Cargo project directory: {}",file.display()));
            }
            Ok((file.join("src").join("lib.rs"), crate_name(&cargo_toml)))
        } else { // should be just a Rust source file
            if file.extension().or_die("expecting extension") != "rs" {
                return Err("expecting Rust source file".into());
            }
            let name = path_file_name(&file.with_extension(""));
            Ok((file.to_path_buf(), name))
        }
    } else {
        let project_dir = cache_path(first_arg);
        let cargo_toml = project_dir.join("Cargo.toml");
        Ok((project_dir.join("src").join("lib.rs"), crate_name(&cargo_toml)))
    }
}

<|endoftext|>


<commit_before>/*!

Rust MIR: a lowered representation of Rust. Also: an experiment!

*/

#![feature(nll)]
#![feature(in_band_lifetimes)]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
#![feature(drain_filter)]
#![feature(exhaustive_patterns)]
#![feature(iter_order_by)]
#![feature(never_type)]
#![feature(specialization)]
#![feature(trusted_len)]
#![feature(try_blocks)]
#![feature(associated_type_bounds)]
#![feature(range_is_empty)]
#![feature(stmt_expr_attributes)]
#![feature(trait_alias)]
#![recursion_limit = "256"]

#[macro_use]
extern crate log;
#[macro_use]
extern crate rustc;

mod borrow_check;
pub mod const_eval;
pub mod dataflow;
pub mod interpret;
pub mod monomorphize;
mod shim;
pub mod transform;
pub mod util;

use rustc::ty::query::Providers;

pub fn provide(providers: &mut Providers<'_>) {
    borrow_check::provide(providers);
    const_eval::provide(providers);
    shim::provide(providers);
    transform::provide(providers);
    monomorphize::partitioning::provide(providers);
    providers.const_eval_validated = const_eval::const_eval_validated_provider;
    providers.const_eval_raw = const_eval::const_eval_raw_provider;
    providers.const_caller_location = const_eval::const_caller_location;
    providers.const_field = |tcx, param_env_and_value| {
        let (param_env, (value, field)) = param_env_and_value.into_parts();
        const_eval::const_field(tcx, param_env, None, field, value)
    };
    providers.destructure_const = |tcx, param_env_and_value| {
        let (param_env, value) = param_env_and_value.into_parts();
        const_eval::destructure_const(tcx, param_env, value)
    };
}
<commit_msg>MIR is not an experiment anymore<commit_after>/*!

Rust MIR: a lowered representation of Rust.

*/

#![feature(nll)]
#![feature(in_band_lifetimes)]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
#![feature(drain_filter)]
#![feature(exhaustive_patterns)]
#![feature(iter_order_by)]
#![feature(never_type)]
#![feature(specialization)]
#![feature(trusted_len)]
#![feature(try_blocks)]
#![feature(associated_type_bounds)]
#![feature(range_is_empty)]
#![feature(stmt_expr_attributes)]
#![feature(trait_alias)]
#![recursion_limit = "256"]

#[macro_use]
extern crate log;
#[macro_use]
extern crate rustc;

mod borrow_check;
pub mod const_eval;
pub mod dataflow;
pub mod interpret;
pub mod monomorphize;
mod shim;
pub mod transform;
pub mod util;

use rustc::ty::query::Providers;

pub fn provide(providers: &mut Providers<'_>) {
    borrow_check::provide(providers);
    const_eval::provide(providers);
    shim::provide(providers);
    transform::provide(providers);
    monomorphize::partitioning::provide(providers);
    providers.const_eval_validated = const_eval::const_eval_validated_provider;
    providers.const_eval_raw = const_eval::const_eval_raw_provider;
    providers.const_caller_location = const_eval::const_caller_location;
    providers.const_field = |tcx, param_env_and_value| {
        let (param_env, (value, field)) = param_env_and_value.into_parts();
        const_eval::const_field(tcx, param_env, None, field, value)
    };
    providers.destructure_const = |tcx, param_env_and_value| {
        let (param_env, value) = param_env_and_value.into_parts();
        const_eval::destructure_const(tcx, param_env, value)
    };
}
<|endoftext|>