<commit_before>use std::env;
use std::thread;
use std::process;
use renderer::Renderer;
use std::io::{self, Write};
use std::sync::mpsc::{self, TryRecvError};

use messenger;
use app::TurtleApp;
use query::{Query, DrawingCommand, Request, StateUpdate, Response};
use {Event};

/// Start the turtle window in advance
///
/// You must call this function at the beginning of `main()` if you do not create the
/// turtle immediately using [`Turtle::new()`].
///
/// It's a good idea to call this function before any other code runs in `main()`. Programs that
/// parse command line arguments or look at environment variables may **fail** to start if this
/// function is not called right at the beginning of the program. Programs that perform any
/// expensive computations may experience delayed start up problems unless they call this
/// function first.
///
/// The [`Turtle::new()`] method will call this function for you so that you don't need to worry
/// about this unless you are doing something before that.
///
/// # Example
/// ```rust,no_run
/// # #![allow(unused_variables, unused_mut)]
/// extern crate turtle;
/// use turtle::Turtle;
///
/// fn main() {
///     // Initializes the turtle renderer first so that there is less delay when a Turtle
///     // is created and so that there are no conflicts with command line arguments or
///     // environment variables.
///     // Not required if Turtle::new() is already at the top of main.
///     turtle::start();
///
///     // Do all kinds of expensive work here...
///     // Feel free to check environment variables, command line arguments, etc.
///
///     // Create the turtle when you are ready
///     // Turtle::new() will also call start(), but calling it twice doesn't matter
///     let mut turtle = Turtle::new();
///     // Do things with the turtle...
/// }
/// ```
///
/// [`Turtle::new()`]: struct.Turtle.html#method.new
pub fn start() {
    // If this environment variable is present, this process is taken over so that no other
    // code runs after main(). This allows us to ship one executable that appears to
    // have two separate processes.
    // We run the renderer loop and then immediately exit.
    if env::var("RUN_TURTLE_CANVAS").unwrap_or_else(|_| "".to_owned()) == "true" {
        // This code MUST be run on the main thread.

        // Run the renderer process
        main();
        unreachable!("bug: renderer loop did not exit after finishing");
    }
}

/// Run the renderer process in the current thread
///
/// This function must run in the main thread ONLY
fn main() {
    let app = TurtleApp::new();
    let read_only = app.read_only();
    let (drawing_tx, drawing_rx) = mpsc::channel();
    let (events_tx, events_rx) = mpsc::channel();

    // The running channel is entirely for checking if the other thread is still active.
    // We need to check because while we can exit while that thread is still running, we want
    // any errors caused in that thread to be reported.
    let (running_tx, running_rx) = mpsc::channel();
    let handle = thread::spawn(move || {
        read_queries_forever(app, drawing_tx, events_rx, running_tx);
    });

    // Renderer MUST run on the main thread or else it will panic on MacOS
    Renderer::new().run(drawing_rx, events_tx, read_only);

    // Quit immediately when the window is closed

    // Check if an error has occurred on the thread
    match running_rx.try_recv() {
        Ok(_) => unreachable!("bug: running channel should always be empty"),
        // The thread was still running, exit normally
        Err(mpsc::TryRecvError::Empty) => process::exit(0),
        Err(mpsc::TryRecvError::Disconnected) => match handle.join() {
            Ok(_) => process::exit(0),
            // The other thread must have panicked
            Err(_) => process::exit(1),
        },
    }
}

/// Continuously read queries from stdin and send them to the renderer
fn read_queries_forever(
    mut app: TurtleApp,
    drawing_tx: mpsc::Sender<DrawingCommand>,
    events_rx: mpsc::Receiver<Event>,
    // Intentionally unused. Only used to tell if thread has already quit.
    _running_tx: mpsc::Sender<()>,
) {
    // Read queries from the turtle process
    let stdin = io::stdin();
    let mut stdout = io::stdout();
    messenger::read_forever(
        stdin,
        "bug: unable to read data from stdin",
        "bug: failed to read command from turtle process",
        |query| handle_query(query, &mut app, &events_rx, &drawing_tx).and_then(|resp| match resp {
            Some(ref response) => send_response(&mut stdout, response),
            None => Ok(()),
        }),
    );
}

/// We want to expose this specifically for tests so that tests can mimic the behaviour of the
/// server without actually spawning a new process. See renderer_process.rs for more details.
#[cfg(any(feature = "test", test))]
pub(crate) fn handle_query_for_test_use_only(
    query: Query,
    app: &mut TurtleApp,
    events_rx: &mpsc::Receiver<Event>,
    drawing_tx: &mpsc::Sender<DrawingCommand>,
) -> Result<Option<Response>, ()> {
    handle_query(query, app, events_rx, drawing_tx)
}

/// Returns the appropriate Response (if any) to the given Query
///
/// Returns Err(()) if it is time to quit because we have been disconnected.
fn handle_query(
    query: Query,
    app: &mut TurtleApp,
    events_rx: &mpsc::Receiver<Event>,
    drawing_tx: &mpsc::Sender<DrawingCommand>,
) -> Result<Option<Response>, ()> {
    match query {
        Query::Request(req) => handle_request(req, &app, &events_rx),
        Query::Update(update) => handle_update(update, app),
        Query::Drawing(cmd) => drawing_tx.send(cmd).map(|_| None).map_err(|_| ()),
    }
}

fn handle_request(
    request: Request,
    app: &TurtleApp,
    events_rx: &mpsc::Receiver<Event>,
) -> Result<Option<Response>, ()> {
    use self::Request::*;
    Ok(Some(match request {
        TurtleState => Response::TurtleState((*app.turtle()).clone()),
        DrawingState => Response::DrawingState((*app.drawing()).clone()),
        Event => Response::Event(match events_rx.try_recv() {
            Ok(event) => Some(event),
            Err(TryRecvError::Empty) => None,
            Err(TryRecvError::Disconnected) => return Err(()),
        }),
    }))
}

fn handle_update(
    update: StateUpdate,
    app: &mut TurtleApp,
) -> Result<Option<Response>, ()> {
    use self::StateUpdate::*;
    match update {
        TurtleState(turtle) => *app.turtle_mut() = turtle,
        DrawingState(drawing) => *app.drawing_mut() = drawing,
        TemporaryPath(path) => app.set_temporary_path(path),
    }

    Ok(None)
}

/// Sends a response to stdout
fn send_response<W: Write>(writer: W, response: &Response) -> Result<(), ()> {
    messenger::send(writer, response, "bug: unable to write final newline when sending response")
}
<commit_msg>More detailed docs in server::start<commit_after>use std::env;
use std::thread;
use std::process;
use std::io::{self, Write};
use std::sync::mpsc::{self, TryRecvError};

use messenger;
use app::TurtleApp;
use renderer::Renderer;
use query::{Query, DrawingCommand, Request, StateUpdate, Response};
use {Event};

/// Start the turtle window in advance
///
/// You must call this function at the beginning of `main()` if you do not create the
/// turtle immediately using [`Turtle::new()`].
///
/// It's a good idea to call this function before any other code runs in `main()`. Programs that
/// parse command line arguments or look at environment variables may **fail** to start if this
/// function is not called right at the beginning of the program. Programs that perform any
/// expensive computations may experience delayed start up problems unless they call this
/// function first.
///
/// The [`Turtle::new()`] method will call this function for you so that you don't need to worry
/// about this unless you are doing something before that.
///
/// # Example
/// ```rust,no_run
/// # #![allow(unused_variables, unused_mut)]
/// extern crate turtle;
/// use turtle::Turtle;
///
/// fn main() {
///     // Initializes the turtle renderer first so that there is less delay when a Turtle
///     // is created and so that there are no conflicts with command line arguments or
///     // environment variables.
///     // Not required if Turtle::new() is already at the top of main.
///     turtle::start();
///
///     // Do all kinds of expensive work here...
///     // Feel free to check environment variables, command line arguments, etc.
///
///     // Create the turtle when you are ready
///     // Turtle::new() will also call start(), but calling it twice doesn't matter
///     let mut turtle = Turtle::new();
///     // Do things with the turtle...
/// }
/// ```
///
/// [`Turtle::new()`]: struct.Turtle.html#method.new
pub fn start() {
    // If this environment variable is present, this process is taken over so that no other
    // code runs after main(). This allows us to ship one executable that appears to
    // have two separate processes.
    // This implementation detail is why we request that users run start() at the beginning of
    // their programs. When we spawn the same executable, we don't pass along any environment,
    // input or command line arguments. That means that the user *needs* to run start() first or
    // else their program won't be able to run at all. This is a tradeoff of this design decision.
    if env::var("RUN_TURTLE_CANVAS").unwrap_or_else(|_| "".to_owned()) == "true" {
        // This code MUST be run on the main thread.

        // Run the renderer process
        main();
        unreachable!("bug: renderer loop did not exit after finishing");
    }
}

/// Run the renderer process in the current thread
///
/// This function must run in the main thread ONLY
fn main() {
    let app = TurtleApp::new();
    let read_only = app.read_only();
    let (drawing_tx, drawing_rx) = mpsc::channel();
    let (events_tx, events_rx) = mpsc::channel();

    // The running channel is entirely for checking if the other thread is still active.
    // We need to check because while we can exit while that thread is still running, we want
    // any errors caused in that thread to be reported.
    let (running_tx, running_rx) = mpsc::channel();
    let handle = thread::spawn(move || {
        read_queries_forever(app, drawing_tx, events_rx, running_tx);
    });

    // Renderer MUST run on the main thread or else it will panic on MacOS
    Renderer::new().run(drawing_rx, events_tx, read_only);

    // Quit immediately when the window is closed

    // Check if an error has occurred on the thread
    match running_rx.try_recv() {
        Ok(_) => unreachable!("bug: running channel should always be empty"),
        // The thread was still running, exit normally
        Err(mpsc::TryRecvError::Empty) => process::exit(0),
        Err(mpsc::TryRecvError::Disconnected) => match handle.join() {
            Ok(_) => process::exit(0),
            // The other thread must have panicked
            Err(_) => process::exit(1),
        },
    }
}

