<commit_before>use game::constants::{RESOLUTION_X, RESOLUTION_Y};
use gfx;
use gfx_device_gl;
use gfx_window_glutin;
use glutin;
use glutin::GlContext;

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct GlutinWindow {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl GlutinWindow {
  pub fn new() -> GlutinWindow {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Hinterland");

    let builder = if cfg!(feature = "windowed") {
      window_title.with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    } else {
      let monitor = {
        events_loop.get_available_monitors().nth(0).expect("Please enter a valid ID")
      };
      window_title.with_fullscreen(Some(monitor))
                  .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    };

    let context = glutin::ContextBuilder::new()
      .with_vsync(true)
      .with_pixel_format(24, 8)
      .with_gl(glutin::GlRequest::GlThenGles {
        opengles_version: (3, 0),
        opengl_version: (4, 1),
      });

    let (window, device, factory, rtv, dsv) = gfx_window_glutin::init::<ColorFormat,
      DepthFormat>(builder, context, &events_loop);

    GlutinWindow {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0),
    }
  }
}

#[derive(Debug, PartialEq, Eq)]
pub enum GameStatus {
  Running,
  Quit,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);
  fn get_viewport_size(&mut self) -> (f32, f32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_hidpi_factor(&mut self) -> f32;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
  fn poll_events(&mut self) -> GameStatus;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for GlutinWindow {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
        .swap_buffers()
        .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (f32, f32) {
    let viewport = self.window
        .get_inner_size()
        .unwrap_or((RESOLUTION_X, RESOLUTION_Y));
    ((viewport.0 as f32), (viewport.1 as f32))
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_hidpi_factor(&mut self) -> f32 {
    self.window.hidpi_factor()
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }
  fn poll_events(&mut self) -> GameStatus {
    use glutin::KeyboardInput;
    use glutin::MouseButton;
    use glutin::WindowEvent::{Resized, CloseRequested, CursorMoved, MouseInput};
    use glutin::ElementState::{Pressed, Released};
    use glutin::VirtualKeyCode::{Escape, Z, X, W, A, S, D};

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };
    let w = &self.window;
    let m_rtv = &mut self.render_target_view;
    let m_dsv = &mut self.depth_stencil_view;
    let m_pos = &mut self.mouse_pos;

    let mut game_status = GameStatus::Running;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => match input {
            KeyboardInput { virtual_keycode: Some(Escape), .. } => GameStatus::Quit,
            KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => {
              controls.zoom_out();
              GameStatus::Running
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
              controls.zoom_in();
              GameStatus::Running
            }
            KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
              controls.zoom_stop();
              GameStatus::Running
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
              controls.move_character_up();
              GameStatus::Running
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
              controls.move_character_down();
              GameStatus::Running
            }
            KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
              controls.stop_character_y();
              GameStatus::Running
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
              controls.move_character_left();
              GameStatus::Running
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
              controls.move_character_right();
              GameStatus::Running
            }
            KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
              controls.stop_character_x();
              GameStatus::Running
            }
            KeyboardInput { state: Pressed, modifiers, .. } => {
              if modifiers.ctrl {
                controls.ctrl_pressed();
              }
              GameStatus::Running
            }
            KeyboardInput { state: Released, modifiers, .. } => {
              if !modifiers.ctrl {
                controls.ctrl_released();
              }
              GameStatus::Running
            }
          },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            GameStatus::Running
          }
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            GameStatus::Running
          }
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            GameStatus::Running
          }
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            GameStatus::Running
          }
          CursorMoved { position, .. } => {
            *m_pos = position;
            GameStatus::Running
          }
          CloseRequested => GameStatus::Quit,
          Resized(_, _) => {
            gfx_window_glutin::update_views(w, m_rtv, m_dsv);
            GameStatus::Quit
          }
          _ => GameStatus::Running,
        }
      } else {
        GameStatus::Running
      };
    });
    game_status
  }
}

<commit_msg>Fix GameStatus bug when resizing window<commit_after>use game::constants::{RESOLUTION_X, RESOLUTION_Y};
use gfx;
use gfx_device_gl;
use gfx_window_glutin;
use glutin;
use glutin::GlContext;

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct GlutinWindow {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl GlutinWindow {
  pub fn new() -> GlutinWindow {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Hinterland");

    let builder = if cfg!(feature = "windowed") {
      window_title.with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    } else {
      let monitor = {
        events_loop.get_available_monitors().nth(0).expect("Please enter a valid ID")
      };
      window_title.with_fullscreen(Some(monitor))
                  .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    };

    let context = glutin::ContextBuilder::new()
      .with_vsync(true)
      .with_pixel_format(24, 8)
      .with_gl(glutin::GlRequest::GlThenGles {
        opengles_version: (3, 0),
        opengl_version: (4, 1),
      });

    let (window, device, factory, rtv, dsv) = gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    GlutinWindow {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0),
    }
  }
}

#[derive(Debug, PartialEq, Eq)]
pub enum GameStatus {
  Running,
  Quit,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);
  fn get_viewport_size(&mut self) -> (f32, f32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_hidpi_factor(&mut self) -> f32;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
  fn poll_events(&mut self) -> GameStatus;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for GlutinWindow {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
        .swap_buffers()
        .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (f32, f32) {
    let viewport = self.window
        .get_inner_size()
        .unwrap_or((RESOLUTION_X, RESOLUTION_Y));
    ((viewport.0 as f32), (viewport.1 as f32))
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_hidpi_factor(&mut self) -> f32 {
    self.window.hidpi_factor()
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }
  fn poll_events(&mut self) -> GameStatus {
    use glutin::KeyboardInput;
    use glutin::MouseButton;
    use glutin::WindowEvent::{Resized, CloseRequested, CursorMoved, MouseInput};
    use glutin::ElementState::{Pressed, Released};
    use glutin::VirtualKeyCode::{Escape, Z, X, W, A, S, D};

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };
    let w = &self.window;
    let m_rtv = &mut self.render_target_view;
    let m_dsv = &mut self.depth_stencil_view;
    let m_pos = &mut self.mouse_pos;

    let mut game_status = GameStatus::Running;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => match input {
            KeyboardInput { virtual_keycode: Some(Escape), .. } => GameStatus::Quit,
            KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => {
              controls.zoom_out();
              GameStatus::Running
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
              controls.zoom_in();
              GameStatus::Running
            }
            KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
              controls.zoom_stop();
              GameStatus::Running
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
              controls.move_character_up();
              GameStatus::Running
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
              controls.move_character_down();
              GameStatus::Running
            }
            KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
              controls.stop_character_y();
              GameStatus::Running
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
              controls.move_character_left();
              GameStatus::Running
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
              controls.move_character_right();
              GameStatus::Running
            }
            KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
              controls.stop_character_x();
              GameStatus::Running
            }
            KeyboardInput { state: Pressed, modifiers, .. } => {
              if modifiers.ctrl {
                controls.ctrl_pressed();
              }
              GameStatus::Running
            }
            KeyboardInput { state: Released, modifiers, .. } => {
              if !modifiers.ctrl {
                controls.ctrl_released();
              }
              GameStatus::Running
            }
          },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            GameStatus::Running
          }
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            GameStatus::Running
          }
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            GameStatus::Running
          }
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            GameStatus::Running
          }
          CursorMoved { position, .. } => {
            *m_pos = position;
            GameStatus::Running
          }
          CloseRequested => GameStatus::Quit,
          Resized(_, _) => {
            gfx_window_glutin::update_views(w, m_rtv, m_dsv);
            GameStatus::Running
          }
          _ => GameStatus::Running,
        }
      } else {
        GameStatus::Running
      };
    });
    game_status
  }
}

<|endoftext|>


<commit_before>use std::sync::Arc;
use crate::{syntax::{ast, Value}, tree::Tree, core::Dir};
use super::{ConcatElem, Expr, Func, FunctionDef, Item, Scope, ShapeMsg, ExprDn, VarId, LeafItem };

