<commit_before>//! Main entry point to the library.
//! See examples for documentation on how to use this struct.

use manager::{InputManager, InputManagerHandler, OutputManager, OutputManagerHandler};
use std::cell::UnsafeCell;
use std::env;
use std::ffi::CStr;
use types::server_decoration::ServerDecorationManager;
use wayland_sys::server::{WAYLAND_SERVER_HANDLE, wl_display, wl_event_loop};
use wayland_sys::server::signal::wl_signal_add;
use wlroots_sys::{wlr_backend, wlr_backend_autocreate, wlr_backend_destroy, wlr_backend_start};

/// Global compositor pointer, used to refer to the compositor state unsafely.
static mut COMPOSITOR_PTR: *mut Compositor = 0 as *mut _;

#[allow(dead_code)]
pub struct Compositor {
    input_manager: Box<InputManager>,
    output_manager: Box<OutputManager>,
    backend: *mut wlr_backend,
    display: *mut wl_display,
    event_loop: *mut wl_event_loop,
    pub server_decoration_manager: Option<ServerDecorationManager>
}

impl Compositor {
    /// Makes a new compositor that handles the setup of the graphical backend
    /// (e.g, Wayland, X11, or DRM).
    ///
    /// Also automatically opens the socket for clients to communicate to the
    /// compositor with.
    pub fn new(input_manager_handler: Box<InputManagerHandler>,
               output_manager_handler: Box<OutputManagerHandler>)
               -> Self {
        unsafe {
            let display = ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_create,) as
                *mut wl_display;
            let event_loop =
                ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_get_event_loop, display);
            let backend = wlr_backend_autocreate(display as *mut _);
            if backend.is_null() {
                // NOTE Rationale for panicking:
                // * Won't be in C land just yet, so it's safe to panic
                // * Can always be returned in a Result instead, but for now
                //   if you auto create it's assumed you can't recover.
                panic!("Could not auto-create backend");
            }
            let mut input_manager = InputManager::new((vec![], input_manager_handler));
            let mut output_manager = OutputManager::new((vec![], output_manager_handler));
            wl_signal_add(&mut (*backend).events.input_add as *mut _ as _,
                          input_manager.add_listener() as *mut _ as _);
            wl_signal_add(&mut (*backend).events.input_remove as *mut _ as _,
                          input_manager.remove_listener() as *mut _ as _);
            wl_signal_add(&mut (*backend).events.output_add as *mut _ as _,
                          output_manager.add_listener() as *mut _ as _);
            wl_signal_add(&mut (*backend).events.output_remove as *mut _ as _,
                          output_manager.remove_listener() as *mut _ as _);

            let socket = ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_add_socket_auto, display);
            if socket.is_null() {
                // NOTE Rationale for panicking:
                // * Won't be in C land just yet, so it's safe to panic
                // * Can always be returned in a Result instead, but for now
                //   if you auto create it's assumed you can't recover.
                panic!("Unable to open wayland socket");
            }
            let socket_name = CStr::from_ptr(socket).to_string_lossy().into_owned();
            wlr_log!(L_DEBUG,
                     "Running compositor on wayland display {}",
                     socket_name);
            env::set_var("_WAYLAND_DISPLAY", socket_name);
            Compositor {
                input_manager,
                output_manager,
                backend,
                display,
                event_loop,
                server_decoration_manager: None
            }
        }
    }

    /// Enters the wayland event loop. Won't return until the compositor is
    /// shut off
    pub fn run(self) {
        unsafe {
            let compositor = UnsafeCell::new(self);
            if COMPOSITOR_PTR != 0 as _ {
                // NOTE Rationale for panicking:
                // * Nicer than an abort
                // * Not yet in C land
                panic!("A compositor is already running!")
            }
            COMPOSITOR_PTR = compositor.get();
            wlr_log!(L_INFO, "Starting compositor");
            if !wlr_backend_start((*compositor.get()).backend) {
                wlr_backend_destroy((*compositor.get()).backend);
                // NOTE Rationale for panicking:
                // * Won't be in C land just yet, so it's safe to panic
                // * Can always be returned in a Result instead, but for now
                //   if you auto create it's assumed you can't recover.
                panic!("Failed to start backend");
            }
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_display_run,
                          (*compositor.get()).display);
        }
        // TODO Clean up
    }

    /// Adds the server decoration manager protocol.
    pub fn add_server_decoration_manager(&mut self) {
        if self.server_decoration_manager.is_some() {
            wlr_log!(L_ERROR, "Server decoration manager already loaded!");
            return
        }
        unsafe {
            self.server_decoration_manager = ServerDecorationManager::new(self.display);
            if self.server_decoration_manager.is_none() {
                wlr_log!(L_ERROR, "Server decoration manager could not be loaded");
            }
        }
    }

    pub fn server_decoration_manager(&mut self) -> Option<&mut ServerDecorationManager> {
        self.server_decoration_manager.as_mut()
    }

    fn terminate(&mut self) {
        unsafe {
            ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_terminate, self.display);
        }
    }
}

/// Terminates the compositor.
/// If one is not running, does nothing
pub fn terminate() {
    unsafe {
        if COMPOSITOR_PTR != 0 as _ {
            (*COMPOSITOR_PTR).terminate();
            COMPOSITOR_PTR = 0 as _
        }
    }
}
<commit_msg>fmtttt<commit_after>//! Main entry point to the library.
//! See examples for documentation on how to use this struct.

use manager::{InputManager, InputManagerHandler, OutputManager, OutputManagerHandler};
use std::cell::UnsafeCell;
use std::env;
use std::ffi::CStr;
use types::server_decoration::ServerDecorationManager;
use wayland_sys::server::{WAYLAND_SERVER_HANDLE, wl_display, wl_event_loop};
use wayland_sys::server::signal::wl_signal_add;
use wlroots_sys::{wlr_backend, wlr_backend_autocreate, wlr_backend_destroy, wlr_backend_start};

/// Global compositor pointer, used to refer to the compositor state unsafely.
static mut COMPOSITOR_PTR: *mut Compositor = 0 as *mut _;

#[allow(dead_code)]
pub struct Compositor {
    input_manager: Box<InputManager>,
    output_manager: Box<OutputManager>,
    backend: *mut wlr_backend,
    display: *mut wl_display,
    event_loop: *mut wl_event_loop,
    pub server_decoration_manager: Option<ServerDecorationManager>
}

impl Compositor {
    /// Makes a new compositor that handles the setup of the graphical backend
    /// (e.g, Wayland, X11, or DRM).
    ///
    /// Also automatically opens the socket for clients to communicate to the
    /// compositor with.
    pub fn new(input_manager_handler: Box<InputManagerHandler>,
               output_manager_handler: Box<OutputManagerHandler>)
               -> Self {
        unsafe {
            let display = ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_create,) as
                *mut wl_display;
            let event_loop =
                ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_get_event_loop, display);
            let backend = wlr_backend_autocreate(display as *mut _);
            if backend.is_null() {
                // NOTE Rationale for panicking:
                // * Won't be in C land just yet, so it's safe to panic
                // * Can always be returned in a Result instead, but for now
                //   if you auto create it's assumed you can't recover.
                panic!("Could not auto-create backend");
            }
            let mut input_manager = InputManager::new((vec![], input_manager_handler));
            let mut output_manager = OutputManager::new((vec![], output_manager_handler));
            wl_signal_add(&mut (*backend).events.input_add as *mut _ as _,
                          input_manager.add_listener() as *mut _ as _);
            wl_signal_add(&mut (*backend).events.input_remove as *mut _ as _,
                          input_manager.remove_listener() as *mut _ as _);
            wl_signal_add(&mut (*backend).events.output_add as *mut _ as _,
                          output_manager.add_listener() as *mut _ as _);
            wl_signal_add(&mut (*backend).events.output_remove as *mut _ as _,
                          output_manager.remove_listener() as *mut _ as _);

            let socket = ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_add_socket_auto, display);
            if socket.is_null() {
                // NOTE Rationale for panicking:
                // * Won't be in C land just yet, so it's safe to panic
                // * Can always be returned in a Result instead, but for now
                //   if you auto create it's assumed you can't recover.
                panic!("Unable to open wayland socket");
            }
            let socket_name = CStr::from_ptr(socket).to_string_lossy().into_owned();
            wlr_log!(L_DEBUG,
                     "Running compositor on wayland display {}",
                     socket_name);
            env::set_var("_WAYLAND_DISPLAY", socket_name);
            Compositor {
                input_manager,
                output_manager,
                backend,
                display,
                event_loop,
                server_decoration_manager: None
            }
        }
    }

    /// Enters the wayland event loop. Won't return until the compositor is
    /// shut off
    pub fn run(self) {
        unsafe {
            let compositor = UnsafeCell::new(self);
            if COMPOSITOR_PTR != 0 as _ {
                // NOTE Rationale for panicking:
                // * Nicer than an abort
                // * Not yet in C land
                panic!("A compositor is already running!")
            }
            COMPOSITOR_PTR = compositor.get();
            wlr_log!(L_INFO, "Starting compositor");
            if !wlr_backend_start((*compositor.get()).backend) {
                wlr_backend_destroy((*compositor.get()).backend);
                // NOTE Rationale for panicking:
                // * Won't be in C land just yet, so it's safe to panic
                // * Can always be returned in a Result instead, but for now
                //   if you auto create it's assumed you can't recover.
                panic!("Failed to start backend");
            }
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_display_run,
                          (*compositor.get()).display);
        }
        // TODO Clean up
    }

    /// Adds the server decoration manager protocol.
    pub fn add_server_decoration_manager(&mut self) {
        if self.server_decoration_manager.is_some() {
            wlr_log!(L_ERROR, "Server decoration manager already loaded!");
            return;
        }
        unsafe {
            self.server_decoration_manager = ServerDecorationManager::new(self.display);
            if self.server_decoration_manager.is_none() {
                wlr_log!(L_ERROR, "Server decoration manager could not be loaded");
            }
        }
    }

    pub fn server_decoration_manager(&mut self) -> Option<&mut ServerDecorationManager> {
        self.server_decoration_manager.as_mut()
    }

    fn terminate(&mut self) {
        unsafe {
            ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_terminate, self.display);
        }
    }
}

