<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use {Module, Resolver};
use build_reduced_graph::BuildReducedGraphVisitor;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex};
use rustc::hir::map::{self, DefCollector};
use rustc::util::nodemap::FnvHashMap;
use std::cell::Cell;
use std::rc::Rc;
use syntax::ast;
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator, MultiItemModifier};
use syntax::ext::base::{NormalTT, SyntaxExtension};
use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules;
use syntax::parse::token::intern;
use syntax::util::lev_distance::find_best_match_for_name;
use syntax_pos::Span;

#[derive(Clone)]
pub struct InvocationData<'a> {
    pub module: Cell<Module<'a>>,
    def_index: DefIndex,
    // True if this expansion is in a `const_integer` position, for example `[u32; m!()]`.
    // c.f. `DefCollector::visit_ast_const_integer`.
    const_integer: bool,
    // The scope in which the invocation path is resolved.
    pub legacy_scope: Cell<LegacyScope<'a>>,
    // The smallest scope that includes this invocation's expansion,
    // or `Empty` if this invocation has not been expanded yet.
    pub expansion: Cell<LegacyScope<'a>>,
}

impl<'a> InvocationData<'a> {
    pub fn root(graph_root: Module<'a>) -> Self {
        InvocationData {
            module: Cell::new(graph_root),
            def_index: CRATE_DEF_INDEX,
            const_integer: false,
            legacy_scope: Cell::new(LegacyScope::Empty),
            expansion: Cell::new(LegacyScope::Empty),
        }
    }
}

#[derive(Copy, Clone)]
pub enum LegacyScope<'a> {
    Empty,
    Invocation(&'a InvocationData<'a>), // The scope of the invocation, not including its expansion
    Expansion(&'a InvocationData<'a>), // The scope of the invocation, including its expansion
    Binding(&'a LegacyBinding<'a>),
}

impl<'a> LegacyScope<'a> {
    fn simplify_expansion(mut invoc: &'a InvocationData<'a>) -> Self {
        while let LegacyScope::Invocation(_) = invoc.expansion.get() {
            match invoc.legacy_scope.get() {
                LegacyScope::Expansion(new_invoc) => invoc = new_invoc,
                LegacyScope::Binding(_) => break,
                scope @ _ => return scope,
            }
        }
        LegacyScope::Expansion(invoc)
    }
}

pub struct LegacyBinding<'a> {
    parent: LegacyScope<'a>,
    kind: LegacyBindingKind,
}

pub enum LegacyBindingKind {
    MacroRules(ast::Name, Rc<SyntaxExtension>, Span),
    MacroUse(LegacyImports),
}

pub type LegacyImports = FnvHashMap<ast::Name, (Rc<SyntaxExtension>, Span)>;

impl<'a> base::Resolver for Resolver<'a> {
    fn next_node_id(&mut self) -> ast::NodeId {
        self.session.next_node_id()
    }

    fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
        let mark = Mark::fresh();
        let module = self.module_map[&id];
        self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData {
            module: Cell::new(module),
            def_index: module.def_id().unwrap().index,
            const_integer: false,
            legacy_scope: Cell::new(LegacyScope::Empty),
            expansion: Cell::new(LegacyScope::Empty),
        }));
        mark
    }

    fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
        let invocation = self.invocations[&mark];
        self.collect_def_ids(invocation, expansion);

        self.current_module = invocation.module.get();
        let mut visitor = BuildReducedGraphVisitor {
            resolver: self,
            legacy_scope: LegacyScope::Invocation(invocation),
            expansion: mark,
        };
        expansion.visit_with(&mut visitor);
        invocation.expansion.set(visitor.legacy_scope);
    }

    fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
        if &def.ident.name.as_str() == "macro_rules" {
            self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`");
        }
        if def.use_locally {
            let invocation = self.invocations[&scope];
            let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, &def));
            let binding = self.arenas.alloc_legacy_binding(LegacyBinding {
                parent: invocation.legacy_scope.get(),
                kind: LegacyBindingKind::MacroRules(def.ident.name, ext, def.span),
            });
            invocation.legacy_scope.set(LegacyScope::Binding(binding));
            self.macro_names.insert(def.ident.name);
        }
        if def.export {
            def.id = self.next_node_id();
            self.exported_macros.push(def);
        }
    }

    fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
        if let NormalTT(..) = *ext {
            self.macro_names.insert(ident.name);
        }
        self.builtin_macros.insert(ident.name, ext);
    }

    fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
        self.macros_at_scope.insert(id, macros);
    }

    fn find_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
        for i in 0..attrs.len() {
            let name = intern(&attrs[i].name());
            match self.builtin_macros.get(&name) {
                Some(ext) => match **ext {
                    MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
                        return Some(attrs.remove(i))
                    }
                    _ => {}
                },
                None => {}
            }
        }
        None
    }

    fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool)
                     -> Result<Rc<SyntaxExtension>, Determinacy> {
        let (name, span) = match invoc.kind {
            InvocationKind::Bang { ref mac, .. } => {
                let path = &mac.node.path;
                if path.segments.len() > 1 || path.global ||
                   !path.segments[0].parameters.is_empty() {
                    self.session.span_err(path.span,
                                          "expected macro name without module separators");
                    return Err(Determinacy::Determined);
                }
                (path.segments[0].identifier.name, path.span)
            }
            InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
        };

        let invocation = self.invocations[&scope];
        if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() {
            invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent));
        }
        self.resolve_macro_name(invocation.legacy_scope.get(), name, true).ok_or_else(|| {
            if force {
                let mut err =
                    self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
                self.suggest_macro_name(&name.as_str(), &mut err);
                err.emit();
                Determinacy::Determined
            } else {
                Determinacy::Undetermined
            }
        })
    }

    fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>> {
        self.derive_modes.get(&ident.name).cloned()
    }
}

impl<'a> Resolver<'a> {
    pub fn resolve_macro_name(&mut self,
                              mut scope: LegacyScope<'a>,
                              name: ast::Name,
                              record_used: bool)
                              -> Option<Rc<SyntaxExtension>> {
        let check_shadowing = |this: &mut Self, relative_depth, scope, span| {
            if record_used && relative_depth > 0 {
                this.disallowed_shadowing.push((name, span, scope));
            }
        };

        let mut relative_depth: u32 = 0;
        loop {
            scope = match scope {
                LegacyScope::Empty => break,
                LegacyScope::Expansion(invocation) => {
                    if let LegacyScope::Empty = invocation.expansion.get() {
                        invocation.legacy_scope.get()
                    } else {
                        relative_depth += 1;
                        invocation.expansion.get()
                    }
                }
                LegacyScope::Invocation(invocation) => {
                    let new_relative_depth = relative_depth.saturating_sub(1);
                    let mut scope = invocation.legacy_scope.get();
                    if let LegacyScope::Binding(binding) = scope {
                        match binding.kind {
                            LegacyBindingKind::MacroUse(ref imports) => {
                                if let Some(&(ref ext, span)) = imports.get(&name) {
                                    check_shadowing(self, relative_depth, binding.parent, span);
                                    return Some(ext.clone());
                                }
                            },
                            LegacyBindingKind::MacroRules(name_, ref ext, span) => {
                                if name_ == name {
                                    check_shadowing(self, new_relative_depth, binding.parent, span);
                                    return Some(ext.clone());
                                }
                            }
                        }
                        scope = binding.parent
                    }
                    relative_depth = new_relative_depth;
                    scope
                }
                _ => unreachable!(),
            };
        }

        self.builtin_macros.get(&name).cloned()
    }

    fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
        if let Some(suggestion) = find_best_match_for_name(self.macro_names.iter(), name, None) {
            if suggestion != name {
                err.help(&format!("did you mean `{}!`?", suggestion));
            } else {
                err.help(&format!("have you added the `#[macro_use]` on the module/import?"));
            }
        }
    }

    fn collect_def_ids(&mut self, invocation: &'a InvocationData<'a>, expansion: &Expansion) {
        let Resolver { ref mut invocations, arenas, graph_root, .. } = *self;
        let InvocationData { def_index, const_integer, .. } = *invocation;

        let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| {
            invocations.entry(invoc.mark).or_insert_with(|| {
                arenas.alloc_invocation_data(InvocationData {
                    def_index: invoc.def_index,
                    const_integer: invoc.const_integer,
                    module: Cell::new(graph_root),
                    expansion: Cell::new(LegacyScope::Empty),
                    legacy_scope: Cell::new(LegacyScope::Empty),
                })
            });
        };

        let mut def_collector = DefCollector::new(&mut self.definitions);
        def_collector.visit_macro_invoc = Some(visit_macro_invoc);
        def_collector.with_parent(def_index, |def_collector| {
            if const_integer {
                if let Expansion::Expr(ref expr) = *expansion {
                    def_collector.visit_ast_const_integer(expr);
                }
            }
            expansion.visit_with(def_collector)
        });
    }
}
<commit_msg>Remove `LegacyBindingKind::MacroUse`.<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use {Module, Resolver};
use build_reduced_graph::BuildReducedGraphVisitor;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex};
use rustc::hir::map::{self, DefCollector};
use rustc::util::nodemap::FnvHashMap;
use std::cell::Cell;
use std::rc::Rc;
use syntax::ast;
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator, MultiItemModifier};
use syntax::ext::base::{NormalTT, SyntaxExtension};
use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules;
use syntax::parse::token::intern;
use syntax::util::lev_distance::find_best_match_for_name;
use syntax_pos::Span;

#[derive(Clone)]
pub struct InvocationData<'a> {
    pub module: Cell<Module<'a>>,
    def_index: DefIndex,
    // True if this expansion is in a `const_integer` position, for example `[u32; m!()]`.
    // c.f. `DefCollector::visit_ast_const_integer`.
    const_integer: bool,
    // The scope in which the invocation path is resolved.
    pub legacy_scope: Cell<LegacyScope<'a>>,
    // The smallest scope that includes this invocation's expansion,
    // or `Empty` if this invocation has not been expanded yet.
    pub expansion: Cell<LegacyScope<'a>>,
}

impl<'a> InvocationData<'a> {
    pub fn root(graph_root: Module<'a>) -> Self {
        InvocationData {
            module: Cell::new(graph_root),
            def_index: CRATE_DEF_INDEX,
            const_integer: false,
            legacy_scope: Cell::new(LegacyScope::Empty),
            expansion: Cell::new(LegacyScope::Empty),
        }
    }
}

#[derive(Copy, Clone)]
pub enum LegacyScope<'a> {
    Empty,
    Invocation(&'a InvocationData<'a>), // The scope of the invocation, not including its expansion
    Expansion(&'a InvocationData<'a>), // The scope of the invocation, including its expansion
    Binding(&'a LegacyBinding<'a>),
}

impl<'a> LegacyScope<'a> {
    fn simplify_expansion(mut invoc: &'a InvocationData<'a>) -> Self {
        while let LegacyScope::Invocation(_) = invoc.expansion.get() {
            match invoc.legacy_scope.get() {
                LegacyScope::Expansion(new_invoc) => invoc = new_invoc,
                LegacyScope::Binding(_) => break,
                scope @ _ => return scope,
            }
        }
        LegacyScope::Expansion(invoc)
    }
}

