<commit_before>//	MIT License
//
//  Copyright © 2017 Michael J Simms. All rights reserved.
//
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in all
//	copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//	SOFTWARE.

extern crate rand;
use rand::distributions::IndependentSample;
use std::collections::HashMap;

/// Each feature has a name and value.
pub struct Feature {
    name: String,
    value: u64,
}

impl Feature {
    pub fn new (name: &str, value: u64) -> Feature {
        Feature { name: name.to_string(), value: value }
    }
}

pub type FeatureList = Vec<Feature>;
pub type Uint64Vec = Vec<u64>;
pub type FeatureNameToValuesMap<'a> = HashMap<&'a String, Uint64Vec>;

/// This class represents a sample.
/// Each sample has a name and list of features.
pub struct Sample {
    name: String,
    features: FeatureList,
}

impl Sample {
    pub fn new (name: &str) -> Sample {
        Sample { name: name.to_string(), features: Sample::create_feature_list() }
    }

    fn create_feature_list() -> FeatureList {
        let v: FeatureList = vec![];
        v
    }

    pub fn add_features(&mut self, features: &mut FeatureList) {
        self.features.append(features);
    }

    pub fn add_feature(&mut self, feature: Feature) {
        self.features.push(feature);
    }
}

pub type SampleList = Vec<Sample>;

/// Tree node, used internally.
struct Node {
    feature_name: String,
    split_value: u64,
    left: NodeLink,
    right: NodeLink,
}

impl Node {
    pub fn new (feature_name: &str, split_value: u64) -> Node {
        Node { feature_name: feature_name.to_string(), split_value: split_value, left: None, right: None }
    }

	fn set_left_subtree(&mut self, subtree: NodeBox) {
		self.left = Some(subtree);
	}

	fn set_right_subtree(&mut self, subtree: NodeBox) {
		self.right = Some(subtree);
	}
}

type NodeBox = Box<Node>;
type NodeLink = Option<Box<Node>>;
type NodeList = Vec<Box<Node>>;

/// Isolation Forest implementation.
pub struct Forest<'a> {
    feature_values: FeatureNameToValuesMap<'a>, // Lists each feature and maps it to all unique values in the training set
    trees: NodeList, // The decision trees that comprise the forest
    num_trees_to_create: u32, // The maximum number of trees to create
    sub_sampling_size: u32, // The maximum depth of a tree
    rng: rand::ThreadRng,
}

impl<'a> Forest<'a> {
    pub fn new (num_trees_to_create: u32, sub_sampling_size: u32) -> Forest<'a> {
        Forest { num_trees_to_create: num_trees_to_create, sub_sampling_size: sub_sampling_size, trees: Forest::initialize_trees(), feature_values: Forest::create_feature_name_to_values_map(), rng: rand::thread_rng() }
    }

    fn initialize_trees() -> NodeList {
        let v: NodeList = vec![];
        v
    }

    fn create_feature_name_to_values_map() -> FeatureNameToValuesMap<'a> {
        let m = FeatureNameToValuesMap::new();
        m
    }

    pub fn add_sample(&mut self, sample: Sample) {
		// Add each of this sample's features to the list of known features
		// with the corresponding set of unique values.

        for feature in &sample.features {
            if self.feature_values.contains_key(&feature.name) {
                let mut feature_value_set = &mut self.feature_values[&feature.name];
                feature_value_set.push(feature.value);
            }
            else {
                let mut feature_value_set = Vec::new();
                feature_value_set.push(feature.value);
                self.feature_values.insert(&feature.name, feature_value_set);
            }
        }
    }

    fn create_tree(&mut self, feature_values: FeatureNameToValuesMap, depth: u32) -> NodeLink {
        // Creates and returns a single tree. As this is a recursive function, depth indicates the current depth of the recursion.

		// Sanity check.
		if feature_values.len() <= 1 {
			return None;
		}

		// If we've exceeded the maximum desired depth, then stop.
		if (self.sub_sampling_size > 0) && (depth >= self.sub_sampling_size) {
			return None;
		}

		// Randomly select a feature.
        let mut range = rand::distributions::Range::new(0.0, (feature_values.len() as f32) - 1.0);
		let selected_feature_index = range.ind_sample(&mut self.rng) as usize;
        let selected_feature_name = feature_values.keys().nth(selected_feature_index);
        match selected_feature_name {
            None => {
                return None;
            }
            Some(ref name) => {
        		// Randomly select a split value.
                let feature_value_set = &feature_values[*name];
                range = rand::distributions::Range::new(0.0, (feature_value_set.len() - 1) as f32);
                let split_value_index = range.ind_sample(&mut self.rng) as usize;
                let split_value = feature_value_set[split_value_index];

                // Create a tree node to hold the split value.
                let mut tree_root = Node::new(name, split_value);

                // Create two versions of the feature value set that we just used,
                // one for the left side of the tree and one for the right.
                let mut temp_feature_values = feature_values.clone();
                let (left_features, right_features) = feature_value_set.split_at(split_value_index);

                // Create the left subtree.
                temp_feature_values.insert(name, left_features.to_vec());
                tree_root.left = self.create_tree(temp_feature_values, depth + 1);

                // Create the right subtree.
                temp_feature_values.insert(name, right_features.to_vec());
                tree_root.right = self.create_tree(temp_feature_values, depth + 1);

                let tree = Some(Box::new(tree_root));
                tree
            }
        }
    }

    pub fn create(&mut self) {
        // Creates a forest containing the number of trees specified to the constructor.

    	for _i in 0..self.num_trees_to_create {
            let temp_feature_values = self.feature_values.clone();
            let tree = self.create_tree(temp_feature_values, 0);
            match tree {
                None => {
                }
                Some(ref new_tree) => {
                    self.trees.push(*new_tree);
                }
            }
        }
    }

    fn score_tree(&self, sample: &Sample, tree: &NodeBox) -> f64 {
        // Scores the sample against the specified tree.

        let mut depth = 0.0;
        let mut current_node = tree;
        let mut done = false;

        while !done {
            let mut found_feature = false;

            for feature in &sample.features {
                if feature.name == current_node.feature_name {
					if feature.value < current_node.split_value {
                        match current_node.left {
                            None => {
                                done = true;
                            }
                            Some(ref next_node) => {
                                current_node = next_node;
                            }
                        }
                    } else {
                        match current_node.right {
                            None => {
                                done = true;
                            }
                            Some(ref next_node) => {
                                current_node = next_node;
                            }
                        }
                    }

                    depth = depth + 1.0;
                    found_feature = true;
                }
            }

			// If the tree contained a feature not in the sample then take
			// both sides of the tree and average the scores together.
			if found_feature == false {
                let left_tree = &current_node.left;
                let right_tree = &current_node.right;
                let mut left_depth = depth;
                let mut right_depth = depth;

                match left_tree {
                    &None => {
                    }
                    &Some(ref left_tree) => {
        			    left_depth = left_depth + self.score_tree(sample, left_tree);
                    }
                }
                match right_tree {
                    &None => {
                    }
                    &Some(ref right_tree) => {
        			    right_depth = right_depth + self.score_tree(sample, right_tree);
                    }
                }
				return (left_depth + right_depth) / 2.0;
            }
        }
        depth
    }

    pub fn score(&self, sample: &Sample) -> f64 {
        // Scores the sample against the entire forest of trees.

        let mut score = 0.0;

        if self.trees.len() > 0 {
            for tree in &self.trees {
                score += self.score_tree(sample, tree);
            }
            score /= self.trees.len() as f64;
        }
        score
    }
}
<commit_msg>Backup commit. Now building.<commit_after>//	MIT License
//
//  Copyright © 2017 Michael J Simms. All rights reserved.
//
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in all
//	copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//	SOFTWARE.

extern crate rand;
use rand::distributions::IndependentSample;
use std::collections::HashMap;

/// Each feature has a name and value.
pub struct Feature {
    name: String,
    value: u64,
}

impl Feature {
    pub fn new (name: &str, value: u64) -> Feature {
        Feature { name: name.to_string(), value: value }
    }
}

pub type FeatureList = Vec<Feature>;
pub type Uint64Vec = Vec<u64>;
pub type FeatureNameToValuesMap = HashMap<String, Uint64Vec>;

/// This class represents a sample.
/// Each sample has a name and list of features.
pub struct Sample {
    name: String,
    features: FeatureList,
}

impl Sample {
    pub fn new (name: &str) -> Sample {
        Sample { name: name.to_string(), features: Sample::create_feature_list() }
    }

    fn create_feature_list() -> FeatureList {
        let v: FeatureList = vec![];
        v
    }

    pub fn add_features(&mut self, features: &mut FeatureList) {
        self.features.append(features);
    }

    pub fn add_feature(&mut self, feature: Feature) {
        self.features.push(feature);
    }
}

/// Tree node, used internally.
struct Node {
    feature_name: String,
    split_value: u64,
    left: NodeLink,
    right: NodeLink,
}

impl Node {
    pub fn new (feature_name: &str, split_value: u64) -> Node {
        Node { feature_name: feature_name.to_string(), split_value: split_value, left: None, right: None }
    }
}

type NodeBox = Box<Node>;
type NodeLink = Option<Box<Node>>;
type NodeList = Vec<Box<Node>>;

/// Isolation Forest implementation.
pub struct Forest {
    feature_values: FeatureNameToValuesMap, // Lists each feature and maps it to all unique values in the training set
    trees: NodeList, // The decision trees that comprise the forest
    num_trees_to_create: u32, // The maximum number of trees to create
    sub_sampling_size: u32, // The maximum depth of a tree
    rng: rand::ThreadRng,
}

