<commit_before>// Copyright (c) 2018 Jason White
//
// 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.

use std::fs;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
use std::str::FromStr;

use crate::error::{Error, ResultExt};
use crate::util::Process;

use super::detected::Detected;

use tempfile::NamedTempFile;

use crate::util::MakeFile;

pub fn run(
    root: &Path,
    process: &Process,
    log: &mut dyn io::Write,
) -> Result<Detected, Error> {
    let mut process = process.clone();

    // Use `-MMD -MF` to capture header files used by the build.
    //
    // TODO: Handle the case where this is already in the command line arguments
    // or when we are not compiling (i.e., no `-c` flag).
    process.args.push("-MMD".into());
    process.args.push("-MF".into());

    let temppath = NamedTempFile::new()
        .context("Failed creating temporary deps file")?
        .into_temp_path();
    process
        .args
        .push(temppath.to_string_lossy().into_owned().into());

    // Generate a response file if necessary.
    let response_file = if process.args.too_large() {
        Some(
            process
                .response_file()
                .context("Failed generating response file")?,
        )
    } else {
        None
    };

    let (mut reader, child) = process.spawn(root)?;

    // Read the combined stdout/stderr.
    let mut buf = [0u8; 4096];
    loop {
        let n = reader.read(&mut buf)?;
        if n == 0 {
            break;
        }

        log.write_all(&buf[0..n])?;
    }

    child.wait()?;

    if let Some(response_file) = response_file {
        response_file
            .close()
            .context("Failed deleting response file")?;
    }

    let mut makefile = fs::read_to_string(&temppath).with_context(|_| {
        format!("Failed reading temporary file \"{}\"", temppath.display())
    })?;

    // The makefile parser requires a null terminator.
    makefile.push('\0');

    // TODO: Fix error handling!
    let makefile = MakeFile::from_str(&makefile).unwrap();

    let mut detected = Detected::new();

    for rule in makefile.rules() {
        for input in &rule.prereqs {
            // TODO: Handle working directories and whatnot.
            detected.add_input(PathBuf::from(input).into());
        }
    }

    // Detect errors in deleting temporary file.
    temppath
        .close()
        .context("Failed deleting temporary deps file")?;

    Ok(detected)
}
<commit_msg>Always enable color output for clang<commit_after>// Copyright (c) 2018 Jason White
//
// 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.

use std::fs;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
use std::str::FromStr;

use crate::error::{Error, ResultExt};
use crate::util::Process;

use super::detected::Detected;

use tempfile::NamedTempFile;

use crate::util::MakeFile;

pub fn run(
    root: &Path,
    process: &Process,
    log: &mut dyn io::Write,
) -> Result<Detected, Error> {
    let mut process = process.clone();

    // Always enable color output. The logger will take care of filtering out
    // the ANSI escape codes if necessary.
    process.args.push("-fdiagnostics-color=always".into());

    // Use `-MMD -MF` to capture header files used by the build.
    //
    // TODO: Handle the case where this is already in the command line arguments
    // or when we are not compiling (i.e., no `-c` flag).
    process.args.push("-MMD".into());
    process.args.push("-MF".into());

    let temppath = NamedTempFile::new()
        .context("Failed creating temporary deps file")?
        .into_temp_path();
    process
        .args
        .push(temppath.to_string_lossy().into_owned().into());

    // Generate a response file if necessary.
    let response_file = if process.args.too_large() {
        Some(
            process
                .response_file()
                .context("Failed generating response file")?,
        )
    } else {
        None
    };

    let (mut reader, child) = process.spawn(root)?;

    // Read the combined stdout/stderr.
    let mut buf = [0u8; 4096];
    loop {
        let n = reader.read(&mut buf)?;
        if n == 0 {
            break;
        }

        log.write_all(&buf[0..n])?;
    }

    child.wait()?;

    if let Some(response_file) = response_file {
        response_file
            .close()
            .context("Failed deleting response file")?;
    }

    let mut makefile = fs::read_to_string(&temppath).with_context(|_| {
        format!("Failed reading temporary file \"{}\"", temppath.display())
    })?;

    // The makefile parser requires a null terminator.
    makefile.push('\0');

    // TODO: Fix error handling!
    let makefile = MakeFile::from_str(&makefile).unwrap();

    let mut detected = Detected::new();

    for rule in makefile.rules() {
        for input in &rule.prereqs {
            // TODO: Handle working directories and whatnot.
            detected.add_input(PathBuf::from(input).into());
        }
    }

    // Detect errors in deleting temporary file.
    temppath
        .close()
        .context("Failed deleting temporary deps file")?;

    Ok(detected)
}
<|endoftext|>


<commit_before>//! The main entry point for the Space API server.
//!
//! Running this code starts a HTTP server instance. The default port is 3000, but you can set your
//! own favorite port by exporting the `PORT` environment variable.

extern crate rustc_serialize;
extern crate iron;
extern crate spaceapi;

pub mod datastore;
pub mod sensors;

use std::net::Ipv4Addr;

use rustc_serialize::json::{Json, ToJson};
use iron::{Request, Response, IronResult, Iron, Set};
use iron::{status, headers, middleware};
use iron::modifiers::Header;

pub use spaceapi as api;
use datastore::SafeDataStore;
use spaceapi::utils::Optional;
use spaceapi::SensorTemplate;

/// A Space API server instance.
///
/// You can create a new instance using the ``new`` constructor method by
/// passing it the host, the port, the ``Status`` object and a datastore.
///
/// The ``SpaceapiServer`` includes a web server through
/// [Hyper](http://hyper.rs/hyper/hyper/server/index.html). Simply call the ``serve`` method.
pub struct SpaceapiServer {
    host: Ipv4Addr,
    port: u16,
    status: api::Status,
    datastore: SafeDataStore,
    sensor_specs: Vec<sensors::SensorSpec>
}

impl SpaceapiServer {

    pub fn new(host: Ipv4Addr, port: u16, status: api::Status, datastore: SafeDataStore) -> SpaceapiServer {
        SpaceapiServer {
            host: host,
            port: port,
            status: status,
            datastore: datastore,
            sensor_specs: vec![],
        }
    }

    /// Start a HTTP server listening on ``self.host:self.port``.
    ///
    /// This call is blocking. It can be interrupted with SIGINT (Ctrl+C).
    pub fn serve(self) {
        let host = self.host;
        let port = self.port;
        println!("Starting HTTP server on http://{}:{}...", host, port);
        Iron::new(self).http((host, port)).unwrap();
    }

    /// Register a new sensor.
    ///
    /// The first argument is a ``api::SensorTemplate`` instance containing all static data.
    /// The second argument specifies how to get the actual sensor value from the datastore.
    /// And the third argument specifies the data type of the value.
    pub fn register_sensor(&mut self, template: Box<api::SensorTemplate>, data_key: String) {
        self.sensor_specs.push(
            sensors::SensorSpec { template: template, data_key: data_key}
        );
    }

    fn build_response_json(&self) -> Json {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in &self.sensor_specs {

            sensor_spec.get_sensor_value(&self.datastore).map(|value| {
                if status_copy.sensors.is_absent() {
                    status_copy.sensors = Optional::Value(spaceapi::Sensors {
                        people_now_present: Optional::Absent,
                        temperature: Optional::Absent,
                    });
                }
                sensor_spec.template.to_sensor(&value,
                                               &mut status_copy.sensors.as_mut().unwrap());
            });
        }

        // Serialize to JSON
        status_copy.to_json()
    }

}

impl middleware::Handler for SpaceapiServer {

    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        // Get response body
        let body = self.build_response_json().to_string();

        // Create response
        let mut response = Response::with((status::Ok, body));

        // Set headers
        response.set_mut(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())));
        response.set_mut(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])));
        response.set_mut(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }
}

#[cfg(test)]
mod test {
    extern crate spaceapi;
    extern crate rustc_serialize;

    use std::net::Ipv4Addr;
    use std::sync::{Mutex,Arc};
    use rustc_serialize::json::Json;
    use spaceapi::utils::Optional;
    use super::SpaceapiServer;
    use super::datastore::{DataStore, RedisStore};

    fn get_test_data() -> Json {
        // Create minimal status object
        let status = spaceapi::Status::new(
            "ourspace".to_string(),
            "https://example.com/logo.png".to_string(),
            "https://example.com/".to_string(),
            spaceapi::Location {
                address: Optional::Value("Street 1, Zürich, Switzerland".to_string()),
                lat: 47.123,
                lon: 8.88,
            },
            spaceapi::Contact {
                irc: Optional::Absent,
                twitter: Optional::Absent,
                foursquare: Optional::Absent,
                email: Optional::Value("hi@example.com".to_string()),
            },
            vec![
                "email".to_string(),
                "twitter".to_string(),
            ],
        );

        // Create datastore (TODO: Create dummy store for testing?)
        let datastore = Arc::new(Mutex::new(Box::new(RedisStore::new().unwrap()) as Box<DataStore>));

        // Initialize server
        let server = SpaceapiServer::new(Ipv4Addr::new(127, 0, 0, 1), 3001, status, datastore);

        // Build JSON
        server.build_response_json()
    }

    #[test]
    /// Verify that the result is a JSON object.
    fn verify_json_obj() {
        let json = get_test_data();
        assert!(json.is_object());
    }

    #[test]
    /// Verify that the result has the correct keys.
    fn verify_json_keys() {
        let json = get_test_data();
        let status = json.as_object().unwrap();  // We get back a BTreeMap<String, Json>
        let keys: Vec<String> = status.keys().cloned().collect();  // Collect the keys
        assert_eq!(keys, ["api", "contact", "issue_report_channels", "location",
                          "logo", "space", "state", "url"]);
    }

    #[test]
    /// Verify static data
    fn verify_json_static_data() {
        let json = get_test_data();
        let status = json.as_object().unwrap();  // We get back a BTreeMap<String, Json>

        // Strings
        assert_eq!(status.get("api").unwrap().as_string().unwrap(), "0.13");
        assert_eq!(status.get("space").unwrap().as_string().unwrap(), "ourspace");
        assert_eq!(status.get("url").unwrap().as_string().unwrap(), "https://example.com/");
        assert_eq!(status.get("logo").unwrap().as_string().unwrap(), "https://example.com/logo.png");

        // Channels
        let channels: &Vec<Json> = status.get("issue_report_channels").unwrap().as_array().unwrap();
        let channel_values: Vec<String> = channels.iter()
                                                  .cloned()
                                                  .map(|c| c.as_string().unwrap().to_string())
                                                  .collect();
        assert_eq!(vec!["email", "twitter"], channel_values);
    }