/// Continuously read queries from stdin and send them to the renderer
fn read_queries_forever(
    mut app: TurtleApp,
    drawing_tx: mpsc::Sender<DrawingCommand>,
    events_rx: mpsc::Receiver<Event>,
    // Intentionally unused. Only used to tell if thread has already quit.
    _running_tx: mpsc::Sender<()>,
) {
    // Read queries from the turtle process
    let stdin = io::stdin();
    let mut stdout = io::stdout();
    messenger::read_forever(
        stdin,
        "bug: unable to read data from stdin",
        "bug: failed to read command from turtle process",
        |query| handle_query(query, &mut app, &events_rx, &drawing_tx).and_then(|resp| match resp {
            Some(ref response) => send_response(&mut stdout, response),
            None => Ok(()),
        }),
    );
}

/// We want to expose this specifically for tests so that tests can mimic the behaviour of the
/// server without actually spawning a new process. See renderer_process.rs for more details.
#[cfg(any(feature = "test", test))]
pub(crate) fn handle_query_for_test_use_only(
    query: Query,
    app: &mut TurtleApp,
    events_rx: &mpsc::Receiver<Event>,
    drawing_tx: &mpsc::Sender<DrawingCommand>,
) -> Result<Option<Response>, ()> {
    handle_query(query, app, events_rx, drawing_tx)
}

/// Returns the appropriate Response (if any) to the given Query
///
/// Returns Err(()) if it is time to quit because we have been disconnected.
fn handle_query(
    query: Query,
    app: &mut TurtleApp,
    events_rx: &mpsc::Receiver<Event>,
    drawing_tx: &mpsc::Sender<DrawingCommand>,
) -> Result<Option<Response>, ()> {
    match query {
        Query::Request(req) => handle_request(req, &app, &events_rx),
        Query::Update(update) => handle_update(update, app),
        Query::Drawing(cmd) => drawing_tx.send(cmd).map(|_| None).map_err(|_| ()),
    }
}

fn handle_request(
    request: Request,
    app: &TurtleApp,
    events_rx: &mpsc::Receiver<Event>,
) -> Result<Option<Response>, ()> {
    use self::Request::*;
    Ok(Some(match request {
        TurtleState => Response::TurtleState((*app.turtle()).clone()),
        DrawingState => Response::DrawingState((*app.drawing()).clone()),
        Event => Response::Event(match events_rx.try_recv() {
            Ok(event) => Some(event),
            Err(TryRecvError::Empty) => None,
            Err(TryRecvError::Disconnected) => return Err(()),
        }),
    }))
}

fn handle_update(
    update: StateUpdate,
    app: &mut TurtleApp,
) -> Result<Option<Response>, ()> {
    use self::StateUpdate::*;
    match update {
        TurtleState(turtle) => *app.turtle_mut() = turtle,
        DrawingState(drawing) => *app.drawing_mut() = drawing,
        TemporaryPath(path) => app.set_temporary_path(path),
    }

    Ok(None)
}

/// Sends a response to stdout
fn send_response<W: Write>(writer: W, response: &Response) -> Result<(), ()> {
    messenger::send(writer, response, "bug: unable to write final newline when sending response")
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::panic::catch_unwind;
use std::panic::AssertUnwindSafe;

use futures_cpupool::CpuPool;

use bytes::Bytes;

use httpbis::HttpError;
use httpbis::Header;
use httpbis::Headers;
use httpbis::server::HttpServer;
use httpbis::server::ServerTlsOption;

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

use method::*;
use error::*;
use futures_grpc::*;
use httpbis::futures_misc::*;
use grpc::*;
use grpc_frame::*;
use httpbis::http_common::*;
use httpbis::server_conf::*;
use httpbis::misc::any_to_string;
use req::GrpcRequestOptions;
use resp::*;
use metadata::GrpcMetadata;

pub trait MethodHandler<Req, Resp>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp>;
}

pub struct MethodHandlerUnary<F> {
    f: Arc<F>
}

pub struct MethodHandlerServerStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerClientStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerBidi<F> {
    f: Arc<F>
}

impl<F> GrpcStreamingFlavor for MethodHandlerUnary<F> {
    type Flavor = GrpcStreamingUnary;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::Unary
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerClientStreaming<F> {
    type Flavor = GrpcStreamingClientStreaming;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::ClientStreaming
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerServerStreaming<F> {
    type Flavor = GrpcStreamingServerStreaming;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::ServerStreaming
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerBidi<F> {
    type Flavor = GrpcStreamingBidi;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::Bidi
    }
}

impl<F> MethodHandlerUnary<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, Req) -> GrpcSingleResponse<Resp> + Send + 'static,
    {
        MethodHandlerUnary {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerClientStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcSingleResponse<Resp> + Send + 'static,
    {
        MethodHandlerClientStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerServerStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, Req) -> GrpcStreamingResponse<Resp> + Send + 'static,
    {
        MethodHandlerServerStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerBidi<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> + Send + 'static,
    {
        MethodHandlerBidi {
            f: Arc::new(f),
        }
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerUnary<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, Req) -> GrpcSingleResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        let f = self.f.clone();
        GrpcSingleResponse(
            Box::new(stream_single(req)
                .and_then(move |req| f(m, req).0)))
                    .into_stream()
    }
}

impl<Req : Send + 'static, Resp : Send + 'static, F> MethodHandler<Req, Resp> for MethodHandlerClientStreaming<F>
    where
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcSingleResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        ((self.f)(m, req)).into_stream()
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerServerStreaming<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, Req) -> GrpcStreamingResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, o: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        let f = self.f.clone();
        GrpcStreamingResponse(Box::new(
            stream_single(req)
                .and_then(move |req| f(o, req).0)))
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerBidi<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        (self.f)(m, req)
    }
}

trait MethodHandlerDispatch {
    fn start_request(&self, m: GrpcRequestOptions, grpc_frames: GrpcStreamSend<Vec<u8>>)
        -> GrpcStreamingResponse<Vec<u8>>;
}

struct MethodHandlerDispatchImpl<Req, Resp> {
    desc: Arc<MethodDescriptor<Req, Resp>>,
    method_handler: Box<MethodHandler<Req, Resp> + Sync + Send>,
}

impl<Req, Resp> MethodHandlerDispatch for MethodHandlerDispatchImpl<Req, Resp>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
{
    fn start_request(&self, o: GrpcRequestOptions, req_grpc_frames: GrpcStreamSend<Vec<u8>>)
        -> GrpcStreamingResponse<Vec<u8>>
    {
        let desc = self.desc.clone();
        let req = req_grpc_frames.and_then(move |frame| desc.req_marshaller.read(&frame));
        let resp =
            catch_unwind(AssertUnwindSafe(|| self.method_handler.handle(o, Box::new(req))));
        match resp {
            Ok(resp) => {
                let desc_copy = self.desc.clone();
                resp.and_then_items(move |resp| {
                    desc_copy.resp_marshaller.write(&resp)
                })
            }
            Err(e) => {
                let message = any_to_string(e);
                GrpcStreamingResponse::err(GrpcError::Panic(message))
            }
        }
    }
}

pub struct ServerMethod {
    name: String,
    dispatch: Box<MethodHandlerDispatch + Sync + Send>,
}

impl ServerMethod {
    pub fn new<Req, Resp, H>(method: Arc<MethodDescriptor<Req, Resp>>, handler: H) -> ServerMethod
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            H : MethodHandler<Req, Resp> + 'static + Sync + Send,
    {
        ServerMethod {
            name: method.name.clone(),
            dispatch: Box::new(MethodHandlerDispatchImpl {
                desc: method,
                method_handler: Box::new(handler),
            }),
        }
    }
}

pub struct ServerServiceDefinition {
    methods: Vec<ServerMethod>,
}

impl ServerServiceDefinition {
    pub fn new(methods: Vec<ServerMethod>) -> ServerServiceDefinition {
        ServerServiceDefinition {
            methods: methods,
        }
    }

    /// Join multiple service definitions into one
    pub fn join<I>(iter: I) -> ServerServiceDefinition
        where I : IntoIterator<Item=ServerServiceDefinition>
    {
        ServerServiceDefinition {
            methods: iter.into_iter().flat_map(|s| s.methods).collect()
        }
    }

    pub fn find_method(&self, name: &str) -> &ServerMethod {
        self.methods.iter()
            .filter(|m| m.name == name)
            .next()
            .expect(&format!("unknown method: {}", name))
    }

    pub fn handle_method(&self, name: &str, o: GrpcRequestOptions, message: GrpcStreamSend<Vec<u8>>)
        -> GrpcStreamingResponse<Vec<u8>>
    {
        self.find_method(name).dispatch.start_request(o, message)
    }
}

#[derive(Default, Debug, Clone)]
pub struct GrpcServerConf {
    pub http: HttpServerConf,
}

pub struct GrpcServer {
    server: HttpServer,
}

impl GrpcServer {
    /// Without TLS
    pub fn new_plain<A : ToSocketAddrs>(
        addr: A,
        conf: GrpcServerConf,
        service_definition: ServerServiceDefinition)
            -> GrpcServer
    {
        GrpcServer::new(addr, ServerTlsOption::Plain, conf, service_definition)
    }

