<commit_before>extern crate rustc_serialize;

use rustc_serialize::json::Json;
use rustc_serialize::json::Json::{Array, Object};

// TODO: doc comments

pub enum JsonPathElement {
    Key(&'static str), // Use the value associated with a specific key.
    Only the only value in an array or object.
}

use json::JsonPathElement::Key;
use json::JsonPathElement::Only;

// TODO: return &str with a lifetime matching path_elements
fn pretty_print(path_elements: &[JsonPathElement]) -> String {
    // TODO: add (root) to the beginning always.
    if path_elements.is_empty() {
        "(root)".to_string()
    } else {
        path_elements.into_iter().map(|path_element| {
            match path_element {
                // TODO: why do I need the JsonPathElement:: here? I think I don't.
                &JsonPathElement::Key(ref key) => key.to_string(), // TODO: can I remove to_string()?
                &JsonPathElement::Only => "(only)".to_string(),
            }
        }).collect::<Vec<_>>().join(".")
    }
}

// TODO: document
fn get_json_value<'a>(json: &'a Json, path: &[JsonPathElement], index: usize) ->
    Result<&'a Json, String> {
    if index == path.len() {
        return Ok(json);
    }
    match path[index] {
        JsonPathElement::Key(key) => {
            match json {
                &Object(ref obj) => {
                    match obj.get(key) {
                        Some(value) => get_json_value(value, path, index + 1),
                        None => Err(format!("Key {} not found in {}", key, pretty_print(&path[0 .. index]))),
                    }
                }
                _ => Err(format!("Asked for key {} in {}, but value is not an object",
                         key, pretty_print(&path[0 .. index]))),
            }
        },
        JsonPathElement::Only => {
            match json {
                &Object(ref obj) =>
                    if obj.len() == 1 {
                        get_json_value(obj.values().next().unwrap(), path, index + 1)
                    } else {
                        Err(format!("Asked for only key in {}, but object has {} values",
                                    pretty_print(&path[0 .. index]), obj.len()))
                    },
                &Array(ref vec) =>
                    if vec.len() == 1 {
                        get_json_value(vec.first().unwrap(), path, index + 1)
                    } else {
                        Err(format!("Asked for only key in {}, but array has {} elements",
                                    pretty_print(&path[0 .. index]), vec.len()))
                    },
                _ => Err(format!("Asked for only key in {}, but value is not an object or array",
                                 pretty_print(&path[0 .. index]))),
            }
        },
    }
}

pub fn get_json_array<'a>(json: &'a Json, path: &[JsonPathElement]) -> Result<&'a Vec<Json>, String> {
    match get_json_value(json, path, 0) {
        Ok(&Json::Array(ref value)) => Ok(value),
        Ok(..) => Err(format!("Asked for array {}, but value is not an array",
                              pretty_print(&path[..]))),
        Err(message) => Err(message),
    }
}

pub fn get_json_number(json: &Json, path: &[JsonPathElement]) -> Result<u64, String> {
    match get_json_value(json, path, 0) {
        Ok(ref value) => {
            if value.is_number() {
                Ok(value.as_u64().unwrap())
            } else {
                Err(format!("Asked for number {}, but value is not a number",
                            pretty_print(&path[..])))
            }
        },
        Err(message) => Err(message),
    }
}

pub fn get_json_string<'a>(json: &'a Json, path: &[JsonPathElement]) -> Result<&'a str, String> {
    match get_json_value(json, path, 0) {
        Ok(&Json::String(ref value)) => Ok(value),
        Ok(..) => Err(format!("Asked for string {}, but value is not a string",
                              pretty_print(&path[..]))),
        Err(message) => Err(message),
    }
}

#[cfg(test)]
mod tests {
    use super::{get_json_array, get_json_string, get_json_number};
    use super::JsonPathElement::*;
    use rustc_serialize::json::Json;

    #[test]
    fn test_get_json_value_key() {
        assert_eq!(Ok("val"),
                   get_json_string(&Json::from_str("{\"key\": \"val\"}").unwrap(),
                                  &[Key("key")]))
    }

    #[test]
    fn test_get_json_value_only_with_object() {
        let json = Json::from_str("{\"key\": \"val\"}").unwrap();
        let value = get_json_string(&json, &[Only]);
        assert_eq!(Ok("val"), value);
    }

    #[test]
    fn test_get_json_value_only_with_array() {
        let json = Json::from_str("[\"val1\"]").unwrap();
        let value = get_json_string(&json, &[Only]);
        assert_eq!(Ok("val1"), value);
    }

    #[test]
    fn test_get_json_value_multiple_elements() {
        assert_eq!(
            Ok("val3"),
            get_json_string(
                &Json::from_str(
                    "{\"key1\": \"val1\", \"key2\": [{\"key3\": \"val3\"}]}").unwrap(),
                &[Key("key2"), Only, Only]))
    }

    fn assert_error_message<T>(result: &Result<T, String>, expected_message: &str) {
        match result {
            &Ok(..) => panic!(format!("Expected error message: \"{}\"", expected_message)),
            &Err(ref message) if message == expected_message => return,
            &Err(ref message) => panic!(format!("Wrong error message: \"{}\"", message)),
        }
    }

    #[test]
    fn test_get_json_value_key_not_found() {
        assert_error_message(
            &get_json_string(
                &Json::from_str("{\"key\": \"val\"}").unwrap(), &[Key("wrong_key")]),
            "Key wrong_key not found in (root)");
    }

    #[test]
    fn test_get_json_value_key_not_object() {
        for json in &["{\"key1\": 4}",
                      "{\"key1\": false}",
                      "{\"key1\": \"val1\"}",
                      "{\"key1\": [1, 2, 3]}",
                      "{\"key1\": null}"] {
            assert_error_message(
                &get_json_string(&Json::from_str(json).unwrap(), &[Key("key1"), Key("key2")]),
                "Asked for key key2 in key1, but value is not an object");
        }
    }

    #[test]
    fn test_get_json_value_only_object_empty() {
        assert_error_message(
            &get_json_string(
                &Json::from_str("{\"key\": {}}").unwrap(), &[Key("key"), Only]),
            "Asked for only key in key, but object has 0 values");
    }

    #[test]
    fn test_get_json_value_only_object_multiple_values() {
        assert_error_message(
            &get_json_string(
                &Json::from_str("{\"key\": {\"key1\": \"val1\", \"key2\": \"val2\"}}").unwrap(),
                &[Key("key"), Only]),
            "Asked for only key in key, but object has 2 values");
    }

    #[test]
    fn test_get_json_value_only_array_empty() {
        assert_error_message(
            &get_json_string(
                &Json::from_str("{\"key\": []}").unwrap(), &[Key("key"), Only]),
            "Asked for only key in key, but array has 0 elements");
    }

    #[test]
    fn test_get_json_value_only_array_multiple_values() {
        assert_error_message(
            &get_json_string(
                &Json::from_str("{\"key\": [\"val1\", \"val2\"]}").unwrap(),
                &[Key("key"), Only]),
            "Asked for only key in key, but array has 2 elements");
    }

    #[test]
    fn test_get_json_value_only_not_object_or_array() {
        for json in &["{\"key1\": 4}",
                      "{\"key1\": false}",
                      "{\"key1\": \"val1\"}",
                      "{\"key1\": null}"] {
            assert_error_message(
                &get_json_string(&Json::from_str(json).unwrap(), &[Key("key1"), Only]),
                "Asked for only key in key1, but value is not an object or array");
        }
    }

    #[test]
    fn test_get_json_array_wrong_type() {
        for json in &["{\"key1\": 4}",
                      "{\"key1\": \"val1\"}",
                      "{\"key1\": false}",
                      "{\"key1\": {\"key2\": \"val1\"}}",
                      "{\"key1\": null}"] {
            assert_error_message(
                &get_json_array(&Json::from_str(json).unwrap(), &[Key("key1")]),
                "Asked for array key1, but value is not an array");
        }
    }

    #[test]
    fn test_get_json_number_wrong_type() {
        for json in &["{\"key1\": \"val1\"}",
                      "{\"key1\": false}",
                      "{\"key1\": [\"val1\"]}",
                      "{\"key1\": {\"key2\": \"val1\"}}",
                      "{\"key1\": null}"] {
            assert_error_message(
                &get_json_number(&Json::from_str(json).unwrap(), &[Key("key1")]),
                "Asked for number key1, but value is not a number");
        }
    }

    #[test]
    fn test_get_json_string_wrong_type() {
        for json in &["{\"key1\": 4}",
                      "{\"key1\": false}",
                      "{\"key1\": [\"val1\"]}",
                      "{\"key1\": {\"key2\": \"val1\"}}",
                      "{\"key1\": null}"] {
            assert_error_message(
                &get_json_string(&Json::from_str(json).unwrap(), &[Key("key1")]),
                "Asked for string key1, but value is not a string");
        }
    }
}
<commit_msg>Restore erroneously-deleted characters in json.rs.<commit_after>extern crate rustc_serialize;

use rustc_serialize::json::Json;
use rustc_serialize::json::Json::{Array, Object};

// TODO: doc comments

pub enum JsonPathElement {
    Key(&'static str), // Use the value associated with a specific key.
    Only,               // Use the only value in an array or object.
}

use json::JsonPathElement::Key;
use json::JsonPathElement::Only;

// TODO: return &str with a lifetime matching path_elements
fn pretty_print(path_elements: &[JsonPathElement]) -> String {
    // TODO: add (root) to the beginning always.
    if path_elements.is_empty() {
        "(root)".to_string()
    } else {
        path_elements.into_iter().map(|path_element| {
            match path_element {
                // TODO: why do I need the JsonPathElement:: here? I think I don't.
                &JsonPathElement::Key(ref key) => key.to_string(), // TODO: can I remove to_string()?
                &JsonPathElement::Only => "(only)".to_string(),
            }
        }).collect::<Vec<_>>().join(".")
    }
}

// TODO: document
fn get_json_value<'a>(json: &'a Json, path: &[JsonPathElement], index: usize) ->
    Result<&'a Json, String> {
    if index == path.len() {
        return Ok(json);
    }
    match path[index] {
        JsonPathElement::Key(key) => {
            match json {
                &Object(ref obj) => {
                    match obj.get(key) {
                        Some(value) => get_json_value(value, path, index + 1),
                        None => Err(format!("Key {} not found in {}", key, pretty_print(&path[0 .. index]))),
                    }
                }
                _ => Err(format!("Asked for key {} in {}, but value is not an object",
                         key, pretty_print(&path[0 .. index]))),
            }
        },
        JsonPathElement::Only => {
            match json {
                &Object(ref obj) =>
                    if obj.len() == 1 {
                        get_json_value(obj.values().next().unwrap(), path, index + 1)
                    } else {
                        Err(format!("Asked for only key in {}, but object has {} values",
                                    pretty_print(&path[0 .. index]), obj.len()))
                    },
                &Array(ref vec) =>
                    if vec.len() == 1 {
                        get_json_value(vec.first().unwrap(), path, index + 1)
                    } else {
                        Err(format!("Asked for only key in {}, but array has {} elements",
                                    pretty_print(&path[0 .. index]), vec.len()))
                    },
                _ => Err(format!("Asked for only key in {}, but value is not an object or array",
                                 pretty_print(&path[0 .. index]))),
            }
        },
    }
}

pub fn get_json_array<'a>(json: &'a Json, path: &[JsonPathElement]) -> Result<&'a Vec<Json>, String> {
    match get_json_value(json, path, 0) {
        Ok(&Json::Array(ref value)) => Ok(value),
        Ok(..) => Err(format!("Asked for array {}, but value is not an array",
                              pretty_print(&path[..]))),
        Err(message) => Err(message),
    }
}