pub fn value(scope: &Scope, e: &ast::Expr) -> Expr {
    match e {
        ast::Expr::Ignore(_) => Expr::Ignored,
        ast::Expr::Value(ref node) => Expr::Const(node.value.clone()),

        ast::Expr::Flip(ref node) => {
            Expr::Flip(
                Box::new(node.dn.as_ref().map_or(Expr::Ignored,  |dn| value(scope, dn))),
                Box::new(node.up.as_ref().map_or(Expr::Ignored,  |up| value(scope, up))),
            )
        }

        ast::Expr::Range(ref node) => {
            let min = value(scope, &node.lo);
            let max = value(scope, &node.hi);

            match (min, max) {
                (Expr::Const(Value::Number(l)), Expr::Const(Value::Number(h))) => Expr::Range(l, h),
                (Expr::Const(Value::Integer(l)), Expr::Const(Value::Integer(h))) => Expr::RangeInt(l, h),
                _ => panic!("Range expressions must be numeric constant")
            }
        }

        ast::Expr::Union(ref node) => {
            Expr::Union(node.items.iter().map(|i| value(scope, i)).collect())
        }

        ast::Expr::Choose(ref node) => {
            let head = value(scope, &node.e);

            if let Expr::Const(v) = head {
                let re = node.choices.iter().find(|&(ref le, _)| {
                    let l = value(scope, le);
                    l.eval_up(&mut |_, _, _| panic!("Variable not expected here"), v.clone())
                }).map(|x| &x.1).unwrap_or_else(|| {
                    panic!("No match for {} at {:?}", v, &node.span);
                });
                value(scope, re)
            } else {
                let pairs: Vec<(Value, Value)> = node.choices.iter().map(|&(ref le, ref re)| {
                    let l = value(scope, le);
                    let r = value(scope, re);

                    match (l, r) {
                        (Expr::Const(lv), Expr::Const(rv)) => (lv, rv),
                        _ => panic!("Choose expression arms must be constant, for now")
                    }
                }).collect();

                Expr::Choose(Box::new(head), pairs)
            }
        }

        ast::Expr::Concat(ref node) =>  {
            let elems = node.elems.iter().map(|&(slice_width, ref e)| {
                let expr = value(scope, e);
                match slice_width {
                    None => ConcatElem::Elem(expr),
                    Some(w) => ConcatElem::Slice(expr, w as usize)
                }
            }).collect();

            Expr::Concat(elems)
        }

        ast::Expr::Bin(ref node) => {
            use self::Expr::Const;
            let lhs = value(scope, &node.l);
            let rhs = value(scope, &node.r);
            let op = node.op;
            match (lhs, rhs) {
                (Const(Value::Number(a)),  Const(Value::Number(b))) => Const(Value::Number(op.eval(a, b))),
                (Const(Value::Integer(a)), Const(Value::Integer(b))) => Const(Value::Integer(op.eval(a, b))),
                (Const(Value::Complex(a)), Const(Value::Complex(b))) => Const(Value::Complex(op.eval(a, b))),
                (Const(Value::Complex(a)), Const(Value::Number(b))) => Const(Value::Complex(op.eval(a, b))),
                (Const(Value::Number(a)),  Const(Value::Complex(b))) => Const(Value::Complex(op.eval(a, b))),
                (l, Const(b)) => Expr::BinaryConst(Box::new(l), op, b),
                (Const(a), r) => Expr::BinaryConst(Box::new(r), op.swap(), a),
                _ => panic!("One side of a binary operation must be constant")
            }
        }

        ast::Expr::Var(ref name) => {
            match scope.get(&name.name) {
                Some(Item::Leaf(LeafItem::Value(v))) => v,
                Some(..) => panic!("Variable {} is not a value expression", name.name),
                None => panic!("Undefined variable {}", name.name),
            }
        }

        ast::Expr::Call(ref node) => {
            match resolve_call(scope, &node.func, &node.arg) {
                Item::Leaf(LeafItem::Value(v)) => v,
                other => panic!("Expcted value item, but function evaluated to {:?}", other),
            }
        }

        ast::Expr::Tup(t) if t.items.len() == 1 => { value(scope, &t.items[0]) }

        ast::Expr::Tup(..) => panic!("Tuple not allowed here"),
        ast::Expr::String(..) => panic!("String not allowed here"),
        ast::Expr::Func{..} => panic!("Function not allowed here"),
        ast::Expr::Error(_) => panic!("Syntax error"),
    }
}

pub fn rexpr_tup(scope: &Scope, node: &ast::ExprTup) -> Item {
    let values: Vec<Item> = node.items.iter().map(|i| rexpr(scope, i)).collect();
    if values.len() == 1 {
        values.into_iter().next().unwrap()
    } else {
        Item::Tuple(values)
    }
}

/// Resolve an expression as used in an argument or right hand side of an assignment
pub fn rexpr(scope: &Scope, e: &ast::Expr) -> Item {
    match e {
        ast::Expr::Var(ref name) => {
            if let Some(s) = scope.get(&name.name) { s } else { panic!("Undefined variable `{}`", name.name); }
        }

        ast::Expr::Tup(ref node) => rexpr_tup(scope, node),

        ast::Expr::String(ref node) => Item::Leaf(LeafItem::String(node.value.clone())),

        ast::Expr::Func(ref node) => {
            Item::Leaf(LeafItem::Func(Arc::new(FunctionDef::Code(Func{
                args: (*node.args).clone(),
                body: (*node.body).clone(),
                scope: scope.clone(),
            }))))
        }

        ast::Expr::Call(ref node) => {
            resolve_call(scope, &node.func, &node.arg)
        }

        _ => Item::Leaf(LeafItem::Value(value(scope, e)))
    }
}

fn resolve_call(scope: &Scope, func: &ast::Expr, arg: &ast::ExprTup) -> Item {
    let func = rexpr(scope, func);
    let arg = rexpr_tup(scope, arg);

    if let Item::Leaf(LeafItem::Func(func)) = func {
        func.apply(arg)
    } else {
        panic!("{:?} is not a function", func)
    }
}