    /// Without TLS and execute handler in given CpuPool
    pub fn new_plain_pool<A : ToSocketAddrs>(
        addr: A,
        conf: GrpcServerConf,
        service_definition: ServerServiceDefinition,
        cpu_pool: CpuPool)
            -> GrpcServer
    {
        GrpcServer::new_pool(addr, ServerTlsOption::Plain, conf, service_definition, cpu_pool)
    }

    pub fn new<A : ToSocketAddrs>(
        addr: A,
        tls: ServerTlsOption,
        conf: GrpcServerConf,
        service_definition: ServerServiceDefinition)
            -> GrpcServer
    {
        GrpcServer::with_starter(addr, tls, conf, service_definition, CallStarterSync)
    }

    pub fn new_pool<A : ToSocketAddrs>(
        addr: A,
        tls: ServerTlsOption,
        conf: GrpcServerConf,
        service_definition: ServerServiceDefinition,
        cpu_pool: CpuPool)
            -> GrpcServer
    {
        GrpcServer::with_starter(addr, tls, conf, service_definition, CallStarterCpupool {
            cpu_pool: cpu_pool,
        })
    }

    fn with_starter<A : ToSocketAddrs, S : CallStarter>(
        addr: A,
        tls: ServerTlsOption,
        conf: GrpcServerConf,
        service_definition: ServerServiceDefinition,
        call_starter: S)
            -> GrpcServer
    {
        let mut conf = conf;
        conf.http.thread_name =
            Some(conf.http.thread_name.unwrap_or_else(|| "grpc-server-loop".to_owned()));

        let service_definition = Arc::new(service_definition);
        GrpcServer {
            server: HttpServer::new(addr, tls, conf.http, GrpcHttpService {
                service_definition: service_definition.clone(),
                call_starter: CallStarterSync,
            })
        }
    }

    pub fn local_addr(&self) -> &SocketAddr {
        self.server.local_addr()
    }

    pub fn is_alive(&self) -> bool {
        self.server.is_alive()
    }
}

trait CallStarter : Send + 'static {
    fn start(
        &self,
        service_definition: &Arc<ServerServiceDefinition>,
        name: &str,
        o: GrpcRequestOptions,
        message: GrpcStreamSend<Vec<u8>>)
            -> GrpcStreamingResponse<Vec<u8>>;
}

struct CallStarterSync;

impl CallStarter for CallStarterSync {
    fn start(
        &self,
        service_definition: &Arc<ServerServiceDefinition>,
        name: &str,
        o: GrpcRequestOptions,
        message: GrpcStreamSend<Vec<u8>>)
            -> GrpcStreamingResponse<Vec<u8>>
    {
        service_definition.handle_method(name, o, message)
    }
}

struct CallStarterCpupool {
    cpu_pool: CpuPool,
}

impl CallStarter for CallStarterCpupool {
    fn start(
        &self,
        service_definition: &Arc<ServerServiceDefinition>,
        name: &str,
        o: GrpcRequestOptions,
        message: GrpcStreamSend<Vec<u8>>)
            -> GrpcStreamingResponse<Vec<u8>>
    {
        let service_definition = service_definition.clone();
        let name = name.to_owned();
        let f = self.cpu_pool.spawn_fn(move || {
            service_definition.handle_method(&name, o, message).0
        });
        GrpcStreamingResponse::new(f)
    }
}

struct GrpcHttpService<S : CallStarter> {
    service_definition: Arc<ServerServiceDefinition>,
    call_starter: S,
}

fn stream_500(message: &str) -> HttpResponse {
    // TODO: HttpResponse::headers
    HttpResponse::from_stream(stream::once(Ok(HttpStreamPart::last_headers(Headers(vec![
        Header::new(":status", "500"),
        Header::new(HEADER_GRPC_MESSAGE, message.to_owned()),
    ])))))
}

impl<S : CallStarter> HttpService for GrpcHttpService<S> {
    fn new_request(&self, headers: Headers, req: HttpPartFutureStreamSend) -> HttpResponse {

        let path = match headers.get_opt(":path") {
            Some(path) => path.to_owned(),
            None => return stream_500("no :path header"),
        };

        let grpc_request = GrpcFrameFromHttpFramesStreamRequest::new(req);

        let metadata = match GrpcMetadata::from_headers(headers) {
            Ok(metadata) => metadata,
            Err(_) => return stream_500("decode metadata error"),
        };

        // TODO: catch unwind
        let grpc_response = self.call_starter.start(
            &self.service_definition,
            &path,
            GrpcRequestOptions { metadata: metadata },
            Box::new(grpc_request));

        HttpResponse::new(grpc_response.0.map_err(HttpError::from).map(|(metadata, grpc_frames)| {
            let mut init_headers = Headers(vec![
                Header::new(":status", "200"),
                Header::new("content-type", "application/grpc"),
            ]);

            init_headers.extend(metadata.into_headers());

            let s2 = grpc_frames
                .map(|frame| HttpStreamPart::intermediate_data(Bytes::from(write_grpc_frame_to_vec(&frame))))
                .then(|result| {
                    match result {
                        Ok(part) => {
                            let r: Result<_, HttpError> = Ok(part);
                            r
                        }
                        Err(e) =>
                            Ok(HttpStreamPart::last_headers(
                                match e {
                                    GrpcError::GrpcMessage(GrpcMessageError { grpc_status, grpc_message }) => {
                                        Headers(vec![
                                            Header::new(":status", "500"),
                                            // TODO: check nonzero
                                            Header::new(HEADER_GRPC_STATUS, format!("{}", grpc_status)),
                                            // TODO: escape invalid
                                            Header::new(HEADER_GRPC_MESSAGE, grpc_message),
                                        ])
                                    }
                                    e => {
                                        Headers(vec![
                                            Header::new(":status", "500"),
                                            Header::new(HEADER_GRPC_MESSAGE, format!("error: {:?}", e)),
                                        ])
                                    }
                                }
                            ))
                    }
                })
                .map_err(HttpError::from);

            let s3 = stream::once(Ok(HttpStreamPart::last_headers(Headers(vec![
                Header::new(HEADER_GRPC_STATUS, "0"),
            ]))));

            let http_parts: HttpPartFutureStreamSend = Box::new(s2.chain(s3));

            (init_headers, http_parts)
        }))
    }
}
<commit_msg>Oops, make it actually async<commit_after>use std::sync::Arc;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::panic::catch_unwind;
use std::panic::AssertUnwindSafe;

use futures_cpupool::CpuPool;

use bytes::Bytes;

use httpbis::HttpError;
use httpbis::Header;
use httpbis::Headers;
use httpbis::server::HttpServer;
use httpbis::server::ServerTlsOption;

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

use method::*;
use error::*;
use futures_grpc::*;
use httpbis::futures_misc::*;
use grpc::*;
use grpc_frame::*;
use httpbis::http_common::*;
use httpbis::server_conf::*;
use httpbis::misc::any_to_string;
use req::GrpcRequestOptions;
use resp::*;
use metadata::GrpcMetadata;

pub trait MethodHandler<Req, Resp>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp>;
}

pub struct MethodHandlerUnary<F> {
    f: Arc<F>
}

pub struct MethodHandlerServerStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerClientStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerBidi<F> {
    f: Arc<F>
}