pub struct LegacyBinding<'a> {
    parent: LegacyScope<'a>,
    name: ast::Name,
    ext: Rc<SyntaxExtension>,
    span: Span,
}

pub type LegacyImports = FnvHashMap<ast::Name, (Rc<SyntaxExtension>, Span)>;

impl<'a> base::Resolver for Resolver<'a> {
    fn next_node_id(&mut self) -> ast::NodeId {
        self.session.next_node_id()
    }

    fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
        let mark = Mark::fresh();
        let module = self.module_map[&id];
        self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData {
            module: Cell::new(module),
            def_index: module.def_id().unwrap().index,
            const_integer: false,
            legacy_scope: Cell::new(LegacyScope::Empty),
            expansion: Cell::new(LegacyScope::Empty),
        }));
        mark
    }

    fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
        let invocation = self.invocations[&mark];
        self.collect_def_ids(invocation, expansion);

        self.current_module = invocation.module.get();
        let mut visitor = BuildReducedGraphVisitor {
            resolver: self,
            legacy_scope: LegacyScope::Invocation(invocation),
            expansion: mark,
        };
        expansion.visit_with(&mut visitor);
        invocation.expansion.set(visitor.legacy_scope);
    }

    fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
        if &def.ident.name.as_str() == "macro_rules" {
            self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`");
        }
        if def.use_locally {
            let invocation = self.invocations[&scope];
            let binding = self.arenas.alloc_legacy_binding(LegacyBinding {
                parent: invocation.legacy_scope.get(),
                name: def.ident.name,
                ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
                span: def.span,
            });
            invocation.legacy_scope.set(LegacyScope::Binding(binding));
            self.macro_names.insert(def.ident.name);
        }
        if def.export {
            def.id = self.next_node_id();
            self.exported_macros.push(def);
        }
    }

    fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
        if let NormalTT(..) = *ext {
            self.macro_names.insert(ident.name);
        }
        self.builtin_macros.insert(ident.name, ext);
    }

    fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
        self.macros_at_scope.insert(id, macros);
    }

    fn find_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
        for i in 0..attrs.len() {
            let name = intern(&attrs[i].name());
            match self.builtin_macros.get(&name) {
                Some(ext) => match **ext {
                    MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
                        return Some(attrs.remove(i))
                    }
                    _ => {}
                },
                None => {}
            }
        }
        None
    }

    fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool)
                     -> Result<Rc<SyntaxExtension>, Determinacy> {
        let (name, span) = match invoc.kind {
            InvocationKind::Bang { ref mac, .. } => {
                let path = &mac.node.path;
                if path.segments.len() > 1 || path.global ||
                   !path.segments[0].parameters.is_empty() {
                    self.session.span_err(path.span,
                                          "expected macro name without module separators");
                    return Err(Determinacy::Determined);
                }
                (path.segments[0].identifier.name, path.span)
            }
            InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
        };

        let invocation = self.invocations[&scope];
        if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() {
            invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent));
        }
        self.resolve_macro_name(invocation.legacy_scope.get(), name, true).ok_or_else(|| {
            if force {
                let mut err =
                    self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
                self.suggest_macro_name(&name.as_str(), &mut err);
                err.emit();
                Determinacy::Determined
            } else {
                Determinacy::Undetermined
            }
        })
    }

    fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>> {
        self.derive_modes.get(&ident.name).cloned()
    }
}

impl<'a> Resolver<'a> {
    pub fn resolve_macro_name(&mut self,
                              mut scope: LegacyScope<'a>,
                              name: ast::Name,
                              record_used: bool)
                              -> Option<Rc<SyntaxExtension>> {
        let mut relative_depth: u32 = 0;
        loop {
            scope = match scope {
                LegacyScope::Empty => break,
                LegacyScope::Expansion(invocation) => {
                    if let LegacyScope::Empty = invocation.expansion.get() {
                        invocation.legacy_scope.get()
                    } else {
                        relative_depth += 1;
                        invocation.expansion.get()
                    }
                }
                LegacyScope::Invocation(invocation) => {
                    relative_depth = relative_depth.saturating_sub(1);
                    invocation.legacy_scope.get()
                }
                LegacyScope::Binding(binding) => {
                    if binding.name == name {
                        if record_used && relative_depth > 0 {
                            self.disallowed_shadowing.push((name, binding.span, binding.parent));
                        }
                        return Some(binding.ext.clone());
                    }
                    binding.parent
                }
            };
        }

        self.builtin_macros.get(&name).cloned()
    }

    fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
        if let Some(suggestion) = find_best_match_for_name(self.macro_names.iter(), name, None) {
            if suggestion != name {
                err.help(&format!("did you mean `{}!`?", suggestion));
            } else {
                err.help(&format!("have you added the `#[macro_use]` on the module/import?"));
            }
        }
    }

    fn collect_def_ids(&mut self, invocation: &'a InvocationData<'a>, expansion: &Expansion) {
        let Resolver { ref mut invocations, arenas, graph_root, .. } = *self;
        let InvocationData { def_index, const_integer, .. } = *invocation;

        let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| {
            invocations.entry(invoc.mark).or_insert_with(|| {
                arenas.alloc_invocation_data(InvocationData {
                    def_index: invoc.def_index,
                    const_integer: invoc.const_integer,
                    module: Cell::new(graph_root),
                    expansion: Cell::new(LegacyScope::Empty),
                    legacy_scope: Cell::new(LegacyScope::Empty),
                })
            });
        };

        let mut def_collector = DefCollector::new(&mut self.definitions);
        def_collector.visit_macro_invoc = Some(visit_macro_invoc);
        def_collector.with_parent(def_index, |def_collector| {
            if const_integer {
                if let Expansion::Expr(ref expr) = *expansion {
                    def_collector.visit_ast_const_integer(expr);
                }
            }
            expansion.visit_with(def_collector)
        });
    }
}
<|endoftext|>


<commit_before>extern crate minifb;
extern crate bgfx_rs;
extern crate viewdock;

use bgfx_rs::Bgfx;
use libc::{c_void, c_int};
use minifb::{Scale, WindowOptions, MouseMode, MouseButton, Key, KeyRepeat};
use core::view_plugins::{ViewHandle, ViewPlugins, ViewInstance};
use core::session::{Sessions, Session, SessionHandle};
use core::reader_wrapper::ReaderWrapper;
use self::viewdock::{Workspace, Rect, Direction, DockHandle, SplitHandle};
use menu::Menu;
use imgui_sys::Imgui;
use prodbg_api::ui_ffi::{PDVec2};
use prodbg_api::view::CViewCallbacks;

const WIDTH: usize = 1280;
const HEIGHT: usize = 800;

enum State {
    Default,
    DraggingSlider,
}

pub struct MouseState {
    handle: Option<(SplitHandle, Direction)>,
    state: State,
    prev_mouse: (f32, f32)
}

impl MouseState {
    pub fn new() -> MouseState {
        MouseState {
            handle: None,
            state: State::Default,
            prev_mouse: (0.0, 0.0),
        }
    }
}

pub struct Window<'a> {
    /// minifb window
    pub win: minifb::Window,
    pub menu: Menu<'a>,

    /// Views in this window
    pub views: Vec<ViewHandle>,

    ///
    pub ws: Workspace,

    pub mouse_state: MouseState,
}

struct WindowState {
    pub showed_popup: u32,
    pub should_close: bool,
}

///! Windows keeps track of all different windows that are present with in the application
///! There are several ways windows can be created:
///!
///! 1. User opens a new window using a shortcut or menu selection.
///! 2. User "undocks" a view from an existing window giving it it's own floating window.
///! 3. etc

pub struct Windows<'a> {
    /// All the windows being tracked
    windows: Vec<Window<'a>>,
    current: usize,
}

impl<'a> Windows<'a> {
    pub fn new() -> Windows<'a> {
        Windows {
            windows: Vec::new(),
            current: 0,
        }
    }

    /// Create a default window which will only be created if there are no other
    pub fn create_default(&mut self) {
        if self.windows.len() > 0 {
            return;
        }

        let window = Self::create_window_with_menus().expect("Unable to create window");

        self.windows.push(window)
   }

    pub fn create_window(width: usize, height: usize) -> minifb::Result<Window<'a>> {
        let res = minifb::Window::new("ProDBG",
                                      width,
                                      height,
                                      WindowOptions {
                                          resize: true,
                                          scale: Scale::X1,
                                          ..WindowOptions::default()
                                      });
        match res {
            Ok(win) => {
                Bgfx::create_window(win.get_window_handle() as *const c_void,
                                    width as c_int,
                                    height as c_int);
                Ok(Window {
                    win: win,
                    menu: Menu::new(),
                    views: Vec::new(),
                    mouse_state: MouseState::new(),
                    ws: Workspace::new(Rect::new(0.0, 0.0, width as f32, (height - 20) as f32)).unwrap(),
                })
            }
            Err(err) => Err(err),
        }
    }

    pub fn create_window_with_menus() -> minifb::Result<Window<'a>> {
        let mut window = try!(Self::create_window(WIDTH, HEIGHT));

        // we ignore the results because we likely brake this on Linux otherwise
        // TODO: Figure out how to deal with this on Linux
        let _ = window.win.add_menu("File", &window.menu.file_menu);
        let _ = window.win.add_menu("Debug", &window.menu.debug_menu);

        Ok(window)
    }

    pub fn update(&mut self, sessions: &mut Sessions, view_plugins: &mut ViewPlugins) {
        for i in (0..self.windows.len()).rev() {
            self.windows[i].update(sessions, view_plugins);

            if !self.windows[i].win.is_open() {
                self.windows.swap_remove(i);
            }
        }
    }

    pub fn get_current(&mut self) -> &'a mut Window {
        let current = self.current;
        &mut self.windows[current]
    }

    /// Checks if application should exit (all window instances closed)
    pub fn should_exit(&self) -> bool {
        self.windows.len() == 0
    }

    /// Save the state of the windows (usually done when exiting the application)
    pub fn save(_filename: &str) {}

    /// Load the state of all the views from a previous run
    pub fn load(_filename: &str) {}
}

impl<'a> Window<'a> {
    fn is_inside(v: (f32, f32), pos: PDVec2, size: PDVec2) -> bool {
        let x0 = pos.x;
        let y0 = pos.y;
        let x1 = pos.x + size.x;
        let y1 = pos.y + size.y;

        if (v.0 >= x0 && v.0 < x1) && (v.1 >= y0 && v.1 < y1) {
            true
        } else {
            false
        }
    }