    #[test]
    /// Verify location
    fn verify_json_location() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let location = status.get("location").unwrap().as_object().unwrap();

        // Verify data
        let address = location.get("address").unwrap().as_string().unwrap();
        assert_eq!("Street 1, Zürich, Switzerland".to_string(), address);
        assert_eq!(47.123, location.get("lat").unwrap().as_f64().unwrap());
        assert_eq!(8.88, location.get("lon").unwrap().as_f64().unwrap());
    }

    #[test]
    /// Verify contact
    fn verify_json_contact() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let contact = status.get("contact").unwrap().as_object().unwrap();

        // Verify data
        let email = contact.get("email").unwrap().as_string().unwrap();
        assert_eq!("hi@example.com".to_string(), email);
    }

    /* TODO: Update
    #[test]
    /// Verify sensor data
    fn verify_json_sensors() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let sensors = status.get("sensors").unwrap().as_object().unwrap();
        let temperature_sensor = sensors.get("temperature").unwrap()
                                        .as_array().unwrap()[0]  // List of sensors
                                        .as_object().unwrap();  // Sensor object
        let people_sensor = sensors.get("people_now_present").unwrap()  // List of sensors
                                        .as_array().unwrap()[0]  // Sensor object
                                        .as_object().unwrap();

        // Verify temperature sensor
        let temp_location = temperature_sensor.get("location").unwrap().as_string().unwrap();
        let temp_name = temperature_sensor.get("name").unwrap().as_string().unwrap();
        let temp_unit = temperature_sensor.get("unit").unwrap().as_string().unwrap();
        let temp_value = temperature_sensor.get("value").unwrap().as_f64().unwrap();
        assert_eq!("Basement".to_string(), temp_location);
        assert_eq!("Raspberry CPU".to_string(), temp_name);
        assert_eq!("°C".to_string(), temp_unit);
        assert_eq!(42.5, temp_value);

        // Verify peoplesensor
        let people_location = people_sensor.get("location").unwrap().as_string().unwrap();
        let people_value = people_sensor.get("value").unwrap().as_u64().unwrap();
        assert_eq!("Hackerspace".to_string(), people_location);
        assert_eq!(23, people_value);
    }
    */

}
<commit_msg>server: Update state.open according to people_now_present sensor<commit_after>//! The main entry point for the Space API server.
//!
//! Running this code starts a HTTP server instance. The default port is 3000, but you can set your
//! own favorite port by exporting the `PORT` environment variable.

extern crate rustc_serialize;
extern crate iron;
extern crate spaceapi;

pub mod datastore;
pub mod sensors;

use std::net::Ipv4Addr;

use rustc_serialize::json::{Json, ToJson};
use iron::{Request, Response, IronResult, Iron, Set};
use iron::{status, headers, middleware};
use iron::modifiers::Header;

pub use spaceapi as api;
use datastore::SafeDataStore;
use spaceapi::utils::Optional;
use spaceapi::SensorTemplate;

/// A Space API server instance.
///
/// You can create a new instance using the ``new`` constructor method by
/// passing it the host, the port, the ``Status`` object and a datastore.
///
/// The ``SpaceapiServer`` includes a web server through
/// [Hyper](http://hyper.rs/hyper/hyper/server/index.html). Simply call the ``serve`` method.
pub struct SpaceapiServer {
    host: Ipv4Addr,
    port: u16,
    status: api::Status,
    datastore: SafeDataStore,
    sensor_specs: Vec<sensors::SensorSpec>
}

impl SpaceapiServer {

    pub fn new(host: Ipv4Addr, port: u16, status: api::Status, datastore: SafeDataStore) -> SpaceapiServer {
        SpaceapiServer {
            host: host,
            port: port,
            status: status,
            datastore: datastore,
            sensor_specs: vec![],
        }
    }

    /// Start a HTTP server listening on ``self.host:self.port``.
    ///
    /// This call is blocking. It can be interrupted with SIGINT (Ctrl+C).
    pub fn serve(self) {
        let host = self.host;
        let port = self.port;
        println!("Starting HTTP server on http://{}:{}...", host, port);
        Iron::new(self).http((host, port)).unwrap();
    }

    /// Register a new sensor.
    ///
    /// The first argument is a ``api::SensorTemplate`` instance containing all static data.
    /// The second argument specifies how to get the actual sensor value from the datastore.
    /// And the third argument specifies the data type of the value.
    pub fn register_sensor(&mut self, template: Box<api::SensorTemplate>, data_key: String) {
        self.sensor_specs.push(
            sensors::SensorSpec { template: template, data_key: data_key}
        );
    }

    fn build_response_json(&self) -> Json {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in &self.sensor_specs {

            sensor_spec.get_sensor_value(&self.datastore).map(|value| {
                if status_copy.sensors.is_absent() {
                    status_copy.sensors = Optional::Value(spaceapi::Sensors {
                        people_now_present: Optional::Absent,
                        temperature: Optional::Absent,
                    });
                }
                sensor_spec.template.to_sensor(&value,
                                               &mut status_copy.sensors.as_mut().unwrap());
            });
        }

        status_copy.state.open = status_copy.sensors.as_ref()
            .and_then(|sensors| sensors.people_now_present.as_ref())
            .and_then(|people_now_present| {
                match people_now_present[0].value {
                    0i64 => Optional::Value(false),
                    _ => Optional::Value(true),
                }
            }).into();

        // Serialize to JSON
        status_copy.to_json()
    }

}

impl middleware::Handler for SpaceapiServer {

    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        // Get response body
        let body = self.build_response_json().to_string();

        // Create response
        let mut response = Response::with((status::Ok, body));

        // Set headers
        response.set_mut(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())));
        response.set_mut(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])));
        response.set_mut(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }
}

#[cfg(test)]
mod test {
    extern crate spaceapi;
    extern crate rustc_serialize;

    use std::net::Ipv4Addr;
    use std::sync::{Mutex,Arc};
    use rustc_serialize::json::Json;
    use spaceapi::utils::Optional;
    use super::SpaceapiServer;
    use super::datastore::{DataStore, RedisStore};

    fn get_test_data() -> Json {
        // Create minimal status object
        let status = spaceapi::Status::new(
            "ourspace".to_string(),
            "https://example.com/logo.png".to_string(),
            "https://example.com/".to_string(),
            spaceapi::Location {
                address: Optional::Value("Street 1, Zürich, Switzerland".to_string()),
                lat: 47.123,
                lon: 8.88,
            },
            spaceapi::Contact {
                irc: Optional::Absent,
                twitter: Optional::Absent,
                foursquare: Optional::Absent,
                email: Optional::Value("hi@example.com".to_string()),
            },
            vec![
                "email".to_string(),
                "twitter".to_string(),
            ],
        );

        // Create datastore (TODO: Create dummy store for testing?)
        let datastore = Arc::new(Mutex::new(Box::new(RedisStore::new().unwrap()) as Box<DataStore>));

        // Initialize server
        let server = SpaceapiServer::new(Ipv4Addr::new(127, 0, 0, 1), 3001, status, datastore);

        // Build JSON
        server.build_response_json()
    }

    #[test]
    /// Verify that the result is a JSON object.
    fn verify_json_obj() {
        let json = get_test_data();
        assert!(json.is_object());
    }

    #[test]
    /// Verify that the result has the correct keys.
    fn verify_json_keys() {
        let json = get_test_data();
        let status = json.as_object().unwrap();  // We get back a BTreeMap<String, Json>
        let keys: Vec<String> = status.keys().cloned().collect();  // Collect the keys
        assert_eq!(keys, ["api", "contact", "issue_report_channels", "location",
                          "logo", "space", "state", "url"]);
    }

    #[test]
    /// Verify static data
    fn verify_json_static_data() {
        let json = get_test_data();
        let status = json.as_object().unwrap();  // We get back a BTreeMap<String, Json>

        // Strings
        assert_eq!(status.get("api").unwrap().as_string().unwrap(), "0.13");
        assert_eq!(status.get("space").unwrap().as_string().unwrap(), "ourspace");
        assert_eq!(status.get("url").unwrap().as_string().unwrap(), "https://example.com/");
        assert_eq!(status.get("logo").unwrap().as_string().unwrap(), "https://example.com/logo.png");

        // Channels
        let channels: &Vec<Json> = status.get("issue_report_channels").unwrap().as_array().unwrap();
        let channel_values: Vec<String> = channels.iter()
                                                  .cloned()
                                                  .map(|c| c.as_string().unwrap().to_string())
                                                  .collect();
        assert_eq!(vec!["email", "twitter"], channel_values);
    }

    #[test]
    /// Verify location
    fn verify_json_location() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let location = status.get("location").unwrap().as_object().unwrap();

        // Verify data
        let address = location.get("address").unwrap().as_string().unwrap();
        assert_eq!("Street 1, Zürich, Switzerland".to_string(), address);
        assert_eq!(47.123, location.get("lat").unwrap().as_f64().unwrap());
        assert_eq!(8.88, location.get("lon").unwrap().as_f64().unwrap());
    }

    #[test]
    /// Verify contact
    fn verify_json_contact() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let contact = status.get("contact").unwrap().as_object().unwrap();

        // Verify data
        let email = contact.get("email").unwrap().as_string().unwrap();
        assert_eq!("hi@example.com".to_string(), email);
    }

    /* TODO: Update
    #[test]
    /// Verify sensor data
    fn verify_json_sensors() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let sensors = status.get("sensors").unwrap().as_object().unwrap();
        let temperature_sensor = sensors.get("temperature").unwrap()
                                        .as_array().unwrap()[0]  // List of sensors
                                        .as_object().unwrap();  // Sensor object
        let people_sensor = sensors.get("people_now_present").unwrap()  // List of sensors
                                        .as_array().unwrap()[0]  // Sensor object
                                        .as_object().unwrap();

        // Verify temperature sensor
        let temp_location = temperature_sensor.get("location").unwrap().as_string().unwrap();
        let temp_name = temperature_sensor.get("name").unwrap().as_string().unwrap();
        let temp_unit = temperature_sensor.get("unit").unwrap().as_string().unwrap();
        let temp_value = temperature_sensor.get("value").unwrap().as_f64().unwrap();
        assert_eq!("Basement".to_string(), temp_location);
        assert_eq!("Raspberry CPU".to_string(), temp_name);
        assert_eq!("°C".to_string(), temp_unit);
        assert_eq!(42.5, temp_value);

        // Verify peoplesensor
        let people_location = people_sensor.get("location").unwrap().as_string().unwrap();
        let people_value = people_sensor.get("value").unwrap().as_u64().unwrap();
        assert_eq!("Hackerspace".to_string(), people_location);
        assert_eq!(23, people_value);
    }
    */

}
<|endoftext|>


