<commit_before>use callback::Callable;
use frame::Frameable;
use color::{ Color, Colorable };
use dimensions::Dimensions;
use mouse::Mouse;
use point::Point;
use rectangle;
use ui_context::{ UIID, UiContext };
use vecmath::vec2_add;
use graphics::Graphics;
use graphics::character::CharacterCache;
use widget::Widget;

/// Tuple / Callback params.
pub type Idx = usize;
pub type Len = usize;

/// Represents the state of the menu.
#[derive(PartialEq, Clone, Copy)]
pub enum State {
    Closed(DrawState),
    Open(DrawState),
}

/// Represents the state of the DropDownList widget.
#[derive(PartialEq, Clone, Copy)]
pub enum DrawState {
    Normal,
    Highlighted(Idx, Len),
    Clicked(Idx, Len),
}

impl DrawState {
    /// Translate the DropDownList's DrawState to the equivalent rectangle::State.
    fn as_rect_state(&self) -> rectangle::State {
        match self {
            &DrawState::Normal => rectangle::State::Normal,
            &DrawState::Highlighted(_, _) => rectangle::State::Highlighted,
            &DrawState::Clicked(_, _) => rectangle::State::Clicked,
        }
    }
}

impl State {
    /// Translate the DropDownList's State to the equivalent rectangle::State.
    fn as_rect_state(&self) -> rectangle::State {
        match self {
            &State::Open(draw_state) | &State::Closed(draw_state) => draw_state.as_rect_state(),
        }
    }
}

widget_fns!(DropDownList, State, Widget::DropDownList(State::Closed(DrawState::Normal)));

/// Is the cursor currently over the widget? If so which item?
fn is_over(pos: Point,
           mouse_pos: Point,
           dim: Dimensions,
           state: State,
           len: Len) -> Option<Idx> {
    match state {
        State::Closed(_) => {
            match rectangle::is_over(pos, mouse_pos, dim) {
                false => None,
                true => Some(0),
            }
        },
        State::Open(_) => {
            let total_h = dim[1] * len as f64;
            match rectangle::is_over(pos, mouse_pos, [dim[0], total_h]) {
                false => None,
                true => Some((((mouse_pos[1] - pos[1]) / total_h) * len as f64) as usize),
            }
        },
    }
}

/// Determine and return the new State by comparing the mouse state
/// and position to the previous State.
fn get_new_state(is_over_idx: Option<Idx>,
                 len: Len,
                 state: State,
                 mouse: Mouse) -> State {
    use self::DrawState::{Normal, Clicked, Highlighted};
    use mouse::ButtonState::{Down, Up};
    match state {
        State::Closed(draw_state) => {
            match is_over_idx {
                Some(_) => {
                    match (draw_state, mouse.left) {
                        (Normal,            Down) => State::Closed(Normal),
                        (Normal,            Up)   |
                        (Highlighted(_, _), Up)   => State::Closed(Highlighted(0, len)),
                        (Highlighted(_, _), Down) => State::Closed(Clicked(0, len)),
                        (Clicked(_, _),     Down) => State::Closed(Clicked(0, len)),
                        (Clicked(_, _),     Up)   => State::Open(Normal),
                    }
                },
                None => State::Closed(Normal),
            }
        },
        State::Open(draw_state) => {
            match is_over_idx {
                Some(idx) => {
                    match (draw_state, mouse.left) {
                        (Normal,            Down) => State::Open(Normal),
                        (Normal,            Up)   |
                        (Highlighted(_, _), Up)   => State::Open(Highlighted(idx, len)),
                        (Highlighted(_, _), Down) => State::Open(Clicked(idx, len)),
                        (Clicked(p_idx, _), Down) => State::Open(Clicked(p_idx, len)),
                        (Clicked(_, _),     Up)   => State::Closed(Normal),
                    }
                },
                None => {
                    match (draw_state, mouse.left) {
                        (Highlighted(p_idx, _), Up) => State::Open(Highlighted(p_idx, len)),
                        _ => State::Closed(Normal),
                    }
                },
            }
        }
    }
}

/// A context on which the builder pattern can be implemented.
pub struct DropDownList<'a, F> {
    ui_id: UIID,
    strings: &'a mut Vec<String>,
    selected: &'a mut Option<Idx>,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_label: Option<&'a str>,
    maybe_label_color: Option<Color>,
    maybe_label_font_size: Option<u32>,
}

impl<'a, F> DropDownList<'a, F> {
    pub fn new(ui_id: UIID,
               strings: &'a mut Vec<String>,
               selected: &'a mut Option<Idx>) -> DropDownList<'a, F> {
        DropDownList {
            ui_id: ui_id,
            strings: strings,
            selected: selected,
            pos: [0.0, 0.0],
            dim: [128.0, 32.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_label: None,
            maybe_label_color: None,
            maybe_label_font_size: None,
        }
    }
}

impl<'a, F> Colorable for DropDownList<'a, F> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

impl<'a, F> Frameable for DropDownList<'a, F> {
    fn frame(mut self, width: f64) -> Self {
        self.maybe_frame = Some(width);
        self
    }
    fn frame_color(mut self, color: Color) -> Self {
        self.maybe_frame_color = Some(color);
        self
    }
}

impl<'a, F> Callable<F> for DropDownList<'a, F> {
    fn callback(mut self, cb: F) -> Self {
        self.maybe_callback = Some(cb);
        self
    }
}

/*
quack! {
    list: DropDownList['a, F]
    get:
        fn () -> Size [] { Size(list.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(
                Widget::DropDownList(State::Closed(DrawState::Normal))
            )
        }
        fn () -> Id [] { Id(list.ui_id) }
    set:
        fn (val: LabelText<'a>) [] { list.maybe_label = Some(val.0) }
        fn (val: LabelColor) [] { list.maybe_label_color = Some(val.0) }
        fn (val: LabelFontSize) [] { list.maybe_label_font_size = Some(val.0) }
        fn (val: Position) [] { list.pos = val.0 }
        fn (val: Size) [] { list.dim = val.0 }
    action:
}
*/

impl<'a, F> ::draw::Drawable for DropDownList<'a, F>
    where
        F: FnMut(&mut Option<Idx>, Idx, String) + 'a
{

    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {

        let state = *get_state(uic, self.ui_id);
        let mouse = uic.get_mouse_state();
        let is_over_idx = is_over(self.pos, mouse.pos, self.dim, state, self.strings.len());
        let new_state = get_new_state(is_over_idx, self.strings.len(), state, mouse);

        let sel = match *self.selected {
            Some(idx) if idx < self.strings.len() => { Some(idx) },
            _ => None,
        };
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);
        let t_size = self.maybe_label_font_size.unwrap_or(uic.theme.font_size_medium);
        let t_color = self.maybe_label_color.unwrap_or(uic.theme.label_color);

        // Call the `callback` closure if mouse was released
        // on one of the DropDownMenu items.
        match (state, new_state) {
            (State::Open(o_d_state), State::Closed(c_d_state)) => {
                match (o_d_state, c_d_state) {
                    (DrawState::Clicked(idx, _), DrawState::Normal) => {
                        match self.maybe_callback {
                            Some(ref mut callback) => (*callback)(self.selected, idx, (*self.strings)[idx].clone()),
                            None => (),
                        }
                    }, _ => (),
                }
            }, _ => (),
        }

        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let maybe_frame = match frame_w > 0.0 {
            true => Some((frame_w, self.maybe_frame_color.unwrap_or(uic.theme.frame_color))),
            false => None,
        };

        match new_state {

            State::Closed(_) => {
                let rect_state = new_state.as_rect_state();
                let text = match sel {
                    Some(idx) => &(*self.strings)[idx][..],
                    None => match self.maybe_label {
                        Some(text) => text,
                        None => &(*self.strings)[0][..],
                    },
                };
                rectangle::draw_with_centered_label(
                    uic.win_w, uic.win_h, graphics, uic, rect_state,
                    self.pos, self.dim, maybe_frame, color,
                    text, t_size, t_color
                )
            },

            State::Open(draw_state) => {
                for (i, string) in self.strings.iter().enumerate() {
                    let rect_state = match sel {
                        None => {
                            match draw_state {
                                DrawState::Normal => rectangle::State::Normal,
                                DrawState::Highlighted(idx, _) => {
                                    if i == idx { rectangle::State::Highlighted }
                                    else { rectangle::State::Normal }
                                },
                                DrawState::Clicked(idx, _) => {
                                    if i == idx { rectangle::State::Clicked }
                                    else { rectangle::State::Normal }
                                },
                            }
                        },
                        Some(sel_idx) => {
                            if sel_idx == i { rectangle::State::Clicked }
                            else {
                                match draw_state {
                                    DrawState::Normal => rectangle::State::Normal,
                                    DrawState::Highlighted(idx, _) => {
                                        if i == idx { rectangle::State::Highlighted }
                                        else { rectangle::State::Normal }
                                    },
                                    DrawState::Clicked(idx, _) => {
                                        if i == idx { rectangle::State::Clicked }
                                        else { rectangle::State::Normal }
                                    },
                                }
                            }
                        },
                    };
                    let idx_y = self.dim[1] * i as f64 - i as f64 * frame_w;
                    let idx_pos = vec2_add(self.pos, [0.0, idx_y]);
                    rectangle::draw_with_centered_label(
                        uic.win_w, uic.win_h, graphics, uic, rect_state, idx_pos,
                        self.dim, maybe_frame, color, &string,
                        t_size, t_color
                    )
                }
            },

        }

        set_state(uic, self.ui_id, Widget::DropDownList(new_state), self.pos, self.dim);

    }
}
<commit_msg>Implemented `Labelable` for `DropDownList`<commit_after>use callback::Callable;
use frame::Frameable;
use label::{ FontSize, Labelable };
use color::{ Color, Colorable };
use dimensions::Dimensions;
use mouse::Mouse;
use point::Point;
use rectangle;
use ui_context::{ UIID, UiContext };
use vecmath::vec2_add;
use graphics::Graphics;
use graphics::character::CharacterCache;
use widget::Widget;

/// Tuple / Callback params.
pub type Idx = usize;
pub type Len = usize;

/// Represents the state of the menu.
#[derive(PartialEq, Clone, Copy)]
pub enum State {
    Closed(DrawState),
    Open(DrawState),
}

/// Represents the state of the DropDownList widget.
#[derive(PartialEq, Clone, Copy)]
pub enum DrawState {
    Normal,
    Highlighted(Idx, Len),
    Clicked(Idx, Len),
}

impl DrawState {
    /// Translate the DropDownList's DrawState to the equivalent rectangle::State.
    fn as_rect_state(&self) -> rectangle::State {
        match self {
            &DrawState::Normal => rectangle::State::Normal,
            &DrawState::Highlighted(_, _) => rectangle::State::Highlighted,
            &DrawState::Clicked(_, _) => rectangle::State::Clicked,
        }
    }
}

impl State {
    /// Translate the DropDownList's State to the equivalent rectangle::State.
    fn as_rect_state(&self) -> rectangle::State {
        match self {
            &State::Open(draw_state) | &State::Closed(draw_state) => draw_state.as_rect_state(),
        }
    }
}

widget_fns!(DropDownList, State, Widget::DropDownList(State::Closed(DrawState::Normal)));

/// Is the cursor currently over the widget? If so which item?
fn is_over(pos: Point,
           mouse_pos: Point,
           dim: Dimensions,
           state: State,
           len: Len) -> Option<Idx> {
    match state {
        State::Closed(_) => {
            match rectangle::is_over(pos, mouse_pos, dim) {
                false => None,
                true => Some(0),
            }
        },
        State::Open(_) => {
            let total_h = dim[1] * len as f64;
            match rectangle::is_over(pos, mouse_pos, [dim[0], total_h]) {
                false => None,
                true => Some((((mouse_pos[1] - pos[1]) / total_h) * len as f64) as usize),
            }
        },
    }
}

/// Determine and return the new State by comparing the mouse state
/// and position to the previous State.
fn get_new_state(is_over_idx: Option<Idx>,
                 len: Len,
                 state: State,
                 mouse: Mouse) -> State {
    use self::DrawState::{Normal, Clicked, Highlighted};
    use mouse::ButtonState::{Down, Up};
    match state {
        State::Closed(draw_state) => {
            match is_over_idx {
                Some(_) => {
                    match (draw_state, mouse.left) {
                        (Normal,            Down) => State::Closed(Normal),
                        (Normal,            Up)   |
                        (Highlighted(_, _), Up)   => State::Closed(Highlighted(0, len)),
                        (Highlighted(_, _), Down) => State::Closed(Clicked(0, len)),
                        (Clicked(_, _),     Down) => State::Closed(Clicked(0, len)),
                        (Clicked(_, _),     Up)   => State::Open(Normal),
                    }
                },
                None => State::Closed(Normal),
            }
        },
        State::Open(draw_state) => {
            match is_over_idx {
                Some(idx) => {
                    match (draw_state, mouse.left) {
                        (Normal,            Down) => State::Open(Normal),
                        (Normal,            Up)   |
                        (Highlighted(_, _), Up)   => State::Open(Highlighted(idx, len)),
                        (Highlighted(_, _), Down) => State::Open(Clicked(idx, len)),
                        (Clicked(p_idx, _), Down) => State::Open(Clicked(p_idx, len)),
                        (Clicked(_, _),     Up)   => State::Closed(Normal),
                    }
                },
                None => {
                    match (draw_state, mouse.left) {
                        (Highlighted(p_idx, _), Up) => State::Open(Highlighted(p_idx, len)),
                        _ => State::Closed(Normal),
                    }
                },
            }
        }
    }
}

/// A context on which the builder pattern can be implemented.
pub struct DropDownList<'a, F> {
    ui_id: UIID,
    strings: &'a mut Vec<String>,
    selected: &'a mut Option<Idx>,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_label: Option<&'a str>,
    maybe_label_color: Option<Color>,
    maybe_label_font_size: Option<u32>,
}