impl Forest {
    pub fn new (num_trees_to_create: u32, sub_sampling_size: u32) -> Forest {
        Forest { num_trees_to_create: num_trees_to_create, sub_sampling_size: sub_sampling_size, trees: Forest::initialize_trees(), feature_values: Forest::create_feature_name_to_values_map(), rng: rand::thread_rng() }
    }

    fn initialize_trees() -> NodeList {
        let v: NodeList = vec![];
        v
    }

    fn create_feature_name_to_values_map() -> FeatureNameToValuesMap {
        let m = FeatureNameToValuesMap::new();
        m
    }

    pub fn add_sample(&mut self, sample: Sample) {
		// Add each of this sample's features to the list of known features
		// with the corresponding set of unique values.

        for feature in &sample.features {
            if self.feature_values.contains_key(&feature.name) {
                let mut feature_value_set = self.feature_values[&feature.name].clone();
                feature_value_set.push(feature.value);
            }
            else {
                let mut feature_value_set = Vec::new();
                feature_value_set.push(feature.value);
                self.feature_values.insert(feature.name.clone(), feature_value_set);
            }
        }
    }

    fn create_tree(&mut self, feature_values: FeatureNameToValuesMap, depth: u32) -> NodeLink {
        // Creates and returns a single tree. As this is a recursive function, depth indicates the current depth of the recursion.

		// Sanity check.
		if feature_values.len() <= 1 {
			return None;
		}

		// If we've exceeded the maximum desired depth, then stop.
		if (self.sub_sampling_size > 0) && (depth >= self.sub_sampling_size) {
			return None;
		}

		// Randomly select a feature.
        let mut range = rand::distributions::Range::new(0.0, (feature_values.len() as f32) - 1.0);
		let selected_feature_index = range.ind_sample(&mut self.rng) as usize;
        let selected_feature_name = feature_values.keys().nth(selected_feature_index);
        match selected_feature_name {
            None => {
                return None;
            }
            Some(ref name) => {
        		// Randomly select a split value.
                let feature_value_set = &feature_values[*name];
                range = rand::distributions::Range::new(0.0, (feature_value_set.len() - 1) as f32);
                let split_value_index = range.ind_sample(&mut self.rng) as usize;
                let split_value = feature_value_set[split_value_index];

                // Create a tree node to hold the split value.
                let mut tree_root = Node::new(name, split_value);

                // Create two versions of the feature value set that we just used,
                // one for the left side of the tree and one for the right.
                let mut temp_feature_values = feature_values.clone();
                let (left_features, right_features) = feature_value_set.split_at(split_value_index);

                // Create the left subtree.
                temp_feature_values.insert(name.to_string(), left_features.to_vec());
                tree_root.left = self.create_tree(temp_feature_values.clone(), depth + 1);

                // Create the right subtree.
                temp_feature_values.insert(name.to_string(), right_features.to_vec());
                tree_root.right = self.create_tree(temp_feature_values, depth + 1);

                let tree = Some(Box::new(tree_root));
                tree
            }
        }
    }

    pub fn create(&mut self) {
        // Creates a forest containing the number of trees specified to the constructor.

    	for _i in 0..self.num_trees_to_create {
            let temp_feature_values = self.feature_values.clone();
            let tree = self.create_tree(temp_feature_values, 0);
            self.trees.push(tree.unwrap());
        }
    }

    fn score_tree(&self, sample: &Sample, tree: &NodeBox) -> f64 {
        // Scores the sample against the specified tree.

        let mut depth = 0.0;
        let mut current_node = tree;
        let mut done = false;

        while !done {
            let mut found_feature = false;

            for feature in &sample.features {
                if feature.name == current_node.feature_name {
					if feature.value < current_node.split_value {
                        match current_node.left {
                            None => {
                                done = true;
                            }
                            Some(ref next_node) => {
                                current_node = next_node;
                            }
                        }
                    } else {
                        match current_node.right {
                            None => {
                                done = true;
                            }
                            Some(ref next_node) => {
                                current_node = next_node;
                            }
                        }
                    }

                    depth = depth + 1.0;
                    found_feature = true;
                }
            }

			// If the tree contained a feature not in the sample then take
			// both sides of the tree and average the scores together.
			if found_feature == false {
                let left_tree = &current_node.left;
                let right_tree = &current_node.right;
                let mut left_depth = depth;
                let mut right_depth = depth;

                match left_tree {
                    &None => {
                    }
                    &Some(ref left_tree) => {
        			    left_depth = left_depth + self.score_tree(sample, left_tree);
                    }
                }
                match right_tree {
                    &None => {
                    }
                    &Some(ref right_tree) => {
        			    right_depth = right_depth + self.score_tree(sample, right_tree);
                    }
                }
				return (left_depth + right_depth) / 2.0;
            }
        }
        depth
    }

    pub fn score(&self, sample: &Sample) -> f64 {
        // Scores the sample against the entire forest of trees.

        let mut score = 0.0;

        if self.trees.len() > 0 {
            for tree in &self.trees {
                score += self.score_tree(sample, tree);
            }
            score /= self.trees.len() as f64;
        }
        score
    }
}
<|endoftext|>


<commit_before>use sdl2;
use sdl2::EventPump;
use sdl2::event::Event;
use sdl2::render::Renderer;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::image::LoadTexture;
use sdl2::render::Texture as SdlTexture;
use sdl2::mixer;
use OptionLoaned;
use input_private;
use input::Input;
use input_private::input;
use game_object::GameObject;
use component::Message;
use game_object;
use graphics::Texture;
use graphics_private::texture;
use graphics::Sprite;
use graphics_private::sprite_sheet;
use math::PolarCoords;
use math::Vector;
use math::IntVector;
use math_private::int_vector::IntVecConvert;
use audio::Audio;
use audio_private::audio;
use audio_private::playlist;
use math::Transform;
use graphics::Canvas;
use camera::Camera;
use nphysics2d::world::World;
use nphysics2d::math::Translation;
use nalgebra::geometry::UnitComplex;
use std::sync::Arc;
use std::mem::replace;
use std::collections::HashMap;
use std::borrow::Borrow;
use std::path::PathBuf;
use std::f32;
use std::time::Instant;
use chrono::Duration;

/// This structure represents a game instance.
///
/// This structure is responsible for managing asset loading,
/// processing input, rendering the game and playing audio.
pub struct App {
    exit: bool,
    renderer: Renderer<'static>,
    event_pump: EventPump,
    game_objects: HashMap<u64, Option<Box<GameObject>>>,
    texture_cache: HashMap<String, Arc<SdlTexture>>,
    next_game_object_id: u64,
    pub input: Input,
    pub camera: Camera,
    pub world: World<f32>,
    pub audio: Audio,
}

impl App {
    ///Constructs a new App using the given name for the window title.
    pub fn new(name: &str) -> App {
        let sdl_context = sdl2::init().expect("Failed to initialize SDL2.");
        let video_subsystem = sdl_context.video().expect("Failed to initialize video subsystem");
        let window = video_subsystem.window(name, 800, 600)
            .position_centered()
            .fullscreen_desktop()
            .opengl()
            .build()
            .unwrap();
        let renderer = window.renderer().build().expect("Failed to initialize renderer");
        let audio = sdl_context.audio().expect("Failed to initialize audio");
        let mixer = mixer::init(mixer::INIT_OGG).expect("Failed to initialize mixer");
        mixer::open_audio(mixer::DEFAULT_FREQUENCY, mixer::DEFAULT_FORMAT, 2, 1024)
            .expect("Failed to open audio");
        mixer::allocate_channels(256);
        mixer::reserve_channels(128);
        let input = input::new(sdl_context.mouse());
        App {
            exit: false,
            next_game_object_id: 0,
            game_objects: HashMap::new(),
            input: input,
            renderer: renderer,
            texture_cache: HashMap::new(),
            audio: audio::new(audio, mixer),
            event_pump: sdl_context.event_pump().expect("Failed to initalize event pump."),
            camera: Camera { transform: Transform::new(Vector::new(0.0, 0.0), 0.0) },
            world: World::new(),
        }
    }