/// Terminates the compositor.
/// If one is not running, does nothing
pub fn terminate() {
    unsafe {
        if COMPOSITOR_PTR != 0 as _ {
            (*COMPOSITOR_PTR).terminate();
            COMPOSITOR_PTR = 0 as _
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Jauhien Piatlicki.
//
// Copyright 2012-2015 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Core LLVM: Value hierarchy
// LLVM-C header Core.h

use std;

use core;
use core::{TypeRef, ValueRef, UseRef};
use self::ffi::*;

pub trait Value {
    fn get_ref(&self) -> ValueRef;

    fn type_of(&self) -> TypeRef {
        unsafe {
            LLVMTypeOf(self.get_ref())
        }
    }

    fn get_name(&self) -> String {
        let buf = unsafe {
            std::ffi::CStr::from_ptr(LLVMGetValueName(self.get_ref()))
        };
        let result = String::from_utf8_lossy(buf.to_bytes()).into_owned();
        result
    }

    fn set_name(&self, name: &str) {
        unsafe {
            LLVMSetValueName(self.get_ref(), name.as_ptr() as *const i8)
        }
    }

    fn dump(&self) {
        unsafe {
            LLVMDumpValue(self.get_ref())
        }
    }

    fn print_to_string(&self) -> String {
        let buf = unsafe {
            std::ffi::CStr::from_ptr(LLVMPrintValueToString(self.get_ref()))
        };
        let result = String::from_utf8_lossy(buf.to_bytes()).into_owned();
        unsafe { core::ffi::LLVMDisposeMessage(buf.as_ptr()); }
        result
    }

    fn replace_all_uses_with(&self, new_val: &Value) {
        unsafe {
            LLVMReplaceAllUsesWith(self.get_ref(), new_val.get_ref())
        }
    }

    fn is_constant(&self) -> bool {
        unsafe {
            LLVMIsConstant(self.get_ref()) > 0
        }
    }

    fn is_undef(&self) -> bool {
        unsafe {
            LLVMIsUndef(self.get_ref()) > 0
        }
    }

    fn use_iter(&self) -> UseIter {
        let first = unsafe {
            LLVMGetFirstUse(self.get_ref())
        };

        let current = if first.is_null() {
            None
        } else {
            Some(first)
        };

        UseIter{current: current}
    }
}

impl Value for ValueRef {
    fn get_ref(&self) -> ValueRef {
        *self
    }
}

pub trait Use {
    fn get_ref(&self) -> UseRef;

    fn get_user(&self) -> ValueRef {
        unsafe {
            LLVMGetUser(self.get_ref())
        }
    }

    fn get_used_value(&self) -> ValueRef {
        unsafe {
            LLVMGetUsedValue(self.get_ref())
        }
    }
}

impl Use for UseRef {
    fn get_ref(&self) -> UseRef {
        *self
    }
}

pub struct UseIter {
    current: Option<UseRef>
}

impl Iterator for UseIter {
    type Item = UseRef;

    fn next(&mut self) -> Option<UseRef> {
        match self.current {
            Some(cur) => {
                let next = unsafe {
                    LLVMGetNextUse(cur)
                };
                self.current = if next.is_null() {
                    None
                } else {
                    Some(next)
                };

                self.current
            },
            None => None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        return (0, None)
    }
}

pub mod ffi {
    use ::Bool;
    use core::*;
    use libc::{c_char, c_uint};

    #[link(name = "LLVMCore")]
    extern {
        /* Operations on all values */

        /**
         * Obtain the type of a value.
         */
        pub fn LLVMTypeOf(Val: ValueRef) -> TypeRef;

        /**
         * Obtain the string name of a value.
         */
        pub fn LLVMGetValueName(Val: ValueRef) -> *const c_char;

        /**
         * Set the string name of a value.
         */
        pub fn LLVMSetValueName(Val: ValueRef, Name: *const c_char);

        /**
         * Dump a representation of a value to stderr.
         */
        pub fn LLVMDumpValue(Val: ValueRef);

        /**
         * Return a string representation of the value. Use
         * LLVMDisposeMessage to free the string.
         */
        pub fn LLVMPrintValueToString(Val: ValueRef) -> *const c_char;

        /**
         * Replace all uses of a value with another one.
         */
        pub fn LLVMReplaceAllUsesWith(OldVal: ValueRef, NewVal: ValueRef);

        /**
         * Determine whether the specified constant instance is constant.
         */
        pub fn LLVMIsConstant(Val: ValueRef) -> Bool;

        /**
         * Determine whether a value instance is undefined.
         */
        pub fn LLVMIsUndef(Val: ValueRef) -> Bool;

        /* Operations on Uses */

        /**
         * Obtain the first use of a value.
         *
         * Uses are obtained in an iterator fashion. First, call this function
         * to obtain a reference to the first use. Then, call LLVMGetNextUse()
         * on that instance and all subsequently obtained instances until
         * LLVMGetNextUse() returns NULL.
         */
        pub fn LLVMGetFirstUse(Val: ValueRef) -> UseRef;

        /**
         * Obtain the next use of a value.
         *
         * This effectively advances the iterator. It returns NULL if you are on
         * the final use and no more are available.
         */
        pub fn LLVMGetNextUse(U: UseRef) -> UseRef;

        /**
         * Obtain the user value for a user.
         *
         * The returned value corresponds to a llvm::User type.
         */
        pub fn LLVMGetUser(U: UseRef) -> ValueRef;

        /**
         * Obtain the value this use corresponds to.
         */
        pub fn LLVMGetUsedValue(U: UseRef) -> ValueRef;
    }
}
<commit_msg>[core] implement User<commit_after>// Copyright 2015 Jauhien Piatlicki.
//
// Copyright 2012-2015 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Core LLVM: Value hierarchy
// LLVM-C header Core.h

use std;

use core;
use core::{TypeRef, ValueRef, UseRef};
use self::ffi::*;

pub trait Value {
    fn get_ref(&self) -> ValueRef;

    fn type_of(&self) -> TypeRef {
        unsafe {
            LLVMTypeOf(self.get_ref())
        }
    }

    fn get_name(&self) -> String {
        let buf = unsafe {
            std::ffi::CStr::from_ptr(LLVMGetValueName(self.get_ref()))
        };
        let result = String::from_utf8_lossy(buf.to_bytes()).into_owned();
        result
    }

    fn set_name(&self, name: &str) {
        unsafe {
            LLVMSetValueName(self.get_ref(), name.as_ptr() as *const i8)
        }
    }

    fn dump(&self) {
        unsafe {
            LLVMDumpValue(self.get_ref())
        }
    }

    fn print_to_string(&self) -> String {
        let buf = unsafe {
            std::ffi::CStr::from_ptr(LLVMPrintValueToString(self.get_ref()))
        };
        let result = String::from_utf8_lossy(buf.to_bytes()).into_owned();
        unsafe { core::ffi::LLVMDisposeMessage(buf.as_ptr()); }
        result
    }

    fn replace_all_uses_with(&self, new_val: &Value) {
        unsafe {
            LLVMReplaceAllUsesWith(self.get_ref(), new_val.get_ref())
        }
    }

    fn is_constant(&self) -> bool {
        unsafe {
            LLVMIsConstant(self.get_ref()) > 0
        }
    }

    fn is_undef(&self) -> bool {
        unsafe {
            LLVMIsUndef(self.get_ref()) > 0
        }
    }

    fn use_iter(&self) -> UseIter {
        let first = unsafe {
            LLVMGetFirstUse(self.get_ref())
        };

        let current = if first.is_null() {
            None
        } else {
            Some(first)
        };

        UseIter{current: current}
    }
}

impl Value for ValueRef {
    fn get_ref(&self) -> ValueRef {
        *self
    }
}

pub trait Use {
    fn get_ref(&self) -> UseRef;

    fn get_user(&self) -> UserRef {
        unsafe {
            UserRef::Ref(LLVMGetUser(self.get_ref()))
        }
    }

    fn get_used_value(&self) -> ValueRef {
        unsafe {
            LLVMGetUsedValue(self.get_ref())
        }
    }
}

impl Use for UseRef {
    fn get_ref(&self) -> UseRef {
        *self
    }
}

pub struct UseIter {
    current: Option<UseRef>
}

impl Iterator for UseIter {
    type Item = UseRef;

    fn next(&mut self) -> Option<UseRef> {
        match self.current {
            Some(cur) => {
                let next = unsafe {
                    LLVMGetNextUse(cur)
                };
                self.current = if next.is_null() {
                    None
                } else {
                    Some(next)
                };

                self.current
            },
            None => None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        return (0, None)
    }
}

// TODO: implement iterator and some better indexing for User

pub enum UserRef {
    Ref(ValueRef)
}

impl Value for UserRef {
    fn get_ref(&self) -> ValueRef {
        match *self {
            UserRef::Ref(rf) => rf
        }
    }
}

pub trait User : Value {
    fn get_operand(&self, index: u32) -> ValueRef {
        unsafe {
            LLVMGetOperand(self.get_ref(), index)
        }
    }

    fn get_operand_use(&self, index: u32) -> UseRef {
        unsafe {
            LLVMGetOperandUse(self.get_ref(), index)
        }
    }

    fn set_operand(&self, index: u32, op: &Value) {
        unsafe {
            LLVMSetOperand(self.get_ref(), index, op.get_ref())
        }
    }

    fn get_num_operands(&self) -> i32 {
        unsafe {
            LLVMGetNumOperands(self.get_ref())
        }
    }
}

impl User for UserRef {}

pub mod ffi {
    use ::Bool;
    use core::*;
    use libc::{c_char, c_int, c_uint};

    #[link(name = "LLVMCore")]
    extern {
        /* Operations on all values */

        /**
         * Obtain the type of a value.
         */
        pub fn LLVMTypeOf(Val: ValueRef) -> TypeRef;

        /**
         * Obtain the string name of a value.
         */
        pub fn LLVMGetValueName(Val: ValueRef) -> *const c_char;

        /**
         * Set the string name of a value.
         */
        pub fn LLVMSetValueName(Val: ValueRef, Name: *const c_char);

        /**
         * Dump a representation of a value to stderr.
         */
        pub fn LLVMDumpValue(Val: ValueRef);

        /**
         * Return a string representation of the value. Use
         * LLVMDisposeMessage to free the string.
         */
        pub fn LLVMPrintValueToString(Val: ValueRef) -> *const c_char;

        /**
         * Replace all uses of a value with another one.
         */
        pub fn LLVMReplaceAllUsesWith(OldVal: ValueRef, NewVal: ValueRef);

        /**
         * Determine whether the specified constant instance is constant.
         */
        pub fn LLVMIsConstant(Val: ValueRef) -> Bool;

        /**
         * Determine whether a value instance is undefined.
         */
        pub fn LLVMIsUndef(Val: ValueRef) -> Bool;

        /* Operations on Uses */

        /**
         * Obtain the first use of a value.
         *
         * Uses are obtained in an iterator fashion. First, call this function
         * to obtain a reference to the first use. Then, call LLVMGetNextUse()
         * on that instance and all subsequently obtained instances until
         * LLVMGetNextUse() returns NULL.
         */
        pub fn LLVMGetFirstUse(Val: ValueRef) -> UseRef;

        /**
         * Obtain the next use of a value.
         *
         * This effectively advances the iterator. It returns NULL if you are on
         * the final use and no more are available.
         */
        pub fn LLVMGetNextUse(U: UseRef) -> UseRef;

        /**
         * Obtain the user value for a user.
         *
         * The returned value corresponds to a llvm::User type.
         */
        pub fn LLVMGetUser(U: UseRef) -> ValueRef;

        /**
         * Obtain the value this use corresponds to.
         */
        pub fn LLVMGetUsedValue(U: UseRef) -> ValueRef;

        /* Operations on Users */

        /**
         * Obtain an operand at a specific index in a llvm::User value.
         */
        pub fn LLVMGetOperand(Val: ValueRef, Index: c_uint) -> ValueRef;

        /**
         * Obtain the use of an operand at a specific index in a llvm::User value.
         */
        pub fn LLVMGetOperandUse(Val: ValueRef, Index: c_uint) -> UseRef;

        /**
         * Set an operand at a specific index in a llvm::User value.
         */
        pub fn LLVMSetOperand(Val: ValueRef, Index: c_uint, Op: ValueRef);

        /**
         * Obtain the number of operands in a llvm::User value.
         */
        pub fn LLVMGetNumOperands(Val: ValueRef) -> c_int;
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc;
use std::thread;
use std::result::Result;

use action::ExecResult;
use action::ActionHandlers;
use super::{config, Command, Context, Dispatcher, Event, Message, Timer};

const TIMER_STEP: u32 = 100;

pub struct Correlator {
    action_handlers: ActionHandlers,
    dispatcher_input_channel: mpsc::Sender<Command>,
    dispatcher_output_channel: mpsc::Receiver<ExecResult>,
    dispatcher_thread_handle: thread::JoinHandle<()>
}

impl Correlator {
    pub fn new(contexts: Vec<config::Context>, action_handlers: ActionHandlers) -> Correlator {
        let (dispatcher_input_channel, rx) = mpsc::channel();
        let (dispatcher_output_channel_tx, dispatcher_output_channel_rx) = mpsc::channel();
        let _ = Timer::from_chan(TIMER_STEP, dispatcher_input_channel.clone());

        let handle = thread::spawn(move || {
            let mut dispatcher = Dispatcher::new(contexts, dispatcher_output_channel_tx);

            for i in rx.iter() {
                match i {
                    Command::Dispatch(event) => dispatcher.dispatch(event),
                    Command::Exit => break
                }
            }
        });

        Correlator {
            action_handlers: action_handlers,
            dispatcher_input_channel: dispatcher_input_channel,
            dispatcher_output_channel: dispatcher_output_channel_rx,
            dispatcher_thread_handle: handle
        }
    }

    pub fn push_message(&mut self, message: Message) -> Result<(), mpsc::SendError<Command>> {
        for i in self.dispatcher_output_channel.try_recv() {
            self.action_handlers.handle(i);
        }

        self.dispatcher_input_channel.send(Command::Dispatch(Event::Message(message)))
    }

    pub fn stop(self) -> thread::Result<()> {
        let _ = self.dispatcher_input_channel.send(Command::Exit);
        self.dispatcher_thread_handle.join()
    }
}
<commit_msg>Correlator: consume unprocessed results right before stop() call<commit_after>use std::sync::mpsc;
use std::thread;
use std::result::Result;

use action::ExecResult;
use action::ActionHandlers;
use super::{config, Command, Context, Dispatcher, Event, Message, Timer};

const TIMER_STEP: u32 = 100;

pub struct Correlator {
    action_handlers: ActionHandlers,
    dispatcher_input_channel: mpsc::Sender<Command>,
    dispatcher_output_channel: mpsc::Receiver<ExecResult>,
    dispatcher_thread_handle: thread::JoinHandle<()>
}

impl Correlator {
    pub fn new(contexts: Vec<config::Context>, action_handlers: ActionHandlers) -> Correlator {
        let (dispatcher_input_channel, rx) = mpsc::channel();
        let (dispatcher_output_channel_tx, dispatcher_output_channel_rx) = mpsc::channel();
        let _ = Timer::from_chan(TIMER_STEP, dispatcher_input_channel.clone());

        let handle = thread::spawn(move || {
            let mut dispatcher = Dispatcher::new(contexts, dispatcher_output_channel_tx);

            for i in rx.iter() {
                match i {
                    Command::Dispatch(event) => dispatcher.dispatch(event),
                    Command::Exit => break
                }
            }
        });

        Correlator {
            action_handlers: action_handlers,
            dispatcher_input_channel: dispatcher_input_channel,
            dispatcher_output_channel: dispatcher_output_channel_rx,
            dispatcher_thread_handle: handle
        }
    }

    pub fn push_message(&mut self, message: Message) -> Result<(), mpsc::SendError<Command>> {
        Correlator::consume_all_remaining_results(&mut self.dispatcher_output_channel, &mut self.action_handlers);
        self.dispatcher_input_channel.send(Command::Dispatch(Event::Message(message)))
    }

    fn consume_all_remaining_results(channel: &mut mpsc::Receiver<ExecResult>, handlers: &mut ActionHandlers) {
        for i in channel.try_recv() {
            handlers.handle(i);
        }
    }

    pub fn stop(self) -> thread::Result<()> {
        let Correlator {
            action_handlers: mut handlers,
            dispatcher_input_channel: input,
            dispatcher_output_channel: mut output,
            dispatcher_thread_handle: thread_handle } = self;

        Correlator::consume_all_remaining_results(&mut output, &mut handlers);
        let _ = input.send(Command::Exit);
        let join_result = thread_handle.join();
        Correlator::consume_all_remaining_results(&mut output, &mut handlers);
        join_result
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

// We won't use the usual `main` function. We are going to use a different "entry point".
#![no_main]

// We won't use the standard library because it requires OS abstractions like threads and files and
// those are not available in this platform.
#![no_std]
#![feature(alloc)]

#[macro_use]
extern crate cc3200;
extern crate alloc;
extern crate freertos_rs;
extern crate freertos_alloc;
#[macro_use]
extern crate log;

use cc3200::cc3200::{Board, Console, Utils, LedEnum, LedName};

use alloc::arc::Arc;
use freertos_rs::{CurrentTask, Duration, Task, Queue};

static VERSION: &'static str = "1.0";

// Conceptually, this is our program "entry point". It's the first thing the microcontroller will
// execute when it (re)boots. (As far as the linker is concerned the entry point must be named
// `start` (by default; it can have a different name). That's why this function is `pub`lic, named
// `start` and is marked as `#[no_mangle]`.)
//
// Returning from this function is undefined because there is nothing to return to! To statically
// forbid returning from this function, we mark it as divergent, hence the `fn() -> !` signature.
#[no_mangle]
pub fn start() -> ! {

    Board::init();

    info!("Welcome to CC3200 blinking leds version {}", VERSION);

    Board::test();

    let queue = Arc::new(Queue::new(10).unwrap());
    let _producer = {
        let queue = queue.clone();
        Task::new()
            .name("producer")
            .start(move || {
                let msgs = ["Welcome ", "to ", "CC32xx ", "development !\n"];
                loop {
                    for msg in msgs.iter() {
                        queue.send(msg, Duration::ms(15)).unwrap();
                        CurrentTask::delay(Duration::ms(15))
                    }
                    CurrentTask::delay(Duration::ms(1000))
                }
            })
            .unwrap()
    };

    let _consumer = {
        let queue = queue.clone();
        Task::new()
            .name("consumer")
            .start(move || {
                loop {
                    let msg = queue.receive(Duration::ms(2000)).unwrap();
                    Console::message("Received: ");
                    Console::message(msg);
                    Console::message("\n");
                }
            })
            .unwrap()
    };

    let _blinky = {
        Task::new()
            .name("blinky")
            .start(|| {
                Board::led_configure(&[LedEnum::LED1, LedEnum::LED2, LedEnum::LED3]);
                Board::led_off(LedName::MCU_ALL_LED_IND);
                loop {
                    Board::led_on(LedName::MCU_RED_LED_GPIO);
                    Utils::delay(1333333);
                    Board::led_off(LedName::MCU_RED_LED_GPIO);
                    Utils::delay(1333333);
                    Board::led_on(LedName::MCU_RED_LED_GPIO);
                    Utils::delay(1333333);
                    Board::led_off(LedName::MCU_RED_LED_GPIO);
                    Utils::delay(1333333 * 7);
                }
            })
            .unwrap()
    };

    Board::start_scheduler();

    // The only reason start_scheduler should fail is if there wasn't enough
    // heap to initialize the IDLE and timer tasks

    loop {}
}
<commit_msg>Change blinky to use FreRTPOS delay rather than busy wait.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

// We won't use the usual `main` function. We are going to use a different "entry point".
#![no_main]

// We won't use the standard library because it requires OS abstractions like threads and files and
// those are not available in this platform.
#![no_std]
#![feature(alloc)]

#[macro_use]
extern crate cc3200;
extern crate alloc;
extern crate freertos_rs;
extern crate freertos_alloc;
#[macro_use]
extern crate log;

use cc3200::cc3200::{Board, Console, LedEnum, LedName};

use alloc::arc::Arc;
use freertos_rs::{CurrentTask, Duration, Task, Queue};

static VERSION: &'static str = "1.0";

// Conceptually, this is our program "entry point". It's the first thing the microcontroller will
// execute when it (re)boots. (As far as the linker is concerned the entry point must be named
// `start` (by default; it can have a different name). That's why this function is `pub`lic, named
// `start` and is marked as `#[no_mangle]`.)
//
// Returning from this function is undefined because there is nothing to return to! To statically
// forbid returning from this function, we mark it as divergent, hence the `fn() -> !` signature.
#[no_mangle]
pub fn start() -> ! {

    Board::init();

    info!("Welcome to CC3200 blinking leds version {}", VERSION);

    Board::test();

    let queue = Arc::new(Queue::new(10).unwrap());
    let _producer = {
        let queue = queue.clone();
        Task::new()
            .name("producer")
            .start(move || {
                let msgs = ["Welcome ", "to ", "CC32xx ", "development !\n"];
                loop {
                    for msg in msgs.iter() {
                        queue.send(msg, Duration::ms(15)).unwrap();
                        CurrentTask::delay(Duration::ms(15));
                    }
                    CurrentTask::delay(Duration::ms(1000));
                }
            })
            .unwrap()
    };

    let _consumer = {
        let queue = queue.clone();
        Task::new()
            .name("consumer")
            .start(move || {
                loop {
                    let msg = queue.receive(Duration::ms(2000)).unwrap();
                    Console::message("Received: ");
                    Console::message(msg);
                    Console::message("\n");
                }
            })
            .unwrap()
    };

    let _blinky = {
        Task::new()
            .name("blinky")
            .start(|| {
                Board::led_configure(&[LedEnum::LED1, LedEnum::LED2, LedEnum::LED3]);
                Board::led_off(LedName::MCU_ALL_LED_IND);
                loop {
                    Board::led_on(LedName::MCU_RED_LED_GPIO);
                    CurrentTask::delay(Duration::ms(100));
                    Board::led_off(LedName::MCU_RED_LED_GPIO);
                    CurrentTask::delay(Duration::ms(100));
                    Board::led_on(LedName::MCU_RED_LED_GPIO);
                    CurrentTask::delay(Duration::ms(100));
                    Board::led_off(LedName::MCU_RED_LED_GPIO);
                    CurrentTask::delay(Duration::ms(700));
                }
            })
            .unwrap()
    };

    Board::start_scheduler();

    // The only reason start_scheduler should fail is if there wasn't enough
    // heap to initialize the IDLE and timer tasks

    loop {}
}
<|endoftext|>


<commit_before>extern crate fuse;
extern crate libc;
extern crate time;
extern crate argparse;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::string::String;
use std::fmt;
use std::env;
use std::path::Path;
use std::collections::{HashMap, HashSet};
use std::ffi::OsStr;

use log::LogLevel::Debug;

use libc::{ENOSYS,c_int,ENOENT};
use time::Timespec;
use argparse::{ArgumentParser, StoreTrue, Store};
use fuse::{FileType, FileAttr, Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyEmpty, ReplyDirectory};
use fuse::argument::ArgumentIterator;

// FIXME these are ugly as fuck and it seems like a BAD DECISION to have these kind of macros in rust.
// FIXME in any case, clean up our usage of these later.
// from: http://stackoverflow.com/questions/28392008/more-concise-hashmap-initialization
// auto-converts to String
macro_rules! hashmap {
    ($( $key: expr => $val: expr ),*) => {{
         let mut map = ::std::collections::HashMap::new();
         $( map.insert($key.to_string(), $val); )*
         map
    }}
}
// similar to above, jesus christ this is terrible
macro_rules! hashset {
    ($( $x: expr ),* ) => {{
            let mut set = HashSet::new();
            $( set.insert($x.to_string()); )*
            set
    }}
}

const TTL: Timespec = Timespec { sec: 1, nsec: 0 };                 // 1 second

const CREATE_TIME: Timespec = Timespec { sec: 1381237736, nsec: 0 };    // 2013-10-08 08:56

const HELLO_DIR_ATTR: FileAttr = FileAttr {
    ino: 1,
    size: 0,
    blocks: 0,
    atime: CREATE_TIME,
    mtime: CREATE_TIME,
    ctime: CREATE_TIME,
    crtime: CREATE_TIME,
    kind: FileType::Directory,
    perm: 0o755,
    nlink: 2,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

const HELLO_TXT_CONTENT: &'static str = "Hello World!\n";

const HELLO_TXT_ATTR: FileAttr = FileAttr {
    ino: 2,
    size: 13,
    blocks: 1,
    atime: CREATE_TIME,
    mtime: CREATE_TIME,
    ctime: CREATE_TIME,
    crtime: CREATE_TIME,
    kind: FileType::RegularFile,
    perm: 0o644,
    nlink: 1,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

struct UrchinFSEntry {
    display_name: String,
    destination: String,
    metadata: HashMap<String, HashSet<String>>
}

struct UrchinFS {
    entries: Vec<UrchinFSEntry>
}

impl Filesystem for UrchinFS {
    fn lookup (&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        info!("lookup parent:{} name:{}", parent, name.to_str().unwrap());
        if parent == 1 && name.to_str() == Some("hello.txt") {
            reply.entry(&TTL, &HELLO_TXT_ATTR, 0);
        } else {
            reply.error(ENOENT);
        }
    }

    fn getattr (&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        info!("getattr {}", ino);
        match ino {
            1 => reply.attr(&TTL, &HELLO_DIR_ATTR),
            2 => reply.attr(&TTL, &HELLO_TXT_ATTR),
            _ => reply.error(ENOENT),
        }
    }

    fn read (&mut self, _req: &Request, ino: u64, _fh: u64, offset: u64, _size: u32, reply: ReplyData) {
        info!("read ino:{} offset:{}", ino, offset);
        if ino == 2 {
            reply.data(&HELLO_TXT_CONTENT.as_bytes()[offset as usize..]);
        } else {
            reply.error(ENOENT);
        }
    }

    fn readdir (&mut self, _req: &Request, ino: u64, _fh: u64, offset: u64, mut reply: ReplyDirectory) {
        let mut data = ArgumentIterator::new(_req.data);
        info!("readdir path?? {}", data.fetch_path().to_str().unwrap());

        // FIXME correct besides field/type visibility
        //let mut data = ArgumentIterator::new(_req.data);
        //info!("readdir path?? {}", data.fetch_path().to_str().unwrap());
        info!("readdir ino:{} offset:{}", ino, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, ".");
                reply.add(1, 1, FileType::Directory, "..");
                reply.add(2, 2, FileType::RegularFile, "hello.txt");
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }

    fn access (&mut self, _req: &Request, ino: u64, _mask: u32, reply: ReplyEmpty) {
        info!("access ino:{}", ino);
        reply.error(ENOSYS);
    }
}

fn main () {
    env_logger::init().unwrap();

    let mut mountpoint = String::new();
    let mut optstr = String::new();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("faceted-search FUSE filesystem");
        ap.refer(&mut optstr).add_option(&["-o", "--options"], Store, "comma-separated mount options");
        ap.refer(&mut mountpoint).add_argument("mountpoint", Store, "the mountpoint").required();
        ap.parse_args_or_exit();
    }

// -o plugin=foo,plugin=bar,source=/home/kellen/films/,glob=*.json,format=json,watch=true,type=directory,formatter=generic
// FIXME dynamically load plugins for globbing/formatting see:
// http://stackoverflow.com/questions/22461457/does-rust-have-a-dlopen-equivalent

    // FIXME seems weird to have to have two variable refs
    let vec;
    let mut options : &[&OsStr] = &[];
    if optstr.trim() != "" {
        vec = optstr.trim().split(",").map(|s| OsStr::new(s)).collect::<Vec<_>>();
        options = &vec;
    }

    if log_enabled!(Debug) {
        if options.len() > 0 {
            debug!("using options:");
            for s in options {
                match s.to_str() {
                    Some(y) => {debug!("\t{}", y);}
                    None => {}
                }
            }
        }
    }

    // FIMXE do this better
    let easter = UrchinFSEntry {
        display_name: "Easter Parade (1948, color)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1948"], "color" => hashset!["color"]]
    };
    let city = UrchinFSEntry {
        display_name: "The Naked City (1948, bw)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1948"], "color" => hashset!["black-and-white"]]
    };
    let vanish = UrchinFSEntry {
        display_name: "The Lady Vanishes (1938, bw)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1938"], "color" => hashset!["black-and-white"]]
    };
    let kiss = UrchinFSEntry {
        display_name: "Kiss Me Deadly (1955, bw)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1955"], "color" => hashset!["black-and-white"]]
    };

    fuse::mount(UrchinFS {entries: vec![easter, city, vanish, kiss]}, &mountpoint, options);
}
<commit_msg>test with modified rust-fuse<commit_after>extern crate fuse;
extern crate libc;
extern crate time;
extern crate argparse;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::string::String;
use std::fmt;
use std::env;
use std::path::Path;
use std::collections::{HashMap, HashSet};
use std::ffi::{CStr, OsStr};
use std::os::unix::ffi::OsStrExt;
use libc::c_char;

use log::LogLevel::Debug;

use libc::{ENOSYS,c_int,ENOENT};
use time::Timespec;
use argparse::{ArgumentParser, StoreTrue, Store};
use fuse::{FileType, FileAttr, Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyEmpty, ReplyDirectory};

// FIXME these are ugly as fuck and it seems like a BAD DECISION to have these kind of macros in rust.
// FIXME in any case, clean up our usage of these later.
// from: http://stackoverflow.com/questions/28392008/more-concise-hashmap-initialization
// auto-converts to String
macro_rules! hashmap {
    ($( $key: expr => $val: expr ),*) => {{
         let mut map = ::std::collections::HashMap::new();
         $( map.insert($key.to_string(), $val); )*
         map
    }}
}
// similar to above, jesus christ this is terrible
macro_rules! hashset {
    ($( $x: expr ),* ) => {{
            let mut set = HashSet::new();
            $( set.insert($x.to_string()); )*
            set
    }}
}

const TTL: Timespec = Timespec { sec: 1, nsec: 0 };                 // 1 second

const CREATE_TIME: Timespec = Timespec { sec: 1381237736, nsec: 0 };    // 2013-10-08 08:56

const HELLO_DIR_ATTR: FileAttr = FileAttr {
    ino: 1,
    size: 0,
    blocks: 0,
    atime: CREATE_TIME,
    mtime: CREATE_TIME,
    ctime: CREATE_TIME,
    crtime: CREATE_TIME,
    kind: FileType::Directory,
    perm: 0o755,
    nlink: 2,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

const HELLO_TXT_CONTENT: &'static str = "Hello World!\n";

const HELLO_TXT_ATTR: FileAttr = FileAttr {
    ino: 2,
    size: 13,
    blocks: 1,
    atime: CREATE_TIME,
    mtime: CREATE_TIME,
    ctime: CREATE_TIME,
    crtime: CREATE_TIME,
    kind: FileType::RegularFile,
    perm: 0o644,
    nlink: 1,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

struct UrchinFSEntry {
    display_name: String,
    destination: String,
    metadata: HashMap<String, HashSet<String>>
}

struct UrchinFS {
    entries: Vec<UrchinFSEntry>
}

impl Filesystem for UrchinFS {
    fn lookup (&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        info!("lookup parent:{} name:{}", parent, name.to_str().unwrap());
        if parent == 1 && name.to_str() == Some("hello.txt") {
            reply.entry(&TTL, &HELLO_TXT_ATTR, 0);
        } else {
            reply.error(ENOENT);
        }
    }

    fn getattr (&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        info!("getattr {}", ino);
        match ino {
            1 => reply.attr(&TTL, &HELLO_DIR_ATTR),
            2 => reply.attr(&TTL, &HELLO_TXT_ATTR),
            _ => reply.error(ENOENT),
        }
    }

    fn read (&mut self, _req: &Request, ino: u64, _fh: u64, offset: u64, _size: u32, reply: ReplyData) {
        info!("read ino:{} offset:{}", ino, offset);
        if ino == 2 {
            reply.data(&HELLO_TXT_CONTENT.as_bytes()[offset as usize..]);
        } else {
            reply.error(ENOENT);
        }
    }

    fn readdir (&mut self, _req: &Request, ino: u64, _fh: u64, offset: u64, mut reply: ReplyDirectory) {

        let ptr = unsafe { _req.data.as_ptr()};
        let s = unsafe { CStr::from_ptr(ptr as *const c_char) };

        info!("readdir data?? {}", OsStr::from_bytes(s.to_bytes()).to_str().unwrap());

        // FIXME correct besides field/type visibility
        //let mut data = ArgumentIterator::new(_req.data);
        //info!("readdir path?? {}", data.fetch_path().to_str().unwrap());
        info!("readdir ino:{} offset:{}", ino, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, ".");
                reply.add(1, 1, FileType::Directory, "..");
                reply.add(2, 2, FileType::RegularFile, "hello.txt");
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }

    fn access (&mut self, _req: &Request, ino: u64, _mask: u32, reply: ReplyEmpty) {
        info!("access ino:{}", ino);
        reply.error(ENOSYS);
    }
}

fn main () {
    env_logger::init().unwrap();

    let mut mountpoint = String::new();
    let mut optstr = String::new();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("faceted-search FUSE filesystem");
        ap.refer(&mut optstr).add_option(&["-o", "--options"], Store, "comma-separated mount options");
        ap.refer(&mut mountpoint).add_argument("mountpoint", Store, "the mountpoint").required();
        ap.parse_args_or_exit();
    }

// -o plugin=foo,plugin=bar,source=/home/kellen/films/,glob=*.json,format=json,watch=true,type=directory,formatter=generic
// FIXME dynamically load plugins for globbing/formatting see:
// http://stackoverflow.com/questions/22461457/does-rust-have-a-dlopen-equivalent

    // FIXME seems weird to have to have two variable refs
    let vec;
    let mut options : &[&OsStr] = &[];
    if optstr.trim() != "" {
        vec = optstr.trim().split(",").map(|s| OsStr::new(s)).collect::<Vec<_>>();
        options = &vec;
    }

    if log_enabled!(Debug) {
        if options.len() > 0 {
            debug!("using options:");
            for s in options {
                match s.to_str() {
                    Some(y) => {debug!("\t{}", y);}
                    None => {}
                }
            }
        }
    }

    // FIMXE do this better
    let easter = UrchinFSEntry {
        display_name: "Easter Parade (1948, color)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1948"], "color" => hashset!["color"]]
    };
    let city = UrchinFSEntry {
        display_name: "The Naked City (1948, bw)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1948"], "color" => hashset!["black-and-white"]]
    };
    let vanish = UrchinFSEntry {
        display_name: "The Lady Vanishes (1938, bw)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1938"], "color" => hashset!["black-and-white"]]
    };
    let kiss = UrchinFSEntry {
        display_name: "Kiss Me Deadly (1955, bw)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1955"], "color" => hashset!["black-and-white"]]
    };

    fuse::mount(UrchinFS {entries: vec![easter, city, vanish, kiss]}, &mountpoint, options);
}
<|endoftext|>