impl<'a, F> DropDownList<'a, F> {
    pub fn new(ui_id: UIID,
               strings: &'a mut Vec<String>,
               selected: &'a mut Option<Idx>) -> DropDownList<'a, F> {
        DropDownList {
            ui_id: ui_id,
            strings: strings,
            selected: selected,
            pos: [0.0, 0.0],
            dim: [128.0, 32.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_label: None,
            maybe_label_color: None,
            maybe_label_font_size: None,
        }
    }
}

impl<'a, F> Colorable for DropDownList<'a, F> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

impl<'a, F> Frameable for DropDownList<'a, F> {
    fn frame(mut self, width: f64) -> Self {
        self.maybe_frame = Some(width);
        self
    }
    fn frame_color(mut self, color: Color) -> Self {
        self.maybe_frame_color = Some(color);
        self
    }
}

impl<'a, F> Callable<F> for DropDownList<'a, F> {
    fn callback(mut self, cb: F) -> Self {
        self.maybe_callback = Some(cb);
        self
    }
}

impl<'a, F> Labelable<'a> for DropDownList<'a, F>
{
    fn label(mut self, text: &'a str) -> Self {
        self.maybe_label = Some(text);
        self
    }

    fn label_color(mut self, color: Color) -> Self {
        self.maybe_label_color = Some(color);
        self
    }

    fn label_font_size(mut self, size: FontSize) -> Self {
        self.maybe_label_font_size = Some(size);
        self
    }
}

/*
quack! {
    list: DropDownList['a, F]
    get:
        fn () -> Size [] { Size(list.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(
                Widget::DropDownList(State::Closed(DrawState::Normal))
            )
        }
        fn () -> Id [] { Id(list.ui_id) }
    set:
        fn (val: Position) [] { list.pos = val.0 }
        fn (val: Size) [] { list.dim = val.0 }
    action:
}
*/

impl<'a, F> ::draw::Drawable for DropDownList<'a, F>
    where
        F: FnMut(&mut Option<Idx>, Idx, String) + 'a
{

    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {

        let state = *get_state(uic, self.ui_id);
        let mouse = uic.get_mouse_state();
        let is_over_idx = is_over(self.pos, mouse.pos, self.dim, state, self.strings.len());
        let new_state = get_new_state(is_over_idx, self.strings.len(), state, mouse);

        let sel = match *self.selected {
            Some(idx) if idx < self.strings.len() => { Some(idx) },
            _ => None,
        };
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);
        let t_size = self.maybe_label_font_size.unwrap_or(uic.theme.font_size_medium);
        let t_color = self.maybe_label_color.unwrap_or(uic.theme.label_color);

        // Call the `callback` closure if mouse was released
        // on one of the DropDownMenu items.
        match (state, new_state) {
            (State::Open(o_d_state), State::Closed(c_d_state)) => {
                match (o_d_state, c_d_state) {
                    (DrawState::Clicked(idx, _), DrawState::Normal) => {
                        match self.maybe_callback {
                            Some(ref mut callback) => (*callback)(self.selected, idx, (*self.strings)[idx].clone()),
                            None => (),
                        }
                    }, _ => (),
                }
            }, _ => (),
        }

        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let maybe_frame = match frame_w > 0.0 {
            true => Some((frame_w, self.maybe_frame_color.unwrap_or(uic.theme.frame_color))),
            false => None,
        };

        match new_state {

            State::Closed(_) => {
                let rect_state = new_state.as_rect_state();
                let text = match sel {
                    Some(idx) => &(*self.strings)[idx][..],
                    None => match self.maybe_label {
                        Some(text) => text,
                        None => &(*self.strings)[0][..],
                    },
                };
                rectangle::draw_with_centered_label(
                    uic.win_w, uic.win_h, graphics, uic, rect_state,
                    self.pos, self.dim, maybe_frame, color,
                    text, t_size, t_color
                )
            },

            State::Open(draw_state) => {
                for (i, string) in self.strings.iter().enumerate() {
                    let rect_state = match sel {
                        None => {
                            match draw_state {
                                DrawState::Normal => rectangle::State::Normal,
                                DrawState::Highlighted(idx, _) => {
                                    if i == idx { rectangle::State::Highlighted }
                                    else { rectangle::State::Normal }
                                },
                                DrawState::Clicked(idx, _) => {
                                    if i == idx { rectangle::State::Clicked }
                                    else { rectangle::State::Normal }
                                },
                            }
                        },
                        Some(sel_idx) => {
                            if sel_idx == i { rectangle::State::Clicked }
                            else {
                                match draw_state {
                                    DrawState::Normal => rectangle::State::Normal,
                                    DrawState::Highlighted(idx, _) => {
                                        if i == idx { rectangle::State::Highlighted }
                                        else { rectangle::State::Normal }
                                    },
                                    DrawState::Clicked(idx, _) => {
                                        if i == idx { rectangle::State::Clicked }
                                        else { rectangle::State::Normal }
                                    },
                                }
                            }
                        },
                    };
                    let idx_y = self.dim[1] * i as f64 - i as f64 * frame_w;
                    let idx_pos = vec2_add(self.pos, [0.0, idx_y]);
                    rectangle::draw_with_centered_label(
                        uic.win_w, uic.win_h, graphics, uic, rect_state, idx_pos,
                        self.dim, maybe_frame, color, &string,
                        t_size, t_color
                    )
                }
            },

        }

        set_state(uic, self.ui_id, Widget::DropDownList(new_state), self.pos, self.dim);

    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use rustc_serialize::json::{self, Json};

use git2::build::RepoBuilder;
use git2::{Object, Oid, Reference, Delta, DiffFormat, ObjectType, Tree, Repository, ErrorClass,
    Error as GitError};
use std::str;

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";
static LAST_SEEN_REFNAME: &'static str = "crates-index-diff_last-seen";
static EMPTY_TREE_HASH: &'static str = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";

pub struct Index {
    repo: Repository,
}

#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)]
pub enum ChangeType {
    Added,
    Yanked,
}

#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)]
pub struct Crate {
    pub name: String,
    pub state: ChangeType,
    pub version: String,
}

#[derive(PartialOrd, PartialEq, Debug)]
enum CrateDecodeError {
    InvalidTopology {
        json: Json
    },
    MissingFieldError {
        object: json::Object,
        field: &'static str,
    },
    StringExpected {
        json: Json
    },
    BoolExpected {
        json: Json
    },
}

use self::CrateDecodeError::*;

impl Crate {
    fn from_json(value: Json) -> Result<Crate, CrateDecodeError> {
        fn extract<'a>(o: &'a json::Object,
                       field: &'static str)
                       -> Result<&'a Json, CrateDecodeError> {
            o.get(field).ok_or_else(|| {
                MissingFieldError {
                    object: o.clone(),
                    field: field,
                }
            })
        }

        fn into_string(value: &Json) -> Result<String, CrateDecodeError> {
            value.as_string()
                 .ok_or_else(|| StringExpected { json: value.clone() })
                 .map(Into::into)
        }

        fn into_bool(value: &Json) -> Result<bool, CrateDecodeError> {
            value.as_boolean()
                 .ok_or_else(|| BoolExpected { json: value.clone() })
                 .map(Into::into)
        }

        value.as_object().ok_or_else(|| InvalidTopology { json: value.clone() }).and_then(|o| {
            extract(o, "name")
                .and_then(into_string)
                .and_then(|name| {
                    extract(o, "vers")
                        .and_then(into_string)
                        .and_then(|version| {
                            extract(o, "yanked").and_then(into_bool).map(|yanked| {
                                Crate {
                                    name: name,
                                    state: if yanked {
                                        ChangeType::Yanked
                                    } else {
                                        ChangeType::Added
                                    },
                                    version: version,
                                }
                            })
                        })
                })
        })
    }
}

impl Index {
    pub fn repository(&self) -> &Repository {
        &self.repo
    }

    pub fn last_seen_reference(&self) -> Result<Reference, GitError> {
        self.repo.find_reference(LAST_SEEN_REFNAME)
    }

    pub fn at_path<P>(path: P) -> Result<Index, GitError>
        where P: AsRef<Path>
    {
        let repo =
        Repository::open(path.as_ref()).or_else(|err| if err.class() == ErrorClass::Repository {
            RepoBuilder::new().bare(true).clone(INDEX_GIT_URL, path.as_ref())
        } else {
            Err(err)
        })?;

        Ok(Index { repo: repo })
    }

    pub fn fetch_changes(&self) -> Result<Vec<Crate>, GitError> {
        let from = self.last_seen_reference()
                       .and_then(|r| {
                           r.target().ok_or_else(|| {
                               GitError::from_str("last-seen reference did not have a valid target")
                           })
                       })
                       .or_else(|_| Oid::from_str(EMPTY_TREE_HASH))?;
        self.changes("master~1", "master")
    }

    pub fn changes<S1, S2>(&self, from: S1, to: S2) -> Result<Vec<Crate>, GitError>
        where S1: AsRef<str>,
              S2: AsRef<str>
    {
        self.changes_from_objects(self.repo.revparse_single(from.as_ref())?, self.repo.revparse_single(to.as_ref())?)
    }

    pub fn changes_from_objects(&self, from: Object, to: Object) -> Result<Vec<Crate>, GitError> {
        fn into_tree<'a>(repo: &'a Repository, obj: Object) -> Result<Tree<'a>, GitError> {
            repo.find_tree(match obj.kind() {
                Some(ObjectType::Commit) => obj.as_commit().expect("object of kind commit yields commit").tree_id(),
                _ => /* let it possibly fail later */ obj.id()
            })
        }
        let diff = self.repo.diff_tree_to_tree(Some(&into_tree(&self.repo, from)?), Some(&into_tree(&self.repo, to)?), None)?;
        let mut res = Vec::new();
        diff.print(DiffFormat::Patch, |delta, _, diffline| -> bool {
            if !match delta.status() {
                Delta::Added | Delta::Modified => true,
                _ => false,
            } {
                return true;
            }

            let content = match str::from_utf8(diffline.content()) {
                Ok(c) => c,
                Err(_) => return true,
            };
            if diffline.origin() != '+' {
                return true;
            }

            if let Some(c) = Json::from_str(content)
                .ok()
                .and_then(|json| Crate::from_json(json).ok()) {
                res.push(c)
            }
            return true;
        })?;

        Ok(res)
    }
}
<commit_msg>imp(index): attempt of fetch_changes implementation<commit_after>use std::path::Path;
use rustc_serialize::json::{self, Json};