impl<F> GrpcStreamingFlavor for MethodHandlerUnary<F> {
    type Flavor = GrpcStreamingUnary;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::Unary
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerClientStreaming<F> {
    type Flavor = GrpcStreamingClientStreaming;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::ClientStreaming
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerServerStreaming<F> {
    type Flavor = GrpcStreamingServerStreaming;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::ServerStreaming
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerBidi<F> {
    type Flavor = GrpcStreamingBidi;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::Bidi
    }
}

impl<F> MethodHandlerUnary<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, Req) -> GrpcSingleResponse<Resp> + Send + 'static,
    {
        MethodHandlerUnary {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerClientStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcSingleResponse<Resp> + Send + 'static,
    {
        MethodHandlerClientStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerServerStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, Req) -> GrpcStreamingResponse<Resp> + Send + 'static,
    {
        MethodHandlerServerStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerBidi<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> + Send + 'static,
    {
        MethodHandlerBidi {
            f: Arc::new(f),
        }
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerUnary<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, Req) -> GrpcSingleResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        let f = self.f.clone();
        GrpcSingleResponse(
            Box::new(stream_single(req)
                .and_then(move |req| f(m, req).0)))
                    .into_stream()
    }
}

impl<Req : Send + 'static, Resp : Send + 'static, F> MethodHandler<Req, Resp> for MethodHandlerClientStreaming<F>
    where
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcSingleResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        ((self.f)(m, req)).into_stream()
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerServerStreaming<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, Req) -> GrpcStreamingResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, o: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        let f = self.f.clone();
        GrpcStreamingResponse(Box::new(
            stream_single(req)
                .and_then(move |req| f(o, req).0)))
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerBidi<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(GrpcRequestOptions, GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> + Send + Sync + 'static,
{
    fn handle(&self, m: GrpcRequestOptions, req: GrpcStreamSend<Req>) -> GrpcStreamingResponse<Resp> {
        (self.f)(m, req)
    }
}

trait MethodHandlerDispatch {
    fn start_request(&self, m: GrpcRequestOptions, grpc_frames: GrpcStreamSend<Vec<u8>>)
        -> GrpcStreamingResponse<Vec<u8>>;
}

struct MethodHandlerDispatchImpl<Req, Resp> {
    desc: Arc<MethodDescriptor<Req, Resp>>,
    method_handler: Box<MethodHandler<Req, Resp> + Sync + Send>,
}

impl<Req, Resp> MethodHandlerDispatch for MethodHandlerDispatchImpl<Req, Resp>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
{
    fn start_request(&self, o: GrpcRequestOptions, req_grpc_frames: GrpcStreamSend<Vec<u8>>)
        -> GrpcStreamingResponse<Vec<u8>>
    {
        let desc = self.desc.clone();
        let req = req_grpc_frames.and_then(move |frame| desc.req_marshaller.read(&frame));
        let resp =
            catch_unwind(AssertUnwindSafe(|| self.method_handler.handle(o, Box::new(req))));
        match resp {
            Ok(resp) => {
                let desc_copy = self.desc.clone();
                resp.and_then_items(move |resp| {
                    desc_copy.resp_marshaller.write(&resp)
                })
            }
            Err(e) => {
                let message = any_to_string(e);
                GrpcStreamingResponse::err(GrpcError::Panic(message))
            }
        }
    }
}

pub struct ServerMethod {
    name: String,
    dispatch: Box<MethodHandlerDispatch + Sync + Send>,
}

impl ServerMethod {
    pub fn new<Req, Resp, H>(method: Arc<MethodDescriptor<Req, Resp>>, handler: H) -> ServerMethod
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            H : MethodHandler<Req, Resp> + 'static + Sync + Send,
    {
        ServerMethod {
            name: method.name.clone(),
            dispatch: Box::new(MethodHandlerDispatchImpl {
                desc: method,
                method_handler: Box::new(handler),
            }),
        }
    }
}

pub struct ServerServiceDefinition {
    methods: Vec<ServerMethod>,
}

impl ServerServiceDefinition {
    pub fn new(methods: Vec<ServerMethod>) -> ServerServiceDefinition {
        ServerServiceDefinition {
            methods: methods,
        }
    }

    /// Join multiple service definitions into one
    pub fn join<I>(iter: I) -> ServerServiceDefinition
        where I : IntoIterator<Item=ServerServiceDefinition>
    {
        ServerServiceDefinition {
            methods: iter.into_iter().flat_map(|s| s.methods).collect()
        }
    }

    pub fn find_method(&self, name: &str) -> &ServerMethod {
        self.methods.iter()
            .filter(|m| m.name == name)
            .next()
            .expect(&format!("unknown method: {}", name))
    }

    pub fn handle_method(&self, name: &str, o: GrpcRequestOptions, message: GrpcStreamSend<Vec<u8>>)
        -> GrpcStreamingResponse<Vec<u8>>
    {
        self.find_method(name).dispatch.start_request(o, message)
    }
}

#[derive(Default, Debug, Clone)]
pub struct GrpcServerConf {
    pub http: HttpServerConf,
}

pub struct GrpcServer {
    server: HttpServer,
}

impl GrpcServer {
    /// Without TLS
    pub fn new_plain<A : ToSocketAddrs>(
        addr: A,
        conf: GrpcServerConf,
        service_definition: ServerServiceDefinition)
            -> GrpcServer
    {
        GrpcServer::new(addr, ServerTlsOption::Plain, conf, service_definition)
    }

    /// Without TLS and execute handler in given CpuPool
    pub fn new_plain_pool<A : ToSocketAddrs>(
        addr: A,
        conf: GrpcServerConf,
        service_definition: ServerServiceDefinition,
        cpu_pool: CpuPool)
            -> GrpcServer
    {
        GrpcServer::new_pool(addr, ServerTlsOption::Plain, conf, service_definition, cpu_pool)
    }

    pub fn new<A : ToSocketAddrs>(
        addr: A,
        tls: ServerTlsOption,
        conf: GrpcServerConf,
        service_definition: ServerServiceDefinition)
            -> GrpcServer
    {
        GrpcServer::with_starter(addr, tls, conf, service_definition, CallStarterSync)
    }

    pub fn new_pool<A : ToSocketAddrs>(
        addr: A,
        tls: ServerTlsOption,
        conf: GrpcServerConf,
        service_definition: ServerServiceDefinition,
        cpu_pool: CpuPool)
            -> GrpcServer
    {
        GrpcServer::with_starter(addr, tls, conf, service_definition, CallStarterCpupool {
            cpu_pool: cpu_pool,
        })
    }

    fn with_starter<A : ToSocketAddrs, S : CallStarter>(
        addr: A,
        tls: ServerTlsOption,
        conf: GrpcServerConf,
        service_definition: ServerServiceDefinition,
        call_starter: S)
            -> GrpcServer
    {
        let mut conf = conf;
        conf.http.thread_name =
            Some(conf.http.thread_name.unwrap_or_else(|| "grpc-server-loop".to_owned()));

        let service_definition = Arc::new(service_definition);
        GrpcServer {
            server: HttpServer::new(addr, tls, conf.http, GrpcHttpService {
                service_definition: service_definition.clone(),
                call_starter: call_starter,
            })
        }
    }

    pub fn local_addr(&self) -> &SocketAddr {
        self.server.local_addr()
    }

    pub fn is_alive(&self) -> bool {
        self.server.is_alive()
    }
}

trait CallStarter : Send + 'static {
    fn start(
        &self,
        service_definition: &Arc<ServerServiceDefinition>,
        name: &str,
        o: GrpcRequestOptions,
        message: GrpcStreamSend<Vec<u8>>)
            -> GrpcStreamingResponse<Vec<u8>>;
}

struct CallStarterSync;

impl CallStarter for CallStarterSync {
    fn start(
        &self,
        service_definition: &Arc<ServerServiceDefinition>,
        name: &str,
        o: GrpcRequestOptions,
        message: GrpcStreamSend<Vec<u8>>)
            -> GrpcStreamingResponse<Vec<u8>>
    {
        service_definition.handle_method(name, o, message)
    }
}

struct CallStarterCpupool {
    cpu_pool: CpuPool,
}

impl CallStarter for CallStarterCpupool {
    fn start(
        &self,
        service_definition: &Arc<ServerServiceDefinition>,
        name: &str,
        o: GrpcRequestOptions,
        message: GrpcStreamSend<Vec<u8>>)
            -> GrpcStreamingResponse<Vec<u8>>
    {
        let service_definition = service_definition.clone();
        let name = name.to_owned();
        let f = self.cpu_pool.spawn_fn(move || {
            service_definition.handle_method(&name, o, message).0
        });
        GrpcStreamingResponse::new(f)
    }
}

struct GrpcHttpService<S : CallStarter> {
    service_definition: Arc<ServerServiceDefinition>,
    call_starter: S,
}

fn stream_500(message: &str) -> HttpResponse {
    // TODO: HttpResponse::headers
    HttpResponse::from_stream(stream::once(Ok(HttpStreamPart::last_headers(Headers(vec![
        Header::new(":status", "500"),
        Header::new(HEADER_GRPC_MESSAGE, message.to_owned()),
    ])))))
}

impl<S : CallStarter> HttpService for GrpcHttpService<S> {
    fn new_request(&self, headers: Headers, req: HttpPartFutureStreamSend) -> HttpResponse {

        let path = match headers.get_opt(":path") {
            Some(path) => path.to_owned(),
            None => return stream_500("no :path header"),
        };

        let grpc_request = GrpcFrameFromHttpFramesStreamRequest::new(req);

        let metadata = match GrpcMetadata::from_headers(headers) {
            Ok(metadata) => metadata,
            Err(_) => return stream_500("decode metadata error"),
        };

        // TODO: catch unwind
        let grpc_response = self.call_starter.start(
            &self.service_definition,
            &path,
            GrpcRequestOptions { metadata: metadata },
            Box::new(grpc_request));

        HttpResponse::new(grpc_response.0.map_err(HttpError::from).map(|(metadata, grpc_frames)| {
            let mut init_headers = Headers(vec![
                Header::new(":status", "200"),
                Header::new("content-type", "application/grpc"),
            ]);

            init_headers.extend(metadata.into_headers());

            let s2 = grpc_frames
                .map(|frame| HttpStreamPart::intermediate_data(Bytes::from(write_grpc_frame_to_vec(&frame))))
                .then(|result| {
                    match result {
                        Ok(part) => {
                            let r: Result<_, HttpError> = Ok(part);
                            r
                        }
                        Err(e) =>
                            Ok(HttpStreamPart::last_headers(
                                match e {
                                    GrpcError::GrpcMessage(GrpcMessageError { grpc_status, grpc_message }) => {
                                        Headers(vec![
                                            Header::new(":status", "500"),
                                            // TODO: check nonzero
                                            Header::new(HEADER_GRPC_STATUS, format!("{}", grpc_status)),
                                            // TODO: escape invalid
                                            Header::new(HEADER_GRPC_MESSAGE, grpc_message),
                                        ])
                                    }
                                    e => {
                                        Headers(vec![
                                            Header::new(":status", "500"),
                                            Header::new(HEADER_GRPC_MESSAGE, format!("error: {:?}", e)),
                                        ])
                                    }
                                }
                            ))
                    }
                })
                .map_err(HttpError::from);

            let s3 = stream::once(Ok(HttpStreamPart::last_headers(Headers(vec![
                Header::new(HEADER_GRPC_STATUS, "0"),
            ]))));

            let http_parts: HttpPartFutureStreamSend = Box::new(s2.chain(s3));

            (init_headers, http_parts)
        }))
    }
}
<|endoftext|>


<commit_before>use std::thread::{self};
use std::sync::{Arc, Mutex};
use std::io::Read;
use std::net::TcpStream;
use std::mem;
use hyper::server::{Handler, Server, Request, Response};
use hyper::header::ContentLength;
use hyper::method::{Method};
use hyper::status::StatusCode;
use rustc_serialize::json;
use {Mock, MockResponse, SERVER_ADDRESS};

#[derive(Debug)]
enum CreateMockError {
    MethodMissing,
    PathMissing,
    ContentLengthMissing,
    InvalidMockResponse,
}

struct RequestHandler {
    mocks: Arc<Mutex<Vec<Mock>>>,
}

impl RequestHandler {
    pub fn new(mocks: Arc<Mutex<Vec<Mock>>>) -> Self {
        RequestHandler {
            mocks: mocks,
        }
    }