    fn update_view(&self, instance: &mut ViewInstance, session: &mut Session, show_context_menu: bool, mouse: (f32, f32)) -> WindowState {
        let ui = instance.ui;

        if let Some(rect) = self.ws.get_rect_by_handle(DockHandle(instance.handle.0)) {
            Imgui::set_window_pos(rect.x, rect.y);
            Imgui::set_window_size(rect.width, rect.height);
        }

        let open = Imgui::begin_window(&instance.name, true);
        Imgui::init_state(ui.api);

        let pos = ui.get_window_pos();
        let size = ui.get_window_size();

        if Self::is_inside(mouse, pos, size) && show_context_menu {
            Imgui::mark_show_popup(ui.api, true);
        } else {
            Imgui::mark_show_popup(ui.api, false);
        }

        // Make sure we move the cursor to the start of the stream here
        ReaderWrapper::reset_reader(&mut session.reader);

        unsafe {
            let plugin_funcs = instance.plugin_type.plugin_funcs as *mut CViewCallbacks;
            ((*plugin_funcs).update.unwrap())(instance.plugin_data,
                                                ui.api as *mut c_void,
                                                session.reader.api as *mut c_void,
                                                session.get_current_writer().api as *mut c_void);
        }

        let has_shown_menu = Imgui::has_showed_popup(ui.api);

        Imgui::end_window();

        WindowState {
            showed_popup: has_shown_menu,
            should_close: !open,
        }
    }

    pub fn remove_views(&mut self, view_plugins: &mut ViewPlugins, views: &Vec<ViewHandle>) {
        for view in views {
            view_plugins.destroy_instance(*view);
            self.ws.delete_by_handle(DockHandle(view.0));
        }
    }

    fn update_mouse_state(&mut self, mouse_pos: (f32, f32)) {
        match self.mouse_state.state {
            State::Default => {
                if let Some(h) = self.ws.is_hovering_sizer(mouse_pos) {
                    if h.1 == Direction::Vertical {
                        Bgfx::cursor_set_type(2);
                    } else {
                        Bgfx::cursor_set_type(1);
                    }

                    if self.win.get_mouse_down(MouseButton::Left) {
                        self.mouse_state.handle = Some(h);
                        self.mouse_state.state = State::DraggingSlider;
                    }
                } else {
                    Bgfx::cursor_set_type(0);
                }
            },

            State::DraggingSlider => {
                let pm = self.mouse_state.prev_mouse;
                let delta = (pm.0 - mouse_pos.0, pm.1 - mouse_pos.1);

                if self.win.get_mouse_down(MouseButton::Left) {
                    let t = self.mouse_state.handle.unwrap();
                    if t.1 == Direction::Vertical {
                        Bgfx::cursor_set_type(2);
                    } else {
                        Bgfx::cursor_set_type(1);
                    }
                    self.ws.drag_sizer(t.0, delta);
                } else {
                    self.mouse_state.handle = None;
                    self.mouse_state.state = State::Default;
                    Bgfx::cursor_set_type(0);
                }
            }
        }

        /*
        if let Some(handle) = ws.is_hovering_sizer(mouse_pos) {
            let delta = (prev_mouse.0 - mouse_pos.0, prev_mouse.1 - mouse_pos.1);

            if window.get_mouse_down(MouseButton::Left) {
                println!("drangging sizer");
                ws.drag_sizer(handle, delta);
            }
        }
        */

        self.mouse_state.prev_mouse = mouse_pos;
    }

    pub fn update(&mut self, sessions: &mut Sessions, view_plugins: &mut ViewPlugins) {
        let mut views_to_delete = Vec::new();
        let mut has_shown_menu = 0u32;

        self.win.update();
        self.ws.update();

        let mouse = self.win.get_mouse_pos(MouseMode::Clamp).unwrap_or((0.0, 0.0));

        self.update_mouse_state(mouse);

        Bgfx::set_mouse_pos(mouse);
        Bgfx::set_mouse_state(0, self.win.get_mouse_down(MouseButton::Left));

        let show_context_menu = self.win.get_mouse_down(MouseButton::Right);

        for view in &self.views {
            if let Some(ref mut v) = view_plugins.get_view(*view) {
                if let Some(ref mut s) = sessions.get_session(v.session_handle) {
                    let state = Self::update_view(self, v, s, show_context_menu, mouse);

                    if state.should_close {
                        views_to_delete.push(*view);
                    }

                    has_shown_menu |= state.showed_popup;
                }
            }
        }

        if self.win.is_key_pressed(Key::Down, KeyRepeat::No) {
            self.ws.dump_tree();
        }

        if self.win.is_key_pressed(Key::Up, KeyRepeat::No) {
            let _ = self.ws.save("/Users/danielcollin/code/temp/test.xml");
        }

        if self.win.is_key_pressed(Key::Right, KeyRepeat::No) {
            let ws = Workspace::load("/Users/danielcollin/code/temp/test.xml").unwrap();
            let docks = ws.get_docks();
            self.views.clear();

            for dock in &docks {
                //println!("create stuff... {} - {}", dock.name, dock.handle.0);
                let ui = Imgui::create_ui_instance();
                let handle = ViewHandle(dock.handle.0);
                if dock.name == "" {
                    view_plugins.create_instance_with_handle(ui, &"Bitmap View".to_owned(), SessionHandle(0), ViewHandle(dock.handle.0));
                } else {
                    view_plugins.create_instance_with_handle(ui, &dock.name, SessionHandle(0), ViewHandle(dock.handle.0));
                }
                self.views.push(handle);
            }

            self.ws = ws;
        }

        // if now plugin has showed a menu we do it here
        // TODO: Handle diffrent cases when attach menu on to plugin menu or not

        if has_shown_menu == 0 && show_context_menu {
            Self::show_popup(self, true, mouse, view_plugins);
        } else {
            Self::show_popup(self, false, mouse, view_plugins);
        }

        Self::remove_views(self, view_plugins, &views_to_delete);
    }

    fn split_view(&mut self, name: &String, view_plugins: &mut ViewPlugins, pos: (f32, f32), direction: Direction) {
        let ui = Imgui::create_ui_instance();
        if let Some(handle) = view_plugins.create_instance(ui, name, SessionHandle(0)) {
            if let Some(dock_handle) = self.ws.get_hover_dock(pos) {
                let new_handle = DockHandle(handle.0);
                self.ws.split_by_dock_handle(direction, dock_handle, new_handle);
                self.ws.set_name_to_handle(name, new_handle);
                //self.ws.dump_tree_linear();
            } else {
                self.ws.new_split(DockHandle(handle.0), direction);
                //println!("no split");
            }

            self.views.push(handle);
        }
    }

    fn show_popup(&mut self, show: bool, mouse_pos: (f32, f32), view_plugins: &mut ViewPlugins) {
        let ui = Imgui::get_ui();

        if show {
            ui.open_popup("plugins");
        }

        if ui.begin_popup("plugins") {
            let plugin_names = view_plugins.get_plugin_names();

            if ui.begin_menu("Split Horizontally", true) {
                for name in &plugin_names {
                    if ui.menu_item(name, false, true) {
                        Self::split_view(self, &name, view_plugins, mouse_pos, Direction::Horizontal);
                    }
                }
                ui.end_menu();
            }

            if ui.begin_menu("Split Vertically", true) {
                for name in &plugin_names {
                    if ui.menu_item(name, false, true) {
                        Self::split_view(self, &name, view_plugins, mouse_pos, Direction::Vertical);
                    }
                }
                ui.end_menu();
            }

            ui.end_popup();
        }
    }
}
<commit_msg>Send "step in" to session<commit_after>extern crate minifb;
extern crate bgfx_rs;
extern crate viewdock;

use bgfx_rs::Bgfx;
use libc::{c_void, c_int};
use minifb::{Scale, WindowOptions, MouseMode, MouseButton, Key, KeyRepeat};
use core::view_plugins::{ViewHandle, ViewPlugins, ViewInstance};
use core::session::{Sessions, Session, SessionHandle};
use core::reader_wrapper::ReaderWrapper;
use self::viewdock::{Workspace, Rect, Direction, DockHandle, SplitHandle};
use menu::{Menu, MENU_DEBUG_STEP_IN};
use imgui_sys::Imgui;
use prodbg_api::ui_ffi::{PDVec2};
use prodbg_api::view::CViewCallbacks;

const WIDTH: usize = 1280;
const HEIGHT: usize = 800;

enum State {
    Default,
    DraggingSlider,
}

pub struct MouseState {
    handle: Option<(SplitHandle, Direction)>,
    state: State,
    prev_mouse: (f32, f32)
}

impl MouseState {
    pub fn new() -> MouseState {
        MouseState {
            handle: None,
            state: State::Default,
            prev_mouse: (0.0, 0.0),
        }
    }
}

pub struct Window<'a> {
    /// minifb window
    pub win: minifb::Window,
    pub menu: Menu<'a>,

    /// Views in this window
    pub views: Vec<ViewHandle>,

    ///
    pub ws: Workspace,

    pub mouse_state: MouseState,
}

struct WindowState {
    pub showed_popup: u32,
    pub should_close: bool,
}

///! Windows keeps track of all different windows that are present with in the application
///! There are several ways windows can be created:
///!
///! 1. User opens a new window using a shortcut or menu selection.
///! 2. User "undocks" a view from an existing window giving it it's own floating window.
///! 3. etc

pub struct Windows<'a> {
    /// All the windows being tracked
    windows: Vec<Window<'a>>,
    current: usize,
}

impl<'a> Windows<'a> {
    pub fn new() -> Windows<'a> {
        Windows {
            windows: Vec::new(),
            current: 0,
        }
    }

    /// Create a default window which will only be created if there are no other
    pub fn create_default(&mut self) {
        if self.windows.len() > 0 {
            return;
        }

        let window = Self::create_window_with_menus().expect("Unable to create window");

        self.windows.push(window)
   }

    pub fn create_window(width: usize, height: usize) -> minifb::Result<Window<'a>> {
        let res = minifb::Window::new("ProDBG",
                                      width,
                                      height,
                                      WindowOptions {
                                          resize: true,
                                          scale: Scale::X1,
                                          ..WindowOptions::default()
                                      });
        match res {
            Ok(win) => {
                Bgfx::create_window(win.get_window_handle() as *const c_void,
                                    width as c_int,
                                    height as c_int);
                Ok(Window {
                    win: win,
                    menu: Menu::new(),
                    views: Vec::new(),
                    mouse_state: MouseState::new(),
                    ws: Workspace::new(Rect::new(0.0, 0.0, width as f32, (height - 20) as f32)).unwrap(),
                })
            }
            Err(err) => Err(err),
        }
    }

    pub fn create_window_with_menus() -> minifb::Result<Window<'a>> {
        let mut window = try!(Self::create_window(WIDTH, HEIGHT));

        // we ignore the results because we likely brake this on Linux otherwise
        // TODO: Figure out how to deal with this on Linux
        let _ = window.win.add_menu("File", &window.menu.file_menu);
        let _ = window.win.add_menu("Debug", &window.menu.debug_menu);

        Ok(window)
    }

    pub fn update(&mut self, sessions: &mut Sessions, view_plugins: &mut ViewPlugins) {
        for i in (0..self.windows.len()).rev() {
            self.windows[i].update(sessions, view_plugins);

            if !self.windows[i].win.is_open() {
                self.windows.swap_remove(i);
            }
        }
    }

    pub fn get_current(&mut self) -> &'a mut Window {
        let current = self.current;
        &mut self.windows[current]
    }

    /// Checks if application should exit (all window instances closed)
    pub fn should_exit(&self) -> bool {
        self.windows.len() == 0
    }

    /// Save the state of the windows (usually done when exiting the application)
    pub fn save(_filename: &str) {}

    /// Load the state of all the views from a previous run
    pub fn load(_filename: &str) {}
}