<commit_before>use std::hashmap::HashMap;
use module::{Type, TypeVariable, TypeOperator, Expr, Identifier, Number, Apply, Lambda, Let, Case, Typed, Alternative, Module, Class, Instance, Binding, DataDefinition, Constructor, TypeDeclaration,
    Pattern, ConstructorPattern, NumberPattern, IdentifierPattern};
use Scope;

#[cfg(test)]
use parser::Parser;
#[cfg(test)]
use typecheck::{identifier, apply, number, lambda, let_};

#[deriving(Eq)]
pub enum Instruction {
    Add,
    Sub,
    Multiply,
    Divide,
    Remainder,
    Push(int),
    PushGlobal(int),
    PushInt(int),
    Mkap,
    Eval,
    Unwind,
    Update(int),
    Pop(int),
    Slide(uint),
    Split(uint),
    Pack(u16, u16),
    CaseJump(uint),
    Jump(uint)
}

enum Var {
    StackVariable(int),
    GlobalVariable(int),
    ConstructorVariable(u16, u16)
}

pub struct SuperCombinator {
    arity : int,
    instructions : ~[Instruction]
}
impl SuperCombinator {
    fn new() -> SuperCombinator {
        SuperCombinator { arity : 0, instructions : ~[] }
    }
}

pub struct Assembly {
    superCombinators: ~[(~str, SuperCombinator)]
}

impl Assembly {
    fn find(&self, name: &str) -> Option<Var> {
        let mut index = 0;
        for &(ref n, _) in self.superCombinators.iter() {
            if name == *n {
                return Some(GlobalVariable(index));
            }
            index += 1;
        }
        return None;
    }
}

pub struct Compiler {
    stackSize : int,
    globals : HashMap<~str, SuperCombinator>,
    variables: HashMap<~str, Var>,
    globalIndex : int
}

impl Compiler {
    pub fn new() -> Compiler {
        let mut variables = HashMap::new();
        variables.insert(~"[]", ConstructorVariable(0, 0));
        variables.insert(~":", ConstructorVariable(1, 2));
        Compiler { stackSize : 0, globals : HashMap::new(), globalIndex : 0, variables: variables }
    }

    pub fn compileModule(&mut self, module : &Module) -> Assembly {
        //TODO
        let mut superCombinators = ~[];
        for bind in module.bindings.iter() {
            self.variables.insert(bind.name.clone(), GlobalVariable(self.globalIndex));
            self.globalIndex += 1;
            let sc = self.compileBinding(bind.arity, &bind.expression);
            superCombinators.push((bind.name.clone(), sc));
        }
        Assembly { superCombinators: superCombinators }
    }
    fn compileBinding<'a>(&mut self, arity : int, expr : &Typed<Expr>) -> SuperCombinator {

        let mut comb = SuperCombinator::new();
        comb.arity = arity;
        let mut stack = CompilerNode { compiler: self, stack: Scope::new() };
        match &expr.expr {
            &Lambda(_, _) => {
                stack.compile(expr, &mut comb.instructions, false);
                comb.instructions.push(Update(0));
                comb.instructions.push(Pop(comb.arity));
                comb.instructions.push(Unwind);
            }
            _ => {
                stack.compile(expr, &mut comb.instructions, false);
                comb.instructions.push(Update(0));
                comb.instructions.push(Unwind);
            }
       }
       comb
    }
    pub fn compileExpression(&mut self, expr: &Typed<Expr>) -> ~[Instruction] {
        let mut stack = CompilerNode { compiler: self, stack: Scope::new() };
        let mut instructions = ~[];
        stack.compile(expr, &mut instructions, false);
        instructions
    }

}

struct CompilerNode<'a> {
    stack: Scope<'a, Var>,
    compiler: &'a mut Compiler
}

//CompilerNode are only used locally and the destructor are just to reduce the stack size
//so this should be safe(?)
#[unsafe_destructor]
impl <'a> Drop for CompilerNode<'a> {
    fn drop(&mut self) {
        self.compiler.stackSize -= self.stack.variables.len() as int;
    }
}

impl <'a> CompilerNode<'a> {

    fn find(&'a self, identifier : &str) -> Option<&'a Var> {
       match self.stack.find(identifier) {
            Some(var) => Some(var),
            None => self.compiler.variables.find_equiv(&identifier)
        }
    }

    fn newStackVar(&mut self, identifier : ~str) {
        self.stack.insert(identifier, StackVariable(self.compiler.stackSize));
        self.compiler.stackSize += 1;
    }

    fn child(&'a self) -> CompilerNode<'a> {
        CompilerNode { compiler: self.compiler, stack : self.stack.child() }
    }

    fn compile<'a>(&mut self, expr : &Typed<Expr>, instructions : &mut ~[Instruction], strict: bool) {
        match &expr.expr {
            &Identifier(ref name) => {
                match self.find(*name) {
                    None => fail!("Undefined variable " + *name),
                    Some(var) => {
                        match var {
                            &StackVariable(index) => instructions.push(Push(index)),
                            &GlobalVariable(index) => instructions.push(PushGlobal(index)),
                            &ConstructorVariable(tag, arity) => instructions.push(Pack(tag, arity))
                        }
                    }
                }
            }
            &Number(num) => instructions.push(PushInt(num)),
            &Apply(ref func, ref arg) => {
                if !self.primitive(*func, *arg, instructions) {
                    self.compile(*arg, instructions, false);
                    self.compile(*func, instructions, strict);
                    match &instructions[instructions.len() - 1] {
                        &Pack(_, _) => (),//The function was only the pack instruction so to do Mkap
                        _ => instructions.push(Mkap)
                    }
                    if strict {
                        instructions.push(Eval);
                    }
                }
            }
            &Lambda(ref varname, ref body) => {
                self.newStackVar(varname.clone());
                self.compile(*body, instructions, false);
            }
            &Let(ref bindings, ref body) => {
                for bind in bindings.iter() {
                    self.newStackVar(bind.name.clone());
                    self.compile(&bind.expression, instructions, false);
                }
                self.compile(*body, instructions, strict);
                instructions.push(Slide(bindings.len()));
            }
            &Case(ref body, ref alternatives) => {
                self.compile(*body, instructions, strict);
                self.newStackVar(~"");//Dummy variable for the case expression
                let mut branches = ~[];
                for alt in alternatives.iter() {
                    self.compile_pattern(&alt.pattern, &mut branches, instructions);
                }
                self.compiler.stackSize -= 1;
                for i in range(0, alternatives.len()) {
                    let alt = &alternatives[i];

                    //Set the jump instruction to jump to this place
                    instructions[branches[i]] = Jump(instructions.len());

                    let mut childScope = self.child();
                    let num_vars = childScope.add_pattern_variables(&alt.pattern, instructions);
                    childScope.compile(&alt.expression, instructions, strict);
                    instructions.push(Slide(num_vars));

                    //Reuse branches for the next Jump
                    branches[i] = instructions.len();
                    instructions.push(Jump(0));
                }
                for branch in branches.iter() {
                    instructions[*branch] = Jump(instructions.len());
                }
                if strict {
                    instructions.push(Eval);
                }
            }
        }
    }

    fn primitive(&mut self, func: &Typed<Expr>, arg: &Typed<Expr>, instructions: &mut ~[Instruction]) -> bool {
        match &func.expr {
            &Apply(ref prim_func, ref arg2) => {
                match &prim_func.expr {
                    &Identifier(ref name) => {
                        let maybeOP = match *name {
                            ~"primIntAdd" => Some(Add),
                            ~"primIntSubtract" => Some(Sub),
                            ~"primIntMultiply" => Some(Multiply),
                            ~"primIntDivide" => Some(Divide),
                            ~"primIntRemainder" => Some(Remainder),
                            _ => None
                        };
                        match maybeOP {
                            Some(op) => {
                                self.compile(*arg2, instructions, true);
                                self.compile(arg, instructions, true);
                                instructions.push(op);
                                true
                            }
                            None => false
                        }
                    }
                    _ => false
                }
            }
            _ => false
        }
    }

    fn compile_pattern(&self, pattern: &Pattern, branches: &mut ~[uint], instructions: &mut ~[Instruction]) {
        //TODO this is unlikely to work with nested patterns currently
        match pattern {
            &ConstructorPattern(ref name, ref patterns) => {
                match self.find(*name) {
                    Some(&ConstructorVariable(tag, _)) => {
                        instructions.push(CaseJump(tag as uint));
                        branches.push(instructions.len());
                        instructions.push(Jump(0));//To be determined later
                    }
                    _ => fail!("Undefined constructor {}", *name)
                }
                for p in patterns.iter() {
                    self.compile_pattern(p, branches, instructions);
                }
            }
            _ => ()
        }
    }

    fn add_pattern_variables(&mut self, pattern: &Pattern, instructions: &mut ~[Instruction]) -> uint {
        match pattern {
            &ConstructorPattern(_, ref patterns) => {
                instructions.push(Split(patterns.len()));
                let mut vars = 0;
                for p in patterns.iter() {
                    vars += self.add_pattern_variables(p, instructions);
                }
                vars
            }
            &IdentifierPattern(ref ident) => {
                self.newStackVar(ident.clone());
                1
            }
            &NumberPattern(_) => 0
        }
    }
}

#[test]
fn test_add() {
    let e = apply(apply(identifier(~"primIntAdd"), number(1)), number(2));
    let mut comp = Compiler::new();
    let instr = comp.compileExpression(&e);

    assert_eq!(instr, ~[PushInt(1), PushInt(2), Add]);
}

#[test]
fn test_apply() {
    let file =
r"add x y = primIntAdd x y
main = add 2 3";
    let mut parser = Parser::new(file.chars());
    let module = parser.module();
    let mut comp = Compiler::new();
    let assembly = comp.compileModule(&module);

    assert_eq!(assembly.superCombinators[1].n1().instructions, ~[PushInt(3), PushInt(2), PushGlobal(0), Mkap, Mkap, Update(0), Unwind]);
}

#[test]
fn test_compile_constructor() {
    let file =
r"1 : []";
    let mut parser = Parser::new(file.chars());
    let expr = parser.expression_();
    let mut comp = Compiler::new();
    let instructions = comp.compileExpression(&expr);

    assert_eq!(instructions, ~[Pack(0, 0), PushInt(1), Pack(1, 2)]);
}

#[test]
fn test_compile_case() {
    let file =
r"case [1] of
    : x xs -> x
    [] -> 2";
    let mut parser = Parser::new(file.chars());
    let expr = parser.expression_();
    let mut comp = Compiler::new();
    let instructions = comp.compileExpression(&expr);

    assert_eq!(instructions, ~[Pack(0, 0), PushInt(1), Pack(1, 2),
        CaseJump(1), Jump(7),
        CaseJump(0), Jump(11),
        Split(2), Push(1), Slide(2), Jump(15),
        Split(0), PushInt(2), Slide(0), Jump(15)]);
}
<commit_msg>Fixed the case compilation test<commit_after>use std::hashmap::HashMap;
use module::{Type, TypeVariable, TypeOperator, Expr, Identifier, Number, Apply, Lambda, Let, Case, Typed, Alternative, Module, Class, Instance, Binding, DataDefinition, Constructor, TypeDeclaration,
    Pattern, ConstructorPattern, NumberPattern, IdentifierPattern};
use Scope;

#[cfg(test)]
use parser::Parser;
#[cfg(test)]
use typecheck::{identifier, apply, number, lambda, let_};

#[deriving(Eq)]
pub enum Instruction {
    Add,
    Sub,
    Multiply,
    Divide,
    Remainder,
    Push(int),
    PushGlobal(int),
    PushInt(int),
    Mkap,
    Eval,
    Unwind,
    Update(int),
    Pop(int),
    Slide(uint),
    Split(uint),
    Pack(u16, u16),
    CaseJump(uint),
    Jump(uint)
}

enum Var {
    StackVariable(int),
    GlobalVariable(int),
    ConstructorVariable(u16, u16)
}

pub struct SuperCombinator {
    arity : int,
    instructions : ~[Instruction]
}
impl SuperCombinator {
    fn new() -> SuperCombinator {
        SuperCombinator { arity : 0, instructions : ~[] }
    }
}

pub struct Assembly {
    superCombinators: ~[(~str, SuperCombinator)]
}

impl Assembly {
    fn find(&self, name: &str) -> Option<Var> {
        let mut index = 0;
        for &(ref n, _) in self.superCombinators.iter() {
            if name == *n {
                return Some(GlobalVariable(index));
            }
            index += 1;
        }
        return None;
    }
}

pub struct Compiler {
    stackSize : int,
    globals : HashMap<~str, SuperCombinator>,
    variables: HashMap<~str, Var>,
    globalIndex : int
}

impl Compiler {
    pub fn new() -> Compiler {
        let mut variables = HashMap::new();
        variables.insert(~"[]", ConstructorVariable(0, 0));
        variables.insert(~":", ConstructorVariable(1, 2));
        Compiler { stackSize : 0, globals : HashMap::new(), globalIndex : 0, variables: variables }
    }

