<commit_before>/* Copyright 2015 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

use std::any::Any;
use std::cell::RefCell;
use std::collections::{hash_map, HashMap};
use std::marker::PhantomData;
use std::mem;
use std::ops::{CoerceUnsized};
use std::panic::{self, RecoverSafe};
use std::rc::Rc;
use std::thread::LocalKey;
use libc::{c_int, c_char};
use iup_sys::*;
use smallvec::SmallVec;
use super::attributes::str_to_c_vec;
use super::{Control, MouseButton, KeyboardMouseStatus};
use super::handle_rc::{add_ldestroy_callback, remove_ldestroy_callback};

pub enum CallbackAction {
    Default,
    // Close is not needed because it is just as easy to call IupExitLoop()
    // and then the API is smaller.
    Close,
    Ignore,
    Continue,
}

impl CallbackAction {
    #[allow(dead_code)]
    pub fn from_int(action: c_int) -> CallbackAction {
        match action {
            IUP_DEFAULT => CallbackAction::Default,
            IUP_IGNORE => CallbackAction::Ignore,
            IUP_CONTINUE => CallbackAction::Continue,
            _ => panic!("can't convert callback action"),
        }
    }

    pub fn to_int(&self) -> c_int {
        match *self {
            CallbackAction::Default => IUP_DEFAULT,
            CallbackAction::Close => IUP_CLOSE,
            CallbackAction::Ignore => IUP_IGNORE,
            CallbackAction::Continue => IUP_CONTINUE,
        }
    }
}

// To avoid letting panics unwind into C stack frames, we need to catch the panic,
// store it away, and check it later when there's no C code on the stack.
thread_local!(
    static PANIC_PAYLOAD: RefCell<Option<Box<Any + Send + 'static>>> = RefCell::new(None)
);

pub fn set_panic_payload(payload: Box<Any + Send + 'static>) {
    PANIC_PAYLOAD.with(|cell|
        *cell.borrow_mut() = Some(payload)
    );
}

pub fn is_panic_pending() -> bool {
    PANIC_PAYLOAD.with(|cell| cell.borrow().is_some())
}

pub fn take_panic_payload() -> Option<Box<Any + Send + 'static>> {
    PANIC_PAYLOAD.with(|cell| cell.borrow_mut().take())
}

// If a callback's documentation does not specify valid return values, then only IUP_DEFAULT is
// supported.

// use LDESTROY_CB instead of DESTROY_CB

// TODO: if Token is public, then I need to make sure that converting from a MapCallbackToken to
// a DestroyToken can't cause unsafety
#[derive(Debug)]
pub struct Token {
    pub id: usize,
    pub ih: *mut Ihandle,
}

macro_rules! callback_token {
    ($name:ident) => {
        #[derive(Debug)]
        pub struct $name(Token);

        impl From<$name> for Token {
            fn from($name(t): $name) -> Token { t }
        }

        impl From<Token> for $name {
            fn from(t: Token) -> $name { $name(t) }
        }
    };
}

struct ControlCallbacks<F: ?Sized + 'static> {
    ldestroy_token: Token,
    // Copy-on-write is used on the vector in the `Rc` so that if a callback is added or removed
    // inside a callback, it can make the change to a copy of the vector. The in-progress
    // notification can continue iterating over the original vector. To make the vector
    // `Clone`, each function is wrapped in an `Rc`. Since each function is in a `RefCell`, there
    // is no need to have the vector in a RefCell. Iterating over the vector only requires read
    // access (even to reentrantly iterate over the vector because you can have multiple
    // immutable references), and for write access in add/remove_callback, `make_mut` is used.
    vec: Rc<Vec<(usize, Rc<RefCell<F>>)>>,
}

pub struct CallbackRegistry<F: ?Sized + 'static, T: Into<Token> + From<Token>> {
    cb_name: &'static str,
    cb_fn: Icallback,
    callbacks: Rc<RefCell<HashMap<*mut Ihandle, ControlCallbacks<F>>>>,
    phantom: PhantomData<*const T>,
}

impl<F: ?Sized, T: Into<Token> + From<Token>> CallbackRegistry<F, T> {
    // Icallback is the most common type of callback, but there are many exceptions. If the
    // callback's signature does not match Icallback, just cast to Icallback.
    pub fn new(cb_name: &'static str, cb_fn: Icallback) -> CallbackRegistry<F, T> {
        CallbackRegistry {
            cb_name: cb_name,
            cb_fn: cb_fn,
            callbacks: Rc::new(RefCell::new(HashMap::new())),
            phantom: PhantomData,
        }
    }

    // `add_callback` and `remove_callback` do not try to borrow the `RefCell` until they have
    // called `Rc::make_mut` (the `RefCell` could already be borrowed by `with_callbacks`). After
    // `Rc::make_mut`, it is guaranteed safe to borrow.
    fn add_callback_inner(&self, ih: *mut Ihandle, cb: Rc<RefCell<F>>) -> T {
        let mut map = self.callbacks.borrow_mut();
        let cc = map.entry(ih).or_insert_with(|| {
            let callbacks2 = self.callbacks.clone();
            let t = add_ldestroy_callback(ih, move |ih| { callbacks2.borrow_mut().remove(&ih); });
            ControlCallbacks { ldestroy_token: t, vec: Rc::new(Vec::with_capacity(4)) }
        });
        let cbs = Rc::make_mut(&mut cc.vec);
        let id = cbs.last().map(|&(id, _)| id + 1).unwrap_or(0);
        cbs.push((id, cb));

        unsafe {
            let mut buf = SmallVec::<[u8; 32]>::new();
            IupSetCallback(ih, str_to_c_vec(self.cb_name, &mut buf) as *const i8, self.cb_fn);
        }

        Token { id: id, ih: ih }.into()
    }

    pub fn add_callback<G>(&self, ih: *mut Ihandle, cb: G) -> T
    where Rc<RefCell<G>>: CoerceUnsized<Rc<RefCell<F>>>
    {
        self.add_callback_inner(ih, Rc::new(RefCell::new(cb)) as Rc<RefCell<F>>)
    }

    pub fn remove_callback(&self, ih: *mut Ihandle, token: T) {
        let token: Token = token.into();
        assert!(ih == token.ih, "token used with wrong control");
        let mut map = self.callbacks.borrow_mut();
        if let hash_map::Entry::Occupied(mut entry) = map.entry(token.ih) {
            let is_empty = {
                // Use make_mut() in case the vector is being iterated over.
                let cbs = Rc::make_mut(&mut entry.get_mut().vec);
                let index = cbs.iter().position(|&(id, _)| id == token.id).expect("failed to remove callback");
                cbs.remove(index);

                cbs.is_empty()
            };
            if is_empty {
                let ControlCallbacks { ldestroy_token, .. } = entry.remove();
                remove_ldestroy_callback(ldestroy_token);
            }

            // I could use the below code with non-lexical borrows.
            // Use make_mut() in case the vector is being iterated over.
            //let cbs = Rc::make_mut(&mut entry.get_mut().vec);
            //let index = cbs.iter().position(|&(id, _)| id == token.id).expect("failed to remove callback");
            //cbs.remove(index);

            //if cbs.is_empty() {
            //    let ControlCallbacks { ldestroy_token, .. } = entry.remove();
            //    remove_ldestroy_callback(ldestroy_token);
            //}
        }
    }
}

struct AssertRecoverSafeVal<T: ?Sized>(T);

impl<T: ?Sized> RecoverSafe for AssertRecoverSafeVal<T> {}

// Takes a function that takes one parameter that is a slice of (id, callback) tuples.
pub fn with_callbacks<F, G: ?Sized, T>(ih: *mut Ihandle,
                                       reg: &'static LocalKey<CallbackRegistry<G, T>>, f: F)
                                       -> c_int
                                       where F: FnOnce(&[(usize, Rc<RefCell<G>>)]) -> c_int,
                                             G: 'static,
                                             T: Into<Token> + From<Token> {
    let h = AssertRecoverSafeVal(f);
    let result = panic::recover(move || {
        reg.with(move |reg| {
            let cbs_rc = reg.callbacks.borrow().get(&ih).map(|cc| cc.vec.clone());
            if let Some(cbs) = cbs_rc {
                h.0(&*cbs)
            } else {
                IUP_DEFAULT
            }
        })
    });
    match result {
        Ok(r) => r,
        Err(err) => {
            set_panic_payload(err);
            unsafe { IupExitLoop(); }
            IUP_DEFAULT
        },
    }
}

pub fn simple_callback<T>(ih: *mut Ihandle,
                      reg: &'static LocalKey<CallbackRegistry<FnMut(), T>>)
                      -> c_int where T: Into<Token> + From<Token> {
    with_callbacks(ih, reg, |cbs| {
        for cb in cbs {
            (&mut *cb.1.borrow_mut())();
        }
        IUP_DEFAULT
    })
}

pub struct Event<'a, F: ?Sized + 'static, T: 'static + Into<Token> + From<Token>> {
    control: &'a Control,
    reg: &'static LocalKey<CallbackRegistry<F, T>>,
}

impl<'a, F: ?Sized, T: Into<Token> + From<Token>> Event<'a, F, T> {
    pub fn new(control: &'a Control, reg: &'static LocalKey<CallbackRegistry<F, T>>) -> Event<'a, F, T> {
        Event { control: control, reg: reg }
    }

    pub fn add<G>(&self, cb: G) -> T
    where Rc<RefCell<G>>: CoerceUnsized<Rc<RefCell<F>>>
    {
        self.reg.with(|reg| reg.add_callback_inner(self.control.handle(), Rc::new(RefCell::new(cb)) as Rc<RefCell<F>>))
    }

    pub fn remove(&self, token: T) {
        self.reg.with(|reg| reg.remove_callback(self.control.handle(), token))
    }
}

pub trait MenuCommonCallbacks : Control {
    // fn map_event();
    // fn unmap_event();
    // fn destroy_event();
}

callback_token!(GetFocusCallbackToken);
thread_local!(
    static GET_FOCUS_CALLBACKS: CallbackRegistry<FnMut(), GetFocusCallbackToken> =
        CallbackRegistry::new("GETFOCUS_CB", get_focus_cb)
);
extern fn get_focus_cb(ih: *mut Ihandle) -> c_int {
    simple_callback(ih, &GET_FOCUS_CALLBACKS)
}

callback_token!(KillFocusCallbackToken);
thread_local!(
    static KILL_FOCUS_CALLBACKS: CallbackRegistry<FnMut(), KillFocusCallbackToken> =
        CallbackRegistry::new("KILLFOCUS_CB", kill_focus_cb)
);
extern fn kill_focus_cb(ih: *mut Ihandle) -> c_int {
    simple_callback(ih, &KILL_FOCUS_CALLBACKS)
}

callback_token!(EnterWindowCallbackToken);
thread_local!(
    static ENTER_WINDOW_CALLBACKS: CallbackRegistry<FnMut(), EnterWindowCallbackToken> =
        CallbackRegistry::new("ENTERWINDOW_CB", enter_window_cb)
);
extern fn enter_window_cb(ih: *mut Ihandle) -> c_int {
    simple_callback(ih, &ENTER_WINDOW_CALLBACKS)
}

callback_token!(LeaveWindowCallbackToken);
thread_local!(
    static LEAVE_WINDOW_CALLBACKS: CallbackRegistry<FnMut(), LeaveWindowCallbackToken> =
        CallbackRegistry::new("LEAVEWINDOW_CB", leave_window_cb)
);
extern fn leave_window_cb(ih: *mut Ihandle) -> c_int {
    simple_callback(ih, &LEAVE_WINDOW_CALLBACKS)
}

pub trait GetKillFocusCallbacks : Control {
    fn get_focus_event<'a>(&'a self) -> Event<'a, FnMut(), GetFocusCallbackToken>
    where &'a Self: CoerceUnsized<&'a Control> {
        Event::new(self as &Control, &GET_FOCUS_CALLBACKS)
    }

    fn kill_focus_event<'a>(&'a self) -> Event<'a, FnMut(), KillFocusCallbackToken>
    where &'a Self: CoerceUnsized<&'a Control> {
        Event::new(self as &Control, &KILL_FOCUS_CALLBACKS)
    }
}

pub trait EnterLeaveWindowCallbacks : Control {
    fn enter_window_event<'a>(&'a self) -> Event<'a, FnMut(), EnterWindowCallbackToken>
    where &'a Self: CoerceUnsized<&'a Control> {
        Event::new(self as &Control, &ENTER_WINDOW_CALLBACKS)
    }

    fn leave_window_event<'a>(&'a self) -> Event<'a, FnMut(), LeaveWindowCallbackToken>
    where &'a Self: CoerceUnsized<&'a Control> {
        Event::new(self as &Control, &LEAVE_WINDOW_CALLBACKS)
    }
}

pub trait KAnyCallback : Control {
    // fn k_any_event();
}

#[derive(Clone)]
pub struct ButtonArgs {
    pub button: MouseButton,
    pub pressed: bool,
    pub x: i32,
    pub y: i32,
    pub status: KeyboardMouseStatus,
    _dummy: (),
}

callback_token!(ButtonCallbackToken);
thread_local!(
    static BUTTON_CALLBACKS: CallbackRegistry<FnMut(&ButtonArgs) -> CallbackAction, ButtonCallbackToken> =
        CallbackRegistry::new("BUTTON_CB",  unsafe { mem::transmute::<_, Icallback>(button_cb) })
);
unsafe extern fn button_cb(ih: *mut Ihandle, button: c_int, pressed: c_int, x: c_int, y: c_int, status: *mut c_char) -> c_int {
    // Maybe the callback should be able to return Ignore (and thus this function return
    // IUP_IGNORE). My main hesitation is that IUP's docs state that it is system
    // dependent: "On some controls if IUP_IGNORE is returned the action is ignored (this is
    // system dependent)." Plus, it doesn't seem really useful and is more verbose.
    with_callbacks(ih, &BUTTON_CALLBACKS, |cbs| {
        let args = ButtonArgs {
            button: MouseButton::from_int(button),
            pressed: pressed != 0,
            x: x as i32,
            y: y as i32,
            status: KeyboardMouseStatus::from_cstr(status),
            _dummy: (),
        };
        let mut action = CallbackAction::Default;
        for cb in cbs {
            match (&mut *cb.1.borrow_mut())(&args) {
                CallbackAction::Default => {},
                cb_action => action = cb_action,
            }
        }
        action.to_int()
    })
}

pub trait ButtonCallback {
    fn button_event<'a>(&'a self) -> Event<'a, FnMut(&ButtonArgs) -> CallbackAction, ButtonCallbackToken>
    where &'a Self: CoerceUnsized<&'a Control> {
        Event::new(self as &Control, &BUTTON_CALLBACKS)
    }
}
<commit_msg>Implement the destroy event<commit_after>/* Copyright 2015 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

use std::any::Any;
use std::cell::RefCell;
use std::collections::{hash_map, HashMap};
use std::marker::PhantomData;
use std::mem;
use std::ops::{CoerceUnsized};
use std::panic::{self, RecoverSafe};
use std::rc::Rc;
use std::thread::LocalKey;
use libc::{c_int, c_char};
use iup_sys::*;
use smallvec::SmallVec;
use super::attributes::str_to_c_vec;
use super::{Control, MouseButton, KeyboardMouseStatus};
use super::handle_rc::{add_ldestroy_callback, remove_ldestroy_callback};

pub enum CallbackAction {
    Default,
    // Close is not needed because it is just as easy to call IupExitLoop()
    // and then the API is smaller.
    Close,
    Ignore,
    Continue,
}

impl CallbackAction {
    #[allow(dead_code)]
    pub fn from_int(action: c_int) -> CallbackAction {
        match action {
            IUP_DEFAULT => CallbackAction::Default,
            IUP_IGNORE => CallbackAction::Ignore,
            IUP_CONTINUE => CallbackAction::Continue,
            _ => panic!("can't convert callback action"),
        }
    }

    pub fn to_int(&self) -> c_int {
        match *self {
            CallbackAction::Default => IUP_DEFAULT,
            CallbackAction::Close => IUP_CLOSE,
            CallbackAction::Ignore => IUP_IGNORE,
            CallbackAction::Continue => IUP_CONTINUE,
        }
    }
}

// To avoid letting panics unwind into C stack frames, we need to catch the panic,
// store it away, and check it later when there's no C code on the stack.
thread_local!(
    static PANIC_PAYLOAD: RefCell<Option<Box<Any + Send + 'static>>> = RefCell::new(None)
);

pub fn set_panic_payload(payload: Box<Any + Send + 'static>) {
    PANIC_PAYLOAD.with(|cell|
        *cell.borrow_mut() = Some(payload)
    );
}

pub fn is_panic_pending() -> bool {
    PANIC_PAYLOAD.with(|cell| cell.borrow().is_some())
}

pub fn take_panic_payload() -> Option<Box<Any + Send + 'static>> {
    PANIC_PAYLOAD.with(|cell| cell.borrow_mut().take())
}

// If a callback's documentation does not specify valid return values, then only IUP_DEFAULT is
// supported.

// use LDESTROY_CB instead of DESTROY_CB

// TODO: if Token is public, then I need to make sure that converting from a MapCallbackToken to
// a DestroyToken can't cause unsafety
#[derive(Debug)]
pub struct Token {
    pub id: usize,
    pub ih: *mut Ihandle,
}

macro_rules! callback_token {
    ($name:ident) => {
        #[derive(Debug)]
        pub struct $name(Token);

        impl From<$name> for Token {
            fn from($name(t): $name) -> Token { t }
        }

        impl From<Token> for $name {
            fn from(t: Token) -> $name { $name(t) }
        }
    };
}

struct ControlCallbacks<F: ?Sized + 'static> {
    ldestroy_token: Token,
    // Copy-on-write is used on the vector in the `Rc` so that if a callback is added or removed
    // inside a callback, it can make the change to a copy of the vector. The in-progress
    // notification can continue iterating over the original vector. To make the vector
    // `Clone`, each function is wrapped in an `Rc`. Since each function is in a `RefCell`, there
    // is no need to have the vector in a RefCell. Iterating over the vector only requires read
    // access (even to reentrantly iterate over the vector because you can have multiple
    // immutable references), and for write access in add/remove_callback, `make_mut` is used.
    vec: Rc<Vec<(usize, Rc<RefCell<F>>)>>,
}

pub struct CallbackRegistry<F: ?Sized + 'static, T: Into<Token> + From<Token>> {
    cb_name: &'static str,
    cb_fn: Icallback,
    callbacks: Rc<RefCell<HashMap<*mut Ihandle, ControlCallbacks<F>>>>,
    phantom: PhantomData<*const T>,
}

impl<F: ?Sized, T: Into<Token> + From<Token>> CallbackRegistry<F, T> {
    // Icallback is the most common type of callback, but there are many exceptions. If the
    // callback's signature does not match Icallback, just cast to Icallback.
    pub fn new(cb_name: &'static str, cb_fn: Icallback) -> CallbackRegistry<F, T> {
        CallbackRegistry {
            cb_name: cb_name,
            cb_fn: cb_fn,
            callbacks: Rc::new(RefCell::new(HashMap::new())),
            phantom: PhantomData,
        }
    }

    // `add_callback` and `remove_callback` do not try to borrow the `RefCell` until they have
    // called `Rc::make_mut` (the `RefCell` could already be borrowed by `with_callbacks`). After
    // `Rc::make_mut`, it is guaranteed safe to borrow.
    fn add_callback_inner(&self, ih: *mut Ihandle, cb: Rc<RefCell<F>>) -> T {
        let mut map = self.callbacks.borrow_mut();
        let cc = map.entry(ih).or_insert_with(|| {
            let callbacks2 = self.callbacks.clone();
            let t = add_ldestroy_callback(ih, move |ih| { callbacks2.borrow_mut().remove(&ih); });
            ControlCallbacks { ldestroy_token: t, vec: Rc::new(Vec::with_capacity(4)) }
        });
        let cbs = Rc::make_mut(&mut cc.vec);
        let id = cbs.last().map(|&(id, _)| id + 1).unwrap_or(0);
        cbs.push((id, cb));

        unsafe {
            let mut buf = SmallVec::<[u8; 32]>::new();
            IupSetCallback(ih, str_to_c_vec(self.cb_name, &mut buf) as *const i8, self.cb_fn);
        }

        Token { id: id, ih: ih }.into()
    }

    pub fn add_callback<G>(&self, ih: *mut Ihandle, cb: G) -> T
    where Rc<RefCell<G>>: CoerceUnsized<Rc<RefCell<F>>>
    {
        self.add_callback_inner(ih, Rc::new(RefCell::new(cb)) as Rc<RefCell<F>>)
    }

    pub fn remove_callback(&self, ih: *mut Ihandle, token: T) {
        let token: Token = token.into();
        assert!(ih == token.ih, "token used with wrong control");
        let mut map = self.callbacks.borrow_mut();
        if let hash_map::Entry::Occupied(mut entry) = map.entry(token.ih) {
            let is_empty = {
                // Use make_mut() in case the vector is being iterated over.
                let cbs = Rc::make_mut(&mut entry.get_mut().vec);
                let index = cbs.iter().position(|&(id, _)| id == token.id).expect("failed to remove callback");
                cbs.remove(index);

                cbs.is_empty()
            };
            if is_empty {
                let ControlCallbacks { ldestroy_token, .. } = entry.remove();
                remove_ldestroy_callback(ldestroy_token);
            }

            // I could use the below code with non-lexical borrows.
            // Use make_mut() in case the vector is being iterated over.
            //let cbs = Rc::make_mut(&mut entry.get_mut().vec);
            //let index = cbs.iter().position(|&(id, _)| id == token.id).expect("failed to remove callback");
            //cbs.remove(index);

            //if cbs.is_empty() {
            //    let ControlCallbacks { ldestroy_token, .. } = entry.remove();
            //    remove_ldestroy_callback(ldestroy_token);
            //}
        }
    }
}

struct AssertRecoverSafeVal<T: ?Sized>(T);

impl<T: ?Sized> RecoverSafe for AssertRecoverSafeVal<T> {}

// Takes a function that takes one parameter that is a slice of (id, callback) tuples.
pub fn with_callbacks<F, G: ?Sized, T>(ih: *mut Ihandle,
                                       reg: &'static LocalKey<CallbackRegistry<G, T>>, f: F)
                                       -> c_int
                                       where F: FnOnce(&[(usize, Rc<RefCell<G>>)]) -> c_int,
                                             G: 'static,
                                             T: Into<Token> + From<Token> {
    let h = AssertRecoverSafeVal(f);
    let result = panic::recover(move || {
        reg.with(move |reg| {
            let cbs_rc = reg.callbacks.borrow().get(&ih).map(|cc| cc.vec.clone());
            if let Some(cbs) = cbs_rc {
                h.0(&*cbs)
            } else {
                IUP_DEFAULT
            }
        })
    });
    match result {
        Ok(r) => r,
        Err(err) => {
            set_panic_payload(err);
            unsafe { IupExitLoop(); }
            IUP_DEFAULT
        },
    }
}

pub fn simple_callback<T>(ih: *mut Ihandle,
                      reg: &'static LocalKey<CallbackRegistry<FnMut(), T>>)
                      -> c_int where T: Into<Token> + From<Token> {
    with_callbacks(ih, reg, |cbs| {
        for cb in cbs {
            (&mut *cb.1.borrow_mut())();
        }
        IUP_DEFAULT
    })
}

pub struct Event<'a, F: ?Sized + 'static, T: 'static + Into<Token> + From<Token>> {
    control: &'a Control,
    reg: &'static LocalKey<CallbackRegistry<F, T>>,
}

impl<'a, F: ?Sized, T: Into<Token> + From<Token>> Event<'a, F, T> {
    pub fn new(control: &'a Control, reg: &'static LocalKey<CallbackRegistry<F, T>>) -> Event<'a, F, T> {
        Event { control: control, reg: reg }
    }

    pub fn add<G>(&self, cb: G) -> T
    where Rc<RefCell<G>>: CoerceUnsized<Rc<RefCell<F>>>
    {
        self.reg.with(|reg| reg.add_callback_inner(self.control.handle(), Rc::new(RefCell::new(cb)) as Rc<RefCell<F>>))
    }

    pub fn remove(&self, token: T) {
        self.reg.with(|reg| reg.remove_callback(self.control.handle(), token))
    }
}

callback_token!(DestroyCallbackToken);
thread_local!(
    static DESTROY_CALLBACKS: CallbackRegistry<FnMut(), DestroyCallbackToken> =
        CallbackRegistry::new("DESTROY_CB", destroy_cb)
);
extern fn destroy_cb(ih: *mut Ihandle) -> c_int {
    simple_callback(ih, &DESTROY_CALLBACKS)
}

pub trait MenuCommonCallbacks : Control {
    // fn map_event();
    // fn unmap_event();

    fn destroy_event<'a>(&'a self) -> Event<'a, FnMut(), DestroyCallbackToken>
    where &'a Self: CoerceUnsized<&'a Control> {
        Event::new(self as &Control, &DESTROY_CALLBACKS)
    }
}

callback_token!(GetFocusCallbackToken);
thread_local!(
    static GET_FOCUS_CALLBACKS: CallbackRegistry<FnMut(), GetFocusCallbackToken> =
        CallbackRegistry::new("GETFOCUS_CB", get_focus_cb)
);
extern fn get_focus_cb(ih: *mut Ihandle) -> c_int {
    simple_callback(ih, &GET_FOCUS_CALLBACKS)
}

callback_token!(KillFocusCallbackToken);
thread_local!(
    static KILL_FOCUS_CALLBACKS: CallbackRegistry<FnMut(), KillFocusCallbackToken> =
        CallbackRegistry::new("KILLFOCUS_CB", kill_focus_cb)
);
extern fn kill_focus_cb(ih: *mut Ihandle) -> c_int {
    simple_callback(ih, &KILL_FOCUS_CALLBACKS)
}

callback_token!(EnterWindowCallbackToken);
thread_local!(
    static ENTER_WINDOW_CALLBACKS: CallbackRegistry<FnMut(), EnterWindowCallbackToken> =
        CallbackRegistry::new("ENTERWINDOW_CB", enter_window_cb)
);
extern fn enter_window_cb(ih: *mut Ihandle) -> c_int {
    simple_callback(ih, &ENTER_WINDOW_CALLBACKS)
}

callback_token!(LeaveWindowCallbackToken);
thread_local!(
    static LEAVE_WINDOW_CALLBACKS: CallbackRegistry<FnMut(), LeaveWindowCallbackToken> =
        CallbackRegistry::new("LEAVEWINDOW_CB", leave_window_cb)
);
extern fn leave_window_cb(ih: *mut Ihandle) -> c_int {
    simple_callback(ih, &LEAVE_WINDOW_CALLBACKS)
}

pub trait GetKillFocusCallbacks : Control {
    fn get_focus_event<'a>(&'a self) -> Event<'a, FnMut(), GetFocusCallbackToken>
    where &'a Self: CoerceUnsized<&'a Control> {
        Event::new(self as &Control, &GET_FOCUS_CALLBACKS)
    }

    fn kill_focus_event<'a>(&'a self) -> Event<'a, FnMut(), KillFocusCallbackToken>
    where &'a Self: CoerceUnsized<&'a Control> {
        Event::new(self as &Control, &KILL_FOCUS_CALLBACKS)
    }
}

pub trait EnterLeaveWindowCallbacks : Control {
    fn enter_window_event<'a>(&'a self) -> Event<'a, FnMut(), EnterWindowCallbackToken>
    where &'a Self: CoerceUnsized<&'a Control> {
        Event::new(self as &Control, &ENTER_WINDOW_CALLBACKS)
    }

    fn leave_window_event<'a>(&'a self) -> Event<'a, FnMut(), LeaveWindowCallbackToken>
    where &'a Self: CoerceUnsized<&'a Control> {
        Event::new(self as &Control, &LEAVE_WINDOW_CALLBACKS)
    }
}

pub trait KAnyCallback : Control {
    // fn k_any_event();
}

#[derive(Clone)]
pub struct ButtonArgs {
    pub button: MouseButton,
    pub pressed: bool,
    pub x: i32,
    pub y: i32,
    pub status: KeyboardMouseStatus,
    _dummy: (),
}

callback_token!(ButtonCallbackToken);
thread_local!(
    static BUTTON_CALLBACKS: CallbackRegistry<FnMut(&ButtonArgs) -> CallbackAction, ButtonCallbackToken> =
        CallbackRegistry::new("BUTTON_CB",  unsafe { mem::transmute::<_, Icallback>(button_cb) })
);
unsafe extern fn button_cb(ih: *mut Ihandle, button: c_int, pressed: c_int, x: c_int, y: c_int, status: *mut c_char) -> c_int {
    // Maybe the callback should be able to return Ignore (and thus this function return
    // IUP_IGNORE). My main hesitation is that IUP's docs state that it is system
    // dependent: "On some controls if IUP_IGNORE is returned the action is ignored (this is
    // system dependent)." Plus, it doesn't seem really useful and is more verbose.
    with_callbacks(ih, &BUTTON_CALLBACKS, |cbs| {
        let args = ButtonArgs {
            button: MouseButton::from_int(button),
            pressed: pressed != 0,
            x: x as i32,
            y: y as i32,
            status: KeyboardMouseStatus::from_cstr(status),
            _dummy: (),
        };
        let mut action = CallbackAction::Default;
        for cb in cbs {
            match (&mut *cb.1.borrow_mut())(&args) {
                CallbackAction::Default => {},
                cb_action => action = cb_action,
            }
        }
        action.to_int()
    })
}

pub trait ButtonCallback {
    fn button_event<'a>(&'a self) -> Event<'a, FnMut(&ButtonArgs) -> CallbackAction, ButtonCallbackToken>
    where &'a Self: CoerceUnsized<&'a Control> {
        Event::new(self as &Control, &BUTTON_CALLBACKS)
    }
}
<|endoftext|>


<commit_before>extern crate mio;
use getopts::{Options,Matches};
use std::net::{SocketAddr,lookup_host,IpAddr};
use std::io::{BufStream,Write};
use std::old_io;

use self::mio::*;
use self::mio::net::tcp::*;
use self::mio::buf::{ByteBuf};
use self::mio::net::*;

use std::thread;

use super::util::parse_addr;

const CLIENT: Token = Token(1);

struct ClientHandler {
    sock: NonBlock<TcpStream>
}

impl Handler for ClientHandler {
    type Timeout = usize;
    type Message = String;

    fn readable(&mut self, event_loop: &mut EventLoop<ClientHandler>, token: Token, _: ReadHint) {
        match token {
            CLIENT => {
                let mut read_buf = ByteBuf::mut_with_capacity(2048);
                match self.sock.read(&mut read_buf) {
                    Ok(None) => {
                        panic!("Read operation would block, bailing cuz this shouldn't happen.");
                    }
                    Ok(Some(r)) => {
                        // `_` would be the number of bytes read.
                        // `flip` will return a `ByteBuf` on which we can call
                        // `read_slice` to get the data available to be read.
                        // See http://carllerche.github.io/bytes/bytes/struct.ByteBuf.html
                        let mut buf = read_buf.flip();
                        let mut sl = [0; 2048];
                        buf.read_slice(&mut sl);
                        // Assuming what was written was encoded as UTF8, print what
                        // was read to STDOUT.
                        print!("{}", String::from_utf8(sl.to_vec()).unwrap());
                    }
                    Err(e) => {
                        // Probably because connection could not be established.
                        event_loop.shutdown();
                        panic!(e.to_string());
                    }
                }
            },
            _ => {
                panic!("unepxected token!".to_string());
            }
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<ClientHandler>, msg: String) {
        self.sock.write_slice(msg.as_bytes()).unwrap();
    }
}

pub fn nc_connect(matches: &Matches) {
    let addr = parse_addr(matches);
    let sock = match addr.ip() {
        IpAddr::V4(..) => v4(),
        IpAddr::V6(..) => v6()
    }.unwrap();

    let mut event_loop = EventLoop::new().unwrap();

    match sock.connect(&addr) {
        Ok((stream, _)) => {
            let mut client = ClientHandler { sock: stream };
            event_loop.register(&client.sock, CLIENT).unwrap();
            let sender = event_loop.channel();
            thread::spawn(move || {
                readwrite_chan(&sender);
            });
            let _ = event_loop.run(&mut client);
        },
        Err(f) => {
            println!("exiting");
            // just exit
        }
    }
}

fn readwrite_chan(channel: &EventLoopSender<String>) {
    let mut stdin_reader = old_io::stdin();
    let mut read_buf = [0; 4096];
    loop {
        // Have to block here, so we can't immediately terminate if server closes socket.
        match stdin_reader.read(&mut read_buf) {
            Ok(n) => {
                let read = read_buf.slice_to(n);
                let byte_vec: Vec<u8> = read.to_vec();
                let message = String::from_utf8(byte_vec).unwrap();
                channel.send(message).unwrap();
            },
            Err(f) => {
                panic!(f.to_string());
            }
        }
    }
}
<commit_msg>include message when we fail to connect in output<commit_after>extern crate mio;
use getopts::{Options,Matches};
use std::net::{SocketAddr,lookup_host,IpAddr};
use std::io::{BufStream,Write};
use std::old_io;

use self::mio::*;
use self::mio::net::tcp::*;
use self::mio::buf::{ByteBuf};
use self::mio::net::*;

use std::thread;

use super::util::parse_addr;

const CLIENT: Token = Token(1);

struct ClientHandler {
    sock: NonBlock<TcpStream>
}

impl Handler for ClientHandler {
    type Timeout = usize;
    type Message = String;

    fn readable(&mut self, event_loop: &mut EventLoop<ClientHandler>, token: Token, _: ReadHint) {
        match token {
            CLIENT => {
                let mut read_buf = ByteBuf::mut_with_capacity(2048);
                match self.sock.read(&mut read_buf) {
                    Ok(None) => {
                        panic!("Read operation would block, bailing cuz this shouldn't happen.");
                    }
                    Ok(Some(r)) => {
                        // `_` would be the number of bytes read.
                        // `flip` will return a `ByteBuf` on which we can call
                        // `read_slice` to get the data available to be read.
                        // See http://carllerche.github.io/bytes/bytes/struct.ByteBuf.html
                        let mut buf = read_buf.flip();
                        let mut sl = [0; 2048];
                        buf.read_slice(&mut sl);
                        // Assuming what was written was encoded as UTF8, print what
                        // was read to STDOUT.
                        print!("{}", String::from_utf8(sl.to_vec()).unwrap());
                    }
                    Err(e) => {
                        // Probably because connection could not be established.
                        event_loop.shutdown();
                        panic!(e.to_string());
                    }
                }
            },
            _ => {
                panic!("unepxected token!".to_string());
            }
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<ClientHandler>, msg: String) {
        self.sock.write_slice(msg.as_bytes()).unwrap();
    }
}

pub fn nc_connect(matches: &Matches) {
    let addr = parse_addr(matches);
    let sock = match addr.ip() {
        IpAddr::V4(..) => v4(),
        IpAddr::V6(..) => v6()
    }.unwrap();

    let mut event_loop = EventLoop::new().unwrap();

    match sock.connect(&addr) {
        Ok((stream, _)) => {
            let mut client = ClientHandler { sock: stream };
            event_loop.register(&client.sock, CLIENT).unwrap();
            let sender = event_loop.channel();
            thread::spawn(move || {
                readwrite_chan(&sender);
            });
            let _ = event_loop.run(&mut client);
        },
        Err(f) => {
            println!("exiting: {}", f.to_string());
            // just exit
        }
    }
}

fn readwrite_chan(channel: &EventLoopSender<String>) {
    let mut stdin_reader = old_io::stdin();
    let mut read_buf = [0; 4096];
    loop {
        // Have to block here, so we can't immediately terminate if server closes socket.
        match stdin_reader.read(&mut read_buf) {
            Ok(n) => {
                let read = read_buf.slice_to(n);
                let byte_vec: Vec<u8> = read.to_vec();
                let message = String::from_utf8(byte_vec).unwrap();
                channel.send(message).unwrap();
            },
            Err(f) => {
                panic!(f.to_string());
            }
        }
    }
}
<|endoftext|>


<commit_before>// The code below is a stub. Just enough to satisfy the compiler.
// In order to pass the tests you can add-to or change any of this code.

#[derive(PartialEq, Debug)]
pub enum Direction {
    North,
    East,
    South,
    West,
}

pub struct Robot {
    rx: isize,
    ry: isize,
    rd: Direction,
}

impl Robot {
    #[allow(unused_variables)]
    pub fn new(x: isize, y: isize, d: Direction) -> Self {
        Robot {
            rx: x,
            ry: y,
            rd: d,
        }
    }

    pub fn turn_right(self) -> Self {
        Robot {
            rx: self.rx,
            ry: self.ry,
            rd: match self.rd {
                Direction::North => Direction::East,
                Direction::East => Direction::South,
                Direction::South => Direction::West,
                Direction::West => Direction::North,
            },
        }
    }

    pub fn turn_left(self) -> Self {
        Robot {
            rx: self.rx,
            ry: self.ry,
            rd: match self.rd {
                Direction::North => Direction::West,
                Direction::East => Direction::North,
                Direction::South => Direction::East,
                Direction::West => Direction::South,
            },
        }
    }

    pub fn advance(self) -> Self {
        let (x, y) = match self.rd {
            Direction::North => (self.rx, self.ry + 1),
            Direction::East => (self.rx + 1, self.ry),
            Direction::South => (self.rx, self.ry - 1),
            Direction::West => (self.rx - 1, self.ry),
        };

        Robot {
            rx: x,
            ry: y,
            rd: self.rd,
        }
    }

    #[allow(unused_variables)]
    pub fn instructions(self, instructions: &str) -> Self {
        let mut r = self;
        for c in instructions.chars() {
            r = match c {
                'L' => r.turn_left(),
                'R' => r.turn_right(),
                'A' => r.advance(),
                _ => r,
            };
        }

        r
    }

    pub fn position(&self) -> (isize, isize) {
        (self.rx, self.ry)
    }

    pub fn direction(&self) -> &Direction {
        &self.rd
    }
}
<commit_msg>Use ..self to simplify code<commit_after>// The code below is a stub. Just enough to satisfy the compiler.
// In order to pass the tests you can add-to or change any of this code.

#[derive(PartialEq, Debug)]
pub enum Direction {
    North,
    East,
    South,
    West,
}

pub struct Robot {
    rx: isize,
    ry: isize,
    rd: Direction,
}

impl Robot {
    #[allow(unused_variables)]
    pub fn new(x: isize, y: isize, d: Direction) -> Self {
        Robot {
            rx: x,
            ry: y,
            rd: d,
        }
    }

    pub fn turn_right(self) -> Self {
        Robot {
            rd: match self.rd {
                Direction::North => Direction::East,
                Direction::East => Direction::South,
                Direction::South => Direction::West,
                Direction::West => Direction::North,
            },
            ..self
        }
    }

    pub fn turn_left(self) -> Self {
        Robot {
            rd: match self.rd {
                Direction::North => Direction::West,
                Direction::East => Direction::North,
                Direction::South => Direction::East,
                Direction::West => Direction::South,
            },
            ..self
        }
    }

    pub fn advance(self) -> Self {
        match self.rd {
            Direction::North => Robot{ry: self.ry + 1, ..self},
            Direction::East => Robot{rx: self.rx + 1, ..self},
            Direction::South => Robot{ry: self.ry - 1, ..self},
            Direction::West => Robot{rx: self.rx - 1, ..self},
        }
    }

    #[allow(unused_variables)]
    pub fn instructions(self, instructions: &str) -> Self {
        let mut r = self;

        for c in instructions.chars() {
            r = match c {
                'L' => r.turn_left(),
                'R' => r.turn_right(),
                'A' => r.advance(),
                _ => r,
            };
        }

        r
    }

    pub fn position(&self) -> (isize, isize) {
        (self.rx, self.ry)
    }

    pub fn direction(&self) -> &Direction {
        &self.rd
    }
}
<|endoftext|>


<commit_before>use std::fs;

use kite_rocksdb::RocksDBIndexStore;

use analysis::AnalyzerSpec;
use analysis::tokenizers::TokenizerSpec;
use analysis::filters::FilterSpec;
use analysis::ngram_generator::Edge;
use index::Index;

use api::persistent;
use api::iron::prelude::*;
use api::iron::status;
use api::router::Router;
use api::utils::json_response;

pub fn view_get_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let indices = system.indices.read().unwrap();

    // Check index exists
    get_index_or_404!(indices, *index_name);

    // TODO
    return Ok(json_response(status::Ok, "{}"));
}

pub fn view_put_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Load data from body
    // let data = json_from_request_body!(req);

    // Find index
    let index_ref = indices.names.find_canonical(&index_name);

    match index_ref {
        Some(_) => {
            // Update existing index
            // TODO

            system.log.info("[api] updated index", b!("index" => *index_name));
        }
        None => {
            // Create index
            let mut indices_dir = system.get_indices_dir();
            indices_dir.push(index_name);
            let mut index = Index::new(index_name.clone().to_owned(), RocksDBIndexStore::create(indices_dir).unwrap());

            // Insert standard and edgengram analyzers
            // TODO: Load these from index settings
            index.analyzers.insert("standard".to_string(), AnalyzerSpec {
                tokenizer: TokenizerSpec::Standard,
                filters: vec![
                    FilterSpec::Lowercase,
                    FilterSpec::ASCIIFolding,
                ]
            });
            index.analyzers.insert("edgengram_analyzer".to_string(), AnalyzerSpec {
                tokenizer: TokenizerSpec::Standard,
                filters: vec![
                    FilterSpec::Lowercase,
                    FilterSpec::ASCIIFolding,
                    FilterSpec::NGram {
                        min_size: 2,
                        max_size: 15,
                        edge: Edge::Left
                    },
                ]
            });

            // TODO: load settings

            let index_ref = indices.insert(index);

            // If there's an alias with the new indexes name, delete it.
            let alias_deleted = indices.names.delete_alias_whole(index_name).unwrap();
            if alias_deleted {
                 system.log.info("[api] deleted alias", b!("alias" => format!("{}", index_name)));
            }

            // Register canonical name
            indices.names.insert_canonical(index_name.clone().to_owned(), index_ref).unwrap();

            system.log.info("[api] created index", b!("index" => *index_name));
        }
    }

    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}

pub fn view_delete_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_selector = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Make sure the index exists
    get_index_or_404!(indices, *index_selector);

    // Remove indices
    for index_ref in indices.names.find(*index_selector) {
        // Get the index name
        let index_name = {
            if let Some(index) = indices.get(&index_ref) {
                index.name().to_string()
            } else {
                // Index doesn't exist
                continue;
            }
        };

        // Remove index from array
        indices.remove(&index_ref);

        // Delete canonical name
        indices.names.delete_canonical(&index_name, index_ref).unwrap();

        // Delete file
        let mut indices_dir = system.get_indices_dir();
        indices_dir.push(&index_name);
        match fs::remove_dir_all(&indices_dir) {
            Ok(()) => {},
            Err(e) => {
                system.log.warn("[api] failed to delete index data", b!("index" => format!("{}", index_name), "error" => format!("{}", e)));
            }
        }

        system.log.info("[api] deleted index", b!("index" => format!("{}", index_name)));

        // Delete aliases
        let alias_names = indices.names.iter_index_aliases(index_ref).map(|n| n.to_string()).collect::<Vec<String>>();
        for alias_name in alias_names {
            let alias_deleted = indices.names.delete_alias(&alias_name, index_ref).unwrap();

            // If this was the only index being referenced by the alias, the alias would be deleted
            if alias_deleted {
                 system.log.info("[api] deleted alias", b!("alias" => format!("{}", alias_name)));
            }
        }
    }

    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}

pub fn view_post_refresh_index(_req: &mut Request) -> IronResult<Response> {
    // let ref system = get_system!(req);
    // let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    // TODO
    // let mut indices = system.indices.write().unwrap();

    // TODO: {"_shards":{"total":10,"successful":5,"failed":0}}
    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}
<commit_msg>Added reasons to auto-delete alias logs<commit_after>use std::fs;

use kite_rocksdb::RocksDBIndexStore;

use analysis::AnalyzerSpec;
use analysis::tokenizers::TokenizerSpec;
use analysis::filters::FilterSpec;
use analysis::ngram_generator::Edge;
use index::Index;

use api::persistent;
use api::iron::prelude::*;
use api::iron::status;
use api::router::Router;
use api::utils::json_response;

pub fn view_get_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let indices = system.indices.read().unwrap();

    // Check index exists
    get_index_or_404!(indices, *index_name);

    // TODO
    return Ok(json_response(status::Ok, "{}"));
}

pub fn view_put_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Load data from body
    // let data = json_from_request_body!(req);

    // Find index
    let index_ref = indices.names.find_canonical(&index_name);

    match index_ref {
        Some(_) => {
            // Update existing index
            // TODO

            system.log.info("[api] updated index", b!("index" => *index_name));
        }
        None => {
            // Create index
            let mut indices_dir = system.get_indices_dir();
            indices_dir.push(index_name);
            let mut index = Index::new(index_name.clone().to_owned(), RocksDBIndexStore::create(indices_dir).unwrap());

            // Insert standard and edgengram analyzers
            // TODO: Load these from index settings
            index.analyzers.insert("standard".to_string(), AnalyzerSpec {
                tokenizer: TokenizerSpec::Standard,
                filters: vec![
                    FilterSpec::Lowercase,
                    FilterSpec::ASCIIFolding,
                ]
            });
            index.analyzers.insert("edgengram_analyzer".to_string(), AnalyzerSpec {
                tokenizer: TokenizerSpec::Standard,
                filters: vec![
                    FilterSpec::Lowercase,
                    FilterSpec::ASCIIFolding,
                    FilterSpec::NGram {
                        min_size: 2,
                        max_size: 15,
                        edge: Edge::Left
                    },
                ]
            });

            // TODO: load settings

            let index_ref = indices.insert(index);

            // If there's an alias with the new indexes name, delete it.
            let alias_deleted = indices.names.delete_alias_whole(index_name).unwrap();
            if alias_deleted {
                 system.log.info("[api] deleted alias", b!("alias" => format!("{}", index_name), "reason" => "replaced by index"));
            }

            // Register canonical name
            indices.names.insert_canonical(index_name.clone().to_owned(), index_ref).unwrap();

            system.log.info("[api] created index", b!("index" => *index_name));
        }
    }

    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}

pub fn view_delete_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_selector = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Make sure the index exists
    get_index_or_404!(indices, *index_selector);

    // Remove indices
    for index_ref in indices.names.find(*index_selector) {
        // Get the index name
        let index_name = {
            if let Some(index) = indices.get(&index_ref) {
                index.name().to_string()
            } else {
                // Index doesn't exist
                continue;
            }
        };

        // Remove index from array
        indices.remove(&index_ref);

        // Delete canonical name
        indices.names.delete_canonical(&index_name, index_ref).unwrap();

        // Delete file
        let mut indices_dir = system.get_indices_dir();
        indices_dir.push(&index_name);
        match fs::remove_dir_all(&indices_dir) {
            Ok(()) => {},
            Err(e) => {
                system.log.warn("[api] failed to delete index data", b!("index" => format!("{}", index_name), "error" => format!("{}", e)));
            }
        }

        system.log.info("[api] deleted index", b!("index" => format!("{}", index_name)));

        // Delete aliases
        let alias_names = indices.names.iter_index_aliases(index_ref).map(|n| n.to_string()).collect::<Vec<String>>();
        for alias_name in alias_names {
            let alias_deleted = indices.names.delete_alias(&alias_name, index_ref).unwrap();

            // If this was the only index being referenced by the alias, the alias would be deleted
            if alias_deleted {
                 system.log.info("[api] deleted alias", b!("alias" => format!("{}", alias_name), "reason" => "no indices left"));
            }
        }
    }

    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}

pub fn view_post_refresh_index(_req: &mut Request) -> IronResult<Response> {
    // let ref system = get_system!(req);
    // let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    // TODO
    // let mut indices = system.indices.write().unwrap();

    // TODO: {"_shards":{"total":10,"successful":5,"failed":0}}
    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}
<|endoftext|>


<commit_before>use std::{
    collections::HashMap,
    path::{Path, PathBuf},
};

use xshell::{cmd, read_file};
use xtask::{
    codegen::{self, Mode},
    project_root, run_rustfmt, rust_files,
};

#[test]
fn generated_grammar_is_fresh() {
    if let Err(error) = codegen::generate_syntax(Mode::Verify) {
        panic!("{}. Please update it by running `cargo xtask codegen`", error);
    }
}

#[test]
fn generated_tests_are_fresh() {
    if let Err(error) = codegen::generate_parser_tests(Mode::Verify) {
        panic!("{}. Please update tests by running `cargo xtask codegen`", error);
    }
}

#[test]
fn generated_assists_are_fresh() {
    if let Err(error) = codegen::generate_assists_tests(Mode::Verify) {
        panic!("{}. Please update assists by running `cargo xtask codegen`", error);
    }
}

#[test]
fn check_code_formatting() {
    if let Err(error) = run_rustfmt(Mode::Verify) {
        panic!("{}. Please format the code by running `cargo format`", error);
    }
}

#[test]
fn smoke_test_docs_generation() {
    // We don't commit docs to the repo, so we can just overwrite in tests.
    codegen::generate_assists_docs(Mode::Overwrite).unwrap();
    codegen::generate_feature_docs(Mode::Overwrite).unwrap();
    codegen::generate_diagnostic_docs(Mode::Overwrite).unwrap();
}

#[test]
fn check_lsp_extensions_docs() {
    let expected_hash = {
        let lsp_ext_rs =
            read_file(project_root().join("crates/rust-analyzer/src/lsp_ext.rs")).unwrap();
        stable_hash(lsp_ext_rs.as_str())
    };

    let actual_hash = {
        let lsp_extensions_md =
            read_file(project_root().join("docs/dev/lsp-extensions.md")).unwrap();
        let text = lsp_extensions_md
            .lines()
            .find_map(|line| line.strip_prefix("lsp_ext.rs hash:"))
            .unwrap()
            .trim();
        u64::from_str_radix(text, 16).unwrap()
    };

    if actual_hash != expected_hash {
        panic!(
            "
lsp_ext.rs was changed without touching lsp-extensions.md.

Expected hash: {:x}
Actual hash:   {:x}

Please adjust docs/dev/lsp-extensions.md.
",
            expected_hash, actual_hash
        )
    }
}

#[test]
fn rust_files_are_tidy() {
    let mut tidy_docs = TidyDocs::default();
    for path in rust_files(&project_root().join("crates")) {
        let text = read_file(&path).unwrap();
        check_todo(&path, &text);
        check_trailing_ws(&path, &text);
        deny_clippy(&path, &text);
        tidy_docs.visit(&path, &text);
    }
    tidy_docs.finish();
}

#[test]
fn check_merge_commits() {
    let stdout =
        dbg!(cmd!("git rev-list --merges --invert-grep --author 'bors\\[bot\\]' HEAD~19.."))
            .read()
            .unwrap();
    if !stdout.is_empty() {
        panic!(
            "
Merge commits are not allowed in the history.

When updating a pull-request, please rebase your feature branch
on top of master by running `git rebase master`. If rebase fails,
you can re-apply your changes like this:

  # Just look around to see the current state.
  $ git status
  $ git log

  # Abort in-progress rebase and merges, if any.
  $ git rebase --abort
  $ git merge --abort

  # Make the branch point to the latest commit from master,
  # while maintaining your local changes uncommited.
  $ git reset --soft origin/master

  # Commit all changes in a single batch.
  $ git commit -am'My changes'

  # Verify that everything looks alright.
  $ git status
  $ git log

  # Push the changes. We did a rebase, so we need `--force` option.
  # `--force-with-lease` is a more safe (Rusty) version of `--force`.
  $ git push --force-with-lease

  # Verify that both local and remote branch point to the same commit.
  $ git log

And don't fear to mess something up during a rebase -- you can
always restore the previous state using `git ref-log`:

https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git/#redo-after-undo-local
"
        );
    }
}

fn deny_clippy(path: &PathBuf, text: &String) {
    let ignore = &[
        // The documentation in string literals may contain anything for its own purposes
        "completion/src/generated_lint_completions.rs",
    ];
    if ignore.iter().any(|p| path.ends_with(p)) {
        return;
    }

    if text.contains("\u{61}llow(clippy") {
        panic!(
            "\n\nallowing lints is forbidden: {}.
rust-analyzer intentionally doesn't check clippy on CI.
You can allow lint globally via `xtask clippy`.
See https://github.com/rust-lang/rust-clippy/issues/5537 for discussion.

",
            path.display()
        )
    }
}

#[test]
fn check_licenses() {
    let expected = "
0BSD OR MIT OR Apache-2.0
Apache-2.0
Apache-2.0 OR BSL-1.0
Apache-2.0 OR MIT
Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
Apache-2.0/MIT
BSD-3-Clause
CC0-1.0
ISC
MIT
MIT / Apache-2.0
MIT OR Apache-2.0
MIT OR Apache-2.0 OR Zlib
MIT OR Zlib OR Apache-2.0
MIT/Apache-2.0
Unlicense OR MIT
Unlicense/MIT
Zlib OR Apache-2.0 OR MIT
"
    .lines()
    .filter(|it| !it.is_empty())
    .collect::<Vec<_>>();

    let meta = cmd!("cargo metadata --format-version 1").read().unwrap();
    let mut licenses = meta
        .split(|c| c == ',' || c == '{' || c == '}')
        .filter(|it| it.contains(r#""license""#))
        .map(|it| it.trim())
        .map(|it| it[r#""license":"#.len()..].trim_matches('"'))
        .collect::<Vec<_>>();
    licenses.sort();
    licenses.dedup();
    if licenses != expected {
        let mut diff = String::new();

        diff += &format!("New Licenses:\n");
        for &l in licenses.iter() {
            if !expected.contains(&l) {
                diff += &format!("  {}\n", l)
            }
        }

        diff += &format!("\nMissing Licenses:\n");
        for &l in expected.iter() {
            if !licenses.contains(&l) {
                diff += &format!("  {}\n", l)
            }
        }

        panic!("different set of licenses!\n{}", diff);
    }
    assert_eq!(licenses, expected);
}

fn check_todo(path: &Path, text: &str) {
    let need_todo = &[
        // This file itself obviously needs to use todo (<- like this!).
        "tests/cli.rs",
        // Some of our assists generate `todo!()`.
        "handlers/add_turbo_fish.rs",
        "handlers/generate_function.rs",
        // To support generating `todo!()` in assists, we have `expr_todo()` in
        // `ast::make`.
        "ast/make.rs",
        // The documentation in string literals may contain anything for its own purposes
        "completion/src/generated_lint_completions.rs",
    ];
    if need_todo.iter().any(|p| path.ends_with(p)) {
        return;
    }
    if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {
        // Generated by an assist
        if text.contains("${0:todo!()}") {
            return;
        }

        panic!(
            "\nTODO markers or todo! macros should not be committed to the master branch,\n\
             use FIXME instead\n\
             {}\n",
            path.display(),
        )
    }
}

fn check_trailing_ws(path: &Path, text: &str) {
    if is_exclude_dir(path, &["test_data"]) {
        return;
    }
    for (line_number, line) in text.lines().enumerate() {
        if line.chars().last().map(char::is_whitespace) == Some(true) {
            panic!("Trailing whitespace in {} at line {}", path.display(), line_number)
        }
    }
}

#[derive(Default)]
struct TidyDocs {
    missing_docs: Vec<String>,
    contains_fixme: Vec<PathBuf>,
}

impl TidyDocs {
    fn visit(&mut self, path: &Path, text: &str) {
        // Test hopefully don't really need comments, and for assists we already
        // have special comments which are source of doc tests and user docs.
        if is_exclude_dir(path, &["tests", "test_data"]) {
            return;
        }

        if is_exclude_file(path) {
            return;
        }

        let first_line = match text.lines().next() {
            Some(it) => it,
            None => return,
        };

        if first_line.starts_with("//!") {
            if first_line.contains("FIXME") {
                self.contains_fixme.push(path.to_path_buf());
            }
        } else {
            if text.contains("// Feature:") || text.contains("// Assist:") {
                return;
            }
            self.missing_docs.push(path.display().to_string());
        }

        fn is_exclude_file(d: &Path) -> bool {
            let file_names = ["tests.rs"];

            d.file_name()
                .unwrap_or_default()
                .to_str()
                .map(|f_n| file_names.iter().any(|name| *name == f_n))
                .unwrap_or(false)
        }
    }

    fn finish(self) {
        if !self.missing_docs.is_empty() {
            panic!(
                "\nMissing docs strings\n\n\
                 modules:\n{}\n\n",
                self.missing_docs.join("\n")
            )
        }

        let poorly_documented = [
            "hir",
            "hir_expand",
            "ide",
            "mbe",
            "parser",
            "profile",
            "project_model",
            "syntax",
            "tt",
            "hir_ty",
        ];

        let mut has_fixmes =
            poorly_documented.iter().map(|it| (*it, false)).collect::<HashMap<&str, bool>>();
        'outer: for path in self.contains_fixme {
            for krate in poorly_documented.iter() {
                if path.components().any(|it| it.as_os_str() == *krate) {
                    has_fixmes.insert(krate, true);
                    continue 'outer;
                }
            }
            panic!("FIXME doc in a fully-documented crate: {}", path.display())
        }

        for (krate, has_fixme) in has_fixmes.iter() {
            if !has_fixme {
                panic!("crate {} is fully documented :tada:, remove it from the list of poorly documented crates", krate)
            }
        }
    }
}

fn is_exclude_dir(p: &Path, dirs_to_exclude: &[&str]) -> bool {
    p.strip_prefix(project_root())
        .unwrap()
        .components()
        .rev()
        .skip(1)
        .filter_map(|it| it.as_os_str().to_str())
        .any(|it| dirs_to_exclude.contains(&it))
}

#[allow(deprecated)]
fn stable_hash(text: &str) -> u64 {
    use std::hash::{Hash, Hasher, SipHasher};

    let text = text.replace('\r', "");
    let mut hasher = SipHasher::default();
    text.hash(&mut hasher);
    hasher.finish()
}
<commit_msg>Remove unused dbg<commit_after>use std::{
    collections::HashMap,
    path::{Path, PathBuf},
};

use xshell::{cmd, read_file};
use xtask::{
    codegen::{self, Mode},
    project_root, run_rustfmt, rust_files,
};

#[test]
fn generated_grammar_is_fresh() {
    if let Err(error) = codegen::generate_syntax(Mode::Verify) {
        panic!("{}. Please update it by running `cargo xtask codegen`", error);
    }
}

#[test]
fn generated_tests_are_fresh() {
    if let Err(error) = codegen::generate_parser_tests(Mode::Verify) {
        panic!("{}. Please update tests by running `cargo xtask codegen`", error);
    }
}

#[test]
fn generated_assists_are_fresh() {
    if let Err(error) = codegen::generate_assists_tests(Mode::Verify) {
        panic!("{}. Please update assists by running `cargo xtask codegen`", error);
    }
}

#[test]
fn check_code_formatting() {
    if let Err(error) = run_rustfmt(Mode::Verify) {
        panic!("{}. Please format the code by running `cargo format`", error);
    }
}

#[test]
fn smoke_test_docs_generation() {
    // We don't commit docs to the repo, so we can just overwrite in tests.
    codegen::generate_assists_docs(Mode::Overwrite).unwrap();
    codegen::generate_feature_docs(Mode::Overwrite).unwrap();
    codegen::generate_diagnostic_docs(Mode::Overwrite).unwrap();
}

#[test]
fn check_lsp_extensions_docs() {
    let expected_hash = {
        let lsp_ext_rs =
            read_file(project_root().join("crates/rust-analyzer/src/lsp_ext.rs")).unwrap();
        stable_hash(lsp_ext_rs.as_str())
    };

    let actual_hash = {
        let lsp_extensions_md =
            read_file(project_root().join("docs/dev/lsp-extensions.md")).unwrap();
        let text = lsp_extensions_md
            .lines()
            .find_map(|line| line.strip_prefix("lsp_ext.rs hash:"))
            .unwrap()
            .trim();
        u64::from_str_radix(text, 16).unwrap()
    };

    if actual_hash != expected_hash {
        panic!(
            "
lsp_ext.rs was changed without touching lsp-extensions.md.

Expected hash: {:x}
Actual hash:   {:x}

Please adjust docs/dev/lsp-extensions.md.
",
            expected_hash, actual_hash
        )
    }
}

#[test]
fn rust_files_are_tidy() {
    let mut tidy_docs = TidyDocs::default();
    for path in rust_files(&project_root().join("crates")) {
        let text = read_file(&path).unwrap();
        check_todo(&path, &text);
        check_trailing_ws(&path, &text);
        deny_clippy(&path, &text);
        tidy_docs.visit(&path, &text);
    }
    tidy_docs.finish();
}

#[test]
fn check_merge_commits() {
    let stdout = cmd!("git rev-list --merges --invert-grep --author 'bors\\[bot\\]' HEAD~19..")
        .read()
        .unwrap();
    if !stdout.is_empty() {
        panic!(
            "
Merge commits are not allowed in the history.

When updating a pull-request, please rebase your feature branch
on top of master by running `git rebase master`. If rebase fails,
you can re-apply your changes like this:

  # Just look around to see the current state.
  $ git status
  $ git log

  # Abort in-progress rebase and merges, if any.
  $ git rebase --abort
  $ git merge --abort

  # Make the branch point to the latest commit from master,
  # while maintaining your local changes uncommited.
  $ git reset --soft origin/master

  # Commit all changes in a single batch.
  $ git commit -am'My changes'

  # Verify that everything looks alright.
  $ git status
  $ git log

  # Push the changes. We did a rebase, so we need `--force` option.
  # `--force-with-lease` is a more safe (Rusty) version of `--force`.
  $ git push --force-with-lease

  # Verify that both local and remote branch point to the same commit.
  $ git log

And don't fear to mess something up during a rebase -- you can
always restore the previous state using `git ref-log`:

https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git/#redo-after-undo-local
"
        );
    }
}

fn deny_clippy(path: &PathBuf, text: &String) {
    let ignore = &[
        // The documentation in string literals may contain anything for its own purposes
        "completion/src/generated_lint_completions.rs",
    ];
    if ignore.iter().any(|p| path.ends_with(p)) {
        return;
    }

    if text.contains("\u{61}llow(clippy") {
        panic!(
            "\n\nallowing lints is forbidden: {}.
rust-analyzer intentionally doesn't check clippy on CI.
You can allow lint globally via `xtask clippy`.
See https://github.com/rust-lang/rust-clippy/issues/5537 for discussion.

",
            path.display()
        )
    }
}

#[test]
fn check_licenses() {
    let expected = "
0BSD OR MIT OR Apache-2.0
Apache-2.0
Apache-2.0 OR BSL-1.0
Apache-2.0 OR MIT
Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
Apache-2.0/MIT
BSD-3-Clause
CC0-1.0
ISC
MIT
MIT / Apache-2.0
MIT OR Apache-2.0
MIT OR Apache-2.0 OR Zlib
MIT OR Zlib OR Apache-2.0
MIT/Apache-2.0
Unlicense OR MIT
Unlicense/MIT
Zlib OR Apache-2.0 OR MIT
"
    .lines()
    .filter(|it| !it.is_empty())
    .collect::<Vec<_>>();

    let meta = cmd!("cargo metadata --format-version 1").read().unwrap();
    let mut licenses = meta
        .split(|c| c == ',' || c == '{' || c == '}')
        .filter(|it| it.contains(r#""license""#))
        .map(|it| it.trim())
        .map(|it| it[r#""license":"#.len()..].trim_matches('"'))
        .collect::<Vec<_>>();
    licenses.sort();
    licenses.dedup();
    if licenses != expected {
        let mut diff = String::new();

        diff += &format!("New Licenses:\n");
        for &l in licenses.iter() {
            if !expected.contains(&l) {
                diff += &format!("  {}\n", l)
            }
        }

        diff += &format!("\nMissing Licenses:\n");
        for &l in expected.iter() {
            if !licenses.contains(&l) {
                diff += &format!("  {}\n", l)
            }
        }

        panic!("different set of licenses!\n{}", diff);
    }
    assert_eq!(licenses, expected);
}

fn check_todo(path: &Path, text: &str) {
    let need_todo = &[
        // This file itself obviously needs to use todo (<- like this!).
        "tests/cli.rs",
        // Some of our assists generate `todo!()`.
        "handlers/add_turbo_fish.rs",
        "handlers/generate_function.rs",
        // To support generating `todo!()` in assists, we have `expr_todo()` in
        // `ast::make`.
        "ast/make.rs",
        // The documentation in string literals may contain anything for its own purposes
        "completion/src/generated_lint_completions.rs",
    ];
    if need_todo.iter().any(|p| path.ends_with(p)) {
        return;
    }
    if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {
        // Generated by an assist
        if text.contains("${0:todo!()}") {
            return;
        }

        panic!(
            "\nTODO markers or todo! macros should not be committed to the master branch,\n\
             use FIXME instead\n\
             {}\n",
            path.display(),
        )
    }
}

fn check_trailing_ws(path: &Path, text: &str) {
    if is_exclude_dir(path, &["test_data"]) {
        return;
    }
    for (line_number, line) in text.lines().enumerate() {
        if line.chars().last().map(char::is_whitespace) == Some(true) {
            panic!("Trailing whitespace in {} at line {}", path.display(), line_number)
        }
    }
}

#[derive(Default)]
struct TidyDocs {
    missing_docs: Vec<String>,
    contains_fixme: Vec<PathBuf>,
}

impl TidyDocs {
    fn visit(&mut self, path: &Path, text: &str) {
        // Test hopefully don't really need comments, and for assists we already
        // have special comments which are source of doc tests and user docs.
        if is_exclude_dir(path, &["tests", "test_data"]) {
            return;
        }

        if is_exclude_file(path) {
            return;
        }

        let first_line = match text.lines().next() {
            Some(it) => it,
            None => return,
        };

        if first_line.starts_with("//!") {
            if first_line.contains("FIXME") {
                self.contains_fixme.push(path.to_path_buf());
            }
        } else {
            if text.contains("// Feature:") || text.contains("// Assist:") {
                return;
            }
            self.missing_docs.push(path.display().to_string());
        }

        fn is_exclude_file(d: &Path) -> bool {
            let file_names = ["tests.rs"];

            d.file_name()
                .unwrap_or_default()
                .to_str()
                .map(|f_n| file_names.iter().any(|name| *name == f_n))
                .unwrap_or(false)
        }
    }

    fn finish(self) {
        if !self.missing_docs.is_empty() {
            panic!(
                "\nMissing docs strings\n\n\
                 modules:\n{}\n\n",
                self.missing_docs.join("\n")
            )
        }

        let poorly_documented = [
            "hir",
            "hir_expand",
            "ide",
            "mbe",
            "parser",
            "profile",
            "project_model",
            "syntax",
            "tt",
            "hir_ty",
        ];

        let mut has_fixmes =
            poorly_documented.iter().map(|it| (*it, false)).collect::<HashMap<&str, bool>>();
        'outer: for path in self.contains_fixme {
            for krate in poorly_documented.iter() {
                if path.components().any(|it| it.as_os_str() == *krate) {
                    has_fixmes.insert(krate, true);
                    continue 'outer;
                }
            }
            panic!("FIXME doc in a fully-documented crate: {}", path.display())
        }

        for (krate, has_fixme) in has_fixmes.iter() {
            if !has_fixme {
                panic!("crate {} is fully documented :tada:, remove it from the list of poorly documented crates", krate)
            }
        }
    }
}

fn is_exclude_dir(p: &Path, dirs_to_exclude: &[&str]) -> bool {
    p.strip_prefix(project_root())
        .unwrap()
        .components()
        .rev()
        .skip(1)
        .filter_map(|it| it.as_os_str().to_str())
        .any(|it| dirs_to_exclude.contains(&it))
}

#[allow(deprecated)]
fn stable_hash(text: &str) -> u64 {
    use std::hash::{Hash, Hasher, SipHasher};

    let text = text.replace('\r', "");
    let mut hasher = SipHasher::default();
    text.hash(&mut hasher);
    hasher.finish()
}
<|endoftext|>


<commit_before>use bytes::{ Buf, BigEndian, BytesMut, IntoBuf };
use tokio::net::TcpStream;
use tokio::prelude::{ Async, AsyncRead, Poll, Stream };
use tokio::io;
use super::ClientMessage;

pub struct ClientCodec {
    stream: TcpStream,
    read_buffer: BytesMut,
//    write_buffer: BytesMut
}

impl ClientCodec {
    pub fn new(stream: TcpStream) -> Self {
        Self {
            stream,
            read_buffer: BytesMut::new(),
 //           write_buffer: BytesMut::new()
        }
    }

    fn read_next_packet(&mut self) -> Poll<(), io::Error> {
        loop {
            // This initial value of 1024 is totally just an educated guess. It should be reviewed at some later point.
            self.read_buffer.reserve(1024);

            let n = try_ready!(self.stream.read_buf(&mut self.read_buffer));

            println!("Got value from try_ready: {}", n);

            if n == 0 {
                return Ok(Async::Ready(()))
            }
        }
    }

    fn read_label(buffer: &mut BytesMut) -> Async<Option<String>> {
        const LABEL_LEN_SIZE: usize = 1;

        if buffer.len() >= LABEL_LEN_SIZE {
            let label_len = buffer.split_to(LABEL_LEN_SIZE)[0] as usize;

            if buffer.len() >= label_len {
                let raw_label = buffer.split_to(label_len);

                Async::Ready(Some(String::from_utf8(raw_label.as_ref().to_vec()).unwrap_or(String::from("[Label error]"))))
            } else {
                Async::NotReady
            }
        } else {
            Async::NotReady
        }
    }
}

impl Stream for ClientCodec {

    type Item = ClientMessage;
    type Error = io::Error;

    /// For each invocation of `poll` we try to read and retrieve a `ClientMessage`.
    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        let sock_closed = self.read_next_packet()?.is_ready();
        let mut read_bytes: usize = 0;

        println!("Read buffer: {:?}", self.read_buffer);

        const MSG_MNEMONIC_SIZE: usize = 2;
        const STR_LENGTH_SIZE: usize = 1;

        let mut buffer = self.read_buffer.clone();

        if buffer.len() >= MSG_MNEMONIC_SIZE {
            let msg_code = buffer.split_to(MSG_MNEMONIC_SIZE);

            read_bytes += MSG_MNEMONIC_SIZE;

            println!("Message code: #{:?}", msg_code);

            let result = match &msg_code[..] {
                b"la" => ClientCodec::read_label(&mut buffer).map(|label| label.map(|name| ClientMessage::ClientHello { name: name })),
                b"he" => {
                    if buffer.len() >= STR_LENGTH_SIZE {
                        let msg_size = buffer.split_to(STR_LENGTH_SIZE);
                        read_bytes += STR_LENGTH_SIZE;

                        println!("Message size: {}", msg_size[0]);
                        let offset = msg_size[0] as usize - '0' as usize;

                        if buffer.len() >= offset {
                            let raw_name = buffer.split_to(offset);
                            read_bytes += offset;

                            println!("Found name: {:?}", raw_name);

                            Async::Ready(Some(ClientMessage::ClientHello { name: String::from_utf8(raw_name.as_ref().to_vec()).unwrap_or(String::from("Name error"))  }))
                        } else {
                            Async::NotReady
                        }
                    } else {
                        Async::NotReady
                    }
                },
                _ => Async::Ready(None)
            };

            match result {
                Async::Ready(_) => { self.read_buffer.split_to(read_bytes); },
                _ => ()
            }

            println!("Inner result: {:?}", result);

            return Ok(result)
        }

        if sock_closed {
            Ok(Async::Ready(None))
        } else {
            Ok(Async::NotReady)
        }
    }
}
<commit_msg>Partial ClientDecoder<commit_after>use bytes::{ Buf, BigEndian, BytesMut, IntoBuf };
use tokio::net::TcpStream;
use tokio::prelude::{ Async, AsyncRead, Poll, Stream };
use tokio::io;
use super::ClientMessage;

pub struct ClientDecoder;

impl ClientDecoder {
    pub fn decode_packet(&mut self, mut buffer: BytesMut) -> Option<(usize, ClientMessage)> {
        const MNEMONIC_SIZE: usize = 2;

        let mut read_bytes: usize = 0;

        if buffer.len() >= MNEMONIC_SIZE {
            let mnemonic = buffer.split_to(MNEMONIC_SIZE);
            read_bytes += MNEMONIC_SIZE;

            match &mnemonic[..] {
                b"he" => (),
                _ => ()
            }
        }

        None
    }

}

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

pub struct ClientCodec {
    stream: TcpStream,
    read_buffer: BytesMut,
//    write_buffer: BytesMut
}

impl ClientCodec {
    pub fn new(stream: TcpStream) -> Self {
        Self {
            stream,
            read_buffer: BytesMut::new(),
 //           write_buffer: BytesMut::new()
        }
    }

    fn read_next_packet(&mut self) -> Poll<(), io::Error> {
        loop {
            // This initial value of 1024 is totally just an educated guess. It should be reviewed at some later point.
            self.read_buffer.reserve(1024);

            let n = try_ready!(self.stream.read_buf(&mut self.read_buffer));

            println!("Got value from try_ready: {}", n);

            if n == 0 {
                return Ok(Async::Ready(()))
            }
        }
    }

    fn read_label(buffer: &mut BytesMut) -> Async<Option<String>> {
        const LABEL_LEN_SIZE: usize = 1;

        if buffer.len() >= LABEL_LEN_SIZE {
            let label_len = buffer.split_to(LABEL_LEN_SIZE)[0] as usize;

            if buffer.len() >= label_len {
                let raw_label = buffer.split_to(label_len);

                Async::Ready(Some(String::from_utf8(raw_label.as_ref().to_vec()).unwrap_or(String::from("[Label error]"))))
            } else {
                Async::NotReady
            }
        } else {
            Async::NotReady
        }
    }
}

impl Stream for ClientCodec {

    type Item = ClientMessage;
    type Error = io::Error;

    /// For each invocation of `poll` we try to read and retrieve a `ClientMessage`.
    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        let sock_closed = self.read_next_packet()?.is_ready();
        let mut read_bytes: usize = 0;

        println!("Read buffer: {:?}", self.read_buffer);

        const MSG_MNEMONIC_SIZE: usize = 2;
        const STR_LENGTH_SIZE: usize = 1;

        let mut buffer = self.read_buffer.clone();

        if buffer.len() >= MSG_MNEMONIC_SIZE {
            let msg_code = buffer.split_to(MSG_MNEMONIC_SIZE);

            read_bytes += MSG_MNEMONIC_SIZE;

            println!("Message code: #{:?}", msg_code);

            let result = match &msg_code[..] {
                /*
                b"la" => ClientCodec::read_label(&mut buffer).map(|label| label.map(|name| ClientMessage::ClientHello { name: name })),
                b"he" => {
                    if buffer.len() >= STR_LENGTH_SIZE {
                        let msg_size = buffer.split_to(STR_LENGTH_SIZE);
                        read_bytes += STR_LENGTH_SIZE;

                        println!("Message size: {}", msg_size[0]);
                        let offset = msg_size[0] as usize - '0' as usize;

                        if buffer.len() >= offset {
                            let raw_name = buffer.split_to(offset);
                            read_bytes += offset;

                            println!("Found name: {:?}", raw_name);

                            Async::Ready(Some(ClientMessage::ClientHello { name: String::from_utf8(raw_name.as_ref().to_vec()).unwrap_or(String::from("Name error"))  }))
                        } else {
                            Async::NotReady
                        }
                    } else {
                        Async::NotReady
                    }
                },
                */
                _ => Async::Ready(None)
            };

            match result {
                Async::Ready(_) => { self.read_buffer.split_to(read_bytes); },
                _ => ()
            }

            println!("Inner result: {:?}", result);

            return Ok(result)
        }

        if sock_closed {
            Ok(Async::Ready(None))
        } else {
            Ok(Async::NotReady)
        }
    }
}
<|endoftext|>