impl<'a> Window<'a> {
    fn is_inside(v: (f32, f32), pos: PDVec2, size: PDVec2) -> bool {
        let x0 = pos.x;
        let y0 = pos.y;
        let x1 = pos.x + size.x;
        let y1 = pos.y + size.y;

        if (v.0 >= x0 && v.0 < x1) && (v.1 >= y0 && v.1 < y1) {
            true
        } else {
            false
        }
    }

    fn update_view(&self, instance: &mut ViewInstance, session: &mut Session, show_context_menu: bool, mouse: (f32, f32)) -> WindowState {
        let ui = instance.ui;

        if let Some(rect) = self.ws.get_rect_by_handle(DockHandle(instance.handle.0)) {
            Imgui::set_window_pos(rect.x, rect.y);
            Imgui::set_window_size(rect.width, rect.height);
        }

        let open = Imgui::begin_window(&instance.name, true);
        Imgui::init_state(ui.api);

        let pos = ui.get_window_pos();
        let size = ui.get_window_size();

        if Self::is_inside(mouse, pos, size) && show_context_menu {
            Imgui::mark_show_popup(ui.api, true);
        } else {
            Imgui::mark_show_popup(ui.api, false);
        }

        // Make sure we move the cursor to the start of the stream here
        ReaderWrapper::reset_reader(&mut session.reader);

        unsafe {
            let plugin_funcs = instance.plugin_type.plugin_funcs as *mut CViewCallbacks;
            ((*plugin_funcs).update.unwrap())(instance.plugin_data,
                                                ui.api as *mut c_void,
                                                session.reader.api as *mut c_void,
                                                session.get_current_writer().api as *mut c_void);
        }

        let has_shown_menu = Imgui::has_showed_popup(ui.api);

        Imgui::end_window();

        WindowState {
            showed_popup: has_shown_menu,
            should_close: !open,
        }
    }

    pub fn remove_views(&mut self, view_plugins: &mut ViewPlugins, views: &Vec<ViewHandle>) {
        for view in views {
            view_plugins.destroy_instance(*view);
            self.ws.delete_by_handle(DockHandle(view.0));
        }
    }

    fn update_mouse_state(&mut self, mouse_pos: (f32, f32)) {
        match self.mouse_state.state {
            State::Default => {
                if let Some(h) = self.ws.is_hovering_sizer(mouse_pos) {
                    if h.1 == Direction::Vertical {
                        Bgfx::cursor_set_type(2);
                    } else {
                        Bgfx::cursor_set_type(1);
                    }

                    if self.win.get_mouse_down(MouseButton::Left) {
                        self.mouse_state.handle = Some(h);
                        self.mouse_state.state = State::DraggingSlider;
                    }
                } else {
                    Bgfx::cursor_set_type(0);
                }
            },

            State::DraggingSlider => {
                let pm = self.mouse_state.prev_mouse;
                let delta = (pm.0 - mouse_pos.0, pm.1 - mouse_pos.1);

                if self.win.get_mouse_down(MouseButton::Left) {
                    let t = self.mouse_state.handle.unwrap();
                    if t.1 == Direction::Vertical {
                        Bgfx::cursor_set_type(2);
                    } else {
                        Bgfx::cursor_set_type(1);
                    }
                    self.ws.drag_sizer(t.0, delta);
                } else {
                    self.mouse_state.handle = None;
                    self.mouse_state.state = State::Default;
                    Bgfx::cursor_set_type(0);
                }
            }
        }

        /*
        if let Some(handle) = ws.is_hovering_sizer(mouse_pos) {
            let delta = (prev_mouse.0 - mouse_pos.0, prev_mouse.1 - mouse_pos.1);

            if window.get_mouse_down(MouseButton::Left) {
                println!("drangging sizer");
                ws.drag_sizer(handle, delta);
            }
        }
        */

        self.mouse_state.prev_mouse = mouse_pos;
    }

    pub fn update(&mut self, sessions: &mut Sessions, view_plugins: &mut ViewPlugins) {
        let mut views_to_delete = Vec::new();
        let mut has_shown_menu = 0u32;

        self.win.update();
        self.ws.update();

        let mouse = self.win.get_mouse_pos(MouseMode::Clamp).unwrap_or((0.0, 0.0));

        self.update_mouse_state(mouse);

        Bgfx::set_mouse_pos(mouse);
        Bgfx::set_mouse_state(0, self.win.get_mouse_down(MouseButton::Left));

        let show_context_menu = self.win.get_mouse_down(MouseButton::Right);

        for view in &self.views {
            if let Some(ref mut v) = view_plugins.get_view(*view) {
                if let Some(ref mut s) = sessions.get_session(v.session_handle) {

                    // TODO: Only do this on the correct session

                    self.win.is_menu_pressed().map(|menu_id| {
                        if menu_id == MENU_DEBUG_STEP_IN {
                            println!("action_step");
                            s.action_step();
                        }
                    });

                    let state = Self::update_view(self, v, s, show_context_menu, mouse);

                    if state.should_close {
                        views_to_delete.push(*view);
                    }

                    has_shown_menu |= state.showed_popup;
                }
            }
        }

        if self.win.is_key_pressed(Key::Down, KeyRepeat::No) {
            self.ws.dump_tree();
        }

        if self.win.is_key_pressed(Key::Up, KeyRepeat::No) {
            let _ = self.ws.save("/Users/danielcollin/code/temp/test.xml");
        }

        if self.win.is_key_pressed(Key::Right, KeyRepeat::No) {
            let ws = Workspace::load("/Users/danielcollin/code/temp/test.xml").unwrap();
            let docks = ws.get_docks();
            self.views.clear();

            for dock in &docks {
                //println!("create stuff... {} - {}", dock.name, dock.handle.0);
                let ui = Imgui::create_ui_instance();
                let handle = ViewHandle(dock.handle.0);
                if dock.name == "" {
                    view_plugins.create_instance_with_handle(ui, &"Bitmap View".to_owned(), SessionHandle(0), ViewHandle(dock.handle.0));
                } else {
                    view_plugins.create_instance_with_handle(ui, &dock.name, SessionHandle(0), ViewHandle(dock.handle.0));
                }
                self.views.push(handle);
            }

            self.ws = ws;
        }

        // if now plugin has showed a menu we do it here
        // TODO: Handle diffrent cases when attach menu on to plugin menu or not

        if has_shown_menu == 0 && show_context_menu {
            Self::show_popup(self, true, mouse, view_plugins);
        } else {
            Self::show_popup(self, false, mouse, view_plugins);
        }

        Self::remove_views(self, view_plugins, &views_to_delete);
    }

    fn split_view(&mut self, name: &String, view_plugins: &mut ViewPlugins, pos: (f32, f32), direction: Direction) {
        let ui = Imgui::create_ui_instance();
        if let Some(handle) = view_plugins.create_instance(ui, name, SessionHandle(0)) {
            if let Some(dock_handle) = self.ws.get_hover_dock(pos) {
                let new_handle = DockHandle(handle.0);
                self.ws.split_by_dock_handle(direction, dock_handle, new_handle);
                self.ws.set_name_to_handle(name, new_handle);
                //self.ws.dump_tree_linear();
            } else {
                self.ws.new_split(DockHandle(handle.0), direction);
                //println!("no split");
            }

            self.views.push(handle);
        }
    }

    fn show_popup(&mut self, show: bool, mouse_pos: (f32, f32), view_plugins: &mut ViewPlugins) {
        let ui = Imgui::get_ui();

        if show {
            ui.open_popup("plugins");
        }

        if ui.begin_popup("plugins") {
            let plugin_names = view_plugins.get_plugin_names();

            if ui.begin_menu("Split Horizontally", true) {
                for name in &plugin_names {
                    if ui.menu_item(name, false, true) {
                        Self::split_view(self, &name, view_plugins, mouse_pos, Direction::Horizontal);
                    }
                }
                ui.end_menu();
            }

            if ui.begin_menu("Split Vertically", true) {
                for name in &plugin_names {
                    if ui.menu_item(name, false, true) {
                        Self::split_view(self, &name, view_plugins, mouse_pos, Direction::Vertical);
                    }
                }
                ui.end_menu();
            }

            ui.end_popup();
        }
    }
}
<|endoftext|>


<commit_before>use screen::*;
use piston_window;
use conrod::{self, Widget, Frameable, Positionable, Sizeable, Labelable};
use conrod::color::Colorable;

pub struct MainMenuScreen {
    ui: conrod::Ui<piston_window::Glyphs>,
    new_game: bool,
    exit: bool,
}

impl MainMenuScreen {
    pub fn new(window: &piston_window::PistonWindow, context: &mut Context) -> MainMenuScreen {
        MainMenuScreen { ui: create_ui(&window, &context.assets_path), new_game: false, exit: false, }
    }
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self,
                input: &piston_window::Input,
                window: &piston_window::PistonWindow,
                context: &mut Context)
                -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new(&window, context))));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        handle_on_update(&mut self.ui, &mut self.new_game, &mut self.exit);
    }
}

widget_ids! {
    CANVAS,
    NEW_GAME_BUTTON,
    OPTIONS_BUTTON,
    EXIT_BUTTON,
}

fn create_ui(window: &piston_window::PistonWindow,
             assets_path: &::std::path::Path)
             -> conrod::Ui<piston_window::Glyphs> {
    let font_path = assets_path.join("NotoSans-Regular.ttf");
    let theme = conrod::Theme::default();
    let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
    conrod::Ui::new(glyph_cache.unwrap(), theme)
}

fn handle_on_update(ui: &mut conrod::Ui<piston_window::Glyphs>, new_game: &mut bool, exit: &mut bool) {
    ui.set_widgets(|ui| {
        conrod::Canvas::new()
            .pad(30.)
            .color(conrod::color::rgb(0.2, 0.35, 0.45))
            .scroll_kids()
            .set(CANVAS, ui);

        conrod::Button::new()
            .w_h(200.0, 50.0)
            .mid_left_of(CANVAS)
            .rgb(0.4, 0.75, 0.6)
            .label("New game")
            .react(|| *new_game = true)
            .set(NEW_GAME_BUTTON, ui);

        conrod::Button::new()
            .w_h(200.0, 50.0)
            .mid_left_of(CANVAS)
            .down_from(NEW_GAME_BUTTON, 45.0)
            .rgb(0.4, 0.75, 0.6)
            .label("Exit")
            .react(|| *exit = true)
            .set(EXIT_BUTTON, ui);
    });
}
<commit_msg>Options button<commit_after>use screen::*;
use piston_window;
use conrod::{self, Widget, Frameable, Positionable, Sizeable, Labelable};
use conrod::color::Colorable;

