<commit_before>use std::env;
use std::collections::{BTreeMap, HashMap};
use std::path::{Path, PathBuf};

use quire::{parse_config, parse_string, Options};
use quire::validate as V;

use config::Settings;
use path_util::Expand;

#[derive(PartialEq, RustcDecodable, Debug)]
struct SecureSettings {
    storage_dir: Option<PathBuf>,
    cache_dir: Option<PathBuf>,
    version_check: Option<bool>,
    proxy_env_vars: Option<bool>,
    ubuntu_mirror: Option<String>,
    alpine_mirror: Option<String>,
    site_settings: BTreeMap<PathBuf, SecureSettings>,
    external_volumes: HashMap<String, PathBuf>,
    push_image_script: Option<String>,
    build_lock_wait: Option<bool>,
    auto_apply_sysctl: Option<bool>,
    index_all_images: Option<bool>,
    run_symlinks_as_commands: Option<bool>,
    environ: BTreeMap<String, String>,
}

pub fn secure_settings_validator<'a>(has_children: bool)
    -> V::Structure<'a>
{
    let mut s = V::Structure::new()
        .member("storage_dir", V::Scalar::new().optional())
        .member("cache_dir", V::Scalar::new().optional())
        .member("version_check", V::Scalar::new().optional())
        .member("proxy_env_vars", V::Scalar::new().optional())
        .member("ubuntu_mirror", V::Scalar::new().optional())
        .member("alpine_mirror", V::Scalar::new().optional())
        .member("external_volumes", V::Mapping::new(
            V::Directory::new().absolute(false),
            V::Directory::new().absolute(true)))
        .member("push_image_script", V::Scalar::new().optional())
        .member("build_lock_wait", V::Scalar::new().optional())
        .member("auto_apply_sysctl", V::Scalar::new().optional())
        .member("index_all_images", V::Scalar::new().optional())
        .member("run_symlinks_as_commands", V::Scalar::new().optional())
        .member("environ", V::Mapping::new(
            V::Scalar::new(), V::Scalar::new()));
    if has_children {
        s = s.member("site_settings", V::Mapping::new(
            V::Scalar::new(),
            secure_settings_validator(false)));
    }
    return s;
}

#[derive(PartialEq, RustcDecodable)]
struct InsecureSettings {
    version_check: Option<bool>,
    shared_cache: Option<bool>,
    ubuntu_mirror: Option<String>,
    alpine_mirror: Option<String>,
    build_lock_wait: Option<bool>,
    run_symlinks_as_commands: Option<bool>,
    environ: BTreeMap<String, String>,
}

pub fn insecure_settings_validator<'a>() -> Box<V::Validator + 'a> {
    Box::new(V::Structure::new()
    .member("version_check", V::Scalar::new().optional())
    .member("shared_cache", V::Scalar::new().optional())
    .member("ubuntu_mirror", V::Scalar::new().optional())
    .member("alpine_mirror", V::Scalar::new().optional())
    .member("run_symlinks_as_commands", V::Scalar::new().optional())
    .member("environ", V::Mapping::new(
        V::Scalar::new(), V::Scalar::new())))
}

#[derive(Debug)]
pub struct MergedSettings {
    pub external_volumes: HashMap<String, PathBuf>,
    pub push_image_script: Option<String>,
    pub storage_dir: Option<PathBuf>,
    pub cache_dir: Option<PathBuf>,
    pub shared_cache: bool,
}

fn merge_settings(cfg: SecureSettings, project_root: &Path,
    ext_settings: &mut MergedSettings, int_settings: &mut Settings)
    -> Result<(), String>
{
    if let Some(dir) = cfg.storage_dir {
        ext_settings.storage_dir = Some(dir.expand_home()
            .map_err(|()| format!("Can't expand tilde `~` in storage dir \
                no HOME found"))?);
    }
    if let Some(dir) = cfg.cache_dir {
        ext_settings.cache_dir = Some(dir.expand_home()
            .map_err(|()| format!("Can't expand tilde `~` in cache dir \
                no HOME found"))?);
        ext_settings.shared_cache = true;
    }
    if let Some(val) = cfg.version_check {
        int_settings.version_check = val;
    }
    if let Some(val) = cfg.proxy_env_vars {
        int_settings.proxy_env_vars = val;
    }
    if let Some(ref val) = cfg.ubuntu_mirror {
        int_settings.ubuntu_mirror = Some(val.clone());
    }
    if let Some(ref val) = cfg.alpine_mirror {
        int_settings.alpine_mirror = Some(val.clone());
    }
    for (k, v) in &cfg.external_volumes {
        ext_settings.external_volumes.insert(k.clone(), v.clone());
    }
    if let Some(ref val) = cfg.push_image_script {
        int_settings.push_image_script = Some(val.clone());
    }
    if let Some(val) = cfg.build_lock_wait {
        int_settings.build_lock_wait = val;
    }
    if let Some(val) = cfg.auto_apply_sysctl {
        int_settings.auto_apply_sysctl = val;
    }
    if let Some(val) = cfg.index_all_images {
        int_settings.index_all_images = val;
    }
    if let Some(val) = cfg.run_symlinks_as_commands {
        int_settings.run_symlinks_as_commands = val;
    }
    for (k, v) in &cfg.environ {
        int_settings.environ.insert(k.clone(), v.clone());
    }
    if let Some(cfg) = cfg.site_settings.get(project_root) {
        if let Some(ref dir) = cfg.storage_dir {
            ext_settings.storage_dir = Some(dir.clone());
        }
        if let Some(ref dir) = cfg.cache_dir {
            ext_settings.cache_dir = Some(dir.clone());
            ext_settings.shared_cache = true;
        }
        if let Some(val) = cfg.version_check {
            int_settings.version_check = val;
        }
        if let Some(ref val) = cfg.ubuntu_mirror {
            int_settings.ubuntu_mirror = Some(val.clone());
        }
        if let Some(ref val) = cfg.alpine_mirror {
            int_settings.alpine_mirror = Some(val.clone());
        }
        for (k, v) in &cfg.external_volumes {
            ext_settings.external_volumes.insert(k.clone(), v.clone());
        }
        if let Some(ref val) = cfg.push_image_script {
            int_settings.push_image_script = Some(val.clone());
        }
        if let Some(val) = cfg.build_lock_wait {
            int_settings.build_lock_wait = val;
        }
        if let Some(val) = cfg.auto_apply_sysctl {
            int_settings.auto_apply_sysctl = val;
        }
        if let Some(val) = cfg.index_all_images {
            int_settings.index_all_images = val;
        }
        if let Some(val) = cfg.run_symlinks_as_commands {
            int_settings.run_symlinks_as_commands = val;
        }
        for (k, v) in &cfg.environ {
            int_settings.environ.insert(k.clone(), v.clone());
        }
    }
    Ok(())
}

pub fn read_settings(project_root: &Path)
    -> Result<(MergedSettings, Settings), String>
{
    let mut ext_settings = MergedSettings {
        external_volumes: HashMap::new(),
        push_image_script: None,
        storage_dir: None,
        cache_dir: None,
        shared_cache: false,
    };
    let mut int_settings = Settings {
        proxy_env_vars: true,
        version_check: true,
        uid_map: None,
        ubuntu_mirror: None,
        alpine_mirror: None,
        push_image_script: None,
        build_lock_wait: false,
        auto_apply_sysctl: false,
        index_all_images: false,
        // This will be changed to `true` in some future release
        run_symlinks_as_commands: false,
        environ: BTreeMap::new(),
    };
    let mut secure_files = vec!();
    if let Ok(home) = env::var("_VAGGA_HOME") {
        let home = Path::new(&home);
        secure_files.push(home.join(".config/vagga/settings.yaml"));
        secure_files.push(home.join(".vagga/settings.yaml"));
        secure_files.push(home.join(".vagga.yaml"));
    };
    for filename in secure_files.iter() {
        if !filename.exists() {
            continue;
        }
        let cfg: SecureSettings = parse_config(filename,
            &secure_settings_validator(true), &Options::default())
            .map_err(|e| format!("{}", e))?;
        merge_settings(cfg, &project_root,
            &mut ext_settings, &mut int_settings)?
    }
    if let Ok(settings) = env::var("VAGGA_SETTINGS") {
        let cfg: SecureSettings = parse_string("<env:VAGGA_SETTINGS>",
                &settings,
                &secure_settings_validator(true), &Options::default())
            .map_err(|e| format!("{}", e))?;
        merge_settings(cfg, &project_root,
            &mut ext_settings, &mut int_settings)?
    }
    let mut insecure_files = vec!();
    insecure_files.push(project_root.join(".vagga.settings.yaml"));
    insecure_files.push(project_root.join(".vagga/settings.yaml"));
    for filename in insecure_files.iter() {
        if !filename.exists() {
            continue;
        }
        let cfg: InsecureSettings = parse_config(filename,
            &*insecure_settings_validator(), &Options::default())
            .map_err(|e| format!("{}", e))?;
        if let Some(val) = cfg.version_check {
            int_settings.version_check = val;
        }
        if let Some(ref val) = cfg.ubuntu_mirror {
            int_settings.ubuntu_mirror = Some(val.clone());
        }
        if let Some(ref val) = cfg.alpine_mirror {
            int_settings.alpine_mirror = Some(val.clone());
        }
        if let Some(val) = cfg.shared_cache {
            ext_settings.shared_cache = val;
        }
        if let Some(val) = cfg.build_lock_wait {
            int_settings.build_lock_wait = val;
        }
        if let Some(val) = cfg.run_symlinks_as_commands {
            int_settings.run_symlinks_as_commands = val;
        }
        for (k, v) in &cfg.environ {
            int_settings.environ.insert(k.clone(), v.clone());
        }
    }
    return Ok((ext_settings, int_settings));
}
<commit_msg>Enables `run-symlinks-as-commands` by default<commit_after>use std::env;
use std::collections::{BTreeMap, HashMap};
use std::path::{Path, PathBuf};

use quire::{parse_config, parse_string, Options};
use quire::validate as V;

use config::Settings;
use path_util::Expand;