<commit_before>pub mod search;

use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::time::SystemTime;
use basetypes::*;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use position::Position;
use chess_move::*;
use tt::TranspositionTable;

// use rand;
// use rand::distributions::{Sample, Range};
// let mut rng = rand::thread_rng();
// let mut between = Range::new(0, 10);
// let x = between.sample(&mut rng);

const VERSION: &'static str = "0.1";

/// Implements `UciEngine` trait.
pub struct Engine {
    position: Position,
    pondering_is_allowed: bool,
    is_thinking: bool,
    is_pondering: bool,
    replies: Vec<EngineReply>,
    infinite: bool,
    tt: Arc<TranspositionTable>,
    commands: Sender<search::Command>,
    reports: Receiver<search::Report>,
    started_thinking_at: SystemTime,
    curr_depth: u8,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt = Arc::new(tt);
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        let tt2 = tt.clone();
        thread::spawn(move || {
            search::run_deepening(tt2, commands_rx, reports_tx);
        });

        Engine {
            position: Position::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 \
                                          1")
                          .ok()
                          .unwrap(),
            pondering_is_allowed: false,
            is_thinking: false,
            is_pondering: false,
            replies: vec![],
            infinite: false,
            tt: tt,
            commands: commands_tx,
            reports: reports_rx,
            started_thinking_at: SystemTime::now(),
            curr_depth: 0,
        }
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            // We do not support re-sizing of the transposition table
            // once the engine had started, so we do nothing.
            "Hash" => (),

