<commit_before>extern crate router;
extern crate persistent;

use std::io::Read;

use iron::prelude::*;
use iron::status;
use router::Router;
use rustc_serialize::json::{self, Json};

use super::{Globals, Index, Mapping, Document, query};

fn index_not_found_response() -> Response {
    let mut response = Response::with((status::NotFound, "{\"message\": \"Index not found\"}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    return response;
}

pub fn view_home(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "Hello World!")))
}

pub fn view_count(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // URL parameters
    let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

    // Lock index array
    let indices = glob.indices.lock().unwrap();

    // Find index
    let index = match indices.get(index_name) {
        Some(index) => index,
        None => {
            return Ok(index_not_found_response());
        }
    };

    // Load query from body
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let data = if !payload.is_empty() {
        Some(match Json::from_str(&payload) {
            Ok(data) => data,
            Err(error) => {
                // TODO: What specifically is bad about the JSON?
                let mut response = Response::with((status::BadRequest,
                                                   "{\"message\": \"Couldn't parse JSON\"}"));
                response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                return Ok(response);
            }
        })
    } else {
        None
    };

    println!("{:#?}", query::parse_query(data.unwrap().as_object().unwrap().get("query").unwrap()));

    // TODO: Run query

    // Temporary count and return numbers
    let mut count = 0;
    for mapping in index.mappings.values() {
        count += mapping.docs.len();
    }

    let mut response = Response::with((status::Ok, format!("{{\"count\": {}}}", count)));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn view_search(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // URL parameters
    let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

    // Lock index array
    let indices = glob.indices.lock().unwrap();

    // Find index
    let index = match indices.get(index_name) {
        Some(index) => index,
        None => {
            return Ok(index_not_found_response());
        }
    };

    // Load query from body
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let data = if !payload.is_empty() {
        Some(match Json::from_str(&payload) {
            Ok(data) => data,
            Err(error) => {
                // TODO: What specifically is bad about the JSON?
                let mut response = Response::with((status::BadRequest,
                                                   "{\"message\": \"Couldn't parse JSON\"}"));
                response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                return Ok(response);
            }
        })
    } else {
        None
    };

    println!("{:#?}", query::parse_query(data.unwrap().as_object().unwrap().get("query").unwrap()));

    // TODO: Run query

    let mut response = Response::with((status::Ok, "{\"hits\": {\"total\": 0, \"hits\": []}}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn view_get_doc(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // URL parameters
    let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");
    let mapping_name = req.extensions.get::<Router>().unwrap().find("mapping").unwrap_or("");
    let doc_id = req.extensions.get::<Router>().unwrap().find("doc").unwrap_or("");

    // Lock index array
    let indices = glob.indices.lock().unwrap();

    // Find index
    let index = match indices.get(index_name) {
        Some(index) => index,
        None => {
            return Ok(index_not_found_response());
        }
    };

    // Find mapping
    let mapping = match index.mappings.get(mapping_name) {
        Some(mapping) => mapping,
        None => {
            let mut response = Response::with((status::NotFound,
                                               "{\"message\": \"Mapping not found\"}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            return Ok(response);
        }
    };

    // Find document
    let doc = match mapping.docs.get(doc_id) {
        Some(doc) => doc,
        None => {
            let mut response = Response::with((status::NotFound,
                                               "{\"message\": \"Document not found\"}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            return Ok(response);
        }
    };

    let mut response = Response::with((status::Ok, json::encode(&doc.data).unwrap()));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn view_put_doc(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // URL parameters
    let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");
    let mapping_name = req.extensions.get::<Router>().unwrap().find("mapping").unwrap_or("");
    let ref doc_id = req.extensions.get::<Router>().unwrap().find("doc").unwrap_or("");

    // Lock index array
    let mut indices = glob.indices.lock().unwrap();

    // Find index
    let mut index = match indices.get_mut(index_name) {
        Some(index) => index,
        None => {
            return Ok(index_not_found_response());
        }
    };

    // Find mapping
    let mut mapping = match index.mappings.get_mut(mapping_name) {
        Some(mapping) => mapping,
        None => {
            let mut response = Response::with((status::NotFound,
                                               "{\"message\": \"Mapping not found\"}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            return Ok(response);
        }
    };

    // Load data from body
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let data = if !payload.is_empty() {
        Some(match Json::from_str(&payload) {
            Ok(data) => data,
            Err(error) => {
                // TODO: What specifically is bad about the JSON?
                let mut response = Response::with((status::BadRequest,
                                                   "{\"message\": \"Couldn't parse JSON\"}"));
                response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                return Ok(response);
            }
        })
    } else {
        None
    };

    // Create and insert document
    if let Some(data) = data {
        let doc = Document::from_json(data);
        mapping.docs.insert(doc_id.clone().to_owned(), doc);
    }

    let mut response = Response::with((status::Ok, "{}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn view_put_index(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // URL parameters
    let ref index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

    // Lock index array
    let mut indices = glob.indices.lock().unwrap();

    // Load data from body
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let data = if !payload.is_empty() {
        Some(match Json::from_str(&payload) {
            Ok(data) => data,
            Err(error) => {
                // TODO: What specifically is bad about the JSON?
                let mut response = Response::with((status::BadRequest,
                                                   "{\"message\": \"Couldn't parse JSON\"}"));
                response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                return Ok(response);
            }
        })
    } else {
        None
    };

    // Create index
    indices.insert(index_name.clone().to_owned(), Index::new());

    let mut response = Response::with((status::Ok, "{\"acknowledged\": true}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn view_put_mapping(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // URL parameters
    let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");
    let ref mapping_name = req.extensions.get::<Router>().unwrap().find("mapping").unwrap_or("");

    // Lock index array
    let mut indices = glob.indices.lock().unwrap();

    // Find index
    let mut index = match indices.get_mut(index_name) {
        Some(index) => index,
        None => {
            return Ok(index_not_found_response());
        }
    };

    // Load data from body
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    if payload.is_empty() {
        // TODO: Better error
        let mut response = Response::with((status::Ok, "{\"acknowledged\": false}"));
        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
        return Ok(response)
    }

    let data = match Json::from_str(&payload) {
        Ok(data) => data,
        Err(error) => {
            // TODO: What specifically is bad about the JSON?
            let mut response = Response::with((status::BadRequest,
                                               "{\"message\": \"Couldn't parse JSON\"}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            return Ok(response);
        }
    };

    let data = data.as_object().unwrap().get(*mapping_name).unwrap();

    // Insert mapping
    let mapping = Mapping::from_json(&data);
    println!("{:#?}", mapping);
    index.mappings.insert(mapping_name.clone().to_owned(), mapping);

    let mut response = Response::with((status::Ok, "{\"acknowledged\": true}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn view_post_bulk(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // Lock index array
    let mut indices = glob.indices.lock().unwrap();

    // Load data from body
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    for payload_part in payload.split('\n') {
        let data = if !payload.is_empty() {
            Some(Json::from_str(&payload))
        } else {
            None
        };
    }

    let mut response = Response::with((status::Ok, "{\"acknowledged\": true}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn view_post_refresh(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // Lock index array
    let mut indices = glob.indices.lock().unwrap();

    let mut response = Response::with((status::Ok, "{\"acknowledged\": true}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn get_router() -> Router {
    router!(get "/" => view_home,
            get "/:index/_count" => view_count,
            get "/:index/_search" => view_search,
            get "/:index/:mapping/:doc" => view_get_doc,
            put "/:index/:mapping/:doc" => view_put_doc,
            put "/:index" => view_put_index,
            put "/:index/_mapping/:mapping" => view_put_mapping,
            post "/_bulk" => view_post_bulk,
            post ":index/_refresh" => view_post_refresh)
}
<commit_msg>Allow posting to search/count APIs<commit_after>extern crate router;
extern crate persistent;

use std::io::Read;

use iron::prelude::*;
use iron::status;
use router::Router;
use rustc_serialize::json::{self, Json};

use super::{Globals, Index, Mapping, Document, query};

fn index_not_found_response() -> Response {
    let mut response = Response::with((status::NotFound, "{\"message\": \"Index not found\"}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    return response;
}

pub fn view_home(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "Hello World!")))
}

pub fn view_count(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // URL parameters
    let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

    // Lock index array
    let indices = glob.indices.lock().unwrap();

    // Find index
    let index = match indices.get(index_name) {
        Some(index) => index,
        None => {
            return Ok(index_not_found_response());
        }
    };

    // Load query from body
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let data = if !payload.is_empty() {
        Some(match Json::from_str(&payload) {
            Ok(data) => data,
            Err(error) => {
                // TODO: What specifically is bad about the JSON?
                let mut response = Response::with((status::BadRequest,
                                                   "{\"message\": \"Couldn't parse JSON\"}"));
                response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                return Ok(response);
            }
        })
    } else {
        None
    };

    println!("{:#?}", query::parse_query(data.unwrap().as_object().unwrap().get("query").unwrap()));

    // TODO: Run query

    // Temporary count and return numbers
    let mut count = 0;
    for mapping in index.mappings.values() {
        count += mapping.docs.len();
    }

    let mut response = Response::with((status::Ok, format!("{{\"count\": {}}}", count)));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn view_search(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // URL parameters
    let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

    // Lock index array
    let indices = glob.indices.lock().unwrap();

    // Find index
    let index = match indices.get(index_name) {
        Some(index) => index,
        None => {
            return Ok(index_not_found_response());
        }
    };

    // Load query from body
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let data = if !payload.is_empty() {
        Some(match Json::from_str(&payload) {
            Ok(data) => data,
            Err(error) => {
                // TODO: What specifically is bad about the JSON?
                let mut response = Response::with((status::BadRequest,
                                                   "{\"message\": \"Couldn't parse JSON\"}"));
                response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                return Ok(response);
            }
        })
    } else {
        None
    };

    println!("{:#?}", query::parse_query(data.unwrap().as_object().unwrap().get("query").unwrap()));

    // TODO: Run query

    let mut response = Response::with((status::Ok, "{\"hits\": {\"total\": 0, \"hits\": []}}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn view_get_doc(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // URL parameters
    let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");
    let mapping_name = req.extensions.get::<Router>().unwrap().find("mapping").unwrap_or("");
    let doc_id = req.extensions.get::<Router>().unwrap().find("doc").unwrap_or("");

    // Lock index array
    let indices = glob.indices.lock().unwrap();

    // Find index
    let index = match indices.get(index_name) {
        Some(index) => index,
        None => {
            return Ok(index_not_found_response());
        }
    };

    // Find mapping
    let mapping = match index.mappings.get(mapping_name) {
        Some(mapping) => mapping,
        None => {
            let mut response = Response::with((status::NotFound,
                                               "{\"message\": \"Mapping not found\"}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            return Ok(response);
        }
    };

    // Find document
    let doc = match mapping.docs.get(doc_id) {
        Some(doc) => doc,
        None => {
            let mut response = Response::with((status::NotFound,
                                               "{\"message\": \"Document not found\"}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            return Ok(response);
        }
    };

    let mut response = Response::with((status::Ok, json::encode(&doc.data).unwrap()));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn view_put_doc(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // URL parameters
    let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");
    let mapping_name = req.extensions.get::<Router>().unwrap().find("mapping").unwrap_or("");
    let ref doc_id = req.extensions.get::<Router>().unwrap().find("doc").unwrap_or("");

    // Lock index array
    let mut indices = glob.indices.lock().unwrap();

    // Find index
    let mut index = match indices.get_mut(index_name) {
        Some(index) => index,
        None => {
            return Ok(index_not_found_response());
        }
    };

    // Find mapping
    let mut mapping = match index.mappings.get_mut(mapping_name) {
        Some(mapping) => mapping,
        None => {
            let mut response = Response::with((status::NotFound,
                                               "{\"message\": \"Mapping not found\"}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            return Ok(response);
        }
    };

    // Load data from body
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let data = if !payload.is_empty() {
        Some(match Json::from_str(&payload) {
            Ok(data) => data,
            Err(error) => {
                // TODO: What specifically is bad about the JSON?
                let mut response = Response::with((status::BadRequest,
                                                   "{\"message\": \"Couldn't parse JSON\"}"));
                response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                return Ok(response);
            }
        })
    } else {
        None
    };

    // Create and insert document
    if let Some(data) = data {
        let doc = Document::from_json(data);
        mapping.docs.insert(doc_id.clone().to_owned(), doc);
    }

    let mut response = Response::with((status::Ok, "{}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn view_put_index(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // URL parameters
    let ref index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");

    // Lock index array
    let mut indices = glob.indices.lock().unwrap();

    // Load data from body
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let data = if !payload.is_empty() {
        Some(match Json::from_str(&payload) {
            Ok(data) => data,
            Err(error) => {
                // TODO: What specifically is bad about the JSON?
                let mut response = Response::with((status::BadRequest,
                                                   "{\"message\": \"Couldn't parse JSON\"}"));
                response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                return Ok(response);
            }
        })
    } else {
        None
    };

    // Create index
    indices.insert(index_name.clone().to_owned(), Index::new());

    let mut response = Response::with((status::Ok, "{\"acknowledged\": true}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn view_put_mapping(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // URL parameters
    let index_name = req.extensions.get::<Router>().unwrap().find("index").unwrap_or("");
    let ref mapping_name = req.extensions.get::<Router>().unwrap().find("mapping").unwrap_or("");

    // Lock index array
    let mut indices = glob.indices.lock().unwrap();

    // Find index
    let mut index = match indices.get_mut(index_name) {
        Some(index) => index,
        None => {
            return Ok(index_not_found_response());
        }
    };

    // Load data from body
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    if payload.is_empty() {
        // TODO: Better error
        let mut response = Response::with((status::Ok, "{\"acknowledged\": false}"));
        response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
        return Ok(response)
    }

    let data = match Json::from_str(&payload) {
        Ok(data) => data,
        Err(error) => {
            // TODO: What specifically is bad about the JSON?
            let mut response = Response::with((status::BadRequest,
                                               "{\"message\": \"Couldn't parse JSON\"}"));
            response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
            return Ok(response);
        }
    };

    let data = data.as_object().unwrap().get(*mapping_name).unwrap();

    // Insert mapping
    let mapping = Mapping::from_json(&data);
    println!("{:#?}", mapping);
    index.mappings.insert(mapping_name.clone().to_owned(), mapping);

    let mut response = Response::with((status::Ok, "{\"acknowledged\": true}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn view_post_bulk(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // Lock index array
    let mut indices = glob.indices.lock().unwrap();

    // Load data from body
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    for payload_part in payload.split('\n') {
        let data = if !payload.is_empty() {
            Some(Json::from_str(&payload))
        } else {
            None
        };
    }

    let mut response = Response::with((status::Ok, "{\"acknowledged\": true}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn view_post_refresh(req: &mut Request) -> IronResult<Response> {
    let ref glob = req.get::<persistent::Read<Globals>>().unwrap();

    // Lock index array
    let mut indices = glob.indices.lock().unwrap();

    let mut response = Response::with((status::Ok, "{\"acknowledged\": true}"));
    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
    Ok(response)
}

pub fn get_router() -> Router {
    router!(get "/" => view_home,
            get "/:index/_count" => view_count,
            get "/:index/_search" => view_search,
            post "/:index/_count" => view_count,
            post "/:index/_search" => view_search,
            get "/:index/:mapping/:doc" => view_get_doc,
            put "/:index/:mapping/:doc" => view_put_doc,
            put "/:index" => view_put_index,
            put "/:index/_mapping/:mapping" => view_put_mapping,
            post "/_bulk" => view_post_bulk,
            post ":index/_refresh" => view_post_refresh)
}
<|endoftext|>


<commit_before>use std::convert::TryFrom;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{thread, time};
use std::thread::JoinHandle;

use instruction::Instruction;
use peripherals::Peripherals;

use rand::{thread_rng, Rng};

const FONT_BASE_ADDR: usize = 0x0;
const NUM_FONTS: usize = 16;
const FONT_SIZE: usize = 5;
const FONT_MAP: [u8; NUM_FONTS * FONT_SIZE] =
    [0xF0, 0x90, 0x90, 0x90, 0xF0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xF0, 0x10, 0xF0, 0x80, 0xF0,
     0xF0, 0x10, 0xF0, 0x10, 0xF0, 0x90, 0x90, 0xF0, 0x10, 0x10, 0xF0, 0x80, 0xF0, 0x10, 0xF0,
     0xF0, 0x80, 0xF0, 0x90, 0xF0, 0xF0, 0x10, 0x20, 0x40, 0x40, 0xF0, 0x90, 0xF0, 0x90, 0xF0,
     0xF0, 0x90, 0xF0, 0x10, 0xF0, 0xF0, 0x90, 0xF0, 0x90, 0x90, 0xE0, 0x90, 0xE0, 0x90, 0xE0,
     0xF0, 0x80, 0x80, 0x80, 0xF0, 0xF0, 0x80, 0x80, 0x80, 0xF0, 0xF0, 0x80, 0xF0, 0x80, 0xF0,
     0xF0, 0x80, 0xF0, 0x80, 0x80];

pub struct Chip8 {
    mem: Vec<u8>,
    reg_v: Vec<u8>,
    reg_i: u16,
    reg_delay_timer: Arc<AtomicUsize>,
    reg_sound_timer: u8,
    pc: usize,
    sp: usize,
    stack: Vec<usize>,

}

impl Chip8 {
    pub fn new(rom: &Vec<u8>) -> Chip8 {
        let mut chip8 = Chip8 {
            mem: vec![0; 0xFFF],
            reg_v: vec![0; 16],
            reg_i: 0,
            reg_delay_timer: Arc::new(AtomicUsize::new(0)),
            reg_sound_timer: 0,
            pc: 0x200,
            sp: 0,
            stack: vec![0; 16],

        };
        chip8.load_fonts();
        chip8.load_rom(rom);
        chip8
    }

    fn load_fonts(&mut self) {
        for i in FONT_BASE_ADDR..FONT_MAP.len() {
            self.mem[i] = FONT_MAP[i - FONT_BASE_ADDR]
        }
    }

    fn load_rom(&mut self, rom: &Vec<u8>) {
        for (b, buf_i) in rom.iter().enumerate() {
            self.mem[0x200 + b] = *buf_i;
        }
    }

    pub fn step(&mut self, peripherals: &mut Peripherals) {
        let hi_nibble = self.mem[self.pc] as u16;
        let lo_nibble = self.mem[self.pc + 1] as u16;
        let opcode = (hi_nibble << 8) | lo_nibble;
        match Instruction::try_from(opcode) {
            Err(msg) => panic!("Error decoding instruction at 0x{0:03x}: {1}", self.pc, msg),
            Ok(instruction) => self.step_instruction(instruction, peripherals),
        }
    }

    fn memory_read(&self, pos: usize) -> u8 {
        self.mem[pos]
    }

    fn memory_write(&mut self, pos: usize, data: u8) {
        self.mem[pos] = data;
        // println!("[W][0x{:03x}] 0x{:03x}", pos, data);
    }

    fn step_instruction(&mut self, instruction: Instruction, peripherals: &mut Peripherals) {
        match instruction {
            Instruction::Cls => peripherals.video_engine.cls(),
            Instruction::Ret => {
                assert!(self.sp > 0);
                self.sp -= 1;
                let old_pc = self.stack[self.sp];
                println!("Resuming execution at PC 0x{:x}", old_pc);
                self.pc = old_pc; // Jump to the instruction immediately after
            }
            Instruction::Jmp { addr } => self.pc = addr - 2, // Correct for pc increment later
            Instruction::Jsr { addr } => {
                self.stack[self.sp] = self.pc;
                self.sp += 1;
                self.pc = addr - 2
            } // Correct for pc increment later
            Instruction::Mov { vr, k } => self.reg_v[vr] = k,
            Instruction::Movr { vr, vy } => self.reg_v[vr] = self.reg_v[vy],
            Instruction::Shr { vr } => {
                let current_val = self.reg_v[vr];
                self.reg_v[0xF] = current_val & 1;
                self.reg_v[vr] = current_val >> 1;
            }
            Instruction::Skeq { vr, k } => {
                if self.reg_v[vr] == k {
                    self.pc += 2
                }
            }
            Instruction::Add { vr, k } => {
                let old_val = self.reg_v[vr];
                self.reg_v[vr] = old_val.wrapping_add(k);
            }
            Instruction::Addr { vr, vy } => {
                let old_r = self.reg_v[vr];
                let old_y = self.reg_v[vy];
                let (result, overflow) = old_r.overflowing_add(old_y);
                if overflow {
                    self.reg_v[0xF] = 1
                } else {
                    self.reg_v[0xF] = 0
                }
                self.reg_v[vr] = result;
            }
            Instruction::Mvi { k } => self.reg_i = k,
            Instruction::Rnd { vr, k } => {
                let mut buffer = [0u8; 1];
                thread_rng().fill_bytes(&mut buffer);
                self.reg_v[vr] = buffer[0] & k;
            }
            Instruction::Sprite { rx, ry, s } => {
                let x = self.reg_v[rx] as usize;
                let y = self.reg_v[ry] as usize;
                let height = s;
                self.reg_v[0xF] = 0;
                for yline in 0..height {
                    let mem_pos = self.reg_i as usize + yline as usize;
                    let pixel = self.memory_read(mem_pos);
                    for xline in 0..8 {
                        if pixel & (0x80 >> xline) != 0 {
                            let collision = peripherals.video_engine
                                .set_pixel_to_1(x + xline, y + yline);
                            if collision {
                                self.reg_v[0xF] = 1;
                            }
                        }

                    }
                }
            }
            Instruction::Skp { k } => {
                println!("Waiting for key {:?} to skip", k);
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) if x == k => self.pc += 2,
                    _ => {}
                }
            }
            Instruction::Key { vr } => {
                println!("Waiting for a key to be pressed");
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) => {
                        println!(" ... Got {:?}", x);
                        self.reg_v[vr] = x
                    },
                    _ => {
                        println!(" ... Waiting more");
                        self.pc -= 2; // Emulate a SLEEP
                    }
                }

            }
            Instruction::Adi { vr } => {
                self.reg_i += self.reg_v[vr] as u16;
            }
            Instruction::Font { vr } => {
                let character = self.reg_v[vr] as usize;
                self.reg_i = (FONT_BASE_ADDR + (character * FONT_SIZE)) as u16;
                println!("Font draw for character: {:x}", character);
            }
            Instruction::Bcd { vr } => {
                let value = self.reg_v[vr];
                println!("BCD DECODING OF {}", value);
                let i = self.reg_i as usize;
                self.mem[i] = value / 100;
                self.mem[i + 1] = (value / 10) % 10;
                self.mem[i + 2] = (value % 100) % 100;
            }
            Instruction::Str { vr } => {
                for idx in 0..(vr + 1) {
                    let target_pos = self.reg_i as usize + idx;
                    let data = self.reg_v[idx];
                    self.memory_write(target_pos, data);
                }
            }
            Instruction::Ldr { vr } => {
                for idx in 0..(vr + 1) {
                    self.reg_v[idx] = self.memory_read(self.reg_i as usize + idx)
                }
            }
            Instruction::Gdelay { vr } => {
                let amount = self.reg_delay_timer();
                self.reg_v[vr] = amount;
            }
            Instruction::Sdelay { vr } => {
                let amount = self.reg_v[vr];
                self.reg_delay_timer.store((amount + 1) as _, Ordering::SeqCst);
                let timer_clone = self.reg_delay_timer.clone();
                thread::spawn(move || loop {
                    let ticks_left = timer_clone.fetch_sub(1, Ordering::SeqCst) - 1;
                    if ticks_left > 0 {
                        println!("Still {} ticks left", ticks_left);
                        thread::sleep(time::Duration::from_millis(1000));
                    } else {
                        break;
                    }
                });
            }
        }
        self.pc += 2;
    }

    pub fn pc(&self) -> usize {
        self.pc
    }

    pub fn mem(&self) -> &Vec<u8> {
        &self.mem
    }

    pub fn reg_v(&self) -> &Vec<u8> {
        &self.reg_v
    }

    pub fn reg_i(&self) -> u16 {
        self.reg_i
    }

    pub fn reg_delay_timer(&self) -> u8 {
        self.reg_delay_timer.load(Ordering::SeqCst) as _
    }

    pub fn reg_sound_timer(&self) -> u8 {
        self.reg_sound_timer
    }

    pub fn stack(&self) -> &Vec<usize> {
        &self.stack
    }

    pub fn sp(&self) -> usize {
        self.sp
    }
}
<commit_msg>Fix timer rate...60Hz is not once a second...<commit_after>use std::convert::TryFrom;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{thread, time};
use std::thread::JoinHandle;

use instruction::Instruction;
use peripherals::Peripherals;

use rand::{thread_rng, Rng};

const FONT_BASE_ADDR: usize = 0x0;
const NUM_FONTS: usize = 16;
const FONT_SIZE: usize = 5;
const FONT_MAP: [u8; NUM_FONTS * FONT_SIZE] =
    [0xF0, 0x90, 0x90, 0x90, 0xF0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xF0, 0x10, 0xF0, 0x80, 0xF0,
     0xF0, 0x10, 0xF0, 0x10, 0xF0, 0x90, 0x90, 0xF0, 0x10, 0x10, 0xF0, 0x80, 0xF0, 0x10, 0xF0,
     0xF0, 0x80, 0xF0, 0x90, 0xF0, 0xF0, 0x10, 0x20, 0x40, 0x40, 0xF0, 0x90, 0xF0, 0x90, 0xF0,
     0xF0, 0x90, 0xF0, 0x10, 0xF0, 0xF0, 0x90, 0xF0, 0x90, 0x90, 0xE0, 0x90, 0xE0, 0x90, 0xE0,
     0xF0, 0x80, 0x80, 0x80, 0xF0, 0xF0, 0x80, 0x80, 0x80, 0xF0, 0xF0, 0x80, 0xF0, 0x80, 0xF0,
     0xF0, 0x80, 0xF0, 0x80, 0x80];

pub struct Chip8 {
    mem: Vec<u8>,
    reg_v: Vec<u8>,
    reg_i: u16,
    reg_delay_timer: Arc<AtomicUsize>,
    reg_sound_timer: u8,
    pc: usize,
    sp: usize,
    stack: Vec<usize>,

}

impl Chip8 {
    pub fn new(rom: &Vec<u8>) -> Chip8 {
        let mut chip8 = Chip8 {
            mem: vec![0; 0xFFF],
            reg_v: vec![0; 16],
            reg_i: 0,
            reg_delay_timer: Arc::new(AtomicUsize::new(0)),
            reg_sound_timer: 0,
            pc: 0x200,
            sp: 0,
            stack: vec![0; 16],

        };
        chip8.load_fonts();
        chip8.load_rom(rom);
        chip8
    }

    fn load_fonts(&mut self) {
        for i in FONT_BASE_ADDR..FONT_MAP.len() {
            self.mem[i] = FONT_MAP[i - FONT_BASE_ADDR]
        }
    }

    fn load_rom(&mut self, rom: &Vec<u8>) {
        for (b, buf_i) in rom.iter().enumerate() {
            self.mem[0x200 + b] = *buf_i;
        }
    }

    pub fn step(&mut self, peripherals: &mut Peripherals) {
        let hi_nibble = self.mem[self.pc] as u16;
        let lo_nibble = self.mem[self.pc + 1] as u16;
        let opcode = (hi_nibble << 8) | lo_nibble;
        match Instruction::try_from(opcode) {
            Err(msg) => panic!("Error decoding instruction at 0x{0:03x}: {1}", self.pc, msg),
            Ok(instruction) => self.step_instruction(instruction, peripherals),
        }
    }

    fn memory_read(&self, pos: usize) -> u8 {
        self.mem[pos]
    }

    fn memory_write(&mut self, pos: usize, data: u8) {
        self.mem[pos] = data;
        // println!("[W][0x{:03x}] 0x{:03x}", pos, data);
    }

    fn step_instruction(&mut self, instruction: Instruction, peripherals: &mut Peripherals) {
        match instruction {
            Instruction::Cls => peripherals.video_engine.cls(),
            Instruction::Ret => {
                assert!(self.sp > 0);
                self.sp -= 1;
                let old_pc = self.stack[self.sp];
                println!("Resuming execution at PC 0x{:x}", old_pc);
                self.pc = old_pc; // Jump to the instruction immediately after
            }
            Instruction::Jmp { addr } => self.pc = addr - 2, // Correct for pc increment later
            Instruction::Jsr { addr } => {
                self.stack[self.sp] = self.pc;
                self.sp += 1;
                self.pc = addr - 2
            } // Correct for pc increment later
            Instruction::Mov { vr, k } => self.reg_v[vr] = k,
            Instruction::Movr { vr, vy } => self.reg_v[vr] = self.reg_v[vy],
            Instruction::Shr { vr } => {
                let current_val = self.reg_v[vr];
                self.reg_v[0xF] = current_val & 1;
                self.reg_v[vr] = current_val >> 1;
            }
            Instruction::Skeq { vr, k } => {
                if self.reg_v[vr] == k {
                    self.pc += 2
                }
            }
            Instruction::Add { vr, k } => {
                let old_val = self.reg_v[vr];
                self.reg_v[vr] = old_val.wrapping_add(k);
            }
            Instruction::Addr { vr, vy } => {
                let old_r = self.reg_v[vr];
                let old_y = self.reg_v[vy];
                let (result, overflow) = old_r.overflowing_add(old_y);
                if overflow {
                    self.reg_v[0xF] = 1
                } else {
                    self.reg_v[0xF] = 0
                }
                self.reg_v[vr] = result;
            }
            Instruction::Mvi { k } => self.reg_i = k,
            Instruction::Rnd { vr, k } => {
                let mut buffer = [0u8; 1];
                thread_rng().fill_bytes(&mut buffer);
                self.reg_v[vr] = buffer[0] & k;
            }
            Instruction::Sprite { rx, ry, s } => {
                let x = self.reg_v[rx] as usize;
                let y = self.reg_v[ry] as usize;
                let height = s;
                self.reg_v[0xF] = 0;
                for yline in 0..height {
                    let mem_pos = self.reg_i as usize + yline as usize;
                    let pixel = self.memory_read(mem_pos);
                    for xline in 0..8 {
                        if pixel & (0x80 >> xline) != 0 {
                            let collision = peripherals.video_engine
                                .set_pixel_to_1(x + xline, y + yline);
                            if collision {
                                self.reg_v[0xF] = 1;
                            }
                        }

                    }
                }
            }
            Instruction::Skp { k } => {
                println!("Waiting for key {:?} to skip", k);
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) if x == k => self.pc += 2,
                    _ => {}
                }
            }
            Instruction::Key { vr } => {
                println!("Waiting for a key to be pressed");
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) => {
                        println!(" ... Got {:?}", x);
                        self.reg_v[vr] = x
                    },
                    _ => {
                        println!(" ... Waiting more");
                        self.pc -= 2; // Emulate a SLEEP
                    }
                }

            }
            Instruction::Adi { vr } => {
                self.reg_i += self.reg_v[vr] as u16;
            }
            Instruction::Font { vr } => {
                let character = self.reg_v[vr] as usize;
                self.reg_i = (FONT_BASE_ADDR + (character * FONT_SIZE)) as u16;
                println!("Font draw for character: {:x}", character);
            }
            Instruction::Bcd { vr } => {
                let value = self.reg_v[vr];
                println!("BCD DECODING OF {}", value);
                let i = self.reg_i as usize;
                self.mem[i] = value / 100;
                self.mem[i + 1] = (value / 10) % 10;
                self.mem[i + 2] = (value % 100) % 100;
            }
            Instruction::Str { vr } => {
                for idx in 0..(vr + 1) {
                    let target_pos = self.reg_i as usize + idx;
                    let data = self.reg_v[idx];
                    self.memory_write(target_pos, data);
                }
            }
            Instruction::Ldr { vr } => {
                for idx in 0..(vr + 1) {
                    self.reg_v[idx] = self.memory_read(self.reg_i as usize + idx)
                }
            }
            Instruction::Gdelay { vr } => {
                let amount = self.reg_delay_timer();
                self.reg_v[vr] = amount;
            }
            Instruction::Sdelay { vr } => {
                let amount = self.reg_v[vr];
                self.reg_delay_timer.store((amount + 1) as _, Ordering::SeqCst);
                let timer_clone = self.reg_delay_timer.clone();
                thread::spawn(move || loop {
                    let ticks_left = timer_clone.fetch_sub(1, Ordering::SeqCst) - 1;
                    if ticks_left > 0 {
                        println!("Still {} ticks left", ticks_left);
                        thread::sleep(time::Duration::from_millis(1000/60));
                    } else {
                        break;
                    }
                });
            }
        }
        self.pc += 2;
    }

    pub fn pc(&self) -> usize {
        self.pc
    }

    pub fn mem(&self) -> &Vec<u8> {
        &self.mem
    }

    pub fn reg_v(&self) -> &Vec<u8> {
        &self.reg_v
    }

    pub fn reg_i(&self) -> u16 {
        self.reg_i
    }

    pub fn reg_delay_timer(&self) -> u8 {
        self.reg_delay_timer.load(Ordering::SeqCst) as _
    }

    pub fn reg_sound_timer(&self) -> u8 {
        self.reg_sound_timer
    }

    pub fn stack(&self) -> &Vec<usize> {
        &self.stack
    }

    pub fn sp(&self) -> usize {
        self.sp
    }
}
<|endoftext|>


<commit_before>use std::hash::Hash;
use std::collections::HashMap;
use std::collections::hash_map::Entry;

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum TemporalRelation {
    Equal,
    Caused,
    EffectOf,
    Concurrent,
}

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct VectorClock<HostType: Clone + Hash + Eq> {
    entries: HashMap<HostType, u64>,
}

impl<HostType: Clone + Hash + Eq> VectorClock<HostType> {
    pub fn new() -> VectorClock<HostType> {
        VectorClock {
            entries: HashMap::new(),
        }
    }

    pub fn incremented(&self, host: HostType) -> Self {
        let mut entries = self.entries.clone();

        {
            match entries.entry(host) {
                Entry::Vacant(e) => { e.insert(1); },
                Entry::Occupied(mut e) => {
                    let v = *e.get();
                    e.insert(v + 1);
                },
            };
        }

        VectorClock {
            entries: entries,
        }
    }

    pub fn temporal_relation(&self, other: &Self) -> TemporalRelation {
        if self == other {
            TemporalRelation::Equal
        }
        else if self.superseded_by(other) {
            TemporalRelation::Caused
        }
        else if other.superseded_by(self) {
            TemporalRelation::EffectOf
        }
        else {
            TemporalRelation::Concurrent
        }
    }

    fn superseded_by(&self, other: &Self) -> bool {
        let mut has_smaller = false;

        for (host, &self_n) in self.entries.iter() {
            let other_n = *other.entries.get(host).unwrap_or(&0);

            if self_n > other_n {
                return false;
            }

            has_smaller = has_smaller || (self_n < other_n);
        }

        for (host, &other_n) in other.entries.iter() {
            let self_n = *self.entries.get(host).unwrap_or(&0);

            if self_n > other_n {
                return false;
            }

            has_smaller = has_smaller || (self_n < other_n);
        }

        has_smaller
    }

    pub fn merge_with(&self, other: &Self) -> Self {
        let mut entries = self.entries.clone();

        for (host, &other_n) in other.entries.iter() {
            match entries.entry(host.clone()) {
                Entry::Vacant(e) => { e.insert(other_n); },
                Entry::Occupied(mut e) => {
                    let self_n = *e.get();

                    if other_n > self_n {
                        e.insert(other_n);
                    }
                }
            }
        }

        VectorClock {
            entries: entries,
        }
    }
}

#[cfg(test)]
mod test {
    use super::{VectorClock, TemporalRelation};

    type StrVectorClock = VectorClock<&'static str>;

    #[test]
    fn test_empty_ordering() {
        let c1 = StrVectorClock::new();
        let c2 = StrVectorClock::new();

        assert_eq!(c1, c2);

        assert!(c1.temporal_relation(&c2) == TemporalRelation::Equal);
        assert!(c2.temporal_relation(&c1) == TemporalRelation::Equal);
    }

    #[test]
    fn test_incremented_ordering() {
        let c1 = StrVectorClock::new();
        let c2 = c1.incremented("A");

        assert!(!(c1 == c2));

        assert!(c1.temporal_relation(&c2) == TemporalRelation::Caused);
        assert!(c2.temporal_relation(&c1) == TemporalRelation::EffectOf);
    }

    #[test]
    fn test_diverged() {
        let base = StrVectorClock::new();
        let c1 = base.incremented("A");
        let c2 = base.incremented("B");

        assert!(!(c1 == c2));

        assert!(c1.temporal_relation(&c2) == TemporalRelation::Concurrent);
        assert!(c2.temporal_relation(&c1) == TemporalRelation::Concurrent);
    }

    #[test]
    fn test_merged() {
        let base = StrVectorClock::new();
        let c1 = base.incremented("A");
        let c2 = base.incremented("B");

        let m = c1.merge_with(&c2);

        assert!(m.temporal_relation(&c1) == TemporalRelation::EffectOf);
        assert!(c1.temporal_relation(&m) == TemporalRelation::Caused);

        assert!(m.temporal_relation(&c2) == TemporalRelation::EffectOf);
        assert!(c2.temporal_relation(&m) == TemporalRelation::Caused);
    }
}
<commit_msg>Remove Clone from VectorClock impl/requirement<commit_after>use std::hash::Hash;
use std::collections::HashMap;
use std::collections::hash_map::Entry;

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum TemporalRelation {
    Equal,
    Caused,
    EffectOf,
    Concurrent,
}

#[derive(PartialEq, Eq, Debug)]
pub struct VectorClock<HostType: Hash + Eq> {
    entries: HashMap<HostType, u64>,
}

impl<HostType: Clone + Hash + Eq> VectorClock<HostType> {
    pub fn new() -> VectorClock<HostType> {
        VectorClock {
            entries: HashMap::new(),
        }
    }

    pub fn incremented(&self, host: HostType) -> Self {
        let mut entries = self.entries.clone();

        {
            match entries.entry(host) {
                Entry::Vacant(e) => { e.insert(1); },
                Entry::Occupied(mut e) => {
                    let v = *e.get();
                    e.insert(v + 1);
                },
            };
        }

        VectorClock {
            entries: entries,
        }
    }

    pub fn temporal_relation(&self, other: &Self) -> TemporalRelation {
        if self == other {
            TemporalRelation::Equal
        }
        else if self.superseded_by(other) {
            TemporalRelation::Caused
        }
        else if other.superseded_by(self) {
            TemporalRelation::EffectOf
        }
        else {
            TemporalRelation::Concurrent
        }
    }

    fn superseded_by(&self, other: &Self) -> bool {
        let mut has_smaller = false;

        for (host, &self_n) in self.entries.iter() {
            let other_n = *other.entries.get(host).unwrap_or(&0);

            if self_n > other_n {
                return false;
            }

            has_smaller = has_smaller || (self_n < other_n);
        }

        for (host, &other_n) in other.entries.iter() {
            let self_n = *self.entries.get(host).unwrap_or(&0);

            if self_n > other_n {
                return false;
            }

            has_smaller = has_smaller || (self_n < other_n);
        }

        has_smaller
    }

    pub fn merge_with(&self, other: &Self) -> Self {
        let mut entries = self.entries.clone();

        for (host, &other_n) in other.entries.iter() {
            match entries.entry(host.clone()) {
                Entry::Vacant(e) => { e.insert(other_n); },
                Entry::Occupied(mut e) => {
                    let self_n = *e.get();

                    if other_n > self_n {
                        e.insert(other_n);
                    }
                }
            }
        }

        VectorClock {
            entries: entries,
        }
    }
}

#[cfg(test)]
mod test {
    use super::{VectorClock, TemporalRelation};

    type StrVectorClock = VectorClock<&'static str>;

    #[test]
    fn test_empty_ordering() {
        let c1 = StrVectorClock::new();
        let c2 = StrVectorClock::new();

        assert_eq!(c1, c2);

        assert!(c1.temporal_relation(&c2) == TemporalRelation::Equal);
        assert!(c2.temporal_relation(&c1) == TemporalRelation::Equal);
    }

    #[test]
    fn test_incremented_ordering() {
        let c1 = StrVectorClock::new();
        let c2 = c1.incremented("A");

        assert!(!(c1 == c2));

        assert!(c1.temporal_relation(&c2) == TemporalRelation::Caused);
        assert!(c2.temporal_relation(&c1) == TemporalRelation::EffectOf);
    }

    #[test]
    fn test_diverged() {
        let base = StrVectorClock::new();
        let c1 = base.incremented("A");
        let c2 = base.incremented("B");

        assert!(!(c1 == c2));

        assert!(c1.temporal_relation(&c2) == TemporalRelation::Concurrent);
        assert!(c2.temporal_relation(&c1) == TemporalRelation::Concurrent);
    }

    #[test]
    fn test_merged() {
        let base = StrVectorClock::new();
        let c1 = base.incremented("A");
        let c2 = base.incremented("B");

        let m = c1.merge_with(&c2);

        assert!(m.temporal_relation(&c1) == TemporalRelation::EffectOf);
        assert!(c1.temporal_relation(&m) == TemporalRelation::Caused);

        assert!(m.temporal_relation(&c2) == TemporalRelation::EffectOf);
        assert!(c2.temporal_relation(&m) == TemporalRelation::Caused);
    }
}
<|endoftext|>


<commit_before>#![feature(core, io, libc, os, path, plugin)]
#![plugin(json_macros)]

extern crate fuse;
extern crate time;
extern crate libc;
extern crate "rustc-serialize" as rustc_serialize;

use std::collections::BTreeMap;
use std::old_io::{FileType, USER_FILE, USER_DIR};
use std::os;
use std::old_path::PosixPath;
use libc::{ENOENT};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory};
use rustc_serialize::json;

struct JsonFilesystem {
    tree: json::Object,
    attrs: BTreeMap<u64, FileAttr>,
    inodes: BTreeMap<String, u64>,
}

impl JsonFilesystem {
    fn new(tree: &json::Object) -> JsonFilesystem {
        let mut attrs = BTreeMap::new();
        let mut inodes = BTreeMap::new();
        let ts = time::now().to_timespec();
        let attr = FileAttr {
            ino: 1,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: USER_DIR,
            nlink: 0,
            uid: 0,
            gid: 0,
            rdev: 0,
            flags: 0,
        };
        attrs.insert(1, attr);
        inodes.insert("/".to_string(), 1);
        for (i, (key, value)) in tree.iter().enumerate() {
            let attr = FileAttr {
                ino: i as u64 + 2,
                size: value.pretty().to_string().len() as u64,
                blocks: 0,
                atime: ts,
                mtime: ts,
                ctime: ts,
                crtime: ts,
                kind: FileType::RegularFile,
                perm: USER_FILE,
                nlink: 0,
                uid: 0,
                gid: 0,
                rdev: 0,
                flags: 0,
            };
            attrs.insert(attr.ino, attr);
            inodes.insert(key.clone(), attr.ino);
        }
        JsonFilesystem { tree: tree.clone(), attrs: attrs, inodes: inodes }
    }
}

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(ino={})", ino);
        match self.attrs.get(&ino) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.attr(&ttl, attr);
            },
            None => reply.error(ENOENT),
        };
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &PosixPath, reply: ReplyEntry) {
        println!("lookup(parent={}, name={})", parent, name.display());
        let inode = match self.inodes.get(name.as_str().unwrap()) {
            Some(inode) => inode,
            None => {
                reply.error(ENOENT);
                return;
            },
        };
        match self.attrs.get(inode) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.entry(&ttl, attr, 0);
            },
            None => reply.error(ENOENT),
        };
    }

    fn read(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, size: u32, reply: ReplyData) {
        println!("read(ino={}, fh={}, offset={}, size={})", ino, fh, offset, size);
        for (key, &inode) in self.inodes.iter() {
            if inode == ino {
                let value = self.tree.get(key).unwrap();
                reply.data(value.pretty().to_string().as_bytes());
                return;
            }
        }
        reply.error(ENOENT);
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(ino={}, fh={}, offset={})", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
                for (key, &inode) in self.inodes.iter() {
                    if inode == 1 { continue; }
                    let offset = inode; // hack
                    println!("\tkey={}, inode={}, offset={}", key, inode, offset);
                    reply.add(inode, offset, FileType::RegularFile, &PosixPath::new(key));
                }
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (days 15 & 16)");
    let data = json!({
        "foo": "bar",
        "answer": 42,
    });
    let tree = data.as_object().unwrap();
    let fs = JsonFilesystem::new(tree);
    let mountpoint = match os::args().as_slice() {
        [_, ref path] => Path::new(path),
        _ => {
            println!("Usage: {} <MOUNTPOINT>", os::args()[0]);
            return;
        }
    };
    fuse::mount(fs, &mountpoint, &[]);
}
<commit_msg>Updated day 15 for env::args().<commit_after>#![feature(core, env, io, libc, path, plugin)]
#![plugin(json_macros)]

extern crate fuse;
extern crate time;
extern crate libc;
extern crate "rustc-serialize" as rustc_serialize;

use std::collections::BTreeMap;
use std::old_io::{FileType, USER_FILE, USER_DIR};
use std::env;
use std::old_path::PosixPath;
use libc::{ENOENT};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory};
use rustc_serialize::json;

struct JsonFilesystem {
    tree: json::Object,
    attrs: BTreeMap<u64, FileAttr>,
    inodes: BTreeMap<String, u64>,
}

impl JsonFilesystem {
    fn new(tree: &json::Object) -> JsonFilesystem {
        let mut attrs = BTreeMap::new();
        let mut inodes = BTreeMap::new();
        let ts = time::now().to_timespec();
        let attr = FileAttr {
            ino: 1,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: USER_DIR,
            nlink: 0,
            uid: 0,
            gid: 0,
            rdev: 0,
            flags: 0,
        };
        attrs.insert(1, attr);
        inodes.insert("/".to_string(), 1);
        for (i, (key, value)) in tree.iter().enumerate() {
            let attr = FileAttr {
                ino: i as u64 + 2,
                size: value.pretty().to_string().len() as u64,
                blocks: 0,
                atime: ts,
                mtime: ts,
                ctime: ts,
                crtime: ts,
                kind: FileType::RegularFile,
                perm: USER_FILE,
                nlink: 0,
                uid: 0,
                gid: 0,
                rdev: 0,
                flags: 0,
            };
            attrs.insert(attr.ino, attr);
            inodes.insert(key.clone(), attr.ino);
        }
        JsonFilesystem { tree: tree.clone(), attrs: attrs, inodes: inodes }
    }
}

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(ino={})", ino);
        match self.attrs.get(&ino) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.attr(&ttl, attr);
            },
            None => reply.error(ENOENT),
        };
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &PosixPath, reply: ReplyEntry) {
        println!("lookup(parent={}, name={})", parent, name.display());
        let inode = match self.inodes.get(name.as_str().unwrap()) {
            Some(inode) => inode,
            None => {
                reply.error(ENOENT);
                return;
            },
        };
        match self.attrs.get(inode) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.entry(&ttl, attr, 0);
            },
            None => reply.error(ENOENT),
        };
    }

    fn read(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, size: u32, reply: ReplyData) {
        println!("read(ino={}, fh={}, offset={}, size={})", ino, fh, offset, size);
        for (key, &inode) in self.inodes.iter() {
            if inode == ino {
                let value = self.tree.get(key).unwrap();
                reply.data(value.pretty().to_string().as_bytes());
                return;
            }
        }
        reply.error(ENOENT);
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(ino={}, fh={}, offset={})", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
                for (key, &inode) in self.inodes.iter() {
                    if inode == 1 { continue; }
                    let offset = inode; // hack
                    println!("\tkey={}, inode={}, offset={}", key, inode, offset);
                    reply.add(inode, offset, FileType::RegularFile, &PosixPath::new(key));
                }
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (days 15 & 16)");
    let data = json!({
        "foo": "bar",
        "answer": 42,
    });
    let tree = data.as_object().unwrap();
    let fs = JsonFilesystem::new(tree);
    let args = env::args().collect::<Vec<_>>();
    let mountpoint = match &args[] {
        [_, ref path] => Path::new(path),
        _ => {
            println!("Usage: {} <MOUNTPOINT>", args[0]);
            return;
        }
    };
    fuse::mount(fs, &mountpoint, &[]);
}
<|endoftext|>


<commit_before>
use std;
use std::num::FromPrimitive;
use ffi;
use {
    BBox,
    BitmapGlyph,
    FtResult,
    Matrix,
    RenderMode,
    Vector,
};

pub struct Glyph {
    library_raw: ffi::FT_Library,
    raw: ffi::FT_Glyph,
}

impl Glyph {
    pub fn from_raw(library_raw: ffi::FT_Library, raw: ffi::FT_Glyph) -> Glyph {
        unsafe {
            ffi::FT_Reference_Library(library_raw);
        }

        Glyph {
            library_raw: library_raw,
            raw: raw,
        }
    }

    pub fn transform(&self, matrix: Option<Matrix>, delta: Option<Vector>) -> FtResult<()> {
        unsafe {
            let mut p_matrix : *const Matrix = std::ptr::null();
            let mut p_delta : *const Vector = std::ptr::null();

            if matrix.is_some() {
                p_matrix = &matrix.unwrap() as *const Matrix;
            }

            if delta.is_some() {
                p_delta = &delta.unwrap() as *const Vector;
            }

            let err = ffi::FT_Glyph_Transform(self.raw, p_matrix, p_delta);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn get_cbox(&self, bbox_mode: ffi::FT_Glyph_BBox_Mode) -> BBox {
        unsafe {
            let acbox = ffi::FT_BBox {
                xMin: 0,
                yMin: 0,
                xMax: 0,
                yMax: 0,
            };
            ffi::FT_Glyph_Get_CBox(self.raw, bbox_mode, &acbox);
            acbox
        }
    }

    pub fn to_bitmap(&self, render_mode: RenderMode, origin: Option<Vector>) -> FtResult<BitmapGlyph> {
        unsafe {
            let mut p_origin = std::ptr::null();
            if origin.is_some() {
                p_origin = origin.as_ref().unwrap() as *const Vector;
            }

            let the_glyph = self.raw;
            let err = ffi::FT_Glyph_To_Bitmap(&the_glyph, render_mode as u32, p_origin, 0);
            if err == ffi::FT_Err_Ok {
                Ok(BitmapGlyph::from_raw(the_glyph as ffi::FT_BitmapGlyph))
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn advance(&self) -> ffi::FT_Vector {
        unsafe {
            (*self.raw).advance
        }
    }

    #[inline(always)]
    pub fn format(&self) -> ffi::FT_Glyph_Format {
        unsafe {
            (*self.raw).format
        }
    }

    #[inline(always)]
    pub fn raw(&self) -> &ffi::FT_GlyphRec {
        unsafe {
            &*self.raw
        }
    }
}

impl Clone for Glyph {
    fn clone(&self) -> Glyph {
        unsafe {
            let mut target = std::ptr::null_mut();
            match ffi::FT_Glyph_Copy(self.raw, &mut target) {
                ffi::FT_Err_Ok => Glyph::from_raw(self.library_raw, target),
                _ => panic!("Falid to copy glyph"),
            }
        }
    }
}

impl Drop for Glyph {
    fn drop(&mut self) {
        unsafe {
            ffi::FT_Done_Glyph(self.raw);
            ffi::FT_Done_Library(self.library_raw);
        }
    }
}

<commit_msg>add glyph advance_x and advance_y in favor of exposing raw ffi<commit_after>
use std;
use std::num::FromPrimitive;
use ffi;
use {
    BBox,
    BitmapGlyph,
    FtResult,
    Matrix,
    RenderMode,
    Vector,
};

pub struct Glyph {
    library_raw: ffi::FT_Library,
    raw: ffi::FT_Glyph,
}

impl Glyph {
    pub fn from_raw(library_raw: ffi::FT_Library, raw: ffi::FT_Glyph) -> Glyph {
        unsafe {
            ffi::FT_Reference_Library(library_raw);
        }

        Glyph {
            library_raw: library_raw,
            raw: raw,
        }
    }

    pub fn transform(&self, matrix: Option<Matrix>, delta: Option<Vector>) -> FtResult<()> {
        unsafe {
            let mut p_matrix : *const Matrix = std::ptr::null();
            let mut p_delta : *const Vector = std::ptr::null();

            if matrix.is_some() {
                p_matrix = &matrix.unwrap() as *const Matrix;
            }

            if delta.is_some() {
                p_delta = &delta.unwrap() as *const Vector;
            }

            let err = ffi::FT_Glyph_Transform(self.raw, p_matrix, p_delta);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn get_cbox(&self, bbox_mode: ffi::FT_Glyph_BBox_Mode) -> BBox {
        unsafe {
            let acbox = ffi::FT_BBox {
                xMin: 0,
                yMin: 0,
                xMax: 0,
                yMax: 0,
            };
            ffi::FT_Glyph_Get_CBox(self.raw, bbox_mode, &acbox);
            acbox
        }
    }

    pub fn to_bitmap(&self, render_mode: RenderMode, origin: Option<Vector>) -> FtResult<BitmapGlyph> {
        unsafe {
            let mut p_origin = std::ptr::null();
            if origin.is_some() {
                p_origin = origin.as_ref().unwrap() as *const Vector;
            }

            let the_glyph = self.raw;
            let err = ffi::FT_Glyph_To_Bitmap(&the_glyph, render_mode as u32, p_origin, 0);
            if err == ffi::FT_Err_Ok {
                Ok(BitmapGlyph::from_raw(the_glyph as ffi::FT_BitmapGlyph))
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn advance_x(&self) -> isize {
        unsafe {
            (*self.raw).advance.x as isize
        }
    }

    pub fn advance_y(&self) -> isize {
        unsafe {
            (*self.raw).advance.y as isize
        }
    }

    #[deprecated = "use advance_x and advance_y instead"]
    pub fn advance(&self) -> ffi::FT_Vector {
        unsafe {
            (*self.raw).advance
        }
    }

    #[inline(always)]
    pub fn format(&self) -> ffi::FT_Glyph_Format {
        unsafe {
            (*self.raw).format
        }
    }

    #[inline(always)]
    pub fn raw(&self) -> &ffi::FT_GlyphRec {
        unsafe {
            &*self.raw
        }
    }
}

impl Clone for Glyph {
    fn clone(&self) -> Glyph {
        unsafe {
            let mut target = std::ptr::null_mut();
            match ffi::FT_Glyph_Copy(self.raw, &mut target) {
                ffi::FT_Err_Ok => Glyph::from_raw(self.library_raw, target),
                _ => panic!("Falid to copy glyph"),
            }
        }
    }
}

impl Drop for Glyph {
    fn drop(&mut self) {
        unsafe {
            ffi::FT_Done_Glyph(self.raw);
            ffi::FT_Done_Library(self.library_raw);
        }
    }
}

<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use super::{LldFlavor, TargetOptions, PanicStrategy, LinkerFlavor};

pub fn options() -> TargetOptions {
    let mut lld_args = Vec::new();
    let mut clang_args = Vec::new();
    let mut arg = |arg: &str| {
        lld_args.push(arg.to_string());
        clang_args.push(format!("-Wl,{}", arg));
    };

    // There have been reports in the wild (rustwasm/wasm-bindgen#119) of
    // using threads causing weird hangs and bugs. Disable it entirely as
    // this isn't yet the bottleneck of compilation at all anyway.
    //
    // FIXME: we should file an upstream issue with LLD about this
    arg("--no-threads");

    // By default LLD only gives us one page of stack (64k) which is a
    // little small. Default to a larger stack closer to other PC platforms
    // (1MB) and users can always inject their own link-args to override this.
    arg("-z");
    arg("stack-size=1048576");

    // By default LLD's memory layout is:
    //
    // 1. First, a blank page
    // 2. Next, all static data
    // 3. Finally, the main stack (which grows down)
    //
    // This has the unfortunate consequence that on stack overflows you
    // corrupt static data and can cause some exceedingly weird bugs. To
    // help detect this a little sooner we instead request that the stack is
    // placed before static data.
    //
    // This means that we'll generate slightly larger binaries as references
    // to static data will take more bytes in the ULEB128 encoding, but
    // stack overflow will be guaranteed to trap as it underflows instead of
    // corrupting static data.
    arg("--stack-first");

    // FIXME we probably shouldn't pass this but instead pass an explicit
    // whitelist of symbols we'll allow to be undefined. We don't currently have
    // a mechanism of knowing, however, which symbols are intended to be
    // imported from the environment and which are intended to be imported from
    // other objects linked elsewhere. This is a coarse approximation but is
    // sure to hide some bugs and frustrate someone at some point, so we should
    // ideally work towards a world where we can explicitly list symbols that
    // are supposed to be imported and have all other symbols generate errors if
    // they remain undefined.
    arg("--allow-undefined");

    // Rust code should never have warnings, and warnings are often
    // indicative of bugs, let's prevent them.
    arg("--fatal-warnings");

    // LLD only implements C++-like demangling, which doesn't match our own
    // mangling scheme. Tell LLD to not demangle anything and leave it up to
    // us to demangle these symbols later. Currently rustc does not perform
    // further demangling, but tools like twiggy and wasm-bindgen are intended
    // to do so.
    arg("--no-demangle");

    // The symbol visibility story is a bit in flux right now with LLD.
    // It's... not entirely clear to me what's going on, but this looks to
    // make everything work when `export_symbols` isn't otherwise called for
    // things like executables.
    //
    // This is really only here to get things working. If it can be removed and
    // basic tests still work, then sounds like it should be removed!
    arg("--export-dynamic");

    let mut pre_link_args = BTreeMap::new();
    pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args);
    pre_link_args.insert(LinkerFlavor::Gcc, clang_args);

    TargetOptions {
        // we allow dynamic linking, but only cdylibs. Basically we allow a
        // final library artifact that exports some symbols (a wasm module) but
        // we don't allow intermediate `dylib` crate types
        dynamic_linking: true,
        only_cdylib: true,

        // This means we'll just embed a `start` function in the wasm module
        executables: true,

        // relatively self-explanatory!
        exe_suffix: ".wasm".to_string(),
        dll_prefix: String::new(),
        dll_suffix: ".wasm".to_string(),
        linker_is_gnu: false,

        max_atomic_width: Some(64),

        // Unwinding doesn't work right now, so the whole target unconditionally
        // defaults to panic=abort. Note that this is guaranteed to change in
        // the future once unwinding is implemented. Don't rely on this as we're
        // basically guaranteed to change it once WebAssembly supports
        // exceptions.
        panic_strategy: PanicStrategy::Abort,

        // Wasm doesn't have atomics yet, so tell LLVM that we're in a single
        // threaded model which will legalize atomics to normal operations.
        singlethread: true,

        // no dynamic linking, no need for default visibility!
        default_hidden_visibility: true,

        // we use the LLD shipped with the Rust toolchain by default
        linker: Some("rust-lld".to_owned()),
        lld_flavor: LldFlavor::Wasm,

        // No need for indirection here, simd types can always be passed by
        // value as the whole module either has simd or not, which is different
        // from x86 (for example) where programs can have functions that don't
        // enable simd features.
        simd_types_indirect: false,

        pre_link_args,

        .. Default::default()
    }
}
<commit_msg>wasm32: Default to a "static" relocation model<commit_after>use std::collections::BTreeMap;
use super::{LldFlavor, TargetOptions, PanicStrategy, LinkerFlavor};

pub fn options() -> TargetOptions {
    let mut lld_args = Vec::new();
    let mut clang_args = Vec::new();
    let mut arg = |arg: &str| {
        lld_args.push(arg.to_string());
        clang_args.push(format!("-Wl,{}", arg));
    };

    // There have been reports in the wild (rustwasm/wasm-bindgen#119) of
    // using threads causing weird hangs and bugs. Disable it entirely as
    // this isn't yet the bottleneck of compilation at all anyway.
    //
    // FIXME: we should file an upstream issue with LLD about this
    arg("--no-threads");

    // By default LLD only gives us one page of stack (64k) which is a
    // little small. Default to a larger stack closer to other PC platforms
    // (1MB) and users can always inject their own link-args to override this.
    arg("-z");
    arg("stack-size=1048576");

    // By default LLD's memory layout is:
    //
    // 1. First, a blank page
    // 2. Next, all static data
    // 3. Finally, the main stack (which grows down)
    //
    // This has the unfortunate consequence that on stack overflows you
    // corrupt static data and can cause some exceedingly weird bugs. To
    // help detect this a little sooner we instead request that the stack is
    // placed before static data.
    //
    // This means that we'll generate slightly larger binaries as references
    // to static data will take more bytes in the ULEB128 encoding, but
    // stack overflow will be guaranteed to trap as it underflows instead of
    // corrupting static data.
    arg("--stack-first");

    // FIXME we probably shouldn't pass this but instead pass an explicit
    // whitelist of symbols we'll allow to be undefined. We don't currently have
    // a mechanism of knowing, however, which symbols are intended to be
    // imported from the environment and which are intended to be imported from
    // other objects linked elsewhere. This is a coarse approximation but is
    // sure to hide some bugs and frustrate someone at some point, so we should
    // ideally work towards a world where we can explicitly list symbols that
    // are supposed to be imported and have all other symbols generate errors if
    // they remain undefined.
    arg("--allow-undefined");

    // Rust code should never have warnings, and warnings are often
    // indicative of bugs, let's prevent them.
    arg("--fatal-warnings");

    // LLD only implements C++-like demangling, which doesn't match our own
    // mangling scheme. Tell LLD to not demangle anything and leave it up to
    // us to demangle these symbols later. Currently rustc does not perform
    // further demangling, but tools like twiggy and wasm-bindgen are intended
    // to do so.
    arg("--no-demangle");

    // The symbol visibility story is a bit in flux right now with LLD.
    // It's... not entirely clear to me what's going on, but this looks to
    // make everything work when `export_symbols` isn't otherwise called for
    // things like executables.
    //
    // This is really only here to get things working. If it can be removed and
    // basic tests still work, then sounds like it should be removed!
    arg("--export-dynamic");

    let mut pre_link_args = BTreeMap::new();
    pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args);
    pre_link_args.insert(LinkerFlavor::Gcc, clang_args);

    TargetOptions {
        // we allow dynamic linking, but only cdylibs. Basically we allow a
        // final library artifact that exports some symbols (a wasm module) but
        // we don't allow intermediate `dylib` crate types
        dynamic_linking: true,
        only_cdylib: true,

        // This means we'll just embed a `start` function in the wasm module
        executables: true,

        // relatively self-explanatory!
        exe_suffix: ".wasm".to_string(),
        dll_prefix: String::new(),
        dll_suffix: ".wasm".to_string(),
        linker_is_gnu: false,

        max_atomic_width: Some(64),

        // Unwinding doesn't work right now, so the whole target unconditionally
        // defaults to panic=abort. Note that this is guaranteed to change in
        // the future once unwinding is implemented. Don't rely on this as we're
        // basically guaranteed to change it once WebAssembly supports
        // exceptions.
        panic_strategy: PanicStrategy::Abort,

        // Wasm doesn't have atomics yet, so tell LLVM that we're in a single
        // threaded model which will legalize atomics to normal operations.
        singlethread: true,

        // no dynamic linking, no need for default visibility!
        default_hidden_visibility: true,

        // we use the LLD shipped with the Rust toolchain by default
        linker: Some("rust-lld".to_owned()),
        lld_flavor: LldFlavor::Wasm,

        // No need for indirection here, simd types can always be passed by
        // value as the whole module either has simd or not, which is different
        // from x86 (for example) where programs can have functions that don't
        // enable simd features.
        simd_types_indirect: false,

        pre_link_args,

        // This has no effect in LLVM 8 or prior, but in LLVM 9 and later when
        // PIC code is implemented this has quite a drastric effect if it stays
        // at the default, `pic`. In an effort to keep wasm binaries as minimal
        // as possible we're defaulting to `static` for now, but the hope is
        // that eventually we can ship a `pic`-compatible standard library which
        // works with `static` as well (or works with some method of generating
        // non-relative calls and such later on).
        relocation_model: "static".to_string(),

        .. Default::default()
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Read, Write};

use futures::{Poll, Task};
use futures::stream::Stream;

use Ready;

/// An I/O object which can be used to track the read/write readiness of an
/// underlying object.
///
/// Many I/O objects implement a stream of readiness with "edge" semantics where
/// once a notification is returned another one will never be returned until the
/// stream is not ready for I/O. That is, once a stream receives a `Read`
/// notification, it will never receive another one until all the pending data
/// has been read.
///
/// This object will keep track of this and implements two methods,
/// `maybe_read_ready` and `maybe_write_ready`. If an appropriate notification
/// has been seen in the `Stream` implementation and `WouldBlock` has *not*
/// been seen yet from the `Read` and `Write` implementations, these methods
/// will return `true`. Otherwise, if `WouldBlock` has been seen, then the
/// methods will return `false`.
///
/// This abstraction can be useful when readiness notifications need to be
/// translated to different readiness notifications at a particular I/O layer.
/// For example if an underlying stream is readable it doesn't necessarily mean
/// the outer stream may always be readable, and this object can be used to keep
/// track of all the notifications.
pub struct ReadyTracker<S> {
    inner: S,
    read_ready: bool,
    write_ready: bool,
}

impl<S> ReadyTracker<S>
    where S: Stream<Item=Ready, Error=io::Error>,
{
    /// Creates a new I/O object ready to track read/write notifications.
    pub fn new(s: S) -> ReadyTracker<S> {
        ReadyTracker {
            inner: s,
            read_ready: true,
            write_ready: true,
        }
    }
}

impl<S> ReadyTracker<S> {
    /// Returns whether the underlying stream might be ready for a read.
    ///
    /// A stream may be ready for a read when a `Read` notification was seen
    /// from the `Stream::poll` implementation, and the object has not be `read`
    /// enough to see `WouldBlock` yet.
    pub fn maybe_read_ready(&self) -> bool {
        self.read_ready
    }

    /// Returns whether the underlying stream might be ready for a write.
    ///
    /// A stream may be ready for a write when a `Write` notification was seen
    /// from the `Stream::poll` implementation, and the object has not be
    /// `write` enough to see `WouldBlock` yet.
    pub fn maybe_write_ready(&self) -> bool {
        self.write_ready
    }
}

impl<S> Stream for ReadyTracker<S>
    where S: Stream<Item=Ready, Error=io::Error>,
{
    type Item = Ready;
    type Error = io::Error;

    fn poll(&mut self, task: &mut Task) -> Poll<Option<Ready>, io::Error> {
        match self.inner.poll(task) {
            Poll::Ok(Some(ready)) => {
                self.read_ready = self.read_ready || ready.is_read();
                self.write_ready = self.write_ready || ready.is_write();
                Poll::Ok(Some(ready))
            }
            other => other,
        }
    }

    fn schedule(&mut self, task: &mut Task) {
        self.inner.schedule(task)
    }
}

fn is_wouldblock<T>(res: &io::Result<T>) -> bool {
    match *res {
        Ok(_) => false,
        Err(ref e) => e.kind() == io::ErrorKind::WouldBlock,
    }
}

impl<S: Read> Read for ReadyTracker<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let res = self.inner.read(buf);
        if is_wouldblock(&res) {
            debug!("read no longer ready");
            self.read_ready = false;
        }
        return res
    }
}

impl<S: Write> Write for ReadyTracker<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let res = self.inner.write(buf);
        if is_wouldblock(&res) {
            debug!("write no longer ready");
            self.write_ready = false;
        }
        return res
    }

    fn flush(&mut self) -> io::Result<()> {
        let res = self.inner.flush();
        if is_wouldblock(&res) {
            debug!("write no longer ready");
            self.write_ready = false;
        }
        return res
    }
}

<commit_msg>Add get_ref/get_mut to ReadyTracker<commit_after>use std::io::{self, Read, Write};

use futures::{Poll, Task};
use futures::stream::Stream;

use Ready;

/// An I/O object which can be used to track the read/write readiness of an
/// underlying object.
///
/// Many I/O objects implement a stream of readiness with "edge" semantics where
/// once a notification is returned another one will never be returned until the
/// stream is not ready for I/O. That is, once a stream receives a `Read`
/// notification, it will never receive another one until all the pending data
/// has been read.
///
/// This object will keep track of this and implements two methods,
/// `maybe_read_ready` and `maybe_write_ready`. If an appropriate notification
/// has been seen in the `Stream` implementation and `WouldBlock` has *not*
/// been seen yet from the `Read` and `Write` implementations, these methods
/// will return `true`. Otherwise, if `WouldBlock` has been seen, then the
/// methods will return `false`.
///
/// This abstraction can be useful when readiness notifications need to be
/// translated to different readiness notifications at a particular I/O layer.
/// For example if an underlying stream is readable it doesn't necessarily mean
/// the outer stream may always be readable, and this object can be used to keep
/// track of all the notifications.
pub struct ReadyTracker<S> {
    inner: S,
    read_ready: bool,
    write_ready: bool,
}

impl<S> ReadyTracker<S>
    where S: Stream<Item=Ready, Error=io::Error>,
{
    /// Creates a new I/O object ready to track read/write notifications.
    pub fn new(s: S) -> ReadyTracker<S> {
        ReadyTracker {
            inner: s,
            read_ready: true,
            write_ready: true,
        }
    }
}

impl<S> ReadyTracker<S> {
    /// Returns whether the underlying stream might be ready for a read.
    ///
    /// A stream may be ready for a read when a `Read` notification was seen
    /// from the `Stream::poll` implementation, and the object has not be `read`
    /// enough to see `WouldBlock` yet.
    pub fn maybe_read_ready(&self) -> bool {
        self.read_ready
    }

    /// Returns whether the underlying stream might be ready for a write.
    ///
    /// A stream may be ready for a write when a `Write` notification was seen
    /// from the `Stream::poll` implementation, and the object has not be
    /// `write` enough to see `WouldBlock` yet.
    pub fn maybe_write_ready(&self) -> bool {
        self.write_ready
    }

    /// Get a shared reference to the underlying stream.
    pub fn get_ref(&self) -> &S {
        &self.inner
    }

    /// Get a mutable reference to the underlying stream.
    pub fn get_mut(&mut self) -> &mut S {
        &mut self.inner
    }
}

impl<S> Stream for ReadyTracker<S>
    where S: Stream<Item=Ready, Error=io::Error>,
{
    type Item = Ready;
    type Error = io::Error;

    fn poll(&mut self, task: &mut Task) -> Poll<Option<Ready>, io::Error> {
        match self.inner.poll(task) {
            Poll::Ok(Some(ready)) => {
                self.read_ready = self.read_ready || ready.is_read();
                self.write_ready = self.write_ready || ready.is_write();
                Poll::Ok(Some(ready))
            }
            other => other,
        }
    }

    fn schedule(&mut self, task: &mut Task) {
        self.inner.schedule(task)
    }
}

fn is_wouldblock<T>(res: &io::Result<T>) -> bool {
    match *res {
        Ok(_) => false,
        Err(ref e) => e.kind() == io::ErrorKind::WouldBlock,
    }
}

impl<S: Read> Read for ReadyTracker<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let res = self.inner.read(buf);
        if is_wouldblock(&res) {
            debug!("read no longer ready");
            self.read_ready = false;
        }
        return res
    }
}

impl<S: Write> Write for ReadyTracker<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let res = self.inner.write(buf);
        if is_wouldblock(&res) {
            debug!("write no longer ready");
            self.write_ready = false;
        }
        return res
    }

    fn flush(&mut self) -> io::Result<()> {
        let res = self.inner.flush();
        if is_wouldblock(&res) {
            debug!("write no longer ready");
            self.write_ready = false;
        }
        return res
    }
}

<|endoftext|>


<commit_before>use time::get_time;
use time::Timespec;

use std::sync::{Mutex,MutexGuard};

use ewma::EWMA;
use metric::Metric;

const WINDOW: [f64; 3] = [1f64, 5f64, 15f64];

// A MeterSnapshot
pub struct MeterSnapshot {
    count: i64,
    rates: [f64; 3],
    mean: f64,
}

// A StdMeter struct
pub struct StdMeter {
    data: Mutex<MeterSnapshot>,
    ewma: [EWMA; 3],
    start: Timespec,
}

// A Meter trait
pub trait Meter : Metric {
    fn snapshot(&self) -> MeterSnapshot;

    fn mark(&self, n: i64);

    fn tick(&mut self);

    fn rate(&self, rate: f64) -> f64;

    fn mean(&self) -> f64;

    fn count(&self) -> i64;
}

impl Meter for StdMeter {
    fn snapshot(&self) -> MeterSnapshot {
        let s = self.data.lock().unwrap();

        MeterSnapshot {
            count: s.count,
            rates: s.rates,
            mean: s.mean
        }
    }

    fn mark(&self, n: i64) {
        let mut s = self.data.lock().unwrap();

        s.count += n;

        for i in (0..WINDOW.len()) {
            self.ewma[i].update(n as usize);
        }

        self.update_snapshot(s);
    }

    fn tick(&mut self) {
        let s = self.data.lock().unwrap();

        for i in (0..WINDOW.len()) {
            self.ewma[i].tick();
        }

        self.update_snapshot(s);
    }

    /// Return the given EWMA for a rate like 1, 5, 15 minutes
    fn rate(&self, rate: f64) -> f64 {
        let s = self.data.lock().unwrap();

        if let Some(pos) = WINDOW.position_elem(&rate) {
            let r: f64 = s.rates[pos];
            return r;
        }
        0f64
    }

    /// Return the mean rate
    fn mean(&self) -> f64 {
        let s = self.data.lock().unwrap();

        s.mean
    }

    fn count(&self) -> i64 {
        let s = self.data.lock().unwrap();

        s.count
    }
}

impl Metric for StdMeter { }

impl StdMeter {
    fn update_snapshot(&self, mut s: MutexGuard<MeterSnapshot>) {
        for i in (0..WINDOW.len()) {
            s.rates[i] = self.ewma[i].rate();
        }

        let diff = get_time() - self.start;
        s.mean = s.count as f64 / diff.num_seconds() as f64;
    }

    pub fn new() -> StdMeter {
        let data: MeterSnapshot = MeterSnapshot{
            count: 0i64,
            rates: [0f64, 0f64, 0f64],
            mean: 0f64,
        };

        let ewma: [EWMA; 3] = [EWMA::new(1f64), EWMA::new(5f64), EWMA::new(15f64)];

        StdMeter {
            data: Mutex::new(data),
            ewma: ewma,
            start: get_time(),
        }
    }
}

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

    #[test]
    fn zero() {
        let m: StdMeter = StdMeter::new();
        let s: MeterSnapshot = m.snapshot();

        assert_eq!(s.count, 0);
    }

    #[test]
    fn non_zero() {
        let m: StdMeter = StdMeter::new();
        m.mark(3);

        let s: MeterSnapshot = m.snapshot();

        assert_eq!(s.count, 3);
    }

    #[test]
    fn snapshot() {
        let m: StdMeter = StdMeter::new();
        m.mark(1);
        m.mark(1);

        let s = m.snapshot();

        m.mark(1);

        assert_eq!(s.count, 2);
        assert_eq!(m.snapshot().count, 3);
    }

    // Test that decay works correctly
    #[test]
    fn decay() {
        let mut m: StdMeter = StdMeter::new();

        m.tick();
    }
}
<commit_msg>position_elem is unstable<commit_after>use time::get_time;
use time::Timespec;

use std::sync::{Mutex,MutexGuard};

use ewma::EWMA;
use metric::Metric;

const WINDOW: [f64; 3] = [1f64, 5f64, 15f64];

// A MeterSnapshot
pub struct MeterSnapshot {
    count: i64,
    rates: [f64; 3],
    mean: f64,
}

// A StdMeter struct
pub struct StdMeter {
    data: Mutex<MeterSnapshot>,
    ewma: [EWMA; 3],
    start: Timespec,
}

// A Meter trait
pub trait Meter : Metric {
    fn snapshot(&self) -> MeterSnapshot;

    fn mark(&self, n: i64);

    fn tick(&mut self);

    fn rate(&self, rate: f64) -> f64;

    fn mean(&self) -> f64;

    fn count(&self) -> i64;
}

impl Meter for StdMeter {
    fn snapshot(&self) -> MeterSnapshot {
        let s = self.data.lock().unwrap();

        MeterSnapshot {
            count: s.count,
            rates: s.rates,
            mean: s.mean
        }
    }

    fn mark(&self, n: i64) {
        let mut s = self.data.lock().unwrap();

        s.count += n;

        for i in (0..WINDOW.len()) {
            self.ewma[i].update(n as usize);
        }

        self.update_snapshot(s);
    }

    fn tick(&mut self) {
        let s = self.data.lock().unwrap();

        for i in (0..WINDOW.len()) {
            self.ewma[i].tick();
        }

        self.update_snapshot(s);
    }

    /// Return the given EWMA for a rate like 1, 5, 15 minutes
    fn rate(&self, rate: f64) -> f64 {
        let s = self.data.lock().unwrap();

        if let Some(pos) = WINDOW.iter().position(|w| *w == rate) {
            let r: f64 = s.rates[pos];
            return r;
        }
        0f64
    }

    /// Return the mean rate
    fn mean(&self) -> f64 {
        let s = self.data.lock().unwrap();

        s.mean
    }

    fn count(&self) -> i64 {
        let s = self.data.lock().unwrap();

        s.count
    }
}

impl Metric for StdMeter { }

impl StdMeter {
    fn update_snapshot(&self, mut s: MutexGuard<MeterSnapshot>) {
        for i in (0..WINDOW.len()) {
            s.rates[i] = self.ewma[i].rate();
        }

        let diff = get_time() - self.start;
        s.mean = s.count as f64 / diff.num_seconds() as f64;
    }

    pub fn new() -> StdMeter {
        let data: MeterSnapshot = MeterSnapshot{
            count: 0i64,
            rates: [0f64, 0f64, 0f64],
            mean: 0f64,
        };

        let ewma: [EWMA; 3] = [EWMA::new(1f64), EWMA::new(5f64), EWMA::new(15f64)];

        StdMeter {
            data: Mutex::new(data),
            ewma: ewma,
            start: get_time(),
        }
    }
}

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

    #[test]
    fn zero() {
        let m: StdMeter = StdMeter::new();
        let s: MeterSnapshot = m.snapshot();

        assert_eq!(s.count, 0);
    }

    #[test]
    fn non_zero() {
        let m: StdMeter = StdMeter::new();
        m.mark(3);

        let s: MeterSnapshot = m.snapshot();

        assert_eq!(s.count, 3);
    }

    #[test]
    fn snapshot() {
        let m: StdMeter = StdMeter::new();
        m.mark(1);
        m.mark(1);

        let s = m.snapshot();

        m.mark(1);

        assert_eq!(s.count, 2);
        assert_eq!(m.snapshot().count, 3);
    }

    // Test that decay works correctly
    #[test]
    fn decay() {
        let mut m: StdMeter = StdMeter::new();

        m.tick();
    }
}
<|endoftext|>