#[derive(PartialEq, RustcDecodable, Debug)]
struct SecureSettings {
    storage_dir: Option<PathBuf>,
    cache_dir: Option<PathBuf>,
    version_check: Option<bool>,
    proxy_env_vars: Option<bool>,
    ubuntu_mirror: Option<String>,
    alpine_mirror: Option<String>,
    site_settings: BTreeMap<PathBuf, SecureSettings>,
    external_volumes: HashMap<String, PathBuf>,
    push_image_script: Option<String>,
    build_lock_wait: Option<bool>,
    auto_apply_sysctl: Option<bool>,
    index_all_images: Option<bool>,
    run_symlinks_as_commands: Option<bool>,
    environ: BTreeMap<String, String>,
}

pub fn secure_settings_validator<'a>(has_children: bool)
    -> V::Structure<'a>
{
    let mut s = V::Structure::new()
        .member("storage_dir", V::Scalar::new().optional())
        .member("cache_dir", V::Scalar::new().optional())
        .member("version_check", V::Scalar::new().optional())
        .member("proxy_env_vars", V::Scalar::new().optional())
        .member("ubuntu_mirror", V::Scalar::new().optional())
        .member("alpine_mirror", V::Scalar::new().optional())
        .member("external_volumes", V::Mapping::new(
            V::Directory::new().absolute(false),
            V::Directory::new().absolute(true)))
        .member("push_image_script", V::Scalar::new().optional())
        .member("build_lock_wait", V::Scalar::new().optional())
        .member("auto_apply_sysctl", V::Scalar::new().optional())
        .member("index_all_images", V::Scalar::new().optional())
        .member("run_symlinks_as_commands", V::Scalar::new().optional())
        .member("environ", V::Mapping::new(
            V::Scalar::new(), V::Scalar::new()));
    if has_children {
        s = s.member("site_settings", V::Mapping::new(
            V::Scalar::new(),
            secure_settings_validator(false)));
    }
    return s;
}

#[derive(PartialEq, RustcDecodable)]
struct InsecureSettings {
    version_check: Option<bool>,
    shared_cache: Option<bool>,
    ubuntu_mirror: Option<String>,
    alpine_mirror: Option<String>,
    build_lock_wait: Option<bool>,
    run_symlinks_as_commands: Option<bool>,
    environ: BTreeMap<String, String>,
}

pub fn insecure_settings_validator<'a>() -> Box<V::Validator + 'a> {
    Box::new(V::Structure::new()
    .member("version_check", V::Scalar::new().optional())
    .member("shared_cache", V::Scalar::new().optional())
    .member("ubuntu_mirror", V::Scalar::new().optional())
    .member("alpine_mirror", V::Scalar::new().optional())
    .member("run_symlinks_as_commands", V::Scalar::new().optional())
    .member("environ", V::Mapping::new(
        V::Scalar::new(), V::Scalar::new())))
}

#[derive(Debug)]
pub struct MergedSettings {
    pub external_volumes: HashMap<String, PathBuf>,
    pub push_image_script: Option<String>,
    pub storage_dir: Option<PathBuf>,
    pub cache_dir: Option<PathBuf>,
    pub shared_cache: bool,
}

fn merge_settings(cfg: SecureSettings, project_root: &Path,
    ext_settings: &mut MergedSettings, int_settings: &mut Settings)
    -> Result<(), String>
{
    if let Some(dir) = cfg.storage_dir {
        ext_settings.storage_dir = Some(dir.expand_home()
            .map_err(|()| format!("Can't expand tilde `~` in storage dir \
                no HOME found"))?);
    }
    if let Some(dir) = cfg.cache_dir {
        ext_settings.cache_dir = Some(dir.expand_home()
            .map_err(|()| format!("Can't expand tilde `~` in cache dir \
                no HOME found"))?);
        ext_settings.shared_cache = true;
    }
    if let Some(val) = cfg.version_check {
        int_settings.version_check = val;
    }
    if let Some(val) = cfg.proxy_env_vars {
        int_settings.proxy_env_vars = val;
    }
    if let Some(ref val) = cfg.ubuntu_mirror {
        int_settings.ubuntu_mirror = Some(val.clone());
    }
    if let Some(ref val) = cfg.alpine_mirror {
        int_settings.alpine_mirror = Some(val.clone());
    }
    for (k, v) in &cfg.external_volumes {
        ext_settings.external_volumes.insert(k.clone(), v.clone());
    }
    if let Some(ref val) = cfg.push_image_script {
        int_settings.push_image_script = Some(val.clone());
    }
    if let Some(val) = cfg.build_lock_wait {
        int_settings.build_lock_wait = val;
    }
    if let Some(val) = cfg.auto_apply_sysctl {
        int_settings.auto_apply_sysctl = val;
    }
    if let Some(val) = cfg.index_all_images {
        int_settings.index_all_images = val;
    }
    if let Some(val) = cfg.run_symlinks_as_commands {
        int_settings.run_symlinks_as_commands = val;
    }
    for (k, v) in &cfg.environ {
        int_settings.environ.insert(k.clone(), v.clone());
    }
    if let Some(cfg) = cfg.site_settings.get(project_root) {
        if let Some(ref dir) = cfg.storage_dir {
            ext_settings.storage_dir = Some(dir.clone());
        }
        if let Some(ref dir) = cfg.cache_dir {
            ext_settings.cache_dir = Some(dir.clone());
            ext_settings.shared_cache = true;
        }
        if let Some(val) = cfg.version_check {
            int_settings.version_check = val;
        }
        if let Some(ref val) = cfg.ubuntu_mirror {
            int_settings.ubuntu_mirror = Some(val.clone());
        }
        if let Some(ref val) = cfg.alpine_mirror {
            int_settings.alpine_mirror = Some(val.clone());
        }
        for (k, v) in &cfg.external_volumes {
            ext_settings.external_volumes.insert(k.clone(), v.clone());
        }
        if let Some(ref val) = cfg.push_image_script {
            int_settings.push_image_script = Some(val.clone());
        }
        if let Some(val) = cfg.build_lock_wait {
            int_settings.build_lock_wait = val;
        }
        if let Some(val) = cfg.auto_apply_sysctl {
            int_settings.auto_apply_sysctl = val;
        }
        if let Some(val) = cfg.index_all_images {
            int_settings.index_all_images = val;
        }
        if let Some(val) = cfg.run_symlinks_as_commands {
            int_settings.run_symlinks_as_commands = val;
        }
        for (k, v) in &cfg.environ {
            int_settings.environ.insert(k.clone(), v.clone());
        }
    }
    Ok(())
}

pub fn read_settings(project_root: &Path)
    -> Result<(MergedSettings, Settings), String>
{
    let mut ext_settings = MergedSettings {
        external_volumes: HashMap::new(),
        push_image_script: None,
        storage_dir: None,
        cache_dir: None,
        shared_cache: false,
    };
    let mut int_settings = Settings {
        proxy_env_vars: true,
        version_check: true,
        uid_map: None,
        ubuntu_mirror: None,
        alpine_mirror: None,
        push_image_script: None,
        build_lock_wait: false,
        auto_apply_sysctl: false,
        index_all_images: false,
        run_symlinks_as_commands: true,
        environ: BTreeMap::new(),
    };
    let mut secure_files = vec!();
    if let Ok(home) = env::var("_VAGGA_HOME") {
        let home = Path::new(&home);
        secure_files.push(home.join(".config/vagga/settings.yaml"));
        secure_files.push(home.join(".vagga/settings.yaml"));
        secure_files.push(home.join(".vagga.yaml"));
    };
    for filename in secure_files.iter() {
        if !filename.exists() {
            continue;
        }
        let cfg: SecureSettings = parse_config(filename,
            &secure_settings_validator(true), &Options::default())
            .map_err(|e| format!("{}", e))?;
        merge_settings(cfg, &project_root,
            &mut ext_settings, &mut int_settings)?
    }
    if let Ok(settings) = env::var("VAGGA_SETTINGS") {
        let cfg: SecureSettings = parse_string("<env:VAGGA_SETTINGS>",
                &settings,
                &secure_settings_validator(true), &Options::default())
            .map_err(|e| format!("{}", e))?;
        merge_settings(cfg, &project_root,
            &mut ext_settings, &mut int_settings)?
    }
    let mut insecure_files = vec!();
    insecure_files.push(project_root.join(".vagga.settings.yaml"));
    insecure_files.push(project_root.join(".vagga/settings.yaml"));
    for filename in insecure_files.iter() {
        if !filename.exists() {
            continue;
        }
        let cfg: InsecureSettings = parse_config(filename,
            &*insecure_settings_validator(), &Options::default())
            .map_err(|e| format!("{}", e))?;
        if let Some(val) = cfg.version_check {
            int_settings.version_check = val;
        }
        if let Some(ref val) = cfg.ubuntu_mirror {
            int_settings.ubuntu_mirror = Some(val.clone());
        }
        if let Some(ref val) = cfg.alpine_mirror {
            int_settings.alpine_mirror = Some(val.clone());
        }
        if let Some(val) = cfg.shared_cache {
            ext_settings.shared_cache = val;
        }
        if let Some(val) = cfg.build_lock_wait {
            int_settings.build_lock_wait = val;
        }
        if let Some(val) = cfg.run_symlinks_as_commands {
            int_settings.run_symlinks_as_commands = val;
        }
        for (k, v) in &cfg.environ {
            int_settings.environ.insert(k.clone(), v.clone());
        }
    }
    return Ok((ext_settings, int_settings));
}
<|endoftext|>


<commit_before>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Starting code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu and David Evans
// Version 0.3

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::{SocketAddr, Ipv4Addr};
use std::io::println;
use std::cell::Cell;
use std::{os, str, io, run, hashmap, task, vec};
use extra::arc;
use extra::priority_queue::PriorityQueue;
use std::comm::*;
use std::cast;
use extra::comm::DuplexStream;
use std::hashmap::HashSet;
use std::path::Path;
use extra::sort;

static PORT:  int = 4414;
static IP: &'static str = "127.0.0.1";
static mut visitor_count: uint = 0;

#[deriving(Clone)]
struct access_t {
    filepath: ~std::path::PosixPath,
    size: i64,
    num_access: uint
}

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath,
    priority: uint
}