pub fn get_json_number(json: &Json, path: &[JsonPathElement]) -> Result<u64, String> {
    match get_json_value(json, path, 0) {
        Ok(ref value) => {
            if value.is_number() {
                Ok(value.as_u64().unwrap())
            } else {
                Err(format!("Asked for number {}, but value is not a number",
                            pretty_print(&path[..])))
            }
        },
        Err(message) => Err(message),
    }
}

pub fn get_json_string<'a>(json: &'a Json, path: &[JsonPathElement]) -> Result<&'a str, String> {
    match get_json_value(json, path, 0) {
        Ok(&Json::String(ref value)) => Ok(value),
        Ok(..) => Err(format!("Asked for string {}, but value is not a string",
                              pretty_print(&path[..]))),
        Err(message) => Err(message),
    }
}

#[cfg(test)]
mod tests {
    use super::{get_json_array, get_json_string, get_json_number};
    use super::JsonPathElement::*;
    use rustc_serialize::json::Json;

    #[test]
    fn test_get_json_value_key() {
        assert_eq!(Ok("val"),
                   get_json_string(&Json::from_str("{\"key\": \"val\"}").unwrap(),
                                  &[Key("key")]))
    }

    #[test]
    fn test_get_json_value_only_with_object() {
        let json = Json::from_str("{\"key\": \"val\"}").unwrap();
        let value = get_json_string(&json, &[Only]);
        assert_eq!(Ok("val"), value);
    }

    #[test]
    fn test_get_json_value_only_with_array() {
        let json = Json::from_str("[\"val1\"]").unwrap();
        let value = get_json_string(&json, &[Only]);
        assert_eq!(Ok("val1"), value);
    }

    #[test]
    fn test_get_json_value_multiple_elements() {
        assert_eq!(
            Ok("val3"),
            get_json_string(
                &Json::from_str(
                    "{\"key1\": \"val1\", \"key2\": [{\"key3\": \"val3\"}]}").unwrap(),
                &[Key("key2"), Only, Only]))
    }

    fn assert_error_message<T>(result: &Result<T, String>, expected_message: &str) {
        match result {
            &Ok(..) => panic!(format!("Expected error message: \"{}\"", expected_message)),
            &Err(ref message) if message == expected_message => return,
            &Err(ref message) => panic!(format!("Wrong error message: \"{}\"", message)),
        }
    }

    #[test]
    fn test_get_json_value_key_not_found() {
        assert_error_message(
            &get_json_string(
                &Json::from_str("{\"key\": \"val\"}").unwrap(), &[Key("wrong_key")]),
            "Key wrong_key not found in (root)");
    }

    #[test]
    fn test_get_json_value_key_not_object() {
        for json in &["{\"key1\": 4}",
                      "{\"key1\": false}",
                      "{\"key1\": \"val1\"}",
                      "{\"key1\": [1, 2, 3]}",
                      "{\"key1\": null}"] {
            assert_error_message(
                &get_json_string(&Json::from_str(json).unwrap(), &[Key("key1"), Key("key2")]),
                "Asked for key key2 in key1, but value is not an object");
        }
    }

    #[test]
    fn test_get_json_value_only_object_empty() {
        assert_error_message(
            &get_json_string(
                &Json::from_str("{\"key\": {}}").unwrap(), &[Key("key"), Only]),
            "Asked for only key in key, but object has 0 values");
    }

    #[test]
    fn test_get_json_value_only_object_multiple_values() {
        assert_error_message(
            &get_json_string(
                &Json::from_str("{\"key\": {\"key1\": \"val1\", \"key2\": \"val2\"}}").unwrap(),
                &[Key("key"), Only]),
            "Asked for only key in key, but object has 2 values");
    }

    #[test]
    fn test_get_json_value_only_array_empty() {
        assert_error_message(
            &get_json_string(
                &Json::from_str("{\"key\": []}").unwrap(), &[Key("key"), Only]),
            "Asked for only key in key, but array has 0 elements");
    }

    #[test]
    fn test_get_json_value_only_array_multiple_values() {
        assert_error_message(
            &get_json_string(
                &Json::from_str("{\"key\": [\"val1\", \"val2\"]}").unwrap(),
                &[Key("key"), Only]),
            "Asked for only key in key, but array has 2 elements");
    }

    #[test]
    fn test_get_json_value_only_not_object_or_array() {
        for json in &["{\"key1\": 4}",
                      "{\"key1\": false}",
                      "{\"key1\": \"val1\"}",
                      "{\"key1\": null}"] {
            assert_error_message(
                &get_json_string(&Json::from_str(json).unwrap(), &[Key("key1"), Only]),
                "Asked for only key in key1, but value is not an object or array");
        }
    }

    #[test]
    fn test_get_json_array_wrong_type() {
        for json in &["{\"key1\": 4}",
                      "{\"key1\": \"val1\"}",
                      "{\"key1\": false}",
                      "{\"key1\": {\"key2\": \"val1\"}}",
                      "{\"key1\": null}"] {
            assert_error_message(
                &get_json_array(&Json::from_str(json).unwrap(), &[Key("key1")]),
                "Asked for array key1, but value is not an array");
        }
    }

    #[test]
    fn test_get_json_number_wrong_type() {
        for json in &["{\"key1\": \"val1\"}",
                      "{\"key1\": false}",
                      "{\"key1\": [\"val1\"]}",
                      "{\"key1\": {\"key2\": \"val1\"}}",
                      "{\"key1\": null}"] {
            assert_error_message(
                &get_json_number(&Json::from_str(json).unwrap(), &[Key("key1")]),
                "Asked for number key1, but value is not a number");
        }
    }

    #[test]
    fn test_get_json_string_wrong_type() {
        for json in &["{\"key1\": 4}",
                      "{\"key1\": false}",
                      "{\"key1\": [\"val1\"]}",
                      "{\"key1\": {\"key2\": \"val1\"}}",
                      "{\"key1\": null}"] {
            assert_error_message(
                &get_json_string(&Json::from_str(json).unwrap(), &[Key("key1")]),
                "Asked for string key1, but value is not a string");
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

extern crate graphics;
extern crate piston;

extern crate glutin_window;
extern crate opengl_graphics;

use std::str::FromStr;
use std::collections::HashSet;
use clap::Arg;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::window::WindowSettings;
use piston::event_loop::*;
use piston::input::*;
use piston::window::AdvancedWindow;
use glutin_window::GlutinWindow;

pub const WINDOW_TITLE: &'static str = "Conway's Game of Life";

pub const WINDOW_HEIGHT: usize = 480;
pub const WINDOW_WIDTH: usize = 640;

pub const DEFAULT_SPEED: u64 = 2;

pub const BLOCK_SIZE: usize = 10;  // NOTE: WINDOW_HEIGHT and WINDOW_WIDTH should be divisible by this

pub enum Neighbor {
   Block(Block),
   Location(Location)
}

pub struct Grid {
   grid: Vec<Vec<Option<Block>>>,
   blocks: HashSet<Block>
}

#[derive(Clone, PartialEq, Eq, Hash, Copy)]
pub struct Block {
   pub loc: Location
}

#[derive(Clone, PartialEq, Eq, Hash, Copy)]
pub struct Location {
   pub x: usize,
   pub y: usize
}

pub struct App {
   gl: GlGraphics,
   grid: Grid,
   started: bool,
   mouse_loc: (f64, f64)
}

impl Grid {
   pub fn new() -> Grid {
      let mut rows: Vec<Vec<Option<Block>>> = vec!();
      rows.reserve(WINDOW_HEIGHT / BLOCK_SIZE);
      for _ in 0..(WINDOW_HEIGHT / BLOCK_SIZE) {
         rows.push(vec![None; WINDOW_WIDTH / BLOCK_SIZE]);
      }
      Grid {
         grid: rows,
         blocks: HashSet::new()
      }
   }

   pub fn insert(&mut self, block: Block) {
      let (x, y) = (block.loc.x, block.loc.y);
      if self.valid(x, y) {
         if self.grid[y][x] == None {
            self.grid[y][x] = Some(block);
            self.blocks.insert(self.grid[y][x].unwrap());
         } else if self.grid[y][x].unwrap() != block {
            // FIXME: is this even necessary?
            self.blocks.remove(&self.grid[y][x].unwrap());
            self.grid[y][x] = Some(block);
            self.blocks.insert(self.grid[y][x].unwrap());
         }
      }
   }

   pub fn remove(&mut self, block: &Block) {
      if self.valid(block.loc.x, block.loc.y) {
         self.blocks.remove(block);
         self.grid[block.loc.y][block.loc.x] = None;
      }
   }

   pub fn neighbors(&self, block: &Block) -> Vec<Neighbor> {
      let mut vec = vec!();
      if self.valid(block.loc.x, block.loc.y) {
         let places = [(-1, -1), (-1, 0), (-1, 1), (0, 1), (0, -1), (1, 1), (1, -1), (1, 0)];
         for &(x, y) in &places {
            let xpos = (block.loc.x as isize + x) as usize;
            let ypos = (block.loc.y as isize + y) as usize;
            if self.valid(xpos, ypos) {
               let row = &self.grid[ypos];
               vec.push(match row[xpos] {
                  Some(blk) => Neighbor::Block(blk),
                  None => Neighbor::Location(Location::new(xpos, ypos))
               });
            }
         }
      }
      vec
   }

   #[inline]
   pub fn live_neighbors(&self, block: &Block) -> Vec<Block> {
      let mut live = vec!();
      for neighbor in self.neighbors(block) {
         match neighbor {
            Neighbor::Block(blk) => live.push(blk),
            _ => {}
         }
      }
      live
   }

   #[inline]
   pub fn dead_neighbors(&self, block: &Block) -> Vec<Location> {
      let mut dead = vec!();
      for neighbor in self.neighbors(block) {
         match neighbor {
            Neighbor::Location(loc) => dead.push(loc),
            _ => {}
         }
      }
      dead
   }

   pub fn contains(&self, block: &Block) -> bool {
      if self.valid(block.loc.x, block.loc.y) {
         self.grid[block.loc.y][block.loc.x].is_some()
      } else {
         false
      }
   }

   #[inline]
   fn valid(&self, x: usize, y: usize) -> bool {
      y < self.grid.len() && x < self.grid[0].len()
   }

   #[inline]
   pub fn render(&self, gl: &mut GlGraphics, started: bool, args: &RenderArgs) {
      use graphics::grid::*;
      use graphics::line::Line;

      const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];

      if !started {
         gl.draw(args.viewport(), |c, gl| {
            Grid {
               cols: self.grid[0].len() as u32,
               rows: self.grid.len() as u32,
               units: BLOCK_SIZE as f64
            }.draw(&Line::new(BLACK, 1.0), &c.draw_state, c.transform, gl);
         });
      }

      for block in &self.blocks {
         block.render(gl, args);
      }
   }
}

impl Block {
   #[inline]
   pub fn new(loc: Location) -> Block {
      Block {
         loc: loc
      }
   }

   #[inline]
   pub fn render(&self, gl: &mut GlGraphics, args: &RenderArgs) {
      use graphics::*;

      const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];

      let block = rectangle::square(0.0, 0.0, BLOCK_SIZE as f64);

      gl.draw(args.viewport(), |c, gl| {
         rectangle(BLACK,
                   block,
                   c.transform.trans((self.loc.x * BLOCK_SIZE) as f64,
                                     (self.loc.y * BLOCK_SIZE) as f64),
                   gl);
      });
   }
}

impl Location {
   #[inline]
   pub fn new(x: usize, y: usize) -> Location {
      assert!(x <= WINDOW_WIDTH / BLOCK_SIZE);
      assert!(y <= WINDOW_HEIGHT / BLOCK_SIZE);
      Location {
         x: x,
         y: y
      }
   }
}

impl App {
   #[inline]
   pub fn new(gl: GlGraphics) -> App {
      App {
         gl: gl,
         grid: Grid::new(),
         started: false,
         mouse_loc: (0.0, 0.0)
      }
   }