    /// Called every frame to paint the scene. Do not put game logic here, that goes in update.
    fn render(&mut self) {
        use std::f32;
        let game_objs = &self.game_objects;
        let camera_transform = self.camera.transform;
        // Clear the screen with grey.
        self.renderer.set_draw_color(Color::RGB(0, 0, 0));
        self.renderer.clear();
        let (screen_width, screen_height) = self.renderer
            .window()
            .unwrap()
            .size();
        for game_obj in game_objs.values() {
            if let Some(ref game_obj) = *game_obj {
                if let Some(ref sprite) = game_obj.sprite {
                    let mut render_transform = game_obj.transform;
                    render_transform.translation.vector.x -= camera_transform.translation.vector.x;
                    render_transform.translation.vector.y -= camera_transform.translation.vector.y;
                    let mut polar = PolarCoords::from(render_transform.translation.vector.clone());
                    polar.rotation -= camera_transform.rotation.angle();
                    render_transform.translation = Translation::from_vector(Vector::from(polar));
                    render_transform.translation.vector.x += (screen_width / 2) as f32;
                    render_transform.translation.vector.y += (screen_height / 2) as f32;
                    render_transform.rotation = UnitComplex::from_angle(render_transform.rotation.angle() - camera_transform.rotation.angle());
                    match *sprite {
                        Sprite::Texture(ref texture) => {
                            let (tex_width, tex_height) = texture::size(texture);
                            let render_rect = Rect::new((render_transform.translation.vector.x as i32) -
                                                        (tex_width as i32 / 2),
                                                        (render_transform.translation.vector.y as i32) -
                                                        (tex_height as i32 / 2),
                                                        tex_width,
                                                        tex_height);
                            let result = self.renderer.copy_ex(texture::get_raw(texture),
                                                               None,
                                                               Some(render_rect),
                                                               (game_obj.transform.rotation.angle() *
                                                                180.0 /
                                                                f32::consts::PI) as
                                                               f64,
                                                               None,
                                                               texture.flip_horizontal,
                                                               texture.flip_vertical);
                            if let Err(err) = result {
                                println!("Unable to draw texture, Error: {:?}", err);
                            }
                        }
                        Sprite::SpriteSheet(ref sprite_sheet) => {
                            let ref current_frame = sprite_sheet.animations[sprite_sheet.current_animation as
                            usize]
                                [sprite_sheet.current_frame as usize];
                            let result = self.renderer
                                .copy_ex(sprite_sheet::get_texture(sprite_sheet),
                                         Some(Rect::from(current_frame.frame_rect)),
                                         Some(Rect::new((render_transform.translation.vector.x as i32) -
                                                        (current_frame.frame_rect.width() as i32 /
                                                         2),
                                                        (render_transform.translation.vector.y as i32) -
                                                        (current_frame.frame_rect.height() as i32 /
                                                         2),
                                                        current_frame.frame_rect.width(),
                                                        current_frame.frame_rect.height())),
                                         (game_obj.transform.rotation.angle() * 180.0 /
                                          f32::consts::PI) as
                                         f64,
                                         None,
                                         current_frame.flip_horizontal,
                                         current_frame.flip_vertical);
                            if let Err(err) = result {
                                println!("Unable to draw texture, Error: {:?}", err);
                            }
                        }
                    }
                }
            }
        }
        {
            let mut canvas = Canvas::new(&mut self.renderer);
            for game_obj in game_objs.values() {
                if let Some(ref game_obj) = *game_obj {
                    for key in game_obj.component_keys() {
                        if let OptionLoaned::Some(component) = game_obj.component(key) {
                            component.render_gui(&mut canvas, game_obj);
                        }
                    }
                }
            }
        }
        self.renderer.present();
    }

    /// Called every frame to simulate the game. Do not put rendering here, that goes in render.
    fn update(&mut self, delta_time: f32) {
        // Advance audio if necessary.
        playlist::advance_if_needed(&mut self.audio.playlist);
        //Copy game_object to the physics world, step, then copy from physics to game_object
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_to_physics(game_object);
            }
        }
        self.world.step(delta_time);
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_from_physics(game_object);
            }
        }

        //Send update messages
        let keys = self.game_objects
            .keys()
            .map(|x| *x)
            .collect::<Vec<u64>>();
        for key in keys {
            let mut game_obj_option = None;
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                game_obj_option = replace(game_obj_ref, None);
            }
            if let Some(ref mut game_obj) = game_obj_option {
                game_obj.update(self, delta_time);
            }
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                replace(game_obj_ref, game_obj_option);
            }
        }

        // Drop any game objects that need to be dropped.
        let mut dropped_keys = Vec::new();
        for (key, game_obj) in self.game_objects.iter() {
            if let Some(ref game_obj) = *game_obj {
                if game_object::was_dropped(game_obj.borrow()) {
                    dropped_keys.push(*key);
                }
            } else {
                dropped_keys.push(*key);
            }
        }
        for key in dropped_keys {
            let removed = self.game_objects.remove(&key);
            if let Some(Some(mut game_obj)) = removed {
                game_obj.receive_message(self, &Message::OnDestroy);
            }
        }

        input_private::input::shift_frame(&mut self.input);
    }

    /// Begin execution of the game.
    ///
    /// This function won't return until the game has been quit.
    pub fn run(&mut self) {
        let mut last_frame_instant = Instant::now();
        while !self.exit {
            while let Some(e) = self.event_pump.poll_event() {
                if let Event::Quit { .. } = e {
                    self.exit = true;
                }
                input_private::input::process_event(&mut self.input, &e);
            }
            self.update(Duration::from_std(last_frame_instant.elapsed())
                            .unwrap()
                            .num_microseconds()
                            .unwrap() as f32 / 1000000.0);
            last_frame_instant = Instant::now();
            self.render();
        }
    }

    /// Exit the game
    ///
    /// Signals that it's time to quit. Execution will stop at the end of the current frame.
    pub fn quit(&mut self) {
        self.exit = true;
    }

    pub fn camera(&self) -> &Camera {
        &self.camera
    }

    pub fn camera_mut(&mut self) -> &mut Camera {
        &mut self.camera
    }

    pub fn world_mouse_pos(&self) -> Vector {
         let (screen_width, screen_height) = self.renderer
            .window()
            .unwrap()
            .size();
        let mut mouse_relative_pos = PolarCoords::from((self.input.mouse.pos() - IntVector::new((screen_width / 2) as i32, (screen_height / 2) as i32)).to_vec());
        mouse_relative_pos.rotation += self.camera.transform.rotation.angle();
        self.camera.transform.translation.vector + Vector::from(mouse_relative_pos)
    }

    /// Creates a new GameObject
    ///
    /// GameObjects are typically physical objects in your game world, such as characters or
    /// decorative objects.
    ///
    /// Parameter f will be called on the newly created GameObject, allowing you to initialize it.
    /// Returns the id of the new GameObject, which can be used to retrieve this GameObject later.
    pub fn new_gameobject<F>(&mut self, f: F) -> u64
        where F: FnOnce(&mut App, &mut GameObject)
    {
        let mut game_object = Box::new(game_object::new(self));
        f(self, &mut game_object);
        let id = game_object.id();
        self.game_objects.insert(id, Some(game_object));
        id
    }

    /// Retrieves a reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id(&self, id: u64) -> OptionLoaned<&GameObject> {
        OptionLoaned::from(self.game_objects.get(&id))
    }

    /// Retrieves a mutable reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id_mut(&mut self, id: u64) -> OptionLoaned<&mut GameObject> {
        OptionLoaned::from(self.game_objects.get_mut(&id))
    }

    /// Loads a texture and returns it for use.
    ///
    /// texture_name is the file name of the texture relative to assets/textures
    /// (assets\textures on Windows)
    pub fn fetch_texture(&mut self, texture_name: &str) -> Result<Texture, String> {
        if let Some(sdl_texture) = self.texture_cache.get(texture_name) {
            return Ok(texture::new(sdl_texture.clone()));
        }
        let mut texture_path = PathBuf::from("assets");
        texture_path.push("textures");
        texture_path.push(texture_name);
        let sdl_texture = self.renderer.load_texture(texture_path.as_path())?;
        let sdl_texture = Arc::new(sdl_texture);
        self.texture_cache.insert(texture_name.to_string(), sdl_texture.clone());
        Ok(texture::new(sdl_texture))
    }
}

// This function will never return 0.  0 can now be used as a null value.
pub fn next_game_object_id(app: &mut App) -> u64 {
    app.next_game_object_id += 1;
    app.next_game_object_id
}
<commit_msg>Remove incorrect comment<commit_after>use sdl2;
use sdl2::EventPump;
use sdl2::event::Event;
use sdl2::render::Renderer;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::image::LoadTexture;
use sdl2::render::Texture as SdlTexture;
use sdl2::mixer;
use OptionLoaned;
use input_private;
use input::Input;
use input_private::input;
use game_object::GameObject;
use component::Message;
use game_object;
use graphics::Texture;
use graphics_private::texture;
use graphics::Sprite;
use graphics_private::sprite_sheet;
use math::PolarCoords;
use math::Vector;
use math::IntVector;
use math_private::int_vector::IntVecConvert;
use audio::Audio;
use audio_private::audio;
use audio_private::playlist;
use math::Transform;
use graphics::Canvas;
use camera::Camera;
use nphysics2d::world::World;
use nphysics2d::math::Translation;
use nalgebra::geometry::UnitComplex;
use std::sync::Arc;
use std::mem::replace;
use std::collections::HashMap;
use std::borrow::Borrow;
use std::path::PathBuf;
use std::f32;
use std::time::Instant;
use chrono::Duration;

/// This structure represents a game instance.
///
/// This structure is responsible for managing asset loading,
/// processing input, rendering the game and playing audio.
pub struct App {
    exit: bool,
    renderer: Renderer<'static>,
    event_pump: EventPump,
    game_objects: HashMap<u64, Option<Box<GameObject>>>,
    texture_cache: HashMap<String, Arc<SdlTexture>>,
    next_game_object_id: u64,
    pub input: Input,
    pub camera: Camera,
    pub world: World<f32>,
    pub audio: Audio,
}

impl App {
    ///Constructs a new App using the given name for the window title.
    pub fn new(name: &str) -> App {
        let sdl_context = sdl2::init().expect("Failed to initialize SDL2.");
        let video_subsystem = sdl_context.video().expect("Failed to initialize video subsystem");
        let window = video_subsystem.window(name, 800, 600)
            .position_centered()
            .fullscreen_desktop()
            .opengl()
            .build()
            .unwrap();
        let renderer = window.renderer().build().expect("Failed to initialize renderer");
        let audio = sdl_context.audio().expect("Failed to initialize audio");
        let mixer = mixer::init(mixer::INIT_OGG).expect("Failed to initialize mixer");
        mixer::open_audio(mixer::DEFAULT_FREQUENCY, mixer::DEFAULT_FORMAT, 2, 1024)
            .expect("Failed to open audio");
        mixer::allocate_channels(256);
        mixer::reserve_channels(128);
        let input = input::new(sdl_context.mouse());
        App {
            exit: false,
            next_game_object_id: 0,
            game_objects: HashMap::new(),
            input: input,
            renderer: renderer,
            texture_cache: HashMap::new(),
            audio: audio::new(audio, mixer),
            event_pump: sdl_context.event_pump().expect("Failed to initalize event pump."),
            camera: Camera { transform: Transform::new(Vector::new(0.0, 0.0), 0.0) },
            world: World::new(),
        }
    }