pub struct MainMenuScreen {
    ui: conrod::Ui<piston_window::Glyphs>,
    new_game: bool,
    exit: bool,
}

impl MainMenuScreen {
    pub fn new(window: &piston_window::PistonWindow, context: &mut Context) -> MainMenuScreen {
        MainMenuScreen { ui: create_ui(&window, &context.assets_path), new_game: false, exit: false, }
    }
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self,
                input: &piston_window::Input,
                window: &piston_window::PistonWindow,
                context: &mut Context)
                -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new(&window, context))));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        handle_on_update(&mut self.ui, &mut self.new_game, &mut self.exit);
    }
}

widget_ids! {
    CANVAS,
    NEW_GAME_BUTTON,
    OPTIONS_BUTTON,
    EXIT_BUTTON,
}

fn create_ui(window: &piston_window::PistonWindow,
             assets_path: &::std::path::Path)
             -> conrod::Ui<piston_window::Glyphs> {
    let font_path = assets_path.join("NotoSans-Regular.ttf");
    let theme = conrod::Theme::default();
    let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
    conrod::Ui::new(glyph_cache.unwrap(), theme)
}

fn handle_on_update(ui: &mut conrod::Ui<piston_window::Glyphs>, new_game: &mut bool, exit: &mut bool) {
    ui.set_widgets(|ui| {
        conrod::Canvas::new()
            .pad(30.)
            .color(conrod::color::rgb(0.2, 0.35, 0.45))
            .scroll_kids()
            .set(CANVAS, ui);

        conrod::Button::new()
            .w_h(200.0, 50.0)
            .mid_left_of(CANVAS)
            .rgb(0.4, 0.75, 0.6)
            .label("New game")
            .react(|| *new_game = true)
            .set(NEW_GAME_BUTTON, ui);

        conrod::Button::new()
            .w_h(200.0, 50.0)
            .mid_left_of(CANVAS)
            .down_from(NEW_GAME_BUTTON, 45.0)
            .rgb(0.4, 0.75, 0.6)
            .label("Options")
            .react(|| ())
            .set(OPTIONS_BUTTON, ui);

        conrod::Button::new()
            .w_h(200.0, 50.0)
            .mid_left_of(CANVAS)
            .down_from(OPTIONS_BUTTON, 45.0)
            .rgb(0.4, 0.75, 0.6)
            .label("Exit")
            .react(|| *exit = true)
            .set(EXIT_BUTTON, ui);
    });
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(dynasm)]

#[macro_use]
extern crate dynasmrt;
use dynasmrt::{DynasmApi, DynasmLabelApi};

// aliases, and dynasm! in item position
dynasm!(ops
    ; .alias test, rax
);

fn main() {
    let mut ops = dynasmrt::x64::Assembler::new();
    let d = 3;
    let c = 4;

    let label = ops.new_dynamic_label();

    // interesting testcases
    dynasm!(ops
        // no args
        ; ret
        // immediate
        ; ret 16
        // register
        ; inc test
        // memory ref
        ; inc DWORD [16]
        ; inc DWORD [test]
        ; inc DWORD [rax*2]
        ; inc DWORD [rax*3]
        ; inc DWORD [rax*4]
        ; inc DWORD [rax*5]
        ; inc DWORD [rax*8]
        ; inc DWORD [rax*9]
        ; inc DWORD [rax + 16]
        ; inc DWORD [rax*8 + 16]
        ; inc DWORD [rax + rbx]
        ; inc DWORD [rax + rbx + 16]
        ; inc DWORD [rax*8 + rbx + 16]
        // special memoryref cases
        ; inc DWORD [rsp]
        ; inc DWORD [r12]
        ; inc DWORD [rsp + rax]
        ; inc DWORD [rax + rsp]
        ; inc DWORD [rbp]
        ; inc DWORD [r13]
        ; inc DWORD [rbp + 16]
        ; inc DWORD [rbp*8]
        ; inc DWORD [rip]
        ; inc DWORD [rip + 16]
        // weird registers
        ; xchg al, ah
        ; xchg al, dil
        // register-specific forms
        ; adc rax, 5
        // multi arg forms
        ; mov rax, rbx
        ; mov rax, [rbx]
        ; mov [rbx], rax
        ; mov rax, 1
        ; mov [rax], BYTE 1
        ; imul rax, rbx, 1
        ; imul rax, [rbx], 1
        // prefixes
        ; fs inc DWORD [rax]
        ; lock fs inc DWORD [rax]
        ; rep stosq
        ; inc DWORD [eax]
        // really long instructions
        ; fs imul r9w, [r10d*8 + r11d + 0x66778899], 0x1122
        ; fs imul r9,  [edi*8 + r11d + 0x66778899], 0x11223344
        ; fs mov r9, QWORD 0x1122334455667788
        ; fs movabs rax, 0x1122334455667788
        // funky syntax features
        ; inc BYTE [rax]
        ; inc WORD [rax]
        ; inc DWORD [rax]
        ; inc QWORD [rax]
        // very odd memoryrefs
        ; mov rax, [rbx + rbx * 3 + 2 + c + rax + d]
        ; mov rax, [rbx - 4]
        // labels
        ; a: // local
        ; -> b: // global
        ; => label // dynamic. note the lack of a trailing :. this is due to : being a valid symbol within expressions that does not occur in any other normal rust expr contexts.
        // jumps
        ; jmp <a
        ; jmp -> b
        ; jmp => label
        // rip relative stuff
        ; lea rax, [->b]
        // dynamic registers
        ; inc Rb(1)
        ; inc Rh(5)
        ; inc Rw(1)
        ; inc Rd(1)
        ; inc Rq(1)
        ; mov Rb(7), [Rq(3)*4 + rax]
        ; fsub Rf(5), st0
        // other register families
        ; mov cr1, rax
        ; mov dr1, rax
        ; mov rax, cr1
        ; mov rax, dr1
        ; pop fs
        ; movmskps eax, xmm7
        ; movd mmx7, eax
        ; movd eax, mmx7
        ; fcomp st0
        // VEX/XOP instructions
        ; andn rax, rcx, rdx
        ; andn r8, r9, r10
        ; bextr rax, rbx, 1
        ; vaddpd xmm0, xmm1, [rax]
        // VSIB addressing
        ; vgatherqpd ymm1, QWORD [ymm15*8 + rsi + 0x11112222], ymm8
        // 4 argument instructions
        ; vfmaddss xmm0, xmm1, xmm2, xmm3
        // directives
        ; string:
        //; .bytes "Hello world!\0".bytes()
    );

    // typemap support
    #[allow(dead_code)]
    struct Test {
        foo: i32,
        bar: u32
    }
    let mut test_array = [Test {foo: 1, bar: 2}, Test {foo: 3, bar: 4}, Test {foo: 5, bar: 6}];
    let mut test_array = &mut test_array;
    let mut test_single = Test {foo: 7, bar: 8};
    let mut test_single = &mut test_single;
    dynasm!(ops
        ; mov rax, AWORD MutPointer!(test_array)
        ; mov ebx, 2
        ; inc DWORD rax => Test[2].bar
        ; inc DWORD rax => Test[2 + rbx].bar
        ; inc DWORD rax => Test[rbx].bar
        ; inc DWORD rax => Test[rbx]
        ; mov rax, AWORD MutPointer!(test_single)
        ; inc DWORD rax => Test.bar
    );

    // dynasm in expr position
    match 1 {
        0 => (),
        _ => dynasm!(ops; inc rax)
    }

    // fixups
    let start = ops.offset();
    dynasm!( (ops)
        ; inc rbx
    );
    let end = ops.offset();
    ops.alter(|ops| {
        ops.goto(start);
        dynasm!(ops
            ; inc r12
        );
        ops.check(end);
    });

    let index = ops.offset();
    dynasm!(ops
        ; mov eax, 10203040
        ; ret
    );

    let buf = ops.finalize().unwrap();

    println!("Generated assembly:");
    for i in buf.iter() {
        print!("{:02x }", i);
    }
    println!("");

    let func: extern "C" fn() -> i64 = unsafe { std::mem::transmute(buf.ptr(index)) };
    println!("assembled function result: {}", func() );
}
<commit_msg>Update tests<commit_after>#![feature(plugin)]
#![plugin(dynasm)]

#[macro_use]
extern crate dynasmrt;
use dynasmrt::{DynasmApi, DynasmLabelApi};

// aliases, and dynasm! in item position
dynasm!(ops
    ; .alias test, rax
);