            // Tells the engine that it will be allowed to ponder.
            // This option is needed because the engine might change
            // its time management algorithm when pondering is
            // allowed.
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            // An invalid option.
            _ => {
                self.replies.push(EngineReply::Info(vec![("string".to_string(),
                                                          format!("Invalid option \"{}\"", name))]));
            }
        }
    }

    fn new_game(&mut self) {
        // Clearing the transposition table would not change anything,
        // so we do nothing.
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if !self.is_thinking {
            if let Ok(p) = Position::from_history(fen, moves) {
                self.position = p;
                self.tt.new_search();
            }
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        if !self.is_thinking {
            self.commands
                .send(search::Command::Search {
                    search_id: 0,
                    position: self.position.clone(),
                    depth: 126,
                    lower_bound: -20000,
                    upper_bound: 20000,
                })
                .unwrap();
            self.is_thinking = true;
            self.is_pondering = ponder;
            self.infinite = infinite;
            self.started_thinking_at = SystemTime::now();
            self.curr_depth = 0;
        }
    }

    fn ponder_hit(&mut self) {
        if self.is_thinking && self.is_pondering {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        if self.is_thinking {
            self.commands.send(search::Command::Stop).unwrap();
            let best_move = self.get_best_move();
            self.replies.push(EngineReply::BestMove {
                best_move: best_move,
                ponder_move: None,
            });
            self.is_thinking = false;
        }
    }

    fn is_thinking(&self) -> bool {
        self.is_thinking
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        // TODO: implement real time management here.
        if self.is_thinking && !self.is_pondering && !self.infinite &&
           self.started_thinking_at.elapsed().unwrap().as_secs() > 3 {
            self.stop();
        }

        // Empty the reports queue.
        while let Ok(report) = self.reports.try_recv() {
            // let rep_type = match report {
            //     search::Report::Progress { searched_nodes, .. } => format!("progress {}", searched_nodes),
            //     search::Report::Done { .. } => "done".to_string(),
            // };
            // self.replies.push(EngineReply::Info(vec![
            //     ("string".to_string(), rep_type),
            // ]));
            if self.is_thinking {
                match report {
                    search::Report::Progress { searched_nodes, depth, .. } => {
                        if self.curr_depth < depth {
                            self.curr_depth = depth;
                            let mut p = self.position.clone();
                            let mut v = MoveStack::new();
                            let mut pv = String::from("");
                            let mut pv_length = 0;
                            let mut value = None;
                            'depthloop: for _ in 0..depth {
                                let m = match self.tt.probe(p.hash()) {
                                    Some(entry) => {
                                        if value.is_none() {
                                            value = Some(entry.value());
                                        }
                                        entry.move16()
                                    }
                                    None => 0,
                                };
                                if m != 0 {
                                    p.generate_moves(&mut v);
                                    while let Some(x) = v.pop() {
                                        if x.digest() == m && p.do_move(x) {
                                            pv_length += 1;
                                            pv.push_str(&x.notation());
                                            pv.push(' ');
                                            v.clear();
                                            continue 'depthloop;
                                        }
                                    }
                                }
                                break;
                            }
                            let duration = self.started_thinking_at.elapsed().unwrap();
                            let elapsed_time_milis = 1000 * duration.as_secs() +
                                                     (duration.subsec_nanos() / 1000000) as u64;
                            if searched_nodes > 0 && pv_length >= depth {
                                self.replies.push(EngineReply::Info(vec![
                                    ("depth".to_string(), format!("{}", depth)),
                                    ("score".to_string(), format!("cp {}", value.unwrap_or(666))),
                                    ("nodes".to_string(), format!("{}", searched_nodes)),
                                    ("time".to_string(), format!("{}", elapsed_time_milis)),
                                    ("pv".to_string(), format!("{}", pv)),
                                ]));
                            }
                        }
                    }
                    _ => (),
                }
            }
        }

        if self.replies.len() > 0 {
            Some(self.replies.remove(0))
        } else {
            None
        }
    }
}