    pub fn compileModule(&mut self, module : &Module) -> Assembly {
        //TODO
        let mut superCombinators = ~[];
        for bind in module.bindings.iter() {
            self.variables.insert(bind.name.clone(), GlobalVariable(self.globalIndex));
            self.globalIndex += 1;
            let sc = self.compileBinding(bind.arity, &bind.expression);
            superCombinators.push((bind.name.clone(), sc));
        }
        Assembly { superCombinators: superCombinators }
    }
    fn compileBinding<'a>(&mut self, arity : int, expr : &Typed<Expr>) -> SuperCombinator {

        let mut comb = SuperCombinator::new();
        comb.arity = arity;
        let mut stack = CompilerNode { compiler: self, stack: Scope::new() };
        match &expr.expr {
            &Lambda(_, _) => {
                stack.compile(expr, &mut comb.instructions, false);
                comb.instructions.push(Update(0));
                comb.instructions.push(Pop(comb.arity));
                comb.instructions.push(Unwind);
            }
            _ => {
                stack.compile(expr, &mut comb.instructions, false);
                comb.instructions.push(Update(0));
                comb.instructions.push(Unwind);
            }
       }
       comb
    }
    pub fn compileExpression(&mut self, expr: &Typed<Expr>) -> ~[Instruction] {
        let mut stack = CompilerNode { compiler: self, stack: Scope::new() };
        let mut instructions = ~[];
        stack.compile(expr, &mut instructions, false);
        instructions
    }

}

struct CompilerNode<'a> {
    stack: Scope<'a, Var>,
    compiler: &'a mut Compiler
}

//CompilerNode are only used locally and the destructor are just to reduce the stack size
//so this should be safe(?)
#[unsafe_destructor]
impl <'a> Drop for CompilerNode<'a> {
    fn drop(&mut self) {
        self.compiler.stackSize -= self.stack.variables.len() as int;
    }
}

impl <'a> CompilerNode<'a> {

    fn find(&'a self, identifier : &str) -> Option<&'a Var> {
       match self.stack.find(identifier) {
            Some(var) => Some(var),
            None => self.compiler.variables.find_equiv(&identifier)
        }
    }

    fn newStackVar(&mut self, identifier : ~str) {
        self.stack.insert(identifier, StackVariable(self.compiler.stackSize));
        self.compiler.stackSize += 1;
    }

    fn child(&'a self) -> CompilerNode<'a> {
        CompilerNode { compiler: self.compiler, stack : self.stack.child() }
    }

    fn compile<'a>(&mut self, expr : &Typed<Expr>, instructions : &mut ~[Instruction], strict: bool) {
        match &expr.expr {
            &Identifier(ref name) => {
                match self.find(*name) {
                    None => fail!("Undefined variable " + *name),
                    Some(var) => {
                        match var {
                            &StackVariable(index) => instructions.push(Push(index)),
                            &GlobalVariable(index) => instructions.push(PushGlobal(index)),
                            &ConstructorVariable(tag, arity) => instructions.push(Pack(tag, arity))
                        }
                    }
                }
            }
            &Number(num) => instructions.push(PushInt(num)),
            &Apply(ref func, ref arg) => {
                if !self.primitive(*func, *arg, instructions) {
                    self.compile(*arg, instructions, false);
                    self.compile(*func, instructions, strict);
                    match &instructions[instructions.len() - 1] {
                        &Pack(_, _) => (),//The function was only the pack instruction so to do Mkap
                        _ => instructions.push(Mkap)
                    }
                    if strict {
                        instructions.push(Eval);
                    }
                }
            }
            &Lambda(ref varname, ref body) => {
                self.newStackVar(varname.clone());
                self.compile(*body, instructions, false);
            }
            &Let(ref bindings, ref body) => {
                for bind in bindings.iter() {
                    self.newStackVar(bind.name.clone());
                    self.compile(&bind.expression, instructions, false);
                }
                self.compile(*body, instructions, strict);
                instructions.push(Slide(bindings.len()));
            }
            &Case(ref body, ref alternatives) => {
                self.compile(*body, instructions, strict);
                self.newStackVar(~"");//Dummy variable for the case expression
                let mut branches = ~[];
                for alt in alternatives.iter() {
                    self.compile_pattern(&alt.pattern, &mut branches, instructions);
                }
                self.compiler.stackSize -= 1;
                for i in range(0, alternatives.len()) {
                    let alt = &alternatives[i];

                    //Set the jump instruction to jump to this place
                    instructions[branches[i]] = Jump(instructions.len());

                    let mut childScope = self.child();
                    let num_vars = childScope.add_pattern_variables(&alt.pattern, instructions);
                    childScope.compile(&alt.expression, instructions, strict);
                    instructions.push(Slide(num_vars));

                    //Reuse branches for the next Jump
                    branches[i] = instructions.len();
                    instructions.push(Jump(0));
                }
                for branch in branches.iter() {
                    instructions[*branch] = Jump(instructions.len());
                }
                if strict {
                    instructions.push(Eval);
                }
            }
        }
    }

    fn primitive(&mut self, func: &Typed<Expr>, arg: &Typed<Expr>, instructions: &mut ~[Instruction]) -> bool {
        match &func.expr {
            &Apply(ref prim_func, ref arg2) => {
                match &prim_func.expr {
                    &Identifier(ref name) => {
                        let maybeOP = match *name {
                            ~"primIntAdd" => Some(Add),
                            ~"primIntSubtract" => Some(Sub),
                            ~"primIntMultiply" => Some(Multiply),
                            ~"primIntDivide" => Some(Divide),
                            ~"primIntRemainder" => Some(Remainder),
                            _ => None
                        };
                        match maybeOP {
                            Some(op) => {
                                self.compile(*arg2, instructions, true);
                                self.compile(arg, instructions, true);
                                instructions.push(op);
                                true
                            }
                            None => false
                        }
                    }
                    _ => false
                }
            }
            _ => false
        }
    }

    fn compile_pattern(&self, pattern: &Pattern, branches: &mut ~[uint], instructions: &mut ~[Instruction]) {
        //TODO this is unlikely to work with nested patterns currently
        match pattern {
            &ConstructorPattern(ref name, ref patterns) => {
                match self.find(*name) {
                    Some(&ConstructorVariable(tag, _)) => {
                        instructions.push(CaseJump(tag as uint));
                        branches.push(instructions.len());
                        instructions.push(Jump(0));//To be determined later
                    }
                    _ => fail!("Undefined constructor {}", *name)
                }
                for p in patterns.iter() {
                    self.compile_pattern(p, branches, instructions);
                }
            }
            _ => ()
        }
    }

    fn add_pattern_variables(&mut self, pattern: &Pattern, instructions: &mut ~[Instruction]) -> uint {
        match pattern {
            &ConstructorPattern(_, ref patterns) => {
                instructions.push(Split(patterns.len()));
                let mut vars = 0;
                for p in patterns.iter() {
                    vars += self.add_pattern_variables(p, instructions);
                }
                vars
            }
            &IdentifierPattern(ref ident) => {
                self.newStackVar(ident.clone());
                1
            }
            &NumberPattern(_) => 0
        }
    }
}

#[test]
fn test_add() {
    let e = apply(apply(identifier(~"primIntAdd"), number(1)), number(2));
    let mut comp = Compiler::new();
    let instr = comp.compileExpression(&e);

    assert_eq!(instr, ~[PushInt(1), PushInt(2), Add]);
}

#[test]
fn test_apply() {
    let file =
r"add x y = primIntAdd x y
main = add 2 3";
    let mut parser = Parser::new(file.chars());
    let module = parser.module();
    let mut comp = Compiler::new();
    let assembly = comp.compileModule(&module);

    assert_eq!(assembly.superCombinators[1].n1().instructions, ~[PushInt(3), PushInt(2), PushGlobal(0), Mkap, Mkap, Update(0), Unwind]);
}

#[test]
fn test_compile_constructor() {
    let file =
r"1 : []";
    let mut parser = Parser::new(file.chars());
    let expr = parser.expression_();
    let mut comp = Compiler::new();
    let instructions = comp.compileExpression(&expr);

    assert_eq!(instructions, ~[Pack(0, 0), PushInt(1), Pack(1, 2)]);
}

#[test]
fn test_compile_case() {
    let file =
r"case [1] of
    : x xs -> x
    [] -> 2";
    let mut parser = Parser::new(file.chars());
    let expr = parser.expression_();
    let mut comp = Compiler::new();
    let instructions = comp.compileExpression(&expr);

    assert_eq!(instructions, ~[Pack(0, 0), PushInt(1), Pack(1, 2),
        CaseJump(1), Jump(7),
        CaseJump(0), Jump(11),
        Split(2), Push(0), Slide(2), Jump(15),
        Split(0), PushInt(2), Slide(0), Jump(15)]);
}
<|endoftext|>


<commit_before>use Printer;

use direction::Direction;
use event::{Event, EventResult};
use std::any::Any;
use theme::ColorStyle;
use vec::Vec2;
use view::{Offset, Position, Selector, View};
use views::{Layer, ShadowView};

/// Simple stack of views.
/// Only the top-most view is active and can receive input.
pub struct StackView {
    layers: Vec<Child>,
    last_size: Vec2,
}

enum Placement {
    Floating(Position),
    Fullscreen,
}

impl Placement {
    pub fn compute_offset<S, A, P>(&self, size: S, available: A, parent: P)
                                   -> Vec2
        where S: Into<Vec2>,
              A: Into<Vec2>,
              P: Into<Vec2>
    {
        match *self {
            Placement::Floating(ref position) => {
                position.compute_offset(size, available, parent)
            }
            Placement::Fullscreen => Vec2::zero(),
        }
    }
}

struct Child {
    view: Box<View>,
    size: Vec2,
    placement: Placement,