impl std::cmp::Ord for sched_msg {
    fn lt(&self, other: &sched_msg) -> bool {
        return self.priority > other.priority;
    }
}

fn main() {
    let req_heap: PriorityQueue<sched_msg> = PriorityQueue::new();
    let shared_req_heap = arc::RWArc::new(req_heap);
    let add_vec = shared_req_heap.clone();
    let take_vec = shared_req_heap.clone();

    let cache: hashmap::HashMap<~str, ~[u8]> = hashmap::HashMap::new();
    let shared_cache = arc::RWArc::new(cache);
    let add_cache = shared_cache.clone();
    let check_cache = shared_cache.clone();

    let accesses: ~[access_t] = ~[];
    let shared_accesses = arc::RWArc::new(accesses);
    let exist_accesses = shared_accesses.clone();
    let new_accesses = shared_accesses.clone();

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    // dequeue file requests, and send responses.
    // FIFO
    do spawn {
        let (sm_port, sm_chan) = stream();

        // a task for sending responses.
        do spawn {
            loop {
                let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle
                let fpath = tf.filepath.clone();
                println(fmt!("begin serving file [%?]", tf.filepath.to_str()));
                // A web server should always reply a HTTP header for any legal HTTP request.
                let extension = fpath.components().last();
                match extension.rfind('.') {
                    Some(x) =>  {
                        match extension.slice_from(x+1) {
                            "html"|"xhtml"|"txt"|"xml"  => { tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes()); }
                            _                           => { tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream; charset=UTF-8\r\n\r\n".as_bytes()); }
                        }
                    }
                    _       =>  { tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream; charset=UTF-8\r\n\r\n".as_bytes()); }
                }

                match do check_cache.read |cc| { (*cc).find_copy(&tf.filepath.to_str()) } {
                    None        =>  { if tf.filepath.get_mode().unwrap() % 2 == 1 {
                                            execFile(tf);
                                            // No cache for dynamically-generated files.
                                            loop;
                                      }
                                      let data = writeFile(&mut tf);
                                      do new_accesses.write |na| {
                                            if (*na).len() > 20 {
                                                (*na).pop_opt();
                                            }

                                            let file_info = access_t{filepath: fpath.clone(), size: fpath.get_size().unwrap(), num_access: 1};
                                            (*na).push(file_info.clone());
                                            do add_cache.write |ac| {
                                                let sort_access = sort::merge_sort(*na, |it1: &access_t, it2: &access_t| {
                                                                                (it1.size*it1.num_access as i64) <= (it2.size*it2.num_access as i64)
                                                                                });
                                                for item in sort_access.iter() {
                                                    if file_info.size > (item.size*item.num_access as i64) {
                                                        match (*ac).pop(&item.filepath.to_str()) {
                                                            Some(_)    =>  { (*ac).swap(file_info.filepath.to_str(), data.clone()); break;}
                                                            None           =>  { }
                                                        }
                                                    }
                                                }
                                            }
                                      }
                                  }

                    Some(ct)    =>  { tf.stream.write(ct);
                                      do exist_accesses.write |ea| {
                                            for i in range(0, (*ea).len()) {
                                                let mut item = (*ea)[i].clone();
                                                if item.filepath == tf.filepath {
                                                    item.num_access += 1;
                                                    (*ea).remove(i);
                                                    (*ea).push(item);
                                                    break;
                                                }
                                            }
                                        }
                                    }
                }
                println(fmt!("finish file [%?]", fpath.to_str()));
            }
        }

        loop {
            port.recv(); // wait for arrving notification
            do take_vec.write |vec| {
                if ((*vec).len() > 0) {
                    // LIFO didn't make sense in service scheduling, so we modify it as FIFO by using shift_opt() rather than pop().
                    let tf: sched_msg = (*vec).pop();
                    println(fmt!("shift from queue, size: %ud", (*vec).len()));
                    sm_chan.send(tf); // send the request to send-response-task to serve.
                }
            }
        }
    }

    // IP addresses to give higher priority
    let mut ip_vals: HashSet<u32> = HashSet::with_capacity(9000);
    ip_vals.insert((192 as u32 << 24) + (168 as u32 << 16));
    ip_vals.insert((127 as u32 << 24) + (143 as u32 << 16));
    ip_vals.insert((137 as u32 << 24) + (54 as u32 << 16));
    ip_vals.insert(0);
    let shared_ip_map = arc::RWArc::new(ip_vals);

    let shared_count = arc::RWArc::new(0);

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None => { println(fmt!("Error: Invalid IP address <%s>", IP));
                                                     return;},
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on %s:%d ...", ip.to_str(), PORT));
    let mut acceptor = socket.listen().unwrap();

    for stream in acceptor.incoming() {
        let stream = Cell::new(stream);

        let incr_count = shared_count.clone();

        // Start a new task to handle the each connection
        let child_chan = chan.clone();
        let shared_ip_map = shared_ip_map.clone();
        let child_add_vec = add_vec.clone();

        do spawn {
            do incr_count.write |count| {
                *count += 1;
            }

            let mut stream = stream.take();
            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);

            let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
            if req_group.len() > 2 {
                let path = req_group[1];
                println(fmt!("Request for path: \n%?", path));
                // More better path security!
                let unclean_path = os::getcwd().push(Path(path).to_str()).to_str();
                let mut file_path = ~os::getcwd();
                // paths are always normalized so a/b/../c becomes a/c
                if unclean_path.starts_with(file_path.to_str()) {
                    file_path = ~file_path.push(path);
                }
                if !os::path_exists(file_path) || os::path_is_dir(file_path) {
                    println(fmt!("Request received:\n%s", request_str));
                    let response: ~str = fmt!(
                        "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                         <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: %u

                         \r\n", incr_count.read(|c| { *c }));

                    stream.write(response.as_bytes());
                }
                else {
                    // Requests scheduling

                    let mut priority = file_path.stat().unwrap().st_size as uint;
                    unsafe {
                        match stream {
                            Some(ref s) => {
                                    let stream = cast::transmute_mut(s);
                                    let pn = stream.peer_name().unwrap();
                                    println(fmt!("Peer is: %?", pn));
                                    match pn.ip {
                                        Ipv4Addr(a, b, c, d) => {
                                                                // Since we are sharing the ip_map it must be read
                                                                do shared_ip_map.read |map| {
                                                                    if check_ip(a,b,c,d, map) {
                                                                        priority = 1;
                                                                        println("local request!");
                                                                    }
                                                                }
                                                            },
                                        _                    =>  fail!()
                                    }
                            },
                            _    => fail!()
                        };
                    }
                    let msg: sched_msg = sched_msg{stream: stream, filepath: file_path.clone(), priority: priority};
                    let (sm_port, sm_chan) = std::comm::stream();
                    sm_chan.send(msg);

                    do child_add_vec.write |vec| {
                        let msg = sm_port.recv();
                        (*vec).push(msg); // enqueue new request.
                        println("add to queue");
                    }
                    child_chan.send(""); //notify the new arriving request.
                    println(fmt!("get file request: %?", file_path));
                }
            }
            println!("connection terminates")
        }
    }
}

// Looks up an ip prefix in the hashset by trying each octet
fn check_ip(a: u8, b: u8, c: u8, d: u8, map: &HashSet<u32>) -> bool {
    let mut mut_ip = a as u32 << 24;
    if map.contains(&mut_ip) {
        return true;
    }
    mut_ip += (b as u32 << 16);
    if map.contains(&mut_ip) {
        return true;
    }
    mut_ip += (c as u32 << 8);
    if map.contains(&mut_ip) {
        return true;
    }
    mut_ip += (d as u32);
    if map.contains(&mut_ip) {
        return true;
    }
    false
}

fn execFile(file_data: sched_msg) {
    let (port, chan) = DuplexStream();
    do task::spawn_supervised {
        do_gash(&chan)
    }
    let mut file_data = file_data;
    match io::file_reader(file_data.filepath) {
        Ok(rd)      =>  {   let closer = ~['\"',' ', '-','-','>'];
                            while !rd.eof() {
                            let rd_byte = rd.read_byte() as u8;

                            match rd_byte {
                                0x3c =>  { let mut open: ~[u8] = ~[0,0,0,0,0,0,0,0,0,0,0,0,0,0];
                                                          rd.read(open, 14);
                                                          if str::from_utf8(open) == ~"!--#exec cmd=\"" {
                                                                let mut cmd: ~[u8] = ~[];
                                                                let mut cmd_byte: u8;
                                                                let mut i = 0;
                                                                loop {
                                                                    cmd_byte = rd.read_byte() as u8;
                                                                    if cmd_byte == closer[i] as u8 {
                                                                        if i == closer.len() - 1 {
                                                                            break;
                                                                        }

                                                                        i += 1;
                                                                    }
                                                                    else {
                                                                        i = 0;
                                                                    }

                                                                    if cmd_byte != 0xFF {
                                                                        cmd.push(cmd_byte);
                                                                    }
                                                                }

                                                          port.send(str::from_utf8(cmd.slice_to(cmd.len() - 4)));
                                                          let result = port.recv();
                                                          file_data.stream.write(result.as_bytes());
                                                          }
                                                        },
                                _                   =>  { if rd_byte != 0xFF {
                                                                file_data.stream.write(&[rd_byte]);
                                                          }
                                                        }
                            }
                          }
                          port.send(~"end");
                        }
        Err(err)    =>  { println(err); }
    }

}

fn do_gash(chan: &DuplexStream<~str, ~str>) {
    let mut gash = run::Process::new("./gash", &[], run::ProcessOptions::new());
    let mut cmd: ~str;
    let mut result: ~str;
    let gin = gash.input();
    let gout = gash.output();
    let mut res: ~[u8];
    let mut prompt: ~[u8] = ~[];
    let mut res_byte: u8;
    for _ in range(0,8) {
        prompt.push(0);
    }

    gout.read(prompt, 8);
    // Insecure. We should use some other means of communicating the need to die.
    loop {
        cmd = chan.recv();
        if cmd == ~"end" {
            break;
        }

        cmd.push_str("\n");
        res = ~[];
        gin.write(cmd.as_bytes());
        loop {
            res_byte = gout.read_byte() as u8;
            if res_byte == '\0' as u8{
                break;
            }

            res.push(res_byte);
        }

        gout.read(prompt, 7);
        result = str::from_utf8(res);
        chan.send(result.clone());
    }

    gash.destroy();
}

fn writeFile(tf: &mut sched_msg) ->  ~[u8] {
    let mut file: ~[u8] = ~[];
    match io::file_reader(tf.filepath) {
        Ok(rd)      =>  { while !rd.eof() {
                            let mut buffer: ~[u8] = vec::with_capacity(2048u);
                            unsafe { vec::raw::set_len(&mut buffer, 2048u); }
                            let read = rd.read(buffer, 2048u);
                            unsafe { vec::raw::set_len(&mut buffer, read); }
                            file.push_all(buffer);
                            tf.stream.write(buffer);
                            }
                        }
        Err(err)    =>  { println(err); }
    }
    file
}

<commit_msg>everything but time-dependent cache<commit_after>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Starting code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu and David Evans
// Version 0.3

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::{SocketAddr, Ipv4Addr};
use std::io::println;
use std::cell::Cell;
use std::{os, str, io, run, task, vec};
use extra::arc;
use extra::priority_queue::PriorityQueue;
use std::comm::*;
use std::cast;
use extra::comm::DuplexStream;
use std::hashmap::HashSet;
use std::path::Path;

static PORT:  int = 4414;
static IP: &'static str = "127.0.0.1";
static mut visitor_count: uint = 0;

#[deriving(Clone)]
struct access_t {
    filepath: ~std::path::PosixPath,
    size: i64,
    data: ~[u8]
}

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath,
    priority: uint
}