use git2::build::RepoBuilder;
use git2::{Object, Oid, Reference, Delta, DiffFormat, ObjectType, Tree, Repository, ErrorClass,
           Error as GitError};
use std::str;

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";
static LAST_SEEN_REFNAME: &'static str = "crates-index-diff_last-seen";
static EMPTY_TREE_HASH: &'static str = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";

pub struct Index {
    repo: Repository,
}

#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)]
pub enum ChangeType {
    Added,
    Yanked,
}

#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)]
pub struct Crate {
    pub name: String,
    pub state: ChangeType,
    pub version: String,
}

#[derive(PartialOrd, PartialEq, Debug)]
enum CrateDecodeError {
    InvalidTopology { json: Json },
    MissingFieldError {
        object: json::Object,
        field: &'static str,
    },
    StringExpected { json: Json },
    BoolExpected { json: Json },
}

use self::CrateDecodeError::*;

impl Crate {
    fn from_json(value: Json) -> Result<Crate, CrateDecodeError> {
        fn extract<'a>(o: &'a json::Object,
                       field: &'static str)
                       -> Result<&'a Json, CrateDecodeError> {
            o.get(field).ok_or_else(|| {
                MissingFieldError {
                    object: o.clone(),
                    field: field,
                }
            })
        }

        fn into_string(value: &Json) -> Result<String, CrateDecodeError> {
            value.as_string()
                .ok_or_else(|| StringExpected { json: value.clone() })
                .map(Into::into)
        }

        fn into_bool(value: &Json) -> Result<bool, CrateDecodeError> {
            value.as_boolean()
                .ok_or_else(|| BoolExpected { json: value.clone() })
                .map(Into::into)
        }

        value.as_object().ok_or_else(|| InvalidTopology { json: value.clone() }).and_then(|o| {
            extract(o, "name")
                .and_then(into_string)
                .and_then(|name| {
                    extract(o, "vers")
                        .and_then(into_string)
                        .and_then(|version| {
                            extract(o, "yanked").and_then(into_bool).map(|yanked| {
                                Crate {
                                    name: name,
                                    state: if yanked {
                                        ChangeType::Yanked
                                    } else {
                                        ChangeType::Added
                                    },
                                    version: version,
                                }
                            })
                        })
                })
        })
    }
}

impl Index {
    pub fn repository(&self) -> &Repository {
        &self.repo
    }

    pub fn last_seen_reference(&self) -> Result<Reference, GitError> {
        self.repo.find_reference(LAST_SEEN_REFNAME)
    }

    pub fn at_path<P>(path: P) -> Result<Index, GitError>
        where P: AsRef<Path>
    {
        let repo =
            Repository::open(path.as_ref()).or_else(|err| if err.class() == ErrorClass::Repository {
                    RepoBuilder::new().bare(true).clone(INDEX_GIT_URL, path.as_ref())
                } else {
                    Err(err)
                })?;

        Ok(Index { repo: repo })
    }

    pub fn fetch_changes(&self) -> Result<Vec<Crate>, GitError> {
        let from = self.last_seen_reference()
            .and_then(|r| {
                r.target().ok_or_else(|| {
                    GitError::from_str("last-seen reference did not have a valid target")
                })
            })
            .or_else(|_| Oid::from_str(EMPTY_TREE_HASH))?;
        let to = {
            self.repo
                .find_remote("origin")
                .and_then(|mut r| {
                    r.fetch(&["refs/heads/*:refs/remotes/origin/*"], None, None)
                        .and_then(|_| {
                            self.repo
                                .refname_to_id("refs/remotes/origin/master")
                                .and_then(|oid| {
                                    self.last_seen_reference()
                                        .or_else(|_err| {
                                            self.repo.reference(LAST_SEEN_REFNAME,
                                                                oid,
                                                                true,
                                                                "create a tracking ref for \
                                                                 crates-index-diff")
                                        })
                                        .and_then(|mut seen_ref| seen_ref.set_target(oid, ""))
                                })
                                .and_then(|seen_ref| {
                                    seen_ref.target().ok_or_else(|| {
                                        GitError::from_str("could not obtain target of tracking \
                                                            ref")
                                    })
                                })
                        })
                })?
        };
        self.changes_from_objects(self.repo.find_object(from, None)?,
                                  self.repo.find_object(to, None)?)
    }

    pub fn changes<S1, S2>(&self, from: S1, to: S2) -> Result<Vec<Crate>, GitError>
        where S1: AsRef<str>,
              S2: AsRef<str>
    {
        self.changes_from_objects(self.repo.revparse_single(from.as_ref())?,
                                  self.repo.revparse_single(to.as_ref())?)
    }

    pub fn changes_from_objects(&self, from: Object, to: Object) -> Result<Vec<Crate>, GitError> {
        fn into_tree<'a>(repo: &'a Repository, obj: Object) -> Result<Tree<'a>, GitError> {
            repo.find_tree(match obj.kind() {
                Some(ObjectType::Commit)
                    => obj.as_commit().expect("object of kind commit yields commit").tree_id(),
                _ => /* let it possibly fail later */ obj.id()
            })
        }
        let diff = self.repo
            .diff_tree_to_tree(Some(&into_tree(&self.repo, from)?),
                               Some(&into_tree(&self.repo, to)?),
                               None)?;
        let mut res = Vec::new();
        diff.print(DiffFormat::Patch, |delta, _, diffline| -> bool {
                if !match delta.status() {
                    Delta::Added | Delta::Modified => true,
                    _ => false,
                } {
                    return true;
                }

                let content = match str::from_utf8(diffline.content()) {
                    Ok(c) => c,
                    Err(_) => return true,
                };
                if diffline.origin() != '+' {
                    return true;
                }

                if let Some(c) = Json::from_str(content)
                    .ok()
                    .and_then(|json| Crate::from_json(json).ok()) {
                    res.push(c)
                }
                return true;
            })?;

        Ok(res)
    }
}
<|endoftext|>


<commit_before>extern crate csv;
extern crate chrono;

use std::collections::{HashMap, VecDeque};
use std::path::Path;
use config::Config;
use feed::Feed;
use util::lerp;
use self::chrono::{UTC, Timelike};

const MOVING_AVG_SIZE: usize = 5;

#[derive(Debug)]
pub struct Average {
    pub current: f32,
    pub last:    f32,
    pub moving:  VecDeque<f32>,
}

impl Average {
    pub fn new(average: f32) -> Average {
        let mut moving = VecDeque::with_capacity(MOVING_AVG_SIZE + 1);

        if average > 0. {
            moving.push_back(average);
        }

        Average {
            current:    average,
            last:       average,
            moving:     moving,
        }
    }

    pub fn update(&mut self, value: f32) {
        self.moving.push_back(value);

        if self.moving.len() > MOVING_AVG_SIZE {
            self.moving.pop_front();
        }

        self.last    = self.current;
        self.current = self.moving.iter().sum::<f32>() / self.moving.len() as f32;
    }
}

#[derive(Debug)]
pub struct ListenerData {
    pub average:      Average,
    pub unskewed_avg: Option<f32>,
    pub hourly:       [f32; 24],
    spike_count:      u8,
}

impl ListenerData {
    pub fn new(listeners: f32, hourly: [f32; 24]) -> ListenerData {
        ListenerData {
            average:      Average::new(listeners),
            unskewed_avg: None,
            hourly:       hourly,
            spike_count:  0,
        }
    }

    pub fn update(&mut self, config: &Config, hour: usize, listeners: f32, has_spiked: bool) {
        self.average.update(listeners);
        self.update_hourly(&config, hour, has_spiked);
    }

    fn update_hourly(&mut self, config: &Config, hour: usize, has_spiked: bool) {
        self.spike_count = if has_spiked {
            self.spike_count + 1
        } else {
            0
        };

        match self.unskewed_avg {
            Some(unskewed) => {
                // Remove the unskewed average when the current average is close
                if self.average.current - unskewed < unskewed * config.unskewed_avg.reset_pcnt {
                    self.unskewed_avg = None;
                    self.hourly[hour] = self.average.current;
                } else {
                    // Slowly adjust the unskewed average to adjust to any natural listener increases
                    let new_val = lerp(unskewed,
                                        self.average.current,
                                        config.unskewed_avg.adjust_pcnt);

                    self.unskewed_avg = Some(new_val);
                    self.hourly[hour] = new_val;
                }
            },
            None => {
                if has_spiked && self.spike_count > config.unskewed_avg.spikes_required
                    && self.average.last > 0. {
                    // Use the current average instead of the last average to allow
                    // the saved average to catch up to natural listener changes
                    self.unskewed_avg = Some(self.average.current);
                }

                self.hourly[hour] = self.average.current;
            }
        }
    }

    pub fn has_spiked(&self, config: &Config, feed: &Feed) -> bool {
        if self.average.current == 0. {
            return false
        }

        let spike = config.feed_settings
                        .iter()
                        .find(|setting| setting.id == feed.id)
                        .map(|setting| &setting.spike)
                        .unwrap_or(&config.spike);

        let listeners = feed.listeners as f32;

        // If a feed has a low number of listeners, make the threshold higher to
        // make the calculation less sensitive to very small listener jumps
        let threshold = if listeners < 50. {
            spike.jump + (50. - listeners) * config.spike.low_listener_increase
        } else {
            // Otherwise, decrease the threshold by a factor of how fast the feed's listeners are rising
            // to make it easier for the feed to show up in an update
            let pcnt     = config.spike.high_listener_dec;
            let per_pcnt = config.spike.high_listener_dec_every;

            spike.jump - (self.get_average_delta(listeners) / per_pcnt * pcnt).min(spike.jump - 0.01)
        };

        if cfg!(feature = "show-feed-info") {
            print!(" THR: {}", threshold);
        }

        (listeners - self.average.current) >= listeners * threshold
    }