<commit_before>//! This module defines a series of convenience modifiers for changing
//! Responses.
//!
//! Modifiers can be used to edit `Response`s through the owning method `set`
//! or the mutating `set_mut`, both of which are defined in the `Set` trait.
//!
//! For Iron, the `Modifier` interface offers extensible and ergonomic response
//! creation while avoiding the introduction of many highly specific `Response`
//! constructors.
//!
//! The simplest case of a modifier is probably the one used to change the
//! return status code:
//!
//! ```
//! # use std::convert::Into;
//! # use iron::prelude::*;
//! # use iron::StatusCode;
//! let r = Response::with(StatusCode::NOT_FOUND);
//! assert_eq!(404 as u16, r.status.unwrap().as_u16());
//! ```
//!
//! You can also pass in a tuple of modifiers, they will all be applied. Here's
//! an example of a modifier 2-tuple that will change the status code and the
//! body message:
//!
//! ```
//! # use iron::prelude::*;
//! # use iron::StatusCode;
//! Response::with((StatusCode::IM_A_TEAPOT, "I am a tea pot!"));
//! ```
//!
//! There is also a `Redirect` modifier:
//!
//! ```
//! # use iron::prelude::*;
//! # use iron::StatusCode;
//! # use iron::modifiers;
//! # use iron::Url;
//! let url = Url::parse("http://doc.rust-lang.org").unwrap();
//! Response::with((StatusCode::FOUND, modifiers::Redirect(url)));
//! ```
//!
//! The modifiers are applied depending on their type. Currently the easiest
//! way to see how different types are used as modifiers, take a look at [the
//! source code](https://github.com/iron/iron/blob/master/src/modifiers.rs).
//!
//! For more information about the modifier system, see
//! [rust-modifier](https://github.com/reem/rust-modifier).