impl std::cmp::Ord for sched_msg {
    fn lt(&self, other: &sched_msg) -> bool {
        return self.priority > other.priority;
    }
}

impl std::cmp::Ord for access_t {
    fn lt(&self, other: &access_t)  ->  bool {
        self.size > other.size
    }
}

fn main() {
    let req_heap: PriorityQueue<sched_msg> = PriorityQueue::new();
    let shared_req_heap = arc::RWArc::new(req_heap);
    let add_vec = shared_req_heap.clone();
    let take_vec = shared_req_heap.clone();

    let cache: PriorityQueue<access_t> = PriorityQueue::new();
    let shared_cache = arc::RWArc::new(cache);
    let rem_cache = shared_cache.clone();
    let check_cache = shared_cache.clone();

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    /*do spawn {
        loop {
            timer::sleep(7000);
            do rem_cache.write |rc| {
                (*rc).clear();
            }
        }
    }*/

    // dequeue file requests, and send responses.
    // FIFO
    do spawn {
        let (sm_port, sm_chan) = stream();

        // a task for sending responses.
        do spawn {
            loop {
                let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle
                let fpath = tf.filepath.clone();
                println(fmt!("begin serving file [%?]", tf.filepath.to_str()));
                // A web server should always reply a HTTP header for any legal HTTP request.
                let extension = fpath.components().last();
                match extension.rfind('.') {
                    Some(x) =>  {
                        match extension.slice_from(x+1) {
                            "html"|"xhtml"|"txt"|"xml"  => { tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes()); }
                            _                           => { tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream; charset=UTF-8\r\n\r\n".as_bytes()); }
                        }
                    }
                    _       =>  { tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream; charset=UTF-8\r\n\r\n".as_bytes()); }
                }

                do check_cache.write |cc| {
                    let mut cached = false;
                    for elem in (*cc).iter() {
                        if elem.filepath == fpath {
                            tf.stream.write(elem.data);
                            cached = true;
                            break;
                        }
                    }
                    if !cached {
                        if tf.filepath.get_mode().unwrap() % 2 == 1 {
                            execFile(&mut tf);
                            // No cache for dynamically-generated files.
                        }
                        else {
                            let data = writeFile(&mut tf);
                            let size = fpath.get_size().unwrap();
                            if (*cc).len() < 10 {
                                (*cc).push(access_t { filepath: fpath.clone(), size: size, data: data });
                            }
                            else if (*cc).top().size < size { (*cc).push_pop(access_t { filepath: fpath.clone(), size: size, data: data }); }
                        }
                    }
                }

                println(fmt!("finish file [%?]", fpath.to_str()));
            }
        }

        loop {
            port.recv(); // wait for arrving notification
            do take_vec.write |vec| {
                if ((*vec).len() > 0) {
                    // LIFO didn't make sense in service scheduling, so we modify it as FIFO by using shift_opt() rather than pop().
                    let tf: sched_msg = (*vec).pop();
                    println(fmt!("shift from queue, size: %ud", (*vec).len()));
                    sm_chan.send(tf); // send the request to send-response-task to serve.
                }
            }
        }
    }

    // IP addresses to give higher priority
    let mut ip_vals: HashSet<u32> = HashSet::with_capacity(9000);
    ip_vals.insert((192 as u32 << 24) + (168 as u32 << 16));
    ip_vals.insert((127 as u32 << 24) + (143 as u32 << 16));
    ip_vals.insert((137 as u32 << 24) + (54 as u32 << 16));
    ip_vals.insert(0);
    let shared_ip_map = arc::RWArc::new(ip_vals);

    let shared_count = arc::RWArc::new(0);

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None => { println(fmt!("Error: Invalid IP address <%s>", IP));
                                                     return;},
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on %s:%d ...", ip.to_str(), PORT));
    let mut acceptor = socket.listen().unwrap();

    for stream in acceptor.incoming() {
        let stream = Cell::new(stream);

        let incr_count = shared_count.clone();

        // Start a new task to handle the each connection
        let child_chan = chan.clone();
        let shared_ip_map = shared_ip_map.clone();
        let child_add_vec = add_vec.clone();

        do spawn {
            do incr_count.write |count| {
                *count += 1;
            }

            let mut stream = stream.take();
            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);

            let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
            if req_group.len() > 2 {
                let path = req_group[1];
                println(fmt!("Request for path: \n%?", path));
                // More better path security!
                let unclean_path = os::getcwd().push(Path(path).to_str()).to_str();
                let mut file_path = ~os::getcwd();
                // paths are always normalized so a/b/../c becomes a/c
                if unclean_path.starts_with(file_path.to_str()) {
                    file_path = ~file_path.push(path);
                }
                if !os::path_exists(file_path) || os::path_is_dir(file_path) {
                    println(fmt!("Request received:\n%s", request_str));
                    let response: ~str = fmt!(
                        "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                         <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: %u

                         \r\n", incr_count.read(|c| { *c }));

                    stream.write(response.as_bytes());
                }
                else {
                    // Requests scheduling

                    let mut priority = file_path.stat().unwrap().st_size as uint;
                    unsafe {
                        match stream {
                            Some(ref s) => {
                                    let stream = cast::transmute_mut(s);
                                    let pn = stream.peer_name().unwrap();
                                    println(fmt!("Peer is: %?", pn));
                                    match pn.ip {
                                        Ipv4Addr(a, b, c, d) => {
                                                                // Since we are sharing the ip_map it must be read
                                                                do shared_ip_map.read |map| {
                                                                    if check_ip(a,b,c,d, map) {
                                                                        priority = 1;
                                                                        println("local request!");
                                                                    }
                                                                }
                                                            },
                                        _                    =>  fail!()
                                    }
                            },
                            _    => fail!()
                        };
                    }
                    let msg: sched_msg = sched_msg{stream: stream, filepath: file_path.clone(), priority: priority};
                    let (sm_port, sm_chan) = std::comm::stream();
                    sm_chan.send(msg);

                    do child_add_vec.write |vec| {
                        let msg = sm_port.recv();
                        (*vec).push(msg); // enqueue new request.
                        println("add to queue");
                    }
                    child_chan.send(""); //notify the new arriving request.
                    println(fmt!("get file request: %?", file_path));
                }
            }
            println!("connection terminates")
        }
    }
}

// Looks up an ip prefix in the hashset by trying each octet
fn check_ip(a: u8, b: u8, c: u8, d: u8, map: &HashSet<u32>) -> bool {
    let mut mut_ip = a as u32 << 24;
    if map.contains(&mut_ip) {
        return true;
    }
    mut_ip += (b as u32 << 16);
    if map.contains(&mut_ip) {
        return true;
    }
    mut_ip += (c as u32 << 8);
    if map.contains(&mut_ip) {
        return true;
    }
    mut_ip += (d as u32);
    if map.contains(&mut_ip) {
        return true;
    }
    false
}

fn execFile(file_data: &mut sched_msg) {
    let (port, chan) = DuplexStream();
    do task::spawn_supervised {
        do_gash(&chan)
    }
    let mut file_data = file_data;
    match io::file_reader(file_data.filepath) {
        Ok(rd)      =>  {   let closer = ~['\"',' ', '-','-','>'];
                            while !rd.eof() {
                            let rd_byte = rd.read_byte() as u8;

                            match rd_byte {
                                0x3c =>  { let mut open: ~[u8] = ~[0,0,0,0,0,0,0,0,0,0,0,0,0,0];
                                                          rd.read(open, 14);
                                                          if str::from_utf8(open) == ~"!--#exec cmd=\"" {
                                                                let mut cmd: ~[u8] = ~[];
                                                                let mut cmd_byte: u8;
                                                                let mut i = 0;
                                                                loop {
                                                                    cmd_byte = rd.read_byte() as u8;
                                                                    if cmd_byte == closer[i] as u8 {
                                                                        if i == closer.len() - 1 {
                                                                            break;
                                                                        }

                                                                        i += 1;
                                                                    }
                                                                    else {
                                                                        i = 0;
                                                                    }

                                                                    if cmd_byte != 0xFF {
                                                                        cmd.push(cmd_byte);
                                                                    }
                                                                }

                                                          port.send(str::from_utf8(cmd.slice_to(cmd.len() - 4)));
                                                          let result = port.recv();
                                                          file_data.stream.write(result.as_bytes());
                                                          }
                                                        },
                                _                   =>  { if rd_byte != 0xFF {
                                                                file_data.stream.write(&[rd_byte]);
                                                          }
                                                        }
                            }
                          }
                          port.send(~"end");
                        }
        Err(err)    =>  { println(err); }
    }

}

fn do_gash(chan: &DuplexStream<~str, ~str>) {
    let mut gash = run::Process::new("./gash", &[], run::ProcessOptions::new());
    let mut cmd: ~str;
    let mut result: ~str;
    let gin = gash.input();
    let gout = gash.output();
    let mut res: ~[u8];
    let mut prompt: ~[u8] = ~[];
    let mut res_byte: u8;
    for _ in range(0,8) {
        prompt.push(0);
    }

    gout.read(prompt, 8);
    // Insecure. We should use some other means of communicating the need to die.
    loop {
        cmd = chan.recv();
        if cmd == ~"end" {
            break;
        }

        cmd.push_str("\n");
        res = ~[];
        gin.write(cmd.as_bytes());
        loop {
            res_byte = gout.read_byte() as u8;
            if res_byte == '\0' as u8{
                break;
            }

            res.push(res_byte);
        }

        gout.read(prompt, 7);
        result = str::from_utf8(res);
        chan.send(result.clone());
    }

    gash.destroy();
}

fn writeFile(tf: &mut sched_msg) ->  ~[u8] {
    let mut file: ~[u8] = ~[];
    let mut writes = 0;
    match io::file_reader(tf.filepath) {
        Ok(rd)      =>  { while !rd.eof() {
                            let mut buffer: ~[u8] = vec::with_capacity(20971520u);
                            unsafe { vec::raw::set_len(&mut buffer, 20971520u); }
                            let read = rd.read(buffer, 20971520u);
                            unsafe { vec::raw::set_len(&mut buffer, read); }
                            file.push_all(buffer);
                            tf.stream.write(buffer);
                            writes += 1;
                          }
                          println(fmt!("%d", writes));
                        }
        Err(err)    =>  { println(err); }
    }
    file
}

<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match self.instruction_pointer {
            None => {},
            Some(mut index) => {
                while index < self.instructions.len() {
                    let command = self.instructions[index];
                    if command == Command::JumpForward { self.current_depth = self.current_depth + 1}
                    if command == Command::JumpBackward { self.current_depth = self.current_depth - 1}
                    vm.apply(command);
                    index = index + 1;
                }
                self.instruction_pointer = Some(index);
            }
        }
    }

    fn seek_forward(&mut self, mut index: usize) -> usize {
        while self.current_depth != self.goal_depth.unwrap() && index < self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth = self.current_depth + 1,
                Command::JumpBackward => self.current_depth = self.current_depth - 1,
                _ => {},
            }
            index = index + 1;
        }
        return index;
    }

    fn handle_jump_forward(&mut self, vm: &VM, mut index: usize) -> usize {
        if vm.cells[vm.data_pointer] == 0 {
            self.goal_depth = Some(self.current_depth);
            while self.current_depth != self.goal_depth.unwrap() && index < self.instructions.len() {
                match self.instructions[index] {
                    Command::JumpForward => self.current_depth = self.current_depth + 1,
                    Command::JumpBackward => self.current_depth = self.current_depth - 1,
                    _ => {},
                }
                index = index + 1;
            }
            return index;
        } else {
            self.current_depth = self.current_depth + 1;
            return index;
        }
    }
}
<commit_msg>Define handle_jump_forward in terms of seek_forward<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match self.instruction_pointer {
            None => {},
            Some(mut index) => {
                while index < self.instructions.len() {
                    let command = self.instructions[index];
                    if command == Command::JumpForward { self.current_depth = self.current_depth + 1}
                    if command == Command::JumpBackward { self.current_depth = self.current_depth - 1}
                    vm.apply(command);
                    index = index + 1;
                }
                self.instruction_pointer = Some(index);
            }
        }
    }

    fn seek_forward(&mut self, mut index: usize) -> usize {
        while self.current_depth != self.goal_depth.unwrap() && index < self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth = self.current_depth + 1,
                Command::JumpBackward => self.current_depth = self.current_depth - 1,
                _ => {},
            }
            index = index + 1;
        }
        return index;
    }

    fn handle_jump_forward(&mut self, vm: &VM, index: usize) -> usize {
        if vm.cells[vm.data_pointer] == 0 {
            self.goal_depth = Some(self.current_depth);
            return self.seek_forward(index)
        } else {
            self.current_depth = self.current_depth + 1;
            return index;
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(target_arch="x86_64")]
pub use self::x86_64::{ cpu, drivers };

#[cfg(target_arch="x86_64")]
pub mod x86_64;

#[cfg(target_arch = "x86")]
pub use self::x86::{ cpu, drivers };

#[cfg(target_arch = "x86")]
pub mod x86;
<commit_msg>Made arch impl modules no longer pub<commit_after>
#[cfg(target_arch="x86_64")]
mod x86_64;

#[cfg(target_arch="x86_64")]
pub use self::x86_64::{ cpu, drivers };

#[cfg(target_arch = "x86")]
mod x86;

#[cfg(target_arch = "x86")]
pub use self::x86::{ cpu, drivers };
<|endoftext|>


<commit_before>#[macro_use]
pub mod proto;

use bifrost_hasher::hash_str;
use futures::prelude::*;
use futures::{future, Future};
use std::collections::HashMap;
use std::io;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use tcp;
use utils::async_locks::{Mutex, RwLock};
use utils::time;
use utils::u8vec::*;
use DISABLE_SHORTCUT;

lazy_static! {
    pub static ref DEFAULT_CLIENT_POOL: ClientPool = ClientPool::new();
}

#[derive(Serialize, Deserialize, Debug)]
pub enum RPCRequestError {
    FunctionIdNotFound,
    ServiceIdNotFound,
    Other,
}

#[derive(Debug)]
pub enum RPCError {
    IOError(io::Error),
    RequestError(RPCRequestError),
}

pub trait RPCService: Sync + Send {
    fn dispatch(&self, data: Vec<u8>) -> Box<Future<Item = Vec<u8>, Error = RPCRequestError>>;
    fn register_shortcut_service(&self, service_ptr: usize, server_id: u64, service_id: u64);
}

pub struct Server {
    services: RwLock<HashMap<u64, Arc<RPCService>>>,
    pub address: String,
    pub server_id: u64,
}

pub struct ClientPool {
    clients: Arc<Mutex<HashMap<u64, Arc<RPCClient>>>>,
}

fn encode_res(res: Result<Vec<u8>, RPCRequestError>) -> Vec<u8> {
    match res {
        Ok(vec) => [0u8; 1].iter().cloned().chain(vec.into_iter()).collect(),
        Err(e) => {
            let err_id = match e {
                RPCRequestError::FunctionIdNotFound => 1u8,
                RPCRequestError::ServiceIdNotFound => 2u8,
                _ => 255u8,
            };
            vec![err_id]
        }
    }
}

fn decode_res(res: io::Result<Vec<u8>>) -> Result<Vec<u8>, RPCError> {
    match res {
        Ok(res) => {
            if res[0] == 0u8 {
                Ok(res.into_iter().skip(1).collect())
            } else {
                match res[0] {
                    1u8 => Err(RPCError::RequestError(RPCRequestError::FunctionIdNotFound)),
                    2u8 => Err(RPCError::RequestError(RPCRequestError::ServiceIdNotFound)),
                    _ => Err(RPCError::RequestError(RPCRequestError::Other)),
                }
            }
        }
        Err(e) => Err(RPCError::IOError(e)),
    }
}

impl Server {
    pub fn new(address: &String) -> Arc<Server> {
        Arc::new(Server {
            services: RwLock::new(HashMap::new()),
            address: address.clone(),
            server_id: hash_str(address),
        })
    }
    pub fn listen(server: &Arc<Server>) {
        let address = &server.address;
        let server = server.clone();
        tcp::server::Server::new(
            address,
            tcp::server::ServerCallback::new(move |data| {
                let (svr_id, data) = extract_u64_head(data);
                let svr_map = server.services.read();
                let service = svr_map.get(&svr_id);
                match service {
                    Some(ref service) => {
                        let service = service.clone();
                        Box::new(service.dispatch(data).then(|r| Ok(encode_res(r))))
                    }
                    None => Box::new(future::finished(encode_res(Err(
                        RPCRequestError::ServiceIdNotFound,
                    )))),
                }
            }),
        );
    }
    pub fn listen_and_resume(server: &Arc<Server>) {
        let server = server.clone();
        thread::spawn(move || {
            let server = server;
            Server::listen(&server);
        });
    }
    pub fn register_service<T>(&self, service_id: u64, service: &Arc<T>)
    where
        T: RPCService + Sized + 'static,
    {
        let service = service.clone();
        if !DISABLE_SHORTCUT {
            let service_ptr = Arc::into_raw(service.clone()) as usize;
            service.register_shortcut_service(service_ptr, self.server_id, service_id);
        } else {
            println!("SERVICE SHORTCUT DISABLED");
        }
        self.services.write().insert(service_id, service);
    }

    pub fn remove_service(&self, service_id: u64) {
        self.services.write().remove(&service_id);
    }
    pub fn address(&self) -> &String {
        &self.address
    }
}

pub struct RPCClient {
    client: Mutex<tcp::client::Client>,
    pub server_id: u64,
    pub address: String,
}

impl RPCClient {
    pub fn send_async(
        &self,
        svr_id: u64,
        data: Vec<u8>,
    ) -> impl Future<Item = Vec<u8>, Error = RPCError> {
        self.client
            .lock_async()
            .map_err(|_| io::Error::from(io::ErrorKind::Other))
            .and_then(move |client| client.send_async(prepend_u64(svr_id, data)))
            .then(move |res| decode_res(res))
    }
    pub fn new_async(addr: String) -> impl Future<Item = Arc<RPCClient>, Error = io::Error> {
        tcp::client::Client::connect_async(addr.clone()).map(|client| {
            Arc::new(RPCClient {
                server_id: client.server_id,
                client: Mutex::new(client),
                address: addr,
            })
        })
    }

    pub fn with_timeout(
        addr: String,
        timeout: Duration,
    ) -> impl Future<Item = Arc<RPCClient>, Error = io::Error> {
        tcp::client::Client::connect_with_timeout_async(addr.clone(), timeout).map(|client| {
            Arc::new(RPCClient {
                server_id: client.server_id,
                client: Mutex::new(client),
                address: addr,
            })
        })
    }
}

impl ClientPool {
    pub fn new() -> ClientPool {
        ClientPool {
            clients: Arc::new(Mutex::new(HashMap::new())),
        }
    }

    pub fn get_async(
        &self,
        addr: &String,
    ) -> impl Future<Item = Arc<RPCClient>, Error = io::Error> {
        let addr_clone = addr.clone();
        let server_id = hash_str(addr);
        self.get_by_id_async(server_id, move |_| addr_clone)
    }

    pub fn get(&self, addr: &String) -> Result<Arc<RPCClient>, io::Error> {
        let server_id = hash_str(&addr);
        let mut clients = self.clients.lock();
        if clients.contains_key(&server_id) {
            let client = clients.get(&server_id).unwrap().clone();
            Ok(client)
        } else {
            let client = RPCClient::new_async(addr.clone()).wait()?;
            clients.insert(server_id, client.clone());
            return Ok(client.clone());
        }
    }

    pub fn get_by_id_async<F>(
        &self,
        server_id: u64,
        addr_fn: F,
    ) -> impl Future<Item = Arc<RPCClient>, Error = io::Error>
    where
        F: FnOnce(u64) -> String,
    {
        self.clients
            .lock_async()
            .map_err(|_| io::Error::from(io::ErrorKind::Other))
            .and_then(
                move |mut clients| -> Box<Future<Item = Arc<RPCClient>, Error = io::Error>> {
                    if clients.contains_key(&server_id) {
                        let client = clients.get(&server_id).unwrap().clone();
                        box future::ok(client)
                    } else {
                        box RPCClient::new_async(addr_fn(server_id)).map(move |client| {
                            clients.insert(server_id, client.clone());
                            return client.clone();
                        })
                    }
                },
            )
    }
}
<commit_msg>get by id<commit_after>#[macro_use]
pub mod proto;

use bifrost_hasher::hash_str;
use futures::prelude::*;
use futures::{future, Future};
use std::collections::HashMap;
use std::io;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use tcp;
use utils::async_locks::{Mutex, RwLock};
use utils::time;
use utils::u8vec::*;
use DISABLE_SHORTCUT;

lazy_static! {
    pub static ref DEFAULT_CLIENT_POOL: ClientPool = ClientPool::new();
}

#[derive(Serialize, Deserialize, Debug)]
pub enum RPCRequestError {
    FunctionIdNotFound,
    ServiceIdNotFound,
    Other,
}

#[derive(Debug)]
pub enum RPCError {
    IOError(io::Error),
    RequestError(RPCRequestError),
}

pub trait RPCService: Sync + Send {
    fn dispatch(&self, data: Vec<u8>) -> Box<Future<Item = Vec<u8>, Error = RPCRequestError>>;
    fn register_shortcut_service(&self, service_ptr: usize, server_id: u64, service_id: u64);
}

pub struct Server {
    services: RwLock<HashMap<u64, Arc<RPCService>>>,
    pub address: String,
    pub server_id: u64,
}

pub struct ClientPool {
    clients: Arc<Mutex<HashMap<u64, Arc<RPCClient>>>>,
}

fn encode_res(res: Result<Vec<u8>, RPCRequestError>) -> Vec<u8> {
    match res {
        Ok(vec) => [0u8; 1].iter().cloned().chain(vec.into_iter()).collect(),
        Err(e) => {
            let err_id = match e {
                RPCRequestError::FunctionIdNotFound => 1u8,
                RPCRequestError::ServiceIdNotFound => 2u8,
                _ => 255u8,
            };
            vec![err_id]
        }
    }
}

fn decode_res(res: io::Result<Vec<u8>>) -> Result<Vec<u8>, RPCError> {
    match res {
        Ok(res) => {
            if res[0] == 0u8 {
                Ok(res.into_iter().skip(1).collect())
            } else {
                match res[0] {
                    1u8 => Err(RPCError::RequestError(RPCRequestError::FunctionIdNotFound)),
                    2u8 => Err(RPCError::RequestError(RPCRequestError::ServiceIdNotFound)),
                    _ => Err(RPCError::RequestError(RPCRequestError::Other)),
                }
            }
        }
        Err(e) => Err(RPCError::IOError(e)),
    }
}

impl Server {
    pub fn new(address: &String) -> Arc<Server> {
        Arc::new(Server {
            services: RwLock::new(HashMap::new()),
            address: address.clone(),
            server_id: hash_str(address),
        })
    }
    pub fn listen(server: &Arc<Server>) {
        let address = &server.address;
        let server = server.clone();
        tcp::server::Server::new(
            address,
            tcp::server::ServerCallback::new(move |data| {
                let (svr_id, data) = extract_u64_head(data);
                let svr_map = server.services.read();
                let service = svr_map.get(&svr_id);
                match service {
                    Some(ref service) => {
                        let service = service.clone();
                        Box::new(service.dispatch(data).then(|r| Ok(encode_res(r))))
                    }
                    None => Box::new(future::finished(encode_res(Err(
                        RPCRequestError::ServiceIdNotFound,
                    )))),
                }
            }),
        );
    }
    pub fn listen_and_resume(server: &Arc<Server>) {
        let server = server.clone();
        thread::spawn(move || {
            let server = server;
            Server::listen(&server);
        });
    }
    pub fn register_service<T>(&self, service_id: u64, service: &Arc<T>)
    where
        T: RPCService + Sized + 'static,
    {
        let service = service.clone();
        if !DISABLE_SHORTCUT {
            let service_ptr = Arc::into_raw(service.clone()) as usize;
            service.register_shortcut_service(service_ptr, self.server_id, service_id);
        } else {
            println!("SERVICE SHORTCUT DISABLED");
        }
        self.services.write().insert(service_id, service);
    }

    pub fn remove_service(&self, service_id: u64) {
        self.services.write().remove(&service_id);
    }
    pub fn address(&self) -> &String {
        &self.address
    }
}

pub struct RPCClient {
    client: Mutex<tcp::client::Client>,
    pub server_id: u64,
    pub address: String,
}

impl RPCClient {
    pub fn send_async(
        &self,
        svr_id: u64,
        data: Vec<u8>,
    ) -> impl Future<Item = Vec<u8>, Error = RPCError> {
        self.client
            .lock_async()
            .map_err(|_| io::Error::from(io::ErrorKind::Other))
            .and_then(move |client| client.send_async(prepend_u64(svr_id, data)))
            .then(move |res| decode_res(res))
    }
    pub fn new_async(addr: String) -> impl Future<Item = Arc<RPCClient>, Error = io::Error> {
        tcp::client::Client::connect_async(addr.clone()).map(|client| {
            Arc::new(RPCClient {
                server_id: client.server_id,
                client: Mutex::new(client),
                address: addr,
            })
        })
    }

    pub fn with_timeout(
        addr: String,
        timeout: Duration,
    ) -> impl Future<Item = Arc<RPCClient>, Error = io::Error> {
        tcp::client::Client::connect_with_timeout_async(addr.clone(), timeout).map(|client| {
            Arc::new(RPCClient {
                server_id: client.server_id,
                client: Mutex::new(client),
                address: addr,
            })
        })
    }
}

impl ClientPool {
    pub fn new() -> ClientPool {
        ClientPool {
            clients: Arc::new(Mutex::new(HashMap::new())),
        }
    }

    pub fn get_async(
        &self,
        addr: &String,
    ) -> impl Future<Item = Arc<RPCClient>, Error = io::Error> {
        let addr_clone = addr.clone();
        let server_id = hash_str(addr);
        self.get_by_id_async(server_id, move |_| addr_clone)
    }

    pub fn get(&self, addr: &String) -> Result<Arc<RPCClient>, io::Error> {
        let addr_clone = addr.clone();
        let server_id = hash_str(addr);
        self.get_by_id(server_id, move |_| addr_clone)
    }

    pub fn get_by_id<F>(&self, server_id: u64, addr_fn: F) -> Result<Arc<RPCClient>, io::Error>
        where F: FnOnce(u64) -> String
    {
        let mut clients = self.clients.lock();
        if clients.contains_key(&server_id) {
            let client = clients.get(&server_id).unwrap().clone();
            Ok(client)
        } else {
            let client = RPCClient::new_async(addr_fn(server_id)).wait()?;
            clients.insert(server_id, client.clone());
            return Ok(client.clone());
        }
    }

    pub fn get_by_id_async<F>(
        &self,
        server_id: u64,
        addr_fn: F,
    ) -> impl Future<Item = Arc<RPCClient>, Error = io::Error>
    where
        F: FnOnce(u64) -> String,
    {
        self.clients
            .lock_async()
            .map_err(|_| io::Error::from(io::ErrorKind::Other))
            .and_then(
                move |mut clients| -> Box<Future<Item = Arc<RPCClient>, Error = io::Error>> {
                    if clients.contains_key(&server_id) {
                        let client = clients.get(&server_id).unwrap().clone();
                        box future::ok(client)
                    } else {
                        box RPCClient::new_async(addr_fn(server_id)).map(move |client| {
                            clients.insert(server_id, client.clone());
                            return client.clone();
                        })
                    }
                },
            )
    }
}
<|endoftext|>


<commit_before>#![crate_name = "rboy"]
#![license    = "MIT" ]
#![feature(phase)]

#[phase(plugin, link)] extern crate log;
                       extern crate getopts;
                       extern crate sdl2;
                       extern crate rboy;

use rboy::device::Device;
use std::time::Duration;
use std::sync::{Arc,RWLock};
use std::comm::{Sender,Receiver,Disconnected,Empty};

static SCALE: uint = 2;
static EXITCODE_INCORRECTOPTIONS: int = 1;
static EXITCODE_CPULOADFAILS: int = 2;

#[cfg(not(test))]
fn set_exit_status(exitcode: int)
{
    std::os::set_exit_status(exitcode);
}

fn main() {
	let args = std::os::args();
	let opts = &[ getopts::optflag("s", "serial", "Output serial to stdout"), getopts::optflag("c", "classic", "Force Classic mode") ];
	let matches = match getopts::getopts(args.tail(), opts) {
		Ok(m) => { m }
		Err(f) => { println!("{}", f); return }
	};

	let filename = if !matches.free.is_empty() {
		matches.free[0].clone()
	} else {
		let mut info_start = args[0].clone();
		info_start.push_str(" <filename>");
		println!("{}", getopts::usage(info_start.as_slice(), opts));
		set_exit_status(EXITCODE_INCORRECTOPTIONS);
		return;
	};

	sdl2::init(sdl2::INIT_VIDEO);
	let window = match sdl2::video::Window::new("RBoy - A gameboy in Rust",
												sdl2::video::WindowPos::PosUndefined,
												sdl2::video::WindowPos::PosUndefined,
												160*SCALE as int,
												144*SCALE as int,
												sdl2::video::WindowFlags::empty()) {
		Ok(window) => window,
		Err(err) => panic!("failed to open window: {}", err),
	};
	let renderer = match sdl2::render::Renderer::from_window(window, sdl2::render::RenderDriverIndex::Auto, sdl2::render::ACCELERATED) {
		Ok(screen) => screen,
		Err(err) => panic!("failed to open screen: {}", err),
	};

	let (sdl_tx, cpu_rx) = std::comm::channel();
	let (cpu_tx, sdl_rx) = std::comm::channel();
	let rawscreen = [0x00u8,.. 160*144*3];
	let arc = Arc::new(RWLock::new(rawscreen));
	let arc2 = arc.clone();

	spawn(proc() cpuloop(&cpu_tx, &cpu_rx, arc2, filename.as_slice(), &matches));

	let mut timer = std::io::timer::Timer::new().unwrap();
	let periodic = timer.periodic(Duration::milliseconds(8));

	'main : loop {
		periodic.recv();
		match sdl_rx.try_recv() {
			Err(Disconnected) => { break 'main },
			Ok(_) => recalculate_screen(&renderer, &arc),
			Err(Empty) => {},
		}
		'event : loop {
			match sdl2::event::poll_event() {
				sdl2::event::Event::Quit(_) => break 'main,
				sdl2::event::Event::None => break 'event,
				sdl2::event::Event::KeyDown(_, _, sdl2::keycode::KeyCode::Escape, _, _, _)
					=> break 'main,
				sdl2::event::Event::KeyDown(_, _, sdl2::keycode::KeyCode::LShift, _, _, _)
					=> sdl_tx.send(GBEvent::SpeedUp),
				sdl2::event::Event::KeyUp(_, _, sdl2::keycode::KeyCode::LShift, _, _, _)
					=> sdl_tx.send(GBEvent::SlowDown),
				sdl2::event::Event::KeyDown(_, _, sdlkey, _, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => sdl_tx.send(GBEvent::KeyDown(key)),
						None => {},
					}
				},
				sdl2::event::Event::KeyUp(_, _, sdlkey, _, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => sdl_tx.send(GBEvent::KeyUp(key)),
						None => {},
					}
				},
				_ => {}
			}
		}
	}
}