    pub fn get_average_delta(&self, listeners: f32) -> f32 {
        let sub = match self.unskewed_avg {
            Some(unskewed) => unskewed,
            None => self.average.current,
        };

        listeners - sub
    }
}

pub type AverageMap = HashMap<u32, ListenerData>;

pub fn load_averages(path: &Path) -> Result<AverageMap, csv::Error> {
    let mut avgs   = HashMap::new();
    let mut reader = csv::Reader::from_file(path)?
        .has_headers(false);

    let hour = UTC::now().hour() as usize;

    for record in reader.decode() {
        let (id, avg): (_, [_; 24]) = record?;
        avgs.insert(id, ListenerData::new(avg[hour], avg));
    }

    Ok(avgs)
}

pub fn save_averages(path: &Path, averages: &AverageMap) -> Result<(), csv::Error> {
    let mut writer = csv::Writer::from_file(path)?;

    for (id, data) in averages {
        let hourly = data.hourly
            .iter()
            .map(|&v| v as i32)
            .collect::<Vec<_>>();

        writer.encode((id, hourly))?;
    }

    Ok(())
}<commit_msg>Use feed-based percentages instead of global ones (woops)<commit_after>extern crate csv;
extern crate chrono;

use std::collections::{HashMap, VecDeque};
use std::path::Path;
use config::Config;
use feed::Feed;
use util::lerp;
use self::chrono::{UTC, Timelike};

const MOVING_AVG_SIZE: usize = 5;

#[derive(Debug)]
pub struct Average {
    pub current: f32,
    pub last:    f32,
    pub moving:  VecDeque<f32>,
}

impl Average {
    pub fn new(average: f32) -> Average {
        let mut moving = VecDeque::with_capacity(MOVING_AVG_SIZE + 1);

        if average > 0. {
            moving.push_back(average);
        }

        Average {
            current:    average,
            last:       average,
            moving:     moving,
        }
    }

    pub fn update(&mut self, value: f32) {
        self.moving.push_back(value);

        if self.moving.len() > MOVING_AVG_SIZE {
            self.moving.pop_front();
        }

        self.last    = self.current;
        self.current = self.moving.iter().sum::<f32>() / self.moving.len() as f32;
    }
}

#[derive(Debug)]
pub struct ListenerData {
    pub average:      Average,
    pub unskewed_avg: Option<f32>,
    pub hourly:       [f32; 24],
    spike_count:      u8,
}

impl ListenerData {
    pub fn new(listeners: f32, hourly: [f32; 24]) -> ListenerData {
        ListenerData {
            average:      Average::new(listeners),
            unskewed_avg: None,
            hourly:       hourly,
            spike_count:  0,
        }
    }

    pub fn update(&mut self, config: &Config, hour: usize, listeners: f32, has_spiked: bool) {
        self.average.update(listeners);
        self.update_hourly(&config, hour, has_spiked);
    }

    fn update_hourly(&mut self, config: &Config, hour: usize, has_spiked: bool) {
        self.spike_count = if has_spiked {
            self.spike_count + 1
        } else {
            0
        };

        match self.unskewed_avg {
            Some(unskewed) => {
                // Remove the unskewed average when the current average is close
                if self.average.current - unskewed < unskewed * config.unskewed_avg.reset_pcnt {
                    self.unskewed_avg = None;
                    self.hourly[hour] = self.average.current;
                } else {
                    // Slowly adjust the unskewed average to adjust to any natural listener increases
                    let new_val = lerp(unskewed,
                                        self.average.current,
                                        config.unskewed_avg.adjust_pcnt);

                    self.unskewed_avg = Some(new_val);
                    self.hourly[hour] = new_val;
                }
            },
            None => {
                if has_spiked && self.spike_count > config.unskewed_avg.spikes_required
                    && self.average.last > 0. {
                    // Use the current average instead of the last average to allow
                    // the saved average to catch up to natural listener changes
                    self.unskewed_avg = Some(self.average.current);
                }

                self.hourly[hour] = self.average.current;
            }
        }
    }

    pub fn has_spiked(&self, config: &Config, feed: &Feed) -> bool {
        if self.average.current == 0. {
            return false
        }

        let spike = config.feed_settings
                        .iter()
                        .find(|setting| setting.id == feed.id)
                        .map(|setting| &setting.spike)
                        .unwrap_or(&config.spike);

        let listeners = feed.listeners as f32;

        // If a feed has a low number of listeners, make the threshold higher to
        // make the calculation less sensitive to very small listener jumps
        let threshold = if listeners < 50. {
            spike.jump + (50. - listeners) * spike.low_listener_increase
        } else {
            // Otherwise, decrease the threshold by a factor of how fast the feed's listeners are rising
            // to make it easier for the feed to show up in an update
            let pcnt     = spike.high_listener_dec;
            let per_pcnt = spike.high_listener_dec_every;

            spike.jump - (self.get_average_delta(listeners) / per_pcnt * pcnt).min(spike.jump - 0.01)
        };

        if cfg!(feature = "show-feed-info") {
            print!(" THR: {}", threshold);
        }

        (listeners - self.average.current) >= listeners * threshold
    }

    pub fn get_average_delta(&self, listeners: f32) -> f32 {
        let sub = match self.unskewed_avg {
            Some(unskewed) => unskewed,
            None => self.average.current,
        };

        listeners - sub
    }
}

pub type AverageMap = HashMap<u32, ListenerData>;

pub fn load_averages(path: &Path) -> Result<AverageMap, csv::Error> {
    let mut avgs   = HashMap::new();
    let mut reader = csv::Reader::from_file(path)?
        .has_headers(false);

    let hour = UTC::now().hour() as usize;

    for record in reader.decode() {
        let (id, avg): (_, [_; 24]) = record?;
        avgs.insert(id, ListenerData::new(avg[hour], avg));
    }

    Ok(avgs)
}

pub fn save_averages(path: &Path, averages: &AverageMap) -> Result<(), csv::Error> {
    let mut writer = csv::Writer::from_file(path)?;

    for (id, data) in averages {
        let hourly = data.hourly
            .iter()
            .map(|&v| v as i32)
            .collect::<Vec<_>>();

        writer.encode((id, hourly))?;
    }

    Ok(())
}<|endoftext|>


<commit_before>pub mod level;

use std::path::Path;
use std::rc::Rc;
use std::cell::RefCell;
use engine::graphics::{Graphics};

use nalgebra::{Vector2};
use ncollide_geometry::shape::{ShapeHandle2, Ball};
use glium::VertexBuffer;

use engine::Engine;
use engine::util::{HashMap};
use engine::graphics::SpriteVertex;
use game::object::Object;
use game::object::level::LevelEvent;

const SPRITE_VERT_SHADER: &'static str = r#"
    #version 140

    in vec2 position;
    in mat4 transform;
    in vec2 tex_coords;

    out vec2 v_tex_coords;

    void main() {
        gl_Position = vec4(position, 0.0, 1.0) * transform;
        v_tex_coords = tex_coords;
    }
"#;

const SPRITE_FRAG_SHADER: &'static str = r#"
    #version 140

    uniform sampler2D tex;
    in vec2 v_tex_coords;
    out vec4 color;

    void main() {
        color = texture(tex, v_tex_coords);
    }
"#;

pub fn load_assets(engine: &mut Engine<Object>) {
    println!("Loading assets!");
    load_char(engine);
    load_bullet(engine);
    load_sound(engine);
    load_fonts(engine);
}

fn load_level(engine: &mut Engine<Object>) -> Result<HashMap<String, Vec<LevelEvent>>, String> {
    match self::level::load_level_file(engine.graphics.clone(), "assets/level.toml") {
        Ok((_, _, _, events)) => Ok(events),
        Err(e) => Err(e)
    }
}

fn load_fonts(engine: &mut Engine<Object>) {
    println!("Loading fonts!");
    engine.graphics.borrow_mut().load_font(1, "assets/fonts/OxygenMono-Regular.ttf");
}

fn load_sound(engine: &mut Engine<Object>) {
    println!("Loading songs!");
    let path = Path::new("assets/audio/main.mp3");
    engine.audio.borrow_mut().load(1, path);
}

pub fn make_sprite(graphics: Rc<RefCell<Graphics>>,
               texture: &str,
               half_extents: Vector2<f32>,
               amount: usize,
               shape: ShapeHandle2<f32>)
               -> usize {
    let vert_shader = SPRITE_VERT_SHADER;
    let frag_shader = SPRITE_FRAG_SHADER;
    let vbo = make_vbo(graphics.clone(), half_extents);
    let mut gfx = graphics.borrow_mut();
    let texture = gfx.load_texture(&texture[..]);
    let id = gfx.sprite_amount() + 1;
    gfx.new_sprite(id,
                   vert_shader,
                   frag_shader,
                   vbo,
                   Some(texture),
                   amount,
                   Some(shape));
    id
}

fn make_vbo(graphics: Rc<RefCell<Graphics>>, half_extents: Vector2<f32>) -> VertexBuffer<SpriteVertex> {
    let half_extents = half_extents / graphics.borrow().scaler;
    let vertices = &[SpriteVertex {
                         position: [-1.0 * half_extents.x, -1.0 * half_extents.y],
                         tex_coords: [0.0, 0.0],
                     },
                     SpriteVertex {
                         position: [-1.0 * half_extents.x, half_extents.y],
                         tex_coords: [0.0, 1.0],
                     },
                     SpriteVertex {
                         position: [half_extents.x, half_extents.y],
                         tex_coords: [1.0, 1.0],
                     },
                     SpriteVertex {
                         position: [half_extents.x, -1.0 * half_extents.y],
                         tex_coords: [1.0, 0.0],
                     }];
    let gfx = graphics.borrow();
    gfx.make_sprite_vbo(vertices)
}

fn load_char(engine: &mut Engine<Object>) {
    let shape = ShapeHandle2::new(Ball::new(5.0));
    make_sprite(engine.graphics.clone(),
                "assets/sprites/sakuya.png",
                Vector2::new(25.0, 50.0),
                1,
                shape);
}

fn load_bullet(engine: &mut Engine<Object>) {
    let shape = ShapeHandle2::new(Ball::new(5.0));
    make_sprite(engine.graphics.clone(),
                "assets/sprites/bullet.png",
                Vector2::new(2.5, 2.5),
                300,
                shape);
}
<commit_msg>Downgrade GLSL to 1.30 for better compat<commit_after>pub mod level;

use std::path::Path;
use std::rc::Rc;
use std::cell::RefCell;
use engine::graphics::{Graphics};

use nalgebra::{Vector2};
use ncollide_geometry::shape::{ShapeHandle2, Ball};
use glium::VertexBuffer;

use engine::Engine;
use engine::util::{HashMap};
use engine::graphics::SpriteVertex;
use game::object::Object;
use game::object::level::LevelEvent;

const SPRITE_VERT_SHADER: &'static str = r#"
    #version 130

    in vec2 position;
    in mat4 transform;
    in vec2 tex_coords;

    out vec2 v_tex_coords;

    void main() {
        gl_Position = vec4(position, 0.0, 1.0) * transform;
        v_tex_coords = tex_coords;
    }
"#;

