<commit_before>/*!
    Designates a control consisting of a list box and a selection field similar to an edit control.
*/
use std::hash::Hash;
use std::mem;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;

use controls::ControlTemplate;
use controls::base::{WindowBase, create_base, set_window_text, get_window_text,
 get_window_pos, set_window_pos, get_window_size, set_window_size, get_window_parent,
 set_window_parent, get_window_enabled, set_window_enabled, get_window_visibility,
 set_window_visibility, send_message, to_utf16_ref};
use actions::{Action, ActionReturn};
use constants::{CBS_AUTOHSCROLL, CBS_DROPDOWNLIST, CBS_HASSTRINGS, Error, CB_ERR, CBS_SORT};
use events::Event;

use winapi::{HWND, BS_NOTIFY, CB_RESETCONTENT, CB_ADDSTRING, CB_DELETESTRING,
 CB_FINDSTRINGEXACT, CB_GETCOUNT, CB_GETCURSEL, CB_SETCURSEL, LPARAM, WPARAM,
 CB_SHOWDROPDOWN, CB_GETDROPPEDSTATE, CB_GETLBTEXT, CB_GETLBTEXTLEN};

/**
    Configuration properties to create simple button

    * size: The button size (width, height) in pixels
    * position: The button position (x, y) in the parent control
    * parent: The control parent
    * collection: List of combobox choice
*/
pub struct ComboBox<ID: Eq+Clone+Hash> {
    pub size: (u32, u32),
    pub position: (i32, i32),
    pub parent: ID,
    pub collection: Vec<String>,
    pub sorted: bool
}

impl<ID: Eq+Clone+Hash > ControlTemplate<ID> for ComboBox<ID> {

    fn create(&self, ui: &mut ::Ui<ID>, id: ID) -> Result<HWND, ()> {
        let sorted = if self.sorted { CBS_SORT } else { 0 };

        let base = WindowBase::<ID> {
            text: "".to_string(),
            size: self.size.clone(),
            position: self.position.clone(),
            visible: true,
            resizable: false,
            extra_style: BS_NOTIFY | CBS_AUTOHSCROLL | CBS_DROPDOWNLIST | CBS_HASSTRINGS | sorted,
            class: Some("COMBOBOX".to_string()),
            parent: Some(self.parent.clone())
        };

        let handle = unsafe { create_base::<ID>(ui, base) };

        match handle {
            Ok(h) => {
                 for i in self.collection.iter() {
                    add_string_item::<ID>(h, i);
                 }
                 Ok(h)
            }
            e => e
        }
    }

    fn supported_events(&self) -> Vec<Event> {
        vec![Event::Focus, Event::MouseUp, Event::MouseDown, Event::Removed]
    }

    fn evaluator(&self) -> ::ActionEvaluator<ID> {
        Box::new( |ui, id, handle, action| {
            match action {
                Action::SetText(t) => set_window_text(handle, *t),
                Action::GetText => get_window_text(handle),
                Action::GetPosition => get_window_pos(handle, true),
                Action::SetPosition(x, y) => set_window_pos(handle, x, y),
                Action::GetSize => get_window_size(handle),
                Action::SetSize(w, h) => set_window_size(handle, w, h),
                Action::GetParent => get_window_parent(handle),
                Action::SetParent(p) => set_window_parent(ui, handle, *p, true),
                Action::GetEnabled => get_window_enabled(handle),
                Action::SetEnabled(e) => set_window_enabled(handle, e),
                Action::GetVisibility => get_window_visibility(handle),
                Action::SetVisibility(v) => set_window_visibility(handle, v),
                Action::GetSelectedIndex => get_selected_index(handle),
                Action::SetSelectedIndex(i) => set_selected_index(handle, i),
                Action::Reset => reset_combobox(handle),

                Action::GetDropdownVisibility => get_combobox_dropdown_visibility(handle),
                Action::SetDropdownVisibility(s) => show_combobox_dropdown(handle, s),

                Action::AddString(s) => add_string_item(handle, s.as_ref()),
                Action::FindString(s) => find_string_item(handle, s.as_ref()),
                Action::RemoveString(s) => remove_string_item(handle, s.as_ref()),
                Action::GetStringCollection => get_collection(handle),
                Action::SetStringCollection(c) => set_collection(handle, *c),

                Action::GetIndexedItem(i) => get_item(handle, i),
                Action::RemoveIndexedItem(i) => remove_item(handle, i),
                Action::CountItems => count_item(handle),

                _ => ActionReturn::NotSupported
            }
        })
    }

}

#[inline(always)]
fn reset_combobox<ID: Eq+Clone+Hash>(handle: HWND) -> ActionReturn<ID> {
    send_message(handle, CB_RESETCONTENT, 0, 0);
    ActionReturn::None
}

/**
    Add a string to a combobox
*/
#[inline(always)]
fn add_string_item<ID: Eq+Clone+Hash >(handle: HWND, item: &String) -> ActionReturn<ID> {
    let item_vec = to_utf16_ref(item);
    let item_vec_ptr: LPARAM = unsafe { mem::transmute(item_vec.as_ptr()) };
    send_message(handle, CB_ADDSTRING, 0, item_vec_ptr);
    ActionReturn::None
}

/**
    Return the string at index `i` in the combobox dropdown
*/
#[inline(always)]
fn get_item<ID: Eq+Clone+Hash>(handle: HWND, i: u32) -> ActionReturn<ID> {
    let buffer_len: usize;
    let mut buffer: Vec<u16>;
    let buffer_addr: LPARAM;

    buffer_len = send_message(handle, CB_GETLBTEXTLEN, i as WPARAM, 0) as usize;
    if buffer_len == (CB_ERR as usize) {
        return ActionReturn::Error(Error::INDEX_OUT_OF_BOUNDS)
    }

    buffer = Vec::with_capacity(buffer_len);
    unsafe{
        buffer.set_len(buffer_len);
        buffer_addr = mem::transmute(buffer.as_mut_ptr());
    }

    if send_message(handle, CB_GETLBTEXT, i as WPARAM, buffer_addr) != CB_ERR {
        let text = OsString::from_wide(&(buffer.as_slice()));
        let text = text.into_string().unwrap_or("ERROR!".to_string());

        ActionReturn::Text(Box::new(text))
    } else {
        ActionReturn::Error(Error::UNKNOWN)
    }
}

/**
    Remove an item from a list by using its index as reference
*/
#[inline(always)]
fn remove_item<ID: Eq+Clone+Hash >(handle: HWND, index: u32) -> ActionReturn<ID> {
    if send_message(handle, CB_DELETESTRING, index as WPARAM, 0) != CB_ERR {
        ActionReturn::None
    } else {
        ActionReturn::Error(Error::INDEX_OUT_OF_BOUNDS)
    }
}

/**
    Find the index of a string item in a combobox
*/
#[inline(always)]
fn find_string_item<ID: Eq+Clone+Hash >(handle: HWND, s: &String) -> ActionReturn<ID> {
    let item_vec = to_utf16_ref(s);
    let item_vec_ptr: LPARAM = unsafe { mem::transmute(item_vec.as_ptr()) };
    let index = send_message(handle, CB_FINDSTRINGEXACT, 0, item_vec_ptr);
    if index != CB_ERR {
        ActionReturn::ItemIndex(index as u32)
    } else {
        ActionReturn::Error(Error::ITEM_NOT_FOUND)
    }
}

/**
    Remove a string from a combobox
*/
#[inline(always)]
fn remove_string_item<ID: Eq+Clone+Hash >(handle: HWND, s: &String) -> ActionReturn<ID> {
    let item_vec = to_utf16_ref(s);
    let item_vec_ptr: LPARAM = unsafe { mem::transmute(item_vec.as_ptr()) };
    let index = send_message(handle, CB_FINDSTRINGEXACT, 0, item_vec_ptr);
    if index != CB_ERR {
        send_message(handle, CB_DELETESTRING, index as WPARAM, 0);
        ActionReturn::None
    } else {
        ActionReturn::Error(Error::ITEM_NOT_FOUND)
    }
}

/**
    Count the number of item in a combobox
*/
#[inline(always)]
fn count_item<ID: Eq+Clone+Hash >(handle: HWND) -> ActionReturn<ID> {
    let count = send_message(handle, CB_GETCOUNT, 0, 0);
    if count != CB_ERR {
        ActionReturn::ItemCount(count as u32)
    } else {
        ActionReturn::Error(Error::UNKNOWN)
    }
}

/**
    Return the index of the selected item in a combobox
*/
#[inline(always)]
fn get_selected_index<ID: Eq+Clone+Hash >(handle: HWND) -> ActionReturn<ID> {
    let selected = send_message(handle, CB_GETCURSEL, 0, 0);
    if selected != CB_ERR {
        ActionReturn::ItemIndex(selected as u32)
    } else {
        ActionReturn::None
    }
}

/**
    Set the selected index in a combobox
    TODO maybe add some validation to check if index is out of bounds as it currently clear the box
    as if None was passed
*/
#[inline(always)]
fn set_selected_index<ID: Eq+Clone+Hash>(handle: HWND, index: Option<u32>) -> ActionReturn<ID> {
    if let Some(i) = index {
        let result = send_message(handle, CB_SETCURSEL, i as WPARAM, 0);
        if result != CB_ERR {
            ActionReturn::None
        } else {
            ActionReturn::Error(Error::INDEX_OUT_OF_BOUNDS)
        }
    } else {
        send_message(handle, CB_SETCURSEL, !0, 0);
        ActionReturn::None
    }
}

/**
    Set the visibility of the combobox dropdown
*/
#[inline(always)]
fn show_combobox_dropdown<ID: Eq+Clone+Hash>(handle: HWND, show: bool) -> ActionReturn<ID> {
    send_message(handle, CB_SHOWDROPDOWN, show as WPARAM, 0);
    ActionReturn::None
}

/**
    Get the visibility of a combobox dropdown
*/
#[inline(always)]
fn get_combobox_dropdown_visibility<ID: Eq+Clone+Hash>(handle: HWND) -> ActionReturn<ID> {
    ActionReturn::Visibility(send_message(handle, CB_GETDROPPEDSTATE, 0, 0) == 1)
}

/**
    Return every item contained in the combobox list
*/
#[inline(always)]
fn get_collection<ID: Eq+Clone+Hash>(handle: HWND) -> ActionReturn<ID> {
    let item_count: usize;
    let mut buffer_length: usize = 0;
    let mut buffer: Vec<u16>;
    let buffer_addr: LPARAM;
    let mut collection: Vec<String>;

    if let ActionReturn::ItemCount(c) = count_item::<ID>(handle) {
        item_count = c as usize;
    } else {
        return ActionReturn::Error(Error::UNKNOWN);
    }

    // If there are no items, return an empty vector
    if item_count == 0 { return ActionReturn::StringCollection(Box::new(Vec::new())); }

    // Get the length of the biggest string in the combobox
    for i in 0..(item_count as u32) {
        let size = send_message(handle, CB_GETLBTEXTLEN, i as WPARAM, 0) as usize;
        if size > buffer_length {
            buffer_length = size;
        }
    }

    // Create the buffer
    buffer = Vec::with_capacity(buffer_length);
    unsafe {
        buffer.set_len(buffer_length);
        buffer_addr = mem::transmute(buffer.as_mut_ptr());
    }

    // Unpack the items in the collection
    collection = Vec::with_capacity(item_count);
    for i in 0..item_count {
        if send_message(handle, CB_GETLBTEXT, i as WPARAM, buffer_addr) != CB_ERR {
            let end_index = buffer.iter().enumerate().find(|&(index, i)| *i == 0).unwrap_or((buffer_length, &0)).0;
            let text = OsString::from_wide(&(buffer.as_slice()[0..end_index]));
            let text = text.into_string().unwrap_or("ERROR!".to_string());

            collection.push(text);
        }
    }

    ActionReturn::StringCollection(Box::new(collection))
}