fn sdl_to_keypad(key: sdl2::keycode::KeyCode) -> Option<rboy::KeypadKey> {
	match key {
		sdl2::keycode::KeyCode::Z => Some(rboy::KeypadKey::A),
		sdl2::keycode::KeyCode::X => Some(rboy::KeypadKey::B),
		sdl2::keycode::KeyCode::Up => Some(rboy::KeypadKey::Up),
		sdl2::keycode::KeyCode::Down => Some(rboy::KeypadKey::Down),
		sdl2::keycode::KeyCode::Left => Some(rboy::KeypadKey::Left),
		sdl2::keycode::KeyCode::Right => Some(rboy::KeypadKey::Right),
		sdl2::keycode::KeyCode::Space => Some(rboy::KeypadKey::Select),
		sdl2::keycode::KeyCode::Return => Some(rboy::KeypadKey::Start),
		_ => None,
	}
}

fn recalculate_screen(screen: &sdl2::render::Renderer, arc: &Arc<RWLock<[u8,.. 160*144*3]>>) {
	screen.set_draw_color(sdl2::pixels::Color::RGB(0xFF, 0xFF, 0xFF)).unwrap();
	screen.clear().unwrap();

	let data = arc.read();
	for y in range(0u, 144) {
		for x in range(0u, 160) {
			screen.set_draw_color(sdl2::pixels::Color::RGB(data[y*160*3 + x*3 + 0],
															data[y*160*3 + x*3 + 1],
															data[y*160*3 + x*3 + 2])).unwrap();
			screen.draw_rect(&sdl2::rect::Rect::new((x*SCALE) as i32, (y*SCALE) as i32, SCALE as i32, SCALE as i32)).unwrap();
		}
	}
	screen.present();
}