    /// Called every frame to paint the scene. Do not put game logic here, that goes in update.
    fn render(&mut self) {
        use std::f32;
        let game_objs = &self.game_objects;
        let camera_transform = self.camera.transform;
        self.renderer.set_draw_color(Color::RGB(0, 0, 0));
        self.renderer.clear();
        let (screen_width, screen_height) = self.renderer
            .window()
            .unwrap()
            .size();
        for game_obj in game_objs.values() {
            if let Some(ref game_obj) = *game_obj {
                if let Some(ref sprite) = game_obj.sprite {
                    let mut render_transform = game_obj.transform;
                    render_transform.translation.vector.x -= camera_transform.translation.vector.x;
                    render_transform.translation.vector.y -= camera_transform.translation.vector.y;
                    let mut polar = PolarCoords::from(render_transform.translation.vector.clone());
                    polar.rotation -= camera_transform.rotation.angle();
                    render_transform.translation = Translation::from_vector(Vector::from(polar));
                    render_transform.translation.vector.x += (screen_width / 2) as f32;
                    render_transform.translation.vector.y += (screen_height / 2) as f32;
                    render_transform.rotation = UnitComplex::from_angle(render_transform.rotation.angle() - camera_transform.rotation.angle());
                    match *sprite {
                        Sprite::Texture(ref texture) => {
                            let (tex_width, tex_height) = texture::size(texture);
                            let render_rect = Rect::new((render_transform.translation.vector.x as i32) -
                                                        (tex_width as i32 / 2),
                                                        (render_transform.translation.vector.y as i32) -
                                                        (tex_height as i32 / 2),
                                                        tex_width,
                                                        tex_height);
                            let result = self.renderer.copy_ex(texture::get_raw(texture),
                                                               None,
                                                               Some(render_rect),
                                                               (game_obj.transform.rotation.angle() *
                                                                180.0 /
                                                                f32::consts::PI) as
                                                               f64,
                                                               None,
                                                               texture.flip_horizontal,
                                                               texture.flip_vertical);
                            if let Err(err) = result {
                                println!("Unable to draw texture, Error: {:?}", err);
                            }
                        }
                        Sprite::SpriteSheet(ref sprite_sheet) => {
                            let ref current_frame = sprite_sheet.animations[sprite_sheet.current_animation as
                            usize]
                                [sprite_sheet.current_frame as usize];
                            let result = self.renderer
                                .copy_ex(sprite_sheet::get_texture(sprite_sheet),
                                         Some(Rect::from(current_frame.frame_rect)),
                                         Some(Rect::new((render_transform.translation.vector.x as i32) -
                                                        (current_frame.frame_rect.width() as i32 /
                                                         2),
                                                        (render_transform.translation.vector.y as i32) -
                                                        (current_frame.frame_rect.height() as i32 /
                                                         2),
                                                        current_frame.frame_rect.width(),
                                                        current_frame.frame_rect.height())),
                                         (game_obj.transform.rotation.angle() * 180.0 /
                                          f32::consts::PI) as
                                         f64,
                                         None,
                                         current_frame.flip_horizontal,
                                         current_frame.flip_vertical);
                            if let Err(err) = result {
                                println!("Unable to draw texture, Error: {:?}", err);
                            }
                        }
                    }
                }
            }
        }
        {
            let mut canvas = Canvas::new(&mut self.renderer);
            for game_obj in game_objs.values() {
                if let Some(ref game_obj) = *game_obj {
                    for key in game_obj.component_keys() {
                        if let OptionLoaned::Some(component) = game_obj.component(key) {
                            component.render_gui(&mut canvas, game_obj);
                        }
                    }
                }
            }
        }
        self.renderer.present();
    }

    /// Called every frame to simulate the game. Do not put rendering here, that goes in render.
    fn update(&mut self, delta_time: f32) {
        // Advance audio if necessary.
        playlist::advance_if_needed(&mut self.audio.playlist);
        //Copy game_object to the physics world, step, then copy from physics to game_object
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_to_physics(game_object);
            }
        }
        self.world.step(delta_time);
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_from_physics(game_object);
            }
        }

        //Send update messages
        let keys = self.game_objects
            .keys()
            .map(|x| *x)
            .collect::<Vec<u64>>();
        for key in keys {
            let mut game_obj_option = None;
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                game_obj_option = replace(game_obj_ref, None);
            }
            if let Some(ref mut game_obj) = game_obj_option {
                game_obj.update(self, delta_time);
            }
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                replace(game_obj_ref, game_obj_option);
            }
        }

        // Drop any game objects that need to be dropped.
        let mut dropped_keys = Vec::new();
        for (key, game_obj) in self.game_objects.iter() {
            if let Some(ref game_obj) = *game_obj {
                if game_object::was_dropped(game_obj.borrow()) {
                    dropped_keys.push(*key);
                }
            } else {
                dropped_keys.push(*key);
            }
        }
        for key in dropped_keys {
            let removed = self.game_objects.remove(&key);
            if let Some(Some(mut game_obj)) = removed {
                game_obj.receive_message(self, &Message::OnDestroy);
            }
        }

        input_private::input::shift_frame(&mut self.input);
    }

    /// Begin execution of the game.
    ///
    /// This function won't return until the game has been quit.
    pub fn run(&mut self) {
        let mut last_frame_instant = Instant::now();
        while !self.exit {
            while let Some(e) = self.event_pump.poll_event() {
                if let Event::Quit { .. } = e {
                    self.exit = true;
                }
                input_private::input::process_event(&mut self.input, &e);
            }
            self.update(Duration::from_std(last_frame_instant.elapsed())
                            .unwrap()
                            .num_microseconds()
                            .unwrap() as f32 / 1000000.0);
            last_frame_instant = Instant::now();
            self.render();
        }
    }

    /// Exit the game
    ///
    /// Signals that it's time to quit. Execution will stop at the end of the current frame.
    pub fn quit(&mut self) {
        self.exit = true;
    }

    pub fn camera(&self) -> &Camera {
        &self.camera
    }

    pub fn camera_mut(&mut self) -> &mut Camera {
        &mut self.camera
    }

    pub fn world_mouse_pos(&self) -> Vector {
         let (screen_width, screen_height) = self.renderer
            .window()
            .unwrap()
            .size();
        let mut mouse_relative_pos = PolarCoords::from((self.input.mouse.pos() - IntVector::new((screen_width / 2) as i32, (screen_height / 2) as i32)).to_vec());
        mouse_relative_pos.rotation += self.camera.transform.rotation.angle();
        self.camera.transform.translation.vector + Vector::from(mouse_relative_pos)
    }

    /// Creates a new GameObject
    ///
    /// GameObjects are typically physical objects in your game world, such as characters or
    /// decorative objects.
    ///
    /// Parameter f will be called on the newly created GameObject, allowing you to initialize it.
    /// Returns the id of the new GameObject, which can be used to retrieve this GameObject later.
    pub fn new_gameobject<F>(&mut self, f: F) -> u64
        where F: FnOnce(&mut App, &mut GameObject)
    {
        let mut game_object = Box::new(game_object::new(self));
        f(self, &mut game_object);
        let id = game_object.id();
        self.game_objects.insert(id, Some(game_object));
        id
    }

    /// Retrieves a reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id(&self, id: u64) -> OptionLoaned<&GameObject> {
        OptionLoaned::from(self.game_objects.get(&id))
    }

    /// Retrieves a mutable reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id_mut(&mut self, id: u64) -> OptionLoaned<&mut GameObject> {
        OptionLoaned::from(self.game_objects.get_mut(&id))
    }

    /// Loads a texture and returns it for use.
    ///
    /// texture_name is the file name of the texture relative to assets/textures
    /// (assets\textures on Windows)
    pub fn fetch_texture(&mut self, texture_name: &str) -> Result<Texture, String> {
        if let Some(sdl_texture) = self.texture_cache.get(texture_name) {
            return Ok(texture::new(sdl_texture.clone()));
        }
        let mut texture_path = PathBuf::from("assets");
        texture_path.push("textures");
        texture_path.push(texture_name);
        let sdl_texture = self.renderer.load_texture(texture_path.as_path())?;
        let sdl_texture = Arc::new(sdl_texture);
        self.texture_cache.insert(texture_name.to_string(), sdl_texture.clone());
        Ok(texture::new(sdl_texture))
    }
}

// This function will never return 0.  0 can now be used as a null value.
pub fn next_game_object_id(app: &mut App) -> u64 {
    app.next_game_object_id += 1;
    app.next_game_object_id
}
<|endoftext|>


<commit_before>use std::io::{BufWriter, Reader};
use std::num::Float;
use error::Ch8Error;
use ops::{Op, Instruction};
use std::slice::Chunks;

use std::rand::Rng;
use std::rand;

const RAM_SIZE: usize = 4096;
const PROGRAM_START: usize = 0x200;