   pub fn release<W: AdvancedWindow>(&mut self, window: &mut W, button: &Button) {
      match button {
         &Button::Keyboard(key) => self.key_release(window, key),
         &Button::Mouse(button) => self.mouse_release(button),
         _ => { }
      }
   }

   pub fn key_release<W: AdvancedWindow>(&mut self, window: &mut W, key: Key) {
      match key {
         Key::R => {
            self.grid = Grid::new();
            self.started = false;
            self.mouse_loc = (0.0, 0.0);
         }
         Key::P | Key::Return => {
            if self.started {
               self.started = false;
               window.set_title(format!("{} (paused)", WINDOW_TITLE));
            } else {
               self.started = true;
               window.set_title(WINDOW_TITLE.to_string());
            }
         }
         _ => {}
      }
      println!("released key: {:?}", key);
   }

   pub fn mouse_release(&mut self, button: MouseButton) {
      if !self.started {
         let (mut x, mut y) = self.mouse_loc;
         x = (x - (x as usize % BLOCK_SIZE) as f64) / BLOCK_SIZE as f64;
         y = (y - (y as usize % BLOCK_SIZE) as f64) / BLOCK_SIZE as f64;
         self.grid.insert(Block::new(Location::new(x as usize, y as usize)))
      }
      println!("release mouse mutton: {:?}", button);
   }

   pub fn mouse_move(&mut self, pos: [f64; 2]) {
      self.mouse_loc = (pos[0], pos[1]);
   }

   #[cfg(random)]
   #[inline]
   fn update_logic(&mut self) {
      use std::rand::random;

      let mut x = (random::<f64>() * WINDOW_WIDTH as f64) as u32;
      x = (x - x % BLOCK_SIZE) / BLOCK_SIZE;
      let mut y = (random::<f64>() * WINDOW_HEIGHT as f64) as u32;
      y = (y - y % BLOCK_SIZE) / BLOCK_SIZE;
      self.grid.insert(Block::new(Location::new(x, y)));
   }

   #[cfg(not(random))]
   #[inline]
   fn update_logic(&mut self) {
      let mut remove = vec!();
      let mut add = vec!();

      for &block in &self.grid.blocks {
         let live = self.grid.live_neighbors(&block);
         let livelen = live.len();
         if livelen != 2 && livelen != 3 {
            remove.push(block);
         }
         for loc in self.grid.dead_neighbors(&block) {
            let block = Block::new(loc);
            if self.grid.live_neighbors(&block).len() == 3 {
               add.push(block);
            }
         }
      }
      for block in remove {
         self.grid.remove(&block);
      }
      for block in add {
         self.grid.insert(block);
      }
   }

   pub fn update(&mut self, _: &UpdateArgs) {
      if self.started {
         self.update_logic();
      }
   }

   pub fn render(&mut self, args: &RenderArgs) {
      (&mut self.gl).viewport(0, 0, args.width as i32, args.height as i32);
      self.gl.draw(args.viewport(), |_, gl| {
         clear([1.0, 1.0, 1.0, 1.0], gl);
      });

      self.grid.render(&mut self.gl, self.started, args);
   }
}

fn main() {
   assert!(WINDOW_WIDTH % BLOCK_SIZE == 0);
   assert!(WINDOW_HEIGHT % BLOCK_SIZE == 0);

   let matches = clap::App::new("game-of-life")
                               .version(crate_version!())
                               .author(crate_authors!())
                               .about(crate_description!())
                               .arg(Arg::with_name("speed")
                                    .short("s")
                                    .long("speed")
                                    .value_name("SPEED")
                                    .help("Sets the speed of each update")
                                    .takes_value(true))
                               .get_matches();

   // TODO: move error into clap parsing
   let speed = if let Some(valstr) = matches.value_of("speed") {
      match u64::from_str(valstr) {
         Ok(val) => val,
         Err(_) => {
            println!("error: {} is not a valid speed", valstr);
            DEFAULT_SPEED
         }
      }
   } else {
      DEFAULT_SPEED
   };

   let opengl = OpenGL::V3_2;

   let mut window: GlutinWindow = WindowSettings::new(
      WINDOW_TITLE,
      [WINDOW_WIDTH as u32, WINDOW_HEIGHT as u32]
   ).fullscreen(false).exit_on_esc(true).build().unwrap();

   let mut app = App::new(GlGraphics::new(opengl));

   let event_settings = EventSettings::new().ups(speed).max_fps(60);
   let mut events = Events::new(event_settings);
   while let Some(e) = events.next(&mut window) {
      if let Some(r) = e.render_args() {
         app.render(&r);
      }

      if let Some(u) = e.update_args() {
         app.update(&u);
      }

      if let Some(b) = e.release_args() {
         app.release(&mut window, &b);
      }

      if let Some(c) = e.mouse_cursor_args() {
         app.mouse_move(c);
      }
   }
}
<commit_msg>Let the user really scribble with the mouse (and remove blocks).<commit_after>#[macro_use]
extern crate clap;

extern crate graphics;
extern crate piston;

extern crate glutin_window;
extern crate opengl_graphics;

use std::str::FromStr;
use std::collections::HashSet;
use clap::Arg;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::window::WindowSettings;
use piston::event_loop::*;
use piston::input::*;
use piston::window::AdvancedWindow;
use glutin_window::GlutinWindow;

pub const WINDOW_TITLE: &'static str = "Conway's Game of Life";

pub const WINDOW_HEIGHT: usize = 480;
pub const WINDOW_WIDTH: usize = 640;

pub const DEFAULT_SPEED: u64 = 2;

pub const BLOCK_SIZE: usize = 10;  // NOTE: WINDOW_HEIGHT and WINDOW_WIDTH should be divisible by this

pub enum Neighbor {
   Block(Block),
   Location(Location)
}

pub struct Grid {
   grid: Vec<Vec<Option<Block>>>,
   blocks: HashSet<Block>
}

#[derive(Clone, PartialEq, Eq, Hash, Copy)]
pub struct Block {
   pub loc: Location
}

#[derive(Clone, PartialEq, Eq, Hash, Copy)]
pub struct Location {
   pub x: usize,
   pub y: usize
}

pub struct App {
   gl: GlGraphics,
   grid: Grid,
   started: bool,
   mouse_loc: (f64, f64),
   mouse_down: (bool, bool)   // (left, right)
}

impl Grid {
   pub fn new() -> Grid {
      let mut rows: Vec<Vec<Option<Block>>> = vec!();
      rows.reserve(WINDOW_HEIGHT / BLOCK_SIZE);
      for _ in 0..(WINDOW_HEIGHT / BLOCK_SIZE) {
         rows.push(vec![None; WINDOW_WIDTH / BLOCK_SIZE]);
      }
      Grid {
         grid: rows,
         blocks: HashSet::new()
      }
   }

   pub fn insert(&mut self, block: Block) {
      let (x, y) = (block.loc.x, block.loc.y);
      if self.valid(x, y) {
         if self.grid[y][x] == None {
            self.grid[y][x] = Some(block);
            self.blocks.insert(self.grid[y][x].unwrap());
         } else if self.grid[y][x].unwrap() != block {
            // FIXME: is this even necessary?
            self.blocks.remove(&self.grid[y][x].unwrap());
            self.grid[y][x] = Some(block);
            self.blocks.insert(self.grid[y][x].unwrap());
         }
      }
   }

   pub fn remove(&mut self, block: &Block) {
      if self.valid(block.loc.x, block.loc.y) {
         self.blocks.remove(block);
         self.grid[block.loc.y][block.loc.x] = None;
      }
   }

   pub fn neighbors(&self, block: &Block) -> Vec<Neighbor> {
      let mut vec = vec!();
      if self.valid(block.loc.x, block.loc.y) {
         let places = [(-1, -1), (-1, 0), (-1, 1), (0, 1), (0, -1), (1, 1), (1, -1), (1, 0)];
         for &(x, y) in &places {
            let xpos = (block.loc.x as isize + x) as usize;
            let ypos = (block.loc.y as isize + y) as usize;
            if self.valid(xpos, ypos) {
               let row = &self.grid[ypos];
               vec.push(match row[xpos] {
                  Some(blk) => Neighbor::Block(blk),
                  None => Neighbor::Location(Location::new(xpos, ypos))
               });
            }
         }
      }
      vec
   }

   #[inline]
   pub fn live_neighbors(&self, block: &Block) -> Vec<Block> {
      let mut live = vec!();
      for neighbor in self.neighbors(block) {
         match neighbor {
            Neighbor::Block(blk) => live.push(blk),
            _ => {}
         }
      }
      live
   }

   #[inline]
   pub fn dead_neighbors(&self, block: &Block) -> Vec<Location> {
      let mut dead = vec!();
      for neighbor in self.neighbors(block) {
         match neighbor {
            Neighbor::Location(loc) => dead.push(loc),
            _ => {}
         }
      }
      dead
   }

   pub fn contains(&self, block: &Block) -> bool {
      if self.valid(block.loc.x, block.loc.y) {
         self.grid[block.loc.y][block.loc.x].is_some()
      } else {
         false
      }
   }

   #[inline]
   fn valid(&self, x: usize, y: usize) -> bool {
      y < self.grid.len() && x < self.grid[0].len()
   }

   #[inline]
   pub fn render(&self, gl: &mut GlGraphics, started: bool, args: &RenderArgs) {
      use graphics::grid::*;
      use graphics::line::Line;

      const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];

      if !started {
         gl.draw(args.viewport(), |c, gl| {
            Grid {
               cols: self.grid[0].len() as u32,
               rows: self.grid.len() as u32,
               units: BLOCK_SIZE as f64
            }.draw(&Line::new(BLACK, 1.0), &c.draw_state, c.transform, gl);
         });
      }

      for block in &self.blocks {
         block.render(gl, args);
      }
   }
}

impl Block {
   #[inline]
   pub fn new(loc: Location) -> Block {
      Block {
         loc: loc
      }
   }

   #[inline]
   pub fn render(&self, gl: &mut GlGraphics, args: &RenderArgs) {
      use graphics::*;

      const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];

      let block = rectangle::square(0.0, 0.0, BLOCK_SIZE as f64);

      gl.draw(args.viewport(), |c, gl| {
         rectangle(BLACK,
                   block,
                   c.transform.trans((self.loc.x * BLOCK_SIZE) as f64,
                                     (self.loc.y * BLOCK_SIZE) as f64),
                   gl);
      });
   }
}

impl Location {
   #[inline]
   pub fn new(x: usize, y: usize) -> Location {
      assert!(x <= WINDOW_WIDTH / BLOCK_SIZE);
      assert!(y <= WINDOW_HEIGHT / BLOCK_SIZE);
      Location {
         x: x,
         y: y
      }
   }
}

impl App {
   #[inline]
   pub fn new(gl: GlGraphics) -> App {
      App {
         gl: gl,
         grid: Grid::new(),
         started: false,
         mouse_loc: (0.0, 0.0),
         mouse_down: (false, false)
      }
   }

   pub fn press(&mut self, button: &Button) {
      match button {
         &Button::Mouse(button) => self.mouse_press(button),
         _ => {}
      }
   }