use std::fs::File;
use std::io;
use std::path::{Path, PathBuf};

use modifier::Modifier;

use mime::{self, Mime};

use {headers, Request, Response, Set, StatusCode, Url};

use mime_guess;
use response::{BodyReader, WriteBody};

impl Modifier<Response> for Mime {
    #[inline]
    fn modify(self, res: &mut Response) {
        // Mime should always be parsable to a valid HeaderValue, so unwrap should be safe here.
        res.headers
            .insert(headers::CONTENT_TYPE, self.as_ref().parse().unwrap());
    }
}

impl Modifier<Response> for Box<dyn WriteBody> {
    #[inline]
    fn modify(self, res: &mut Response) {
        res.body = Some(self);
    }
}

impl<R: io::Read + Send + 'static> Modifier<Response> for BodyReader<R> {
    #[inline]
    fn modify(self, res: &mut Response) {
        res.body = Some(Box::new(self));
    }
}

impl Modifier<Response> for String {
    #[inline]
    fn modify(self, res: &mut Response) {
        self.into_bytes().modify(res);
    }
}

impl Modifier<Response> for Vec<u8> {
    #[inline]
    fn modify(self, res: &mut Response) {
        res.headers
            .insert(headers::CONTENT_LENGTH, (self.len() as u64).into());
        res.body = Some(Box::new(self));
    }
}