impl Engine {
    fn get_best_move(&mut self) -> String {
        let mut m = match self.tt.probe(self.position.hash()) {
            Some(entry) => entry.move16(),
            None => 0,
        };
        if m == 0 {
            // Pick the first legal move.
            let mut first_legal_move = Move::invalid();
            let mut v = MoveStack::new();
            self.position.generate_moves(&mut v);
            while let Some(x) = v.pop() {
                if self.position.do_move(x) {
                    self.position.undo_move();
                    first_legal_move = x;
                    break;
                }
            }
            m = first_legal_move.digest();
        }
        if m != 0 {
            let move_type = move_type(m);
            let orig_square = orig_square(m);
            let dest_square = dest_square(m);
            let promoted_piece = match aux_data(m) {
                0 => "q",
                1 => "r",
                2 => "b",
                3 => "n",
                _ => panic!("invalid promoted piece code"),
            };
            format!("{}{}{}",
                    notation(orig_square),
                    notation(dest_square),
                    if move_type == MOVE_PROMOTION {
                        promoted_piece
                    } else {
                        ""
                    })

        } else {
            "0000".to_string()
        }
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("Alcibiades {}", VERSION)
    }

    fn author(&self) -> String {
        "Evgeni Pandurski".to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}
<commit_msg>remove unnecessary Hash setoption case<commit_after>pub mod search;

use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::time::SystemTime;
use basetypes::*;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use position::Position;
use chess_move::*;
use tt::TranspositionTable;

// use rand;
// use rand::distributions::{Sample, Range};
// let mut rng = rand::thread_rng();
// let mut between = Range::new(0, 10);
// let x = between.sample(&mut rng);

const VERSION: &'static str = "0.1";

/// Implements `UciEngine` trait.
pub struct Engine {
    position: Position,
    pondering_is_allowed: bool,
    is_thinking: bool,
    is_pondering: bool,
    replies: Vec<EngineReply>,
    infinite: bool,
    tt: Arc<TranspositionTable>,
    commands: Sender<search::Command>,
    reports: Receiver<search::Report>,
    started_thinking_at: SystemTime,
    curr_depth: u8,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt = Arc::new(tt);
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        let tt2 = tt.clone();
        thread::spawn(move || {
            search::run_deepening(tt2, commands_rx, reports_tx);
        });