fn main() {
    let mut ops = dynasmrt::x64::Assembler::new();
    let d = 3;
    let c = 4;

    let label = ops.new_dynamic_label();

    // interesting testcases
    dynasm!(ops
        // no args
        ; ret
        // reserved keyword
        ; loop 5
        // immediate
        ; ret 16
        // register
        ; inc test
        // memory ref
        ; inc DWORD [16]
        ; inc DWORD [test]
        ; inc DWORD [rax*2]
        ; inc DWORD [rax*3]
        ; inc DWORD [rax*4]
        ; inc DWORD [rax*5]
        ; inc DWORD [rax*8]
        ; inc DWORD [rax*9]
        ; inc DWORD [rax + 16]
        ; inc DWORD [rax*8 + 16]
        ; inc DWORD [rax + rbx]
        ; inc DWORD [rax + rbx + 16]
        ; inc DWORD [rax*8 + rbx + 16]
        // special memoryref cases
        ; inc DWORD [rsp]
        ; inc DWORD [r12]
        ; inc DWORD [rsp + rax]
        ; inc DWORD [rax + rsp]
        ; inc DWORD [rbp]
        ; inc DWORD [r13]
        ; inc DWORD [rbp + 16]
        ; inc DWORD [rbp*8]
        ; inc DWORD [rip]
        ; inc DWORD [rip + 16]
        // weird registers
        ; xchg al, ah
        ; xchg al, dil
        // register-specific forms
        ; adc rax, 5
        // multi arg forms
        ; mov rax, rbx
        ; mov rax, [rbx]
        ; mov [rbx], rax
        ; mov rax, 1
        ; mov [rax], BYTE 1
        ; imul rax, rbx, 1
        ; imul rax, [rbx], 1
        // prefixes
        ; fs inc DWORD [rax]
        ; lock fs inc DWORD [rax]
        ; rep stosq
        ; inc DWORD [eax]
        // really long instructions
        ; fs imul r9w, [r10d*8 + r11d + 0x66778899], 0x1122
        ; fs imul r9,  [edi*8 + r11d + 0x66778899], 0x11223344
        ; fs mov r9, QWORD 0x1122334455667788
        ; fs movabs rax, 0x1122334455667788
        // funky syntax features
        ; inc BYTE [rax]
        ; inc WORD [rax]
        ; inc DWORD [rax]
        ; inc QWORD [rax]
        // very odd memoryrefs
        ; mov rax, [rbx + rbx * 3 + 2 + c + rax + d]
        ; mov rax, [rbx - 4]
        // labels
        ; a: // local
        ; -> b: // global
        ; => label // dynamic. note the lack of a trailing :. this is due to : being a valid symbol within expressions that does not occur in any other normal rust expr contexts.
        // jumps
        ; jmp <a
        ; jmp -> b
        ; jmp => label
        // rip relative stuff
        ; lea rax, [->b]
        // dynamic registers
        ; inc Rb(1)
        ; inc Rh(5)
        ; inc Rw(1)
        ; inc Rd(1)
        ; inc Rq(1)
        ; mov Rb(7), [Rq(3)*4 + rax]
        ; fsub Rf(5), st0
        // other register families
        ; mov cr1, rax
        ; mov dr1, rax
        ; mov rax, cr1
        ; mov rax, dr1
        ; pop fs
        ; movmskps eax, xmm7
        ; movd mm7, eax
        ; movd eax, mm7
        ; fcomp st0
        // VEX/XOP instructions
        ; andn rax, rcx, rdx
        ; andn r8, r9, r10
        ; bextr rax, rbx, 1
        ; vaddpd xmm0, xmm1, [rax]
        // VSIB addressing
        ; vgatherqpd ymm1, QWORD [ymm15*8 + rsi + 0x11112222], ymm8
        // 4 argument instructions
        ; vfmaddss xmm0, xmm1, xmm2, xmm3
        // directives
        ; string:
        //; .bytes "Hello world!\0".bytes()
    );

    // typemap support
    #[allow(dead_code)]
    struct Test {
        foo: i32,
        bar: u32
    }
    let mut test_array = [Test {foo: 1, bar: 2}, Test {foo: 3, bar: 4}, Test {foo: 5, bar: 6}];
    let mut test_array = &mut test_array;
    let mut test_single = Test {foo: 7, bar: 8};
    let mut test_single = &mut test_single;
    dynasm!(ops
        ; mov rax, AWORD MutPointer!(test_array)
        ; mov ebx, 2
        ; inc DWORD rax => Test[2].bar
        ; inc DWORD rax => Test[2 + rbx].bar
        ; inc DWORD rax => Test[rbx].bar
        ; inc DWORD rax => Test[rbx]
        ; mov rax, AWORD MutPointer!(test_single)
        ; inc DWORD rax => Test.bar
    );

    // dynasm in expr position
    match 1 {
        0 => (),
        _ => dynasm!(ops; inc rax)
    }

    // fixups
    let start = ops.offset();
    dynasm!( (ops)
        ; inc rbx
    );
    let end = ops.offset();
    ops.alter(|ops| {
        ops.goto(start);
        dynasm!(ops
            ; inc r12
        );
        ops.check(end);
    });

    let index = ops.offset();
    dynasm!(ops
        ; mov eax, 10203040
        ; ret
    );

    let buf = ops.finalize().unwrap();

    println!("Generated assembly:");
    for i in buf.iter() {
        print!("{:02x }", i);
    }
    println!("");

    let func: extern "C" fn() -> i64 = unsafe { std::mem::transmute(buf.ptr(index)) };
    println!("assembled function result: {}", func() );
}
<|endoftext|>


<commit_before>use byteorder::{LittleEndian, WriteBytesExt};
use std::collections::HashSet;
use std::io::prelude::*;
use std::io::{Cursor, Seek};
use std::iter::FromIterator;
use zip::write::FileOptions;
use zip::{CompressionMethod, SUPPORTED_METHODS};

// This test asserts that after creating a zip file, then reading its contents back out,
// the extracted data will *always* be exactly the same as the original data.
#[test]
fn end_to_end() {
    for &method in SUPPORTED_METHODS {
        let file = &mut Cursor::new(Vec::new());

        println!("Writing file with {} compression", method);
        write_to_zip(file, method).expect("Couldn't write to test file");

        println!("Checking file contents");
        check_zip_contents(file, ENTRY_NAME, Some(method));
    }
}

// This test asserts that after copying a `ZipFile` to a new `ZipWriter`, then reading its
// contents back out, the extracted data will *always* be exactly the same as the original data.
#[test]
fn copy() {
    for &method in SUPPORTED_METHODS {
        let src_file = &mut Cursor::new(Vec::new());
        write_to_zip(src_file, method).expect("Couldn't write to test file");

        let mut tgt_file = &mut Cursor::new(Vec::new());

        {
            let mut src_archive = zip::ZipArchive::new(src_file).unwrap();
            let mut zip = zip::ZipWriter::new(&mut tgt_file);

            {
                let file = src_archive
                    .by_name(ENTRY_NAME)
                    .expect("Missing expected file");

                zip.raw_copy_file(file).expect("Couldn't copy file");
            }

            {
                let file = src_archive
                    .by_name(ENTRY_NAME)
                    .expect("Missing expected file");

                zip.raw_copy_file_rename(file, COPY_ENTRY_NAME)
                    .expect("Couldn't copy and rename file");
            }
        }

        let mut tgt_archive = zip::ZipArchive::new(tgt_file).unwrap();

        check_zip_file_contents(&mut tgt_archive, ENTRY_NAME);
        check_zip_file_contents(&mut tgt_archive, COPY_ENTRY_NAME);
    }
}

// This test asserts that after appending to a `ZipWriter`, then reading its contents back out,
// both the prior data and the appended data will be exactly the same as their originals.
#[test]
fn append() {
    for &method in SUPPORTED_METHODS {
        let mut file = &mut Cursor::new(Vec::new());
        write_to_zip(file, method).expect("Couldn't write to test file");

        {
            let mut zip = zip::ZipWriter::new_append(&mut file).unwrap();
            zip.start_file(
                COPY_ENTRY_NAME,
                FileOptions::default().compression_method(method),
            )
            .unwrap();
            zip.write_all(LOREM_IPSUM).unwrap();
            zip.finish().unwrap();
        }

        let mut zip = zip::ZipArchive::new(&mut file).unwrap();
        check_zip_file_contents(&mut zip, ENTRY_NAME);
        check_zip_file_contents(&mut zip, COPY_ENTRY_NAME);
    }
}

fn write_to_zip(
    file: &mut Cursor<Vec<u8>>,
    method: CompressionMethod,
) -> zip::result::ZipResult<()> {
    let mut zip = zip::ZipWriter::new(file);

    zip.add_directory("test/", Default::default())?;

    let options = FileOptions::default()
        .compression_method(method)
        .unix_permissions(0o755);

    zip.start_file("test/☃.txt", options)?;
    zip.write_all(b"Hello, World!\n")?;

    zip.start_file_with_extra_data("test_with_extra_data/🐢.txt", options)?;
    zip.write_u16::<LittleEndian>(0xbeef)?;
    zip.write_u16::<LittleEndian>(EXTRA_DATA.len() as u16)?;
    zip.write_all(EXTRA_DATA)?;
    zip.end_extra_data()?;
    zip.write_all(b"Hello, World! Again.\n")?;

    zip.start_file(ENTRY_NAME, options)?;
    zip.write_all(LOREM_IPSUM)?;

    zip.finish()?;
    Ok(())
}

fn read_zip<R: Read + Seek>(zip_file: R) -> zip::result::ZipResult<zip::ZipArchive<R>> {
    let mut archive = zip::ZipArchive::new(zip_file).unwrap();

    let expected_file_names = [
        "test/",
        "test/☃.txt",
        "test_with_extra_data/🐢.txt",
        ENTRY_NAME,
    ];
    let expected_file_names = HashSet::from_iter(expected_file_names.iter().copied());
    let file_names = archive.file_names().collect::<HashSet<_>>();
    assert_eq!(file_names, expected_file_names);

    {
        let file_with_extra_data = archive.by_name("test_with_extra_data/🐢.txt")?;
        let mut extra_data = Vec::new();
        extra_data.write_u16::<LittleEndian>(0xbeef)?;
        extra_data.write_u16::<LittleEndian>(EXTRA_DATA.len() as u16)?;
        extra_data.write_all(EXTRA_DATA)?;
        assert_eq!(file_with_extra_data.extra_data(), extra_data.as_slice());
    }

    Ok(archive)
}

fn read_zip_file<R: Read + Seek>(
    archive: &mut zip::ZipArchive<R>,
    name: &str,
) -> zip::result::ZipResult<String> {
    let mut file = archive.by_name(name)?;

    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    Ok(contents)
}

fn check_zip_contents(
    zip_file: &mut Cursor<Vec<u8>>,
    name: &str,
    expected_method: Option<CompressionMethod>,
) {
    let mut archive = read_zip(zip_file).unwrap();

    if let Some(expected_method) = expected_method {
        let file = archive.by_name(name).unwrap();
        let real_method = file.compression();

        assert_eq!(
            expected_method, real_method,
            "File does not have expected compression method"
        );
    }

    check_zip_file_contents(&mut archive, name);
}

fn check_zip_file_contents<R: Read + Seek>(archive: &mut zip::ZipArchive<R>, name: &str) {
    let file_contents: String = read_zip_file(archive, name).unwrap();
    assert_eq!(file_contents.as_bytes(), LOREM_IPSUM);
}

const LOREM_IPSUM : &[u8] = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In tellus elit, tristique vitae mattis egestas, ultricies vitae risus. Quisque sit amet quam ut urna aliquet
molestie. Proin blandit ornare dui, a tempor nisl accumsan in. Praesent a consequat felis. Morbi metus diam, auctor in auctor vel, feugiat id odio. Curabitur ex ex,
dictum quis auctor quis, suscipit id lorem. Aliquam vestibulum dolor nec enim vehicula, porta tristique augue tincidunt. Vivamus ut gravida est. Sed pellentesque, dolor
vitae tristique consectetur, neque lectus pulvinar dui, sed feugiat purus diam id lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per
inceptos himenaeos. Maecenas feugiat velit in ex ultrices scelerisque id id neque.
";

const EXTRA_DATA: &[u8] = b"Extra Data";

const ENTRY_NAME: &str = "test/lorem_ipsum.txt";

const COPY_ENTRY_NAME: &str = "test/lorem_ipsum_renamed.txt";
<commit_msg>Add comments to test helpers<commit_after>use byteorder::{LittleEndian, WriteBytesExt};
use std::collections::HashSet;
use std::io::prelude::*;
use std::io::{Cursor, Seek};
use std::iter::FromIterator;
use zip::write::FileOptions;
use zip::{CompressionMethod, SUPPORTED_METHODS};

// This test asserts that after creating a zip file, then reading its contents back out,
// the extracted data will *always* be exactly the same as the original data.
#[test]
fn end_to_end() {
    for &method in SUPPORTED_METHODS {
        let file = &mut Cursor::new(Vec::new());

        println!("Writing file with {} compression", method);
        write_to_zip(file, method).expect("Couldn't write to test file");

        println!("Checking file contents");
        check_zip_contents(file, ENTRY_NAME, Some(method));
    }
}