enum GBEvent {
	KeyUp(rboy::KeypadKey),
	KeyDown(rboy::KeypadKey),
	SpeedUp,
	SlowDown,
}

fn cpuloop(cpu_tx: &Sender<uint>, cpu_rx: &Receiver<GBEvent>, arc: Arc<RWLock<[u8,.. 160*144*3]>>, filename: &str, matches: &getopts::Matches) {
	let opt_c = match matches.opt_present("classic") {
		true => Device::new(filename),
		false => Device::new_cgb(filename),
	};
	let mut c = match opt_c
	{
		Some(cpu) => { cpu },
		None => { error!("Could not get a valid gameboy"); set_exit_status(EXITCODE_CPULOADFAILS); return; },
	};
	c.set_stdout(matches.opt_present("serial"));

	let mut timer = std::io::timer::Timer::new().unwrap();
	let periodic = timer.periodic(Duration::milliseconds(8));
	let mut limit_speed = true;

	let waitticks = (4194.304f32 * 4.0) as uint;

	let mut ticks = 0;
	'cpuloop: loop {
		while ticks < waitticks {
			ticks += c.do_cycle();
			if c.check_and_reset_gpu_updated() {
				let mut data = arc.write();
				let gpu_data = c.get_gpu_data();
				for i in range(0, data.len()) { data[i] = gpu_data[i]; }
				if cpu_tx.send_opt(0).is_err() { break 'cpuloop };
			}
		}
		ticks -= waitticks;
		if limit_speed { periodic.recv(); }

		match cpu_rx.try_recv() {
			Ok(event) => match event {
				GBEvent::KeyUp(key) => c.keyup(key),
				GBEvent::KeyDown(key) => c.keydown(key),
				GBEvent::SpeedUp => limit_speed = false,
				GBEvent::SlowDown => limit_speed = true,
			},
			Err(Empty) => {},
			Err(Disconnected) => { break },
		};
	}
}
<commit_msg>Clone the screen buffer for speed<commit_after>#![crate_name = "rboy"]
#![license    = "MIT" ]
#![feature(phase)]