    // We cannot call `take_focus` until we've called `layout()`
    // So we want to call `take_focus` right after the first call
    // to `layout`; this flag remembers when we've done that.
    virgin: bool,
}

new_default!(StackView);

impl StackView {
    /// Creates a new empty StackView
    pub fn new() -> Self {
        StackView {
            layers: Vec::new(),
            last_size: Vec2::zero(),
        }
    }

    /// Adds a new full-screen layer on top of the stack.
    ///
    /// Fullscreen layers have no shadow.
    pub fn add_fullscreen_layer<T>(&mut self, view: T)
        where T: 'static + View
    {
        self.layers.push(Child {
            view: Box::new(Layer::new(view)),
            size: Vec2::zero(),
            placement: Placement::Fullscreen,
            virgin: true,
        });
    }

    /// Adds new view on top of the stack in the center of the screen.
    pub fn add_layer<T>(&mut self, view: T)
        where T: 'static + View
    {
        self.add_layer_at(Position::center(), view);
    }

    /// Adds a view on top of the stack.
    pub fn add_layer_at<T>(&mut self, position: Position, view: T)
        where T: 'static + View
    {
        self.layers.push(Child {
            // Skip padding for absolute/parent-placed views
            view: Box::new(ShadowView::new(Layer::new(view))
                .top_padding(position.y == Offset::Center)
                .left_padding(position.x == Offset::Center)),
            size: Vec2::new(0, 0),
            placement: Placement::Floating(position),
            virgin: true,
        });
    }

    /// Remove the top-most layer.
    pub fn pop_layer(&mut self) {
        self.layers.pop();
    }

    /// Computes the offset of the current top view.
    pub fn offset(&self) -> Vec2 {
        let mut previous = Vec2::zero();
        for layer in &self.layers {
            let offset = layer.placement
                .compute_offset(layer.size, self.last_size, previous);
            previous = offset;
        }
        previous
    }

    /// Returns the size for each layer in this view.
    pub fn layer_sizes(&self) -> Vec<Vec2> {
        self.layers.iter().map(|layer| layer.size).collect()
    }
}

impl View for StackView {
    fn draw(&self, printer: &Printer) {
        let last = self.layers.len();
        let mut previous = Vec2::zero();
        printer.with_color(ColorStyle::Primary, |printer| {
            for (i, v) in self.layers.iter().enumerate() {
                // Place the view
                // Center the view
                let offset = v.placement
                    .compute_offset(v.size, printer.size, previous);

                previous = offset;
                v.view
                    .draw(&printer.sub_printer(offset, v.size, i + 1 == last));
            }
        });
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        match self.layers.last_mut() {
            None => EventResult::Ignored,
            Some(v) => v.view.on_event(event),
        }
    }

    fn layout(&mut self, size: Vec2) {
        self.last_size = size;

        // The call has been made, we can't ask for more space anymore.
        // Let's make do with what we have.

        for layer in &mut self.layers {
            // Give each guy what he asks for, within the budget constraints.
            let size = Vec2::min(size, layer.view.required_size(size));
            layer.size = size;
            layer.view.layout(layer.size);

            // We need to call `layout()` on the view before giving it focus
            // for the first time. Otherwise it will not be properly set up.
            // Ex: examples/lorem.rs: the text view takes focus because it's
            // scrolling, but it only knows that after a call to `layout()`.
            if layer.virgin {
                layer.view.take_focus(Direction::none());
                layer.virgin = false;
            }
        }
    }

    fn required_size(&mut self, size: Vec2) -> Vec2 {
        // The min size is the max of all children's

        self.layers
            .iter_mut()
            .map(|layer| layer.view.required_size(size))
            .fold(Vec2::new(1, 1), Vec2::max)
    }

    fn take_focus(&mut self, source: Direction) -> bool {
        match self.layers.last_mut() {
            None => false,
            Some(mut v) => v.view.take_focus(source),
        }
    }

    fn call_on_any<'a>(&mut self, selector: &Selector,
                    mut callback: Box<FnMut(&mut Any) + 'a>) {
        for layer in &mut self.layers {
            layer.view.call_on_any(selector, Box::new(|any| callback(any)));
        }
    }

    fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
        for layer in &mut self.layers {
            if layer.view.focus_view(selector).is_ok() {
                return Ok(());
            }
        }

        Err(())
    }
}
<commit_msg>Add chainable methods for `StackView`<commit_after>use Printer;

use ::With;
use direction::Direction;
use event::{Event, EventResult};
use std::any::Any;
use theme::ColorStyle;
use vec::Vec2;
use view::{Offset, Position, Selector, View};
use views::{Layer, ShadowView};

/// Simple stack of views.
/// Only the top-most view is active and can receive input.
pub struct StackView {
    layers: Vec<Child>,
    last_size: Vec2,
}

enum Placement {
    Floating(Position),
    Fullscreen,
}

impl Placement {
    pub fn compute_offset<S, A, P>(&self, size: S, available: A, parent: P)
                                   -> Vec2
        where S: Into<Vec2>,
              A: Into<Vec2>,
              P: Into<Vec2>
    {
        match *self {
            Placement::Floating(ref position) => {
                position.compute_offset(size, available, parent)
            }
            Placement::Fullscreen => Vec2::zero(),
        }
    }
}

struct Child {
    view: Box<View>,
    size: Vec2,
    placement: Placement,

    // We cannot call `take_focus` until we've called `layout()`
    // So we want to call `take_focus` right after the first call
    // to `layout`; this flag remembers when we've done that.
    virgin: bool,
}

new_default!(StackView);

impl StackView {
    /// Creates a new empty StackView
    pub fn new() -> Self {
        StackView {
            layers: Vec::new(),
            last_size: Vec2::zero(),
        }
    }

    /// Adds a new full-screen layer on top of the stack.
    ///
    /// Fullscreen layers have no shadow.
    pub fn add_fullscreen_layer<T>(&mut self, view: T)
        where T: 'static + View
    {
        self.layers.push(Child {
            view: Box::new(Layer::new(view)),
            size: Vec2::zero(),
            placement: Placement::Fullscreen,
            virgin: true,
        });
    }

    /// Adds new view on top of the stack in the center of the screen.
    pub fn add_layer<T>(&mut self, view: T)
        where T: 'static + View
    {
        self.add_layer_at(Position::center(), view);
    }

    /// Adds new view on top of the stack in the center of the screen.
    ///
    /// Chainable variant.
    pub fn layer<T>(self, view: T) -> Self
        where T: 'static + View
    {
        self.with(|s| s.add_layer(view))
    }

    /// Adds a new full-screen layer on top of the stack.
    ///
    /// Chainable variant.
    pub fn fullscreen_layer<T>(self, view: T) -> Self
        where T: 'static + View
    {
        self.with(|s| s.add_fullscreen_layer(view))
    }

    /// Adds a view on top of the stack.
    pub fn add_layer_at<T>(&mut self, position: Position, view: T)
        where T: 'static + View
    {
        self.layers.push(Child {
            // Skip padding for absolute/parent-placed views
            view: Box::new(ShadowView::new(Layer::new(view))
                .top_padding(position.y == Offset::Center)
                .left_padding(position.x == Offset::Center)),
            size: Vec2::new(0, 0),
            placement: Placement::Floating(position),
            virgin: true,
        });
    }

    /// Adds a view on top of the stack.
    ///
    /// Chainable variant.
    pub fn layer_at<T>(self, position: Position, view: T) -> Self
        where T: 'static + View
    {
        self.with(|s| s.add_layer_at(position, view))
    }