// This test asserts that after copying a `ZipFile` to a new `ZipWriter`, then reading its
// contents back out, the extracted data will *always* be exactly the same as the original data.
#[test]
fn copy() {
    for &method in SUPPORTED_METHODS {
        let src_file = &mut Cursor::new(Vec::new());
        write_to_zip(src_file, method).expect("Couldn't write to test file");

        let mut tgt_file = &mut Cursor::new(Vec::new());

        {
            let mut src_archive = zip::ZipArchive::new(src_file).unwrap();
            let mut zip = zip::ZipWriter::new(&mut tgt_file);

            {
                let file = src_archive
                    .by_name(ENTRY_NAME)
                    .expect("Missing expected file");

                zip.raw_copy_file(file).expect("Couldn't copy file");
            }

            {
                let file = src_archive
                    .by_name(ENTRY_NAME)
                    .expect("Missing expected file");

                zip.raw_copy_file_rename(file, COPY_ENTRY_NAME)
                    .expect("Couldn't copy and rename file");
            }
        }

        let mut tgt_archive = zip::ZipArchive::new(tgt_file).unwrap();

        check_zip_file_contents(&mut tgt_archive, ENTRY_NAME);
        check_zip_file_contents(&mut tgt_archive, COPY_ENTRY_NAME);
    }
}

// This test asserts that after appending to a `ZipWriter`, then reading its contents back out,
// both the prior data and the appended data will be exactly the same as their originals.
#[test]
fn append() {
    for &method in SUPPORTED_METHODS {
        let mut file = &mut Cursor::new(Vec::new());
        write_to_zip(file, method).expect("Couldn't write to test file");

        {
            let mut zip = zip::ZipWriter::new_append(&mut file).unwrap();
            zip.start_file(
                COPY_ENTRY_NAME,
                FileOptions::default().compression_method(method),
            )
            .unwrap();
            zip.write_all(LOREM_IPSUM).unwrap();
            zip.finish().unwrap();
        }

        let mut zip = zip::ZipArchive::new(&mut file).unwrap();
        check_zip_file_contents(&mut zip, ENTRY_NAME);
        check_zip_file_contents(&mut zip, COPY_ENTRY_NAME);
    }
}

// Write a test zip archive to buffer.
fn write_to_zip(
    file: &mut Cursor<Vec<u8>>,
    method: CompressionMethod,
) -> zip::result::ZipResult<()> {
    let mut zip = zip::ZipWriter::new(file);

    zip.add_directory("test/", Default::default())?;

    let options = FileOptions::default()
        .compression_method(method)
        .unix_permissions(0o755);

    zip.start_file("test/☃.txt", options)?;
    zip.write_all(b"Hello, World!\n")?;

    zip.start_file_with_extra_data("test_with_extra_data/🐢.txt", options)?;
    zip.write_u16::<LittleEndian>(0xbeef)?;
    zip.write_u16::<LittleEndian>(EXTRA_DATA.len() as u16)?;
    zip.write_all(EXTRA_DATA)?;
    zip.end_extra_data()?;
    zip.write_all(b"Hello, World! Again.\n")?;

    zip.start_file(ENTRY_NAME, options)?;
    zip.write_all(LOREM_IPSUM)?;

    zip.finish()?;
    Ok(())
}

// Load an archive from buffer and check for expected test data.
fn read_zip<R: Read + Seek>(zip_file: R) -> zip::result::ZipResult<zip::ZipArchive<R>> {
    let mut archive = zip::ZipArchive::new(zip_file).unwrap();

    let expected_file_names = [
        "test/",
        "test/☃.txt",
        "test_with_extra_data/🐢.txt",
        ENTRY_NAME,
    ];
    let expected_file_names = HashSet::from_iter(expected_file_names.iter().copied());
    let file_names = archive.file_names().collect::<HashSet<_>>();
    assert_eq!(file_names, expected_file_names);

    {
        let file_with_extra_data = archive.by_name("test_with_extra_data/🐢.txt")?;
        let mut extra_data = Vec::new();
        extra_data.write_u16::<LittleEndian>(0xbeef)?;
        extra_data.write_u16::<LittleEndian>(EXTRA_DATA.len() as u16)?;
        extra_data.write_all(EXTRA_DATA)?;
        assert_eq!(file_with_extra_data.extra_data(), extra_data.as_slice());
    }

    Ok(archive)
}

// Read a file in the archive as a string.
fn read_zip_file<R: Read + Seek>(
    archive: &mut zip::ZipArchive<R>,
    name: &str,
) -> zip::result::ZipResult<String> {
    let mut file = archive.by_name(name)?;

    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    Ok(contents)
}

// Check a file in the archive contains expected data.
fn check_zip_contents(
    zip_file: &mut Cursor<Vec<u8>>,
    name: &str,
    expected_method: Option<CompressionMethod>,
) {
    let mut archive = check_test_archive(zip_file).unwrap();

    if let Some(expected_method) = expected_method {
        // Check the file's compression method.
        let file = archive.by_name(name).unwrap();
        let real_method = file.compression();

        assert_eq!(
            expected_method, real_method,
            "File does not have expected compression method"
        );
    }

    check_test_file_contents(&mut archive, name);
}

// Check a file in the archive contains the lorem string.
fn check_test_file_contents<R: Read + Seek>(archive: &mut zip::ZipArchive<R>, name: &str) {
    let file_contents: String = read_zip_file(archive, name).unwrap();
    assert_eq!(file_contents.as_bytes(), LOREM_IPSUM);
}

const LOREM_IPSUM : &[u8] = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In tellus elit, tristique vitae mattis egestas, ultricies vitae risus. Quisque sit amet quam ut urna aliquet
molestie. Proin blandit ornare dui, a tempor nisl accumsan in. Praesent a consequat felis. Morbi metus diam, auctor in auctor vel, feugiat id odio. Curabitur ex ex,
dictum quis auctor quis, suscipit id lorem. Aliquam vestibulum dolor nec enim vehicula, porta tristique augue tincidunt. Vivamus ut gravida est. Sed pellentesque, dolor
vitae tristique consectetur, neque lectus pulvinar dui, sed feugiat purus diam id lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per
inceptos himenaeos. Maecenas feugiat velit in ex ultrices scelerisque id id neque.
";

const EXTRA_DATA: &[u8] = b"Extra Data";

const ENTRY_NAME: &str = "test/lorem_ipsum.txt";

const COPY_ENTRY_NAME: &str = "test/lorem_ipsum_renamed.txt";
<|endoftext|>


<commit_before>extern crate veye_checker;

use std::path::PathBuf;
use veye_checker::{tasks, product, configs};

#[test]
fn test_task_start_path_scanner(){
    let test_dir = PathBuf::from("test/fixtures/files");
    let (sha_ch, h1) = tasks::start_path_scanner(test_dir);

    for sha in sha_ch.into_iter() {
        assert_eq!(true, sha.value.len() > 0);
        assert_eq!(true, sha.filepath.is_some());
    }

    h1.join().unwrap();

}

#[test]
fn test_task_start_path_scanner_folder_dont_exist(){
    let test_dir = PathBuf::from("test/fixtures/dont_exists");
    assert_eq!(false, test_dir.exists());

    let (sha_ch, h1) = tasks::start_path_scanner(test_dir);

    let res = h1.join().unwrap();
    assert_eq!(true, res.is_err())

}

#[test]
fn test_task_start_sha_publisher(){
    let test_shas = vec![product::ProductSHA::from_sha("abc-123".to_string())];

    let (sha_ch, h1) = tasks::start_sha_publisher(test_shas);

    for sha in sha_ch.into_iter(){
        assert_eq!("abc-123".to_string(), sha.value);
    }

    let res = h1.join().unwrap();
    assert_eq!(true, res.is_ok());
}

#[test]
fn test_task_start_sha_publisher_with_empty_array(){
    let test_shas = vec![];
    let (sha_ch, h1) = tasks::start_sha_publisher(test_shas);

    let res = h1.join().unwrap();
    assert_eq!(true, res.is_ok());
}

#[test]
#[cfg(feature="api")]
fn test_api_task_start_sha_fetcher(){
    let file_sha = "5675fd96b29656504b86029551973d60fb41339b";
    let confs = configs::read_configs(); //dont forget to specify API_KEY
    let test_shas = vec![
        product::ProductSHA::from_sha(file_sha.to_string())
    ];

    let (sha_ch, h1) = tasks::start_sha_publisher(test_shas);
    let (prod_ch, h2) = tasks::start_sha_fetcher(confs.api, sha_ch);

    for res in prod_ch.into_iter() {
        assert_eq!(true, res.sha.is_some());

        let sha = res.sha.unwrap();
        assert_eq!("".to_string(), sha.packaging); //it keeps original sha doc
        assert_eq!("".to_string(), sha.method);
        assert_eq!(file_sha.to_string(), sha.value);
        assert_eq!(None, sha.filepath);

        assert_eq!(true, res.product.is_some());
        let prod = res.product.unwrap();
        assert_eq!("java".to_string(), prod.language);
        assert_eq!("Maven2".to_string(), prod.prod_type.unwrap());
        assert_eq!("commons-beanutils/commons-beanutils".to_string(), prod.prod_key);
        assert_eq!("1.7.0".to_string(), prod.version);
        assert_eq!("commons-beanutils".to_string(), prod.name);

    }

    let res1 = h1.join().unwrap();
    assert_eq!(true, res1.is_ok());
    let res2 = h2.join().unwrap();
    assert_eq!(true, res2.is_ok());
}

#[test]
#[cfg(feature="api")]
fn test_api_task_start_sha_fetcher_sha_dont_exists(){
    let file_sha = "abc-123-dont-exists";
    let confs = configs::read_configs();
    let test_shas = vec![
        product::ProductSHA::from_sha(file_sha.to_string())
    ];

    let (sha_ch, h1) = tasks::start_sha_publisher(test_shas);
    let (prod_ch, h2) = tasks::start_sha_fetcher(confs.api, sha_ch);

    //it should return ProductMatch with original sha and empty prod info
    for res in prod_ch.into_iter() {
        assert_eq!(true, res.sha.is_some());
        let sha = res.sha.unwrap();
        assert_eq!("".to_string(), sha.packaging); //it keeps original sha doc
        assert_eq!("".to_string(), sha.method);
        assert_eq!(file_sha.to_string(), sha.value);
        assert_eq!(None, sha.filepath);

        assert_eq!(true, res.product.is_none());
    }

    let res1 = h1.join().unwrap();
    assert_eq!(true, res1.is_ok());
    let res2 = h2.join().unwrap();
    assert_eq!(true, res2.is_ok());
}<commit_msg>add tests for tasks:start_sha_csv_writer;<commit_after>extern crate veye_checker;

use std::path::PathBuf;
use std::fs::{self, File};
use std::io::Read;
use veye_checker::{tasks, product, configs};

#[test]
fn test_task_start_path_scanner(){
    let test_dir = PathBuf::from("test/fixtures/files");
    let (sha_ch, h1) = tasks::start_path_scanner(test_dir);

    for sha in sha_ch.into_iter() {
        assert_eq!(true, sha.value.len() > 0);
        assert_eq!(true, sha.filepath.is_some());
    }

    h1.join().unwrap();

}