fn zip_ast<T>(ast: &ast::Expr, tree: &Tree<T>, f: &mut impl FnMut(&ast::Expr, &Tree<T>) -> Result<(), &'static str>) -> Result<(), &'static str> {
    match (&ast, tree) {
        (ast::Expr::Tup(a), Tree::Tuple(t)) => {
            let mut a = a.items.iter();
            let mut t = t.iter();
            loop {
                match (a.next(), t.next()) {
                    (None, None) => break,
                    (Some(ai), Some(ti)) => zip_ast(ai, ti, f)?,
                    _ => return Err("mismatched tuples")
                }
            }
        }
        (_, t) => f(ast, t)?
    }
    Ok(())
}

/// Resolve expressions as used in the arguments of an `on` block, defining variables
pub fn on_expr_message(mut new_var: impl FnMut() -> VarId, scope: &mut Scope, msg_def: &ShapeMsg, exprs: &[ast::Expr]) -> (Vec<Expr>, Vec<ExprDn>) {
    assert_eq!(msg_def.params.len(), exprs.len());

    let mut dn = Vec::new();
    let mut up = Vec::new();

    for (param, expr) in msg_def.params.iter().zip(exprs) {
        let push_up = &mut |i: Expr| up.push(i.down().unwrap());
        let push_dn = &mut |i| dn.push(i);
        let push: &mut dyn FnMut(Expr) = match param.direction {
            Dir::Up => push_up,
            Dir::Dn => push_dn,
        };

        zip_ast(expr, &param.item, &mut |a, e| {
            match (e, &a) {
                (&Item::Leaf(LeafItem::Value(ref v)), ast::Expr::Var(ref name)) => {
                    let ty = v.get_type();
                    let id = new_var();
                    scope.bind(&name.name, Item::Leaf(LeafItem::Value(Expr::Variable(id, ty.clone(), param.direction))));
                    push(Expr::Variable(id, ty, param.direction.flip()));
                }
                (&Item::Leaf(LeafItem::Value(_)), _) => {
                    push(value(scope, a));
                }
                (t @ &Item::Tuple(_), ast::Expr::Var(ref name)) => {
                    // Capture a tuple by recursively building a tuple Item containing each of the
                    // captured variables
                    let v = t.map_leaf(&mut |i| {
                        match i {
                            LeafItem::Value(Expr::Const(ref c)) => LeafItem::Value(Expr::Const(c.clone())),
                            LeafItem::Value(ref v) => {
                                let ty = v.get_type();
                                let id = new_var();
                                push(Expr::Variable(id, ty.clone(), param.direction.flip()));
                                LeafItem::Value(Expr::Variable(id, ty, param.direction))
                            }
                            _ => panic!("{:?} not allowed in shape", i)
                        }
                    });
                    scope.bind(&name.name, v);
                }
                _ => return Err("invalid pattern")
            }
            Ok(())
        }).unwrap();
    }

    (dn, up)
}

#[derive(Clone, Debug)]
pub struct PatternError {
    msg: &'static str,
}

/// Destructures an item into left-hand-side binding, such as a function argument, returning
/// whether the pattern matched. If `checks` is not None, runtime checks are enabled
/// and collected.
pub fn lexpr(scope: &mut Scope, pat: &ast::Expr, r: &Item, mut checks: Option<&mut Vec<(Expr, Expr)>>) -> Result<(), PatternError> {
    zip_ast(pat, r, &mut move |pat, r| {
        let pat = match pat {
            ast::Expr::Tup(t) if t.items.len() == 1 => &t.items[0],
            pat => pat,
        };
        match pat {
            ast::Expr::Ignore(_) => Ok(()),

            ast::Expr::Var(ref name) => {
                debug!("defined {} = {:?}", name.name, r);
                scope.bind(&name.name, r.clone());
                Ok(())
            }

            pat => {
                let lv = value(scope, pat); //TODO: disallow variable references?

                if let Item::Leaf(LeafItem::Value(ref rv)) = r {
                    if &lv == rv {
                        Ok(())
                    } else if let Some(checks) = &mut checks {
                        // TODO: check overlap
                        checks.push((lv, rv.clone()));
                        Ok(())
                    } else {
                        Err("expected tuple, variable, or ignore")
                    }
                } else {
                    Err("item cannot be matched")
                }
            }
        }
    }).map_err(|msg| PatternError { msg })
}
<commit_msg>Simplify expr_resolve::rexpr and value<commit_after>use std::sync::Arc;
use crate::{syntax::{ast, Value}, tree::Tree, core::Dir};
use super::{ConcatElem, Expr, Func, FunctionDef, Item, Scope, ShapeMsg, ExprDn, VarId, LeafItem };

pub fn value(scope: &Scope, e: &ast::Expr) -> Expr {
    match rexpr(scope, e) {
        Item::Leaf(LeafItem::Value(v)) => v,
        _ => panic!("Expected a value"),
    }
}

pub fn rexpr_tup(scope: &Scope, node: &ast::ExprTup) -> Item {
    let values: Vec<Item> = node.items.iter().map(|i| rexpr(scope, i)).collect();
    if values.len() == 1 {
        values.into_iter().next().unwrap()
    } else {
        Item::Tuple(values)
    }
}

/// Resolve an expression as used in an argument or right hand side of an assignment
pub fn rexpr(scope: &Scope, e: &ast::Expr) -> Item {
    match e {
        ast::Expr::Var(ref name) => {
            if let Some(s) = scope.get(&name.name) { s } else { panic!("Undefined variable `{}`", name.name); }
        }

        ast::Expr::Tup(ref node) => rexpr_tup(scope, node),

        ast::Expr::String(ref node) => Item::Leaf(LeafItem::String(node.value.clone())),

        ast::Expr::Func(ref node) => {
            Item::Leaf(LeafItem::Func(Arc::new(FunctionDef::Code(Func{
                args: (*node.args).clone(),
                body: (*node.body).clone(),
                scope: scope.clone(),
            }))))
        }

        ast::Expr::Call(ref node) => {
            let func = rexpr(scope, &node.func);
            let arg = rexpr_tup(scope, &node.arg);

            if let Item::Leaf(LeafItem::Func(func)) = func {
                func.apply(arg)
            } else {
                panic!("{:?} is not a function", func)
            }
        }

        ast::Expr::Ignore(_) => Item::Leaf(LeafItem::Value(Expr::Ignored)),
        ast::Expr::Value(ref node) => Item::Leaf(LeafItem::Value(Expr::Const(node.value.clone()))),

        ast::Expr::Flip(ref node) => {
            Item::Leaf(LeafItem::Value(Expr::Flip(
                Box::new(node.dn.as_ref().map_or(Expr::Ignored,  |dn| value(scope, dn))),
                Box::new(node.up.as_ref().map_or(Expr::Ignored,  |up| value(scope, up))),
            )))
        }

        ast::Expr::Range(ref node) => {
            let min = value(scope, &node.lo);
            let max = value(scope, &node.hi);

            Item::Leaf(LeafItem::Value(match (min, max) {
                (Expr::Const(Value::Number(l)), Expr::Const(Value::Number(h))) => Expr::Range(l, h),
                (Expr::Const(Value::Integer(l)), Expr::Const(Value::Integer(h))) => Expr::RangeInt(l, h),
                _ => panic!("Range expressions must be numeric constant")
            }))
        }

        ast::Expr::Union(ref node) => {
            Item::Leaf(LeafItem::Value(Expr::Union(node.items.iter().map(|i| value(scope, i)).collect())))
        }

        ast::Expr::Choose(ref node) => {
            let head = value(scope, &node.e);

            if let Expr::Const(v) = head {
                let re = node.choices.iter().find(|&(ref le, _)| {
                    let l = value(scope, le);
                    l.eval_up(&mut |_, _, _| panic!("Variable not expected here"), v.clone())
                }).map(|x| &x.1).unwrap_or_else(|| {
                    panic!("No match for {} at {:?}", v, &node.span);
                });
                Item::Leaf(LeafItem::Value(value(scope, re)))
            } else {
                let pairs: Vec<(Value, Value)> = node.choices.iter().map(|&(ref le, ref re)| {
                    let l = value(scope, le);
                    let r = value(scope, re);

                    match (l, r) {
                        (Expr::Const(lv), Expr::Const(rv)) => (lv, rv),
                        _ => panic!("Choose expression arms must be constant, for now")
                    }
                }).collect();

                Item::Leaf(LeafItem::Value(Expr::Choose(Box::new(head), pairs)))
            }
        }

        ast::Expr::Concat(ref node) =>  {
            let elems = node.elems.iter().map(|&(slice_width, ref e)| {
                let expr = value(scope, e);
                match slice_width {
                    None => ConcatElem::Elem(expr),
                    Some(w) => ConcatElem::Slice(expr, w as usize)
                }
            }).collect();

            Item::Leaf(LeafItem::Value(Expr::Concat(elems)))
        }

        ast::Expr::Bin(ref node) => {
            use self::Expr::Const;
            let lhs = value(scope, &node.l);
            let rhs = value(scope, &node.r);
            let op = node.op;
            Item::Leaf(LeafItem::Value( match (lhs, rhs) {
                (Const(Value::Number(a)),  Const(Value::Number(b))) => Const(Value::Number(op.eval(a, b))),
                (Const(Value::Integer(a)), Const(Value::Integer(b))) => Const(Value::Integer(op.eval(a, b))),
                (Const(Value::Complex(a)), Const(Value::Complex(b))) => Const(Value::Complex(op.eval(a, b))),
                (Const(Value::Complex(a)), Const(Value::Number(b))) => Const(Value::Complex(op.eval(a, b))),
                (Const(Value::Number(a)),  Const(Value::Complex(b))) => Const(Value::Complex(op.eval(a, b))),
                (l, Const(b)) => Expr::BinaryConst(Box::new(l), op, b),
                (Const(a), r) => Expr::BinaryConst(Box::new(r), op.swap(), a),
                _ => panic!("One side of a binary operation must be constant")
            }))
        }

        ast::Expr::Error(_) => panic!("Syntax error"),
    }
}

fn zip_ast<T>(ast: &ast::Expr, tree: &Tree<T>, f: &mut impl FnMut(&ast::Expr, &Tree<T>) -> Result<(), &'static str>) -> Result<(), &'static str> {
    match (&ast, tree) {
        (ast::Expr::Tup(a), Tree::Tuple(t)) => {
            let mut a = a.items.iter();
            let mut t = t.iter();
            loop {
                match (a.next(), t.next()) {
                    (None, None) => break,
                    (Some(ai), Some(ti)) => zip_ast(ai, ti, f)?,
                    _ => return Err("mismatched tuples")
                }
            }
        }
        (_, t) => f(ast, t)?
    }
    Ok(())
}

/// Resolve expressions as used in the arguments of an `on` block, defining variables
pub fn on_expr_message(mut new_var: impl FnMut() -> VarId, scope: &mut Scope, msg_def: &ShapeMsg, exprs: &[ast::Expr]) -> (Vec<Expr>, Vec<ExprDn>) {
    assert_eq!(msg_def.params.len(), exprs.len());

    let mut dn = Vec::new();
    let mut up = Vec::new();

    for (param, expr) in msg_def.params.iter().zip(exprs) {
        let push_up = &mut |i: Expr| up.push(i.down().unwrap());
        let push_dn = &mut |i| dn.push(i);
        let push: &mut dyn FnMut(Expr) = match param.direction {
            Dir::Up => push_up,
            Dir::Dn => push_dn,
        };

        zip_ast(expr, &param.item, &mut |a, e| {
            match (e, &a) {
                (&Item::Leaf(LeafItem::Value(ref v)), ast::Expr::Var(ref name)) => {
                    let ty = v.get_type();
                    let id = new_var();
                    scope.bind(&name.name, Item::Leaf(LeafItem::Value(Expr::Variable(id, ty.clone(), param.direction))));
                    push(Expr::Variable(id, ty, param.direction.flip()));
                }
                (&Item::Leaf(LeafItem::Value(_)), _) => {
                    push(value(scope, a));
                }
                (t @ &Item::Tuple(_), ast::Expr::Var(ref name)) => {
                    // Capture a tuple by recursively building a tuple Item containing each of the
                    // captured variables
                    let v = t.map_leaf(&mut |i| {
                        match i {
                            LeafItem::Value(Expr::Const(ref c)) => LeafItem::Value(Expr::Const(c.clone())),
                            LeafItem::Value(ref v) => {
                                let ty = v.get_type();
                                let id = new_var();
                                push(Expr::Variable(id, ty.clone(), param.direction.flip()));
                                LeafItem::Value(Expr::Variable(id, ty, param.direction))
                            }
                            _ => panic!("{:?} not allowed in shape", i)
                        }
                    });
                    scope.bind(&name.name, v);
                }
                _ => return Err("invalid pattern")
            }
            Ok(())
        }).unwrap();
    }

    (dn, up)
}

#[derive(Clone, Debug)]
pub struct PatternError {
    msg: &'static str,
}

/// Destructures an item into left-hand-side binding, such as a function argument, returning
/// whether the pattern matched. If `checks` is not None, runtime checks are enabled
/// and collected.
pub fn lexpr(scope: &mut Scope, pat: &ast::Expr, r: &Item, mut checks: Option<&mut Vec<(Expr, Expr)>>) -> Result<(), PatternError> {
    zip_ast(pat, r, &mut move |pat, r| {
        let pat = match pat {
            ast::Expr::Tup(t) if t.items.len() == 1 => &t.items[0],
            pat => pat,
        };
        match pat {
            ast::Expr::Ignore(_) => Ok(()),

            ast::Expr::Var(ref name) => {
                debug!("defined {} = {:?}", name.name, r);
                scope.bind(&name.name, r.clone());
                Ok(())
            }

            pat => {
                let lv = value(scope, pat); //TODO: disallow variable references?

                if let Item::Leaf(LeafItem::Value(ref rv)) = r {
                    if &lv == rv {
                        Ok(())
                    } else if let Some(checks) = &mut checks {
                        // TODO: check overlap
                        checks.push((lv, rv.clone()));
                        Ok(())
                    } else {
                        Err("expected tuple, variable, or ignore")
                    }
                } else {
                    Err("item cannot be matched")
                }
            }
        }
    }).map_err(|msg| PatternError { msg })
}
<|endoftext|>


<commit_before>use redox::{Box, String, ToString, Vec, Url};
use redox::fs::File;
use redox::io::Read;

use orbital::{BmpFile, Color, Point, Size, Event, EventOption, KeyEvent, MouseEvent};

use super::display::Display;
use super::package::*;
use super::scheduler;
use super::window::Window;

/// A session
pub struct Session {
    /// The display
    pub display: Box<Display>,
    /// The font
    pub font: Vec<u8>,
    /// The cursor icon
    pub cursor: BmpFile,
    /// The background image
    pub background: BmpFile,
    /// The last mouse event
    pub last_mouse_event: MouseEvent,
    /// The packages (applications)
    pub packages: Vec<Box<Package>>,
    /// Open windows
    pub windows: Vec<*mut Window>,
    /// Ordered windows
    pub windows_ordered: Vec<*mut Window>,
    /// Redraw
    pub redraw: bool,
}

impl Session {
    /// Create new session
    pub fn new() -> Box<Self> {
        let mut ret = box Session {
            display: unsafe { Display::root() },
            font: Vec::new(),
            cursor: BmpFile::default(),
            background: BmpFile::default(),
            last_mouse_event: MouseEvent {
                x: 0,
                y: 0,
                left_button: false,
                middle_button: false,
                right_button: false,
            },
            packages: Vec::new(),
            windows: Vec::new(),
            windows_ordered: Vec::new(),
            redraw: true,
        };

        if let Some(mut file) = File::open("file:/ui/unifont.font") {
            let mut vec = Vec::new();
            file.read_to_end(&mut vec);
            ret.font = vec;
        } else {
            debugln!("Failed to read font");
        }

        ret.cursor = BmpFile::from_path("file:/ui/cursor.bmp");
        if !ret.cursor.has_data() {
            debugln!("Failed to read cursor");
        }

        ret.background = BmpFile::from_path("file:/ui/background.bmp");
        if !ret.background.has_data() {
            debugln!("Failed to read background");
        }

        if let Some(mut file) = File::open("file:/apps/") {
            let mut string = String::new();
            file.read_to_string(&mut string);

            for folder in string.lines() {
                if folder.ends_with('/') {
                    ret.packages.push(Package::from_url(&Url::from_string("file:/apps/".to_string() + &folder)));
                }
            }
        } else {
            debugln!("Failed to open apps")
        }

        ret
    }

    pub unsafe fn add_window(&mut self, add_window_ptr: *mut Window) {
        self.windows.push(add_window_ptr);
        self.windows_ordered.push(add_window_ptr);
        self.redraw = true;
    }

    /// Remove a window
    pub unsafe fn remove_window(&mut self, remove_window_ptr: *mut Window) {
        let mut i = 0;
        while i < self.windows.len() {
            let mut remove = false;

            match self.windows.get(i) {
                Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                } else {
                    i += 1;
                },
                None => break,
            }

            if remove{
                self.windows.remove(i);
            }
        }

        i = 0;
        while i < self.windows_ordered.len() {
            let mut remove = false;

            match self.windows_ordered.get(i) {
                Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                } else {
                    i += 1;
                },
                None => break,
            }

            if remove {
                self.windows_ordered.remove(i);
            }
        }

        self.redraw = true;
    }

    fn on_key(&mut self, key_event: KeyEvent) {
        if !self.windows.is_empty() {
            match self.windows.get(self.windows.len() - 1) {
                Some(window_ptr) => {
                    unsafe {
                        (**window_ptr).on_key(key_event);
                        self.redraw = true;
                    }
                }
                None => (),
            }
        }
    }

    fn on_mouse(&mut self, mouse_event: MouseEvent) {
        let mut catcher = -1;

        if mouse_event.y >= self.display.height as isize - 32 {
            if !mouse_event.left_button && self.last_mouse_event.left_button {
                let mut x = 0;
                for package in self.packages.iter() {
                    if !package.icon.as_slice().is_empty() {
                        if mouse_event.x >= x &&
                           mouse_event.x < x + package.icon.width() as isize {
                               let binary = package.binary.to_string();
                               File::exec(&binary, &[]);
                        }
                        x = x + package.icon.width() as isize;
                    }
                }

                let mut chars = 32;
                while chars > 4 &&
                      (x as usize + (chars * 8 + 3 * 4) * self.windows.len()) >
                      self.display.width + 32 {
                    chars -= 1;
                }

                x += 4;
                for window_ptr in self.windows_ordered.iter() {
                    let w = (chars*8 + 2*4) as usize;
                    if mouse_event.x >= x && mouse_event.x < x + w as isize {
                        for j in 0..self.windows.len() {
                            match self.windows.get(j) {
                                Some(catcher_window_ptr) =>
                                    if catcher_window_ptr == window_ptr {
                                    unsafe {
                                        if j == self.windows.len() - 1 {
                                            (**window_ptr).minimized = !(**window_ptr).minimized;
                                        } else {
                                            catcher = j as isize;
                                            (**window_ptr).minimized = false;
                                        }
                                    }
                                    break;
                                },
                                None => break,
                            }
                        }
                        self.redraw = true;
                        break;
                    }
                    x += w as isize;
                }
            }
        } else {
            for reverse_i in 0..self.windows.len() {
                let i = self.windows.len() - 1 - reverse_i;
                match self.windows.get(i) {
                    Some(window_ptr) => unsafe {
                        if (**window_ptr).on_mouse(mouse_event, catcher < 0) {
                            catcher = i as isize;

                            self.redraw = true;
                        }
                    },
                    None => (),
                }
            }
        }

        if catcher >= 0 && catcher < self.windows.len() as isize - 1 {
            let window_ptr = self.windows.remove(catcher as usize);
            self.windows.push(window_ptr);
        }

        if mouse_event.x != self.last_mouse_event.x || mouse_event.y != self.last_mouse_event.y {
            self.redraw = true;
        }

        self.last_mouse_event = mouse_event;
    }

    /// Redraw screen
    pub unsafe fn redraw(&mut self) {
        if self.redraw {
            let mouse_point = Point::new(self.last_mouse_event.x, self.last_mouse_event.y);
            self.display.set(Color::rgb(75, 163, 253));
            if !self.background.as_slice().is_empty() {
                self.display.image(Point::new((self.display.width as isize -
                                                 self.background.width() as isize) /
                                                2,
                                                (self.display.height as isize -
                                                 self.background.height() as isize) /
                                                2),
                                    self.background.as_slice().as_ptr(),
                                    Size::new(self.background.width(), self.background.height()));
            }

            for i in 0..self.windows.len() {
                match self.windows.get(i) {
                    Some(window_ptr) => {
                        (**window_ptr).focused = i == self.windows.len() - 1;
                        (**window_ptr).draw(&self.display, self.font.as_ptr() as usize);
                    }
                    None => (),
                }
            }

            self.display.rect(Point::new(0, self.display.height as isize - 32),
                              Size::new(self.display.width, 32),
                              Color::rgba(0, 0, 0, 128));

            let mut x = 0;
            for package in self.packages.iter() {
                if !package.icon.as_slice().is_empty() {
                    let y = self.display.height as isize - package.icon.height() as isize;
                    if mouse_point.y >= y && mouse_point.x >= x &&
                       mouse_point.x < x + package.icon.width() as isize {
                        self.display.rect(Point::new(x, y),
                                          Size::new(package.icon.width(), package.icon.height()),
                                          Color::rgba(128, 128, 128, 128));

                       self.display.rect(Point::new(x, y - 16),
                                         Size::new(package.name.len() * 8, 16),
                                         Color::rgba(0, 0, 0, 128));

                        let mut c_x = x;
                        for c in package.name.chars() {
                            self.display
                                .char(Point::new(c_x, y - 16), c, Color::rgb(255, 255, 255), self.font.as_ptr() as usize);
                            c_x += 8;
                        }
                    }

                    self.display.image_alpha(Point::new(x, y),
                                             package.icon.as_slice().as_ptr(),
                                             Size::new(package.icon.width(), package.icon.height()));
                    x = x + package.icon.width() as isize;
                }
            }

            let mut chars = 32;
            while chars > 4 &&
                  (x as usize + (chars * 8 + 3 * 4) * self.windows.len()) >
                  self.display.width + 32 {
                chars -= 1;
            }

            x += 4;
            for window_ptr in self.windows_ordered.iter() {
                let w = (chars*8 + 2*4) as usize;
                self.display.rect(Point::new(x, self.display.height as isize - 32),
                                  Size::new(w, 32),
                                  (**window_ptr).border_color);
                x += 4;

                let mut i = 0;
                for c in (**window_ptr).title.chars() {
                    if c != '\0' {
                        self.display.char(Point::new(x, self.display.height as isize - 24),
                                          c,
                                          (**window_ptr).title_color,
                                          self.font.as_ptr() as usize);
                    }
                    x += 8;
                    i += 1;
                    if i >= chars {
                        break;
                    }
                }
                while i < chars {
                    x += 8;
                    i += 1;
                }
                x += 8;
            }

            if !self.cursor.as_slice().is_empty() {
                self.display.image_alpha(mouse_point,
                                         self.cursor.as_slice().as_ptr(),
                                         Size::new(self.cursor.width(), self.cursor.height()));
            } else {
                self.display.char(Point::new(mouse_point.x - 3, mouse_point.y - 9),
                                  'X',
                                  Color::rgb(255, 255, 255),
                                  self.font.as_ptr() as usize);
            }

            let reenable = scheduler::start_no_ints();

            self.display.flip();

            self.redraw = false;

            scheduler::end_no_ints(reenable);
        }
    }

    pub fn event(&mut self, event: &Event) {
        match event.to_option() {
            EventOption::Mouse(mouse_event) => self.on_mouse(mouse_event),
            EventOption::Key(key_event) => self.on_key(key_event),
            _ => (),
        }
    }
}
<commit_msg>use has_data function instead of slice conversion check<commit_after>use redox::{Box, String, ToString, Vec, Url};
use redox::fs::File;
use redox::io::Read;