/**
    Set the collection in the combobox list
*/
fn set_collection<ID: Eq+Clone+Hash>(handle: HWND, new_col: Vec<String>) -> ActionReturn<ID> {
    ActionReturn::None
}<commit_msg>set string collection<commit_after>/*!
    Designates a control consisting of a list box and a selection field similar to an edit control.
*/
use std::hash::Hash;
use std::mem;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;

use controls::ControlTemplate;
use controls::base::{WindowBase, create_base, set_window_text, get_window_text,
 get_window_pos, set_window_pos, get_window_size, set_window_size, get_window_parent,
 set_window_parent, get_window_enabled, set_window_enabled, get_window_visibility,
 set_window_visibility, send_message, to_utf16_ref};
use actions::{Action, ActionReturn};
use constants::{CBS_AUTOHSCROLL, CBS_DROPDOWNLIST, CBS_HASSTRINGS, Error, CB_ERR, CBS_SORT};
use events::Event;

use winapi::{HWND, BS_NOTIFY, CB_RESETCONTENT, CB_ADDSTRING, CB_DELETESTRING,
 CB_FINDSTRINGEXACT, CB_GETCOUNT, CB_GETCURSEL, CB_SETCURSEL, LPARAM, WPARAM,
 CB_SHOWDROPDOWN, CB_GETDROPPEDSTATE, CB_GETLBTEXT, CB_GETLBTEXTLEN};

/**
    Configuration properties to create simple button

    * size: The button size (width, height) in pixels
    * position: The button position (x, y) in the parent control
    * parent: The control parent
    * collection: List of combobox choice
*/
pub struct ComboBox<ID: Eq+Clone+Hash> {
    pub size: (u32, u32),
    pub position: (i32, i32),
    pub parent: ID,
    pub collection: Vec<String>,
    pub sorted: bool
}

impl<ID: Eq+Clone+Hash > ControlTemplate<ID> for ComboBox<ID> {

    fn create(&self, ui: &mut ::Ui<ID>, id: ID) -> Result<HWND, ()> {
        let sorted = if self.sorted { CBS_SORT } else { 0 };

        let base = WindowBase::<ID> {
            text: "".to_string(),
            size: self.size.clone(),
            position: self.position.clone(),
            visible: true,
            resizable: false,
            extra_style: BS_NOTIFY | CBS_AUTOHSCROLL | CBS_DROPDOWNLIST | CBS_HASSTRINGS | sorted,
            class: Some("COMBOBOX".to_string()),
            parent: Some(self.parent.clone())
        };

        let handle = unsafe { create_base::<ID>(ui, base) };

        match handle {
            Ok(h) => {
                 set_collection::<ID>(h, &self.collection);
                 Ok(h)
            }
            e => e
        }
    }

    fn supported_events(&self) -> Vec<Event> {
        vec![Event::Focus, Event::MouseUp, Event::MouseDown, Event::Removed]
    }

    fn evaluator(&self) -> ::ActionEvaluator<ID> {
        Box::new( |ui, id, handle, action| {
            match action {
                Action::SetText(t) => set_window_text(handle, *t),
                Action::GetText => get_window_text(handle),
                Action::GetPosition => get_window_pos(handle, true),
                Action::SetPosition(x, y) => set_window_pos(handle, x, y),
                Action::GetSize => get_window_size(handle),
                Action::SetSize(w, h) => set_window_size(handle, w, h),
                Action::GetParent => get_window_parent(handle),
                Action::SetParent(p) => set_window_parent(ui, handle, *p, true),
                Action::GetEnabled => get_window_enabled(handle),
                Action::SetEnabled(e) => set_window_enabled(handle, e),
                Action::GetVisibility => get_window_visibility(handle),
                Action::SetVisibility(v) => set_window_visibility(handle, v),
                Action::GetSelectedIndex => get_selected_index(handle),
                Action::SetSelectedIndex(i) => set_selected_index(handle, i),
                Action::Reset => reset_combobox(handle),

                Action::GetDropdownVisibility => get_combobox_dropdown_visibility(handle),
                Action::SetDropdownVisibility(s) => show_combobox_dropdown(handle, s),

                Action::AddString(s) => add_string_item(handle, s.as_ref()),
                Action::FindString(s) => find_string_item(handle, s.as_ref()),
                Action::RemoveString(s) => remove_string_item(handle, s.as_ref()),
                Action::GetStringCollection => get_collection(handle),
                Action::SetStringCollection(c) => set_collection(handle, c.as_ref()),

                Action::GetIndexedItem(i) => get_item(handle, i),
                Action::RemoveIndexedItem(i) => remove_item(handle, i),
                Action::CountItems => count_item(handle),

                _ => ActionReturn::NotSupported
            }
        })
    }

}

#[inline(always)]
fn reset_combobox<ID: Eq+Clone+Hash>(handle: HWND) -> ActionReturn<ID> {
    send_message(handle, CB_RESETCONTENT, 0, 0);
    ActionReturn::None
}

/**
    Add a string to a combobox
*/
#[inline(always)]
fn add_string_item<ID: Eq+Clone+Hash >(handle: HWND, item: &String) -> ActionReturn<ID> {
    let item_vec = to_utf16_ref(item);
    let item_vec_ptr: LPARAM = unsafe { mem::transmute(item_vec.as_ptr()) };
    send_message(handle, CB_ADDSTRING, 0, item_vec_ptr);
    ActionReturn::None
}

/**
    Return the string at index `i` in the combobox dropdown
*/
#[inline(always)]
fn get_item<ID: Eq+Clone+Hash>(handle: HWND, i: u32) -> ActionReturn<ID> {
    let buffer_len: usize;
    let mut buffer: Vec<u16>;
    let buffer_addr: LPARAM;

    buffer_len = send_message(handle, CB_GETLBTEXTLEN, i as WPARAM, 0) as usize;
    if buffer_len == (CB_ERR as usize) {
        return ActionReturn::Error(Error::INDEX_OUT_OF_BOUNDS)
    }

    buffer = Vec::with_capacity(buffer_len);
    unsafe{
        buffer.set_len(buffer_len);
        buffer_addr = mem::transmute(buffer.as_mut_ptr());
    }

    if send_message(handle, CB_GETLBTEXT, i as WPARAM, buffer_addr) != CB_ERR {
        let text = OsString::from_wide(&(buffer.as_slice()));
        let text = text.into_string().unwrap_or("ERROR!".to_string());

        ActionReturn::Text(Box::new(text))
    } else {
        ActionReturn::Error(Error::UNKNOWN)
    }
}

/**
    Remove an item from a list by using its index as reference
*/
#[inline(always)]
fn remove_item<ID: Eq+Clone+Hash >(handle: HWND, index: u32) -> ActionReturn<ID> {
    if send_message(handle, CB_DELETESTRING, index as WPARAM, 0) != CB_ERR {
        ActionReturn::None
    } else {
        ActionReturn::Error(Error::INDEX_OUT_OF_BOUNDS)
    }
}

/**
    Find the index of a string item in a combobox
*/
#[inline(always)]
fn find_string_item<ID: Eq+Clone+Hash >(handle: HWND, s: &String) -> ActionReturn<ID> {
    let item_vec = to_utf16_ref(s);
    let item_vec_ptr: LPARAM = unsafe { mem::transmute(item_vec.as_ptr()) };
    let index = send_message(handle, CB_FINDSTRINGEXACT, 0, item_vec_ptr);
    if index != CB_ERR {
        ActionReturn::ItemIndex(index as u32)
    } else {
        ActionReturn::Error(Error::ITEM_NOT_FOUND)
    }
}

/**
    Remove a string from a combobox
*/
#[inline(always)]
fn remove_string_item<ID: Eq+Clone+Hash >(handle: HWND, s: &String) -> ActionReturn<ID> {
    let item_vec = to_utf16_ref(s);
    let item_vec_ptr: LPARAM = unsafe { mem::transmute(item_vec.as_ptr()) };
    let index = send_message(handle, CB_FINDSTRINGEXACT, 0, item_vec_ptr);
    if index != CB_ERR {
        send_message(handle, CB_DELETESTRING, index as WPARAM, 0);
        ActionReturn::None
    } else {
        ActionReturn::Error(Error::ITEM_NOT_FOUND)
    }
}

/**
    Count the number of item in a combobox
*/
#[inline(always)]
fn count_item<ID: Eq+Clone+Hash >(handle: HWND) -> ActionReturn<ID> {
    let count = send_message(handle, CB_GETCOUNT, 0, 0);
    if count != CB_ERR {
        ActionReturn::ItemCount(count as u32)
    } else {
        ActionReturn::Error(Error::UNKNOWN)
    }
}

/**
    Return the index of the selected item in a combobox
*/
#[inline(always)]
fn get_selected_index<ID: Eq+Clone+Hash >(handle: HWND) -> ActionReturn<ID> {
    let selected = send_message(handle, CB_GETCURSEL, 0, 0);
    if selected != CB_ERR {
        ActionReturn::ItemIndex(selected as u32)
    } else {
        ActionReturn::None
    }
}

/**
    Set the selected index in a combobox
    TODO maybe add some validation to check if index is out of bounds as it currently clear the box
    as if None was passed
*/
#[inline(always)]
fn set_selected_index<ID: Eq+Clone+Hash>(handle: HWND, index: Option<u32>) -> ActionReturn<ID> {
    if let Some(i) = index {
        let result = send_message(handle, CB_SETCURSEL, i as WPARAM, 0);
        if result != CB_ERR {
            ActionReturn::None
        } else {
            ActionReturn::Error(Error::INDEX_OUT_OF_BOUNDS)
        }
    } else {
        send_message(handle, CB_SETCURSEL, !0, 0);
        ActionReturn::None
    }
}

/**
    Set the visibility of the combobox dropdown
*/
#[inline(always)]
fn show_combobox_dropdown<ID: Eq+Clone+Hash>(handle: HWND, show: bool) -> ActionReturn<ID> {
    send_message(handle, CB_SHOWDROPDOWN, show as WPARAM, 0);
    ActionReturn::None
}

/**
    Get the visibility of a combobox dropdown
*/
#[inline(always)]
fn get_combobox_dropdown_visibility<ID: Eq+Clone+Hash>(handle: HWND) -> ActionReturn<ID> {
    ActionReturn::Visibility(send_message(handle, CB_GETDROPPEDSTATE, 0, 0) == 1)
}

/**
    Return every item contained in the combobox list
*/
#[inline(always)]
fn get_collection<ID: Eq+Clone+Hash>(handle: HWND) -> ActionReturn<ID> {
    let item_count: usize;
    let mut buffer_length: usize = 0;
    let mut buffer: Vec<u16>;
    let buffer_addr: LPARAM;
    let mut collection: Vec<String>;

    if let ActionReturn::ItemCount(c) = count_item::<ID>(handle) {
        item_count = c as usize;
    } else {
        return ActionReturn::Error(Error::UNKNOWN);
    }

    // If there are no items, return an empty vector
    if item_count == 0 { return ActionReturn::StringCollection(Box::new(Vec::new())); }

    // Get the length of the biggest string in the combobox
    for i in 0..(item_count as WPARAM) {
        let size = send_message(handle, CB_GETLBTEXTLEN, i, 0) as usize;
        if size > buffer_length {
            buffer_length = size;
        }
    }

    // Create the buffer
    buffer = Vec::with_capacity(buffer_length);
    unsafe {
        buffer.set_len(buffer_length);
        buffer_addr = mem::transmute(buffer.as_mut_ptr());
    }

    // Unpack the items in the collection
    collection = Vec::with_capacity(item_count);
    for i in 0..(item_count as WPARAM) {
        if send_message(handle, CB_GETLBTEXT, i, buffer_addr) != CB_ERR {
            let end_index = buffer.iter().enumerate().find(|&(index, i)| *i == 0).unwrap_or((buffer_length, &0)).0;
            let text = OsString::from_wide(&(buffer.as_slice()[0..end_index]));
            let text = text.into_string().unwrap_or("ERROR!".to_string());

            collection.push(text);
        }
    }

    ActionReturn::StringCollection(Box::new(collection))
}