    /// Remove the top-most layer.
    pub fn pop_layer(&mut self) {
        self.layers.pop();
    }

    /// Computes the offset of the current top view.
    pub fn offset(&self) -> Vec2 {
        let mut previous = Vec2::zero();
        for layer in &self.layers {
            let offset = layer.placement
                .compute_offset(layer.size, self.last_size, previous);
            previous = offset;
        }
        previous
    }

    /// Returns the size for each layer in this view.
    pub fn layer_sizes(&self) -> Vec<Vec2> {
        self.layers.iter().map(|layer| layer.size).collect()
    }
}

impl View for StackView {
    fn draw(&self, printer: &Printer) {
        let last = self.layers.len();
        let mut previous = Vec2::zero();
        printer.with_color(ColorStyle::Primary, |printer| {
            for (i, v) in self.layers.iter().enumerate() {
                // Place the view
                // Center the view
                let offset = v.placement
                    .compute_offset(v.size, printer.size, previous);

                previous = offset;
                v.view
                    .draw(&printer.sub_printer(offset, v.size, i + 1 == last));
            }
        });
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        match self.layers.last_mut() {
            None => EventResult::Ignored,
            Some(v) => v.view.on_event(event),
        }
    }

    fn layout(&mut self, size: Vec2) {
        self.last_size = size;

        // The call has been made, we can't ask for more space anymore.
        // Let's make do with what we have.

        for layer in &mut self.layers {
            // Give each guy what he asks for, within the budget constraints.
            let size = Vec2::min(size, layer.view.required_size(size));
            layer.size = size;
            layer.view.layout(layer.size);

            // We need to call `layout()` on the view before giving it focus
            // for the first time. Otherwise it will not be properly set up.
            // Ex: examples/lorem.rs: the text view takes focus because it's
            // scrolling, but it only knows that after a call to `layout()`.
            if layer.virgin {
                layer.view.take_focus(Direction::none());
                layer.virgin = false;
            }
        }
    }

    fn required_size(&mut self, size: Vec2) -> Vec2 {
        // The min size is the max of all children's

        self.layers
            .iter_mut()
            .map(|layer| layer.view.required_size(size))
            .fold(Vec2::new(1, 1), Vec2::max)
    }

    fn take_focus(&mut self, source: Direction) -> bool {
        match self.layers.last_mut() {
            None => false,
            Some(mut v) => v.view.take_focus(source),
        }
    }

    fn call_on_any<'a>(&mut self, selector: &Selector,
                    mut callback: Box<FnMut(&mut Any) + 'a>) {
        for layer in &mut self.layers {
            layer.view.call_on_any(selector, Box::new(|any| callback(any)));
        }
    }

    fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
        for layer in &mut self.layers {
            if layer.view.focus_view(selector).is_ok() {
                return Ok(());
            }
        }

        Err(())
    }
}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Visualize_a_tree

extern crate rand;
extern crate rustc_serialize;
extern crate term_painter;

use rand::Rng;
use rustc_serialize::json;
use std::cmp::Ordering;
use std::env;
use std::fmt::{Debug, Display, Formatter, Result};
use term_painter::ToStyle;
use term_painter::Color::*;

type NodePtr = Option<usize>;

#[derive(Debug, PartialEq, Clone, Copy)]
enum Side {
    Left,
    Right,
    Up,
}

#[derive(Debug, PartialEq, Clone, Copy)]
enum DisplayElement {
    TrunkSpace,
    SpaceLeft,
    SpaceRight,
    SpaceSpace,
    Root,
}

impl DisplayElement {
    fn string(&self) -> String {
        match *self {
            DisplayElement::TrunkSpace => "    │   ".to_string(),
            DisplayElement::SpaceRight => "    ┌───".to_string(),
            DisplayElement::SpaceLeft => "    └───".to_string(),
            DisplayElement::SpaceSpace => "        ".to_string(),
            DisplayElement::Root => "├──".to_string(),
        }
    }
}

#[derive(Debug, Clone, Copy, RustcDecodable, RustcEncodable)]
struct Node<K, V> {
    key: K,
    value: V,
    left: NodePtr,
    right: NodePtr,
    up: NodePtr,
}

impl<K: Ord + Copy, V: Copy> Node<K, V> {
    pub fn new(k: K, v: V) -> Node<K, V> {
        Node {
            key: k,
            value: v,
            left: None,
            right: None,
            up: None,
        }
    }

    pub fn set_ptr(&mut self, side: Side, to: NodePtr) {
        let field = match side {
            Side::Up => &mut self.up,
            Side::Left => &mut self.left,
            _ => &mut self.right,
        };
        *field = to;
    }

    pub fn get_ptr(&self, side: Side) -> NodePtr {
        match side {
            Side::Up => self.up,
            Side::Left => self.left,
            _ => self.right,
        }
    }
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Tree<K, V> {
    root: NodePtr,
    store: Vec<Node<K, V>>,
}

impl<K: Ord + Copy + Debug + Display, V: Debug + Copy + Display> Tree<K, V> {
    pub fn get_node(&self, np: NodePtr) -> Node<K, V> {
        assert!(np.is_some());
        self.store[np.unwrap()]
    }

    pub fn get_key(&self, np: NodePtr) -> K {
        assert!(np.is_some());
        self.store[np.unwrap()].key
    }

    pub fn _get_value(&self, np: NodePtr) -> V {
        assert!(np.is_some());
        self.store[np.unwrap()].value
    }

    pub fn get_pointer(&self, np: NodePtr, side: Side) -> NodePtr {
        assert!(np.is_some());
        self.store[np.unwrap()].get_ptr(side)
    }

    pub fn set_pointer(&mut self, np: NodePtr, side: Side, to: NodePtr) {
        assert!(np.is_some());
        self.store[np.unwrap()].set_ptr(side, to);
    }

    pub fn new() -> Self {
        Tree {
            root: None,
            store: Vec::<Node<K, V>>::with_capacity(128),
        }
    }

    pub fn insert(&mut self, k: K, v: V) -> Option<Node<K, V>> {
        let mut n = Node::new(k, v);

        if self.root.is_none() {
            assert!(self.store.len() == 0);
            self.store.push(n);
            self.root = Some(0);
            return Some(n);
        }

        let mut p = self.root;      // Possibly None
        let mut prev = p;
        let mut side = Side::Left;
        while let Some(_) = p {
            prev = p;
            match n.key.cmp(&self.get_key(p)) {
                Ordering::Less => {
                    side = Side::Left;
                    p = self.get_pointer(p, side);
                }
                Ordering::Greater => {
                    side = Side::Right;
                    p = self.get_pointer(p, side);
                }
                Ordering::Equal => {
                    // Key exists
                    return None;
                }
            }
        }
        // Set child's pointer
        n.up = prev;
        // Stow the node
        self.store.push(n);
        // Set parent's pointer
        let ptr = Some(self.store.len() - 1);
        self.set_pointer(prev, side, ptr);
        Some(n)
    }

    // Prints the tree with root p.  The idea is to do an in-order traversal
    // (reverse in-order in this case, where right is on top), and print nodes as they
    // are visited, one per line. Each invocation of display() gets its own copy
    // of the display element vector e, which is grown with either whitespace or
    // a trunk element, then modified in its last and possibly second-to-last
    // characters in context.
    fn display(&self, p: NodePtr, side: Side, e: &Vec<DisplayElement>, f: &mut Formatter) {
        if p.is_none() {
            return;
        }

        let mut elems = e.clone();
        let node = self.get_node(p);
        let mut tail = DisplayElement::SpaceSpace;
        if node.up != self.root {
            // If the direction is switching, I need the trunk element to appear in the lines
            // printed before that node is visited.
            if side == Side::Left && node.right.is_some() {
                elems.push(DisplayElement::TrunkSpace);
            } else {
                elems.push(DisplayElement::SpaceSpace);
            }
        }
        let hindex = elems.len() - 1;
        self.display(node.right, Side::Right, &elems, f);

        if p == self.root {
            elems[hindex] = DisplayElement::Root;
            tail = DisplayElement::TrunkSpace;
        } else if side == Side::Right {
            // Right subtree finished
            elems[hindex] = DisplayElement::SpaceRight;
            // Prepare trunk element in case there is a left subtree
            tail = DisplayElement::TrunkSpace;
        } else if side == Side::Left {
            elems[hindex] = DisplayElement::SpaceLeft;
            let parent = self.get_node(node.up);
            if parent.up.is_some() && self.get_pointer(parent.up, Side::Right) == node.up {
                // Direction switched, need trunk element starting with this node/line
                elems[hindex - 1] = DisplayElement::TrunkSpace;
            }
        }

        // Visit node => print accumulated elements. Each node gets a line and each line gets a
        // node.
        for e in elems.clone() {
            let _ = write!(f, "{}", e.string());
        }
        let _ = write!(f,
                       "{key:>width$} ",
                       key = Green.bold().paint(node.key),
                       width = 2);
        let _ = write!(f,
                       "{value:>width$}\n",
                       value = Blue.bold().paint(format!("{:.*}", 2, node.value)),
                       width = 4);

        // Overwrite last element before continuing traversal
        elems[hindex] = tail;

        self.display(node.left, Side::Left, &elems, f);
    }
}

impl<K: Ord + Copy + Debug + Display, V: Debug + Copy + Display> Display for Tree<K, V> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        if self.root.is_none() {
            write!(f, "[empty]")
        } else {
            let mut v: Vec<DisplayElement> = Vec::new();
            self.display(self.root, Side::Up, &v, f);
            Ok(())
        }
    }
}

fn random_tree(n: u32) -> Tree<i32, f32> {
    let mut tree: Tree<i32, f32> = Tree::new();
    let mut rng = rand::thread_rng();
    tree.insert(0, rng.gen_range(-1f32, 1f32));
    for _ in 0..n - 1 {
        tree.insert(rng.gen_range(-(n as i32) / 2, (n as i32) / 2),
                    rng.gen_range(-1f32, 1f32));
    }
    tree
}