use orbital::{BmpFile, Color, Point, Size, Event, EventOption, KeyEvent, MouseEvent};

use super::display::Display;
use super::package::*;
use super::scheduler;
use super::window::Window;

/// A session
pub struct Session {
    /// The display
    pub display: Box<Display>,
    /// The font
    pub font: Vec<u8>,
    /// The cursor icon
    pub cursor: BmpFile,
    /// The background image
    pub background: BmpFile,
    /// The last mouse event
    pub last_mouse_event: MouseEvent,
    /// The packages (applications)
    pub packages: Vec<Box<Package>>,
    /// Open windows
    pub windows: Vec<*mut Window>,
    /// Ordered windows
    pub windows_ordered: Vec<*mut Window>,
    /// Redraw
    pub redraw: bool,
}

impl Session {
    /// Create new session
    pub fn new() -> Box<Self> {
        let mut ret = box Session {
            display: unsafe { Display::root() },
            font: Vec::new(),
            cursor: BmpFile::default(),
            background: BmpFile::default(),
            last_mouse_event: MouseEvent {
                x: 0,
                y: 0,
                left_button: false,
                middle_button: false,
                right_button: false,
            },
            packages: Vec::new(),
            windows: Vec::new(),
            windows_ordered: Vec::new(),
            redraw: true,
        };

        if let Some(mut file) = File::open("file:/ui/unifont.font") {
            let mut vec = Vec::new();
            file.read_to_end(&mut vec);
            ret.font = vec;
        } else {
            debugln!("Failed to read font");
        }

        ret.cursor = BmpFile::from_path("file:/ui/cursor.bmp");
        if !ret.cursor.has_data() {
            debugln!("Failed to read cursor");
        }

        ret.background = BmpFile::from_path("file:/ui/background.bmp");
        if !ret.background.has_data() {
            debugln!("Failed to read background");
        }

        if let Some(mut file) = File::open("file:/apps/") {
            let mut string = String::new();
            file.read_to_string(&mut string);

            for folder in string.lines() {
                if folder.ends_with('/') {
                    ret.packages.push(Package::from_url(&Url::from_string("file:/apps/".to_string() + &folder)));
                }
            }
        } else {
            debugln!("Failed to open apps")
        }

        ret
    }