/**
    Set the collection in the combobox list
*/
fn set_collection<ID: Eq+Clone+Hash>(handle: HWND, collection: &Vec<String>) -> ActionReturn<ID> {
    reset_combobox::<ID>(handle);
    for i in collection.iter() {
        add_string_item::<ID>(handle, i);
    }

    ActionReturn::None
}<|endoftext|>


<commit_before>use std::error::Error;
use std::str::FromStr;

pub fn puzzle(input: &str) -> i32 {
    for line in input.lines() {
        let line = line.trim();
    }
    0
}

#[derive(Debug, PartialEq)]
pub enum Instruction {
    Copy(FromLocation, Register),
}

impl FromStr for Instruction {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut parts = s.split_whitespace();
        match parts.next() {
            Some("cpy") => Ok(
                Instruction::Copy(
                    parts.next().ok_or("no from location")?.parse()?,
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            _ => unimplemented!(),
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum FromLocation {
    Integer(i32),
    Register(Register),
}

impl FromStr for FromLocation {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        s.parse().map(FromLocation::Integer)
                 .or_else(|_| s.parse().map(FromLocation::Register))
    }
}

#[derive(Debug, PartialEq)]
pub enum Register {
    A,
    B,
    C,
    D,
}

impl FromStr for Register {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Register::*;
        match s {
            "a" => Ok(A),
            "b" => Ok(B),
            "c" => Ok(C),
            "d" => Ok(D),
            other => Err(format!("Unknown register {}", other).into()),
        }
    }
}

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

    #[test]
    fn parse_cpy() {
        let instr: Instruction = "cpy 41 a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Copy(FromLocation::Integer(41), Register::A)
        );
    }

    #[test]
    fn parse_cpy_register() {
        let instr: Instruction = "cpy a c".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Copy(
                FromLocation::Register(Register::A),
                Register::C,
            )
        );
    }

    #[test]
    fn sample() {
        let input = "cpy 41 a
            inc a
            inc a
            dec a
            jnz a 2
            dec a";
        assert_eq!(puzzle(input), 42);
    }
}
<commit_msg>Parse increment<commit_after>use std::error::Error;
use std::str::FromStr;

pub fn puzzle(input: &str) -> i32 {
    for line in input.lines() {
        let line = line.trim();
    }
    0
}

#[derive(Debug, PartialEq)]
pub enum Instruction {
    Copy(FromLocation, Register),
    Increment(Register),
}

impl FromStr for Instruction {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut parts = s.split_whitespace();
        match parts.next() {
            Some("cpy") => Ok(
                Instruction::Copy(
                    parts.next().ok_or("no from location")?.parse()?,
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            Some("inc") => Ok(
                Instruction::Increment(
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            _ => unimplemented!(),
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum FromLocation {
    Integer(i32),
    Register(Register),
}

impl FromStr for FromLocation {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        s.parse().map(FromLocation::Integer)
                 .or_else(|_| s.parse().map(FromLocation::Register))
    }
}

#[derive(Debug, PartialEq)]
pub enum Register {
    A,
    B,
    C,
    D,
}

impl FromStr for Register {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Register::*;
        match s {
            "a" => Ok(A),
            "b" => Ok(B),
            "c" => Ok(C),
            "d" => Ok(D),
            other => Err(format!("Unknown register {}", other).into()),
        }
    }
}

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

    #[test]
    fn parse_cpy() {
        let instr: Instruction = "cpy 41 a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Copy(FromLocation::Integer(41), Register::A)
        );
    }

    #[test]
    fn parse_cpy_register() {
        let instr: Instruction = "cpy a c".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Copy(
                FromLocation::Register(Register::A),
                Register::C,
            )
        );
    }

    #[test]
    fn parse_inc() {
        let instr: Instruction = "inc a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Increment(Register::A)
        );
    }

    #[test]
    fn sample() {
        let input = "cpy 41 a
            inc a
            inc a
            dec a
            jnz a 2
            dec a";
        assert_eq!(puzzle(input), 42);
    }
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]
extern crate libc;
use self::libc::{c_char, size_t, uint8_t, uint16_t, uint32_t, uint64_t};

pub type SkBool = ::libc::c_uint;

/* ATA SMART test type (ATA8 7.52.5.2) */
#[repr(C)]
#[derive(Debug)]
pub enum SkSmartSelfTest {
    SK_SMART_SELF_TEST_SHORT = 1,
    SK_SMART_SELF_TEST_EXTENDED = 2,
    SK_SMART_SELF_TEST_CONVEYANCE = 3,
    SK_SMART_SELF_TEST_ABORT = 127
}

#[repr(C)]
pub struct SkIdentifyParsedData {
    pub serial: [c_char; 21],
    pub firmware: [c_char; 9],
    pub model: [c_char; 41],
}

#[repr(C)]
#[derive(Debug)]
pub enum SkSmartOfflineDataCollectionStatus {
    SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_NEVER,
    SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_SUCCESS,
    SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_INPROGRESS,
    SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_SUSPENDED,
    SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_ABORTED,
    SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_FATAL,
    SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_UNKNOWN,
    _SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_MAX
}

#[repr(C)]
#[derive(Debug)]
pub enum SkSmartSelfTestExecutionStatus {
    SK_SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER = 0,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_ABORTED = 1,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED = 2,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_FATAL = 3,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN = 4,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL = 5,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO = 6,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ = 7,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING = 8,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS = 15,
    _SK_SMART_SELF_TEST_EXECUTION_STATUS_MAX
}

#[repr(C)]
#[derive(Debug)]
pub struct SkSmartParsedData {
    /* Volatile data */
    pub offline_data_collection_status: SkSmartOfflineDataCollectionStatus ,
    pub total_offline_data_collection_seconds: uint32_t,
    pub self_test_execution_status: SkSmartSelfTestExecutionStatus,
    pub self_test_execution_percent_remaining: uint32_t,

    /* Fixed data */
    pub short_and_extended_test_available: SkBool,
    pub conveyance_test_available: SkBool,
    pub start_test_available: SkBool,
    pub abort_test_available: SkBool,

    pub short_test_polling_minutes: uint32_t,
    pub extended_test_polling_minutes: uint32_t,
    pub conveyance_test_polling_minutes: uint32_t,
}

#[repr(C)]
#[derive(Debug)]
pub enum SkSmartAttributeUnit {
    SK_SMART_ATTRIBUTE_UNIT_UNKNOWN,
    SK_SMART_ATTRIBUTE_UNIT_NONE,
    SK_SMART_ATTRIBUTE_UNIT_MSECONDS,      /* milliseconds */
    SK_SMART_ATTRIBUTE_UNIT_SECTORS,
    SK_SMART_ATTRIBUTE_UNIT_MKELVIN,       /* millikelvin */
    SK_SMART_ATTRIBUTE_UNIT_SMALL_PERCENT, /* percentage with 3 decimal points */
    SK_SMART_ATTRIBUTE_UNIT_PERCENT,       /* integer percentage */
    SK_SMART_ATTRIBUTE_UNIT_MB,
    _SK_SMART_ATTRIBUTE_UNIT_MAX

}

#[repr(C)]
#[derive(Debug)]
pub struct SkSmartAttributeParsedData {
    pub id: uint8_t,
    pub name: *const ::libc::c_char,
    pub pretty_unit: SkSmartAttributeUnit,
    pub flags: uint16_t ,
    pub threshold: uint8_t,
    pub threshold_valid: SkBool,
    pub online: SkBool,
    pub prefailure: SkBool,
    pub good_now: SkBool,
    pub good_now_valid: SkBool,
    pub good_in_the_past: SkBool,
    pub good_in_the_past_valid: SkBool,
    pub current_value_valid: SkBool,
    pub worst_value_valid: SkBool,
    pub warn: SkBool,
    pub current_value: uint8_t,
    pub worst_value: uint8_t,
    pub pretty_value: uint64_t,
    pub raw: [uint8_t; 6],
}

pub enum SkDisk{

}

#[repr(C)]
#[derive(Debug)]
pub enum SkSmartOverall  {
    SK_SMART_OVERALL_GOOD,
    SK_SMART_OVERALL_BAD_ATTRIBUTE_IN_THE_PAST,  /* At least one pre-fail attribute exceeded its threshold in the past */
    SK_SMART_OVERALL_BAD_SECTOR,                 /* At least one bad sector */
    SK_SMART_OVERALL_BAD_ATTRIBUTE_NOW,          /* At least one pre-fail attribute is exceeding its threshold now */
    SK_SMART_OVERALL_BAD_SECTOR_MANY,            /* Many bad sectors */
    SK_SMART_OVERALL_BAD_STATUS,                 /* Smart Self Assessment negative */
    SK_SMART_OVERALL_MAX
}

#[link(name = "atasmart")]
extern "C" {
    pub fn sk_smart_self_test_execution_status_to_string(status: SkSmartSelfTestExecutionStatus) -> *const ::libc::c_char;
    pub fn sk_smart_offline_data_collection_status_to_string(status: SkSmartOfflineDataCollectionStatus) -> *const ::libc::c_char;
    pub fn sk_smart_self_test_to_string(test: SkSmartSelfTest) -> *const ::libc::c_char;
    pub fn sk_smart_self_test_available(d: *const SkSmartParsedData, test: SkSmartSelfTest) -> SkBool;
    pub fn sk_smart_self_test_polling_minutes(d: *const SkSmartParsedData, test: SkSmartSelfTest) -> uint32_t;
    pub fn sk_smart_attribute_unit_to_string(unit: SkSmartAttributeUnit) -> *const ::libc::c_char;
    pub fn sk_smart_overall_to_string(overall: SkSmartOverall) -> *const ::libc::c_char;
    pub fn sk_disk_open(name: *const ::libc::c_char, d: *mut *mut SkDisk) -> ::libc::c_int;
    pub fn sk_disk_get_size(d: *mut SkDisk, bytes: *mut uint64_t) -> ::libc::c_int;
    pub fn sk_disk_check_sleep_mode(d: *mut SkDisk, awake: *mut SkBool) -> ::libc::c_int;
    pub fn sk_disk_identify_is_available(d: *mut SkDisk, available: *mut SkBool) -> ::libc::c_int;
    pub fn sk_disk_identify_parse(d: *mut *mut SkDisk, data: *const SkIdentifyParsedData) -> ::libc::c_int;
    pub fn sk_disk_smart_is_available(d: *mut SkDisk, available: *mut SkBool) -> ::libc::c_int;
    pub fn sk_disk_smart_status(d: *mut SkDisk, good: *mut SkBool) -> ::libc::c_int;
    pub fn sk_disk_smart_read_data(d: *mut SkDisk) -> ::libc::c_int;
    pub fn sk_disk_get_blob(d: *mut *mut SkDisk, blob: *const ::libc::c_void, size: *mut size_t) -> ::libc::c_int;
    pub fn sk_disk_set_blob(d: *mut SkDisk, blob: *const ::libc::c_void, size: size_t) -> ::libc::c_int;
    pub fn sk_disk_smart_parse(d: *mut *mut SkDisk, data: *const SkSmartParsedData) -> ::libc::c_int;
    //pub fn sk_disk_smart_parse_attributes(d: *mut SkDisk, cb: SkSmartAttributeParseCallback, userdata: *mut ::libc::c_void) -> ::libc::c_int;
    pub fn sk_disk_smart_self_test(d: *mut SkDisk, test: SkSmartSelfTest) -> ::libc::c_int;
    pub fn sk_disk_smart_get_power_on(d: *mut SkDisk, mseconds: *mut uint64_t) -> ::libc::c_int;
    pub fn sk_disk_smart_get_power_cycle(d: *mut SkDisk, count: *mut uint64_t) -> ::libc::c_int;
    pub fn sk_disk_smart_get_bad(d: *mut SkDisk, sectors: *mut uint64_t) -> ::libc::c_int;
    pub fn sk_disk_smart_get_temperature(d: *mut SkDisk, mkelvin: *mut uint64_t ) -> ::libc::c_int;
    pub fn sk_disk_smart_get_overall(d: *mut SkDisk, overall: *mut SkSmartOverall) -> ::libc::c_int;
    pub fn sk_disk_dump(d: *mut SkDisk) -> ::libc::c_int;
    pub fn sk_disk_free(d: *mut SkDisk) -> ::libc::c_void;
}
<commit_msg>Does this work with travis?<commit_after>#![allow(non_camel_case_types)]
extern crate libc;
use self::libc::{c_char, size_t, uint8_t, uint16_t, uint32_t, uint64_t};