const SPRITE_FRAG_SHADER: &'static str = r#"
    #version 130

    uniform sampler2D tex;
    in vec2 v_tex_coords;
    out vec4 color;

    void main() {
        color = texture(tex, v_tex_coords);
    }
"#;

pub fn load_assets(engine: &mut Engine<Object>) {
    println!("Loading assets!");
    load_char(engine);
    load_bullet(engine);
    load_sound(engine);
    load_fonts(engine);
}

fn load_level(engine: &mut Engine<Object>) -> Result<HashMap<String, Vec<LevelEvent>>, String> {
    match self::level::load_level_file(engine.graphics.clone(), "assets/level.toml") {
        Ok((_, _, _, events)) => Ok(events),
        Err(e) => Err(e)
    }
}

fn load_fonts(engine: &mut Engine<Object>) {
    println!("Loading fonts!");
    engine.graphics.borrow_mut().load_font(1, "assets/fonts/OxygenMono-Regular.ttf");
}

fn load_sound(engine: &mut Engine<Object>) {
    println!("Loading songs!");
    let path = Path::new("assets/audio/main.mp3");
    engine.audio.borrow_mut().load(1, path);
}

pub fn make_sprite(graphics: Rc<RefCell<Graphics>>,
               texture: &str,
               half_extents: Vector2<f32>,
               amount: usize,
               shape: ShapeHandle2<f32>)
               -> usize {
    let vert_shader = SPRITE_VERT_SHADER;
    let frag_shader = SPRITE_FRAG_SHADER;
    let vbo = make_vbo(graphics.clone(), half_extents);
    let mut gfx = graphics.borrow_mut();
    let texture = gfx.load_texture(&texture[..]);
    let id = gfx.sprite_amount() + 1;
    gfx.new_sprite(id,
                   vert_shader,
                   frag_shader,
                   vbo,
                   Some(texture),
                   amount,
                   Some(shape));
    id
}

fn make_vbo(graphics: Rc<RefCell<Graphics>>, half_extents: Vector2<f32>) -> VertexBuffer<SpriteVertex> {
    let half_extents = half_extents / graphics.borrow().scaler;
    let vertices = &[SpriteVertex {
                         position: [-1.0 * half_extents.x, -1.0 * half_extents.y],
                         tex_coords: [0.0, 0.0],
                     },
                     SpriteVertex {
                         position: [-1.0 * half_extents.x, half_extents.y],
                         tex_coords: [0.0, 1.0],
                     },
                     SpriteVertex {
                         position: [half_extents.x, half_extents.y],
                         tex_coords: [1.0, 1.0],
                     },
                     SpriteVertex {
                         position: [half_extents.x, -1.0 * half_extents.y],
                         tex_coords: [1.0, 0.0],
                     }];
    let gfx = graphics.borrow();
    gfx.make_sprite_vbo(vertices)
}

fn load_char(engine: &mut Engine<Object>) {
    let shape = ShapeHandle2::new(Ball::new(5.0));
    make_sprite(engine.graphics.clone(),
                "assets/sprites/sakuya.png",
                Vector2::new(25.0, 50.0),
                1,
                shape);
}

fn load_bullet(engine: &mut Engine<Object>) {
    let shape = ShapeHandle2::new(Ball::new(5.0));
    make_sprite(engine.graphics.clone(),
                "assets/sprites/bullet.png",
                Vector2::new(2.5, 2.5),
                300,
                shape);
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::sync::atomic::Ordering;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::space::Space;
use gc::swiper::card::CardTable;
use gc::swiper::crossing::CrossingMap;
use gc::swiper::old::OldGen;
use gc::swiper::Region;
use gc::swiper::young::YoungGen;
use mem;
use object::Obj;
use os;

pub struct FullCollector<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    rootset: &'a [IndirectObj],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    marking_bitmap: MarkingBitmap,
    fwd_table: HashMap<Address, Address>,
    old_top: Address,
}

impl<'a, 'ast> FullCollector<'a, 'ast> {
    pub fn new(
        ctxt: &'a SemContext<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [IndirectObj],
    ) -> FullCollector<'a, 'ast> {
        let marking_bitmap = MarkingBitmap::new(heap.clone());

        FullCollector {
            ctxt: ctxt,
            heap: heap,
            young: young,
            old: old,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            marking_bitmap: marking_bitmap,
            fwd_table: HashMap::new(),
            old_top: Address::null(),
        }
    }

    pub fn collect(&mut self) {
        self.mark_live();
        self.compute_forward();
        self.update_references();
        self.relocate();

        self.old.free.store(self.old_top.to_usize(), Ordering::SeqCst);
    }

    fn mark_live(&mut self) {
        let mut marking_stack: Vec<Address> = Vec::new();

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if root_ptr.is_null() {
                // do nothing

            } else if self.heap.contains(root_ptr) {
                marking_stack.push(root_ptr);

            } else {
                debug_assert!(self.perm_space.contains(root_ptr));
            }
        }

        while marking_stack.len() > 0 {
            let object_addr = marking_stack.pop().expect("stack already empty");
            let object = unsafe { &mut *object_addr.to_mut_ptr::<Obj>() };

            object.visit_reference_fields(|field| {
                let field_addr = Address::from_ptr(field.get());

                if field_addr.is_null() {
                    // do nothing

                } else if self.heap.contains(field_addr) {
                    if !self.is_marked_addr(field_addr) {
                        marking_stack.push(field_addr);
                        self.mark(field_addr);
                    }

                } else {
                    debug_assert!(self.perm_space.contains(field_addr));
                }
            });
        }
    }

    fn compute_forward(&mut self) {
        let used_region = self.old.used_region();

        let mut scan = used_region.start;
        let end = used_region.end;

        let mut fwd = self.old.total.start;

        while scan < end {
            let obj = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let obj_size = obj.size();

            if self.is_marked(obj) {
                self.fwd_table.insert(scan, fwd);
                fwd = fwd.offset(obj_size);
            }

            scan = scan.offset(obj_size);
        }

        self.old_top = fwd;
    }

    fn update_references(&mut self) {
        let used_region = self.old.used_region();

        let mut scan = used_region.start;
        let end = used_region.end;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            if self.is_marked(object) {
                object.visit_reference_fields(|field| {
                    let field_addr = Address::from_ptr(field.get());

                    if self.heap.contains(field_addr) {
                        let fwd_addr = self.fwd_table.get(&field_addr).expect("forwarding address not found.");
                        field.set(fwd_addr.to_mut_ptr());
                    }
                });
            }

            scan = scan.offset(object_size);
        }
    }

    fn relocate(&mut self) {
        let used_region = self.old.used_region();

        let mut scan = used_region.start;
        let end = used_region.end;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            if self.is_marked(object) {
                let &dest = self.fwd_table.get(&scan).expect("forwarding address not found.");
                object.copy_to(dest, object_size);
            }

            scan = scan.offset(object_size);
        }
    }

    fn is_marked(&self, obj: &Obj) -> bool {
        self.marking_bitmap.is_marked(Address::from_ptr(obj as *const _))
    }

    fn is_marked_addr(&self, addr: Address) -> bool {
        self.marking_bitmap.is_marked(addr)
    }

    fn mark(&mut self, addr: Address) {
        self.marking_bitmap.mark(addr);
    }
}

pub struct MarkingBitmap {
    heap: Region,
    bitmap: Region,
}

impl MarkingBitmap {
    pub fn new(heap: Region) -> MarkingBitmap {
        let bitmap_size = mem::page_align(heap.size() / mem::ptr_width_usize() / 8);
        let bitmap_start = Address::from_ptr(os::mmap(bitmap_size, os::Writable));

        if bitmap_start.is_null() {
            panic!("could not allocate marking bitmap.");
        }

        MarkingBitmap {
            heap: heap,
            bitmap: Region::new(bitmap_start, bitmap_start.offset(bitmap_size)),
        }
    }

    pub fn mark(&mut self, addr: Address) {
        let (byte_offset, bit_offset) = self.mark_offset(addr);

        let byte = self.mark_byte(byte_offset);
        let modified_byte = byte | (1 << bit_offset);
        self.set_mark_byte(byte_offset, modified_byte);
    }

    pub fn is_marked(&self, addr: Address) -> bool {
        let (byte_offset, bit_offset) = self.mark_offset(addr);
        let byte = self.mark_byte(byte_offset);

        byte & (1 << bit_offset) != 0
    }

    fn mark_offset(&self, addr: Address) -> (usize, u8) {
        debug_assert!(self.heap.contains(addr));
        let offset = addr.offset_from(self.heap.start) / mem::ptr_width_usize();
        let byte = offset / 8;
        let bit = offset % 8;

        (byte, bit as u8)
    }

    fn mark_byte(&self, offset: usize) -> u8 {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_ptr()
        }
    }

    fn set_mark_byte(&self, offset: usize, val: u8) {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_mut_ptr() = val;
        }
    }
}

impl Drop for MarkingBitmap {
    fn drop(&mut self) {
        os::munmap(self.bitmap.start.to_ptr(), self.bitmap.size());
    }
}<commit_msg>swiper: fixed marking all objects in full gc<commit_after>use std::collections::HashMap;
use std::sync::atomic::Ordering;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::space::Space;
use gc::swiper::card::CardTable;
use gc::swiper::crossing::CrossingMap;
use gc::swiper::old::OldGen;
use gc::swiper::Region;
use gc::swiper::young::YoungGen;
use mem;
use object::Obj;
use os;

pub struct FullCollector<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    rootset: &'a [IndirectObj],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    marking_bitmap: MarkingBitmap,
    fwd_table: HashMap<Address, Address>,
    old_top: Address,
}

impl<'a, 'ast> FullCollector<'a, 'ast> {
    pub fn new(
        ctxt: &'a SemContext<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [IndirectObj],
    ) -> FullCollector<'a, 'ast> {
        let marking_bitmap = MarkingBitmap::new(heap.clone());

        FullCollector {
            ctxt: ctxt,
            heap: heap,
            young: young,
            old: old,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            marking_bitmap: marking_bitmap,
            fwd_table: HashMap::new(),
            old_top: Address::null(),
        }
    }

    pub fn collect(&mut self) {
        self.mark_live();
        self.compute_forward();
        self.update_references();
        self.relocate();

        self.old.free.store(self.old_top.to_usize(), Ordering::SeqCst);
    }

    fn mark_live(&mut self) {
        let mut marking_stack: Vec<Address> = Vec::new();

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if self.heap.contains(root_ptr) {
                marking_stack.push(root_ptr);

            } else {
                debug_assert!(root_ptr.is_null() || self.perm_space.contains(root_ptr));
            }
        }