/// Prints json representation of tree as well, useful for shorter code listings.
fn main() {
    let args: Vec<String> = env::args().collect();
    let mut r_nodes: u32 = 20;

    match args.len() {
        1 => {}
        2 => {
            r_nodes = args[1].parse::<u32>().unwrap();
        }
        _ => {
            println!("visualize_a_tree <no. of nodes>");
            return;
        }
    }

    let tree = random_tree(r_nodes);
    let encoded = json::encode(&tree).unwrap();

    println!("{}", tree);
    println!("{}", encoded);

    println!("\nCanned tree, decoded:");
    _main_for_rosetta()
}

/// Decodes and prints a previously generated tree.  Presenting this with display(), the fmt()
/// overload, and the struct & enum definitions is sufficient for this demonstration.
fn _main_for_rosetta() {
    let encoded = r#"{"root":0,"store":[{"key":0,"value":0.45,"left":1,"right":3,
        "up":null},{"key":-8,"value":-0.94,"left":7,"right":2,"up":0}, {"key":-1,
        "value":0.15,"left":8,"right":null,"up":1},{"key":7, "value":-0.29,"left":4,
        "right":9,"up":0},{"key":5,"value":0.80,"left":5,"right":null,"up":3},
        {"key":4,"value":-0.85,"left":6,"right":null,"up":4},{"key":3,"value":-0.46,
        "left":null,"right":null,"up":5},{"key":-10,"value":-0.85,"left":null,
        "right":13,"up":1},{"key":-6,"value":-0.42,"left":null,"right":10,"up":2},
        {"key":9,"value":0.63,"left":12,"right":null,"up":3},{"key":-3,"value":-0.83,
        "left":null,"right":11,"up":8},{"key":-2,"value":0.75,"left":null,"right":null,
        "up":10},{"key":8,"value":-0.48,"left":null,"right":null,"up":9},{"key":-9,
        "value":0.53,"left":null,"right":null,"up":7}]}"#;
    let tree: Tree<i32, f32> = json::decode(encoded).unwrap();
    println!("{}", tree);
}

#[cfg(test)]
mod tests {
    use super::{Side, Tree};
    use random_tree;
    use rustc_serialize::json;

    #[test]
    fn test_insert() {
        let mut tree: Tree<i32, f32> = Tree::new();
        tree.insert(0, 0.0);
        tree.insert(8, 8.8);
        tree.insert(-8, -8.8);
        assert!(tree.insert(4, 4.4).is_some());
        tree.insert(12, 12.12);

        assert_eq!(tree._get_value(tree.get_pointer(tree.root, Side::Left)),
                   -8.8);
        assert_eq!(tree._get_value(tree.get_pointer(tree.get_pointer(tree.root, Side::Right),
                                                    Side::Right)),
                   12.12);
        assert_eq!(tree.get_pointer(tree.get_pointer(tree.get_pointer(tree.root, Side::Right),
                                                     Side::Right),
                                    Side::Left),
                   None);

        tree = random_tree(100);
        assert!(tree.store.len() > 0);
    }

    #[test]
    fn test_decode() {
        let encoded = r#"{"root":0,"store":[{"key":0,"value":0.45,"left":1,"right":3,
            "up":null},{"key":-8,"value":-0.94,"left":7,"right":2,"up":0}, {"key":-1,
            "value":0.15,"left":8,"right":null,"up":1},{"key":7, "value":-0.29,"left":4,
            "right":9,"up":0},{"key":5,"value":0.80,"left":5,"right":null,"up":3},
            {"key":4,"value":-0.85,"left":6,"right":null,"up":4},{"key":3,"value":-0.46,
            "left":null,"right":null,"up":5},{"key":-10,"value":-0.85,"left":null,
            "right":13,"up":1},{"key":-6,"value":-0.42,"left":null,"right":10,"up":2},
            {"key":9,"value":0.63,"left":12,"right":null,"up":3},{"key":-3,"value":-0.83,
            "left":null,"right":11,"up":8},{"key":-2,"value":0.75,"left":null,"right":null,
            "up":10},{"key":8,"value":-0.48,"left":null,"right":null,"up":9},{"key":-9,
            "value":0.53,"left":null,"right":null,"up":7}]}"#;
        let tree: Tree<i32, f32> = json::decode(&encoded).unwrap();
        assert_eq!(tree.root, Some(0));
        assert_eq!(tree.store[4].key, 5);
        assert_eq!(tree.store[4].value, 0.80);
        assert_eq!(tree.store[4].right, None);
        assert_eq!(tree.store[12].up, Some(9));
        assert_eq!(tree.store[9].left, Some(12));
    }
}
<commit_msg>pass slices to functions instead of a `Vec`<commit_after>// http://rosettacode.org/wiki/Visualize_a_tree

extern crate rand;
extern crate rustc_serialize;
extern crate term_painter;

use rand::Rng;
use rustc_serialize::json;
use std::cmp::Ordering;
use std::env;
use std::fmt::{Debug, Display, Formatter, Result};
use term_painter::ToStyle;
use term_painter::Color::*;

type NodePtr = Option<usize>;

#[derive(Debug, PartialEq, Clone, Copy)]
enum Side {
    Left,
    Right,
    Up,
}

#[derive(Debug, PartialEq, Clone, Copy)]
enum DisplayElement {
    TrunkSpace,
    SpaceLeft,
    SpaceRight,
    SpaceSpace,
    Root,
}

impl DisplayElement {
    fn string(&self) -> String {
        match *self {
            DisplayElement::TrunkSpace => "    │   ".to_string(),
            DisplayElement::SpaceRight => "    ┌───".to_string(),
            DisplayElement::SpaceLeft => "    └───".to_string(),
            DisplayElement::SpaceSpace => "        ".to_string(),
            DisplayElement::Root => "├──".to_string(),
        }
    }
}

#[derive(Debug, Clone, Copy, RustcDecodable, RustcEncodable)]
struct Node<K, V> {
    key: K,
    value: V,
    left: NodePtr,
    right: NodePtr,
    up: NodePtr,
}

impl<K: Ord + Copy, V: Copy> Node<K, V> {
    pub fn new(k: K, v: V) -> Node<K, V> {
        Node {
            key: k,
            value: v,
            left: None,
            right: None,
            up: None,
        }
    }

    pub fn set_ptr(&mut self, side: Side, to: NodePtr) {
        let field = match side {
            Side::Up => &mut self.up,
            Side::Left => &mut self.left,
            _ => &mut self.right,
        };
        *field = to;
    }

    pub fn get_ptr(&self, side: Side) -> NodePtr {
        match side {
            Side::Up => self.up,
            Side::Left => self.left,
            _ => self.right,
        }
    }
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Tree<K, V> {
    root: NodePtr,
    store: Vec<Node<K, V>>,
}

impl<K: Ord + Copy + Debug + Display, V: Debug + Copy + Display> Tree<K, V> {
    pub fn get_node(&self, np: NodePtr) -> Node<K, V> {
        assert!(np.is_some());
        self.store[np.unwrap()]
    }

    pub fn get_key(&self, np: NodePtr) -> K {
        assert!(np.is_some());
        self.store[np.unwrap()].key
    }

    pub fn _get_value(&self, np: NodePtr) -> V {
        assert!(np.is_some());
        self.store[np.unwrap()].value
    }

    pub fn get_pointer(&self, np: NodePtr, side: Side) -> NodePtr {
        assert!(np.is_some());
        self.store[np.unwrap()].get_ptr(side)
    }

    pub fn set_pointer(&mut self, np: NodePtr, side: Side, to: NodePtr) {
        assert!(np.is_some());
        self.store[np.unwrap()].set_ptr(side, to);
    }

    pub fn new() -> Self {
        Tree {
            root: None,
            store: Vec::<Node<K, V>>::with_capacity(128),
        }
    }

    pub fn insert(&mut self, k: K, v: V) -> Option<Node<K, V>> {
        let mut n = Node::new(k, v);

        if self.root.is_none() {
            assert!(self.store.len() == 0);
            self.store.push(n);
            self.root = Some(0);
            return Some(n);
        }

        let mut p = self.root;      // Possibly None
        let mut prev = p;
        let mut side = Side::Left;
        while let Some(_) = p {
            prev = p;
            match n.key.cmp(&self.get_key(p)) {
                Ordering::Less => {
                    side = Side::Left;
                    p = self.get_pointer(p, side);
                }
                Ordering::Greater => {
                    side = Side::Right;
                    p = self.get_pointer(p, side);
                }
                Ordering::Equal => {
                    // Key exists
                    return None;
                }
            }
        }
        // Set child's pointer
        n.up = prev;
        // Stow the node
        self.store.push(n);
        // Set parent's pointer
        let ptr = Some(self.store.len() - 1);
        self.set_pointer(prev, side, ptr);
        Some(n)
    }

    // Prints the tree with root p.  The idea is to do an in-order traversal
    // (reverse in-order in this case, where right is on top), and print nodes as they
    // are visited, one per line. Each invocation of display() gets its own copy
    // of the display element vector e, which is grown with either whitespace or
    // a trunk element, then modified in its last and possibly second-to-last
    // characters in context.
    fn display(&self, p: NodePtr, side: Side, e: &[DisplayElement], f: &mut Formatter) {
        if p.is_none() {
            return;
        }

        let mut elems = e.to_vec();
        let node = self.get_node(p);
        let mut tail = DisplayElement::SpaceSpace;
        if node.up != self.root {
            // If the direction is switching, I need the trunk element to appear in the lines
            // printed before that node is visited.
            if side == Side::Left && node.right.is_some() {
                elems.push(DisplayElement::TrunkSpace);
            } else {
                elems.push(DisplayElement::SpaceSpace);
            }
        }
        let hindex = elems.len() - 1;
        self.display(node.right, Side::Right, &elems, f);

        if p == self.root {
            elems[hindex] = DisplayElement::Root;
            tail = DisplayElement::TrunkSpace;
        } else if side == Side::Right {
            // Right subtree finished
            elems[hindex] = DisplayElement::SpaceRight;
            // Prepare trunk element in case there is a left subtree
            tail = DisplayElement::TrunkSpace;
        } else if side == Side::Left {
            elems[hindex] = DisplayElement::SpaceLeft;
            let parent = self.get_node(node.up);
            if parent.up.is_some() && self.get_pointer(parent.up, Side::Right) == node.up {
                // Direction switched, need trunk element starting with this node/line
                elems[hindex - 1] = DisplayElement::TrunkSpace;
            }
        }

        // Visit node => print accumulated elements. Each node gets a line and each line gets a
        // node.
        for e in elems.clone() {
            let _ = write!(f, "{}", e.string());
        }
        let _ = write!(f,
                       "{key:>width$} ",
                       key = Green.bold().paint(node.key),
                       width = 2);
        let _ = write!(f,
                       "{value:>width$}\n",
                       value = Blue.bold().paint(format!("{:.*}", 2, node.value)),
                       width = 4);

        // Overwrite last element before continuing traversal
        elems[hindex] = tail;

        self.display(node.left, Side::Left, &elems, f);
    }
}

impl<K: Ord + Copy + Debug + Display, V: Debug + Copy + Display> Display for Tree<K, V> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        if self.root.is_none() {
            write!(f, "[empty]")
        } else {
            let v: Vec<DisplayElement> = vec![];
            self.display(self.root, Side::Up, &v, f);
            Ok(())
        }
    }
}