   pub fn release<W: AdvancedWindow>(&mut self, window: &mut W, button: &Button) {
      match button {
         &Button::Keyboard(key) => self.key_release(window, key),
         &Button::Mouse(button) => self.mouse_release(button),
         _ => { }
      }
   }

   pub fn key_release<W: AdvancedWindow>(&mut self, window: &mut W, key: Key) {
      match key {
         Key::R => {
            self.grid = Grid::new();
            self.started = false;
            self.mouse_loc = (0.0, 0.0);
         }
         Key::P | Key::Return => {
            if self.started {
               self.started = false;
               window.set_title(format!("{} (paused)", WINDOW_TITLE));
            } else {
               self.started = true;
               window.set_title(WINDOW_TITLE.to_string());
            }
         }
         _ => {}
      }
      println!("released key: {:?}", key);
   }

   fn mouse_press(&mut self, button: MouseButton) {
      let (left, right) = self.mouse_down;
      self.mouse_down = match button {
         MouseButton::Left => (true, false),
         MouseButton::Right => (false, true),
         _ => (left, right)
      };
      self.mouse_paint();
      println!("press mouse button: {:?}", button);
   }

   fn mouse_release(&mut self, button: MouseButton) {
      let (left, right) = self.mouse_down;
      self.mouse_down = match button {
         MouseButton::Left => (false, right),
         MouseButton::Right => (left, false),
         _ => (left, right)
      };
      println!("release mouse mutton: {:?}", button);
   }

   pub fn mouse_move(&mut self, pos: [f64; 2]) {
      self.mouse_loc = (pos[0], pos[1]);
      self.mouse_paint();
   }

   fn mouse_paint(&mut self) {
      let (left, right) = self.mouse_down;
      if !self.started && (left || right) {
         let (mut x, mut y) = self.mouse_loc;
         x = (x - (x as usize % BLOCK_SIZE) as f64) / BLOCK_SIZE as f64;
         y = (y - (y as usize % BLOCK_SIZE) as f64) / BLOCK_SIZE as f64;
         let block = Block::new(Location::new(x as usize, y as usize));
         if left {
            self.grid.insert(block);
         } else {
            self.grid.remove(&block);
         }
      }
   }

   #[cfg(random)]
   #[inline]
   fn update_logic(&mut self) {
      use std::rand::random;

      let mut x = (random::<f64>() * WINDOW_WIDTH as f64) as u32;
      x = (x - x % BLOCK_SIZE) / BLOCK_SIZE;
      let mut y = (random::<f64>() * WINDOW_HEIGHT as f64) as u32;
      y = (y - y % BLOCK_SIZE) / BLOCK_SIZE;
      self.grid.insert(Block::new(Location::new(x, y)));
   }

   #[cfg(not(random))]
   #[inline]
   fn update_logic(&mut self) {
      let mut remove = vec!();
      let mut add = vec!();

      for &block in &self.grid.blocks {
         let live = self.grid.live_neighbors(&block);
         let livelen = live.len();
         if livelen != 2 && livelen != 3 {
            remove.push(block);
         }
         for loc in self.grid.dead_neighbors(&block) {
            let block = Block::new(loc);
            if self.grid.live_neighbors(&block).len() == 3 {
               add.push(block);
            }
         }
      }
      for block in remove {
         self.grid.remove(&block);
      }
      for block in add {
         self.grid.insert(block);
      }
   }

   pub fn update(&mut self, _: &UpdateArgs) {
      if self.started {
         self.update_logic();
      }
   }

   pub fn render(&mut self, args: &RenderArgs) {
      (&mut self.gl).viewport(0, 0, args.width as i32, args.height as i32);
      self.gl.draw(args.viewport(), |_, gl| {
         clear([1.0, 1.0, 1.0, 1.0], gl);
      });

      self.grid.render(&mut self.gl, self.started, args);
   }
}

fn main() {
   assert!(WINDOW_WIDTH % BLOCK_SIZE == 0);
   assert!(WINDOW_HEIGHT % BLOCK_SIZE == 0);

   let matches = clap::App::new("game-of-life")
                               .version(crate_version!())
                               .author(crate_authors!())
                               .about(crate_description!())
                               .arg(Arg::with_name("speed")
                                    .short("s")
                                    .long("speed")
                                    .value_name("SPEED")
                                    .help("Sets the speed of each update")
                                    .takes_value(true))
                               .get_matches();

   // TODO: move error into clap parsing
   let speed = if let Some(valstr) = matches.value_of("speed") {
      match u64::from_str(valstr) {
         Ok(val) => val,
         Err(_) => {
            println!("error: {} is not a valid speed", valstr);
            DEFAULT_SPEED
         }
      }
   } else {
      DEFAULT_SPEED
   };

   let opengl = OpenGL::V3_2;

   let mut window: GlutinWindow = WindowSettings::new(
      WINDOW_TITLE,
      [WINDOW_WIDTH as u32, WINDOW_HEIGHT as u32]
   ).fullscreen(false).exit_on_esc(true).build().unwrap();

   let mut app = App::new(GlGraphics::new(opengl));

   let event_settings = EventSettings::new().ups(speed).max_fps(60);
   let mut events = Events::new(event_settings);
   while let Some(e) = events.next(&mut window) {
      if let Some(r) = e.render_args() {
         app.render(&r);
      }

      if let Some(u) = e.update_args() {
         app.update(&u);
      }

      if let Some(b) = e.release_args() {
         app.release(&mut window, &b);
      }

      if let Some(b) = e.press_args() {
         app.press(&b);
      }

      if let Some(c) = e.mouse_cursor_args() {
         app.mouse_move(c);
      }
   }
}
<|endoftext|>


<commit_before>#![macro_escape]

//! LVal: The basic object type

use std::mem;
use std::fmt;
use lenv::LEnv;
use parser::ast::{Expr, ExprNode};
use util::{print_error, stringify_vec};

/// Return an error
macro_rules! err(
    ($msg:expr) => (
        return LVal::err($msg.into_string())
    );

    ($msg:expr, $( $args:expr ),* ) => (
        return LVal::err(format!($msg, $($args),* ))
    );
)

/// A builtin function
///
/// Used to implement PartialEq for the function pointer
#[deriving(Clone)]
pub struct LBuiltin(pub fn(& mut LEnv, LVal) -> LVal);

impl PartialEq for LBuiltin {
    fn eq(&self, other: &LBuiltin) -> bool {
        unsafe {
            let ptr_self:  *const () = mem::transmute(*self);
            let ptr_other: *const () = mem::transmute(*other);
            ptr_self == ptr_other
        }
    }
}

/// A basic object
#[deriving(PartialEq, Clone)]
pub enum LVal {
    Num(f64),
    Err(String),
    Sym(String),  // TODO: Use SharedString?
    Function {
        env: LEnv,
        formals: Vec<LVal>,  // List of formal argument symbols
        body:    Vec<LVal>   // Actually a S-Expr
    },
    Builtin(LBuiltin),
    SExpr(Vec<LVal>),
    QExpr(Vec<LVal>)
}

impl LVal {

    // --- Constructors ---------------------------------------------------------

    /// Create a new number lval
    pub fn num(value: f64) -> LVal {
        LVal::Num(value)
    }

    /// Create a new error lval
    pub fn err(msg: String) -> LVal {
        LVal::Err(msg)
    }

    /// Create a new symbol lval
    pub fn sym(symbol: &str) -> LVal {
        LVal::Sym(symbol.into_string())
    }

    // Create a new lambda lval
    pub fn lambda(formals: LVal, body: LVal) -> LVal {
        LVal::Function {
            env:     LEnv::new(),
            formals: formals.into_values(),
            body:    body.into_values()
        }
    }

    /// Create a new function lval
    pub fn func(f: fn(&mut LEnv, LVal) -> LVal) -> LVal {
        LVal::Builtin(LBuiltin(f))
    }

    /// Create a new sepxr lval
    pub fn sexpr() -> LVal {
        LVal::SExpr(vec![])
    }

    /// Create a new sepxr lval
    pub fn qexpr() -> LVal {
        LVal::QExpr(vec![])
    }

    /// Construct a lval from a given AST
    pub fn from_ast(ast: ExprNode) -> LVal {
        match ast.value {
            Expr::Number(i) => LVal::num(i as f64),
            Expr::Symbol(s) => LVal::sym(s[]),
            Expr::SExpr(exprs) => {
                let mut sexpr = LVal::sexpr();
                for child in exprs.into_iter() {
                    sexpr.append(LVal::from_ast(child));
                }

                sexpr
            },
            Expr::QExpr(exprs) => {
                let mut qexpr = LVal::qexpr();
                for child in exprs.into_iter() {
                    qexpr.append(LVal::from_ast(child));
                }

                qexpr
            }
        }
    }

    // --- Public methods: Conversions ------------------------------------------

    pub fn as_values(&self) -> &Vec<LVal> {
        if let &LVal::SExpr(ref values) = self {
            values
        } else if let &LVal::QExpr(ref values) = self {
            values
        } else {
            panic!("LVal::as_values(self={})", self);
        }
    }

    pub fn into_values(self) -> Vec<LVal> {
        if let LVal::SExpr(values) = self {
            values
        } else if let LVal::QExpr(values) = self {
            values
        } else {
            panic!("LVal::into_values(self={})", self);
        }
    }

    pub fn as_num(&self) -> &f64 {
        if let &LVal::Num(ref float) = self {
            return float
        } else {
            panic!("LVal::as_num(self={})", self)
        }
    }

    pub fn into_num(self) -> f64 {
        if let LVal::Num(float) = self {
            //let Float(ref mut i) = float;
            //return i
            return float
        } else {
            panic!("LVal::into_num(self={})", self)
        }
    }
    pub fn as_sym(&self) -> &String {
        if let &LVal::Sym(ref value) = self {
            return value
        } else {
            panic!("LVal::as_sym(self={})", self)
        }
    }

    // --- Public methods: Other functions --------------------------------------

    /// Delete a lval
    pub fn del(self) {}

    /// Append a lval to a sexpr
    ///
    /// Panics when `self` is not a SExpr
    pub fn append(&mut self, expr: LVal) {
        if let LVal::SExpr(ref mut values) = *self {
            values.push(expr);
        } else if let LVal::QExpr(ref mut values) = *self {
            values.push(expr);
        } else {
            panic!("LVal::append(self={}, expr={})", self, expr);
        }
    }

    /// Append all values from a sexpr to a sexpr
    ///
    /// Panics when `self` or `container` is not a SExpr
    pub fn extend(&mut self, container: LVal) {
        if let LVal::SExpr(ref mut values) = *self {
            values.extend(container.into_values().into_iter());
        } else if let LVal::QExpr(ref mut values) = *self {
            values.extend(container.into_values().into_iter());
        } else {
            panic!("LVal::extend(self={}, expr={})", self, container);
        }
    }

    pub fn type_name(&self) -> &'static str {
        match *self {
            LVal::Num(..)      => "a number",
            LVal::Err(..)      => "an error",
            LVal::Sym(..)      => "a symbol",
            LVal::Function{..} => "a lambda",
            LVal::Builtin(..)  => "a builtin function",
            LVal::SExpr(..)    => "a s-expression",
            LVal::QExpr(..)    => "a q-expression"
        }
    }

    pub fn to_string(&self, env: &LEnv) -> String {
        match *self {
            LVal::Sym(ref name) => {
                match env.get(name[]) {
                    LVal::Err(..) => name.clone(),
                    value         => value.to_string(env)
                }
            },
            LVal::SExpr(ref values) => {
                format!(
                    "({})",
                    values.iter()
                        .map(|v| v.to_string(env))
                        .collect::<Vec<_>>()
                        .connect(" ")
                )
            }
            LVal::Function { ref env, ref formals, ref body } => {
                format!(
                    "\\ {{{}}} {{{}}}",
                    stringify_vec(formals),
                    body.iter()
                        .map(|v| v.to_string(env))
                        .collect::<Vec<_>>()
                        .connect(" ")
                )
            },
            LVal::Builtin(..) => match env.look_up(self) {
                Some(name) => format!("<builtin: '{}'>", name),
                None => format!("{}", self)
            },
            _ => { format!("{}", self) }
        }
    }

    pub fn print(&self, env: &LEnv) {
        if let LVal::Err(ref msg) = *self {
            print_error(msg[]);
        } else {
            print!("{}", self.to_string(env));
        }
    }

    pub fn println(&self, env: &LEnv) {
        self.print(env);
        println!("");
    }
}