impl<'a> Modifier<Response> for &'a str {
    #[inline]
    fn modify(self, res: &mut Response) {
        self.to_owned().modify(res);
    }
}

impl<'a> Modifier<Response> for &'a [u8] {
    #[inline]
    fn modify(self, res: &mut Response) {
        self.to_vec().modify(res);
    }
}

impl Modifier<Response> for File {
    fn modify(self, res: &mut Response) {
        // Set the content type based on the file extension if a path is available.
        if let Ok(metadata) = self.metadata() {
            res.headers
                .insert(headers::CONTENT_LENGTH, metadata.len().into());
        }

        res.body = Some(Box::new(self));
    }
}

impl<'a> Modifier<Response> for &'a Path {
    /// Set the body to the contents of the File at this path.
    ///
    /// ## Panics
    ///
    /// Panics if there is no file at the passed-in Path.
    fn modify(self, res: &mut Response) {
        File::open(self)
            .unwrap_or_else(|_| panic!("No such file: {}", self.display()))
            .modify(res);

        let mime = mime_for_path(self);
        res.set_mut(mime);
    }
}

impl Modifier<Response> for PathBuf {
    /// Set the body to the contents of the File at this path.
    ///
    /// ## Panics
    ///
    /// Panics if there is no file at the passed-in Path.
    #[inline]
    fn modify(self, res: &mut Response) {
        self.as_path().modify(res);
    }
}