        while marking_stack.len() > 0 {
            let object_addr = marking_stack.pop().expect("stack already empty");
            let object = unsafe { &mut *object_addr.to_mut_ptr::<Obj>() };
            self.mark(object_addr);

            object.visit_reference_fields(|field| {
                let field_addr = Address::from_ptr(field.get());

                if self.heap.contains(field_addr) {
                    if !self.is_marked_addr(field_addr) {
                        marking_stack.push(field_addr);
                        self.mark(field_addr);
                    }

                } else {
                    debug_assert!(field_addr.is_null() || self.perm_space.contains(field_addr));
                }
            });
        }
    }

    fn compute_forward(&mut self) {
        let used_region = self.old.used_region();

        let mut scan = used_region.start;
        let end = used_region.end;

        let mut fwd = self.old.total.start;

        while scan < end {
            let obj = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let obj_size = obj.size();

            if self.is_marked(obj) {
                self.fwd_table.insert(scan, fwd);
                fwd = fwd.offset(obj_size);
            }

            scan = scan.offset(obj_size);
        }

        self.old_top = fwd;
    }

    fn update_references(&mut self) {
        let used_region = self.old.used_region();

        let mut scan = used_region.start;
        let end = used_region.end;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            if self.is_marked(object) {
                object.visit_reference_fields(|field| {
                    let field_addr = Address::from_ptr(field.get());

                    if self.old.contains(field_addr) {
                        let fwd_addr = self.fwd_table.get(&field_addr).expect("forwarding address not found.");
                        field.set(fwd_addr.to_mut_ptr());
                    }
                });
            }

            scan = scan.offset(object_size);
        }

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if self.old.contains(root_ptr) {
                let fwd_addr = self.fwd_table.get(&root_ptr).expect("forwarding address not found.");
                root.set(fwd_addr.to_mut_ptr());
            }
        }
    }

    fn relocate(&mut self) {
        let used_region = self.old.used_region();

        let mut scan = used_region.start;
        let end = used_region.end;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            if self.is_marked(object) {
                let &dest = self.fwd_table.get(&scan).expect("forwarding address not found.");
                object.copy_to(dest, object_size);
            }

            scan = scan.offset(object_size);
        }
    }

    fn is_marked(&self, obj: &Obj) -> bool {
        self.marking_bitmap.is_marked(Address::from_ptr(obj as *const _))
    }

    fn is_marked_addr(&self, addr: Address) -> bool {
        self.marking_bitmap.is_marked(addr)
    }

    fn mark(&mut self, addr: Address) {
        self.marking_bitmap.mark(addr);
    }
}

pub struct MarkingBitmap {
    heap: Region,
    bitmap: Region,
}

impl MarkingBitmap {
    pub fn new(heap: Region) -> MarkingBitmap {
        let bitmap_size = mem::page_align(heap.size() / mem::ptr_width_usize() / 8);
        let bitmap_start = Address::from_ptr(os::mmap(bitmap_size, os::Writable));

        if bitmap_start.is_null() {
            panic!("could not allocate marking bitmap.");
        }

        MarkingBitmap {
            heap: heap,
            bitmap: Region::new(bitmap_start, bitmap_start.offset(bitmap_size)),
        }
    }

    pub fn mark(&mut self, addr: Address) {
        let (byte_offset, bit_offset) = self.mark_offset(addr);

        let byte = self.mark_byte(byte_offset);
        let modified_byte = byte | (1 << bit_offset);
        self.set_mark_byte(byte_offset, modified_byte);
    }

    pub fn is_marked(&self, addr: Address) -> bool {
        let (byte_offset, bit_offset) = self.mark_offset(addr);
        let byte = self.mark_byte(byte_offset);

        byte & (1 << bit_offset) != 0
    }

    fn mark_offset(&self, addr: Address) -> (usize, u8) {
        debug_assert!(self.heap.contains(addr));
        let offset = addr.offset_from(self.heap.start) / mem::ptr_width_usize();
        let byte = offset / 8;
        let bit = offset % 8;

        (byte, bit as u8)
    }

    fn mark_byte(&self, offset: usize) -> u8 {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_ptr()
        }
    }

    fn set_mark_byte(&self, offset: usize, val: u8) {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_mut_ptr() = val;
        }
    }
}

impl Drop for MarkingBitmap {
    fn drop(&mut self) {
        os::munmap(self.bitmap.start.to_ptr(), self.bitmap.size());
    }
}<|endoftext|>


<commit_before>pub mod tag_command;
pub mod autotag;
pub mod update_tags;

pub use self::tag_command::TagCommand;
pub use self::autotag::AutoTagCommand;
pub use self::update_tags::UpdateTagsCommand;

use LalafellBot;
use database::AutotagUser;

use xivdb::error::*;

use discord::model::{UserId, LiveServer, Role, RoleId};

use std::sync::{Arc, Mutex};

lazy_static! {
  // Limbo roles are roles that may or may not be added to the Discord bot state.
  static ref LIMBO_ROLES: Mutex<Vec<Role>> = Mutex::default();
}

pub struct Tagger;

impl Tagger {
  pub fn search_tag(bot: Arc<LalafellBot>, who: UserId, on: &LiveServer, server: &str, character_name: &str, ignore_verified: bool) -> Result<Option<String>> {
    let params = &[
      ("one", "characters"),
      ("strict", "on"),
      ("server|et", server)
    ];

    let res = bot.xivdb.search(character_name, params).chain_err(|| "could not query XIVDB")?;

    let search_chars = res.characters.unwrap().results;
    if search_chars.is_empty() {
      return Ok(Some(format!("Could not find any character by the name {} on {}.", character_name, server)));
    }

    let char_id = match search_chars[0]["id"].as_u64() {
      Some(u) => u,
      None => return Err("character ID was not a u64".into())
    };

    let name = match search_chars[0]["name"].as_str() {
      Some(s) => s,
      None => return Err("character name was not a string".into())
    };

    if name.to_lowercase() != character_name.to_lowercase() {
      return Ok(Some(format!("Could not find any character by the name {} on {}.", character_name, server)));
    }

    Tagger::tag(bot, who, on, char_id, ignore_verified)
  }

  pub fn tag(bot: Arc<LalafellBot>, who: UserId, on: &LiveServer, char_id: u64, ignore_verified: bool) -> Result<Option<String>> {
    let is_verified = match bot.database.read().unwrap().autotags.users.iter().find(|u| u.user_id == who.0 && u.server_id == on.id.0) {
      Some(u) => {
        if u.verification.verified && !ignore_verified && char_id != u.character_id {
          return Ok(Some(format!("{} is verified as {} on {}, so they cannot switch to another account.", who.mention(), u.character, u.server)));
        }
        u.verification.verified
      },
      None => false
    };

    let member = bot.discord.get_member(on.id, who).chain_err(|| "could not get member for tagging")?;

    let character = bot.xivdb.character(char_id).chain_err(|| "could not look up character")?;

    bot.database.write().unwrap().autotags.update_or_add(AutotagUser::new(
      who.0,
      on.id.0,
      character.lodestone_id,
      &character.name,
      &character.server
    ));

    // Get a copy of the roles on the server.
    let mut roles = on.roles.clone();
    // Check for existing limbo roles.
    {
      let limbo = &mut *LIMBO_ROLES.lock().unwrap();
      for role in &roles {
        // If the server has updated to contain the limbo role, remove it.
        if let Some(i) = limbo.iter().position(|x| x.id == role.id) {
          limbo.remove(i);
        }
      }
    }
    // Get a copy of the limbo roles.
    let limbo = LIMBO_ROLES.lock().unwrap().clone();
    // Extend the server roles with the limbo roles.
    roles.extend(limbo);
    let mut created_roles = Vec::new();
    let mut add_roles = Vec::new();
    match roles.iter().find(|x| x.name.to_lowercase() == character.data.race.to_lowercase()) {
      Some(r) => add_roles.push(r),
      None => {
        let role = bot.discord.create_role(on.id, Some(&character.data.race.to_lowercase()), None, None, None, None).chain_err(|| "could not create role")?;
        created_roles.push(role);
      }
    }
    match roles.iter().find(|x| x.name.to_lowercase() == character.data.gender.to_lowercase()) {
      Some(r) => add_roles.push(r),
      None => {
        let role = bot.discord.create_role(on.id, Some(&character.data.gender.to_lowercase()), None, None, None, None).chain_err(|| "could not create role")?;
        created_roles.push(role);
      }
    }
    match roles.iter().find(|x| x.name.to_lowercase() == character.server.to_lowercase()) {
      Some(r) => add_roles.push(r),
      None => {
        let role = bot.discord.create_role(on.id, Some(&character.server.to_lowercase()), None, None, None, None).chain_err(|| "could not create role")?;
        created_roles.push(role);
      }
    }
    if is_verified {
      match roles.iter().find(|x| x.name.to_lowercase() == "verified") {
        Some(r) => add_roles.push(r),
        None => {
          let role = bot.discord.create_role(on.id, Some("Verified"), None, None, None, None).chain_err(|| "could not create role")?;
          created_roles.push(role);
        }
      }
    }

    // If we created any roles, the server may or may not update with them fast enough, so store a copy in the limbo
    // roles.
    {
      let mut limbo = &mut *LIMBO_ROLES.lock().unwrap();
      for created in &created_roles {
        limbo.push(created.clone());
      }
    }

    // Extend the roles to add with the roles we created.
    add_roles.extend(created_roles.iter());
    let all_group_roles: Vec<&String> = bot.config.roles.groups.iter().flat_map(|x| x).collect();
    let keep: Vec<&Role> = roles.iter().filter(|x| member.roles.contains(&x.id)).collect();
    let keep: Vec<&Role> = keep.into_iter().filter(|x| !all_group_roles.contains(&&x.name)).collect();
    let mut role_set: Vec<RoleId> = add_roles.iter().map(|r| r.id).chain(keep.into_iter().map(|r| r.id)).collect();
    role_set.sort();
    role_set.dedup();

    if !role_set.iter().all(|r| member.roles.contains(r)) {
      bot.discord.edit_member_roles(on.id, who, &role_set).chain_err(|| "could not add roles")?;
    }

    // cannot edit nickname of those with a higher role
    let nick = match member.nick {
      Some(n) => n,
      None => Default::default()
    };
    if nick != character.name {
      bot.discord.edit_member(on.id, who, |e| e.nickname(&character.name)).ok();
    }
    Ok(None)
  }
}
<commit_msg>fix: ignore case for autotag roles<commit_after>pub mod tag_command;
pub mod autotag;
pub mod update_tags;

pub use self::tag_command::TagCommand;
pub use self::autotag::AutoTagCommand;
pub use self::update_tags::UpdateTagsCommand;

use LalafellBot;
use database::AutotagUser;

use xivdb::error::*;

use discord::model::{UserId, LiveServer, Role, RoleId};

use std::sync::{Arc, Mutex};

lazy_static! {
  // Limbo roles are roles that may or may not be added to the Discord bot state.
  static ref LIMBO_ROLES: Mutex<Vec<Role>> = Mutex::default();
}

pub struct Tagger;

impl Tagger {
  pub fn search_tag(bot: Arc<LalafellBot>, who: UserId, on: &LiveServer, server: &str, character_name: &str, ignore_verified: bool) -> Result<Option<String>> {
    let params = &[
      ("one", "characters"),
      ("strict", "on"),
      ("server|et", server)
    ];

    let res = bot.xivdb.search(character_name, params).chain_err(|| "could not query XIVDB")?;

    let search_chars = res.characters.unwrap().results;
    if search_chars.is_empty() {
      return Ok(Some(format!("Could not find any character by the name {} on {}.", character_name, server)));
    }

    let char_id = match search_chars[0]["id"].as_u64() {
      Some(u) => u,
      None => return Err("character ID was not a u64".into())
    };

    let name = match search_chars[0]["name"].as_str() {
      Some(s) => s,
      None => return Err("character name was not a string".into())
    };

    if name.to_lowercase() != character_name.to_lowercase() {
      return Ok(Some(format!("Could not find any character by the name {} on {}.", character_name, server)));
    }

    Tagger::tag(bot, who, on, char_id, ignore_verified)
  }