const FONT_ADDR: usize = 0;
const FONT_HEIGHT: usize = 5;
const FONT_BYTES: usize = FONT_HEIGHT * 16;
const FONT: [u8; FONT_BYTES] = [
	0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
	0x20, 0x60, 0x20, 0x20, 0x70, // 1
	0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
	0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
	0x90, 0x90, 0xF0, 0x10, 0x10, // 4
	0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
	0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
	0xF0, 0x10, 0x20, 0x40, 0x40, // 7
	0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
	0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
	0xF0, 0x90, 0xF0, 0x90, 0x90, // A
	0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
	0xF0, 0x80, 0x80, 0x80, 0xF0, // C
	0xE0, 0x90, 0x90, 0x90, 0xE0, // D
	0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
	0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

pub struct Vm {
    reg: [u8; 16],
    i: usize,
    pc: usize,
    sp: usize,
    stack: [usize; 256],
    ram: [u8; RAM_SIZE],

    timer: u8,
    t_tick: f32,

    sound_timer: u8,
    st_tick: f32,

    screen: [u8; 64 * 32],
    keys: [u8; 16],
}

impl Vm {
    pub fn new() -> Vm {
        let mut vm = Vm {
            reg: [0; 16],
            i: 0,
            pc: PROGRAM_START,
            sp: 0,
            stack: [0; 256],
            ram: [0; RAM_SIZE],

            timer: 0,
            t_tick: 0.0,

            sound_timer: 0,
            st_tick: 0.0,

            screen: [0; 64 * 32],
            keys: [0; 16],
        };
        {
            let mut ram = BufWriter::new(&mut vm.ram[FONT_ADDR..(FONT_ADDR + FONT_BYTES)]);
            ram.write(FONT.as_slice());
        }
        vm
    }

    pub fn load_rom(&mut self, reader: &mut Reader) -> Result<usize, Ch8Error> {
        let rom = try!(reader.read_to_end());
        if rom.len() > (RAM_SIZE - PROGRAM_START) {
           return Err(Ch8Error::Io("Rom was larger than available RAM", None))
        }
        let mut ram = BufWriter::new(&mut self.ram[PROGRAM_START..RAM_SIZE]);
        try!(ram.write(rom.as_slice()));
        return Ok(rom.len());
    }

    pub fn dump_ram(&self, writer: &mut Writer) {
        writer.write(&self.ram).unwrap();
    }

    pub fn set_key(&mut self, idx: u8) {
        self.keys[idx as usize] = 1;
    }

    pub fn unset_key(&mut self, idx: u8) {
        self.keys[idx as usize] = 0;
    }

    fn exec(&mut self, op: &Op) -> bool {
        use ops::Instruction::*;
        let ins = Instruction::from_op(op);
//        if self.timer == 0 {
//            println!("Executing instruction: 0x{:X} {:?}", self.pc, ins);
//            println!("v: {:?}", self.reg);
//            println!("timers: t: {} s: {}", self.timer, self.sound_timer);
//            self.print_screen();
//        }
        match ins {
            // Sys(addr) intentionally left unimplemented.
            Clear => {
                for b in self.screen.iter_mut() {
                    *b = 0;
                }
            },
            Return => {
                self.pc = self.stack[self.sp];
                self.sp-=1;
            },
            Jump(addr) => {
                let idle = self.pc-2 == addr as usize;
                self.pc = addr as usize;
                if idle { return true; }
            }
            Call(addr) => {
                self.sp+=1;
                self.stack[self.sp] = self.pc;
                self.pc = addr as usize;
            },
            SkipEqualK(vx, k) => {
                if self.reg[vx as usize] == k {
                    self.pc += 2;
                }
            },
            SkipNotEqualK(vx, k) => {
                if self.reg[vx as usize] != k {
                    self.pc += 2;
                }
            },
            SkipEqual(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];
                if x == y {
                    self.pc += 2;
                }
            },
            SetK(vx, byte) => {
                self.reg[vx as usize] = byte;
            },
            AddK(vx, byte) => {
                self.reg[vx as usize] += byte;
            },
            Set(vx, vy) => self.reg[vx as usize] = self.reg[vy as usize],
            Or(vx, vy)  => self.reg[vx as usize] |= self.reg[vy as usize],
            And(vx, vy) => self.reg[vx as usize] &= self.reg[vy as usize],
            XOr(vx, vy) => self.reg[vx as usize] ^= self.reg[vy as usize],
            Add(vx, vy) => {
                let x = self.reg[vx as usize] as u16;
                let y = self.reg[vy as usize] as u16;
                let res = x + y;

                // VF is carryover
                self.reg[15] = (res > 255) as u8;

                self.reg[vx as usize] = res as u8;
            },
            Sub(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];

                // VF is Not Borrow i.e. x > y
                self.reg[15] = (x > y) as u8;

                self.reg[vx as usize] = x - y;
            },
            ShiftRight(vx, vy) => {
                let y = self.reg[vy as usize];

                // VF is lsb before shift
                self.reg[15] = 0x1 & y;

                self.reg[vx as usize] = y >> 1;
            },
            SubInv(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];

                // VF is Not Borrow i.e. y > x
                self.reg[15] = (y > x) as u8;

                self.reg[vx as usize] = y - x;
            },
            ShiftLeft(vx, vy) => {
                let y = self.reg[vy as usize];

                // VF is msb before shift
                self.reg[15] =  0x80 & y;

                self.reg[vx as usize] = y << 1;
            }
            SkipNotEqual(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];
                if x != y {
                    self.pc += 2;
                }
            },
            LoadI(addr) => {
                self.i = addr as usize;
            },
            LongJump(addr) => {
                self.pc = (self.reg[0] as u16 + addr) as usize;
            },
            Rand(vx, byte) => {
                self.reg[vx as usize] = rand::thread_rng().gen::<u8>() & byte;
            }
            Draw(vx, vy, n) => {
                let x = self.reg[vx as usize] as usize;
                let y = self.reg[vy as usize] as usize;
                let i = self.i as usize;
                let n = n as usize;

                let sprite = &self.ram[i..i+n];

                self.reg[15] = 0;
                for (sy, byte) in sprite.iter().enumerate() {
                    let dy = (y + sy) % 32;
                    for sx in 0us..8 {
                        let px = (*byte >> (7 - sx)) & 0b00000001;
                        let dx = (x + sx) % 64;
                        let idx = dy * 64 + dx;
                        self.screen[idx] ^= px;

                        // Vf is if there was a collision
                        self.reg[15] |= (self.screen[idx] == 0 && px == 1) as u8;
                    }
                }
            },
            SkipPressed(vx) => {
                let idx = self.reg[vx as usize];
                if self.keys[idx as usize] == 1 {
                    self.pc += 2;
                }
            }
            SkipNotPressed(vx) => {
                let idx = self.reg[vx as usize];
                if self.keys[idx  as usize] != 1 {
                    self.pc += 2;
                }
            }
            GetTimer(vx) => {
                self.reg[vx as usize] = self.timer;
            },
            //TODO WaitKey(vx) => {}
            SetTimer(vx) => {
                self.timer = self.reg[vx as usize];
                self.t_tick = 1.0 / 60.0;
            },
            SetSoundTimer(vx) => {
                self.sound_timer = self.reg[vx as usize];
                self.st_tick = 1.0 / 60.0;
            },
            AddToI(vx) => {
                self.i += self.reg[vx as usize] as usize;
            },
            LoadHexGlyph(vx) => {
                let x = self.reg[vx as usize];
                self.i = FONT_ADDR + x as usize * FONT_HEIGHT;
            }
            StoreBCD(vx) => {
                let mut x = self.reg[vx as usize];

                let mut place = 100;
                for i in 0us..2 {
                    self.i += i;
                    let bcd = x / place;
                    self.ram[self.i] = bcd;
                    x -= bcd;
                    place /= 10;
                }
            }
            StoreRegisters(vx) => {
                let vx = vx as usize;
                let i = self.i as usize;

                let mut dst = &mut self.ram[i..i+vx+1];
                for (x,b) in dst.iter_mut().enumerate() {
                  //println!("store reg {} to {}", x, i);
                    *b = self.reg[x];
                }
            },
            LoadRegisters(vx) => {
                let vx = vx as usize;
                let i = self.i as usize;

                let src = &self.ram[i..i+vx+1];
                for (x,b) in src.iter().enumerate() {
                  //println!("read reg {} from {}", x, i);
                    self.reg[x] = *b;
                }
            },
            other => {
                println!("Instruction not implemented {:?} skipping...", other)
            }
        }
        return false;
    }

    fn time_step(&mut self, dt:f32) {
        if self.timer > 0 {
            self.t_tick -= dt;
            if self.t_tick <= 0.0 {
                self.timer -= 1;
                self.t_tick = 1.0 / 60.0;
            }
        }

        if self.sound_timer > 0 {
            self.st_tick -= dt;
            if self.st_tick <= 0.0 {
                self.sound_timer -= 1;
                self.st_tick = 1.0 / 60.0;
            }
        }
    }

    // dt: Time in seconds since last step
    pub fn step(&mut self, dt:f32) -> bool {
        let mut idle = false;

        let raw = {
            let codes = &self.ram[self.pc..self.pc+2];
            ((codes[0] as u16) << 8) | codes[1] as u16
        };
        let op = Op::new(raw);
        self.pc += 2;
        idle = self.exec(&op);
        self.time_step(dt);
        return idle;
    }

    pub fn screen_rows<'a>(&'a self) -> Chunks<'a, u8> {
        self.screen.chunks(64)
    }

    pub fn print_screen(&self) {
        for row in self.screen.chunks(64) {
            println!("");
            for byte in row.iter() {
                match *byte {
                    0x0 => print!("░"),
                    _ => print!("▓")
                }
            }
        }
    }

    pub fn print_disassembly(&self) {
        for i in self.ram.chunks(2) {
            match i {
                [0, 0] => continue,
                [h, l] => {
                    let op = Op::new(((h as u16) << 8) | l as u16);
                    println!("raw: 0x{:X}", op.raw());
                    println!("instruction: {:?}", Instruction::from_op(&op));
                    println!("addr: 0x{:X}", op.addr());
                    println!("x: 0x{:X}", op.x());
                    println!("y: 0x{:X}", op.y());
                    println!("n_high: 0x{:X}", op.n_high());
                    println!("n_low: 0x{:X}", op.n_low());
                    println!("k: 0x{:X}\n", op.k());
                },
                _ => continue
            }
        }
    }
}
<commit_msg>Fix BCD<commit_after>use std::io::{BufWriter, Reader};
use std::num::Float;
use error::Ch8Error;
use ops::{Op, Instruction};
use std::slice::Chunks;