// Used for debugging and when the environment is not available
impl fmt::Show for LVal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            LVal::Num(i)            => write!(f, "{}", i),
            LVal::Err(ref msg)      => write!(f, "{}", msg),
            LVal::Sym(ref symbol)   => write!(f, "{}", symbol),
            LVal::Function{ env: _, ref formals, ref body } => {
                write!(f, "\\ {{{}}} {{{}}}", stringify_vec(formals),
                                              stringify_vec(body))
            },
            LVal::Builtin(..)       => write!(f, "<function>"),
            LVal::SExpr(ref values) => {
                write!(f, "({})", stringify_vec(values))
            },
            LVal::QExpr(ref values) => {
                write!(f, "{{{}}}", stringify_vec(values))
            }
        }
    }
}<commit_msg>Update to latest rust<commit_after>#![macro_escape]

//! LVal: The basic object type

use std::mem;
use std::fmt;
use lenv::LEnv;
use parser::ast::{Expr, ExprNode};
use util::{print_error, stringify_vec};

/// Return an error
macro_rules! err(
    ($msg:expr) => (
        return LVal::err($msg.into_string())
    );

    ($msg:expr, $( $args:expr ),* ) => (
        return LVal::err(format!($msg, $($args),* ))
    );
)

/// A builtin function
///
/// Used to implement PartialEq for the function pointer
#[deriving(Clone)]
pub struct LBuiltin(pub fn(& mut LEnv, LVal) -> LVal);

impl PartialEq for LBuiltin {
    fn eq(&self, other: &LBuiltin) -> bool {
        unsafe {
            let ptr_self:  *const () = mem::transmute(self);
            let ptr_other: *const () = mem::transmute(other);
            ptr_self == ptr_other
        }
    }
}

/// A basic object
#[deriving(PartialEq, Clone)]
pub enum LVal {
    Num(f64),
    Err(String),
    Sym(String),  // TODO: Use SharedString?
    Function {
        env: LEnv,
        formals: Vec<LVal>,  // List of formal argument symbols
        body:    Vec<LVal>   // Actually a S-Expr
    },
    Builtin(LBuiltin),
    SExpr(Vec<LVal>),
    QExpr(Vec<LVal>)
}

impl LVal {

    // --- Constructors ---------------------------------------------------------

    /// Create a new number lval
    pub fn num(value: f64) -> LVal {
        LVal::Num(value)
    }

    /// Create a new error lval
    pub fn err(msg: String) -> LVal {
        LVal::Err(msg)
    }

    /// Create a new symbol lval
    pub fn sym(symbol: &str) -> LVal {
        LVal::Sym(symbol.into_string())
    }

    // Create a new lambda lval
    pub fn lambda(formals: LVal, body: LVal) -> LVal {
        LVal::Function {
            env:     LEnv::new(),
            formals: formals.into_values(),
            body:    body.into_values()
        }
    }

    /// Create a new function lval
    pub fn func(f: fn(&mut LEnv, LVal) -> LVal) -> LVal {
        LVal::Builtin(LBuiltin(f))
    }

    /// Create a new sepxr lval
    pub fn sexpr() -> LVal {
        LVal::SExpr(vec![])
    }

    /// Create a new sepxr lval
    pub fn qexpr() -> LVal {
        LVal::QExpr(vec![])
    }

    /// Construct a lval from a given AST
    pub fn from_ast(ast: ExprNode) -> LVal {
        match ast.value {
            Expr::Number(i) => LVal::num(i as f64),
            Expr::Symbol(s) => LVal::sym(s[]),
            Expr::SExpr(exprs) => {
                let mut sexpr = LVal::sexpr();
                for child in exprs.into_iter() {
                    sexpr.append(LVal::from_ast(child));
                }

                sexpr
            },
            Expr::QExpr(exprs) => {
                let mut qexpr = LVal::qexpr();
                for child in exprs.into_iter() {
                    qexpr.append(LVal::from_ast(child));
                }

                qexpr
            }
        }
    }

    // --- Public methods: Conversions ------------------------------------------

    pub fn as_values(&self) -> &Vec<LVal> {
        if let &LVal::SExpr(ref values) = self {
            values
        } else if let &LVal::QExpr(ref values) = self {
            values
        } else {
            panic!("LVal::as_values(self={})", self);
        }
    }

    pub fn into_values(self) -> Vec<LVal> {
        if let LVal::SExpr(values) = self {
            values
        } else if let LVal::QExpr(values) = self {
            values
        } else {
            panic!("LVal::into_values(self={})", self);
        }
    }

    pub fn as_num(&self) -> &f64 {
        if let &LVal::Num(ref float) = self {
            return float
        } else {
            panic!("LVal::as_num(self={})", self)
        }
    }

    pub fn into_num(self) -> f64 {
        if let LVal::Num(float) = self {
            //let Float(ref mut i) = float;
            //return i
            return float
        } else {
            panic!("LVal::into_num(self={})", self)
        }
    }
    pub fn as_sym(&self) -> &String {
        if let &LVal::Sym(ref value) = self {
            return value
        } else {
            panic!("LVal::as_sym(self={})", self)
        }
    }

    // --- Public methods: Other functions --------------------------------------

    /// Delete a lval
    pub fn del(self) {}

    /// Append a lval to a sexpr
    ///
    /// Panics when `self` is not a SExpr
    pub fn append(&mut self, expr: LVal) {
        if let LVal::SExpr(ref mut values) = *self {
            values.push(expr);
        } else if let LVal::QExpr(ref mut values) = *self {
            values.push(expr);
        } else {
            panic!("LVal::append(self={}, expr={})", self, expr);
        }
    }

    /// Append all values from a sexpr to a sexpr
    ///
    /// Panics when `self` or `container` is not a SExpr
    pub fn extend(&mut self, container: LVal) {
        if let LVal::SExpr(ref mut values) = *self {
            values.extend(container.into_values().into_iter());
        } else if let LVal::QExpr(ref mut values) = *self {
            values.extend(container.into_values().into_iter());
        } else {
            panic!("LVal::extend(self={}, expr={})", self, container);
        }
    }

    pub fn type_name(&self) -> &'static str {
        match *self {
            LVal::Num(..)      => "a number",
            LVal::Err(..)      => "an error",
            LVal::Sym(..)      => "a symbol",
            LVal::Function{..} => "a lambda",
            LVal::Builtin(..)  => "a builtin function",
            LVal::SExpr(..)    => "a s-expression",
            LVal::QExpr(..)    => "a q-expression"
        }
    }

    pub fn to_string(&self, env: &LEnv) -> String {
        match *self {
            LVal::Sym(ref name) => {
                match env.get(name[]) {
                    LVal::Err(..) => name.clone(),
                    value         => value.to_string(env)
                }
            },
            LVal::SExpr(ref values) => {
                format!(
                    "({})",
                    values.iter()
                        .map(|v| v.to_string(env))
                        .collect::<Vec<_>>()
                        .connect(" ")
                )
            }
            LVal::Function { ref env, ref formals, ref body } => {
                format!(
                    "\\ {{{}}} {{{}}}",
                    stringify_vec(formals),
                    body.iter()
                        .map(|v| v.to_string(env))
                        .collect::<Vec<_>>()
                        .connect(" ")
                )
            },
            LVal::Builtin(..) => match env.look_up(self) {
                Some(name) => format!("<builtin: '{}'>", name),
                None => format!("{}", self)
            },
            _ => { format!("{}", self) }
        }
    }

    pub fn print(&self, env: &LEnv) {
        if let LVal::Err(ref msg) = *self {
            print_error(msg[]);
        } else {
            print!("{}", self.to_string(env));
        }
    }

    pub fn println(&self, env: &LEnv) {
        self.print(env);
        println!("");
    }
}

// Used for debugging and when the environment is not available
impl fmt::Show for LVal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            LVal::Num(i)            => write!(f, "{}", i),
            LVal::Err(ref msg)      => write!(f, "{}", msg),
            LVal::Sym(ref symbol)   => write!(f, "{}", symbol),
            LVal::Function{ env: _, ref formals, ref body } => {
                write!(f, "\\ {{{}}} {{{}}}", stringify_vec(formals),
                                              stringify_vec(body))
            },
            LVal::Builtin(..)       => write!(f, "<function>"),
            LVal::SExpr(ref values) => {
                write!(f, "({})", stringify_vec(values))
            },
            LVal::QExpr(ref values) => {
                write!(f, "{{{}}}", stringify_vec(values))
            }
        }
    }
}<|endoftext|>


<commit_before>// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![recursion_limit="300"]
#![feature(const_fn)]

extern crate sdl2;
extern crate image;
extern crate time;
extern crate byteorder;
extern crate serde_json;
extern crate openssl;
extern crate hyper;
extern crate flate2;
extern crate rand;
extern crate rustc_serialize;
extern crate cgmath;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
extern crate collision;
pub extern crate steven_blocks;
extern crate steven_shared as shared;

#[macro_use]
pub mod macros;

pub mod ecs;
pub mod protocol;
pub mod format;
pub mod nbt;
pub mod item;
pub mod gl;
pub mod types;
pub mod resources;
pub mod render;
pub mod ui;
pub mod screen;
#[macro_use]
pub mod console;
pub mod server;
pub mod world;
pub mod chunk_builder;
pub mod auth;
pub mod model;
pub mod entity;

use std::sync::{Arc, RwLock, Mutex};
use std::marker::PhantomData;
use std::thread;
use std::sync::mpsc;

const CL_BRAND: console::CVar<String> = console::CVar {
    ty: PhantomData,
    name: "cl_brand",
    description: "cl_brand has the value of the clients current 'brand'. e.g. \"Steven\" or \
                  \"Vanilla\"",
    mutable: false,
    serializable: false,
    default: &|| "Steven".to_owned(),
};

pub struct Game {
    renderer: render::Renderer,
    screen_sys: screen::ScreenSystem,
    resource_manager: Arc<RwLock<resources::Manager>>,
    console: Arc<Mutex<console::Console>>,
    should_close: bool,

    server: server::Server,
    focused: bool,
    chunk_builder: chunk_builder::ChunkBuilder,

    connect_reply: Option<mpsc::Receiver<Result<server::Server, protocol::Error>>>,
}

impl Game {
    pub fn connect_to(&mut self, address: &str) {
        let (tx, rx) = mpsc::channel();
        self.connect_reply = Some(rx);
        let address = address.to_owned();
        let resources = self.resource_manager.clone();
        let console = self.console.clone();
        thread::spawn(move || {
            tx.send(server::Server::connect(resources, console, &address)).unwrap();
        });
    }