    pub unsafe fn add_window(&mut self, add_window_ptr: *mut Window) {
        self.windows.push(add_window_ptr);
        self.windows_ordered.push(add_window_ptr);
        self.redraw = true;
    }

    /// Remove a window
    pub unsafe fn remove_window(&mut self, remove_window_ptr: *mut Window) {
        let mut i = 0;
        while i < self.windows.len() {
            let mut remove = false;

            match self.windows.get(i) {
                Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                } else {
                    i += 1;
                },
                None => break,
            }

            if remove{
                self.windows.remove(i);
            }
        }

        i = 0;
        while i < self.windows_ordered.len() {
            let mut remove = false;

            match self.windows_ordered.get(i) {
                Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                } else {
                    i += 1;
                },
                None => break,
            }

            if remove {
                self.windows_ordered.remove(i);
            }
        }

        self.redraw = true;
    }

    fn on_key(&mut self, key_event: KeyEvent) {
        if !self.windows.is_empty() {
            match self.windows.get(self.windows.len() - 1) {
                Some(window_ptr) => {
                    unsafe {
                        (**window_ptr).on_key(key_event);
                        self.redraw = true;
                    }
                }
                None => (),
            }
        }
    }

    fn on_mouse(&mut self, mouse_event: MouseEvent) {
        let mut catcher = -1;

        if mouse_event.y >= self.display.height as isize - 32 {
            if !mouse_event.left_button && self.last_mouse_event.left_button {
                let mut x = 0;
                for package in self.packages.iter() {
                    if !package.icon.as_slice().is_empty() {
                        if mouse_event.x >= x &&
                           mouse_event.x < x + package.icon.width() as isize {
                               let binary = package.binary.to_string();
                               File::exec(&binary, &[]);
                        }
                        x = x + package.icon.width() as isize;
                    }
                }

                let mut chars = 32;
                while chars > 4 &&
                      (x as usize + (chars * 8 + 3 * 4) * self.windows.len()) >
                      self.display.width + 32 {
                    chars -= 1;
                }

                x += 4;
                for window_ptr in self.windows_ordered.iter() {
                    let w = (chars*8 + 2*4) as usize;
                    if mouse_event.x >= x && mouse_event.x < x + w as isize {
                        for j in 0..self.windows.len() {
                            match self.windows.get(j) {
                                Some(catcher_window_ptr) =>
                                    if catcher_window_ptr == window_ptr {
                                    unsafe {
                                        if j == self.windows.len() - 1 {
                                            (**window_ptr).minimized = !(**window_ptr).minimized;
                                        } else {
                                            catcher = j as isize;
                                            (**window_ptr).minimized = false;
                                        }
                                    }
                                    break;
                                },
                                None => break,
                            }
                        }
                        self.redraw = true;
                        break;
                    }
                    x += w as isize;
                }
            }
        } else {
            for reverse_i in 0..self.windows.len() {
                let i = self.windows.len() - 1 - reverse_i;
                match self.windows.get(i) {
                    Some(window_ptr) => unsafe {
                        if (**window_ptr).on_mouse(mouse_event, catcher < 0) {
                            catcher = i as isize;

                            self.redraw = true;
                        }
                    },
                    None => (),
                }
            }
        }

        if catcher >= 0 && catcher < self.windows.len() as isize - 1 {
            let window_ptr = self.windows.remove(catcher as usize);
            self.windows.push(window_ptr);
        }

        if mouse_event.x != self.last_mouse_event.x || mouse_event.y != self.last_mouse_event.y {
            self.redraw = true;
        }

        self.last_mouse_event = mouse_event;
    }

    /// Redraw screen
    pub unsafe fn redraw(&mut self) {
        if self.redraw {
            let mouse_point = Point::new(self.last_mouse_event.x, self.last_mouse_event.y);
            self.display.set(Color::rgb(75, 163, 253));
            if self.background.has_data() {
                self.display.image(Point::new((self.display.width as isize -
                                                 self.background.width() as isize) /
                                                2,
                                                (self.display.height as isize -
                                                 self.background.height() as isize) /
                                                2),
                                    self.background.as_slice().as_ptr(),
                                    Size::new(self.background.width(), self.background.height()));
            }

            for i in 0..self.windows.len() {
                match self.windows.get(i) {
                    Some(window_ptr) => {
                        (**window_ptr).focused = i == self.windows.len() - 1;
                        (**window_ptr).draw(&self.display, self.font.as_ptr() as usize);
                    }
                    None => (),
                }
            }

            self.display.rect(Point::new(0, self.display.height as isize - 32),
                              Size::new(self.display.width, 32),
                              Color::rgba(0, 0, 0, 128));

            let mut x = 0;
            for package in self.packages.iter() {
                if !package.icon.as_slice().is_empty() {
                    let y = self.display.height as isize - package.icon.height() as isize;
                    if mouse_point.y >= y && mouse_point.x >= x &&
                       mouse_point.x < x + package.icon.width() as isize {
                        self.display.rect(Point::new(x, y),
                                          Size::new(package.icon.width(), package.icon.height()),
                                          Color::rgba(128, 128, 128, 128));

                       self.display.rect(Point::new(x, y - 16),
                                         Size::new(package.name.len() * 8, 16),
                                         Color::rgba(0, 0, 0, 128));

                        let mut c_x = x;
                        for c in package.name.chars() {
                            self.display
                                .char(Point::new(c_x, y - 16), c, Color::rgb(255, 255, 255), self.font.as_ptr() as usize);
                            c_x += 8;
                        }
                    }

                    self.display.image_alpha(Point::new(x, y),
                                             package.icon.as_slice().as_ptr(),
                                             Size::new(package.icon.width(), package.icon.height()));
                    x = x + package.icon.width() as isize;
                }
            }

            let mut chars = 32;
            while chars > 4 &&
                  (x as usize + (chars * 8 + 3 * 4) * self.windows.len()) >
                  self.display.width + 32 {
                chars -= 1;
            }

            x += 4;
            for window_ptr in self.windows_ordered.iter() {
                let w = (chars*8 + 2*4) as usize;
                self.display.rect(Point::new(x, self.display.height as isize - 32),
                                  Size::new(w, 32),
                                  (**window_ptr).border_color);
                x += 4;

                let mut i = 0;
                for c in (**window_ptr).title.chars() {
                    if c != '\0' {
                        self.display.char(Point::new(x, self.display.height as isize - 24),
                                          c,
                                          (**window_ptr).title_color,
                                          self.font.as_ptr() as usize);
                    }
                    x += 8;
                    i += 1;
                    if i >= chars {
                        break;
                    }
                }
                while i < chars {
                    x += 8;
                    i += 1;
                }
                x += 8;
            }

            if self.cursor.has_data() {
                self.display.image_alpha(mouse_point,
                                         self.cursor.as_slice().as_ptr(),
                                         Size::new(self.cursor.width(), self.cursor.height()));
            } else {
                self.display.char(Point::new(mouse_point.x - 3, mouse_point.y - 9),
                                  'X',
                                  Color::rgb(255, 255, 255),
                                  self.font.as_ptr() as usize);
            }

            let reenable = scheduler::start_no_ints();

            self.display.flip();

            self.redraw = false;

            scheduler::end_no_ints(reenable);
        }
    }

    pub fn event(&mut self, event: &Event) {
        match event.to_option() {
            EventOption::Mouse(mouse_event) => self.on_mouse(mouse_event),
            EventOption::Key(key_event) => self.on_key(key_event),
            _ => (),
        }
    }
}
<|endoftext|>