use std::rand::Rng;
use std::rand;

const RAM_SIZE: usize = 4096;
const PROGRAM_START: usize = 0x200;

const FONT_ADDR: usize = 0;
const FONT_HEIGHT: usize = 5;
const FONT_BYTES: usize = FONT_HEIGHT * 16;
const FONT: [u8; FONT_BYTES] = [
	0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
	0x20, 0x60, 0x20, 0x20, 0x70, // 1
	0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
	0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
	0x90, 0x90, 0xF0, 0x10, 0x10, // 4
	0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
	0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
	0xF0, 0x10, 0x20, 0x40, 0x40, // 7
	0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
	0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
	0xF0, 0x90, 0xF0, 0x90, 0x90, // A
	0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
	0xF0, 0x80, 0x80, 0x80, 0xF0, // C
	0xE0, 0x90, 0x90, 0x90, 0xE0, // D
	0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
	0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

pub struct Vm {
    reg: [u8; 16],
    i: usize,
    pc: usize,
    sp: usize,
    stack: [usize; 256],
    ram: [u8; RAM_SIZE],

    timer: u8,
    t_tick: f32,

    sound_timer: u8,
    st_tick: f32,

    screen: [u8; 64 * 32],
    keys: [u8; 16],
}

impl Vm {
    pub fn new() -> Vm {
        let mut vm = Vm {
            reg: [0; 16],
            i: 0,
            pc: PROGRAM_START,
            sp: 0,
            stack: [0; 256],
            ram: [0; RAM_SIZE],

            timer: 0,
            t_tick: 0.0,

            sound_timer: 0,
            st_tick: 0.0,

            screen: [0; 64 * 32],
            keys: [0; 16],
        };
        {
            let mut ram = BufWriter::new(&mut vm.ram[FONT_ADDR..(FONT_ADDR + FONT_BYTES)]);
            ram.write(FONT.as_slice());
        }
        vm
    }

    pub fn load_rom(&mut self, reader: &mut Reader) -> Result<usize, Ch8Error> {
        let rom = try!(reader.read_to_end());
        if rom.len() > (RAM_SIZE - PROGRAM_START) {
           return Err(Ch8Error::Io("Rom was larger than available RAM", None))
        }
        let mut ram = BufWriter::new(&mut self.ram[PROGRAM_START..RAM_SIZE]);
        try!(ram.write(rom.as_slice()));
        return Ok(rom.len());
    }

    pub fn dump_ram(&self, writer: &mut Writer) {
        writer.write(&self.ram).unwrap();
    }

    pub fn set_key(&mut self, idx: u8) {
        self.keys[idx as usize] = 1;
    }

    pub fn unset_key(&mut self, idx: u8) {
        self.keys[idx as usize] = 0;
    }

    fn exec(&mut self, op: &Op) -> bool {
        use ops::Instruction::*;
        let ins = Instruction::from_op(op);
//        if self.timer == 0 {
//            println!("Executing instruction: 0x{:X} {:?}", self.pc, ins);
//            println!("v: {:?}", self.reg);
//            println!("timers: t: {} s: {}", self.timer, self.sound_timer);
//            self.print_screen();
//        }
        match ins {
            // Sys(addr) intentionally left unimplemented.
            Clear => {
                for b in self.screen.iter_mut() {
                    *b = 0;
                }
            },
            Return => {
                self.pc = self.stack[self.sp];
                self.sp-=1;
            },
            Jump(addr) => {
                let idle = self.pc-2 == addr as usize;
                self.pc = addr as usize;
                if idle { return true; }
            }
            Call(addr) => {
                self.sp+=1;
                self.stack[self.sp] = self.pc;
                self.pc = addr as usize;
            },
            SkipEqualK(vx, k) => {
                if self.reg[vx as usize] == k {
                    self.pc += 2;
                }
            },
            SkipNotEqualK(vx, k) => {
                if self.reg[vx as usize] != k {
                    self.pc += 2;
                }
            },
            SkipEqual(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];
                if x == y {
                    self.pc += 2;
                }
            },
            SetK(vx, byte) => {
                self.reg[vx as usize] = byte;
            },
            AddK(vx, byte) => {
                self.reg[vx as usize] += byte;
            },
            Set(vx, vy) => self.reg[vx as usize] = self.reg[vy as usize],
            Or(vx, vy)  => self.reg[vx as usize] |= self.reg[vy as usize],
            And(vx, vy) => self.reg[vx as usize] &= self.reg[vy as usize],
            XOr(vx, vy) => self.reg[vx as usize] ^= self.reg[vy as usize],
            Add(vx, vy) => {
                let x = self.reg[vx as usize] as u16;
                let y = self.reg[vy as usize] as u16;
                let res = x + y;

                // VF is carryover
                self.reg[15] = (res > 255) as u8;

                self.reg[vx as usize] = res as u8;
            },
            Sub(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];

                // VF is Not Borrow i.e. x > y
                self.reg[15] = (x > y) as u8;

                self.reg[vx as usize] = x - y;
            },
            ShiftRight(vx, vy) => {
                let y = self.reg[vy as usize];

                // VF is lsb before shift
                self.reg[15] = 0x1 & y;

                self.reg[vx as usize] = y >> 1;
            },
            SubInv(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];

                // VF is Not Borrow i.e. y > x
                self.reg[15] = (y > x) as u8;

                self.reg[vx as usize] = y - x;
            },
            ShiftLeft(vx, vy) => {
                let y = self.reg[vy as usize];

                // VF is msb before shift
                self.reg[15] =  0x80 & y;

                self.reg[vx as usize] = y << 1;
            }
            SkipNotEqual(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];
                if x != y {
                    self.pc += 2;
                }
            },
            LoadI(addr) => {
                self.i = addr as usize;
            },
            LongJump(addr) => {
                self.pc = (self.reg[0] as u16 + addr) as usize;
            },
            Rand(vx, byte) => {
                self.reg[vx as usize] = rand::thread_rng().gen::<u8>() & byte;
            }
            Draw(vx, vy, n) => {
                let x = self.reg[vx as usize] as usize;
                let y = self.reg[vy as usize] as usize;
                let i = self.i as usize;
                let n = n as usize;

                let sprite = &self.ram[i..i+n];

                self.reg[15] = 0;
                for (sy, byte) in sprite.iter().enumerate() {
                    let dy = (y + sy) % 32;
                    for sx in 0us..8 {
                        let px = (*byte >> (7 - sx)) & 0b00000001;
                        let dx = (x + sx) % 64;
                        let idx = dy * 64 + dx;
                        self.screen[idx] ^= px;

                        // Vf is if there was a collision
                        self.reg[15] |= (self.screen[idx] == 0 && px == 1) as u8;
                    }
                }
            },
            SkipPressed(vx) => {
                let idx = self.reg[vx as usize];
                if self.keys[idx as usize] == 1 {
                    self.pc += 2;
                }
            }
            SkipNotPressed(vx) => {
                let idx = self.reg[vx as usize];
                if self.keys[idx  as usize] != 1 {
                    self.pc += 2;
                }
            }
            GetTimer(vx) => {
                self.reg[vx as usize] = self.timer;
            },
            //TODO WaitKey(vx) => {}
            SetTimer(vx) => {
                self.timer = self.reg[vx as usize];
                self.t_tick = 1.0 / 60.0;
            },
            SetSoundTimer(vx) => {
                self.sound_timer = self.reg[vx as usize];
                self.st_tick = 1.0 / 60.0;
            },
            AddToI(vx) => {
                self.i += self.reg[vx as usize] as usize;
            },
            LoadHexGlyph(vx) => {
                let x = self.reg[vx as usize];
                self.i = FONT_ADDR + x as usize * FONT_HEIGHT;
            }
            StoreBCD(vx) => {
                let mut x = self.reg[vx as usize];

                let mut place = 100;
                for i in 0us..3 {
                    let bcd = x / place;
                    self.ram[self.i + i] = bcd;
                    x -= bcd * place;
                    place /= 10;
                }
            }
            StoreRegisters(vx) => {
                let vx = vx as usize;
                let i = self.i as usize;

                let mut dst = &mut self.ram[i..i+vx+1];
                for (x,b) in dst.iter_mut().enumerate() {
                  //println!("store reg {} to {}", x, i);
                    *b = self.reg[x];
                }
            },
            LoadRegisters(vx) => {
                let vx = vx as usize;
                let i = self.i as usize;

                let src = &self.ram[i..i+vx+1];
                for (x,b) in src.iter().enumerate() {
                  //println!("read reg {} from {}", x, i);
                    self.reg[x] = *b;
                }
            },
            other => {
                println!("Instruction not implemented {:?} skipping...", other)
            }
        }
        return false;
    }

    fn time_step(&mut self, dt:f32) {
        if self.timer > 0 {
            self.t_tick -= dt;
            if self.t_tick <= 0.0 {
                self.timer -= 1;
                self.t_tick = 1.0 / 60.0;
            }
        }

        if self.sound_timer > 0 {
            self.st_tick -= dt;
            if self.st_tick <= 0.0 {
                self.sound_timer -= 1;
                self.st_tick = 1.0 / 60.0;
            }
        }
    }

    // dt: Time in seconds since last step
    pub fn step(&mut self, dt:f32) -> bool {
        let mut idle = false;

        let raw = {
            let codes = &self.ram[self.pc..self.pc+2];
            ((codes[0] as u16) << 8) | codes[1] as u16
        };
        let op = Op::new(raw);
        self.pc += 2;
        idle = self.exec(&op);
        self.time_step(dt);
        return idle;
    }

    pub fn screen_rows<'a>(&'a self) -> Chunks<'a, u8> {
        self.screen.chunks(64)
    }

    pub fn print_screen(&self) {
        for row in self.screen.chunks(64) {
            println!("");
            for byte in row.iter() {
                match *byte {
                    0x0 => print!("░"),
                    _ => print!("▓")
                }
            }
        }
    }

    pub fn print_disassembly(&self) {
        for i in self.ram.chunks(2) {
            match i {
                [0, 0] => continue,
                [h, l] => {
                    let op = Op::new(((h as u16) << 8) | l as u16);
                    println!("raw: 0x{:X}", op.raw());
                    println!("instruction: {:?}", Instruction::from_op(&op));
                    println!("addr: 0x{:X}", op.addr());
                    println!("x: 0x{:X}", op.x());
                    println!("y: 0x{:X}", op.y());
                    println!("n_high: 0x{:X}", op.n_high());
                    println!("n_low: 0x{:X}", op.n_low());
                    println!("k: 0x{:X}\n", op.k());
                },
                _ => continue
            }
        }
    }
}
<|endoftext|>