    #[allow(unused_variables)]
    fn handle_create_mock(&self, request: Request, mut response: Response) {
        match Self::mock_from(request) {
            Ok(mock) => {
                self.mocks.lock().unwrap().push(mock);
            },
            Err(e) => {
                // TODO: implement Display for CreateMockError
                mem::replace(response.status_mut(), StatusCode::UnprocessableEntity);
            }
        }
    }

    #[allow(unused_variables)]
    fn handle_delete_mocks(&self, request: Request, response: Response) {
        match request.headers.iter().find(|header| { header.name().to_lowercase() == "x-mock-id" }) {
            // Remove the element with x-mock-id
            Some(header) => {
                let id = header.value_string();
                let mut mocks = self.mocks.lock().unwrap();
                match mocks.iter().position(|mock| mock.id == id) {
                    Some(pos) => { mocks.remove(pos); },
                    None => {},
                };
            },
            // Remove all elements
            None => { self.mocks.lock().unwrap().clear(); }
        }
    }

    fn handle_default(&self, request: Request, mut response: Response) {
        let mocks = self.mocks.lock().unwrap();

        match mocks.iter().rev().find(|mock| mock.matches(&request)) {
            Some(mock) => {
                // Set the response status code
                // TODO: StatusCode::Unregistered labels everything as `<unknown status code>`
                mem::replace(response.status_mut(), StatusCode::Unregistered(mock.response.status as u16));

                // Set the response headers
                for (field, value) in &mock.response.headers {
                    response.headers_mut().set_raw(field.to_owned(), vec!(value.as_bytes().to_vec()));
                }

                // Set the response body
                response.send(mock.response.body.as_bytes()).unwrap();
            },
            None => { println!("aici"); mem::replace(response.status_mut(), StatusCode::NotImplemented); },
        };
    }

    fn mock_from(request: Request) -> Result<Mock, CreateMockError> {
        let method: String = try!(
            request.headers.iter()
                .find(|header| { header.name().to_lowercase() == "x-mock-method" })
                .ok_or(CreateMockError::MethodMissing)
            ).value_string();

        let path: String = try!(
            request.headers.iter()
                .find(|header| { header.name().to_lowercase() == "x-mock-path" })
                .ok_or(CreateMockError::PathMissing)
            ).value_string();

        let mut mock = Mock::new(&method, &path);

        match request.headers.iter().find(|header| { header.name().to_lowercase() == "x-mock-id" }) {
            Some(header) => { mock.id = header.value_string(); },
            None => {},
        };

        for header in request.headers.iter() {
            let field = header.name().to_lowercase();
            if field.starts_with("x-mock-") && field != "x-mock-id" && field != "x-mock-method" && field != "x-mock-path" {
                mock.match_header(&field.replace("x-mock-", ""), &header.value_string());
            }
        }

        let content_length: ContentLength = *try!(request.headers.get().ok_or(CreateMockError::ContentLengthMissing));

        let mut body = String::new();
        request.take(content_length.0).read_to_string(&mut body).unwrap();

        let response: MockResponse = try!(json::decode(&body).map_err(|_| CreateMockError::InvalidMockResponse));
        mock.response = response;

        Ok(mock)
    }
}

impl Handler for RequestHandler {
    fn handle(&self, request: Request, response: Response) {
        match (&request.method, &*request.uri.to_string()) {
            (&Method::Post, "/mocks") => self.handle_create_mock(request, response),
            (&Method::Delete, "/mocks") => self.handle_delete_mocks(request, response),
            _ => self.handle_default(request, response),
        };
    }
}

pub fn try_start() {
    if is_listening() { return }

    start()
}

fn start() {
    thread::spawn(move || {
        let mocks: Arc<Mutex<Vec<Mock>>> = Arc::new(Mutex::new(vec!()));

        match Server::http(SERVER_ADDRESS) {
            Ok(server) => { server.handle(RequestHandler::new(mocks)).unwrap(); },
            Err(_) => {},
        };
    });

    while !is_listening() {}
}

fn is_listening() -> bool {
    TcpStream::connect(SERVER_ADDRESS).is_ok()
}
<commit_msg>Remove debugging code<commit_after>use std::thread::{self};
use std::sync::{Arc, Mutex};
use std::io::Read;
use std::net::TcpStream;
use std::mem;
use hyper::server::{Handler, Server, Request, Response};
use hyper::header::ContentLength;
use hyper::method::{Method};
use hyper::status::StatusCode;
use rustc_serialize::json;
use {Mock, MockResponse, SERVER_ADDRESS};

#[derive(Debug)]
enum CreateMockError {
    MethodMissing,
    PathMissing,
    ContentLengthMissing,
    InvalidMockResponse,
}

struct RequestHandler {
    mocks: Arc<Mutex<Vec<Mock>>>,
}

impl RequestHandler {
    pub fn new(mocks: Arc<Mutex<Vec<Mock>>>) -> Self {
        RequestHandler {
            mocks: mocks,
        }
    }

    #[allow(unused_variables)]
    fn handle_create_mock(&self, request: Request, mut response: Response) {
        match Self::mock_from(request) {
            Ok(mock) => {
                self.mocks.lock().unwrap().push(mock);
            },
            Err(e) => {
                // TODO: implement Display for CreateMockError
                mem::replace(response.status_mut(), StatusCode::UnprocessableEntity);
            }
        }
    }

    #[allow(unused_variables)]
    fn handle_delete_mocks(&self, request: Request, response: Response) {
        match request.headers.iter().find(|header| { header.name().to_lowercase() == "x-mock-id" }) {
            // Remove the element with x-mock-id
            Some(header) => {
                let id = header.value_string();
                let mut mocks = self.mocks.lock().unwrap();
                match mocks.iter().position(|mock| mock.id == id) {
                    Some(pos) => { mocks.remove(pos); },
                    None => {},
                };
            },
            // Remove all elements
            None => { self.mocks.lock().unwrap().clear(); }
        }
    }

    fn handle_default(&self, request: Request, mut response: Response) {
        let mocks = self.mocks.lock().unwrap();

        match mocks.iter().rev().find(|mock| mock.matches(&request)) {
            Some(mock) => {
                // Set the response status code
                // TODO: StatusCode::Unregistered labels everything as `<unknown status code>`
                mem::replace(response.status_mut(), StatusCode::Unregistered(mock.response.status as u16));

                // Set the response headers
                for (field, value) in &mock.response.headers {
                    response.headers_mut().set_raw(field.to_owned(), vec!(value.as_bytes().to_vec()));
                }

                // Set the response body
                response.send(mock.response.body.as_bytes()).unwrap();
            },
            None => { mem::replace(response.status_mut(), StatusCode::NotImplemented); },
        };
    }

    fn mock_from(request: Request) -> Result<Mock, CreateMockError> {
        let method: String = try!(
            request.headers.iter()
                .find(|header| { header.name().to_lowercase() == "x-mock-method" })
                .ok_or(CreateMockError::MethodMissing)
            ).value_string();

        let path: String = try!(
            request.headers.iter()
                .find(|header| { header.name().to_lowercase() == "x-mock-path" })
                .ok_or(CreateMockError::PathMissing)
            ).value_string();

        let mut mock = Mock::new(&method, &path);

        match request.headers.iter().find(|header| { header.name().to_lowercase() == "x-mock-id" }) {
            Some(header) => { mock.id = header.value_string(); },
            None => {},
        };

        for header in request.headers.iter() {
            let field = header.name().to_lowercase();
            if field.starts_with("x-mock-") && field != "x-mock-id" && field != "x-mock-method" && field != "x-mock-path" {
                mock.match_header(&field.replace("x-mock-", ""), &header.value_string());
            }
        }

        let content_length: ContentLength = *try!(request.headers.get().ok_or(CreateMockError::ContentLengthMissing));

        let mut body = String::new();
        request.take(content_length.0).read_to_string(&mut body).unwrap();

        let response: MockResponse = try!(json::decode(&body).map_err(|_| CreateMockError::InvalidMockResponse));
        mock.response = response;

        Ok(mock)
    }
}

impl Handler for RequestHandler {
    fn handle(&self, request: Request, response: Response) {
        match (&request.method, &*request.uri.to_string()) {
            (&Method::Post, "/mocks") => self.handle_create_mock(request, response),
            (&Method::Delete, "/mocks") => self.handle_delete_mocks(request, response),
            _ => self.handle_default(request, response),
        };
    }
}

pub fn try_start() {
    if is_listening() { return }

    start()
}

fn start() {
    thread::spawn(move || {
        let mocks: Arc<Mutex<Vec<Mock>>> = Arc::new(Mutex::new(vec!()));

        match Server::http(SERVER_ADDRESS) {
            Ok(server) => { server.handle(RequestHandler::new(mocks)).unwrap(); },
            Err(_) => {},
        };
    });

    while !is_listening() {}
}

fn is_listening() -> bool {
    TcpStream::connect(SERVER_ADDRESS).is_ok()
}
<|endoftext|>


<commit_before>use super::gl;
use super::gl_lib::types::*;

pub struct Shader {
    gl_id: GLuint
}

impl Shader {
    pub unsafe fn from_id(id: GLuint) -> Shader {
        Shader { gl_id: id }
    }
}

impl Drop for Shader {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteShader(self.gl_id);
        }
    }
}