#[phase(plugin, link)] extern crate log;
                       extern crate getopts;
                       extern crate sdl2;
                       extern crate rboy;

use rboy::device::Device;
use std::time::Duration;
use std::sync::{Arc,RWLock};
use std::comm::{Sender,Receiver,Disconnected,Empty};

static SCALE: uint = 2;
static EXITCODE_INCORRECTOPTIONS: int = 1;
static EXITCODE_CPULOADFAILS: int = 2;

#[cfg(not(test))]
fn set_exit_status(exitcode: int)
{
    std::os::set_exit_status(exitcode);
}

fn main() {
	let args = std::os::args();
	let opts = &[ getopts::optflag("s", "serial", "Output serial to stdout"), getopts::optflag("c", "classic", "Force Classic mode") ];
	let matches = match getopts::getopts(args.tail(), opts) {
		Ok(m) => { m }
		Err(f) => { println!("{}", f); return }
	};

	let filename = if !matches.free.is_empty() {
		matches.free[0].clone()
	} else {
		let mut info_start = args[0].clone();
		info_start.push_str(" <filename>");
		println!("{}", getopts::usage(info_start.as_slice(), opts));
		set_exit_status(EXITCODE_INCORRECTOPTIONS);
		return;
	};

	sdl2::init(sdl2::INIT_VIDEO);
	let window = match sdl2::video::Window::new("RBoy - A gameboy in Rust",
												sdl2::video::WindowPos::PosUndefined,
												sdl2::video::WindowPos::PosUndefined,
												160*SCALE as int,
												144*SCALE as int,
												sdl2::video::WindowFlags::empty()) {
		Ok(window) => window,
		Err(err) => panic!("failed to open window: {}", err),
	};
	let renderer = match sdl2::render::Renderer::from_window(window, sdl2::render::RenderDriverIndex::Auto, sdl2::render::ACCELERATED) {
		Ok(screen) => screen,
		Err(err) => panic!("failed to open screen: {}", err),
	};

	let (sdl_tx, cpu_rx) = std::comm::channel();
	let (cpu_tx, sdl_rx) = std::comm::channel();
	let rawscreen = [0x00u8,.. 160*144*3];
	let arc = Arc::new(RWLock::new(rawscreen));
	let arc2 = arc.clone();

	spawn(proc() cpuloop(&cpu_tx, &cpu_rx, arc2, filename.as_slice(), &matches));

	let mut timer = std::io::timer::Timer::new().unwrap();
	let periodic = timer.periodic(Duration::milliseconds(8));

	'main : loop {
		periodic.recv();
		match sdl_rx.try_recv() {
			Err(Disconnected) => { break 'main },
			Ok(_) => recalculate_screen(&renderer, &arc),
			Err(Empty) => {},
		}
		'event : loop {
			match sdl2::event::poll_event() {
				sdl2::event::Event::Quit(_) => break 'main,
				sdl2::event::Event::None => break 'event,
				sdl2::event::Event::KeyDown(_, _, sdl2::keycode::KeyCode::Escape, _, _, _)
					=> break 'main,
				sdl2::event::Event::KeyDown(_, _, sdl2::keycode::KeyCode::LShift, _, _, _)
					=> sdl_tx.send(GBEvent::SpeedUp),
				sdl2::event::Event::KeyUp(_, _, sdl2::keycode::KeyCode::LShift, _, _, _)
					=> sdl_tx.send(GBEvent::SlowDown),
				sdl2::event::Event::KeyDown(_, _, sdlkey, _, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => sdl_tx.send(GBEvent::KeyDown(key)),
						None => {},
					}
				},
				sdl2::event::Event::KeyUp(_, _, sdlkey, _, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => sdl_tx.send(GBEvent::KeyUp(key)),
						None => {},
					}
				},
				_ => {}
			}
		}
	}
}