        Engine {
            position: Position::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 \
                                          1")
                          .ok()
                          .unwrap(),
            pondering_is_allowed: false,
            is_thinking: false,
            is_pondering: false,
            replies: vec![],
            infinite: false,
            tt: tt,
            commands: commands_tx,
            reports: reports_rx,
            started_thinking_at: SystemTime::now(),
            curr_depth: 0,
        }
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            // Tells the engine that it will be allowed to ponder.
            // This option is needed because the engine might change
            // its time management algorithm when pondering is
            // allowed.
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            // An invalid option. Notice that we do not support
            // re-sizing of the transposition table once the engine
            // had started.
            _ => ()
        }
    }

    fn new_game(&mut self) {
        // Clearing the transposition table would not change anything,
        // so we do nothing.
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if !self.is_thinking {
            if let Ok(p) = Position::from_history(fen, moves) {
                self.position = p;
                self.tt.new_search();
            }
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        if !self.is_thinking {
            self.commands
                .send(search::Command::Search {
                    search_id: 0,
                    position: self.position.clone(),
                    depth: 126,
                    lower_bound: -20000,
                    upper_bound: 20000,
                })
                .unwrap();
            self.is_thinking = true;
            self.is_pondering = ponder;
            self.infinite = infinite;
            self.started_thinking_at = SystemTime::now();
            self.curr_depth = 0;
        }
    }

    fn ponder_hit(&mut self) {
        if self.is_thinking && self.is_pondering {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        if self.is_thinking {
            self.commands.send(search::Command::Stop).unwrap();
            let best_move = self.get_best_move();
            self.replies.push(EngineReply::BestMove {
                best_move: best_move,
                ponder_move: None,
            });
            self.is_thinking = false;
        }
    }

    fn is_thinking(&self) -> bool {
        self.is_thinking
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        // TODO: implement real time management here.
        if self.is_thinking && !self.is_pondering && !self.infinite &&
           self.started_thinking_at.elapsed().unwrap().as_secs() > 3 {
            self.stop();
        }

        // Empty the reports queue.
        while let Ok(report) = self.reports.try_recv() {
            // let rep_type = match report {
            //     search::Report::Progress { searched_nodes, .. } => format!("progress {}", searched_nodes),
            //     search::Report::Done { .. } => "done".to_string(),
            // };
            // self.replies.push(EngineReply::Info(vec![
            //     ("string".to_string(), rep_type),
            // ]));
            if self.is_thinking {
                match report {
                    search::Report::Progress { searched_nodes, depth, .. } => {
                        if self.curr_depth < depth {
                            self.curr_depth = depth;
                            let mut p = self.position.clone();
                            let mut v = MoveStack::new();
                            let mut pv = String::from("");
                            let mut pv_length = 0;
                            let mut value = None;
                            'depthloop: for _ in 0..depth {
                                let m = match self.tt.probe(p.hash()) {
                                    Some(entry) => {
                                        if value.is_none() {
                                            value = Some(entry.value());
                                        }
                                        entry.move16()
                                    }
                                    None => 0,
                                };
                                if m != 0 {
                                    p.generate_moves(&mut v);
                                    while let Some(x) = v.pop() {
                                        if x.digest() == m && p.do_move(x) {
                                            pv_length += 1;
                                            pv.push_str(&x.notation());
                                            pv.push(' ');
                                            v.clear();
                                            continue 'depthloop;
                                        }
                                    }
                                }
                                break;
                            }
                            let duration = self.started_thinking_at.elapsed().unwrap();
                            let elapsed_time_milis = 1000 * duration.as_secs() +
                                                     (duration.subsec_nanos() / 1000000) as u64;
                            if searched_nodes > 0 && pv_length >= depth {
                                self.replies.push(EngineReply::Info(vec![
                                    ("depth".to_string(), format!("{}", depth)),
                                    ("score".to_string(), format!("cp {}", value.unwrap_or(666))),
                                    ("nodes".to_string(), format!("{}", searched_nodes)),
                                    ("time".to_string(), format!("{}", elapsed_time_milis)),
                                    ("pv".to_string(), format!("{}", pv)),
                                ]));
                            }
                        }
                    }
                    _ => (),
                }
            }
        }

        if self.replies.len() > 0 {
            Some(self.replies.remove(0))
        } else {
            None
        }
    }
}