pub type SkBool = ::libc::c_uint;

/* ATA SMART test type (ATA8 7.52.5.2) */
#[repr(C)]
#[derive(Debug)]
pub enum SkSmartSelfTest {
    SK_SMART_SELF_TEST_SHORT = 1,
    SK_SMART_SELF_TEST_EXTENDED = 2,
    SK_SMART_SELF_TEST_CONVEYANCE = 3,
    SK_SMART_SELF_TEST_ABORT = 127
}

#[repr(C)]
pub struct SkIdentifyParsedData {
    pub serial: [c_char; 21],
    pub firmware: [c_char; 9],
    pub model: [c_char; 41],
}

#[repr(C)]
#[derive(Debug)]
pub enum SkSmartOfflineDataCollectionStatus {
    SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_NEVER,
    SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_SUCCESS,
    SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_INPROGRESS,
    SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_SUSPENDED,
    SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_ABORTED,
    SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_FATAL,
    SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_UNKNOWN,
    _SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_MAX
}

#[repr(C)]
#[derive(Debug)]
pub enum SkSmartSelfTestExecutionStatus {
    SK_SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER = 0,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_ABORTED = 1,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED = 2,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_FATAL = 3,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN = 4,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL = 5,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO = 6,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ = 7,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING = 8,
    SK_SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS = 15,
    _SK_SMART_SELF_TEST_EXECUTION_STATUS_MAX
}

#[repr(C)]
#[derive(Debug)]
pub struct SkSmartParsedData {
    /* Volatile data */
    pub offline_data_collection_status: SkSmartOfflineDataCollectionStatus ,
    pub total_offline_data_collection_seconds: uint32_t,
    pub self_test_execution_status: SkSmartSelfTestExecutionStatus,
    pub self_test_execution_percent_remaining: uint32_t,

    /* Fixed data */
    pub short_and_extended_test_available: SkBool,
    pub conveyance_test_available: SkBool,
    pub start_test_available: SkBool,
    pub abort_test_available: SkBool,

    pub short_test_polling_minutes: uint32_t,
    pub extended_test_polling_minutes: uint32_t,
    pub conveyance_test_polling_minutes: uint32_t,
}

#[repr(C)]
#[derive(Debug)]
pub enum SkSmartAttributeUnit {
    SK_SMART_ATTRIBUTE_UNIT_UNKNOWN,
    SK_SMART_ATTRIBUTE_UNIT_NONE,
    SK_SMART_ATTRIBUTE_UNIT_MSECONDS,      /* milliseconds */
    SK_SMART_ATTRIBUTE_UNIT_SECTORS,
    SK_SMART_ATTRIBUTE_UNIT_MKELVIN,       /* millikelvin */
    SK_SMART_ATTRIBUTE_UNIT_SMALL_PERCENT, /* percentage with 3 decimal points */
    SK_SMART_ATTRIBUTE_UNIT_PERCENT,       /* integer percentage */
    SK_SMART_ATTRIBUTE_UNIT_MB,
    _SK_SMART_ATTRIBUTE_UNIT_MAX

}

#[repr(C)]
#[derive(Debug)]
pub struct SkSmartAttributeParsedData {
    pub id: uint8_t,
    pub name: *const ::libc::c_char,
    pub pretty_unit: SkSmartAttributeUnit,
    pub flags: uint16_t ,
    pub threshold: uint8_t,
    pub threshold_valid: SkBool,
    pub online: SkBool,
    pub prefailure: SkBool,
    pub good_now: SkBool,
    pub good_now_valid: SkBool,
    pub good_in_the_past: SkBool,
    pub good_in_the_past_valid: SkBool,
    pub current_value_valid: SkBool,
    pub worst_value_valid: SkBool,
    pub warn: SkBool,
    pub current_value: uint8_t,
    pub worst_value: uint8_t,
    pub pretty_value: uint64_t,
    pub raw: [uint8_t; 6],
}

pub enum SkDisk{

}

#[repr(C)]
#[derive(Debug)]
pub enum SkSmartOverall  {
    SK_SMART_OVERALL_GOOD,
    SK_SMART_OVERALL_BAD_ATTRIBUTE_IN_THE_PAST,  /* At least one pre-fail attribute exceeded its threshold in the past */
    SK_SMART_OVERALL_BAD_SECTOR,                 /* At least one bad sector */
    SK_SMART_OVERALL_BAD_ATTRIBUTE_NOW,          /* At least one pre-fail attribute is exceeding its threshold now */
    SK_SMART_OVERALL_BAD_SECTOR_MANY,            /* Many bad sectors */
    SK_SMART_OVERALL_BAD_STATUS,                 /* Smart Self Assessment negative */
    SK_SMART_OVERALL_MAX
}

#[link(name = "atasmart4")]
extern "C" {
    pub fn sk_smart_self_test_execution_status_to_string(status: SkSmartSelfTestExecutionStatus) -> *const ::libc::c_char;
    pub fn sk_smart_offline_data_collection_status_to_string(status: SkSmartOfflineDataCollectionStatus) -> *const ::libc::c_char;
    pub fn sk_smart_self_test_to_string(test: SkSmartSelfTest) -> *const ::libc::c_char;
    pub fn sk_smart_self_test_available(d: *const SkSmartParsedData, test: SkSmartSelfTest) -> SkBool;
    pub fn sk_smart_self_test_polling_minutes(d: *const SkSmartParsedData, test: SkSmartSelfTest) -> uint32_t;
    pub fn sk_smart_attribute_unit_to_string(unit: SkSmartAttributeUnit) -> *const ::libc::c_char;
    pub fn sk_smart_overall_to_string(overall: SkSmartOverall) -> *const ::libc::c_char;
    pub fn sk_disk_open(name: *const ::libc::c_char, d: *mut *mut SkDisk) -> ::libc::c_int;
    pub fn sk_disk_get_size(d: *mut SkDisk, bytes: *mut uint64_t) -> ::libc::c_int;
    pub fn sk_disk_check_sleep_mode(d: *mut SkDisk, awake: *mut SkBool) -> ::libc::c_int;
    pub fn sk_disk_identify_is_available(d: *mut SkDisk, available: *mut SkBool) -> ::libc::c_int;
    pub fn sk_disk_identify_parse(d: *mut *mut SkDisk, data: *const SkIdentifyParsedData) -> ::libc::c_int;
    pub fn sk_disk_smart_is_available(d: *mut SkDisk, available: *mut SkBool) -> ::libc::c_int;
    pub fn sk_disk_smart_status(d: *mut SkDisk, good: *mut SkBool) -> ::libc::c_int;
    pub fn sk_disk_smart_read_data(d: *mut SkDisk) -> ::libc::c_int;
    pub fn sk_disk_get_blob(d: *mut *mut SkDisk, blob: *const ::libc::c_void, size: *mut size_t) -> ::libc::c_int;
    pub fn sk_disk_set_blob(d: *mut SkDisk, blob: *const ::libc::c_void, size: size_t) -> ::libc::c_int;
    pub fn sk_disk_smart_parse(d: *mut *mut SkDisk, data: *const SkSmartParsedData) -> ::libc::c_int;
    //pub fn sk_disk_smart_parse_attributes(d: *mut SkDisk, cb: SkSmartAttributeParseCallback, userdata: *mut ::libc::c_void) -> ::libc::c_int;
    pub fn sk_disk_smart_self_test(d: *mut SkDisk, test: SkSmartSelfTest) -> ::libc::c_int;
    pub fn sk_disk_smart_get_power_on(d: *mut SkDisk, mseconds: *mut uint64_t) -> ::libc::c_int;
    pub fn sk_disk_smart_get_power_cycle(d: *mut SkDisk, count: *mut uint64_t) -> ::libc::c_int;
    pub fn sk_disk_smart_get_bad(d: *mut SkDisk, sectors: *mut uint64_t) -> ::libc::c_int;
    pub fn sk_disk_smart_get_temperature(d: *mut SkDisk, mkelvin: *mut uint64_t ) -> ::libc::c_int;
    pub fn sk_disk_smart_get_overall(d: *mut SkDisk, overall: *mut SkSmartOverall) -> ::libc::c_int;
    pub fn sk_disk_dump(d: *mut SkDisk) -> ::libc::c_int;
    pub fn sk_disk_free(d: *mut SkDisk) -> ::libc::c_void;
}
<|endoftext|>


<commit_before>extern crate pulse;
extern crate threadpool;

use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
use pulse::{Pulse, Signal};
use threadpool::ThreadPool;

pub use storage::{Storage, VecStorage, HashMapStorage};

mod storage;

pub type Generation = u32;
#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub struct Entity(u32, Generation);

impl Entity {
    pub fn get_id(&self) -> usize { self.0 as usize }
    pub fn get_gen(&self) -> Generation { self.1 }
}

pub trait Component: Any + Sized {
    type Storage: Storage<Self> + Any + Send + Sync;
}

pub struct World {
    entities: RwLock<Vec<Entity>>,
    components: HashMap<TypeId, Box<Any+Send+Sync>>,
}

impl World {
    pub fn new() -> World {
        World {
            entities: RwLock::new(Vec::new()),
            components: HashMap::new(),
        }
    }
    pub fn register<T: Component>(&mut self) {
        let any = RwLock::new(T::Storage::new());
        self.components.insert(TypeId::of::<T>(), Box::new(any));
    }
    fn lock<T: Component>(&self) -> &RwLock<T::Storage> {
        use std::ops::Deref;
        let boxed = self.components.get(&TypeId::of::<T>()).unwrap();
        (boxed.deref() as &Any).downcast_ref().unwrap()
    }
}

#[derive(Copy, Clone)]
pub struct Components<'a>(&'a World);

impl<'a> Components<'a> {
    pub fn read<T: Component>(self) -> RwLockReadGuard<'a, T::Storage> {
        self.0.lock::<T>().read().unwrap()
    }
    pub fn write<T: Component>(self) -> RwLockWriteGuard<'a, T::Storage> {
        self.0.lock::<T>().write().unwrap()
    }
    pub fn entities(self) -> RwLockReadGuard<'a, Vec<Entity>> {
        self.0.entities.read().unwrap()
    }
}