fn sdl_to_keypad(key: sdl2::keycode::KeyCode) -> Option<rboy::KeypadKey> {
	match key {
		sdl2::keycode::KeyCode::Z => Some(rboy::KeypadKey::A),
		sdl2::keycode::KeyCode::X => Some(rboy::KeypadKey::B),
		sdl2::keycode::KeyCode::Up => Some(rboy::KeypadKey::Up),
		sdl2::keycode::KeyCode::Down => Some(rboy::KeypadKey::Down),
		sdl2::keycode::KeyCode::Left => Some(rboy::KeypadKey::Left),
		sdl2::keycode::KeyCode::Right => Some(rboy::KeypadKey::Right),
		sdl2::keycode::KeyCode::Space => Some(rboy::KeypadKey::Select),
		sdl2::keycode::KeyCode::Return => Some(rboy::KeypadKey::Start),
		_ => None,
	}
}

fn recalculate_screen(screen: &sdl2::render::Renderer, arc: &Arc<RWLock<[u8,.. 160*144*3]>>) {
	screen.set_draw_color(sdl2::pixels::Color::RGB(0xFF, 0xFF, 0xFF)).unwrap();
	screen.clear().unwrap();

	let data =  arc.read().clone();
	for y in range(0u, 144) {
		for x in range(0u, 160) {
			screen.set_draw_color(sdl2::pixels::Color::RGB(data[y*160*3 + x*3 + 0],
															data[y*160*3 + x*3 + 1],
															data[y*160*3 + x*3 + 2])).unwrap();
			screen.draw_rect(&sdl2::rect::Rect::new((x*SCALE) as i32, (y*SCALE) as i32, SCALE as i32, SCALE as i32)).unwrap();
		}
	}
	screen.present();
}

enum GBEvent {
	KeyUp(rboy::KeypadKey),
	KeyDown(rboy::KeypadKey),
	SpeedUp,
	SlowDown,
}

fn cpuloop(cpu_tx: &Sender<uint>, cpu_rx: &Receiver<GBEvent>, arc: Arc<RWLock<[u8,.. 160*144*3]>>, filename: &str, matches: &getopts::Matches) {
	let opt_c = match matches.opt_present("classic") {
		true => Device::new(filename),
		false => Device::new_cgb(filename),
	};
	let mut c = match opt_c
	{
		Some(cpu) => { cpu },
		None => { error!("Could not get a valid gameboy"); set_exit_status(EXITCODE_CPULOADFAILS); return; },
	};
	c.set_stdout(matches.opt_present("serial"));

	let mut timer = std::io::timer::Timer::new().unwrap();
	let periodic = timer.periodic(Duration::milliseconds(8));
	let mut limit_speed = true;

	let waitticks = (4194.304f32 * 4.0) as uint;

	let mut ticks = 0;
	'cpuloop: loop {
		while ticks < waitticks {
			ticks += c.do_cycle();
			if c.check_and_reset_gpu_updated() {
				let mut data = arc.write();
				let gpu_data = c.get_gpu_data();
				for i in range(0, data.len()) { data[i] = gpu_data[i]; }
				if cpu_tx.send_opt(0).is_err() { break 'cpuloop };
			}
		}
		ticks -= waitticks;
		if limit_speed { periodic.recv(); }

		match cpu_rx.try_recv() {
			Ok(event) => match event {
				GBEvent::KeyUp(key) => c.keyup(key),
				GBEvent::KeyDown(key) => c.keydown(key),
				GBEvent::SpeedUp => limit_speed = false,
				GBEvent::SlowDown => limit_speed = true,
			},
			Err(Empty) => {},
			Err(Disconnected) => { break },
		};
	}
}
<|endoftext|>


<commit_before>use std::collections::hash_map::HashMap;

struct Function {
    blocks: HashMap<Block, BlockData>,
    instructions: HashMap<Inst, InstData>,
    uses: HashMap<Inst, UseList>,
    users: HashMap<Inst, UserList>,
    entry_block: Option<Block>,
    exit_block: Option<Block>,
}

impl Function {
    fn new() -> Function {
        Function {
            blocks: HashMap::new(),
            instructions: HashMap::new(),
            uses: HashMap::new(),
            users: HashMap::new(),
            entry_block: None,
            exit_block: None,
        }
    }
}

#[derive(PartialEq, Eq, Hash)]
struct Inst(u32);

#[derive(PartialEq, Eq, Hash)]
struct Block(u32);

struct UseList(Vec<Inst>);
struct UserList(Vec<Inst>);

struct BlockData {
    predecessors: Vec<Block>,
    successors: Vec<Block>,
    first_inst: Option<Inst>,
    last_inst: Option<Inst>,
}

impl BlockData {
    fn new() -> BlockData {
        BlockData {
            predecessors: Vec::new(),
            successors: Vec::new(),
            first_inst: None,
            last_inst: None,
        }
    }
}

enum CmpOp {
    Lt, Le, Eq, Ne, Gt, Ge,
}

enum InstData {
    Add {
        ty: Type,
        lhs: Inst,
        rhs: Inst,
    },

    Sub {
        ty: Type,
        lhs: Inst,
        rhs: Inst,
    },

    Goto {
        target: Block,
    },

    If {
        opnd: Inst,
        then_block: Block,
        else_block: Block,
    },

    Cmp {
        ty: Type,
        op: CmpOp,
        lhs: Inst,
        rhs: Inst,
    },

    Ret {
        opnd: Option<Inst>,
    },

    TrueConst,
    FalseConst,
    NilConst,
    Int8Const(u8),
    Int32Const(i32),
    Int64Const(i64),
    Float32Const(f32),
    Float64Const(f64),

    Param {
        ty: Type,
        idx: u32,
    },

    Deleted,
}

struct InstLoc {
    block: Option<Block>,
    prev: Option<Inst>,
    next: Option<Inst>,
}

enum Type {
    Bool,
    Int8,
    Int32,
    Int64,
    Float32,
    Float64,
    Reference,
}

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

    #[test]
    fn simple_fn() {
        let _fct = Function::new();
    }
}<commit_msg>boots: allow adding blocks to function<commit_after>use std::collections::hash_map::HashMap;
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};

struct Function {
    blocks: VecMap<Block, BlockData>,
    instructions: VecMap<Inst, InstData>,
    uses: HashMap<Inst, UseList>,
    users: HashMap<Inst, UserList>,
    entry_block: Option<Block>,
    exit_block: Option<Block>,
}

impl Function {
    fn new() -> Function {
        Function {
            blocks: VecMap::new(),
            instructions: VecMap::new(),
            uses: HashMap::new(),
            users: HashMap::new(),
            entry_block: None,
            exit_block: None,
        }
    }

    fn make_block(&mut self) -> Block {
        self.blocks.push(BlockData::new())
    }
}

#[derive(PartialEq, Eq, Hash)]
struct Inst(u32);

impl VecKey for Inst {
    fn new(value: usize) -> Inst {
        Inst(value as u32)
    }

    fn index(&self) -> usize {
        self.0 as usize
    }
}

#[derive(PartialEq, Eq, Hash)]
struct Block(u32);

impl VecKey for Block {
    fn new(value: usize) -> Block {
        Block(value as u32)
    }

    fn index(&self) -> usize {
        self.0 as usize
    }
}

struct UseList(Vec<Inst>);
struct UserList(Vec<Inst>);

struct BlockData {
    predecessors: Vec<Block>,
    successors: Vec<Block>,
    first_inst: Option<Inst>,
    last_inst: Option<Inst>,
}

impl BlockData {
    fn new() -> BlockData {
        BlockData {
            predecessors: Vec::new(),
            successors: Vec::new(),
            first_inst: None,
            last_inst: None,
        }
    }
}

enum CmpOp {
    Lt, Le, Eq, Ne, Gt, Ge,
}

enum InstData {
    Add {
        ty: Type,
        lhs: Inst,
        rhs: Inst,
    },

    Sub {
        ty: Type,
        lhs: Inst,
        rhs: Inst,
    },

    Goto {
        target: Block,
    },

    If {
        opnd: Inst,
        then_block: Block,
        else_block: Block,
    },

    Cmp {
        ty: Type,
        op: CmpOp,
        lhs: Inst,
        rhs: Inst,
    },

    Ret {
        opnd: Option<Inst>,
    },

    TrueConst,
    FalseConst,
    NilConst,
    Int8Const(u8),
    Int32Const(i32),
    Int64Const(i64),
    Float32Const(f32),
    Float64Const(f64),

    Param {
        ty: Type,
        idx: u32,
    },

    Deleted,
}

struct InstLoc {
    block: Option<Block>,
    prev: Option<Inst>,
    next: Option<Inst>,
}

enum Type {
    Bool,
    Int8,
    Int32,
    Int64,
    Float32,
    Float64,
    Reference,
}

struct VecMap<K, V> where K: VecKey {
    data: Vec<V>,
    unused: PhantomData<K>,
}

impl<K, V> VecMap<K, V> where K: VecKey {
    fn new() -> VecMap<K, V> {
        VecMap {
            data: Vec::new(),
            unused: PhantomData,
        }
    }

    fn push(&mut self, value: V) -> K {
        let idx = self.data.len();
        self.data.push(value);
        K::new(idx)
    }
}

impl<K, V> Index<K> for VecMap<K, V> where K: VecKey
{
    type Output = V;

    fn index(&self, k: K) -> &V {
        &self.data[k.index()]
    }
}

impl<K, V> IndexMut<K> for VecMap<K, V> where K: VecKey
{
    fn index_mut(&mut self, k: K) -> &mut V {
        &mut self.data[k.index()]
    }
}

trait VecKey {
    fn new(value: usize) -> Self;
    fn index(&self) -> usize;
}

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

    #[test]
    fn simple_fn() {
        let mut fct = Function::new();
        let _blk = fct.make_block();
    }
}<|endoftext|>