<commit_before>
use size_hint;
use Itertools;

use std::mem::replace;
use std::fmt;

macro_rules! clone_fields {
    ($name:ident, $base:expr, $($field:ident),+) => (
        $name {
            $(
                $field : $base . $field .clone()
            ),*
        }
    );
}

/// Head element and Tail iterator pair
///
/// `PartialEq`, `Eq`, `PartialOrd` and `Ord` are implemented by comparing sequences based on
/// first items (which are guaranteed to exist).
///
/// The meanings of `PartialOrd` and `Ord` are reversed so as to turn the heap used in
/// `KMerge` into a min-heap.
#[derive(Debug)]
struct HeadTail<I>
    where I: Iterator
{
    head: I::Item,
    tail: I,
}

impl<I> HeadTail<I>
    where I: Iterator
{
    /// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty.
    fn new(mut it: I) -> Option<HeadTail<I>> {
        let head = it.next();
        head.map(|h| {
            HeadTail {
                head: h,
                tail: it,
            }
        })
    }

    /// Get the next element and update `head`, returning the old head in `Some`.
    ///
    /// Returns `None` when the tail is exhausted (only `head` then remains).
    fn next(&mut self) -> Option<I::Item> {
        if let Some(next) = self.tail.next() {
            Some(replace(&mut self.head, next))
        } else {
            None
        }
    }

    /// Hints at the size of the sequence, same as the `Iterator` method.
    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint::add_scalar(self.tail.size_hint(), 1)
    }
}

impl<I> Clone for HeadTail<I>
    where I: Iterator + Clone,
          I::Item: Clone
{
    fn clone(&self) -> Self {
        clone_fields!(HeadTail, self, head, tail)
    }
}

/// Make `data` a heap (min-heap w.r.t the sorting).
fn heapify<T, S>(data: &mut [T], mut less_than: S)
    where S: FnMut(&T, &T) -> bool
{
    for i in (0..data.len() / 2).rev() {
        sift_down(data, i, &mut less_than);
    }
}

/// Sift down element at `index` (`heap` is a min-heap wrt the ordering)
fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
    where S: FnMut(&T, &T) -> bool
{
    debug_assert!(index <= heap.len());
    let mut pos = index;
    let mut child = 2 * pos + 1;
    // the `pos` conditional is to avoid a bounds check
    while pos < heap.len() && child < heap.len() {
        let right = child + 1;

        // pick the smaller of the two children
        if right < heap.len() && less_than(&heap[right], &heap[child]) {
            child = right;
        }

        // sift down is done if we are already in order
        if !less_than(&heap[child], &heap[pos]) {
            return;
        }
        heap.swap(pos, child);
        pos = child;
        child = 2 * pos + 1;
    }
}

/// An iterator adaptor that merges an abitrary number of base iterators in ascending order.
/// If all base iterators are sorted (ascending), the result is sorted.
///
/// Iterator element type is `I::Item`.
///
/// See [`.kmerge()`](../trait.Itertools.html#method.kmerge) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct KMerge<I>
    where I: Iterator
{
    heap: Vec<HeadTail<I>>,
}

impl<I> fmt::Debug for KMerge<I>
    where I: Iterator + fmt::Debug,
          I::Item: fmt::Debug,
{
    debug_fmt_fields!(KMerge, heap);
}

/// Create an iterator that merges elements of the contained iterators using
/// the ordering function.
///
/// Equivalent to `iterable.into_iter().kmerge()`.
///
/// ```
/// use itertools::kmerge;
///
/// for elt in kmerge(vec![vec![0, 2, 4], vec![1, 3, 5], vec![6, 7]]) {
///     /* loop body */
/// }
/// ```
pub fn kmerge<I>(iterable: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
    where I: IntoIterator,
          I::Item: IntoIterator,
          <<I as IntoIterator>::Item as IntoIterator>::Item: PartialOrd
{
    let iter = iterable.into_iter();
    let (lower, _) = iter.size_hint();
    let mut heap = Vec::with_capacity(lower);
    heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
    heapify(&mut heap, |a, b| a.head < b.head);
    KMerge { heap: heap }
}

impl<I> Clone for KMerge<I>
    where I: Iterator + Clone,
          I::Item: Clone
{
    fn clone(&self) -> KMerge<I> {
        clone_fields!(KMerge, self, heap)
    }
}

impl<I> Iterator for KMerge<I>
    where I: Iterator,
          I::Item: PartialOrd
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        if self.heap.is_empty() {
            return None;
        }
        let result = if let Some(next) = self.heap[0].next() {
            next
        } else {
            self.heap.swap_remove(0).head
        };
        sift_down(&mut self.heap, 0, |a, b| a.head < b.head);
        Some(result)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.heap.iter()
                 .map(|i| i.size_hint())
                 .fold1(size_hint::add)
                 .unwrap_or((0, Some(0)))
    }
}

/// An iterator adaptor that merges an abitrary number of base iterators
/// according to an ordering function.
///
/// Iterator element type is `I::Item`.
///
/// See [`.kmerge_by()`](../trait.Itertools.html#method.kmerge_by) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct KMergeBy<I, F>
    where I: Iterator,
{
    heap: Vec<HeadTail<I>>,
    less_than: F,
}

impl<I, F> fmt::Debug for KMergeBy<I, F>
    where I: Iterator + fmt::Debug,
          I::Item: fmt::Debug,
{
    debug_fmt_fields!(KMergeBy, heap);
}