impl Modifier<Response> for StatusCode {
    fn modify(self, res: &mut Response) {
        res.status = Some(self);
    }
}

/// A modifier for changing headers on requests and responses.
#[derive(Clone)]
pub struct Header<H>(pub H, pub headers::HeaderValue);

impl<H> Modifier<Response> for Header<H>
where
    H: headers::IntoHeaderName,
{
    fn modify(self, res: &mut Response) {
        res.headers.insert(self.0, self.1);
    }
}

impl<H> Modifier<Request> for Header<H>
where
    H: headers::IntoHeaderName,
{
    fn modify(self, res: &mut Request) {
        res.headers.insert(self.0, self.1);
    }
}

/// A modifier for creating redirect responses.
pub struct Redirect(pub Url);

impl Modifier<Response> for Redirect {
    fn modify(self, res: &mut Response) {
        let Redirect(url) = self;
        // Url should always be parsable to a valid HeaderValue, so unwrap should be safe here.
        res.headers
            .insert(headers::LOCATION, url.to_string().parse().unwrap());
    }
}

/// A modifier for creating redirect responses.
pub struct RedirectRaw(pub String);

impl Modifier<Response> for RedirectRaw {
    fn modify(self, res: &mut Response) {
        let RedirectRaw(path) = self;
        res.headers.insert(headers::LOCATION, path.parse().unwrap());
    }
}