  pub fn tag(bot: Arc<LalafellBot>, who: UserId, on: &LiveServer, char_id: u64, ignore_verified: bool) -> Result<Option<String>> {
    let is_verified = match bot.database.read().unwrap().autotags.users.iter().find(|u| u.user_id == who.0 && u.server_id == on.id.0) {
      Some(u) => {
        if u.verification.verified && !ignore_verified && char_id != u.character_id {
          return Ok(Some(format!("{} is verified as {} on {}, so they cannot switch to another account.", who.mention(), u.character, u.server)));
        }
        u.verification.verified
      },
      None => false
    };

    let member = bot.discord.get_member(on.id, who).chain_err(|| "could not get member for tagging")?;

    let character = bot.xivdb.character(char_id).chain_err(|| "could not look up character")?;

    bot.database.write().unwrap().autotags.update_or_add(AutotagUser::new(
      who.0,
      on.id.0,
      character.lodestone_id,
      &character.name,
      &character.server
    ));

    // Get a copy of the roles on the server.
    let mut roles = on.roles.clone();
    // Check for existing limbo roles.
    {
      let limbo = &mut *LIMBO_ROLES.lock().unwrap();
      for role in &roles {
        // If the server has updated to contain the limbo role, remove it.
        if let Some(i) = limbo.iter().position(|x| x.id == role.id) {
          limbo.remove(i);
        }
      }
    }
    // Get a copy of the limbo roles.
    let limbo = LIMBO_ROLES.lock().unwrap().clone();
    // Extend the server roles with the limbo roles.
    roles.extend(limbo);
    let mut created_roles = Vec::new();
    let mut add_roles = Vec::new();
    match roles.iter().find(|x| x.name.to_lowercase() == character.data.race.to_lowercase()) {
      Some(r) => add_roles.push(r),
      None => {
        let role = bot.discord.create_role(on.id, Some(&character.data.race.to_lowercase()), None, None, None, None).chain_err(|| "could not create role")?;
        created_roles.push(role);
      }
    }
    match roles.iter().find(|x| x.name.to_lowercase() == character.data.gender.to_lowercase()) {
      Some(r) => add_roles.push(r),
      None => {
        let role = bot.discord.create_role(on.id, Some(&character.data.gender.to_lowercase()), None, None, None, None).chain_err(|| "could not create role")?;
        created_roles.push(role);
      }
    }
    match roles.iter().find(|x| x.name.to_lowercase() == character.server.to_lowercase()) {
      Some(r) => add_roles.push(r),
      None => {
        let role = bot.discord.create_role(on.id, Some(&character.server.to_lowercase()), None, None, None, None).chain_err(|| "could not create role")?;
        created_roles.push(role);
      }
    }
    if is_verified {
      match roles.iter().find(|x| x.name.to_lowercase() == "verified") {
        Some(r) => add_roles.push(r),
        None => {
          let role = bot.discord.create_role(on.id, Some("Verified"), None, None, None, None).chain_err(|| "could not create role")?;
          created_roles.push(role);
        }
      }
    }

    // If we created any roles, the server may or may not update with them fast enough, so store a copy in the limbo
    // roles.
    {
      let mut limbo = &mut *LIMBO_ROLES.lock().unwrap();
      for created in &created_roles {
        limbo.push(created.clone());
      }
    }

    // Extend the roles to add with the roles we created.
    add_roles.extend(created_roles.iter());
    let all_group_roles: Vec<String> = bot.config.roles.groups.iter().flat_map(|x| x).map(|x| x.to_lowercase()).collect();
    let keep: Vec<&Role> = roles.iter().filter(|x| member.roles.contains(&x.id)).collect();
    let keep: Vec<&Role> = keep.into_iter().filter(|x| !all_group_roles.contains(&x.name.to_lowercase())).collect();
    let mut role_set: Vec<RoleId> = add_roles.iter().map(|r| r.id).chain(keep.into_iter().map(|r| r.id)).collect();
    role_set.sort();
    role_set.dedup();

    if !role_set.iter().all(|r| member.roles.contains(r)) {
      bot.discord.edit_member_roles(on.id, who, &role_set).chain_err(|| "could not add roles")?;
    }

    // cannot edit nickname of those with a higher role
    let nick = match member.nick {
      Some(n) => n,
      None => Default::default()
    };
    if nick != character.name {
      bot.discord.edit_member(on.id, who, |e| e.nickname(&character.name)).ok();
    }
    Ok(None)
  }
}
<|endoftext|>


<commit_before>use graphics::Graphics;
use graphics::character::CharacterCache;
use color::{ Color, Colorable };
use point::Point;
use ui_context::UiContext;

pub type FontSize = u32;

/// An enum for passing in label information to widget arguments.
pub enum Labeling<'a> {
    Label(&'a str, FontSize, Color),
    NoLabel,
}

/// Determine the pixel width of the final text bitmap.
#[inline]
pub fn width<C: CharacterCache>(uic: &mut UiContext<C>, size: FontSize, text: &str) -> f64 {
    text.chars().fold(0u32, |a, ch| {
        let character = uic.get_character(size, ch);
        a + character.width() as u32
    }) as f64
}

/// Determine a suitable FontSize from a given rectangle height.
#[inline]
pub fn auto_size_from_rect_height(rect_height: f64) -> FontSize {
    let size = rect_height as u32 - 832;
    if size % 2 == 0 { size } else { size - 1u32 }
}

/// A trait used for widget types that take a label.
pub trait Labelable<'a> {
    fn label(self, text: &'a str) -> Self;
    fn label_color(self, color: Color) -> Self;
    fn label_rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self;
    fn label_font_size(self, size: FontSize) -> Self;
    fn small_font<C>(self, uic: &UiContext<C>) -> Self;
    fn medium_font<C>(self, uic: &UiContext<C>) -> Self;
    fn large_font<C>(self, uic: &UiContext<C>) -> Self;
}

/// Label text property.
#[derive(Copy, Clone)]
pub struct LabelText<'a>(pub &'a str);

/// Label color property.
#[derive(Copy, Clone)]
pub struct LabelColor(pub Color);

/// Label font size property.
#[derive(Copy, Clone)]
pub struct LabelFontSize(pub FontSize);

/*
impl<'a, T: 'a> Labelable<'a> for T
    where
        (LabelText<'a>, T): Pair<Data = LabelText<'a>, Object = T> + SetAt,
        (LabelColor, T): Pair<Data = LabelColor, Object = T> + SetAt,
        (LabelFontSize, T): Pair<Data = LabelFontSize, Object = T> + SetAt
{
    fn label(self, text: &'a str) -> Self {
        self.set(LabelText(text))
    }

    fn label_color(self, color: Color) -> Self {
        self.set(LabelColor(color))
    }

    fn label_rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self {
        self.set(LabelColor(Color([r, g, b, a])))
    }

    fn label_font_size(self, size: FontSize) -> Self {
        self.set(LabelFontSize(size))
    }

    fn small_font<C>(self, uic: &UiContext<C>) -> Self {
        self.set(LabelFontSize(uic.theme.font_size_small))
    }

    fn medium_font<C>(self, uic: &UiContext<C>) -> Self {
        self.set(LabelFontSize(uic.theme.font_size_medium))
    }

    fn large_font<C>(self, uic: &UiContext<C>) -> Self {
        self.set(LabelFontSize(uic.theme.font_size_large))
    }
}
*/

/// A context on which the builder pattern can be implemented.
pub struct Label<'a> {
    text: &'a str,
    pos: Point,
    size: FontSize,
    maybe_color: Option<Color>,
}

impl<'a> Label<'a> {
    /// A builder method for specifying font_size.
    pub fn size(self, size: FontSize) -> Label<'a> {
        Label { size: size, ..self }
    }
}

impl<'a> Label<'a> {

    /// A label builder method to be implemented on the UiContext.
    pub fn new(text: &'a str) -> Label<'a> {
        Label {
            text: text,
            pos: [0.0, 0.0],
            size: 24u32,
            maybe_color: None,
        }
    }

}

impl<'a> Colorable for Label<'a> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

/*
quack! {
    label: Label['a]
    get:
    set:
        fn (val: Position) [] { label.pos = val.0 }
    action:
}
*/

impl<'a> ::draw::Drawable for Label<'a> {
    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {
        let color = self.maybe_color.unwrap_or(Color::black());
        uic.draw_text(graphics, self.pos, self.size, color, self.text);
    }
}
<commit_msg>Made `Labelable::label_rgba` a provided trait method<commit_after>use graphics::Graphics;
use graphics::character::CharacterCache;
use color::{ Color, Colorable };
use point::Point;
use ui_context::UiContext;

pub type FontSize = u32;

/// An enum for passing in label information to widget arguments.
pub enum Labeling<'a> {
    Label(&'a str, FontSize, Color),
    NoLabel,
}

/// Determine the pixel width of the final text bitmap.
#[inline]
pub fn width<C: CharacterCache>(uic: &mut UiContext<C>, size: FontSize, text: &str) -> f64 {
    text.chars().fold(0u32, |a, ch| {
        let character = uic.get_character(size, ch);
        a + character.width() as u32
    }) as f64
}

/// Determine a suitable FontSize from a given rectangle height.
#[inline]
pub fn auto_size_from_rect_height(rect_height: f64) -> FontSize {
    let size = rect_height as u32 - 832;
    if size % 2 == 0 { size } else { size - 1u32 }
}

/// A trait used for widget types that take a label.
pub trait Labelable<'a>: Sized {
    fn label(self, text: &'a str) -> Self;
    fn label_color(self, color: Color) -> Self;
    fn label_rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self {
        self.label_color(Color([r, g, b, a]))
    }
    fn label_font_size(self, size: FontSize) -> Self;
    fn small_font<C>(self, uic: &UiContext<C>) -> Self;
    fn medium_font<C>(self, uic: &UiContext<C>) -> Self;
    fn large_font<C>(self, uic: &UiContext<C>) -> Self;
}

/// Label text property.
#[derive(Copy, Clone)]
pub struct LabelText<'a>(pub &'a str);

/// Label color property.
#[derive(Copy, Clone)]
pub struct LabelColor(pub Color);

/// Label font size property.
#[derive(Copy, Clone)]
pub struct LabelFontSize(pub FontSize);

/*
impl<'a, T: 'a> Labelable<'a> for T
    where
        (LabelText<'a>, T): Pair<Data = LabelText<'a>, Object = T> + SetAt,
        (LabelColor, T): Pair<Data = LabelColor, Object = T> + SetAt,
        (LabelFontSize, T): Pair<Data = LabelFontSize, Object = T> + SetAt
{
    fn label(self, text: &'a str) -> Self {
        self.set(LabelText(text))
    }

    fn label_color(self, color: Color) -> Self {
        self.set(LabelColor(color))
    }

    fn label_rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self {
        self.set(LabelColor(Color([r, g, b, a])))
    }

    fn label_font_size(self, size: FontSize) -> Self {
        self.set(LabelFontSize(size))
    }

    fn small_font<C>(self, uic: &UiContext<C>) -> Self {
        self.set(LabelFontSize(uic.theme.font_size_small))
    }

    fn medium_font<C>(self, uic: &UiContext<C>) -> Self {
        self.set(LabelFontSize(uic.theme.font_size_medium))
    }

    fn large_font<C>(self, uic: &UiContext<C>) -> Self {
        self.set(LabelFontSize(uic.theme.font_size_large))
    }
}
*/