pub struct WorldArg(Arc<World>, RefCell<Option<Pulse>>);
impl WorldArg {
    pub fn fetch<'a, U, F>(&'a self, f: F) -> U
        where F: FnOnce(Components<'a>) -> U
    {
        let pulse = self.1.borrow_mut().take().expect("fetch may only be called once.");
        let u = f(Components(&self.0));
        pulse.pulse();
        u
    }
}

pub struct EntityBuilder<'a>(Entity, &'a World);

impl<'a> EntityBuilder<'a> {
    pub fn with<T: Component>(self, value: T) -> EntityBuilder<'a> {
        self.1.lock::<T>().write().unwrap().add(self.0, value);
        self
    }
    pub fn build(self) -> Entity {
        self.1.entities.write().unwrap().push(self.0);
        self.0
    }
}

pub struct Scheduler {
    world: Arc<World>,
    threads: ThreadPool,
    last_entity: u32,
}

impl Scheduler {
    pub fn new(world: World, num_threads: usize) -> Scheduler {
        Scheduler {
            world: Arc::new(world),
            threads: ThreadPool::new(num_threads),
            last_entity: 0,
        }
    }
    pub fn run<F>(&mut self, functor: F) where
        F: 'static + Send + FnOnce(WorldArg)
    {
        let (signal, pulse) = Signal::new();
        let world = self.world.clone();
        self.threads.execute(|| {
            let warg = WorldArg(world, RefCell::new(Some(pulse)));
            functor(warg);
        });
        signal.wait().unwrap();
    }
    pub fn add_entity<'a>(&'a mut self) -> EntityBuilder<'a> {
        self.last_entity += 1;
        let ent = Entity(self.last_entity, 0); //TODO
        EntityBuilder(ent, &self.world)
    }
    pub fn wait(&self) {
        while self.threads.active_count() > 0 {} //TODO
    }
}

macro_rules! impl_run {
    ($name:ident [$( $write:ident ),*] [$( $read:ident ),*]) => (impl Scheduler {
        #[allow(non_snake_case, unused_mut)]
        pub fn $name<
            $($write:Component,)* $($read:Component,)*
            F: 'static + Send + FnMut( $(&mut $write,)* $(&$read,)* )
        >(&mut self, functor: F) {
            self.run(|warg| {
                let mut fun = functor;
                let ($(mut $write,)* $($read,)* entities) = warg.fetch(|comp|
                    ($(comp.write::<$write>(),)*
                     $(comp.read::<$read>(),)*
                       comp.entities())
                );
                for &ent in entities.iter() {
                    if let ( $( Some($write), )* $( Some($read), )* ) =
                        ( $( $write.get_mut(ent), )* $( $read.get(ent), )* ) {
                        fun( $($write,)* $($read,)* );
                    }
                }
            });
        }
    })
}

impl_run!( run0w1r [] [R0] );
impl_run!( run0w2r [] [R0, R1] );
impl_run!( run1w0r [W0] [] );
impl_run!( run1w1r [W0] [R0] );
impl_run!( run1w2r [W0] [R0, R1] );
impl_run!( run1w3r [W0] [R0, R1, R2] );
impl_run!( run1w4r [W0] [R0, R1, R2, R3] );
impl_run!( run1w5r [W0] [R0, R1, R2, R3, R4] );
impl_run!( run1w6r [W0] [R0, R1, R2, R3, R4, R5] );
impl_run!( run1w7r [W0] [R0, R1, R2, R3, R5, R6, R7] );
impl_run!( run2w0r [W0, W1] [] );
impl_run!( run2w1r [W0, W1] [R0] );
impl_run!( run2w2r [W0, W1] [R0, R1] );
<commit_msg>Implemented the generations array<commit_after>extern crate pulse;
extern crate threadpool;

use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
use pulse::{Pulse, Signal};
use threadpool::ThreadPool;

pub use storage::{Storage, VecStorage, HashMapStorage};

mod storage;

/// Index generation. When a new entity is placed at the old index,
/// it bumps the generation by 1. This allows to avoid using components
/// from the entities that were deleted.
/// 0 - invalid generation
/// (-X) - the entity at index X is dead
/// (+X) - the entity at index X is alive
pub type Generation = i32;
/// Index type is arbitrary. It doesn't show up in any interfaces.
/// Keeping it 32bit allows for a single 64bit word per entity.
pub type Index = u32;
/// Entity type, as seen by the user.
#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub struct Entity(Index, Generation);

impl Entity {
    pub fn get_id(&self) -> usize { self.0 as usize }
    pub fn get_gen(&self) -> Generation { self.1 }
}

pub trait Component: Any + Sized {
    type Storage: Storage<Self> + Any + Send + Sync;
}

pub struct World {
    entities: RwLock<Vec<Entity>>,
    generations: RwLock<Vec<Generation>>,
    components: HashMap<TypeId, Box<Any+Send+Sync>>,
}

impl World {
    pub fn new() -> World {
        World {
            entities: RwLock::new(Vec::new()),
            generations: RwLock::new(Vec::new()),
            components: HashMap::new(),
        }
    }
    pub fn register<T: Component>(&mut self) {
        let any = RwLock::new(T::Storage::new());
        self.components.insert(TypeId::of::<T>(), Box::new(any));
    }
    fn lock<T: Component>(&self) -> &RwLock<T::Storage> {
        use std::ops::Deref;
        let boxed = self.components.get(&TypeId::of::<T>()).unwrap();
        (boxed.deref() as &Any).downcast_ref().unwrap()
    }
}

#[derive(Copy, Clone)]
pub struct Components<'a>(&'a World);

impl<'a> Components<'a> {
    pub fn read<T: Component>(self) -> RwLockReadGuard<'a, T::Storage> {
        self.0.lock::<T>().read().unwrap()
    }
    pub fn write<T: Component>(self) -> RwLockWriteGuard<'a, T::Storage> {
        self.0.lock::<T>().write().unwrap()
    }
    pub fn entities(self) -> RwLockReadGuard<'a, Vec<Entity>> {
        self.0.entities.read().unwrap()
    }
}

pub struct WorldArg(Arc<World>, RefCell<Option<Pulse>>);
impl WorldArg {
    pub fn fetch<'a, U, F>(&'a self, f: F) -> U
        where F: FnOnce(Components<'a>) -> U
    {
        let pulse = self.1.borrow_mut().take().expect("fetch may only be called once.");
        let u = f(Components(&self.0));
        pulse.pulse();
        u
    }
}

pub struct EntityBuilder<'a>(Entity, &'a World);

impl<'a> EntityBuilder<'a> {
    pub fn with<T: Component>(self, value: T) -> EntityBuilder<'a> {
        self.1.lock::<T>().write().unwrap().add(self.0, value);
        self
    }
    pub fn build(self) -> Entity {
        self.1.entities.write().unwrap().push(self.0);
        self.0
    }
}

pub struct Scheduler {
    world: Arc<World>,
    threads: ThreadPool,
    first_free: Index,
}

fn find_free<'a>(mut gens: RwLockWriteGuard<'a, Vec<Generation>>, base: usize) -> Index {
    match gens[base..].iter().position(|g| *g <= 0) {
        Some(pos) => (base + pos) as Index,
        None => {
            gens.push(0);
            (gens.len() - 1) as Index
        },
    }
}

impl Scheduler {
    pub fn new(world: World, num_threads: usize) -> Scheduler {
        let ff = find_free(world.generations.write().unwrap(), 0);
        Scheduler {
            world: Arc::new(world),
            threads: ThreadPool::new(num_threads),
            first_free: ff,
        }
    }
    pub fn run<F>(&mut self, functor: F) where
        F: 'static + Send + FnOnce(WorldArg)
    {
        let (signal, pulse) = Signal::new();
        let world = self.world.clone();
        self.threads.execute(|| {
            let warg = WorldArg(world, RefCell::new(Some(pulse)));
            functor(warg);
        });
        signal.wait().unwrap();
    }
    pub fn add_entity<'a>(&'a mut self) -> EntityBuilder<'a> {
        let mut gens = self.world.generations.write().unwrap();
        let ent = {
            let gen = &mut gens[self.first_free as usize];
            assert!(*gen <= 0);
            *gen = 1 - *gen;
            Entity(self.first_free, *gen)
        };
        self.first_free = find_free(gens, (self.first_free + 1) as usize);
        EntityBuilder(ent, &self.world)
    }
    pub fn wait(&self) {
        while self.threads.active_count() > 0 {} //TODO
    }
}

macro_rules! impl_run {
    ($name:ident [$( $write:ident ),*] [$( $read:ident ),*]) => (impl Scheduler {
        #[allow(non_snake_case, unused_mut)]
        pub fn $name<
            $($write:Component,)* $($read:Component,)*
            F: 'static + Send + FnMut( $(&mut $write,)* $(&$read,)* )
        >(&mut self, functor: F) {
            self.run(|warg| {
                let mut fun = functor;
                let ($(mut $write,)* $($read,)* entities) = warg.fetch(|comp|
                    ($(comp.write::<$write>(),)*
                     $(comp.read::<$read>(),)*
                       comp.entities())
                );
                for &ent in entities.iter() {
                    if let ( $( Some($write), )* $( Some($read), )* ) =
                        ( $( $write.get_mut(ent), )* $( $read.get(ent), )* ) {
                        fun( $($write,)* $($read,)* );
                    }
                }
            });
        }
    })
}

impl_run!( run0w1r [] [R0] );
impl_run!( run0w2r [] [R0, R1] );
impl_run!( run1w0r [W0] [] );
impl_run!( run1w1r [W0] [R0] );
impl_run!( run1w2r [W0] [R0, R1] );
impl_run!( run1w3r [W0] [R0, R1, R2] );
impl_run!( run1w4r [W0] [R0, R1, R2, R3] );
impl_run!( run1w5r [W0] [R0, R1, R2, R3, R4] );
impl_run!( run1w6r [W0] [R0, R1, R2, R3, R4, R5] );
impl_run!( run1w7r [W0] [R0, R1, R2, R3, R5, R6, R7] );
impl_run!( run2w0r [W0, W1] [] );
impl_run!( run2w1r [W0, W1] [R0] );
impl_run!( run2w2r [W0, W1] [R0, R1] );
<|endoftext|>


<commit_before>use grain_capnp::{powerbox_capability, ui_view, ui_session};
use web_session_capnp::{web_session};

use std::collections::hash_map::HashMap;
use capnp::Error;
use capnp_rpc::{RpcSystem, twoparty, rpc_twoparty_capnp};
use gj::{EventLoop, Promise};
use gj::io::unix;
use sqlite3;

#[derive(Clone, Copy)]
pub struct UiViewImpl;

impl powerbox_capability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self,
                         _params: powerbox_capability::GetPowerboxInfoParams,
                         _results: powerbox_capability::GetPowerboxInfoResults)
                         -> Promise<(), Error>
    {
        Promise::ok(())
    }
}

impl ui_view::Server for UiViewImpl {
    fn get_view_info(&mut self,
                     _params: ui_view::GetViewInfoParams,
                     _results: ui_view::GetViewInfoResults)
                     -> Promise<(), Error>
    {
        Promise::ok(())
    }

    fn new_session(&mut self,
                   _params: ui_view::NewSessionParams,
                   mut results: ui_view::NewSessionResults)
                   -> Promise<(), Error>
    {
        let client: web_session::Client = match WebSessionImpl::new() {
            Ok(session) => {
                web_session::ToClient::new(session).from_server::<::capnp_rpc::Server>()
            }
            Err(_e) => {
                return Promise::err(Error::failed(format!("failed to create web session")));
            }
        };
        // we need to do this dance to upcast.
        results.get().set_session(ui_session::Client { client : client.client});
        Promise::ok(())
    }
}