fn random_tree(n: u32) -> Tree<i32, f32> {
    let mut tree: Tree<i32, f32> = Tree::new();
    let mut rng = rand::thread_rng();
    tree.insert(0, rng.gen_range(-1f32, 1f32));
    for _ in 0..n - 1 {
        tree.insert(rng.gen_range(-(n as i32) / 2, (n as i32) / 2),
                    rng.gen_range(-1f32, 1f32));
    }
    tree
}

/// Prints json representation of tree as well, useful for shorter code listings.
fn main() {
    let args: Vec<String> = env::args().collect();
    let mut r_nodes: u32 = 20;

    match args.len() {
        1 => {}
        2 => {
            r_nodes = args[1].parse::<u32>().unwrap();
        }
        _ => {
            println!("visualize_a_tree <no. of nodes>");
            return;
        }
    }

    let tree = random_tree(r_nodes);
    let encoded = json::encode(&tree).unwrap();

    println!("{}", tree);
    println!("{}", encoded);

    println!("\nCanned tree, decoded:");
    _main_for_rosetta()
}

/// Decodes and prints a previously generated tree.  Presenting this with display(), the fmt()
/// overload, and the struct & enum definitions is sufficient for this demonstration.
fn _main_for_rosetta() {
    let encoded = r#"{"root":0,"store":[{"key":0,"value":0.45,"left":1,"right":3,
        "up":null},{"key":-8,"value":-0.94,"left":7,"right":2,"up":0}, {"key":-1,
        "value":0.15,"left":8,"right":null,"up":1},{"key":7, "value":-0.29,"left":4,
        "right":9,"up":0},{"key":5,"value":0.80,"left":5,"right":null,"up":3},
        {"key":4,"value":-0.85,"left":6,"right":null,"up":4},{"key":3,"value":-0.46,
        "left":null,"right":null,"up":5},{"key":-10,"value":-0.85,"left":null,
        "right":13,"up":1},{"key":-6,"value":-0.42,"left":null,"right":10,"up":2},
        {"key":9,"value":0.63,"left":12,"right":null,"up":3},{"key":-3,"value":-0.83,
        "left":null,"right":11,"up":8},{"key":-2,"value":0.75,"left":null,"right":null,
        "up":10},{"key":8,"value":-0.48,"left":null,"right":null,"up":9},{"key":-9,
        "value":0.53,"left":null,"right":null,"up":7}]}"#;
    let tree: Tree<i32, f32> = json::decode(encoded).unwrap();
    println!("{}", tree);
}

#[cfg(test)]
mod tests {
    use super::{Side, Tree};
    use random_tree;
    use rustc_serialize::json;

    #[test]
    fn test_insert() {
        let mut tree: Tree<i32, f32> = Tree::new();
        tree.insert(0, 0.0);
        tree.insert(8, 8.8);
        tree.insert(-8, -8.8);
        assert!(tree.insert(4, 4.4).is_some());
        tree.insert(12, 12.12);

        assert_eq!(tree._get_value(tree.get_pointer(tree.root, Side::Left)),
                   -8.8);
        assert_eq!(tree._get_value(tree.get_pointer(tree.get_pointer(tree.root, Side::Right),
                                                    Side::Right)),
                   12.12);
        assert_eq!(tree.get_pointer(tree.get_pointer(tree.get_pointer(tree.root, Side::Right),
                                                     Side::Right),
                                    Side::Left),
                   None);

        tree = random_tree(100);
        assert!(tree.store.len() > 0);
    }

    #[test]
    fn test_decode() {
        let encoded = r#"{"root":0,"store":[{"key":0,"value":0.45,"left":1,"right":3,
            "up":null},{"key":-8,"value":-0.94,"left":7,"right":2,"up":0}, {"key":-1,
            "value":0.15,"left":8,"right":null,"up":1},{"key":7, "value":-0.29,"left":4,
            "right":9,"up":0},{"key":5,"value":0.80,"left":5,"right":null,"up":3},
            {"key":4,"value":-0.85,"left":6,"right":null,"up":4},{"key":3,"value":-0.46,
            "left":null,"right":null,"up":5},{"key":-10,"value":-0.85,"left":null,
            "right":13,"up":1},{"key":-6,"value":-0.42,"left":null,"right":10,"up":2},
            {"key":9,"value":0.63,"left":12,"right":null,"up":3},{"key":-3,"value":-0.83,
            "left":null,"right":11,"up":8},{"key":-2,"value":0.75,"left":null,"right":null,
            "up":10},{"key":8,"value":-0.48,"left":null,"right":null,"up":9},{"key":-9,
            "value":0.53,"left":null,"right":null,"up":7}]}"#;
        let tree: Tree<i32, f32> = json::decode(&encoded).unwrap();
        assert_eq!(tree.root, Some(0));
        assert_eq!(tree.store[4].key, 5);
        assert_eq!(tree.store[4].value, 0.80);
        assert_eq!(tree.store[4].right, None);
        assert_eq!(tree.store[12].up, Some(9));
        assert_eq!(tree.store[9].left, Some(12));
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Type {
    /// Reference types
    Ref(Reference),
    /// Primitive types
    Prim(Primitive),
    /// An algebraic data type.
    ///
    /// Represented as a vector of variants.
    Algebraic(Vec<Type>),
    /// A function.
    ///
    /// Represented as a vector of parameters and a return type.
    Function { params: Vec<Type>
             , rt: Rc<Type>
             },
    /// A unique symbol type (`'symbol` syntax)
    Symbol(String)
}

/// Reference types (pointers)
///
/// TODO: how will lifetime analysis actually work?
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Reference {
    /// A reference borrowed from another scope.
    ///
    /// Semantically similar to Rust's `&`-pointers.
    ///
    /// TODO: should this track where it was borrowed from?
    /// (can we even perform this analysis at this stage?)
    Borrowed(Rc<Type>),
    /// A moved reference from another scope
    ///
    /// TODO: should this track where it was moved from?
    /// (can we even perform this analysis at this stage?)
    Moved(Rc<Type>),
    /// A unique (i.e. boxed) reference.
    Unique(Rc<Type>),
    /// A raw (unsafe) reference.
    ///
    /// Unfortunately we have to have this because of
    /// reasons (i.e, FFI).
    Raw(Rc<Type>)
}

/// Language primitive types
///
/// TODO: add some form of provable-refinement (i.e. we know that some value
/// is not just a bool at compile time but that it's true/false, or we know
/// some value is not just a number but the number 1382, or whatever).
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Primitive { Int
                   , Uint
                   , Byte
                   , Char
                   , Str
                   , Bool
                   , Float
                   , Double
                   // TODO: finish
                   }
<commit_msg>Start on fmt::Display for Type<commit_after>use std::rc::Rc;
use std::fmt;

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Type {
    /// Reference types
    Ref(Reference),
    /// Primitive types
    Prim(Primitive),
    /// An algebraic data type.
    ///
    /// Represented as a vector of variants.
    Algebraic(Vec<Type>),
    /// A function.
    ///
    /// Represented as a vector of parameters and a return type.
    Function { params: Vec<Type>
             , rt: Rc<Type>
             },
    /// A unique symbol type (`'symbol` syntax)
    Symbol(String)
}

impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self { &Type::Ref(ref r) =>  write!(f, "{}", r)
                   , &Type::Prim(ref p) => write!(f, "{}", p)
                   , &Type::Algebraic(ref variants) =>
                        unimplemented!()
                   , &Type::Function { ref params, ref rt } =>
                        unimplemented!()
                   , &Type::Symbol(ref s) => write!(f, "{}", s)
                   }
    }
}

/// Reference types (pointers)
///
/// TODO: how will lifetime analysis actually work?
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Reference {
    /// A reference borrowed from another scope.
    ///
    /// Semantically similar to Rust's `&`-pointers.
    ///
    /// TODO: should this track where it was borrowed from?
    /// (can we even perform this analysis at this stage?)
    Borrowed(Rc<Type>),
    /// A moved reference from another scope
    ///
    /// TODO: should this track where it was moved from?
    /// (can we even perform this analysis at this stage?)
    Moved(Rc<Type>),
    /// A unique (i.e. boxed) reference.
    Unique(Rc<Type>),
    /// A raw (unsafe) reference.
    ///
    /// Unfortunately we have to have this because of
    /// reasons (i.e, FFI).
    Raw(Rc<Type>)
}

impl fmt::Display for Reference {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self { Reference::Borrowed(ref t) =>  write!(f, "&{}", t)
                    , Reference::Moved(ref t) =>  write!(f, "move {}", t)
                    , Reference::Unique(ref t) =>  write!(f, "@{}", t)
                    , Reference::Raw(ref t) =>  write!(f, "*{}", t)
                    }
    }
}

/// Language primitive types
///
/// TODO: add some form of provable-refinement (i.e. we know that some value
/// is not just a bool at compile time but that it's true/false, or we know
/// some value is not just a number but the number 1382, or whatever).
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Primitive { Int
                   , Uint
                   , Byte
                   , Char
                   , Str
                   , Bool
                   , Float
                   , Double
                   // TODO: finish
                   }

impl fmt::Display for Primitive {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       match *self { Primitive::Int     => write!(f, "int")
                   , Primitive::Uint    => write!(f, "uint")
                   , Primitive::Double  => write!(f, "double")
                   , Primitive::Float   => write!(f, "float")
                   , Primitive::Bool    => write!(f, "bool")
                   , _ => unimplemented!()
                   }
   }
}
<|endoftext|>