fn mime_for_path(path: &Path) -> Mime {
    mime_guess::from_path(path).first().unwrap_or(mime::TEXT_PLAIN)
}

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

    #[test]
    fn test_mime_for_path() {
        assert_eq!(mime_for_path(Path::new("foo.txt")), mime::TEXT_PLAIN);
        assert_eq!(mime_for_path(Path::new("foo.jpg")), mime::IMAGE_JPEG);
        assert_eq!(
            mime_for_path(Path::new("foo.zip")),
            "application/zip".parse::<Mime>().unwrap()
        );
        assert_eq!(mime_for_path(Path::new("foo")), mime::TEXT_PLAIN);
    }
}
<commit_msg>(doc) Fixed modifiers remote link<commit_after>//! This module defines a series of convenience modifiers for changing
//! Responses.
//!
//! Modifiers can be used to edit `Response`s through the owning method `set`
//! or the mutating `set_mut`, both of which are defined in the `Set` trait.
//!
//! For Iron, the `Modifier` interface offers extensible and ergonomic response
//! creation while avoiding the introduction of many highly specific `Response`
//! constructors.
//!
//! The simplest case of a modifier is probably the one used to change the
//! return status code:
//!
//! ```
//! # use std::convert::Into;
//! # use iron::prelude::*;
//! # use iron::StatusCode;
//! let r = Response::with(StatusCode::NOT_FOUND);
//! assert_eq!(404 as u16, r.status.unwrap().as_u16());
//! ```
//!
//! You can also pass in a tuple of modifiers, they will all be applied. Here's
//! an example of a modifier 2-tuple that will change the status code and the
//! body message:
//!
//! ```
//! # use iron::prelude::*;
//! # use iron::StatusCode;
//! Response::with((StatusCode::IM_A_TEAPOT, "I am a tea pot!"));
//! ```
//!
//! There is also a `Redirect` modifier:
//!
//! ```
//! # use iron::prelude::*;
//! # use iron::StatusCode;
//! # use iron::modifiers;
//! # use iron::Url;
//! let url = Url::parse("http://doc.rust-lang.org").unwrap();
//! Response::with((StatusCode::FOUND, modifiers::Redirect(url)));
//! ```
//!
//! The modifiers are applied depending on their type. Currently the easiest
//! way to see how different types are used as modifiers, take a look at [the
//! source code](https://github.com/iron/iron/blob/master/iron/src/modifiers.rs).
//!
//! For more information about the modifier system, see
//! [rust-modifier](https://github.com/reem/rust-modifier).