#[derive(Debug, Clone, Copy)]
#[allow(non_camel_case_types)]
pub enum ShaderType {
    VERTEX_SHADER = gl::VERTEX_SHADER as isize,
    FRAGMENT_SHADER = gl::FRAGMENT_SHADER as isize
}
pub use self::ShaderType::*;
<commit_msg>Add `Shader.source`<commit_after>use super::gl;
use super::gl_lib::types::*;

pub struct Shader {
    gl_id: GLuint
}

impl Shader {
    pub unsafe fn from_id(id: GLuint) -> Shader {
        Shader { gl_id: id }
    }

    pub fn source(&mut self, shader_source: &str) {
        unsafe {
            let source = shader_source.as_ptr() as *const GLchar;
            let length = shader_source.len() as GLint;

            gl::ShaderSource(self.gl_id, 1,
                             &source as *const *const GLchar,
                             &length as *const GLint);
        }
    }
}

impl Drop for Shader {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteShader(self.gl_id);
        }
    }
}

#[derive(Debug, Clone, Copy)]
#[allow(non_camel_case_types)]
pub enum ShaderType {
    VERTEX_SHADER = gl::VERTEX_SHADER as isize,
    FRAGMENT_SHADER = gl::FRAGMENT_SHADER as isize
}
pub use self::ShaderType::*;
<|endoftext|>


<commit_before>use gl;
use gl::types::*;
use glw::gl_context::GLContext;
use glw::shader::Shader;
use std::collections::HashMap;
use std::io::fs::File;

// Turn a shader definition into a vanilla GLSL shader definition.
// See the README in the shaders folder for details.
fn preprocess(shader: String, vars: &HashMap<String, String>) -> Option<String> {
  let shader = shader.into_bytes();
  let mut processed = String::new();
  let mut i = 0;

  // For termination conditions, look for explicit returns.
  loop {
    if i >= shader.len() {
      return Some(processed);
    }
    match shader[i] as char {
      '$' => {
        let mut var_name = String::new();
        loop {
          i += 1;
          if i >= shader.len() {
            error!("$ without matching $");
            return None;
          }
          match shader[i] as char {
            '$' => {
              break;
            },
            c => {
              var_name.push(c);
            },
          }
        }

        match vars.find(&var_name) {
          None => {
            error!("Reference to undefined variable: {}", var_name);
            return None;
          },
          Some(val) => {
            processed.push_str(val.as_slice());
          },
        }
      },
      c => {
        processed.push(c);
      },
    }

    i += 1;
  }
}