impl Engine {
    fn get_best_move(&mut self) -> String {
        let mut m = match self.tt.probe(self.position.hash()) {
            Some(entry) => entry.move16(),
            None => 0,
        };
        if m == 0 {
            // Pick the first legal move.
            let mut first_legal_move = Move::invalid();
            let mut v = MoveStack::new();
            self.position.generate_moves(&mut v);
            while let Some(x) = v.pop() {
                if self.position.do_move(x) {
                    self.position.undo_move();
                    first_legal_move = x;
                    break;
                }
            }
            m = first_legal_move.digest();
        }
        if m != 0 {
            let move_type = move_type(m);
            let orig_square = orig_square(m);
            let dest_square = dest_square(m);
            let promoted_piece = match aux_data(m) {
                0 => "q",
                1 => "r",
                2 => "b",
                3 => "n",
                _ => panic!("invalid promoted piece code"),
            };
            format!("{}{}{}",
                    notation(orig_square),
                    notation(dest_square),
                    if move_type == MOVE_PROMOTION {
                        promoted_piece
                    } else {
                        ""
                    })

        } else {
            "0000".to_string()
        }
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("Alcibiades {}", VERSION)
    }

    fn author(&self) -> String {
        "Evgeni Pandurski".to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}
<|endoftext|>


<commit_before>pub mod event;
pub mod scene;
pub mod entity;
pub mod graphics;
pub mod audio;

use std::cell::RefCell;
use std::rc::Rc;
use std::thread;
use std::time::Duration;
use std::ops::Deref;
use std::mem;
use glium::glutin;
use ncollide::shape::{Plane, Cuboid, ShapeHandle2};
use ncollide::query::Proximity;
use nalgebra::Vector2;
use ncollide::world::GeometricQueryType;
use clock_ticks;

use self::entity::component::PhysicsData;
use self::scene::PhysicsInteraction;

pub struct Engine<E: entity::Entity> {
    pub events: Rc<RefCell<event::Handler<E>>>,
    pub scene: scene::Scene<E>,
    pub graphics: Rc<RefCell<graphics::Graphics>>,
    pub audio: Rc<RefCell<audio::Audio>>,
}

impl<E: entity::Entity> Engine<E> {
    pub fn new() -> Engine<E> {
        // Default physics dimensions are 400x400 - a square which has a half length 200 units away
        // from the origin
        let scene = scene::Scene::new(200.0);

        let plane_left = ShapeHandle2::new(Plane::new(Vector2::x()));
        let plane_bottom = ShapeHandle2::new(Plane::new(Vector2::y()));
        let plane_right = ShapeHandle2::new(Plane::new(-Vector2::x()));
        let plane_top = ShapeHandle2::new(Plane::new(-Vector2::y()));

        let plane_data = Rc::new(PhysicsData::new(0, String::from("view_border")));

        scene.physics.add(Vector2::new(-200.0, 0.0),
                          plane_left,
                          PhysicsInteraction::Interactive,
                          GeometricQueryType::Contacts(0.2),
                          plane_data.clone());
        scene.physics.add(Vector2::new(0.0, -200.0),
                          plane_bottom,
                          PhysicsInteraction::Interactive,
                          GeometricQueryType::Contacts(0.2),
                          plane_data.clone());
        scene.physics.add(Vector2::new(200.0, 0.0),
                          plane_right,
                          PhysicsInteraction::Interactive,
                          GeometricQueryType::Contacts(0.2),
                          plane_data.clone());
        scene.physics.add(Vector2::new(0.0, 200.0),
                          plane_top,
                          PhysicsInteraction::Interactive,
                          GeometricQueryType::Contacts(0.2),
                          plane_data.clone());

        let rect = ShapeHandle2::new(Cuboid::new(Vector2::new(200.0, 200.0)));
        let rect_data = Rc::new(PhysicsData::new(0, String::from("view_area")));
        scene.physics.add(Vector2::new(0.0, 0.0),
                          rect,
                          PhysicsInteraction::Interactive,
                          GeometricQueryType::Proximity(0.2),
                          rect_data);

        let eh = event::Handler::new();
        let queue = eh.queue.clone();
        let events = Rc::new(RefCell::new(eh));
        scene.physics.register_handlers(queue);

        Engine {
            events: events,
            scene: scene,
            graphics: Rc::new(RefCell::new(graphics::Graphics::new())),
            audio: Rc::new(RefCell::new(audio::Audio::new())),
        }
    }

    pub fn spawn(&self, spawner: Box<Fn(&Engine<E>) -> E>) {
        let mut e = spawner(&self);
        let id = e.id();
        self.events.deref().borrow_mut().subscribe(id.clone(), event::Event::Update(0.0));
        self.events.deref().borrow_mut().subscribe(id.clone(), event::Event::Render);
        e.handle_event(Rc::new(event::Event::Spawn));
        self.scene.world.deref().insert(id, e);
    }

    pub fn destroy(&self, id: usize) {
        self.scene.world.deref().remove(&id);
    }

    pub fn run(&mut self) {
        let mut previous_clock = clock_ticks::precise_time_ns();
        let mut accumulator = 0;

        // Lol
        let glut_mouse_ev_to_local = |e| {
            match e {
                glutin::MouseButton::Left => event::MouseButton::Left,
                glutin::MouseButton::Right => event::MouseButton::Right,
                glutin::MouseButton::Middle => event::MouseButton::Middle,
                glutin::MouseButton::Other(c) => event::MouseButton::Other(c),
            }
        };

        let mut fps_prev_clock = clock_ticks::precise_time_ms();
        let mut frames_drawn = 0;
        let mut key_counter = [0 as u8; 255];
        loop {
            self.events.deref().borrow_mut().enqueue_all(event::Event::Render);
            let ev_queue = {
                self.events.deref().borrow_mut().flush()
            };
            for (id, event) in ev_queue {
                if id != 0 {
                    self.scene.dispatch(id, event);
                } else {
                    self.handle_internal_event(event);
                }
            }

            self.graphics.borrow_mut().render();

            let now = clock_ticks::precise_time_ns();
            let fps_cur_clock = clock_ticks::precise_time_ms();
            frames_drawn += 1;
            if fps_cur_clock - fps_prev_clock >= 1000 {
                println!("{:?} ms/frame", 1000.0 / (frames_drawn as f32));
                frames_drawn = 0;
                fps_prev_clock = fps_cur_clock;
            }

            accumulator += now - previous_clock;
            previous_clock = now;
            const FRAME_DELAY_NANOSECS: u64 = 16666667;

            for event in self.graphics.borrow_mut().get_window_events() {
                match event {
                    glutin::Event::Closed => return,
                    glutin::Event::KeyboardInput(glutin::ElementState::Pressed, n, c) => {
                        if key_counter[n as usize] == 0 && !c.is_none() {
                            key_counter[n as usize] = 1;
                            self.events
                                .deref()
                                .borrow_mut()
                                .enqueue_all(event::Event::KeyInput(event::InputState::Pressed,
                                                                    c.unwrap()))
                        }
                    }
                    glutin::Event::KeyboardInput(glutin::ElementState::Released, n, c) => {
                        if !c.is_none() {
                            key_counter[n as usize] = 0;
                            self.events
                                .deref()
                                .borrow_mut()
                                .enqueue_all(event::Event::KeyInput(event::InputState::Released,
                                                                    c.unwrap()))

                        }
                    }
                    glutin::Event::MouseMoved(x, y) => {
                        self.events
                            .deref()
                            .borrow_mut()
                            .enqueue_all(event::Event::MouseMove((x, y)))
                    }
                    glutin::Event::MouseInput(glutin::ElementState::Pressed, b) => {
                        self.events
                            .deref()
                            .borrow_mut()
                            .enqueue_all(event::Event::MouseInput(event::InputState::Pressed,
                                                                  glut_mouse_ev_to_local(b)))
                    }
                    glutin::Event::MouseInput(glutin::ElementState::Released, b) => {
                        self.events
                            .deref()
                            .borrow_mut()
                            .enqueue_all(event::Event::MouseInput(event::InputState::Released,
                                                                  glut_mouse_ev_to_local(b)))
                    }
                    _ => {}
                }
            }

            while accumulator >= FRAME_DELAY_NANOSECS {
                // Update state here
                self.events.deref().borrow_mut().enqueue_all(event::Event::Update(0.016666667f32));
                let ev_queue = {
                    self.events.deref().borrow_mut().flush()
                };
                for (id, event) in ev_queue {
                    if id != 0 {
                        self.scene.dispatch(id, event);
                    } else {
                        self.handle_internal_event(event);
                    }
                }
                self.scene.update();
                accumulator -= FRAME_DELAY_NANOSECS;
            }

            let sys_ev_queue = {
                self.events.deref().borrow_mut().flush_sys()
            };
            for event in sys_ev_queue {
                match event {
                    event::SysEvent::Create(f) => self.spawn(f),
                    event::SysEvent::Destroy(id) => self.destroy(id),
                }
            }
            thread::sleep(Duration::from_millis(((FRAME_DELAY_NANOSECS - accumulator) / 1000000) as u64));
        }
    }