#[test]
fn test_task_start_path_scanner_folder_dont_exist(){
    let test_dir = PathBuf::from("test/fixtures/dont_exists");
    assert_eq!(false, test_dir.exists());

    let (sha_ch, h1) = tasks::start_path_scanner(test_dir);

    let res = h1.join().unwrap();
    assert_eq!(true, res.is_err())

}

#[test]
fn test_task_start_sha_publisher(){
    let test_shas = vec![product::ProductSHA::from_sha("abc-123".to_string())];

    let (sha_ch, h1) = tasks::start_sha_publisher(test_shas);

    for sha in sha_ch.into_iter(){
        assert_eq!("abc-123".to_string(), sha.value);
    }

    let res = h1.join().unwrap();
    assert_eq!(true, res.is_ok());
}

#[test]
fn test_task_start_sha_publisher_with_empty_array(){
    let test_shas = vec![];
    let (sha_ch, h1) = tasks::start_sha_publisher(test_shas);

    let res = h1.join().unwrap();
    assert_eq!(true, res.is_ok());
}

#[test]
#[cfg(feature="api")]
fn test_api_task_start_sha_fetcher(){
    let file_sha = "5675fd96b29656504b86029551973d60fb41339b";
    let confs = configs::read_configs(); //dont forget to specify API_KEY
    let test_shas = vec![
        product::ProductSHA::from_sha(file_sha.to_string())
    ];

    let (sha_ch, h1) = tasks::start_sha_publisher(test_shas);
    let (prod_ch, h2) = tasks::start_sha_fetcher(confs.api, sha_ch);

    for res in prod_ch.into_iter() {
        assert_eq!(true, res.sha.is_some());

        let sha = res.sha.unwrap();
        assert_eq!("".to_string(), sha.packaging); //it keeps original sha doc
        assert_eq!("".to_string(), sha.method);
        assert_eq!(file_sha.to_string(), sha.value);
        assert_eq!(None, sha.filepath);

        assert_eq!(true, res.product.is_some());
        let prod = res.product.unwrap();
        assert_eq!("java".to_string(), prod.language);
        assert_eq!("Maven2".to_string(), prod.prod_type.unwrap());
        assert_eq!("commons-beanutils/commons-beanutils".to_string(), prod.prod_key);
        assert_eq!("1.7.0".to_string(), prod.version);
        assert_eq!("commons-beanutils".to_string(), prod.name);

    }

    let res1 = h1.join().unwrap();
    assert_eq!(true, res1.is_ok());
    let res2 = h2.join().unwrap();
    assert_eq!(true, res2.is_ok());
}

#[test]
#[cfg(feature="api")]
fn test_api_task_start_sha_fetcher_sha_dont_exists(){
    let file_sha = "abc-123-dont-exists";
    let confs = configs::read_configs();
    let test_shas = vec![
        product::ProductSHA::from_sha(file_sha.to_string())
    ];

    let (sha_ch, h1) = tasks::start_sha_publisher(test_shas);
    let (prod_ch, h2) = tasks::start_sha_fetcher(confs.api, sha_ch);

    //it should return ProductMatch with original sha and empty prod info
    for res in prod_ch.into_iter() {
        assert_eq!(true, res.sha.is_some());
        let sha = res.sha.unwrap();
        assert_eq!("".to_string(), sha.packaging); //it keeps original sha doc
        assert_eq!("".to_string(), sha.method);
        assert_eq!(file_sha.to_string(), sha.value);
        assert_eq!(None, sha.filepath);

        assert_eq!(true, res.product.is_none());
    }

    let res1 = h1.join().unwrap();
    assert_eq!(true, res1.is_ok());
    let res2 = h2.join().unwrap();
    assert_eq!(true, res2.is_ok());
}

#[test]
fn test_task_start_sha_csv_writer(){
    let file_sha = "5675fd96b29656504b86029551973d60fb41339b";
    let test_shas = vec![
        product::ProductSHA::from_sha(file_sha.to_string())
    ];
    let outpath = PathBuf::from("temp/test_task_sha_writer.csv");
    let expected_content = "filepath,packaging,sha_method,sha_value\n,,,5675fd96b29656504b86029551973d60fb41339b\n";

    let (sha_ch, h1) = tasks::start_sha_publisher(test_shas);
    let h2 = tasks::start_sha_csv_writer(outpath.clone(), sha_ch);

    let res1 = h1.join().unwrap();
    assert_eq!(true, res1.is_ok());
    let res2 = h2.join().unwrap();
    assert_eq!(true, res2.is_ok());

    let f_res = File::open(outpath.clone().as_path());
    assert_eq!(true, f_res.is_ok());
    let mut fd = f_res.unwrap();
    let mut content = String::new();
    fd.read_to_string(&mut content);
    assert_eq!(expected_content.to_string(), content);

    fs::remove_file(outpath.as_path()).expect("Failed to delete test_task_start_sha file");
}

#[test]
fn test_task_start_sha_csv_writer_empty_input(){
    let test_shas = vec![];
    let outpath = PathBuf::from("temp/test_task_sha_writer_empty.csv");
    let expected_content = "";

    let (sha_ch, h1) = tasks::start_sha_publisher(test_shas);
    let h2 = tasks::start_sha_csv_writer(outpath.clone(), sha_ch);

    let res1 = h1.join().unwrap();
    assert_eq!(true, res1.is_ok());
    let res2 = h2.join().unwrap();
    assert_eq!(true, res2.is_ok());

    let f_res = File::open(outpath.clone().as_path());
    assert_eq!(true, f_res.is_ok());
    let mut fd = f_res.unwrap();
    let mut content = String::new();
    fd.read_to_string(&mut content);
    assert_eq!(expected_content.to_string(), content);

    fs::remove_file(outpath.as_path()).expect("Failed to delete test_task_start_sha file");
}<|endoftext|>


<commit_before>extern crate adt;

#[cfg(test)]
mod test {
    use adt::{
        ArrayStack,
        Stack
    };

    #[test]
    fn test_new_array_stack() {
        // Initialize the test stack.
        let stack: ArrayStack<int> = ArrayStack::new();

        // Verify that the stack is empty.
        assert!(stack.is_empty());
        assert_eq!(stack.size(), 0);
    }

    #[test]
    fn test_push_array_stack() {
        // Initialize a test stack.
        let mut stack: ArrayStack<int> = ArrayStack::new();

        // Push some elements onto the stack.
        stack.push(1);
        stack.push(43);
        stack.push(22);

        // Verify that the stack contains 3 elements.
        assert!(!stack.is_empty());
        assert_eq!(stack.size(), 3);
    }

    #[test]
    fn test_push_then_pop_array_stack() {
        // Initialize a test stack.
        let mut stack: ArrayStack<int> = ArrayStack::new();

        // Push some elements onto the stack.
        stack.push(1);
        stack.push(43);
        stack.push(22);

        // Verify that the pop() function works correctly.
        assert_eq!(stack.pop().unwrap(), 22);
        assert_eq!(stack.size(), 2);
    }

    #[test]
    fn test_push_then_peek_array_stack() {
        // Initialize a test stack.
        let mut stack: ArrayStack<int> = ArrayStack::new();

        // Push some elements onto the stack.
        stack.push(1);
        stack.push(43);
        stack.push(22);

        // Verify that the peek() function works correctly.
        assert_eq!(stack.peek().unwrap(), &22);
        assert_eq!(stack.size(), 3);
    }

    #[test]
    fn test_pop_until_empty_array_stack() {
        // Initialize a test stack.
        let mut stack: ArrayStack<int> = ArrayStack::new();

        // Push some elements onto the stack.
        stack.push(1);
        stack.push(43);
        stack.push(22);

        // Pop the elements off the stack.
        stack.pop();
        stack.pop();
        stack.pop();

        // Verify that the stack is now empty.
        assert!(stack.is_empty());
        assert_eq!(stack.size(), 0);
    }

    #[test]
    fn test_pop_empty_array_stack() {
        // Initialize a test stack.
        let mut stack: ArrayStack<int> = ArrayStack::new();

        // Pop a non-existing element off the stack.
        assert_eq!(stack.pop(), None);
    }

    #[test]
    fn test_peek_empty_array_stack() {
        // Initialize a test stack.
        let stack: ArrayStack<int> = ArrayStack::new();

        // Peek a non-existing element from the stack.
        assert_eq!(stack.peek(), None);
    }
}
<commit_msg>Remove .unwrap() from Stack tests<commit_after>extern crate adt;

#[cfg(test)]
mod test {
    use adt::{
        ArrayStack,
        Stack
    };

    #[test]
    fn test_new_array_stack() {
        // Initialize the test stack.
        let stack: ArrayStack<int> = ArrayStack::new();

        // Verify that the stack is empty.
        assert!(stack.is_empty());
        assert_eq!(stack.size(), 0);
    }

    #[test]
    fn test_push_array_stack() {
        // Initialize a test stack.
        let mut stack: ArrayStack<int> = ArrayStack::new();

        // Push some elements onto the stack.
        stack.push(1);
        stack.push(43);
        stack.push(22);

        // Verify that the stack contains 3 elements.
        assert!(!stack.is_empty());
        assert_eq!(stack.size(), 3);
    }

    #[test]
    fn test_push_then_pop_array_stack() {
        // Initialize a test stack.
        let mut stack: ArrayStack<int> = ArrayStack::new();

        // Push some elements onto the stack.
        stack.push(1);
        stack.push(43);
        stack.push(22);

        // Verify that the pop() function works correctly.
        assert_eq!(stack.pop(), Some(22));
        assert_eq!(stack.size(), 2);
    }

    #[test]
    fn test_push_then_peek_array_stack() {
        // Initialize a test stack.
        let mut stack: ArrayStack<int> = ArrayStack::new();

        // Push some elements onto the stack.
        stack.push(1);
        stack.push(43);
        stack.push(22);

        // Verify that the peek() function works correctly.
        assert_eq!(stack.peek(), Some(&22));
        assert_eq!(stack.size(), 3);
    }

    #[test]
    fn test_pop_until_empty_array_stack() {
        // Initialize a test stack.
        let mut stack: ArrayStack<int> = ArrayStack::new();

        // Push some elements onto the stack.
        stack.push(1);
        stack.push(43);
        stack.push(22);

        // Pop the elements off the stack.
        stack.pop();
        stack.pop();
        stack.pop();

        // Verify that the stack is now empty.
        assert!(stack.is_empty());
        assert_eq!(stack.size(), 0);
    }

    #[test]
    fn test_pop_empty_array_stack() {
        // Initialize a test stack.
        let mut stack: ArrayStack<int> = ArrayStack::new();

        // Pop a non-existing element off the stack.
        assert_eq!(stack.pop(), None);
    }

    #[test]
    fn test_peek_empty_array_stack() {
        // Initialize a test stack.
        let stack: ArrayStack<int> = ArrayStack::new();

        // Peek a non-existing element from the stack.
        assert_eq!(stack.peek(), None);
    }
}
<|endoftext|>