<commit_before>use error::*;
use std::fmt;
use std::rc::Rc;
use std::collections::HashMap;
use token::Literal;

#[derive(Clone, Debug)]
pub enum Expr {
    Nil,
    Func(Function),
    Atom(Atom),
    List(List),
    Quote(Quote),
}

#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub enum Atom {
    Bool(bool),
    Int(i64),
    Flt(f64),
    Str(String),
    Sym(Symbol),
}

#[derive(Clone, Debug)]
pub struct List(pub Vec<Expr>);

#[derive(Clone, Debug)]
pub struct Quote(pub Vec<Expr>);

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Symbol(pub String);

#[derive(Clone)]
pub struct Function {
    name: Option<String>,
    func: Rc<Box<Lambda>>,
}

pub struct Env<'a> {
    symbols: HashMap<String, Expr>,
    parent: Option<&'a Env<'a>>,
}

pub type Lambda = Fn(&[Expr], &Env) -> Result<Expr>;

impl Expr {
    pub fn eval(&self, env: &Env) -> Result<Expr> {
        match self {
            &Expr::List(ref lst) => {
                if let Some((first, rest)) = lst.0.split_first() {
                    if let Ok(Expr::Func(ref func)) = first.eval(env) {
                        func.apply(rest, env)
                    } else {
                        Err("expected function call".into())
                    }
                } else {
                    Ok(self.clone())
                }
            },
            &Expr::Atom(Atom::Sym(ref symbol)) => {
                env.lookup(&symbol.0)
                    .map(Clone::clone)
                    .ok_or(format!("undefined symbol: {}", symbol.0).into())
            },
            _ => Ok(self.clone()),
        }
    }

    pub fn atom(self) -> Option<Atom> {
        if let Expr::Atom(x) = self { Some(x) } else { None }
    }

    pub fn list(self) -> Option<List> {
        if let Expr::List(x) = self { Some(x) } else { None }
    }

    pub fn quote(self) -> Option<Quote> {
        if let Expr::Quote(x) = self { Some(x) } else { None }
    }

    pub fn func(self) -> Option<Function> {
        if let Expr::Func(x) = self { Some(x) } else { None }
    }
}

impl Atom {
    pub fn is_boolean(&self) -> bool {
        self.boolean().is_some()
    }

    pub fn is_int(&self) -> bool {
        self.int().is_some()
    }

    pub fn is_flt(&self) -> bool {
        self.flt().is_some()
    }

    pub fn is_str(&self) -> bool {
        self.str().is_some()
    }

    pub fn is_num(&self) -> bool {
        match self {
            &Atom::Flt(_) | &Atom::Int(_) => true,
            _ => false,
        }
    }

    pub fn boolean(&self) -> Option<bool> {
        if let &Atom::Bool(x) = self { Some(x) } else { None }
    }

    pub fn int(&self) -> Option<i64> {
        if let &Atom::Int(x) = self { Some(x) } else { None }
    }

    pub fn flt(&self) -> Option<f64> {
        if let &Atom::Flt(x) = self { Some(x) } else { None }
    }

    pub fn str(&self) -> Option<&str> {
        if let &Atom::Str(ref x) = self { Some(x) } else { None }
    }

    pub fn map_int<A, F>(self, f: F) -> Atom
        where F: FnOnce(i64) -> A,
              A: Into<Atom>
    {
        match self {
            Atom::Int(int) => f(int).into(),
            _ => self,
        }
    }

    pub fn map_flt<A, F>(self, f: F) -> Atom
        where F: FnOnce(f64) -> A,
              A: Into<Atom>
    {
        match self {
            Atom::Flt(flt) => f(flt).into(),
            _ => self,
        }
    }
}

impl Function {
    pub fn new<S>(name: Option<S>, func: Box<Lambda>) -> Self
        where S: Into<String>
    {
        Function {
            name: name.map(Into::into),
            func: Rc::new(func),
        }
    }

    pub fn apply<'a>(&self, args: &'a [Expr], env: &Env) -> Result<Expr> {
        // Eval all arguments, returning if any errors
        let evaled_args = args.iter()
            .map(|a| a.eval(env))
            .collect::<Result<Vec<_>>>()
            .chain_err(|| "argument eval failed")?;

        // Call function on args
        (self.func)(&evaled_args, env)
    }
}

impl<'a> Env<'a> {
    pub fn new(symbols: HashMap<String, Expr>, parent: Option<&'a Env<'a>>) -> Self {
        Env { symbols, parent }
    }

    pub fn lookup(&self, symbol: &str) -> Option<&Expr> {
        self.symbols.get(symbol)
            .or_else(|| {
                self.parent.and_then(|p| p.lookup(symbol))
            })
    }
}

impl fmt::Debug for Function {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref name) = self.name {
            write!(f, "#[{}]", name)
        } else {
            write!(f, "#\u{03BB}")
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expr::Nil => write!(f, "()"),
            Expr::Func(ref func) => write!(f, "{}", func),
            Expr::Atom(ref atom) => write!(f, "{}", atom),
            Expr::List(ref list) => write!(f, "{}", list),
            Expr::Quote(ref quote) => write!(f, "{}", quote),
        }
    }
}

impl fmt::Display for Atom {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Atom::Bool(boolean) => write!(f, "#{}", if boolean { "t" } else { "f" }),
            Atom::Int(int) => write!(f, "{}", int),
            Atom::Flt(flt) => write!(f, "{}", flt),
            Atom::Str(ref string) => write!(f, "\"{}\"", string),
            Atom::Sym(ref sym) => write!(f, "#{}", sym.0),
        }
    }
}

impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({})", self.0.split_first()
            .map(|(first, rest)| {
                rest.iter().fold(first.to_string(), |mut acc, x| {
                    acc.push_str(&x.to_string());
                    acc
                })
            }).unwrap_or(String::new())
        )
    }
}

impl fmt::Display for Quote {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}]", self.0.split_first()
            .map(|(first, rest)| {
                rest.iter().fold(first.to_string(), |mut acc, x| {
                    acc.push(' ');
                    acc.push_str(&x.to_string());
                    acc
                })
            }).unwrap_or(String::new())
        )
    }
}

impl fmt::Display for Function {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

impl<T> From<T> for Expr
    where T: Into<Atom>
{
    fn from(x: T) -> Expr {
        Expr::Atom(x.into())
    }
}

impl From<Function> for Expr {
    fn from(x: Function) -> Expr {
        Expr::Func(x)
    }
}

impl<T> From<T> for Atom
    where T: Into<Literal>
{
    fn from(x: T) -> Self {
        match x.into() {
            Literal::Bool(y) => Atom::Bool(y),
            Literal::Int(y) => Atom::Int(y),
            Literal::Flt(y) => Atom::Flt(y),
            Literal::Str(y) => Atom::Str(y),
        }
    }
}

impl From<Symbol> for Atom {
    fn from(x: Symbol) -> Self {
        Atom::Sym(x)
    }
}

impl From<Quote> for List {
    fn from(x: Quote) -> Self {
        List(x.0)
    }
}

impl From<List> for Quote {
    fn from(x: List) -> Self {
        Quote(x.0)
    }
}

impl PartialEq for List {
    fn eq(&self, other: &Self) -> bool {
        self.0.iter().zip(other.0.iter())
            .all(|(a, b)| a == b)
    }
}

impl PartialEq for Quote {
    fn eq(&self, other: &Self) -> bool {
        self.0.iter().zip(other.0.iter())
            .all(|(a, b)| a == b)
    }
}

impl PartialEq for Expr {
    fn eq(&self, other: &Self) -> bool {
        use self::Expr::*;
        match (self, other) {
            (&Nil, &Nil) => true,
            (&Func(_), &Func(_)) => false,
            (&Atom(ref a), &Atom(ref b)) => a == b,
            (&List(ref a), &List(ref b)) => a == b,
            (&Quote(ref a), &Quote(ref b)) => a == b,
            _ => false
        }
    }
}

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

    fn lift(func: Box<Fn(&[Atom]) -> Result<Atom>>) -> Box<Lambda> {
        Box::new(move |args| {
            func(args.iter()
                    .map(|arg| {
                        if let &Expr::Atom(ref atom) = arg {
                            atom.clone()
                        } else {
                            panic!()
                        }
                    })
                    .collect::<Vec<_>>()
                    .as_slice())
                .map(Expr::Atom)
        })
    }