pub struct WebSessionImpl {
    db: sqlite3::Database,
}

unsafe impl Send for WebSessionImpl {}

impl WebSessionImpl {
    pub fn new() -> sqlite3::SqliteResult<WebSessionImpl> {
        let mut db = try!(sqlite3::open("/var/data.db"));
        db.set_busy_timeout(1000); // try for a least a second
        Ok(WebSessionImpl {
            db : db,
        })
    }
}

impl ui_session::Server for WebSessionImpl {

}

impl WebSessionImpl {

    fn is_word(&self, word : &str) -> sqlite3::SqliteResult<bool> {

        if ! word.chars().all(|c| c.is_alphanumeric()) { return Ok(false); }

        let mut cursor = try!(self.db.prepare(
            &format!("SELECT * FROM Words WHERE Word = \"{}\";", word),
            &None));

        return Ok(try!(cursor.step_row()).is_some());
    }

    fn validate_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<bool> {
        if definition.len() != word.len() { return Ok(false); }
        let mut idx = 0;
        for &d in definition.iter() {
            if !(try!(self.is_word(d)) && d.len() > 0 && d.as_bytes()[0] == word.as_bytes()[idx]) {
                return Ok(false);
            }

            idx += 1;
        }

        return Ok(true);
    }

    fn write_def(&mut self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<()> {

        let time : i64 = ::time::get_time().sec;
        let mut query = String::new();
        query.push_str(&format!("BEGIN; DELETE FROM Definitions WHERE Definee =\"{}\"; ", word));
        query.push_str("INSERT INTO Definitions(Definee, Idx, Definer) VALUES");
        let mut idx = 0usize;
        for &d in definition.iter() {
            if idx != 0 { query.push_str(","); }
            query.push_str(&format!("(\"{}\", {}, \"{}\")", word, idx, d));
            idx += 1;
        }
        query.push_str(";");
        query.push_str(&format!("DELETE FROM Log WHERE Word=\"{}\";", word));
        query.push_str(&format!("INSERT INTO Log(Word, Timestamp) VALUES(\"{}\",{});", word, time));
        query.push_str("COMMIT;");

        println!("query: {}", query);

        try!(self.db.exec(&query));

        return Ok(());
    }

    fn get_def(&self, word : &str) -> sqlite3::SqliteResult<String> {

        let mut cursor = try!(self.db.prepare(
            &format!("SELECT * FROM Definitions WHERE Definee = \"{}\";", word),
            &None));

        let mut map = HashMap::<isize, String>::new();

        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let definer = match row[&"Definer".to_string()] { sqlite3::BindArg::Text(ref t) => t.clone(), _ => panic!(), };
                    let idx = match row[&"Idx".to_string()] { sqlite3::BindArg::Integer(ref i) => i.clone(), _ => panic!(), };

                    map.insert(idx, definer);
                }
            }
        }

        if map.len() != word.len() {
            return Ok("
this word has no definition yet
".to_string());
        } else {

            let mut result = String::new();
            result.push_str("
");
            for idx in 0..(word.len() as isize) {
                let definer : &str = &map[&idx];
                result.push_str(&format!(" {word} ", word=definer));
            }
            result.push_str("
");
            return Ok(result);
        }
    }

    fn count_defs(&self) -> sqlite3::SqliteResult<(isize, isize, Vec<String>)> {
        let mut cursor = try!(self.db.prepare("SELECT COUNT(*) FROM Words;", &None));
        assert!(cursor.step() == sqlite3::ResultCode::SQLITE_ROW);
        let num_words = cursor.get_int(0);

        let mut cursor = try!(self.db.prepare("SELECT COUNT(*) FROM Definitions WHERE Idx = 0;", &None));
        assert!(cursor.step() == sqlite3::ResultCode::SQLITE_ROW);
        let defined_words = cursor.get_int(0);

        let mut recent_words = Vec::new();
        let mut cursor = try!(
            self.db.prepare("SELECT Word, Timestamp FROM Log ORDER BY Timestamp DESC LIMIT 5;", &None));
        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let word : String = match row[&"Word".to_string()] {sqlite3::BindArg::Text(ref t) => t.clone(), _ => panic!(),};
                    recent_words.push(word);
                }
            }
        }
        Ok((defined_words, num_words, recent_words))

    }

    fn construct_page_data(&mut self, path : Vec<String>, query: Option<String>) -> sqlite3::SqliteResult<PageData> {
        if path.len() == 1 && path[0] == "define" {

            let mut query_map = HashMap::<String, String>::new();
            match query {
                None => {}
                Some(q) => {
                    for &(ref k, ref v) in ::url::form_urlencoded::parse(q.as_bytes()).iter() {
                        query_map.insert(k.clone(), v.clone());
                    }
                }
            }

            let word : String = match query_map.get(&"word".to_string()) {
                Some(w) if try!(self.is_word(&w)) => {
                    w.clone()
                }
                _ => {
                    return Ok(PageData::Error("that's not a word".to_string()))
                }
            };
            match query_map.get(&"definition".to_string()) {
                None => {
                    let def_div = try!(self.get_def(&word));

                    return Ok(PageData::WordAndDef(word, def_div, None));
                }
                Some(def_query) => {

                    let definition : Vec<&str> = def_query.split(' ').collect();

                    if try!(self.validate_def(&word, &definition)) {

                        try!(self.write_def(&word, &definition));
                        let def_div = try!(self.get_def(&word));
                        return Ok(PageData::WordAndDef(word,
                                                       def_div,
                                                       None));
                    } else {
                        let def_div = try!(self.get_def(&word));
                        return Ok(PageData::WordAndDef(word, def_div, Some("invalid definition".to_string())))
                    }
                }
            }

        } else {
            let (num_defined, total, recent) = try!(self.count_defs());
            return Ok(PageData::HomePage(num_defined, total, recent));
        }
    }

}