    pub fn tick(&mut self, delta: f64) {
        if !self.server.is_connected() {
            self.renderer.camera.yaw += 0.005 * delta;
            if self.renderer.camera.yaw > ::std::f64::consts::PI * 2.0 {
                self.renderer.camera.yaw = 0.0;
            }
        }

        if let Some(disconnect_reason) = self.server.disconnect_reason.take() {
            self.screen_sys.replace_screen(Box::new(screen::ServerList::new(
                Some(disconnect_reason)
            )));
        }
        if !self.server.is_connected() {
            self.focused = false;
        }

        let mut clear_reply = false;
        if let Some(ref recv) = self.connect_reply {
            if let Ok(server) = recv.try_recv() {
                clear_reply = true;
                match server {
                    Ok(val) => {
                        self.screen_sys.pop_screen();
                        self.focused = true;
                        self.server.remove(&mut self.renderer);
                        self.server = val;
                    },
                    Err(err) => {
                        let msg = match err {
                            protocol::Error::Disconnect(val) => val,
                            err => {
                                let mut msg = format::TextComponent::new(&format!("{}", err));
                                msg.modifier.color = Some(format::Color::Red);
                                format::Component::Text(msg)
                            },
                        };
                        self.screen_sys.replace_screen(Box::new(screen::ServerList::new(
                            Some(msg)
                        )));
                    }
                }
            }
        }
        if clear_reply {
            self.connect_reply = None;
        }
    }
}

fn main() {
    let con = Arc::new(Mutex::new(console::Console::new()));
    {
        let mut con = con.lock().unwrap();
        con.register(CL_BRAND);
        auth::register_vars(&mut con);
        con.load_config();
        con.save_config();
    }

    let proxy = console::ConsoleProxy::new(con.clone());

    log::set_logger(|max_log_level| {
        max_log_level.set(log::LogLevelFilter::Trace);
        Box::new(proxy)
    }).unwrap();

    info!("Starting steven");

    let resource_manager = Arc::new(RwLock::new(resources::Manager::new()));
    {
        resource_manager.write().unwrap().tick();
    }

    let sdl = sdl2::init().unwrap();
    let sdl_video = sdl.video().unwrap();

    sdl_video.gl_set_swap_interval(1);

    let window = sdl2::video::WindowBuilder::new(&sdl_video, "Steven", 854, 480)
                            .opengl()
                            .resizable()
                            .build()
                            .expect("Could not create sdl window.");
    let gl_attr = sdl_video.gl_attr();
    gl_attr.set_stencil_size(0);
    gl_attr.set_depth_size(24);
    gl_attr.set_context_major_version(3);
    gl_attr.set_context_minor_version(2);
    gl_attr.set_context_profile(sdl2::video::GLProfile::Core);

    let gl_context = window.gl_create_context().unwrap();
    window.gl_make_current(&gl_context).expect("Could not set current context.");

    gl::init(&sdl_video);

    let renderer = render::Renderer::new(resource_manager.clone());
    let mut ui_container = ui::Container::new();

    let mut last_frame = time::now();
    let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0;

    let mut screen_sys = screen::ScreenSystem::new();
    screen_sys.add_screen(Box::new(screen::Login::new(con.clone())));

    let textures = renderer.get_textures();
    let mut game = Game {
        server: server::Server::dummy_server(resource_manager.clone(), con.clone()),
        focused: false,
        renderer: renderer,
        screen_sys: screen_sys,
        resource_manager: resource_manager.clone(),
        console: con,
        should_close: false,
        chunk_builder: chunk_builder::ChunkBuilder::new(resource_manager, textures),
        connect_reply: None,
    };
    game.renderer.camera.pos = cgmath::Point3::new(0.5, 13.2, 0.5);

    let mut events = sdl.event_pump().unwrap();
    while !game.should_close {
        let version = {
            let mut res = game.resource_manager.write().unwrap();
            res.tick();
            res.version()
        };

        let now = time::now();
        let diff = now - last_frame;
        last_frame = now;
        let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
        let (width, height) = window.drawable_size();

        game.tick(delta);
        game.server.tick(&mut game.renderer, delta);

        game.renderer.update_camera(width, height);
        game.server.world.compute_render_list(&mut game.renderer);
        game.chunk_builder.tick(&mut game.server.world, &mut game.renderer, version);

        game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container);
        game.console
            .lock()
            .unwrap()
            .tick(&mut ui_container, &mut game.renderer, delta, width as f64);
        ui_container.tick(&mut game.renderer, delta, width as f64, height as f64);
        game.renderer.tick(&mut game.server.world, delta, width, height);

        window.gl_swap_window();

        for event in events.poll_iter() {
            handle_window_event(&window, &mut game, &mut ui_container, event)
        }
    }
}

fn handle_window_event(window: &sdl2::video::Window,
                       game: &mut Game,
                       ui_container: &mut ui::Container,
                       event: sdl2::event::Event) {
    use sdl2::event::Event;
    use sdl2::keyboard::Keycode;
    use sdl2::mouse::Mouse;
    use std::f64::consts::PI;

    let mouse = window.subsystem().sdl().mouse();

    match event {
        Event::Quit{..} => game.should_close = true,

        Event::MouseMotion{x, y, xrel, yrel, ..} => {
            let (width, height) = window.size();
            if game.focused {
                if !mouse.relative_mouse_mode() {
                    mouse.set_relative_mouse_mode(true);
                }
                if let Some(player) = game.server.player {
                    let s = 2000.0 + 0.01;
                    let (rx, ry) = (xrel as f64 / s, yrel as f64 / s);
                    let rotation = game.server.entities.get_component_mut(player, game.server.rotation).unwrap();
                    rotation.yaw -= rx;
                    rotation.pitch -= ry;
                    if rotation.pitch < (PI/2.0) + 0.01 {
                        rotation.pitch = (PI/2.0) + 0.01;
                    }
                    if rotation.pitch > (PI/2.0)*3.0 - 0.01 {
                        rotation.pitch = (PI/2.0)*3.0 - 0.01;
                    }
                }
            } else {
                if mouse.relative_mouse_mode() {
                    mouse.set_relative_mouse_mode(false);
                }
                ui_container.hover_at(game, x as f64, y as f64, width as f64, height as f64);
            }
        }
        Event::MouseButtonUp{mouse_btn: Mouse::Left, x, y, ..} => {
            let (width, height) = window.size();

            if game.server.is_connected() && !game.focused {
                game.focused = true;
                mouse.set_relative_mouse_mode(true);
                mouse.warp_mouse_in_window(&window, (width/2) as i32, (height/2) as i32);
                return;
            }
            if mouse.relative_mouse_mode() {
                mouse.set_relative_mouse_mode(false);
            }
            if !game.focused {
                ui_container.click_at(game, x as f64, y as f64, width as f64, height as f64);
            }
        }
        Event::MouseWheel{x, y, ..} => {
            game.screen_sys.on_scroll(x as f64, y as f64);
        }
        Event::KeyUp{keycode: Some(Keycode::Escape), ..} => {
            if game.focused {
                mouse.set_relative_mouse_mode(false);
                game.focused = false;
            }
        }
        Event::KeyDown{keycode: Some(Keycode::Backquote), ..} => {
            game.console.lock().unwrap().toggle();
        }
        Event::KeyDown{keycode: Some(key), ..} => {
            if game.focused {
                game.server.key_press(true, key);
            } else {
                ui_container.key_press(game, key, true);
            }
        }
        Event::KeyUp{keycode: Some(key), ..} => {
            if game.focused {
                game.server.key_press(false, key);
            } else {
                ui_container.key_press(game, key, false);
            }
        }
        Event::TextInput{text, ..} => {
            if !game.focused {
                for c in text.chars() {
                    ui_container.key_type(game, c);
                }
            }
        }
        _ => (),
    }
}
<commit_msg>Fix clicking causing the camera to flick<commit_after>// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![recursion_limit="300"]
#![feature(const_fn)]

extern crate sdl2;
extern crate image;
extern crate time;
extern crate byteorder;
extern crate serde_json;
extern crate openssl;
extern crate hyper;
extern crate flate2;
extern crate rand;
extern crate rustc_serialize;
extern crate cgmath;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
extern crate collision;
pub extern crate steven_blocks;
extern crate steven_shared as shared;

#[macro_use]
pub mod macros;

pub mod ecs;
pub mod protocol;
pub mod format;
pub mod nbt;
pub mod item;
pub mod gl;
pub mod types;
pub mod resources;
pub mod render;
pub mod ui;
pub mod screen;
#[macro_use]
pub mod console;
pub mod server;
pub mod world;
pub mod chunk_builder;
pub mod auth;
pub mod model;
pub mod entity;

use std::sync::{Arc, RwLock, Mutex};
use std::marker::PhantomData;
use std::thread;
use std::sync::mpsc;

const CL_BRAND: console::CVar<String> = console::CVar {
    ty: PhantomData,
    name: "cl_brand",
    description: "cl_brand has the value of the clients current 'brand'. e.g. \"Steven\" or \
                  \"Vanilla\"",
    mutable: false,
    serializable: false,
    default: &|| "Steven".to_owned(),
};

pub struct Game {
    renderer: render::Renderer,
    screen_sys: screen::ScreenSystem,
    resource_manager: Arc<RwLock<resources::Manager>>,
    console: Arc<Mutex<console::Console>>,
    should_close: bool,

    server: server::Server,
    focused: bool,
    chunk_builder: chunk_builder::ChunkBuilder,

    connect_reply: Option<mpsc::Receiver<Result<server::Server, protocol::Error>>>,
}

impl Game {
    pub fn connect_to(&mut self, address: &str) {
        let (tx, rx) = mpsc::channel();
        self.connect_reply = Some(rx);
        let address = address.to_owned();
        let resources = self.resource_manager.clone();
        let console = self.console.clone();
        thread::spawn(move || {
            tx.send(server::Server::connect(resources, console, &address)).unwrap();
        });
    }

    pub fn tick(&mut self, delta: f64) {
        if !self.server.is_connected() {
            self.renderer.camera.yaw += 0.005 * delta;
            if self.renderer.camera.yaw > ::std::f64::consts::PI * 2.0 {
                self.renderer.camera.yaw = 0.0;
            }
        }

        if let Some(disconnect_reason) = self.server.disconnect_reason.take() {
            self.screen_sys.replace_screen(Box::new(screen::ServerList::new(
                Some(disconnect_reason)
            )));
        }
        if !self.server.is_connected() {
            self.focused = false;
        }

        let mut clear_reply = false;
        if let Some(ref recv) = self.connect_reply {
            if let Ok(server) = recv.try_recv() {
                clear_reply = true;
                match server {
                    Ok(val) => {
                        self.screen_sys.pop_screen();
                        self.focused = true;
                        self.server.remove(&mut self.renderer);
                        self.server = val;
                    },
                    Err(err) => {
                        let msg = match err {
                            protocol::Error::Disconnect(val) => val,
                            err => {
                                let mut msg = format::TextComponent::new(&format!("{}", err));
                                msg.modifier.color = Some(format::Color::Red);
                                format::Component::Text(msg)
                            },
                        };
                        self.screen_sys.replace_screen(Box::new(screen::ServerList::new(
                            Some(msg)
                        )));
                    }
                }
            }
        }
        if clear_reply {
            self.connect_reply = None;
        }
    }
}