/// A context on which the builder pattern can be implemented.
pub struct Label<'a> {
    text: &'a str,
    pos: Point,
    size: FontSize,
    maybe_color: Option<Color>,
}

impl<'a> Label<'a> {
    /// A builder method for specifying font_size.
    pub fn size(self, size: FontSize) -> Label<'a> {
        Label { size: size, ..self }
    }
}

impl<'a> Label<'a> {

    /// A label builder method to be implemented on the UiContext.
    pub fn new(text: &'a str) -> Label<'a> {
        Label {
            text: text,
            pos: [0.0, 0.0],
            size: 24u32,
            maybe_color: None,
        }
    }

}

impl<'a> Colorable for Label<'a> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

/*
quack! {
    label: Label['a]
    get:
    set:
        fn (val: Position) [] { label.pos = val.0 }
    action:
}
*/

impl<'a> ::draw::Drawable for Label<'a> {
    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {
        let color = self.maybe_color.unwrap_or(Color::black());
        uic.draw_text(graphics, self.pos, self.size, color, self.text);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

use super::{Graphics, Drawer};
use draw::resize;
use std::time::Instant;

use glium::glutin::{Event, ElementState};

pub use glium::glutin::{VirtualKeyCode, MouseButton};

/// Methods `run_until_closed()` will call
pub trait Game{
    /// Method that gets called each frame from `run_until_closed()`.
    ///
    /// Should return a `GameUpdate` specifying things the game should do.
    fn frame(&mut self, FrameInfo, Drawer) -> GameUpdate;
}

impl<F: FnMut(FrameInfo, Drawer) -> GameUpdate> Game for F{
    fn frame(&mut self, info: FrameInfo, drawer: Drawer) -> GameUpdate{
        (self)(info, drawer)
    }
}

/// This is returned each frame from an object implementing `Game`.
///
/// It describes anything the game should do, e.g. closing the game.
pub struct GameUpdate{
    /// Describes whether the game should be closed
    pub close: bool,
    _fill: ()
}

impl GameUpdate {
    /// Nothing should be changed
    #[inline]
    pub fn nothing() -> Self{
        GameUpdate{
            close: false,
            _fill: ()
        }
    }

    /// Set whether to close the game
    pub fn set_close(self, close: bool) -> Self{
        GameUpdate{
            close: close,
            .. self
        }
    }
}

/// Runs the game until the window is closed
pub fn run_until_closed<G: Game>(mut graphics: Graphics, mut g: G){
    let mut last = Instant::now();
    let mut mousepos = (0., 0.);
    let mut down_keys = HashSet::new();

    'game: loop{
        let mut keys = Vec::new();
        let mut mouses = Vec::new();

        let mut resized = None::<(u32, u32)>;

        for ev in graphics.poll_events() {
            match ev {
                Event::Closed => break 'game,
                Event::KeyboardInput(es, _, Some(vkc)) => match es{
                    ElementState::Pressed  => {
                        down_keys.insert( vkc);
                        keys.push((true , vkc));
                    },
                    ElementState::Released => {
                        down_keys.remove(&vkc);
                        keys.push((false, vkc));
                    }
                },
                Event::MouseMoved(x, y) => {
                    let (w, h) = graphics.get_h_size();

                    mousepos = (x as f32 - w, h - y as f32);
                },
                // This is only neccessary because `graphics` gets immutably borrowed for this for-loop
                Event::Resized(w, h) => resized = Some((w, h)),
                Event::MouseInput(state, button) => mouses.push((state == ElementState::Pressed, button)),
                _ => ()
            }
        }

        if let Some((w, h)) = resized{
            resize(&mut graphics, w, h);
        }

        let dur = last.elapsed();
        let delta = dur.as_secs() as f64 + dur.subsec_nanos() as f64 / 1e9;
        last = Instant::now();

        let update = FrameInfo{
            delta    : delta,
            key_events: keys,
            mouse_events: mouses,
            down_keys: &down_keys,
            mousepos : mousepos
        };

        let update = g.frame(update, Drawer::new(&graphics));

        if update.close{
            break
        }
    }
}

/// Wraps together useful data about what has happened (e.g. events)
#[derive(Debug)]
pub struct FrameInfo<'a>{
    /// The amount of time passed since last frame
    pub delta: f64,
    /// The last position of the mouse on the screen
    pub mousepos: (f32, f32),
    mouse_events: Vec<(bool, MouseButton)>,
    key_events: Vec<(bool, VirtualKeyCode)>,

    // All keys that are pressed down
    down_keys: &'a HashSet<VirtualKeyCode>
}

impl<'a> FrameInfo<'a>{
    #[inline]
    /// Returns a slice of all key events that have happened
    pub fn get_key_events(&self) -> &[(bool, VirtualKeyCode)]{
        &self.key_events
    }
    #[inline]
    /// Returns a slice of all key events that have happened
    pub fn get_mouse_events(&self) -> &[(bool, MouseButton)]{
        &self.mouse_events
    }
    #[inline]
    /// Checks whether a key is pressed down
    pub fn is_down(&self, key: &VirtualKeyCode) -> bool{
        self.down_keys.contains(key)
    }
}

/// Describes objects that can change because of events
pub trait Update{
    /// Changes the object depending on what has happened
    fn update(&mut self, &FrameInfo);
}

/// Macro for easily doing things if particular keys are down
/// # Example
///
/// ```rust
/// # macro_rules! is_down{($l_args:ident; $($($key:ident),+ => $b:block),+) => {}}
/// fn logic(player_y: &mut f32, info: korome::FrameInfo){
///     is_down!{info;
///         W, Up => {
///             player_y -= l_args.delta() as f32;
///         },
///         S, Down => {
///             player_y += l_args.delta() as f32;
///         }
///     };
/// }
/// ```
#[macro_export]
macro_rules! is_down{
    ( $info:ident; $( $( $key:ident ),+ => $b:block ),+ ) => {{
        $( if $( $info.is_down(&$crate::VirtualKeyCode::$key) )||+ $b )+
    }}
}
<commit_msg>Correct is_down! docs<commit_after>use std::collections::HashSet;

use super::{Graphics, Drawer};
use draw::resize;
use std::time::Instant;

use glium::glutin::{Event, ElementState};

pub use glium::glutin::{VirtualKeyCode, MouseButton};

/// Methods `run_until_closed()` will call
pub trait Game{
    /// Method that gets called each frame from `run_until_closed()`.
    ///
    /// Should return a `GameUpdate` specifying things the game should do.
    fn frame(&mut self, FrameInfo, Drawer) -> GameUpdate;
}

impl<F: FnMut(FrameInfo, Drawer) -> GameUpdate> Game for F{
    fn frame(&mut self, info: FrameInfo, drawer: Drawer) -> GameUpdate{
        (self)(info, drawer)
    }
}

/// This is returned each frame from an object implementing `Game`.
///
/// It describes anything the game should do, e.g. closing the game.
pub struct GameUpdate{
    /// Describes whether the game should be closed
    pub close: bool,
    _fill: ()
}

impl GameUpdate {
    /// Nothing should be changed
    #[inline]
    pub fn nothing() -> Self{
        GameUpdate{
            close: false,
            _fill: ()
        }
    }

    /// Set whether to close the game
    pub fn set_close(self, close: bool) -> Self{
        GameUpdate{
            close: close,
            .. self
        }
    }
}

/// Runs the game until the window is closed
pub fn run_until_closed<G: Game>(mut graphics: Graphics, mut g: G){
    let mut last = Instant::now();
    let mut mousepos = (0., 0.);
    let mut down_keys = HashSet::new();

    'game: loop{
        let mut keys = Vec::new();
        let mut mouses = Vec::new();

        let mut resized = None::<(u32, u32)>;

        for ev in graphics.poll_events() {
            match ev {
                Event::Closed => break 'game,
                Event::KeyboardInput(es, _, Some(vkc)) => match es{
                    ElementState::Pressed  => {
                        down_keys.insert( vkc);
                        keys.push((true , vkc));
                    },
                    ElementState::Released => {
                        down_keys.remove(&vkc);
                        keys.push((false, vkc));
                    }
                },
                Event::MouseMoved(x, y) => {
                    let (w, h) = graphics.get_h_size();

                    mousepos = (x as f32 - w, h - y as f32);
                },
                // This is only neccessary because `graphics` gets immutably borrowed for this for-loop
                Event::Resized(w, h) => resized = Some((w, h)),
                Event::MouseInput(state, button) => mouses.push((state == ElementState::Pressed, button)),
                _ => ()
            }
        }

        if let Some((w, h)) = resized{
            resize(&mut graphics, w, h);
        }

        let dur = last.elapsed();
        let delta = dur.as_secs() as f64 + dur.subsec_nanos() as f64 / 1e9;
        last = Instant::now();

        let update = FrameInfo{
            delta    : delta,
            key_events: keys,
            mouse_events: mouses,
            down_keys: &down_keys,
            mousepos : mousepos
        };

        let update = g.frame(update, Drawer::new(&graphics));

        if update.close{
            break
        }
    }
}

/// Wraps together useful data about what has happened (e.g. events)
#[derive(Debug)]
pub struct FrameInfo<'a>{
    /// The amount of time passed since last frame
    pub delta: f64,
    /// The last position of the mouse on the screen
    pub mousepos: (f32, f32),
    mouse_events: Vec<(bool, MouseButton)>,
    key_events: Vec<(bool, VirtualKeyCode)>,

    // All keys that are pressed down
    down_keys: &'a HashSet<VirtualKeyCode>
}

impl<'a> FrameInfo<'a>{
    #[inline]
    /// Returns a slice of all key events that have happened
    pub fn get_key_events(&self) -> &[(bool, VirtualKeyCode)]{
        &self.key_events
    }
    #[inline]
    /// Returns a slice of all key events that have happened
    pub fn get_mouse_events(&self) -> &[(bool, MouseButton)]{
        &self.mouse_events
    }
    #[inline]
    /// Checks whether a key is pressed down
    pub fn is_down(&self, key: &VirtualKeyCode) -> bool{
        self.down_keys.contains(key)
    }
}

/// Describes objects that can change because of events
pub trait Update{
    /// Changes the object depending on what has happened
    fn update(&mut self, &FrameInfo);
}

/// Macro for easily doing things if particular keys are down
/// # Example
///
/// ```rust
// Sadly the macro has to written here again, becauase the example doesn't use macros from the crate
/// # macro_rules! is_down{( $info:ident; $( $( $key:ident ),+ => $b:block ),+ ) => {{$( if $( $info.is_down(&$crate::VirtualKeyCode::$key) )||+ $b )+}}}
/// fn logic(player_y: &mut f32, info: korome::FrameInfo){
///     is_down!{info;
///         W, Up => {
///             *player_y -= l_args.delta() as f32;
///         },
///         S, Down => {
///             *player_y += l_args.delta() as f32;
///         }
///     };
/// }
/// ```
#[macro_export]
macro_rules! is_down{
    ( $info:ident; $( $( $key:ident ),+ => $b:block ),+ ) => {{
        $( if $( $info.is_down(&$crate::VirtualKeyCode::$key) )||+ $b )+
    }}
}
<|endoftext|>