/// Create an iterator that merges elements of the contained iterators.
///
/// Equivalent to `iterable.into_iter().kmerge_by(less_than)`.
pub fn kmerge_by<I, F>(iterable: I, mut less_than: F)
    -> KMergeBy<<I::Item as IntoIterator>::IntoIter, F>
    where I: IntoIterator,
          I::Item: IntoIterator,
          F: FnMut(&<<I as IntoIterator>::Item as IntoIterator>::Item,
                   &<<I as IntoIterator>::Item as IntoIterator>::Item) -> bool
{
    let iter = iterable.into_iter();
    let (lower, _) = iter.size_hint();
    let mut heap: Vec<_> = Vec::with_capacity(lower);
    heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
    heapify(&mut heap, |a, b| less_than(&a.head, &b.head));
    KMergeBy { heap: heap, less_than: less_than }
}

impl<I, F> Clone for KMergeBy<I, F>
    where I: Iterator + Clone,
          I::Item: Clone,
          F: Clone,
{
    fn clone(&self) -> KMergeBy<I, F> {
        clone_fields!(KMergeBy, self, heap, less_than)
    }
}

impl<I, F> Iterator for KMergeBy<I, F>
    where I: Iterator,
          F: FnMut(&I::Item, &I::Item) -> bool
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        if self.heap.is_empty() {
            return None;
        }
        let result = if let Some(next) = self.heap[0].next() {
            next
        } else {
            self.heap.swap_remove(0).head
        };
        let less_than = &mut self.less_than;
        sift_down(&mut self.heap, 0, |a, b| less_than(&a.head, &b.head));
        Some(result)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.heap.iter()
                 .map(|i| i.size_hint())
                 .fold1(size_hint::add)
                 .unwrap_or((0, Some(0)))
    }
}
<commit_msg>Define KMerge in terms of KMergeBy<commit_after>
use size_hint;
use Itertools;

use std::mem::replace;
use std::fmt;

macro_rules! clone_fields {
    ($name:ident, $base:expr, $($field:ident),+) => (
        $name {
            $(
                $field : $base . $field .clone()
            ),*
        }
    );
}

/// Head element and Tail iterator pair
///
/// `PartialEq`, `Eq`, `PartialOrd` and `Ord` are implemented by comparing sequences based on
/// first items (which are guaranteed to exist).
///
/// The meanings of `PartialOrd` and `Ord` are reversed so as to turn the heap used in
/// `KMerge` into a min-heap.
#[derive(Debug)]
struct HeadTail<I>
    where I: Iterator
{
    head: I::Item,
    tail: I,
}

impl<I> HeadTail<I>
    where I: Iterator
{
    /// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty.
    fn new(mut it: I) -> Option<HeadTail<I>> {
        let head = it.next();
        head.map(|h| {
            HeadTail {
                head: h,
                tail: it,
            }
        })
    }

    /// Get the next element and update `head`, returning the old head in `Some`.
    ///
    /// Returns `None` when the tail is exhausted (only `head` then remains).
    fn next(&mut self) -> Option<I::Item> {
        if let Some(next) = self.tail.next() {
            Some(replace(&mut self.head, next))
        } else {
            None
        }
    }

    /// Hints at the size of the sequence, same as the `Iterator` method.
    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint::add_scalar(self.tail.size_hint(), 1)
    }
}

impl<I> Clone for HeadTail<I>
    where I: Iterator + Clone,
          I::Item: Clone
{
    fn clone(&self) -> Self {
        clone_fields!(HeadTail, self, head, tail)
    }
}

/// Make `data` a heap (min-heap w.r.t the sorting).
fn heapify<T, S>(data: &mut [T], mut less_than: S)
    where S: FnMut(&T, &T) -> bool
{
    for i in (0..data.len() / 2).rev() {
        sift_down(data, i, &mut less_than);
    }
}

/// Sift down element at `index` (`heap` is a min-heap wrt the ordering)
fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
    where S: FnMut(&T, &T) -> bool
{
    debug_assert!(index <= heap.len());
    let mut pos = index;
    let mut child = 2 * pos + 1;
    // the `pos` conditional is to avoid a bounds check
    while pos < heap.len() && child < heap.len() {
        let right = child + 1;

        // pick the smaller of the two children
        if right < heap.len() && less_than(&heap[right], &heap[child]) {
            child = right;
        }

        // sift down is done if we are already in order
        if !less_than(&heap[child], &heap[pos]) {
            return;
        }
        heap.swap(pos, child);
        pos = child;
        child = 2 * pos + 1;
    }
}

/// An iterator adaptor that merges an abitrary number of base iterators in ascending order.
/// If all base iterators are sorted (ascending), the result is sorted.
///
/// Iterator element type is `I::Item`.
///
/// See [`.kmerge()`](../trait.Itertools.html#method.kmerge) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type KMerge<I> = KMergeBy<I, KMergeByLt>;

pub trait KMergePredicate<T> {
    fn kmerge_pred(&mut self, a: &T, b: &T) -> bool;
}

#[derive(Clone)]
pub struct KMergeByLt;

impl<T: PartialOrd> KMergePredicate<T> for KMergeByLt {
    fn kmerge_pred(&mut self, a: &T, b: &T) -> bool {
        a < b
    }
}

impl<T, F: FnMut(&T, &T)->bool> KMergePredicate<T> for F {
    fn kmerge_pred(&mut self, a: &T, b: &T) -> bool {
        self(a, b)
    }
}

/// Create an iterator that merges elements of the contained iterators using
/// the ordering function.
///
/// Equivalent to `iterable.into_iter().kmerge()`.
///
/// ```
/// use itertools::kmerge;
///
/// for elt in kmerge(vec![vec![0, 2, 4], vec![1, 3, 5], vec![6, 7]]) {
///     /* loop body */
/// }
/// ```
pub fn kmerge<I>(iterable: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
    where I: IntoIterator,
          I::Item: IntoIterator,
          <<I as IntoIterator>::Item as IntoIterator>::Item: PartialOrd
{
    let iter = iterable.into_iter();
    let (lower, _) = iter.size_hint();
    let mut heap = Vec::with_capacity(lower);
    heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
    heapify(&mut heap, |a, b| a.head < b.head);
    KMerge { heap: heap , less_than: KMergeByLt }
}

/// An iterator adaptor that merges an abitrary number of base iterators
/// according to an ordering function.
///
/// Iterator element type is `I::Item`.
///
/// See [`.kmerge_by()`](../trait.Itertools.html#method.kmerge_by) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct KMergeBy<I, F>
    where I: Iterator,
{
    heap: Vec<HeadTail<I>>,
    less_than: F,
}

impl<I, F> fmt::Debug for KMergeBy<I, F>
    where I: Iterator + fmt::Debug,
          I::Item: fmt::Debug,
{
    debug_fmt_fields!(KMergeBy, heap);
}

/// Create an iterator that merges elements of the contained iterators.
///
/// Equivalent to `iterable.into_iter().kmerge_by(less_than)`.
pub fn kmerge_by<I, F>(iterable: I, mut less_than: F)
    -> KMergeBy<<I::Item as IntoIterator>::IntoIter, F>
    where I: IntoIterator,
          I::Item: IntoIterator,
          F: FnMut(&<<I as IntoIterator>::Item as IntoIterator>::Item,
                   &<<I as IntoIterator>::Item as IntoIterator>::Item) -> bool
{
    let iter = iterable.into_iter();
    let (lower, _) = iter.size_hint();
    let mut heap: Vec<_> = Vec::with_capacity(lower);
    heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
    heapify(&mut heap, |a, b| less_than(&a.head, &b.head));
    KMergeBy { heap: heap, less_than: less_than }
}

impl<I, F> Clone for KMergeBy<I, F>
    where I: Iterator + Clone,
          I::Item: Clone,
          F: Clone,
{
    fn clone(&self) -> KMergeBy<I, F> {
        clone_fields!(KMergeBy, self, heap, less_than)
    }
}

impl<I, F> Iterator for KMergeBy<I, F>
    where I: Iterator,
          F: KMergePredicate<I::Item>
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        if self.heap.is_empty() {
            return None;
        }
        let result = if let Some(next) = self.heap[0].next() {
            next
        } else {
            self.heap.swap_remove(0).head
        };
        let less_than = &mut self.less_than;
        sift_down(&mut self.heap, 0, |a, b| less_than.kmerge_pred(&a.head, &b.head));
        Some(result)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.heap.iter()
                 .map(|i| i.size_hint())
                 .fold1(size_hint::add)
                 .unwrap_or((0, Some(0)))
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 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.

//! Windows console handling

// FIXME (#13400): this is only a tiny fraction of the win32 console api

extern crate libc;

use std::io::IoResult;

use attr;
use color;
use Terminal;

/// A Terminal implementation which uses the Win32 Console API.
pub struct WinConsole<T> {
    buf: T,
    foreground: color::Color,
    background: color::Color,
}

#[link(name = "kernel32")]
extern "system" {
    fn SetConsoleTextAttribute(handle: libc::HANDLE, attr: libc::WORD) -> libc::BOOL;
    fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
}

fn color_to_bits(color: color::Color) -> u16 {
    // magic numbers from mingw-w64's wincon.h

    let bits = match color % 8 {
        color::BLACK   => 0,
        color::BLUE    => 0x1,
        color::GREEN   => 0x2,
        color::RED     => 0x4,
        color::YELLOW  => 0x2 | 0x4,
        color::MAGENTA => 0x1 | 0x4,
        color::CYAN    => 0x1 | 0x2,
        color::WHITE   => 0x1 | 0x2 | 0x4,
        _ => unreachable!()
    };

    if color >= 8 {
        bits | 0x8
    } else {
        bits
    }
}

impl<T: Writer> WinConsole<T> {
    fn apply(&mut self) {
        let mut accum: libc::WORD = 0;
        accum |= color_to_bits(self.foreground);
        accum |= color_to_bits(self.background) << 4;

        unsafe {
            // Magic -11 means stdout, from
            // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
            //
            // You may be wondering, "but what about stderr?", and the answer
            // to that is that setting terminal attributes on the stdout
            // handle also sets them for stderr, since they go to the same
            // terminal! Admittedly, this is fragile, since stderr could be
            // redirected to a different console. This is good enough for
            // rustc though. See #13400.
            let out = GetStdHandle(-11);
            SetConsoleTextAttribute(out, accum);
        }
    }
}

impl<T: Writer> Writer for WinConsole<T> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.buf.write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        self.buf.flush()
    }
}