fn main() {
    let con = Arc::new(Mutex::new(console::Console::new()));
    {
        let mut con = con.lock().unwrap();
        con.register(CL_BRAND);
        auth::register_vars(&mut con);
        con.load_config();
        con.save_config();
    }

    let proxy = console::ConsoleProxy::new(con.clone());

    log::set_logger(|max_log_level| {
        max_log_level.set(log::LogLevelFilter::Trace);
        Box::new(proxy)
    }).unwrap();

    info!("Starting steven");

    let resource_manager = Arc::new(RwLock::new(resources::Manager::new()));
    {
        resource_manager.write().unwrap().tick();
    }

    let sdl = sdl2::init().unwrap();
    let sdl_video = sdl.video().unwrap();

    sdl_video.gl_set_swap_interval(1);

    let window = sdl2::video::WindowBuilder::new(&sdl_video, "Steven", 854, 480)
                            .opengl()
                            .resizable()
                            .build()
                            .expect("Could not create sdl window.");
    let gl_attr = sdl_video.gl_attr();
    gl_attr.set_stencil_size(0);
    gl_attr.set_depth_size(24);
    gl_attr.set_context_major_version(3);
    gl_attr.set_context_minor_version(2);
    gl_attr.set_context_profile(sdl2::video::GLProfile::Core);

    let gl_context = window.gl_create_context().unwrap();
    window.gl_make_current(&gl_context).expect("Could not set current context.");

    gl::init(&sdl_video);

    let renderer = render::Renderer::new(resource_manager.clone());
    let mut ui_container = ui::Container::new();

    let mut last_frame = time::now();
    let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0;

    let mut screen_sys = screen::ScreenSystem::new();
    screen_sys.add_screen(Box::new(screen::Login::new(con.clone())));

    let textures = renderer.get_textures();
    let mut game = Game {
        server: server::Server::dummy_server(resource_manager.clone(), con.clone()),
        focused: false,
        renderer: renderer,
        screen_sys: screen_sys,
        resource_manager: resource_manager.clone(),
        console: con,
        should_close: false,
        chunk_builder: chunk_builder::ChunkBuilder::new(resource_manager, textures),
        connect_reply: None,
    };
    game.renderer.camera.pos = cgmath::Point3::new(0.5, 13.2, 0.5);

    let mut events = sdl.event_pump().unwrap();
    while !game.should_close {
        let version = {
            let mut res = game.resource_manager.write().unwrap();
            res.tick();
            res.version()
        };

        let now = time::now();
        let diff = now - last_frame;
        last_frame = now;
        let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
        let (width, height) = window.drawable_size();

        game.tick(delta);
        game.server.tick(&mut game.renderer, delta);

        game.renderer.update_camera(width, height);
        game.server.world.compute_render_list(&mut game.renderer);
        game.chunk_builder.tick(&mut game.server.world, &mut game.renderer, version);

        game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container);
        game.console
            .lock()
            .unwrap()
            .tick(&mut ui_container, &mut game.renderer, delta, width as f64);
        ui_container.tick(&mut game.renderer, delta, width as f64, height as f64);
        game.renderer.tick(&mut game.server.world, delta, width, height);

        window.gl_swap_window();

        for event in events.poll_iter() {
            handle_window_event(&window, &mut game, &mut ui_container, event)
        }
    }
}

fn handle_window_event(window: &sdl2::video::Window,
                       game: &mut Game,
                       ui_container: &mut ui::Container,
                       event: sdl2::event::Event) {
    use sdl2::event::Event;
    use sdl2::keyboard::Keycode;
    use sdl2::mouse::Mouse;
    use std::f64::consts::PI;

    let mouse = window.subsystem().sdl().mouse();

    match event {
        Event::Quit{..} => game.should_close = true,

        Event::MouseMotion{x, y, xrel, yrel, ..} => {
            let (width, height) = window.size();
            if game.focused {
                if !mouse.relative_mouse_mode() {
                    mouse.set_relative_mouse_mode(true);
                }
                if let Some(player) = game.server.player {
                    let s = 2000.0 + 0.01;
                    let (rx, ry) = (xrel as f64 / s, yrel as f64 / s);
                    let rotation = game.server.entities.get_component_mut(player, game.server.rotation).unwrap();
                    rotation.yaw -= rx;
                    rotation.pitch -= ry;
                    if rotation.pitch < (PI/2.0) + 0.01 {
                        rotation.pitch = (PI/2.0) + 0.01;
                    }
                    if rotation.pitch > (PI/2.0)*3.0 - 0.01 {
                        rotation.pitch = (PI/2.0)*3.0 - 0.01;
                    }
                }
            } else {
                if mouse.relative_mouse_mode() {
                    mouse.set_relative_mouse_mode(false);
                }
                ui_container.hover_at(game, x as f64, y as f64, width as f64, height as f64);
            }
        }
        Event::MouseButtonUp{mouse_btn: Mouse::Left, x, y, ..} => {
            let (width, height) = window.size();

            if game.server.is_connected() && !game.focused {
                game.focused = true;
                if !mouse.relative_mouse_mode() {
                    mouse.set_relative_mouse_mode(true);
                }
                return;
            }
            if !game.focused {
                if mouse.relative_mouse_mode() {
                    mouse.set_relative_mouse_mode(false);
                }
                ui_container.click_at(game, x as f64, y as f64, width as f64, height as f64);
            }
        }
        Event::MouseWheel{x, y, ..} => {
            game.screen_sys.on_scroll(x as f64, y as f64);
        }
        Event::KeyUp{keycode: Some(Keycode::Escape), ..} => {
            if game.focused {
                mouse.set_relative_mouse_mode(false);
                game.focused = false;
            }
        }
        Event::KeyDown{keycode: Some(Keycode::Backquote), ..} => {
            game.console.lock().unwrap().toggle();
        }
        Event::KeyDown{keycode: Some(key), ..} => {
            if game.focused {
                game.server.key_press(true, key);
            } else {
                ui_container.key_press(game, key, true);
            }
        }
        Event::KeyUp{keycode: Some(key), ..} => {
            if game.focused {
                game.server.key_press(false, key);
            } else {
                ui_container.key_press(game, key, false);
            }
        }
        Event::TextInput{text, ..} => {
            if !game.focused {
                for c in text.chars() {
                    ui_container.key_type(game, c);
                }
            }
        }
        _ => (),
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Athena Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(path_ext)]

extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate phosphorus;
extern crate rustc_serialize;

use std::cell::RefCell;
use std::env;
use std::fs::{File, PathExt};
use std::io::{Read, Write};
use std::path::{PathBuf};
use std::rc::Rc;
use gfx::traits::*;
use phosphorus::Gui;
use phosphorus::widget::{ButtonBuilder, Layout, LayoutBuilder, TextBuilder};
use rustc_serialize::json;

struct SharedData {
    canceled: bool,
    queued_layout: Option<Layout<gfx_device_gl::Resources>>
}

#[derive(RustcDecodable, RustcEncodable, Clone)]
struct EntityEntry {
    x: f32,
    y: f32
}

#[derive(RustcDecodable, RustcEncodable, Clone)]
struct WorldModel {
    entities: Vec<EntityEntry>
}

#[derive(RustcDecodable, RustcEncodable, Clone)]
struct Model {
    worlds: Vec<WorldModel>
}

fn main() {
    // This is all a bunch of placeholder code that needs to be refactored into something coherent

    // Get the target path to open the editor at
    let path = match env::args().nth(1) {
        Some(v) => v,
        None => {
            display_error("No path given!");
            return;
        }
    };

    // Make sure it's a zeus project
    let mut toml_path = PathBuf::from(path.clone());
    toml_path.push("Zeus.toml");
    if !toml_path.exists() { display_error("Not a zeus project!"); return; }

    // Get the actual path of the data file
    let mut editor_path = PathBuf::from(path);
    editor_path.push("editor.json");

    let model = Rc::new(RefCell::new(if !editor_path.exists() {
        println!("Creating new editor.json...");
        let model = Model { worlds: vec![] };

        save_model(&editor_path, &model);

        model
    } else {
        println!("Loading in editor.json...");
        let mut file = File::open(editor_path.clone()).unwrap();
        let mut file_data = String::new();
        file.read_to_string(&mut file_data).unwrap();

        json::decode::<Model>(&file_data).unwrap()
    }));

    // Set up our Phosphorus UI
    let data = Rc::new(RefCell::new(SharedData { canceled: false, queued_layout: None }));
    let layout = generate_view(editor_path, data.clone(), model);

    data.borrow_mut().queued_layout = Some(layout);

    display_gui(data);
}

fn save_model(proj_path: &PathBuf, model: &Model){
    let mut file = match File::create(proj_path) {
        Ok(f) => f,
        Err(e) => panic!(format!("Folder does not exist or is not accessable, error: {:?}", e))
    };
    file.write_all(&json::encode(&model).unwrap().as_bytes()).unwrap();
}

fn generate_view(proj_path: PathBuf, data: Rc<RefCell<SharedData>>, model: Rc<RefCell<Model>>) -> Layout<gfx_device_gl::Resources> {
    // Save our model before generating so the file's always up-to-date with what's visible
    save_model(&proj_path, &model.borrow());

    let mut builder = LayoutBuilder::<gfx_device_gl::Resources>::new()
        .with_background_color([21, 23, 24]);

    // Show all of our worlds
    let mut wnum = 0;
    for world in &model.borrow_mut().worlds {
        builder = builder
            .with_widget(TextBuilder::new()
                .with_text(&format!("== World #{} ==", wnum))
                .build_boxed());

        // Show all of our entities
        let mut ennum = 0;
        for entity in &world.entities {
            builder = builder
                .with_widget(ButtonBuilder::new()
                    .with_text(&format!("Entity #{} - {{x: {}, y: {}}}", ennum, entity.x, entity.y))
                    .with_size([160, 20])
                    .build_boxed());
            ennum += 1;
        }

        // Show a button to create a new entity
        let tmp_model = model.clone();
        let tmp_data = data.clone();
        let tmp_path = proj_path.clone();
        builder = builder
            .with_widget(ButtonBuilder::new()
                .with_text("Add Entity")
                .with_callback(Box::new(move || {
                    {
                        let mut m = tmp_model.borrow_mut();
                        let w = m.worlds.get_mut(wnum).unwrap();
                        w.entities.push(EntityEntry { x: 0.0, y: 0.0 });
                    }

                    tmp_data.borrow_mut().queued_layout = Some(generate_view(tmp_path.clone(), tmp_data.clone(), tmp_model.clone()));
                }))
            .build_boxed());
        wnum += 1;

        // Placeholder text as padding
        builder = builder.with_widget(TextBuilder::new().build_boxed());
    }

    // Show an add world button
    builder = builder
        .with_widget(ButtonBuilder::new()
            .with_text("Add World")
            .with_callback(Box::new(move || {
                {
                    let mut m = model.borrow_mut();
                    m.worlds.push(WorldModel { entities: vec![] });
                }

                data.borrow_mut().queued_layout = Some(generate_view(proj_path.clone(), data.clone(), model.clone()));
            }))
            .build_boxed());

    builder.build()
}

fn display_error(text: &str) {
    let data = Rc::new(RefCell::new(SharedData { canceled: false, queued_layout: None }));
    let data_clone = data.clone();
    let layout = LayoutBuilder::<gfx_device_gl::Resources>::new()
        .with_background_color([21, 23, 24])
        .with_widget(TextBuilder::new()
            .with_text(text)
            .build_boxed())
        .with_widget(ButtonBuilder::new()
            .with_text("Ok")
            .with_callback(Box::new(move || data_clone.borrow_mut().canceled = true))
            .build_boxed())
        .build();

    data.borrow_mut().queued_layout = Some(layout);

    display_gui(data);
}

fn display_gui(data: Rc<RefCell<SharedData>>)
{
    // Set up our window
    let (mut stream, mut device, mut factory) = {
        let window = glutin::WindowBuilder::new()
            .with_vsync()
            .with_dimensions(600, 500)
            .with_title(String::from("Phosphorus Widgets"))
            .build_strict().unwrap();
        gfx_window_glutin::init(window)
    };

    let mut gui = Gui::new(&mut device, &mut factory, data.borrow_mut().queued_layout.take().unwrap());

    // Run our actual UI loop
    'main: loop {
        {
            let mut d = data.borrow_mut();

            if d.canceled {
                break 'main;
            }

            if let Some(layout) = d.queued_layout.take() {
                gui.set_root(layout);
            }
        }

        // Quit when the window is closed
        for event in stream.out.window.poll_events() {
            match event {
                glutin::Event::Closed => break 'main,
                glutin::Event::MouseMoved((x, y)) =>
                    gui.raise_event(&stream, phosphorus::Event::MouseMoved([x, y])),
                glutin::Event::MouseInput(glutin::ElementState::Released, _) =>
                    gui.raise_event(&stream, phosphorus::Event::MouseClick),
                _ => (),
            }
        }

        stream.clear(gfx::ClearData {color: [1.0, 1.0, 1.0, 1.0], depth: 1.0, stencil: 0});

        // Render our actual GUI
        gui.render(&mut factory, &mut stream);

        // Show the rendered to buffer on the screen
        //stream.present(&mut device); ICE!
        stream.flush(&mut device);
        stream.out.window.swap_buffers();
        device.cleanup();
    }
}
<commit_msg>Add editor buttons for position<commit_after>// Copyright 2015 The Athena Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(path_ext)]

extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate phosphorus;
extern crate rustc_serialize;

use std::cell::RefCell;
use std::env;
use std::fs::{File, PathExt};
use std::io::{Read, Write};
use std::path::{PathBuf};
use std::rc::Rc;
use gfx::traits::*;
use phosphorus::Gui;
use phosphorus::widget::{ButtonBuilder, Layout, LayoutBuilder, TextBuilder};
use rustc_serialize::json;

struct SharedData {
    canceled: bool,
    queued_layout: Option<Layout<gfx_device_gl::Resources>>
}

#[derive(RustcDecodable, RustcEncodable, Clone)]
struct EntityEntry {
    x: f32,
    y: f32,
    z: f32
}

#[derive(RustcDecodable, RustcEncodable, Clone)]
struct WorldModel {
    entities: Vec<Rc<RefCell<EntityEntry>>>
}

#[derive(RustcDecodable, RustcEncodable, Clone)]
struct Model {
    current_entity: Option<Rc<RefCell<EntityEntry>>>,
    worlds: Vec<WorldModel>
}

fn main() {
    // This is all a bunch of placeholder code that needs to be refactored into something coherent

    // Get the target path to open the editor at
    let path = match env::args().nth(1) {
        Some(v) => v,
        None => {
            display_error("No path given!");
            return;
        }
    };

    // Make sure it's a zeus project
    let mut toml_path = PathBuf::from(path.clone());
    toml_path.push("Zeus.toml");
    if !toml_path.exists() { display_error("Not a zeus project!"); return; }

    // Get the actual path of the data file
    let mut editor_path = PathBuf::from(path);
    editor_path.push("editor.json");

    let model = Rc::new(RefCell::new(if !editor_path.exists() {
        println!("Creating new editor.json...");
        let model = Model { current_entity: None, worlds: vec![] };

        save_model(&editor_path, &model);

        model
    } else {
        println!("Loading in editor.json...");
        let mut file = File::open(editor_path.clone()).unwrap();
        let mut file_data = String::new();
        file.read_to_string(&mut file_data).unwrap();

        json::decode::<Model>(&file_data).unwrap()
    }));
    model.borrow_mut().current_entity = None;

    // Set up our Phosphorus UI
    let data = Rc::new(RefCell::new(SharedData { canceled: false, queued_layout: None }));
    let layout = generate_view(editor_path, data.clone(), model);

    data.borrow_mut().queued_layout = Some(layout);

    display_gui(data);
}

fn save_model(proj_path: &PathBuf, model: &Model){
    let mut file = match File::create(proj_path) {
        Ok(f) => f,
        Err(e) => panic!(format!("Folder does not exist or is not accessable, error: {:?}", e))
    };
    file.write_all(&json::encode(&model).unwrap().as_bytes()).unwrap();
}

fn generate_view(proj_path: PathBuf, data: Rc<RefCell<SharedData>>, model: Rc<RefCell<Model>>) -> Layout<gfx_device_gl::Resources> {
    // Save our model before generating so the file's always up-to-date with what's visible
    save_model(&proj_path, &model.borrow());

    let mut builder = LayoutBuilder::<gfx_device_gl::Resources>::new()
        .with_background_color([21, 23, 24]);

    // Show all of our worlds
    let mut wnum = 0;
    for world in &model.borrow_mut().worlds {
        builder = builder
            .with_widget(TextBuilder::new()
                .with_text(&format!("== World #{} ==", wnum))
                .build_boxed());

        // Show all of our entities
        let mut ennum = 0;
        for rc_entity in &world.entities {
            let entity = rc_entity.borrow_mut();
            let tmp_rc_entity = rc_entity.clone();
            let tmp_model = model.clone();
            let tmp_data = data.clone();
            let tmp_path = proj_path.clone();

            builder = builder
                .with_widget(ButtonBuilder::new()
                    .with_text(&format!("Entity #{} - {{x: {}, y: {}, z: {}}}", ennum, entity.x, entity.y, entity.z))
                    .with_size([180, 20])
                    .with_callback(Box::new(move || {
                        {
                            let mut m = tmp_model.borrow_mut();
                            m.current_entity = Some(tmp_rc_entity.clone());
                        }

                        tmp_data.borrow_mut().queued_layout = Some(generate_view(tmp_path.clone(), tmp_data.clone(), tmp_model.clone()));
                    }))
                    .build_boxed());
            ennum += 1;
        }

        // Show a button to create a new entity
        let tmp_model = model.clone();
        let tmp_data = data.clone();
        let tmp_path = proj_path.clone();
        builder = builder
            .with_widget(ButtonBuilder::new()
                .with_text("Add Entity")
                .with_callback(Box::new(move || {
                    {
                        let mut m = tmp_model.borrow_mut();
                        let w = m.worlds.get_mut(wnum).unwrap();
                        w.entities.push(Rc::new(RefCell::new(EntityEntry { x: 0.0, y: 0.0, z: 0.0 })));
                    }

                    tmp_data.borrow_mut().queued_layout = Some(generate_view(tmp_path.clone(), tmp_data.clone(), tmp_model.clone()));
                }))
                .build_boxed()
            );
        wnum += 1;

        // Placeholder text as padding
        builder = builder.with_widget(TextBuilder::new().build_boxed());
    }

    // Show an add world button
    let tmp_model = model.clone();
    let tmp_data = data.clone();
    let tmp_path = proj_path.clone();
    builder = builder
        .with_widget(ButtonBuilder::new()
            .with_text("Add World")
            .with_callback(Box::new(move || {
                {
                    let mut m = tmp_model.borrow_mut();
                    m.worlds.push(WorldModel { entities: vec![] });
                }

                tmp_data.borrow_mut().queued_layout = Some(generate_view(tmp_path.clone(), tmp_data.clone(), tmp_model.clone()));
            }))
            .build_boxed());

    // Show an editor for the currently selected entity
    builder = builder
        .with_widget(TextBuilder::new().build_boxed())
        .with_widget(TextBuilder::new()
            .with_text("=== Edit Entity ===")
            .build_boxed()
        );

    {
        let m = model.borrow_mut();
        if let &Some(ref rc_entity) = &m.current_entity {
            let entity = rc_entity.borrow();

            builder = builder
                .with_widget(TextBuilder::new()
                    .with_text(&format!("X: {} Y: {} Z: {}", entity.x, entity.y, entity.z))
                    .build_boxed()
                );

            // Show buttons for changing position
            builder = show_adder_button(builder, &proj_path, &data, &model, rc_entity, "X + 1", Box::new(|e| e.x += 1.0));
            builder = show_adder_button(builder, &proj_path, &data, &model, rc_entity, "X - 1", Box::new(|e| e.x -= 1.0));
            builder = show_adder_button(builder, &proj_path, &data, &model, rc_entity, "Y + 1", Box::new(|e| e.y += 1.0));
            builder = show_adder_button(builder, &proj_path, &data, &model, rc_entity, "Y - 1", Box::new(|e| e.y -= 1.0));
            builder = show_adder_button(builder, &proj_path, &data, &model, rc_entity, "Z + 1", Box::new(|e| e.z += 1.0));
            builder = show_adder_button(builder, &proj_path, &data, &model, rc_entity, "Z - 1", Box::new(|e| e.z -= 1.0));
        }
    }

    builder.build()
}

fn show_adder_button(
    mut builder: LayoutBuilder<gfx_device_gl::Resources>,
    path: &PathBuf, data: &Rc<RefCell<SharedData>>, model: &Rc<RefCell<Model>>, rc_entity: &Rc<RefCell<EntityEntry>>,
    text: &'static str, adder: Box<Fn(&mut EntityEntry)>)
 -> LayoutBuilder<gfx_device_gl::Resources>
{
    let tmp_model = model.clone();
    let tmp_data = data.clone();
    let tmp_path = path.clone();
    let tmp_entity = rc_entity.clone();
    builder = builder
        .with_widget(ButtonBuilder::new()
            .with_text(text)
            .with_callback(Box::new(move || {
                {
                    let mut entity = tmp_entity.borrow_mut();
                    adder(&mut entity);
                }

                tmp_data.borrow_mut().queued_layout = Some(generate_view(tmp_path.clone(), tmp_data.clone(), tmp_model.clone()));
            }))
            .build_boxed()
        );

    builder
}

fn display_error(text: &str) {
    let data = Rc::new(RefCell::new(SharedData { canceled: false, queued_layout: None }));
    let data_clone = data.clone();
    let layout = LayoutBuilder::<gfx_device_gl::Resources>::new()
        .with_background_color([21, 23, 24])
        .with_widget(TextBuilder::new()
            .with_text(text)
            .build_boxed())
        .with_widget(ButtonBuilder::new()
            .with_text("Ok")
            .with_callback(Box::new(move || data_clone.borrow_mut().canceled = true))
            .build_boxed())
        .build();

    data.borrow_mut().queued_layout = Some(layout);

    display_gui(data);
}

fn display_gui(data: Rc<RefCell<SharedData>>)
{
    // Set up our window
    let (mut stream, mut device, mut factory) = {
        let window = glutin::WindowBuilder::new()
            .with_vsync()
            .with_dimensions(600, 500)
            .with_title(String::from("Athena Editor"))
            .build_strict().unwrap();
        gfx_window_glutin::init(window)
    };

    let mut gui = Gui::new(&mut device, &mut factory, data.borrow_mut().queued_layout.take().unwrap());

    // Run our actual UI loop
    'main: loop {
        {
            let mut d = data.borrow_mut();

            if d.canceled {
                break 'main;
            }

            if let Some(layout) = d.queued_layout.take() {
                gui.set_root(layout);
            }
        }

        // Quit when the window is closed
        for event in stream.out.window.poll_events() {
            match event {
                glutin::Event::Closed => break 'main,
                glutin::Event::MouseMoved((x, y)) =>
                    gui.raise_event(&stream, phosphorus::Event::MouseMoved([x, y])),
                glutin::Event::MouseInput(glutin::ElementState::Released, _) =>
                    gui.raise_event(&stream, phosphorus::Event::MouseClick),
                _ => (),
            }
        }

        stream.clear(gfx::ClearData {color: [1.0, 1.0, 1.0, 1.0], depth: 1.0, stencil: 0});

        // Render our actual GUI
        gui.render(&mut factory, &mut stream);

        // Show the rendered to buffer on the screen
        //stream.present(&mut device); ICE!
        stream.flush(&mut device);
        stream.out.window.swap_buffers();
        device.cleanup();
    }
}
<|endoftext|>