#[test]
fn preprocess_vanilla_shader() {
  let input = String::from_str(
r"foo
bar
baz
");
  let expected = Some(String::from_str(
r"foo
bar
baz
"));
  let actual = preprocess(input, &HashMap::new());
  assert!(
    actual == expected,
    "{} != {}",
    actual,
    expected
  );
}

#[test]
fn preprocess_var() {
  let input = String::from_str(
r"
$foo$
$bar$
baz
");
  let expected = Some(String::from_str(
r"
foo
bar
baz
"));
  let actual =
    preprocess(
      input,
      &FromIterator::from_iter(
        [
          (String::from_str("foo"), String::from_str("foo")),
          (String::from_str("bar"), String::from_str("bar")),
        ].to_vec().into_iter(),
      ),
    );
  assert!(
    actual == expected,
    "{} != {}",
    actual,
    expected
  );
}

#[test]
fn preprocess_undefined_var() {
  let input = String::from_str(
r"
$foo
bar
baz
");
  let expected = None;
  let actual = preprocess(input, &HashMap::new());
  assert!(
    actual == expected,
    "{} != {}",
    actual,
    expected
  );
}

pub fn from_files<T: Iterator<(String, GLenum)>>(
  gl: &mut GLContext,
  component_paths: T,
  vars: &HashMap<String, String>,
) -> Shader {
  Shader::new(gl, component_paths.map(|(path, component_type)| {
    match File::open(&Path::new(path.as_slice())) {
      Ok(mut f) =>
        match f.read_to_string() {
          Ok(s) => {
            match preprocess(s, vars) {
              None => {
                fail!("Failed to preprocess shader \"{}\".", path);
              },
              Some(s) => (s, component_type),
            }
          },
          Err(e) => {
            fail!("Couldn't read shader file \"{}\": {}", path, e);
          }
        },
      Err(e) => {
        fail!("Couldn't open shader file \"{}\" for reading: {}", path, e);
      }
    }
  }))
}

pub fn from_file_prefix<T: Iterator<GLenum>>(
  gl: &mut GLContext,
  prefix: String,
  components: T,
  vars: &HashMap<String, String>,
) -> Shader {
  from_files(
    gl,
    components.map(|component| {
      let suffix = match component {
        gl::VERTEX_SHADER => "vert",
        gl::FRAGMENT_SHADER => "frag",
        gl::GEOMETRY_SHADER => "geom",
        _ => fail!("Unknown shader component type: {}", component),
      };
      ((prefix + "." + suffix), component)
    }),
    vars,
  )
}
<commit_msg>add a shader preprocessing test<commit_after>use gl;
use gl::types::*;
use glw::gl_context::GLContext;
use glw::shader::Shader;
use std::collections::HashMap;
use std::io::fs::File;

// Turn a shader definition into a vanilla GLSL shader definition.
// See the README in the shaders folder for details.
fn preprocess(shader: String, vars: &HashMap<String, String>) -> Option<String> {
  let shader = shader.into_bytes();
  let mut processed = String::new();
  let mut i = 0;

  // For termination conditions, look for explicit returns.
  loop {
    if i >= shader.len() {
      return Some(processed);
    }
    match shader[i] as char {
      '$' => {
        let mut var_name = String::new();
        loop {
          i += 1;
          if i >= shader.len() {
            error!("$ without matching $");
            return None;
          }
          match shader[i] as char {
            '$' => {
              break;
            },
            c => {
              var_name.push(c);
            },
          }
        }

        match vars.find(&var_name) {
          None => {
            error!("Reference to undefined variable: {}", var_name);
            return None;
          },
          Some(val) => {
            processed.push_str(val.as_slice());
          },
        }
      },
      c => {
        processed.push(c);
      },
    }

    i += 1;
  }
}

#[test]
fn preprocess_vanilla_shader() {
  let input = String::from_str(
r"foo
bar
baz
");
  let expected = Some(String::from_str(
r"foo
bar
baz
"));
  let actual = preprocess(input, &HashMap::new());
  assert!(
    actual == expected,
    "{} != {}",
    actual,
    expected
  );
}

#[test]
fn preprocess_var() {
  let input = String::from_str(
r"
$foo$
$bar$
baz
");
  let expected = Some(String::from_str(
r"
foo
bar
baz
"));
  let actual =
    preprocess(
      input,
      &FromIterator::from_iter(
        [
          (String::from_str("foo"), String::from_str("foo")),
          (String::from_str("bar"), String::from_str("bar")),
        ].to_vec().into_iter(),
      ),
    );
  assert!(
    actual == expected,
    "{} != {}",
    actual,
    expected
  );
}

#[test]
fn preprocess_no_matching_token() {
  let input = String::from_str(
r"
$foo
bar
baz
");
  let expected = None;
  let actual = preprocess(input, &HashMap::new());
  assert!(
    actual == expected,
    "{} != {}",
    actual,
    expected
  );
}

#[test]
fn preprocess_undefined_var() {
  let input = String::from_str(
r"
$foo$
bar
baz
");
  let expected = None;
  let actual = preprocess(input, &HashMap::new());
  assert!(
    actual == expected,
    "{} != {}",
    actual,
    expected
  );
}

pub fn from_files<T: Iterator<(String, GLenum)>>(
  gl: &mut GLContext,
  component_paths: T,
  vars: &HashMap<String, String>,
) -> Shader {
  Shader::new(gl, component_paths.map(|(path, component_type)| {
    match File::open(&Path::new(path.as_slice())) {
      Ok(mut f) =>
        match f.read_to_string() {
          Ok(s) => {
            match preprocess(s, vars) {
              None => {
                fail!("Failed to preprocess shader \"{}\".", path);
              },
              Some(s) => (s, component_type),
            }
          },
          Err(e) => {
            fail!("Couldn't read shader file \"{}\": {}", path, e);
          }
        },
      Err(e) => {
        fail!("Couldn't open shader file \"{}\" for reading: {}", path, e);
      }
    }
  }))
}

pub fn from_file_prefix<T: Iterator<GLenum>>(
  gl: &mut GLContext,
  prefix: String,
  components: T,
  vars: &HashMap<String, String>,
) -> Shader {
  from_files(
    gl,
    components.map(|component| {
      let suffix = match component {
        gl::VERTEX_SHADER => "vert",
        gl::FRAGMENT_SHADER => "frag",
        gl::GEOMETRY_SHADER => "geom",
        _ => fail!("Unknown shader component type: {}", component),
      };
      ((prefix + "." + suffix), component)
    }),
    vars,
  )
}
<|endoftext|>


<commit_before>/*
 * PIC emulation
 */

use vm;

use std::rc::Rc;
use std::cell::RefCell;

const PIC_MASTER_CMD: u16 = 0x20;
const PIC_MASTER_DATA: u16 = 0x21;
const PIC_SLAVE_CMD: u16 = 0xA0;
const PIC_SLAVE_DATA: u16 = 0xA1;

const ICW1_INIT: u8 = 0x10;
const ICW1_ICW4: u8 = 0x01;
const ICW4_8086: u8 = 0x01;

/*
 * Single i8259 PIC chip
 */
struct I8259A
{
    imr: u8,
    isr: u8,
    offset: u8,
    mask: u8,
    icw1: u8,
    icw3: u8,
    next_icw: usize,
}

impl I8259A
{
    fn default() -> I8259A {
        I8259A {
            imr: 0,
            isr: 0,
            offset: 0,
            mask: 0xff,
            icw1: ICW1_INIT | ICW1_ICW4,
            icw3: 0,
            next_icw: 0,
        }
    }

    fn is_initialized(&self) -> bool {
        self.next_icw == 1
    }

    fn command(&mut self, cmd: u8) {
        if cmd & ICW1_INIT != 0 {
            /*
             * Start initialization
             * We support only ICW1 + ICW4
             */
            assert!(cmd & !(ICW1_INIT | ICW1_ICW4) == 0);
            self.icw1 = cmd;
            self.next_icw = 2;
        }
    }

    fn read(&mut self) -> u8 {
        self.mask
    }

    fn write(&mut self, data: u8) {
        match self.next_icw {
            2 => {
                self.offset = data;
                self.next_icw = 3;
            },

            3 => {
                self.icw3 = data;
                if self.icw1 & ICW1_ICW4 != 0 {
                    self.next_icw = 4;
                } else {
                    self.next_icw = 1;
                }
            },

            4 => {
                assert!(data == ICW4_8086); /* Just check that ICW4 is the only one we support */
                self.next_icw = 1;
            },

            _ => {
                self.mask = data; /* Writes go to mask by default */
            }
        }
    }
}

#[cfg(test)]
mod i8259a_test
{
    use super::I8259A;

    fn init(offset: u8, mask: u8, cascade: u8, use_icw4: bool) -> I8259A {
        let mut dev = I8259A::default();
        assert!(!dev.is_initialized());

        if use_icw4 {
            dev.command(super::ICW1_INIT | super::ICW1_ICW4);
        } else {
            dev.command(super::ICW1_INIT);
        }
        assert!(!dev.is_initialized());

        dev.write(offset);
        assert!(!dev.is_initialized());

        dev.write(cascade);

        if use_icw4 {
            assert!(!dev.is_initialized());
            dev.write(super::ICW4_8086);
        }

        assert!(dev.is_initialized());

        dev.write(mask);
        assert!(dev.read() == mask);

        return dev;
    }

    /* Init with ICW4 */
    #[test] fn init_icw4() {
        let mut dev = init(0x08, 0xAB, 0x02, true);
    }

    /* Init without ICW4 */
    #[test] fn init_no_icw4() {
        let mut dev = init(0x08, 0xAB, 0x02, true);
    }
}

struct PIC
{
    master: I8259A,
    slave: I8259A,
}

impl PIC
{
    fn new() -> PIC {
        PIC {
            master: I8259A::default(),
            slave: I8259A::default(),
        }
    }
}

///////////////////////////////////////////////////////////////////////////////

struct PICDev
{
    pic: RefCell<PIC>,
}

impl vm::io_handler for PICDev
{
    fn io_read(&self, port: u16, size: u8) -> vm::IoOperandType
    {
        assert!(size == 1);

        let mut dev = self.pic.borrow_mut();
        vm::IoOperandType::byte(
            match port {
                PIC_MASTER_DATA => dev.master.read(),
                PIC_SLAVE_DATA => dev.slave.read(),
                _ => 0,
            }
        )
    }

    fn io_write(&self, port: u16, data: vm::IoOperandType)
    {
        let mut dev = self.pic.borrow_mut();
        let data8 = data.unwrap_byte();

        match port {
            PIC_MASTER_DATA => dev.master.write(data8),
            PIC_SLAVE_DATA => dev.slave.write(data8),
            PIC_MASTER_CMD => dev.master.command(data8),
            PIC_SLAVE_CMD => dev.slave.command(data8),
            _ => panic!(),
        }
    }
}

pub fn init()
{
	let dev = Rc::new(PICDev {
        pic: RefCell::new(PIC::new()),
    });

    vm::register_io_region(dev.clone(), PIC_MASTER_CMD, 1);
    vm::register_io_region(dev.clone(), PIC_MASTER_DATA, 1);
    vm::register_io_region(dev.clone(), PIC_SLAVE_CMD, 1);
    vm::register_io_region(dev.clone(), PIC_SLAVE_DATA, 1);
}

<commit_msg>PIC: IRQ handling<commit_after>/*
 * PIC emulation
 */

use vm;

use std::rc::Rc;
use std::cell::RefCell;

const PIC_MASTER_CMD: u16 = 0x20;
const PIC_MASTER_DATA: u16 = 0x21;
const PIC_SLAVE_CMD: u16 = 0xA0;
const PIC_SLAVE_DATA: u16 = 0xA1;

const ICW1_INIT: u8 = 0x10;
const ICW1_ICW4: u8 = 0x01;
const ICW4_8086: u8 = 0x01;

const PIC_READ_IRR: u8 = 0x0A;
const PIC_READ_ISR: u8 = 0x0B;
const PIC_EOI: u8 = 0x20;

/**
 * i8259 PIC chip
 */
struct I8259A
{
    irr: u8,    // IRR register
    isr: u8,    // ISR register
    offset: u8, // Interrupt vector base
    mask: u8,   // IRQ mask
    icw1: u8,   // ICW1 value during initialization
    icw3: u8,   // ICW3 value during initialization (cascade IRQ)
    next_icw: usize,    // During init, next ICW word expected during init
    cmd_latch: u8,      // Latched value to be read next time from command port
}

impl I8259A
{
    fn default() -> I8259A {
        I8259A {
            irr: 0,
            isr: 0,
            offset: 0,
            mask: 0xff,
            icw1: ICW1_INIT | ICW1_ICW4,
            icw3: 0,
            next_icw: 0,
            cmd_latch: 0,
        }
    }

    fn is_initialized(&self) -> bool {
        self.next_icw == 1
    }

    fn offset(&self) -> u8 {
        self.offset
    }

    fn slave_irq(&self) -> u8 {
        self.icw3
    }

    /* Assert an IRQ line */
    fn assert_irq(&mut self, irq: u8) {
        assert!(irq < 8);

        if !self.is_initialized() {
            return;
        }

        let mask = 1u8 << irq;
        if (self.mask & mask) != 0 {
            return;
        }

        /* We only update IRR here because we're not sure when
         * interrupt event is going to be injected in guest.
         * So ISR will be updated once guest will try to access it */
        self.irr |= mask;

        /* Notify VM state we need to inject this vector */
        vm::raise_external_interrupt(irq + self.offset);
    }

    /* Write to command port */
    fn write_command(&mut self, cmd: u8) {
        if cmd & ICW1_INIT != 0 {
            /*
             * Start initialization
             * We support only ICW1 + ICW4
             */
            assert!(cmd & !(ICW1_INIT | ICW1_ICW4) == 0);
            self.icw1 = cmd;
            self.next_icw = 2;
        } else if cmd == PIC_READ_IRR {
            self.cmd_latch = self.irr;
        } else if cmd == PIC_READ_ISR {
            self.cmd_latch = self.isr;
        } else if cmd == PIC_EOI {
            self.isr = 0; /* Maybe last sent only? */
        } else {
            debug!("Unsupported PIC command {:x}", cmd);
        }
    }

    /* Read from command port */
    fn read_command(&mut self) -> u8 {
        return self.cmd_latch;
    }

    /* Write to data port */
    fn write_data(&mut self, data: u8) {
        match self.next_icw {
            2 => {
                self.offset = data;
                self.next_icw = 3;
            },

            3 => {
                self.icw3 = data;
                if self.icw1 & ICW1_ICW4 != 0 {
                    self.next_icw = 4;
                } else {
                    self.next_icw = 1;
                }
            },

            4 => {
                assert!(data == ICW4_8086); /* Just check that ICW4 is the only one we support */
                self.next_icw = 1;
            },

            _ => {
                self.mask = data; /* Writes go to mask by default */
            }
        }
    }

    /* Read from data port */
    fn read_data(&mut self) -> u8 {
        self.mask
    }
}

/**
 * Cascade PIC setup
 */
struct PIC
{
    master: I8259A,
    slave: I8259A,
}

impl PIC
{
    fn new() -> PIC {
        PIC {
            master: I8259A::default(),
            slave: I8259A::default(),
        }
    }

    fn assert_irq(&mut self, irq: u8) {
        assert!(irq <= 15);
        if irq < 8 {
            self.master.assert_irq(irq);
        } else {
            let slave_irq = self.master.slave_irq();
            self.master.assert_irq(slave_irq);
            self.slave.assert_irq(irq - 8);
        }
    }
}

///////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod i8259a_test
{
    use super::I8259A;

    fn init(offset: u8, mask: u8, cascade: u8, use_icw4: bool) -> I8259A {
        let mut dev = I8259A::default();
        assert!(!dev.is_initialized());

        if use_icw4 {
            dev.write_command(super::ICW1_INIT | super::ICW1_ICW4);
        } else {
            dev.write_command(super::ICW1_INIT);
        }
        assert!(!dev.is_initialized());

        dev.write_data(offset);
        assert!(!dev.is_initialized());

        dev.write_data(cascade);

        if use_icw4 {
            assert!(!dev.is_initialized());
            dev.write_data(super::ICW4_8086);
        }

        assert!(dev.is_initialized());

        dev.write_data(mask);
        assert!(dev.read_data() == mask);

        return dev;
    }

    /* Init with ICW4 */
    #[test] fn init_icw4() {
        let mut dev = init(0x08, 0xAB, 0x02, true);
    }

    /* Init without ICW4 */
    #[test] fn init_no_icw4() {
        let mut dev = init(0x08, 0xAB, 0x02, true);
    }
}

///////////////////////////////////////////////////////////////////////////////

struct PICDev
{
    pic: RefCell<PIC>,
}

impl vm::io_handler for PICDev
{
    fn io_read(&self, port: u16, size: u8) -> vm::IoOperandType
    {
        assert!(size == 1);

        let mut dev = self.pic.borrow_mut();
        vm::IoOperandType::byte(
            match port {
                PIC_MASTER_DATA => dev.master.read_data(),
                PIC_MASTER_CMD => dev.master.read_command(),

                PIC_SLAVE_DATA => dev.slave.read_data(),
                PIC_SLAVE_CMD => dev.slave.read_command(),

                _ => 0,
            }
        )
    }

    fn io_write(&self, port: u16, data: vm::IoOperandType)
    {
        let mut dev = self.pic.borrow_mut();
        let data8 = data.unwrap_byte();

        match port {
            PIC_MASTER_DATA => dev.master.write_data(data8),
            PIC_MASTER_CMD => dev.master.write_command(data8),

            PIC_SLAVE_DATA => dev.slave.write_data(data8),
            PIC_SLAVE_CMD => dev.slave.write_command(data8),

            _ => panic!(),
        }
    }
}

impl vm::interrupt_controller for PICDev
{
    fn assert_irq(&self, irq: u8)
    {
        let mut dev = self.pic.borrow_mut();
        dev.assert_irq(irq)
    }
}

pub fn init()
{
	let dev = Rc::new(PICDev {
        pic: RefCell::new(PIC::new()),
    });

    vm::register_interrupt_controller(dev.clone());

    vm::register_io_region(dev.clone(), PIC_MASTER_CMD, 1);
    vm::register_io_region(dev.clone(), PIC_MASTER_DATA, 1);
    vm::register_io_region(dev.clone(), PIC_SLAVE_CMD, 1);
    vm::register_io_region(dev.clone(), PIC_SLAVE_DATA, 1);
}

<|endoftext|>


<commit_before>use std::mem;
use heartbeat::{self, Heartbeat, HeartbeatRecord, HeartbeatWindowCompleteFn};
#[cfg(unix)]
use std::fs::File;
#[cfg(unix)]
use std::os::unix::io::AsRawFd;

/// Heartbeat wrapper. Contains the window data buffer.
pub struct HeartbeatSimple {
    pub hb: Heartbeat,
    pub hbr: Vec<HeartbeatRecord>,
}

impl HeartbeatSimple {
    /// Allocate and initialize a new `Heartbeat`.
    pub fn new(window_size: usize,
               hwc_callback: Option<HeartbeatWindowCompleteFn>) -> Result<HeartbeatSimple, &'static str> {
        let mut hbr = Vec::with_capacity(window_size);
        unsafe {
            let mut hb = mem::uninitialized();
            match heartbeat::heartbeat_init(&mut hb, hbr.capacity() as u64, hbr.as_mut_ptr(), hwc_callback) {
                0 => Ok(HeartbeatSimple { hb: hb, hbr: hbr, }),
                _ => Err("Failed to initialize heartbeat")
            }
        }
    }

    /// Issue a heartbeat.
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     start_time: u64,
                     end_time: u64) {
        unsafe {
            heartbeat::heartbeat(&mut self.hb, tag, work, start_time, end_time);
        }
    }

    /// Issue a heartbeat with energy data.
    pub fn heartbeat_pow(&mut self,
                         tag: u64,
                         work: u64,
                         start_time: u64,
                         end_time: u64,
                         start_energy: u64,
                         end_energy: u64) {
        unsafe {
            heartbeat::heartbeat_pow(&mut self.hb, tag, work, start_time, end_time, start_energy, end_energy)
        }
    }

    #[cfg(unix)]
    pub fn log_window_buffer(&self, log: File, print_header: bool) -> Result<(), &'static str> {
        let ph: i32 = match print_header {
            true => 1,
            false => 0,
        };
        unsafe {
            match heartbeat::heartbeat_log_window_buffer(&self.hb, log.as_raw_fd(), ph) {
                0 => Ok(()),
                _ => Err("Error logging window buffer"),
            }
        }
    }

    /// Utility function to get the most recent user-specified tag
    pub fn get_tag(&self) -> u64 {
        unsafe {
            heartbeat::hb_get_user_tag(&self.hb)
        }
    }

    /// Utility function to get the current window performance.
    pub fn get_window_rate(&self) -> f64 {
        unsafe {
            heartbeat::hb_get_window_rate(&self.hb)
        }
    }

    /// Utility function to get the current window power.
    pub fn get_window_pwr(&self) -> f64 {
        unsafe {
            heartbeat::hb_get_window_power(&self.hb)
        }
    }
}

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

    #[test]
    fn test_simple() {
        const TIME_INC: u64 = 1000000000;
        const ENERGY_INC: u64 = 1000000;
        let mut hb = HeartbeatSimple::new(5, None).unwrap();
        let mut start_time: u64 = 0;
        let mut end_time: u64 = TIME_INC;
        let mut start_energy: u64 = 0;
        let mut end_energy: u64 = ENERGY_INC;
        let mut tag: u64 = 0;
        for _ in 0..10 {
            hb.heartbeat_pow(tag, 1, start_time, end_time, start_energy, end_energy);
            assert!(hb.get_tag() == tag);
            assert!(hb.get_window_perf() == 1.0);
            assert!(hb.get_window_pwr() == 1.0);
            tag += 1;
            start_time = end_time;
            end_time += TIME_INC;
            start_energy = end_energy;
            end_energy += ENERGY_INC;
        }
    }
}<commit_msg>Rename HeartbeatSimple to HeartbeatContainer. Fix accidental function renaming.<commit_after>use std::mem;
use heartbeat::{self, Heartbeat, HeartbeatRecord, HeartbeatWindowCompleteFn};
#[cfg(unix)]
use std::fs::File;
#[cfg(unix)]
use std::os::unix::io::AsRawFd;

/// Contains the Heartbeat and its window data buffer.
pub struct HeartbeatContainer {
    pub hb: Heartbeat,
    pub hbr: Vec<HeartbeatRecord>,
}

impl HeartbeatContainer {
    /// Allocate and initialize a new `Heartbeat`.
    pub fn new(window_size: usize,
               hwc_callback: Option<HeartbeatWindowCompleteFn>) -> Result<HeartbeatContainer, &'static str> {
        let mut hbr = Vec::with_capacity(window_size);
        unsafe {
            let mut hb = mem::uninitialized();
            match heartbeat::heartbeat_init(&mut hb, hbr.capacity() as u64, hbr.as_mut_ptr(), hwc_callback) {
                0 => Ok(HeartbeatContainer { hb: hb, hbr: hbr, }),
                _ => Err("Failed to initialize heartbeat")
            }
        }
    }

    /// Issue a heartbeat.
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     start_time: u64,
                     end_time: u64) {
        unsafe {
            heartbeat::heartbeat(&mut self.hb, tag, work, start_time, end_time);
        }
    }

    /// Issue a heartbeat with energy data.
    pub fn heartbeat_pow(&mut self,
                         tag: u64,
                         work: u64,
                         start_time: u64,
                         end_time: u64,
                         start_energy: u64,
                         end_energy: u64) {
        unsafe {
            heartbeat::heartbeat_pow(&mut self.hb, tag, work, start_time, end_time, start_energy, end_energy)
        }
    }

    #[cfg(unix)]
    pub fn log_window_buffer(&self, log: File, print_header: bool) -> Result<(), &'static str> {
        let ph: i32 = match print_header {
            true => 1,
            false => 0,
        };
        unsafe {
            match heartbeat::heartbeat_log_window_buffer(&self.hb, log.as_raw_fd(), ph) {
                0 => Ok(()),
                _ => Err("Error logging window buffer"),
            }
        }
    }

    /// Utility function to get the most recent user-specified tag
    pub fn get_tag(&self) -> u64 {
        unsafe {
            heartbeat::hb_get_user_tag(&self.hb)
        }
    }

    /// Utility function to get the current window performance.
    pub fn get_window_perf(&self) -> f64 {
        unsafe {
            heartbeat::hb_get_window_rate(&self.hb)
        }
    }

    /// Utility function to get the current window power.
    pub fn get_window_pwr(&self) -> f64 {
        unsafe {
            heartbeat::hb_get_window_power(&self.hb)
        }
    }
}

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

    #[test]
    fn test_simple() {
        const TIME_INC: u64 = 1000000000;
        const ENERGY_INC: u64 = 1000000;
        let mut hb = HeartbeatContainer::new(5, None).unwrap();
        let mut start_time: u64 = 0;
        let mut end_time: u64 = TIME_INC;
        let mut start_energy: u64 = 0;
        let mut end_energy: u64 = ENERGY_INC;
        let mut tag: u64 = 0;
        for _ in 0..10 {
            hb.heartbeat_pow(tag, 1, start_time, end_time, start_energy, end_energy);
            assert!(hb.get_tag() == tag);
            assert!(hb.get_window_perf() == 1.0);
            assert!(hb.get_window_pwr() == 1.0);
            tag += 1;
            start_time = end_time;
            end_time += TIME_INC;
            start_energy = end_energy;
            end_energy += ENERGY_INC;
        }
    }
}
<|endoftext|>