const MAIN_CSS : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             text-align: center;
     }
     div {
          padding-bottom: 10pt;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     .err {
       font-size: 90%;
       color: #AA0000;
     }
     .title {
       text-align: center;
       font-size:500%;
     }
     ";

const HEADER : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

const LOOKUP_FORM : &'static str =
      r#"<form action="define" method="get">
          <input name="word" maxlength="100"/><button>find word</button></form>"#;

fn define_form(word :&str) -> String {
       format!("<form action=\"define\" method=\"get\">
               <input name=\"word\" value=\"{word}\" type=\"hidden\"/>
               <input name=\"definition\" maxlength=\"2000\"/>
                   <button>submit definition</button></form>", word=word)
}

enum PageData {
    Error(String),
    WordAndDef(String, String, Option<String>),
    HomePage(isize, isize, Vec<String>),
}

fn construct_html(page_data : PageData) -> String {
    let mut result = String::new();
    result.push_str(&format!("{}", HEADER));

    const HOME_LINK : &'static str = "home";
    match page_data {
        PageData::Error(e) => {
            result.push_str(&format!("
 {}
", e));
            result.push_str(LOOKUP_FORM);
            result.push_str(HOME_LINK);
        }
        PageData::WordAndDef(word, def_div, err) => {
            result.push_str(&format!("
{}
", word));
            result.push_str(&def_div);

            match err {
                None => {}
                Some(e) => {
                    result.push_str(&format!("
{}
", e));
                }
            }

            result.push_str(&define_form(&word));
            result.push_str(HOME_LINK);
        }
        PageData::HomePage(num_defined, total, recent) => {
            result.push_str("
Acronymy
");
            result.push_str("
A user-editable, acronym-only dictionary.
");
            result.push_str(&format!("
So far, we have defined {} out of {} words.
",
                                     num_defined, total));
            if recent.len() > 0 {
                result.push_str("
Recently modified words: ");
                let mut idx = 0usize;
                for w in recent.iter() {
                    if idx != 0 {
                        result.push_str(", ");
                    }
                    result.push_str(&format!("{word}", word=*w));
                    idx += 1;
                }
                result.push_str(".
");
            }
            result.push_str(LOOKUP_FORM);
        }
    }

    result.push_str("");
    result
}

impl web_session::Server for WebSessionImpl {
    fn get(&mut self,
           params: web_session::GetParams,
           mut results: web_session::GetResults)
        -> Promise<(), Error>
    {
        println!("GET");
        {
            let params = pry!(params.get());
            let results = results.get();
            let raw_path = format!("/{}", pry!(params.get_path()));
            let mut content = results.init_content();
            content.set_mime_type("text/html");

            let (path, query) = match ::url::parse_path(&raw_path) {
                Err(_e) => (Vec::new(), None),
                Ok((p, q, _f)) => (p, q),
            };

            println!("path = {}", raw_path);

            if raw_path == "/main.css" {
                content.get_body().set_bytes(MAIN_CSS.as_bytes())
            } else {
                let page_data = match self.construct_page_data(path, query) {
                    Err(e) => { PageData::Error(format!("database error: {:?} ({})", e, self.db.get_errmsg())) }
                    Ok(page_data) => { page_data }
                };
                content.get_body().set_bytes(construct_html(page_data).as_bytes());
            }
        }
        Promise::ok(())
    }
}

pub fn main() -> ::capnp::Result<()> {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() == 4 && args[1] == "--init" {
        println!("initializing...");
        let initdb_path = ::std::path::Path::new(&args[2]);
        let proddb_path = ::std::path::Path::new(&args[3]);
        println!("copying database from {} to {}", args[2], args[3]);
        try!(::std::fs::copy(initdb_path, proddb_path));
        println!("success!");
    }

    EventLoop::top_level(move |wait_scope| {
        // sandstorm launches us with a connection file descriptor 3
        let stream = try!(unsafe { unix::Stream::from_raw_fd(3) });
        let (reader, writer) = stream.split();

        let client = ui_view::ToClient::new(UiViewImpl).from_server::<::capnp_rpc::Server>();

        let network =
            twoparty::VatNetwork::new(reader, writer,
                                      rpc_twoparty_capnp::Side::Server, Default::default());

        let _rpc_system = RpcSystem::new(Box::new(network), Some(client.client));
        println!("about to wait forever...");
        Promise::never_done().wait(wait_scope)
    }).expect("top level error");
    Ok(())
}

<commit_msg>works now, with the latest GJ. Socket needed to be set to NONBLOCK.<commit_after>use grain_capnp::{powerbox_capability, ui_view, ui_session};
use web_session_capnp::{web_session};

use std::collections::hash_map::HashMap;
use capnp::Error;
use capnp_rpc::{RpcSystem, twoparty, rpc_twoparty_capnp};
use gj::{EventLoop, Promise};
use gj::io::unix;
use sqlite3;

#[derive(Clone, Copy)]
pub struct UiViewImpl;

impl powerbox_capability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self,
                         _params: powerbox_capability::GetPowerboxInfoParams,
                         _results: powerbox_capability::GetPowerboxInfoResults)
                         -> Promise<(), Error>
    {
        Promise::ok(())
    }
}

impl ui_view::Server for UiViewImpl {
    fn get_view_info(&mut self,
                     _params: ui_view::GetViewInfoParams,
                     _results: ui_view::GetViewInfoResults)
                     -> Promise<(), Error>
    {
        Promise::ok(())
    }

    fn new_session(&mut self,
                   _params: ui_view::NewSessionParams,
                   mut results: ui_view::NewSessionResults)
                   -> Promise<(), Error>
    {
        let client: web_session::Client = match WebSessionImpl::new() {
            Ok(session) => {
                web_session::ToClient::new(session).from_server::<::capnp_rpc::Server>()
            }
            Err(_e) => {
                return Promise::err(Error::failed(format!("failed to create web session")));
            }
        };
        // we need to do this dance to upcast.
        results.get().set_session(ui_session::Client { client : client.client});
        Promise::ok(())
    }
}

pub struct WebSessionImpl {
    db: sqlite3::Database,
}

unsafe impl Send for WebSessionImpl {}

impl WebSessionImpl {
    pub fn new() -> sqlite3::SqliteResult<WebSessionImpl> {
        let mut db = try!(sqlite3::open("/var/data.db"));
        db.set_busy_timeout(1000); // try for a least a second
        Ok(WebSessionImpl {
            db : db,
        })
    }
}

impl ui_session::Server for WebSessionImpl {

}

impl WebSessionImpl {

    fn is_word(&self, word : &str) -> sqlite3::SqliteResult<bool> {

        if ! word.chars().all(|c| c.is_alphanumeric()) { return Ok(false); }

        let mut cursor = try!(self.db.prepare(
            &format!("SELECT * FROM Words WHERE Word = \"{}\";", word),
            &None));

        return Ok(try!(cursor.step_row()).is_some());
    }

    fn validate_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<bool> {
        if definition.len() != word.len() { return Ok(false); }
        let mut idx = 0;
        for &d in definition.iter() {
            if !(try!(self.is_word(d)) && d.len() > 0 && d.as_bytes()[0] == word.as_bytes()[idx]) {
                return Ok(false);
            }

            idx += 1;
        }

        return Ok(true);
    }

    fn write_def(&mut self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<()> {

        let time : i64 = ::time::get_time().sec;
        let mut query = String::new();
        query.push_str(&format!("BEGIN; DELETE FROM Definitions WHERE Definee =\"{}\"; ", word));
        query.push_str("INSERT INTO Definitions(Definee, Idx, Definer) VALUES");
        let mut idx = 0usize;
        for &d in definition.iter() {
            if idx != 0 { query.push_str(","); }
            query.push_str(&format!("(\"{}\", {}, \"{}\")", word, idx, d));
            idx += 1;
        }
        query.push_str(";");
        query.push_str(&format!("DELETE FROM Log WHERE Word=\"{}\";", word));
        query.push_str(&format!("INSERT INTO Log(Word, Timestamp) VALUES(\"{}\",{});", word, time));
        query.push_str("COMMIT;");

        println!("query: {}", query);

        try!(self.db.exec(&query));

        return Ok(());
    }

    fn get_def(&self, word : &str) -> sqlite3::SqliteResult<String> {

        let mut cursor = try!(self.db.prepare(
            &format!("SELECT * FROM Definitions WHERE Definee = \"{}\";", word),
            &None));

        let mut map = HashMap::<isize, String>::new();

        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let definer = match row[&"Definer".to_string()] { sqlite3::BindArg::Text(ref t) => t.clone(), _ => panic!(), };
                    let idx = match row[&"Idx".to_string()] { sqlite3::BindArg::Integer(ref i) => i.clone(), _ => panic!(), };

                    map.insert(idx, definer);
                }
            }
        }

        if map.len() != word.len() {
            return Ok("
this word has no definition yet
".to_string());
        } else {

            let mut result = String::new();
            result.push_str("
");
            for idx in 0..(word.len() as isize) {
                let definer : &str = &map[&idx];
                result.push_str(&format!(" {word} ", word=definer));
            }
            result.push_str("
");
            return Ok(result);
        }
    }

    fn count_defs(&self) -> sqlite3::SqliteResult<(isize, isize, Vec<String>)> {
        let mut cursor = try!(self.db.prepare("SELECT COUNT(*) FROM Words;", &None));
        assert!(cursor.step() == sqlite3::ResultCode::SQLITE_ROW);
        let num_words = cursor.get_int(0);

        let mut cursor = try!(self.db.prepare("SELECT COUNT(*) FROM Definitions WHERE Idx = 0;", &None));
        assert!(cursor.step() == sqlite3::ResultCode::SQLITE_ROW);
        let defined_words = cursor.get_int(0);

        let mut recent_words = Vec::new();
        let mut cursor = try!(
            self.db.prepare("SELECT Word, Timestamp FROM Log ORDER BY Timestamp DESC LIMIT 5;", &None));
        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let word : String = match row[&"Word".to_string()] {sqlite3::BindArg::Text(ref t) => t.clone(), _ => panic!(),};
                    recent_words.push(word);
                }
            }
        }
        Ok((defined_words, num_words, recent_words))

    }

    fn construct_page_data(&mut self, path : Vec<String>, query: Option<String>) -> sqlite3::SqliteResult<PageData> {
        if path.len() == 1 && path[0] == "define" {

            let mut query_map = HashMap::<String, String>::new();
            match query {
                None => {}
                Some(q) => {
                    for &(ref k, ref v) in ::url::form_urlencoded::parse(q.as_bytes()).iter() {
                        query_map.insert(k.clone(), v.clone());
                    }
                }
            }

            let word : String = match query_map.get(&"word".to_string()) {
                Some(w) if try!(self.is_word(&w)) => {
                    w.clone()
                }
                _ => {
                    return Ok(PageData::Error("that's not a word".to_string()))
                }
            };
            match query_map.get(&"definition".to_string()) {
                None => {
                    let def_div = try!(self.get_def(&word));

                    return Ok(PageData::WordAndDef(word, def_div, None));
                }
                Some(def_query) => {

                    let definition : Vec<&str> = def_query.split(' ').collect();

                    if try!(self.validate_def(&word, &definition)) {

                        try!(self.write_def(&word, &definition));
                        let def_div = try!(self.get_def(&word));
                        return Ok(PageData::WordAndDef(word,
                                                       def_div,
                                                       None));
                    } else {
                        let def_div = try!(self.get_def(&word));
                        return Ok(PageData::WordAndDef(word, def_div, Some("invalid definition".to_string())))
                    }
                }
            }

        } else {
            let (num_defined, total, recent) = try!(self.count_defs());
            return Ok(PageData::HomePage(num_defined, total, recent));
        }
    }

}

const MAIN_CSS : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             text-align: center;
     }
     div {
          padding-bottom: 10pt;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     .err {
       font-size: 90%;
       color: #AA0000;
     }
     .title {
       text-align: center;
       font-size:500%;
     }
     ";

const HEADER : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

const LOOKUP_FORM : &'static str =
      r#"<form action="define" method="get">
          <input name="word" maxlength="100"/><button>find word</button></form>"#;

fn define_form(word :&str) -> String {
       format!("<form action=\"define\" method=\"get\">
               <input name=\"word\" value=\"{word}\" type=\"hidden\"/>
               <input name=\"definition\" maxlength=\"2000\"/>
                   <button>submit definition</button></form>", word=word)
}

enum PageData {
    Error(String),
    WordAndDef(String, String, Option<String>),
    HomePage(isize, isize, Vec<String>),
}

fn construct_html(page_data : PageData) -> String {
    let mut result = String::new();
    result.push_str(&format!("{}", HEADER));

    const HOME_LINK : &'static str = "home";
    match page_data {
        PageData::Error(e) => {
            result.push_str(&format!("
 {}
", e));
            result.push_str(LOOKUP_FORM);
            result.push_str(HOME_LINK);
        }
        PageData::WordAndDef(word, def_div, err) => {
            result.push_str(&format!("
{}
", word));
            result.push_str(&def_div);

            match err {
                None => {}
                Some(e) => {
                    result.push_str(&format!("
{}
", e));
                }
            }

            result.push_str(&define_form(&word));
            result.push_str(HOME_LINK);
        }
        PageData::HomePage(num_defined, total, recent) => {
            result.push_str("
Acronymy
");
            result.push_str("
A user-editable, acronym-only dictionary.
");
            result.push_str(&format!("
So far, we have defined {} out of {} words.
",
                                     num_defined, total));
            if recent.len() > 0 {
                result.push_str("
Recently modified words: ");
                let mut idx = 0usize;
                for w in recent.iter() {
                    if idx != 0 {
                        result.push_str(", ");
                    }
                    result.push_str(&format!("{word}", word=*w));
                    idx += 1;
                }
                result.push_str(".
");
            }
            result.push_str(LOOKUP_FORM);
        }
    }

    result.push_str("");
    result
}

impl web_session::Server for WebSessionImpl {
    fn get(&mut self,
           params: web_session::GetParams,
           mut results: web_session::GetResults)
        -> Promise<(), Error>
    {
        println!("GET");
        {
            let params = pry!(params.get());
            let results = results.get();
            let raw_path = format!("/{}", pry!(params.get_path()));
            let mut content = results.init_content();
            content.set_mime_type("text/html");

            let (path, query) = match ::url::parse_path(&raw_path) {
                Err(_e) => (Vec::new(), None),
                Ok((p, q, _f)) => (p, q),
            };

            println!("path = {}", raw_path);

            if raw_path == "/main.css" {
                content.get_body().set_bytes(MAIN_CSS.as_bytes())
            } else {
                let page_data = match self.construct_page_data(path, query) {
                    Err(e) => { PageData::Error(format!("database error: {:?} ({})", e, self.db.get_errmsg())) }
                    Ok(page_data) => { page_data }
                };
                content.get_body().set_bytes(construct_html(page_data).as_bytes());
            }
        }
        Promise::ok(())
    }
}

pub fn main() -> ::capnp::Result<()> {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() == 4 && args[1] == "--init" {
        println!("initializing...");
        let initdb_path = ::std::path::Path::new(&args[2]);
        let proddb_path = ::std::path::Path::new(&args[3]);
        println!("copying database from {} to {}", args[2], args[3]);
        try!(::std::fs::copy(initdb_path, proddb_path));
        println!("success!");
    }

    EventLoop::top_level(move |wait_scope| {
        // sandstorm launches us with a connection file descriptor 3
        let stream = try!(unsafe { unix::Stream::from_raw_fd(3) });
        let (reader, writer) = stream.split();

        let client = ui_view::ToClient::new(UiViewImpl).from_server::<::capnp_rpc::Server>();

        let network =
            twoparty::VatNetwork::new(reader, writer,
                                      rpc_twoparty_capnp::Side::Server, Default::default());

        let _rpc_system = RpcSystem::new(Box::new(network), Some(client.client));
        Promise::never_done().wait(wait_scope)
    }).expect("top level error");
    Ok(())
}

<|endoftext|>


<commit_before>// Copyright (c) 2015-2016 Ivo Wetzel

// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate clock_ticks;

use std::cmp;
use std::thread;
use std::time::Duration;
use std::io::{Error, ErrorKind};
use std::collections::HashMap;
use std::net::{SocketAddr, ToSocketAddrs};
use traits::socket::Socket;
use shared::udp_socket::UdpSocket;
use shared::stats::{StatsCollector, Stats};
use super::{Config, Connection, ConnectionID, Handler};

/// Implementation of a multi-client server with handler based event dispatch.
#[derive(Debug)]
pub struct Server {
    closed: bool,
    config: Config,
    local_address: Option<SocketAddr>,
    statistics: StatsCollector
}

impl Server {

    /// Creates a new server with the given configuration.
    pub fn new(config: Config) -> Server {
        Server {
            closed: false,
            config: config,
            local_address: None,
            statistics: StatsCollector::new(config)
        }
    }

    /// Returns the local address that the server is bound to.
    pub fn local_addr(&self) -> Result<SocketAddr, Error> {
        self.local_address.ok_or(Error::new(ErrorKind::AddrNotAvailable, ""))
    }

    /// Returns statistics (i.e. bandwidth usage) for the last second.
    pub fn stats(&mut self) -> Stats {
        self.statistics.average()
    }

    /// Binds the server to the specified local address by creating a socket
    /// and actively listens for incoming client connections.
    ///
    /// Clients connecting to the server must use a compatible connection
    /// / packet configuration in order to be able to connect.
    ///
    /// The `handler` is a struct that implements the `Handler` trait in order
    /// to handle events from the server and its connections.
    pub fn bind<A: ToSocketAddrs>(
        &mut self, handler: &mut Handler<Server>, addr: A

    ) -> Result<(), Error> {

        let socket = try!(UdpSocket::new(
            addr,
            self.config.packet_max_size
        ));

        self.bind_to_socket(handler, socket)

    }

    /// Binds the server to specified socket and actively listens for incoming
    /// client connections.
    ///
    /// Clients connecting to the server must use a compatible connection
    /// / packet configuration in order to be able to connect.
    ///
    /// The `handler` is a struct that implements the `Handler` trait in order
    /// to handle events from the server and its connections.
    pub fn bind_to_socket<S: Socket>(
        &mut self, handler: &mut Handler<Server>, mut socket: S

    ) -> Result<(), Error> {

        // Store bound socket address
        self.local_address = Some(try!(socket.local_addr()));

        // Reset stats
        self.statistics.reset();

        // List of dropped connections
        let mut dropped: Vec<ConnectionID> = Vec::new();

        // Mappping of connections to their remote sender address
        let mut addresses: HashMap<ConnectionID, SocketAddr> = HashMap::new();

        // Mapping of the actual connection objects
        let mut connections: HashMap<ConnectionID, Connection> = HashMap::new();

        // Invoke handler
        handler.bind(self);

        // Receive and send until we shut down.
        while !self.closed {

            // Get current time to correct tick delay in order to achieve
            // a more stable tick rate
            let begin = clock_ticks::precise_time_ns();
            let tick_delay = 1000000000 / self.config.send_rate;

            // Receive all incoming UDP packets to our local address
            let mut bytes_received = 0;
            while let Ok((addr, packet)) = socket.try_recv() {

                // Try to extract the connection id from the packet
                match Connection::id_from_packet(&self.config, &packet) {
                    Some(id) => {

                        // Retrieve or create a connection for the current
                        // connection id
                        let connection = connections.entry(id).or_insert_with(|| {

                            // Also map the intitial address which is used by
                            // the connection
                            addresses.insert(id, addr);

                            let mut conn = Connection::new(
                                self.config,
                                socket.local_addr().unwrap(),
                                addr,
                                handler.rate_limiter(&self.config)
                            );

                            conn.set_id(id);
                            conn

                        });

                        // Map the current remote address of the connection to
                        // the latest address that sent a packet for the
                        // connection id in question. This is done in order to
                        // work in situations were the remote port of a
                        // connection is switched around by NAT.
                        if addr != connection.peer_addr() {
                            connection.set_peer_addr(addr);
                            addresses.remove(&id).unwrap();
                            addresses.insert(id, addr);
                        }

                        // Statistics
                        bytes_received += packet.len();

                        // Then feed the packet into the connection object for
                        // parsing
                        connection.receive_packet(
                            packet, tick_delay / 1000000, self, handler
                        );

                    },
                    None => { /* Ignore any invalid packets */ }
                }

            }

            self.statistics.set_bytes_received(bytes_received as u32);

            // Invoke handler
            handler.tick_connections(self, &mut connections);

            // Create outgoing packets for all connections
            let mut bytes_sent = 0;
            for (id, conn) in connections.iter_mut() {

                // Resolve the last known remote address for this
                // connection and send the data
                let addr = addresses.get(id).unwrap();

                // Then invoke the connection to send a outgoing packet
                bytes_sent += conn.send_packet(&mut socket, addr, self, handler);

                // Collect all lost / closed connections
                if conn.open() == false {
                    dropped.push(*id);
                }

            }

            // Update statistics
            self.statistics.set_bytes_sent(bytes_sent);
            self.statistics.tick();

            // Remove any dropped connections and their address mappings
            if dropped.is_empty() == false {

                for id in dropped.iter() {
                    connections.remove(id).unwrap().reset();
                    addresses.remove(id).unwrap();
                }

                dropped.clear();

            }

            // Calculate spend time in current loop iteration and limit ticks
            // accordingly
            thread::sleep(
                Duration::new(0, tick_delay - cmp::min(
                    (clock_ticks::precise_time_ns() - begin) as u32,
                    tick_delay
                ))
            );

        }

        // Invoke handler
        handler.shutdown(self);

        // Reset socket address
        self.local_address = None;

        // Reset all connection states
        for (_, conn) in connections.iter_mut() {
            conn.reset();
        }

        // Close the UDP socket
        socket.shutdown();

        Ok(())

    }

    /// Shuts down the server, closing all active client connections.
    ///
    /// This exits the tick loop, resets all connections and shuts down the
    /// underlying socket the server was bound to.
    pub fn shutdown(&mut self) -> Result<(), Error> {
        if self.closed {
            Err(Error::new(ErrorKind::NotConnected, ""))

        } else {
            self.closed = true;
            Ok(())
        }
    }

}

<commit_msg>Remove a number of optional unwrap() calls.<commit_after>// Copyright (c) 2015-2016 Ivo Wetzel

// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate clock_ticks;

use std::cmp;
use std::thread;
use std::time::Duration;
use std::io::{Error, ErrorKind};
use std::collections::HashMap;
use std::net::{SocketAddr, ToSocketAddrs};
use traits::socket::Socket;
use shared::udp_socket::UdpSocket;
use shared::stats::{StatsCollector, Stats};
use super::{Config, Connection, ConnectionID, Handler};

/// Implementation of a multi-client server with handler based event dispatch.
#[derive(Debug)]
pub struct Server {
    closed: bool,
    config: Config,
    local_address: Option<SocketAddr>,
    statistics: StatsCollector
}

impl Server {

    /// Creates a new server with the given configuration.
    pub fn new(config: Config) -> Server {
        Server {
            closed: false,
            config: config,
            local_address: None,
            statistics: StatsCollector::new(config)
        }
    }

    /// Returns the local address that the server is bound to.
    pub fn local_addr(&self) -> Result<SocketAddr, Error> {
        self.local_address.ok_or(Error::new(ErrorKind::AddrNotAvailable, ""))
    }

    /// Returns statistics (i.e. bandwidth usage) for the last second.
    pub fn stats(&mut self) -> Stats {
        self.statistics.average()
    }

    /// Binds the server to the specified local address by creating a socket
    /// and actively listens for incoming client connections.
    ///
    /// Clients connecting to the server must use a compatible connection
    /// / packet configuration in order to be able to connect.
    ///
    /// The `handler` is a struct that implements the `Handler` trait in order
    /// to handle events from the server and its connections.
    pub fn bind<A: ToSocketAddrs>(
        &mut self, handler: &mut Handler<Server>, addr: A

    ) -> Result<(), Error> {

        let socket = try!(UdpSocket::new(
            addr,
            self.config.packet_max_size
        ));

        self.bind_to_socket(handler, socket)

    }

    /// Binds the server to specified socket and actively listens for incoming
    /// client connections.
    ///
    /// Clients connecting to the server must use a compatible connection
    /// / packet configuration in order to be able to connect.
    ///
    /// The `handler` is a struct that implements the `Handler` trait in order
    /// to handle events from the server and its connections.
    pub fn bind_to_socket<S: Socket>(
        &mut self, handler: &mut Handler<Server>, mut socket: S

    ) -> Result<(), Error> {

        // Store bound socket address
        let local_addr = try!(socket.local_addr());
        self.local_address = Some(local_addr);

        // Reset stats
        self.statistics.reset();

        // List of dropped connections
        let mut dropped: Vec<ConnectionID> = Vec::new();

        // Mappping of connections to their remote sender address
        let mut addresses: HashMap<ConnectionID, SocketAddr> = HashMap::new();

        // Mapping of the actual connection objects
        let mut connections: HashMap<ConnectionID, Connection> = HashMap::new();

        // Invoke handler
        handler.bind(self);

        // Receive and send until we shut down.
        while !self.closed {

            // Get current time to correct tick delay in order to achieve
            // a more stable tick rate
            let begin = clock_ticks::precise_time_ns();
            let tick_delay = 1000000000 / self.config.send_rate;

            // Receive all incoming UDP packets to our local address
            let mut bytes_received = 0;
            while let Ok((addr, packet)) = socket.try_recv() {

                // Try to extract the connection id from the packet
                match Connection::id_from_packet(&self.config, &packet) {
                    Some(id) => {

                        // Retrieve or create a connection for the current
                        // connection id
                        let connection = connections.entry(id).or_insert_with(|| {

                            // Also map the intitial address which is used by
                            // the connection
                            addresses.insert(id, addr);

                            let mut conn = Connection::new(
                                self.config,
                                local_addr,
                                addr,
                                handler.rate_limiter(&self.config)
                            );

                            conn.set_id(id);
                            conn

                        });

                        // Map the current remote address of the connection to
                        // the latest address that sent a packet for the
                        // connection id in question. This is done in order to
                        // work in situations were the remote port of a
                        // connection is switched around by NAT.
                        if addr != connection.peer_addr() {
                            connection.set_peer_addr(addr);
                            addresses.remove(&id);
                            addresses.insert(id, addr);
                        }

                        // Statistics
                        bytes_received += packet.len();

                        // Then feed the packet into the connection object for
                        // parsing
                        connection.receive_packet(
                            packet, tick_delay / 1000000, self, handler
                        );

                    },
                    None => { /* Ignore any invalid packets */ }
                }

            }

            self.statistics.set_bytes_received(bytes_received as u32);

            // Invoke handler
            handler.tick_connections(self, &mut connections);

            // Create outgoing packets for all connections
            let mut bytes_sent = 0;
            for (id, conn) in connections.iter_mut() {

                // Resolve the last known remote address for this
                // connection and send the data
                let addr = addresses.get(id).unwrap();

                // Then invoke the connection to send a outgoing packet
                bytes_sent += conn.send_packet(&mut socket, addr, self, handler);

                // Collect all lost / closed connections
                if conn.open() == false {
                    dropped.push(*id);
                }

            }

            // Update statistics
            self.statistics.set_bytes_sent(bytes_sent);
            self.statistics.tick();

            // Remove any dropped connections and their address mappings
            if dropped.is_empty() == false {

                for id in dropped.iter() {
                    connections.remove(id).unwrap().reset();
                    addresses.remove(id);
                }

                dropped.clear();

            }

            // Calculate spend time in current loop iteration and limit ticks
            // accordingly

            // TODO: In case we spent more time than the tick_delay, make the
            // next tick faster in order to compensate.
            thread::sleep(
                Duration::new(0, tick_delay - cmp::min(
                    (clock_ticks::precise_time_ns() - begin) as u32,
                    tick_delay
                ))
            );

        }

        // Invoke handler
        handler.shutdown(self);

        // Reset socket address
        self.local_address = None;

        // Reset all connection states
        for (_, conn) in connections.iter_mut() {
            conn.reset();
        }

        // Close the UDP socket
        socket.shutdown();

        Ok(())

    }

    /// Shuts down the server, closing all active client connections.
    ///
    /// This exits the tick loop, resets all connections and shuts down the
    /// underlying socket the server was bound to.
    pub fn shutdown(&mut self) -> Result<(), Error> {
        if self.closed {
            Err(Error::new(ErrorKind::NotConnected, ""))

        } else {
            self.closed = true;
            Ok(())
        }
    }

}

<|endoftext|>