    #[test]
    fn call_fn() {
        let func = Box::new(move |atoms: &[Atom]| {
            Ok(Atom::Int(atoms.iter()
                .map(|x| if let &Atom::Int(y) = x { y } else { panic!() })
                .sum()))
        });
        let add = Function::new(Some("add"), lift(func));
        let result = add.apply(vec![Expr::Atom(Atom::Int(1)), Expr::Atom(Atom::Int(2))].as_slice());
        assert_eq!(Some(Atom::from(3)), result.unwrap().atom());
    }
}
<commit_msg>Fix ast fn test<commit_after>use error::*;
use std::fmt;
use std::rc::Rc;
use std::collections::HashMap;
use token::Literal;

#[derive(Clone, Debug)]
pub enum Expr {
    Nil,
    Func(Function),
    Atom(Atom),
    List(List),
    Quote(Quote),
}

#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub enum Atom {
    Bool(bool),
    Int(i64),
    Flt(f64),
    Str(String),
    Sym(Symbol),
}

#[derive(Clone, Debug)]
pub struct List(pub Vec<Expr>);

#[derive(Clone, Debug)]
pub struct Quote(pub Vec<Expr>);

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Symbol(pub String);

#[derive(Clone)]
pub struct Function {
    name: Option<String>,
    func: Rc<Box<Lambda>>,
}

pub struct Env<'a> {
    symbols: HashMap<String, Expr>,
    parent: Option<&'a Env<'a>>,
}

pub type Lambda = Fn(&[Expr], &Env) -> Result<Expr>;

impl Expr {
    pub fn eval(&self, env: &Env) -> Result<Expr> {
        match self {
            &Expr::List(ref lst) => {
                if let Some((first, rest)) = lst.0.split_first() {
                    if let Ok(Expr::Func(ref func)) = first.eval(env) {
                        func.apply(rest, env)
                    } else {
                        Err("expected function call".into())
                    }
                } else {
                    Ok(self.clone())
                }
            },
            &Expr::Atom(Atom::Sym(ref symbol)) => {
                env.lookup(&symbol.0)
                    .map(Clone::clone)
                    .ok_or(format!("undefined symbol: {}", symbol.0).into())
            },
            _ => Ok(self.clone()),
        }
    }

    pub fn atom(self) -> Option<Atom> {
        if let Expr::Atom(x) = self { Some(x) } else { None }
    }

    pub fn list(self) -> Option<List> {
        if let Expr::List(x) = self { Some(x) } else { None }
    }

    pub fn quote(self) -> Option<Quote> {
        if let Expr::Quote(x) = self { Some(x) } else { None }
    }

    pub fn func(self) -> Option<Function> {
        if let Expr::Func(x) = self { Some(x) } else { None }
    }
}

impl Atom {
    pub fn is_boolean(&self) -> bool {
        self.boolean().is_some()
    }

    pub fn is_int(&self) -> bool {
        self.int().is_some()
    }

    pub fn is_flt(&self) -> bool {
        self.flt().is_some()
    }

    pub fn is_str(&self) -> bool {
        self.str().is_some()
    }

    pub fn is_num(&self) -> bool {
        match self {
            &Atom::Flt(_) | &Atom::Int(_) => true,
            _ => false,
        }
    }

    pub fn boolean(&self) -> Option<bool> {
        if let &Atom::Bool(x) = self { Some(x) } else { None }
    }

    pub fn int(&self) -> Option<i64> {
        if let &Atom::Int(x) = self { Some(x) } else { None }
    }

    pub fn flt(&self) -> Option<f64> {
        if let &Atom::Flt(x) = self { Some(x) } else { None }
    }

    pub fn str(&self) -> Option<&str> {
        if let &Atom::Str(ref x) = self { Some(x) } else { None }
    }

    pub fn map_int<A, F>(self, f: F) -> Atom
        where F: FnOnce(i64) -> A,
              A: Into<Atom>
    {
        match self {
            Atom::Int(int) => f(int).into(),
            _ => self,
        }
    }

    pub fn map_flt<A, F>(self, f: F) -> Atom
        where F: FnOnce(f64) -> A,
              A: Into<Atom>
    {
        match self {
            Atom::Flt(flt) => f(flt).into(),
            _ => self,
        }
    }
}

impl Function {
    pub fn new<S>(name: Option<S>, func: Box<Lambda>) -> Self
        where S: Into<String>
    {
        Function {
            name: name.map(Into::into),
            func: Rc::new(func),
        }
    }

    pub fn apply<'a>(&self, args: &'a [Expr], env: &Env) -> Result<Expr> {
        // Eval all arguments, returning if any errors
        let evaled_args = args.iter()
            .map(|a| a.eval(env))
            .collect::<Result<Vec<_>>>()
            .chain_err(|| "argument eval failed")?;

        // Call function on args
        (self.func)(&evaled_args, env)
    }
}

impl<'a> Env<'a> {
    pub fn new(symbols: HashMap<String, Expr>, parent: Option<&'a Env<'a>>) -> Self {
        Env { symbols, parent }
    }

    pub fn lookup(&self, symbol: &str) -> Option<&Expr> {
        self.symbols.get(symbol)
            .or_else(|| {
                self.parent.and_then(|p| p.lookup(symbol))
            })
    }
}

impl fmt::Debug for Function {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref name) = self.name {
            write!(f, "#[{}]", name)
        } else {
            write!(f, "#\u{03BB}")
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expr::Nil => write!(f, "()"),
            Expr::Func(ref func) => write!(f, "{}", func),
            Expr::Atom(ref atom) => write!(f, "{}", atom),
            Expr::List(ref list) => write!(f, "{}", list),
            Expr::Quote(ref quote) => write!(f, "{}", quote),
        }
    }
}

impl fmt::Display for Atom {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Atom::Bool(boolean) => write!(f, "#{}", if boolean { "t" } else { "f" }),
            Atom::Int(int) => write!(f, "{}", int),
            Atom::Flt(flt) => write!(f, "{}", flt),
            Atom::Str(ref string) => write!(f, "\"{}\"", string),
            Atom::Sym(ref sym) => write!(f, "#{}", sym.0),
        }
    }
}

impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({})", self.0.split_first()
            .map(|(first, rest)| {
                rest.iter().fold(first.to_string(), |mut acc, x| {
                    acc.push_str(&x.to_string());
                    acc
                })
            }).unwrap_or(String::new())
        )
    }
}

impl fmt::Display for Quote {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}]", self.0.split_first()
            .map(|(first, rest)| {
                rest.iter().fold(first.to_string(), |mut acc, x| {
                    acc.push(' ');
                    acc.push_str(&x.to_string());
                    acc
                })
            }).unwrap_or(String::new())
        )
    }
}

impl fmt::Display for Function {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

impl<T> From<T> for Expr
    where T: Into<Atom>
{
    fn from(x: T) -> Expr {
        Expr::Atom(x.into())
    }
}

impl From<Function> for Expr {
    fn from(x: Function) -> Expr {
        Expr::Func(x)
    }
}

impl<T> From<T> for Atom
    where T: Into<Literal>
{
    fn from(x: T) -> Self {
        match x.into() {
            Literal::Bool(y) => Atom::Bool(y),
            Literal::Int(y) => Atom::Int(y),
            Literal::Flt(y) => Atom::Flt(y),
            Literal::Str(y) => Atom::Str(y),
        }
    }
}

impl From<Symbol> for Atom {
    fn from(x: Symbol) -> Self {
        Atom::Sym(x)
    }
}

impl From<Quote> for List {
    fn from(x: Quote) -> Self {
        List(x.0)
    }
}

impl From<List> for Quote {
    fn from(x: List) -> Self {
        Quote(x.0)
    }
}

impl PartialEq for List {
    fn eq(&self, other: &Self) -> bool {
        self.0.iter().zip(other.0.iter())
            .all(|(a, b)| a == b)
    }
}

impl PartialEq for Quote {
    fn eq(&self, other: &Self) -> bool {
        self.0.iter().zip(other.0.iter())
            .all(|(a, b)| a == b)
    }
}

impl PartialEq for Expr {
    fn eq(&self, other: &Self) -> bool {
        use self::Expr::*;
        match (self, other) {
            (&Nil, &Nil) => true,
            (&Func(_), &Func(_)) => false,
            (&Atom(ref a), &Atom(ref b)) => a == b,
            (&List(ref a), &List(ref b)) => a == b,
            (&Quote(ref a), &Quote(ref b)) => a == b,
            _ => false
        }
    }
}

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

    fn lift(func: Box<Fn(&[Atom], &Env) -> Result<Atom>>) -> Box<Lambda> {
        Box::new(move |args, env| {
            func(args.iter()
                    .map(|arg| {
                        if let &Expr::Atom(ref atom) = arg {
                            atom.clone()
                        } else {
                            panic!()
                        }
                    })
                    .collect::<Vec<_>>()
                    .as_slice(), env)
                .map(Expr::Atom)
        })
    }

    #[test]
    fn call_fn() {
        let env = ops::env();
        let func = Box::new(move |atoms: &[Atom], _env: &Env| {
            Ok(Atom::Int(atoms.iter()
                .map(|x| if let &Atom::Int(y) = x { y } else { panic!() })
                .sum()))
        });
        let add = Function::new(Some("add"), lift(func));

        let nums: Vec<Expr> = vec![1i64, 2i64].into_iter().map(Expr::from).collect();
        let result = add.apply(nums.as_slice(), &env);
        assert_eq!(Some(Atom::from(3)), result.unwrap().atom());
    }
}
<|endoftext|>