use std::fs::File;
use std::io;
use std::path::{Path, PathBuf};

use modifier::Modifier;

use mime::{self, Mime};

use {headers, Request, Response, Set, StatusCode, Url};

use mime_guess;
use response::{BodyReader, WriteBody};

impl Modifier<Response> for Mime {
    #[inline]
    fn modify(self, res: &mut Response) {
        // Mime should always be parsable to a valid HeaderValue, so unwrap should be safe here.
        res.headers
            .insert(headers::CONTENT_TYPE, self.as_ref().parse().unwrap());
    }
}

impl Modifier<Response> for Box<dyn WriteBody> {
    #[inline]
    fn modify(self, res: &mut Response) {
        res.body = Some(self);
    }
}

impl<R: io::Read + Send + 'static> Modifier<Response> for BodyReader<R> {
    #[inline]
    fn modify(self, res: &mut Response) {
        res.body = Some(Box::new(self));
    }
}

impl Modifier<Response> for String {
    #[inline]
    fn modify(self, res: &mut Response) {
        self.into_bytes().modify(res);
    }
}

impl Modifier<Response> for Vec<u8> {
    #[inline]
    fn modify(self, res: &mut Response) {
        res.headers
            .insert(headers::CONTENT_LENGTH, (self.len() as u64).into());
        res.body = Some(Box::new(self));
    }
}