impl<T: Writer> Terminal<T> for WinConsole<T> {
    fn new(out: T) -> Option<WinConsole<T>> {
        Some(WinConsole { buf: out, foreground: color::WHITE, background: color::BLACK })
    }

    fn fg(&mut self, color: color::Color) -> IoResult<bool> {
        self.foreground = color;
        self.apply();

        Ok(true)
    }

    fn bg(&mut self, color: color::Color) -> IoResult<bool> {
        self.background = color;
        self.apply();

        Ok(true)
    }

    fn attr(&mut self, attr: attr::Attr) -> IoResult<bool> {
        match attr {
            attr::ForegroundColor(f) => {
                self.foreground = f;
                self.apply();
                Ok(true)
            },
            attr::BackgroundColor(b) => {
                self.background = b;
                self.apply();
                Ok(true)
            },
            _ => Ok(false)
        }
    }

    fn supports_attr(&self, attr: attr::Attr) -> bool {
        // it claims support for underscore and reverse video, but I can't get
        // it to do anything -cmr
        match attr {
            attr::ForegroundColor(_) | attr::BackgroundColor(_) => true,
            _ => false
        }
    }

    fn reset(&mut self) -> IoResult<()> {
        self.foreground = color::WHITE;
        self.background = color::BLACK;
        self.apply();

        Ok(())
    }

    fn unwrap(self) -> T { self.buf }

    fn get_ref<'a>(&'a self) -> &'a T { &self.buf }

    fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf }
}
<commit_msg>Flush before applying console attributes<commit_after>// Copyright 2013-2014 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.

//! Windows console handling

// FIXME (#13400): this is only a tiny fraction of the win32 console api

extern crate libc;

use std::io::IoResult;

use attr;
use color;
use Terminal;

/// A Terminal implementation which uses the Win32 Console API.
pub struct WinConsole<T> {
    buf: T,
    foreground: color::Color,
    background: color::Color,
}

#[link(name = "kernel32")]
extern "system" {
    fn SetConsoleTextAttribute(handle: libc::HANDLE, attr: libc::WORD) -> libc::BOOL;
    fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
}

fn color_to_bits(color: color::Color) -> u16 {
    // magic numbers from mingw-w64's wincon.h

    let bits = match color % 8 {
        color::BLACK   => 0,
        color::BLUE    => 0x1,
        color::GREEN   => 0x2,
        color::RED     => 0x4,
        color::YELLOW  => 0x2 | 0x4,
        color::MAGENTA => 0x1 | 0x4,
        color::CYAN    => 0x1 | 0x2,
        color::WHITE   => 0x1 | 0x2 | 0x4,
        _ => unreachable!()
    };

    if color >= 8 {
        bits | 0x8
    } else {
        bits
    }
}

impl<T: Writer> WinConsole<T> {
    fn apply(&mut self) {
        let _unused = self.buf.flush();
        let mut accum: libc::WORD = 0;
        accum |= color_to_bits(self.foreground);
        accum |= color_to_bits(self.background) << 4;

        unsafe {
            // Magic -11 means stdout, from
            // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
            //
            // You may be wondering, "but what about stderr?", and the answer
            // to that is that setting terminal attributes on the stdout
            // handle also sets them for stderr, since they go to the same
            // terminal! Admittedly, this is fragile, since stderr could be
            // redirected to a different console. This is good enough for
            // rustc though. See #13400.
            let out = GetStdHandle(-11);
            SetConsoleTextAttribute(out, accum);
        }
    }
}

impl<T: Writer> Writer for WinConsole<T> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.buf.write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        self.buf.flush()
    }
}

impl<T: Writer> Terminal<T> for WinConsole<T> {
    fn new(out: T) -> Option<WinConsole<T>> {
        Some(WinConsole { buf: out, foreground: color::WHITE, background: color::BLACK })
    }

    fn fg(&mut self, color: color::Color) -> IoResult<bool> {
        self.foreground = color;
        self.apply();

        Ok(true)
    }

    fn bg(&mut self, color: color::Color) -> IoResult<bool> {
        self.background = color;
        self.apply();

        Ok(true)
    }

    fn attr(&mut self, attr: attr::Attr) -> IoResult<bool> {
        match attr {
            attr::ForegroundColor(f) => {
                self.foreground = f;
                self.apply();
                Ok(true)
            },
            attr::BackgroundColor(b) => {
                self.background = b;
                self.apply();
                Ok(true)
            },
            _ => Ok(false)
        }
    }

    fn supports_attr(&self, attr: attr::Attr) -> bool {
        // it claims support for underscore and reverse video, but I can't get
        // it to do anything -cmr
        match attr {
            attr::ForegroundColor(_) | attr::BackgroundColor(_) => true,
            _ => false
        }
    }

    fn reset(&mut self) -> IoResult<()> {
        self.foreground = color::WHITE;
        self.background = color::BLACK;
        self.apply();

        Ok(())
    }

    fn unwrap(self) -> T { self.buf }

    fn get_ref<'a>(&'a self) -> &'a T { &self.buf }

    fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf }
}
<|endoftext|>


<commit_before>use runtime::Runtime;
use values::Value;

use std::io;
use std::io::Write;
use std::path::Path;

pub fn repl(args: Vec<String>) {
    let mut runtime = Runtime::new();

    if args.len() > 1 {
        let path = Path::new(&args[1]);

        match runtime.eval_file(&path) {
            Ok(_)      => (),
            Err(error) => println!("{:?}", error),
        }
    } else {
        enter_repl(&mut runtime);
    }
}

fn enter_repl(runtime: &mut Runtime) {
    let mut input = io::stdin();

    loop {
        print!("> ");
        let _ = io::stdout().flush();

        let mut line = String::new();
        match input.read_line(&mut line) {
            Ok(0) => break,
            Ok(_) => {
                match &*line {
                    "exit\n" => break,
                    "dump-heap\n" => {
                        runtime.dump_heap();
                    }
                    line => {
                        match runtime.eval_str(line) {
                            Ok(exprs) => {
                                for expr in exprs.iter() {
                                    if **expr != Value::Unspecified {
                                        println!("=> {}", expr);
                                    }
                                }
                            },
                            Err(error) => println!("Error: {:?}", error),
                        }
                    }
                }
            },
            Err(error) =>
                panic!("{:?}", error),
        }
    }
}
<commit_msg>Removed mut from stdin<commit_after>use runtime::Runtime;
use values::Value;

use std::io;
use std::io::Write;
use std::path::Path;

pub fn repl(args: Vec<String>) {
    let mut runtime = Runtime::new();

    if args.len() > 1 {
        let path = Path::new(&args[1]);

        match runtime.eval_file(&path) {
            Ok(_)      => (),
            Err(error) => println!("{:?}", error),
        }
    } else {
        enter_repl(&mut runtime);
    }
}

fn enter_repl(runtime: &mut Runtime) {
    let input = io::stdin();

    loop {
        print!("> ");
        let _ = io::stdout().flush();

        let mut line = String::new();
        match input.read_line(&mut line) {
            Ok(0) => break,
            Ok(_) => {
                match &*line {
                    "exit\n" => break,
                    "dump-heap\n" => {
                        runtime.dump_heap();
                    }
                    line => {
                        match runtime.eval_str(line) {
                            Ok(exprs) => {
                                for expr in exprs.iter() {
                                    if **expr != Value::Unspecified {
                                        println!("=> {}", expr);
                                    }
                                }
                            },
                            Err(error) => println!("Error: {:?}", error),
                        }
                    }
                }
            },
            Err(error) =>
                panic!("{:?}", error),
        }
    }
}
<|endoftext|>