    fn handle_internal_event(&mut self, event: Rc<event::Event>) {
        match *event {
            event::Event::Proximity(id, ref data) => {
                match &data.this_object.tag[..] {
                    "view_area" => {
                        match data.proximity {
                            Proximity::Intersecting => {
                                self.events
                                    .deref()
                                    .borrow_mut()
                                    .enqueue_specific(id, event::Event::Entering);
                            }
                            Proximity::Disjoint => {
                                self.events
                                    .deref()
                                    .borrow_mut()
                                    .enqueue_specific(id, event::Event::Exiting);
                            }
                            _ => {}
                        }
                    }
                    "view_border" => {
                        let mut new_data = data.clone();
                        mem::swap(&mut new_data.this_object, &mut new_data.other_object);
                        self.events
                            .deref()
                            .borrow_mut()
                            .enqueue_specific(id, event::Event::Proximity(id, new_data));
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}
<commit_msg>Cleanup some engine code<commit_after>pub mod event;
pub mod scene;
pub mod entity;
pub mod graphics;
pub mod audio;

use std::cell::RefCell;
use std::rc::Rc;
use std::thread;
use std::time::Duration;
use std::ops::Deref;
use std::mem;
use glium::glutin;
use ncollide::shape::{Plane, Cuboid, ShapeHandle2};
use ncollide::query::Proximity;
use nalgebra::Vector2;
use ncollide::world::GeometricQueryType;
use clock_ticks;

use self::entity::component::PhysicsData;
use self::scene::PhysicsInteraction;

pub struct Engine<E: entity::Entity> {
    pub events: Rc<RefCell<event::Handler<E>>>,
    pub scene: scene::Scene<E>,
    pub graphics: Rc<RefCell<graphics::Graphics>>,
    pub audio: Rc<RefCell<audio::Audio>>,
}

impl<E: entity::Entity> Engine<E> {
    pub fn new() -> Engine<E> {
        // Default physics dimensions are 400x400 - a square which has a half length 200 units away
        // from the origin
        let scene = scene::Scene::new(200.0);

        let plane_left = ShapeHandle2::new(Plane::new(Vector2::x()));
        let plane_bottom = ShapeHandle2::new(Plane::new(Vector2::y()));
        let plane_right = ShapeHandle2::new(Plane::new(-Vector2::x()));
        let plane_top = ShapeHandle2::new(Plane::new(-Vector2::y()));

        let plane_data = Rc::new(PhysicsData::new(0, String::from("view_border")));

        scene.physics.add(Vector2::new(-200.0, 0.0),
                          plane_left,
                          PhysicsInteraction::Interactive,
                          GeometricQueryType::Contacts(0.2),
                          plane_data.clone());
        scene.physics.add(Vector2::new(0.0, -200.0),
                          plane_bottom,
                          PhysicsInteraction::Interactive,
                          GeometricQueryType::Contacts(0.2),
                          plane_data.clone());
        scene.physics.add(Vector2::new(200.0, 0.0),
                          plane_right,
                          PhysicsInteraction::Interactive,
                          GeometricQueryType::Contacts(0.2),
                          plane_data.clone());
        scene.physics.add(Vector2::new(0.0, 200.0),
                          plane_top,
                          PhysicsInteraction::Interactive,
                          GeometricQueryType::Contacts(0.2),
                          plane_data.clone());

        let rect = ShapeHandle2::new(Cuboid::new(Vector2::new(200.0, 200.0)));
        let rect_data = Rc::new(PhysicsData::new(0, String::from("view_area")));
        scene.physics.add(Vector2::new(0.0, 0.0),
                          rect,
                          PhysicsInteraction::Interactive,
                          GeometricQueryType::Proximity(0.2),
                          rect_data);

        let eh = event::Handler::new();
        let queue = eh.queue.clone();
        let events = Rc::new(RefCell::new(eh));
        scene.physics.register_handlers(queue);

        Engine {
            events: events,
            scene: scene,
            graphics: Rc::new(RefCell::new(graphics::Graphics::new())),
            audio: Rc::new(RefCell::new(audio::Audio::new())),
        }
    }

    pub fn spawn(&self, spawner: Box<Fn(&Engine<E>) -> E>) {
        let mut e = spawner(&self);
        let id = e.id();
        self.events.deref().borrow_mut().subscribe(id.clone(), event::Event::Update(0.0));
        self.events.deref().borrow_mut().subscribe(id.clone(), event::Event::Render);
        e.handle_event(Rc::new(event::Event::Spawn));
        self.scene.world.deref().insert(id, e);
    }

    pub fn destroy(&self, id: usize) {
        self.scene.world.deref().remove(&id);
    }

    pub fn handle_events(&mut self) {
        let ev_queue = {
            self.events.deref().borrow_mut().flush()
        };
        for (id, event) in ev_queue {
            if id != 0 {
                self.scene.dispatch(id, event);
            } else {
                self.handle_internal_event(event);
            }
        }
    }

    pub fn run(&mut self) {
        let mut previous_clock = clock_ticks::precise_time_ns();
        let mut accumulator = 0;

        // Lol
        let glut_mouse_ev_to_local = |e| {
            match e {
                glutin::MouseButton::Left => event::MouseButton::Left,
                glutin::MouseButton::Right => event::MouseButton::Right,
                glutin::MouseButton::Middle => event::MouseButton::Middle,
                glutin::MouseButton::Other(c) => event::MouseButton::Other(c),
            }
        };

        let mut fps_prev_clock = clock_ticks::precise_time_ms();
        let mut frames_drawn = 0;
        let mut key_counter = [0 as u8; 255];
        loop {
            self.events.deref().borrow_mut().enqueue_all(event::Event::Render);
            self.handle_events();
            self.graphics.borrow_mut().render();

            let now = clock_ticks::precise_time_ns();
            let fps_cur_clock = clock_ticks::precise_time_ms();
            frames_drawn += 1;
            if fps_cur_clock - fps_prev_clock >= 1000 {
                println!("{:?} ms/frame", 1000.0 / (frames_drawn as f32));
                frames_drawn = 0;
                fps_prev_clock = fps_cur_clock;
            }

            accumulator += now - previous_clock;
            previous_clock = now;
            const FRAME_DELAY_NANOSECS: u64 = 16666667;

            for event in self.graphics.borrow_mut().get_window_events() {
                let to_queue = match event {
                    glutin::Event::Closed => return,
                    glutin::Event::KeyboardInput(glutin::ElementState::Pressed, n, c) => {
                        if key_counter[n as usize] == 0 && !c.is_none() {
                            key_counter[n as usize] = 1;
                            Some(event::Event::KeyInput(event::InputState::Pressed, c.unwrap()))
                        } else {
                            None
                        }
                    }
                    glutin::Event::KeyboardInput(glutin::ElementState::Released, n, c) => {
                        match c {
                            Some(code) => {
                                key_counter[n as usize] = 0;
                                Some(event::Event::KeyInput(event::InputState::Released, code))
                            }
                            None => None,
                        }
                    }
                    glutin::Event::MouseMoved(x, y) => Some(event::Event::MouseMove((x, y))),
                    glutin::Event::MouseInput(glutin::ElementState::Pressed, b) => {
                        Some(event::Event::MouseInput(event::InputState::Pressed,
                                                      glut_mouse_ev_to_local(b)))
                    }
                    glutin::Event::MouseInput(glutin::ElementState::Released, b) => {
                        Some(event::Event::MouseInput(event::InputState::Released,
                                                      glut_mouse_ev_to_local(b)))
                    }
                    _ => None,
                };
                if let Some(ev) = to_queue {
                    self.events.borrow_mut().enqueue_all(ev);
                }
            }

            while accumulator >= FRAME_DELAY_NANOSECS {
                // Update state here
                self.events.deref().borrow_mut().enqueue_all(event::Event::Update(0.016666667f32));
                self.handle_events();
                self.scene.update();
                accumulator -= FRAME_DELAY_NANOSECS;
            }

            let sys_ev_queue = {
                self.events.deref().borrow_mut().flush_sys()
            };
            for event in sys_ev_queue {
                match event {
                    event::SysEvent::Create(f) => self.spawn(f),
                    event::SysEvent::Destroy(id) => self.destroy(id),
                }
            }
            thread::sleep(Duration::from_millis(((FRAME_DELAY_NANOSECS - accumulator) / 1000000) as u64));
        }
    }

    fn handle_internal_event(&mut self, event: Rc<event::Event>) {
        match *event {
            event::Event::Proximity(id, ref data) => {
                match &data.this_object.tag[..] {
                    "view_area" => {
                        match data.proximity {
                            Proximity::Intersecting => {
                                self.events
                                    .deref()
                                    .borrow_mut()
                                    .enqueue_specific(id, event::Event::Entering);
                            }
                            Proximity::Disjoint => {
                                self.events
                                    .deref()
                                    .borrow_mut()
                                    .enqueue_specific(id, event::Event::Exiting);
                            }
                            _ => {}
                        }
                    }
                    "view_border" => {
                        let mut new_data = data.clone();
                        mem::swap(&mut new_data.this_object, &mut new_data.other_object);
                        self.events
                            .deref()
                            .borrow_mut()
                            .enqueue_specific(id, event::Event::Proximity(id, new_data));
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}
<|endoftext|>