impl<'a> Modifier<Response> for &'a str {
    #[inline]
    fn modify(self, res: &mut Response) {
        self.to_owned().modify(res);
    }
}

impl<'a> Modifier<Response> for &'a [u8] {
    #[inline]
    fn modify(self, res: &mut Response) {
        self.to_vec().modify(res);
    }
}

impl Modifier<Response> for File {
    fn modify(self, res: &mut Response) {
        // Set the content type based on the file extension if a path is available.
        if let Ok(metadata) = self.metadata() {
            res.headers
                .insert(headers::CONTENT_LENGTH, metadata.len().into());
        }

        res.body = Some(Box::new(self));
    }
}

impl<'a> Modifier<Response> for &'a Path {
    /// Set the body to the contents of the File at this path.
    ///
    /// ## Panics
    ///
    /// Panics if there is no file at the passed-in Path.
    fn modify(self, res: &mut Response) {
        File::open(self)
            .unwrap_or_else(|_| panic!("No such file: {}", self.display()))
            .modify(res);

        let mime = mime_for_path(self);
        res.set_mut(mime);
    }
}

impl Modifier<Response> for PathBuf {
    /// Set the body to the contents of the File at this path.
    ///
    /// ## Panics
    ///
    /// Panics if there is no file at the passed-in Path.
    #[inline]
    fn modify(self, res: &mut Response) {
        self.as_path().modify(res);
    }
}

impl Modifier<Response> for StatusCode {
    fn modify(self, res: &mut Response) {
        res.status = Some(self);
    }
}

/// A modifier for changing headers on requests and responses.
#[derive(Clone)]
pub struct Header<H>(pub H, pub headers::HeaderValue);

impl<H> Modifier<Response> for Header<H>
where
    H: headers::IntoHeaderName,
{
    fn modify(self, res: &mut Response) {
        res.headers.insert(self.0, self.1);
    }
}

impl<H> Modifier<Request> for Header<H>
where
    H: headers::IntoHeaderName,
{
    fn modify(self, res: &mut Request) {
        res.headers.insert(self.0, self.1);
    }
}

/// A modifier for creating redirect responses.
pub struct Redirect(pub Url);

impl Modifier<Response> for Redirect {
    fn modify(self, res: &mut Response) {
        let Redirect(url) = self;
        // Url should always be parsable to a valid HeaderValue, so unwrap should be safe here.
        res.headers
            .insert(headers::LOCATION, url.to_string().parse().unwrap());
    }
}

/// A modifier for creating redirect responses.
pub struct RedirectRaw(pub String);

impl Modifier<Response> for RedirectRaw {
    fn modify(self, res: &mut Response) {
        let RedirectRaw(path) = self;
        res.headers.insert(headers::LOCATION, path.parse().unwrap());
    }
}

fn mime_for_path(path: &Path) -> Mime {
    mime_guess::from_path(path).first().unwrap_or(mime::TEXT_PLAIN)
}

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

    #[test]
    fn test_mime_for_path() {
        assert_eq!(mime_for_path(Path::new("foo.txt")), mime::TEXT_PLAIN);
        assert_eq!(mime_for_path(Path::new("foo.jpg")), mime::IMAGE_JPEG);
        assert_eq!(
            mime_for_path(Path::new("foo.zip")),
            "application/zip".parse::<Mime>().unwrap()
        );
        assert_eq!(mime_for_path(Path::new("foo")), mime::TEXT_PLAIN);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

#[feature(globs)];
#[feature(macro_rules)];

#[link(name = "capnproto-rust-benchmark", vers = "alpha", author = "dwrensha")];

#[crate_type = "bin"];

extern mod capnprust;

pub mod common;

pub mod carsales_capnp;
pub mod carsales;

pub mod catrank_capnp;
pub mod catrank;

pub mod eval_capnp;
pub mod eval;

macro_rules! passByObject(
    ( $testcase:ident, $iters:expr ) => ({
            let mut rng = ~common::FastRand::new();
            for _ in range(0, $iters) {
                let messageReq = capnprust::message::MessageBuilder::new_default();
                let messageRes = capnprust::message::MessageBuilder::new_default();

                let request = messageReq.initRoot::<$testcase::RequestBuilder>();
                let response = messageRes.initRoot::<$testcase::ResponseBuilder>();
                let expected = $testcase::setupRequest(rng, request);

                do request.asReader |requestReader| {
                    $testcase::handleRequest(requestReader, response);
                }

                do response.asReader |responseReader| {
                    if (! $testcase::checkResponse(responseReader, expected)) {
                        println("Incorrect response.");
                    }
                }

                messageReq.release();
                messageRes.release();
            }
        });
    )

pub fn main () {

    let args = std::os::args();

    if (args.len() != 5) {
        println!("USAGE: {} MODE REUSE COMPRESSION ITERATION_COUNT", args[0]);
        return;
    }

    let iters = match from_str::<u64>(args[4]) {
        Some (n) => n,
        None => {
            println!("Could not parse a u64 from: {}", args[4]);
            return;
        }
    };

/* TODO use std::run
    unsafe {
        let child = funcs::posix88::unistd::fork();
        if (child == 0 ) {
            printfln!("%s", "Hello world. I am the child and client.");
        } else {
            printfln!("%s", "Hello world. I am the parent and server.");
        }
    }
*/

//    passByObject!(catrank, iters);
    passByObject!(carsales, iters);
//    passByObject!(eval, iters);

}
<commit_msg>now you can specify the benchmark testcase on the command line<commit_after>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

#[feature(globs)];
#[feature(macro_rules)];

#[link(name = "capnproto-rust-benchmark", vers = "alpha", author = "dwrensha")];

#[crate_type = "bin"];

extern mod capnprust;

pub mod common;

pub mod carsales_capnp;
pub mod carsales;

pub mod catrank_capnp;
pub mod catrank;

pub mod eval_capnp;
pub mod eval;

macro_rules! passByObject(
    ( $testcase:ident, $iters:expr ) => ({
            let mut rng = ~common::FastRand::new();
            for _ in range(0, $iters) {
                let messageReq = capnprust::message::MessageBuilder::new_default();
                let messageRes = capnprust::message::MessageBuilder::new_default();

                let request = messageReq.initRoot::<$testcase::RequestBuilder>();
                let response = messageRes.initRoot::<$testcase::ResponseBuilder>();
                let expected = $testcase::setupRequest(rng, request);

                do request.asReader |requestReader| {
                    $testcase::handleRequest(requestReader, response);
                }

                do response.asReader |responseReader| {
                    if (! $testcase::checkResponse(responseReader, expected)) {
                        println("Incorrect response.");
                    }
                }

                messageReq.release();
                messageRes.release();
            }
        });
    )

macro_rules! doTestcase(
    ( $testcase:ident, $mode:expr, $reuse:expr, $compression:expr, $iters:expr ) => ({
            match $mode {
                ~"object" => passByObject!($testcase, $iters),
                s => fail!("unrecognized mode: {}", s)
            }
        });
    )

pub fn main () {

    let args = std::os::args();

    if (args.len() != 6) {
        println!("USAGE: {} CASE MODE REUSE COMPRESSION ITERATION_COUNT", args[0]);
        return;
    }

    let iters = match from_str::<u64>(args[5]) {
        Some (n) => n,
        None => {
            println!("Could not parse a u64 from: {}", args[5]);
            return;
        }
    };

/* TODO use std::run
    unsafe {
        let child = funcs::posix88::unistd::fork();
        if (child == 0 ) {
            printfln!("%s", "Hello world. I am the child and client.");
        } else {
            printfln!("%s", "Hello world. I am the parent and server.");
        }
    }
*/

    match args[1] {
        ~"carsales" => doTestcase!(carsales, args[2], args[3], args[4], iters),
        ~"catrank" => doTestcase!(catrank, args[2], args[3], args[4], iters),
        ~"eval" => doTestcase!(eval, args[2], args[3], args[4], iters),
        s => fail!("unrecognized test case: {}", s)
    }

}
<|endoftext|>