<commit_before>#![feature(macro_rules)]
#![allow(unused_variable)]
use std::io::{File};

macro_rules! unwrap(
    ($inp: expr) => (
        match $inp {
            Ok(r) => r,
            Err(e) => fail!("{}",e)
        }
    );
)

macro_rules! vprintln(
    ($flag: ident, $msg: expr, $($args:expr)*) => (
        if $flag { println!($msg, $($args)*); }
    );
)

fn main() {
    let path = Path::new("/home/alex/.bitcoin/blocks/blk00000.dat");
    let mut file = unwrap!(File::open(&path));

    verify_block(&mut file);
    parse_block(&mut file, false);
}

fn string_of_hex(hex: & Vec<u8>) -> Vec<String>{
    hex.iter().map(|h| {
        let base16 = ['0', '1', '2', '3',
                      '4', '5', '6', '7',
                      '8', '9', 'A', 'B',
                      'C', 'D', 'E', 'F'];
        let mut s = String::new();
        s.push(base16[(h/16) as uint]);
        s.push(base16[(h%16) as uint]);
        s
    }).collect()
}

fn parse_block(file: &mut File, verbose: bool) {
    let header = unwrap!(file.read_le_u32());
    vprintln!(verbose, "header={}",header);

    let version = unwrap!(file.read_le_u32());
    vprintln!(verbose, "version={}",version);

    let sha = unwrap!(file.read_exact(32));
    vprintln!(verbose, "sha={}",sha);

    let merkle = unwrap!(file.read_exact(32));
    vprintln!(verbose, "merkle={}",string_of_hex(&merkle));

    let timestamp = unwrap!(file.read_le_u32());
    vprintln!(verbose, "timestamp={}",timestamp);

    let difficulty = unwrap!(file.read_le_u32());
    vprintln!(verbose, "difficulty={}",difficulty);

    let nonce = unwrap!(file.read_le_u32());
    vprintln!(verbose, "nonce={}",nonce);

    let transaction_count = read_vli(file);
    vprintln!(verbose, "transaction_count={}",transaction_count);

    for _ in range(0, transaction_count) {
        let transaction_version = unwrap!(file.read_le_u32());

        let input_count = read_vli(file);
        println!("{} inputs", input_count);
        for _ in range(0, input_count) {
            let transaction_hash = unwrap!(file.read_exact(32));
            println!("tx hash={}",string_of_hex(&transaction_hash));
            let transaction_index = unwrap!(file.read_le_u32());
            let script_length = read_vli(file) as uint; // is this okay?
            let script = unwrap!(file.read_exact(script_length));
            let sequence_number = unwrap!(file.read_le_u32());
            assert!(sequence_number == 0xFFFFFFFFu32);
        }

        let output_count = read_vli(file);
        println!("{} outputs", output_count);
        for _ in range(0, output_count) {
            let value = unwrap!(file.read_le_u64());
            println!("value={}", value);
            let script_length = read_vli(file) as uint;
            let script = unwrap!(file.read_exact(script_length));
        }

        let lock_time = unwrap!(file.read_le_u32());
        assert!(lock_time == 0u32);
    }

    // Now, we should be done with the block.
    //assert!(file.eof()); // apparently there's some extra stuff at the end?
}

fn read_vli(file: &mut File) -> u64 {
    let flag = unwrap!(file.read_u8());
    if flag < 0xfd {
        flag as u64
    } else if flag == 0xfd {
        (unwrap!(file.read_le_u16())) as u64
    } else if flag == 0xfe {
        (unwrap!(file.read_le_u32())) as u64
    } else {
        unwrap!(file.read_le_u64())
    }
}

fn verify_block(file: &mut File) {
    print!("verifying block...");

    let magic_uint : u32 = 0xD9B4BEF9;
    let file_uint = unwrap!(file.read_le_u32());
    assert!(magic_uint == file_uint);

    println!("verify passed...");
}
<commit_msg>added data types<commit_after>#![feature(macro_rules)]
#![allow(unused_variable)]
use std::io::{File};

pub mod types;

macro_rules! unwrap(
    ($inp: expr) => (
        match $inp {
            Ok(r) => r,
            Err(e) => fail!("{}",e)
        }
    );
)

macro_rules! vprintln(
    ($flag: ident, $msg: expr, $($args:expr)*) => (
        if $flag { println!($msg, $($args)*); }
    );
)

fn main() {
    let path = Path::new("/home/alex/.bitcoin/blocks/blk00000.dat");
    let mut file = unwrap!(File::open(&path));

    verify_block(&mut file);
    parse_block(&mut file, false);
}

fn string_of_hex(hex: & Vec<u8>) -> Vec<String>{
    hex.iter().map(|h| {
        let base16 = ['0', '1', '2', '3',
                      '4', '5', '6', '7',
                      '8', '9', 'A', 'B',
                      'C', 'D', 'E', 'F'];
        let mut s = String::new();
        s.push(base16[(h/16) as uint]);
        s.push(base16[(h%16) as uint]);
        s
    }).collect()
}

fn parse_block(file: &mut File, verbose: bool) -> types::Block {
    let header = unwrap!(file.read_le_u32());
    let version = unwrap!(file.read_le_u32());
    let sha = unwrap!(file.read_exact(32));
    let merkle = unwrap!(file.read_exact(32));
    let timestamp = unwrap!(file.read_le_u32());
    let difficulty = unwrap!(file.read_le_u32());
    let nonce = unwrap!(file.read_le_u32());
    let transaction_count = read_vli(file);

    let mut txns = Vec::new();
    for _ in range(0, transaction_count) {
        let transaction_version = unwrap!(file.read_le_u32());

        let input_count = read_vli(file);
        let mut txns_in = Vec::new();
        for _ in range(0, input_count) {
            let transaction_hash = unwrap!(file.read_exact(32));
            let transaction_index = unwrap!(file.read_le_u32());
            let script_length = read_vli(file);
            let script = unwrap!(file.read_exact(script_length as uint));
            let sequence_number = unwrap!(file.read_le_u32());
            assert!(sequence_number == 0xFFFFFFFFu32);

            txns_in.push( types::TxIn {
                previous_output : types::OutPoint {
                    hash : transaction_hash,
                    index : transaction_index },
                script_length : script_length,
                signature_script : script,
                sequence : sequence_number
            });
        }

        let output_count = read_vli(file);
        let mut txns_out = Vec::new();
        for _ in range(0, output_count) {
            let value = unwrap!(file.read_le_i64());
            let script_length = read_vli(file);
            let script = unwrap!(file.read_exact(script_length as uint));
            txns_out.push( types::TxOut {
                value : value,
                pk_script_length : script_length,
                pk_script : script
            });
        }

        let lock_time = unwrap!(file.read_le_u32());

        txns.push( types::Transaction {
            version : transaction_version,
            tx_in_count : input_count,
            tx_in : txns_in,
            tx_out_count : output_count,
            tx_out : txns_out,
            lock_time : lock_time
        });
    }

    types::Block {
        version : version,
        prev_block : sha,
        merkle_root : merkle,
        timestamp : timestamp,
        bits : difficulty,
        nonce : nonce,
        txn_count : transaction_count,
        txns : txns
    }
}

fn read_vli(file: &mut File) -> u64 {
    let flag = unwrap!(file.read_u8());
    if flag < 0xfd {
        flag as u64
    } else if flag == 0xfd {
        (unwrap!(file.read_le_u16())) as u64
    } else if flag == 0xfe {
        (unwrap!(file.read_le_u32())) as u64
    } else {
        unwrap!(file.read_le_u64())
    }
}

fn verify_block(file: &mut File) {
    print!("verifying block...");

    let magic_uint : u32 = 0xD9B4BEF9;
    let file_uint = unwrap!(file.read_le_u32());
    assert!(magic_uint == file_uint);

    println!("verify passed...");
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(plugin)]
#![plugin(plugins)]

extern crate content_blocker;
extern crate cookie as cookie_rs;
extern crate devtools_traits;
extern crate flate2;
extern crate hyper;
extern crate hyper_serde;
extern crate ipc_channel;
extern crate msg;
extern crate net;
extern crate net_traits;
extern crate profile_traits;
extern crate servo_config;
extern crate servo_url;
extern crate time;
extern crate unicase;
extern crate url;

#[cfg(test)] mod chrome_loader;
#[cfg(test)] mod cookie;
#[cfg(test)] mod cookie_http_state;
#[cfg(test)] mod data_loader;
#[cfg(test)] mod file_loader;
#[cfg(test)] mod fetch;
#[cfg(test)] mod mime_classifier;
#[cfg(test)] mod resource_thread;
#[cfg(test)] mod hsts;
#[cfg(test)] mod http_loader;
#[cfg(test)] mod filemanager_thread;

use devtools_traits::DevtoolsControlMsg;
use hyper::server::{Handler, Listening, Server};
use net::fetch::methods::{self, FetchContext};
use net::filemanager_thread::FileManager;
use net::test::HttpState;
use net_traits::FetchTaskTarget;
use net_traits::request::Request;
use net_traits::response::Response;
use servo_url::ServoUrl;
use std::rc::Rc;
use std::sync::mpsc::{Sender, channel};

const DEFAULT_USER_AGENT: &'static str = "Such Browser. Very Layout. Wow.";

struct FetchResponseCollector {
    sender: Sender<Response>,
}

fn new_fetch_context(dc: Option<Sender<DevtoolsControlMsg>>) -> FetchContext {
    FetchContext {
        state: HttpState::new(),
        user_agent: DEFAULT_USER_AGENT.into(),
        devtools_chan: dc,
        filemanager: FileManager::new(),
    }
}
impl FetchTaskTarget for FetchResponseCollector {
    fn process_request_body(&mut self, _: &Request) {}
    fn process_request_eof(&mut self, _: &Request) {}
    fn process_response(&mut self, _: &Response) {}
    fn process_response_chunk(&mut self, _: Vec<u8>) {}
    /// Fired when the response is fully fetched
    fn process_response_eof(&mut self, response: &Response) {
        let _ = self.sender.send(response.clone());
    }
}

fn fetch(request: Request, dc: Option<Sender<DevtoolsControlMsg>>) -> Response {
    let (sender, receiver) = channel();
    let target = Box::new(FetchResponseCollector {
        sender: sender,
    });

    methods::fetch(Rc::new(request), &mut Some(target), &new_fetch_context(dc));

    receiver.recv().unwrap()
}

fn fetch_with_context(request: Request, context: &FetchContext) -> Response {
    methods::fetch(Rc::new(request), &mut None, context)
}

fn make_server<H: Handler + 'static>(handler: H) -> (Listening, ServoUrl) {
    // this is a Listening server because of handle_threads()
    let server = Server::http("0.0.0.0:0").unwrap().handle_threads(handler, 1).unwrap();
    let url_string = format!("http://localhost:{}", server.socket.port());
    let url = ServoUrl::parse(&url_string).unwrap();
    (server, url)
}
<commit_msg>Use the asynchronous fetching code for fetch_with_context().<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(plugin)]
#![plugin(plugins)]

extern crate content_blocker;
extern crate cookie as cookie_rs;
extern crate devtools_traits;
extern crate flate2;
extern crate hyper;
extern crate hyper_serde;
extern crate ipc_channel;
extern crate msg;
extern crate net;
extern crate net_traits;
extern crate profile_traits;
extern crate servo_config;
extern crate servo_url;
extern crate time;
extern crate unicase;
extern crate url;

#[cfg(test)] mod chrome_loader;
#[cfg(test)] mod cookie;
#[cfg(test)] mod cookie_http_state;
#[cfg(test)] mod data_loader;
#[cfg(test)] mod file_loader;
#[cfg(test)] mod fetch;
#[cfg(test)] mod mime_classifier;
#[cfg(test)] mod resource_thread;
#[cfg(test)] mod hsts;
#[cfg(test)] mod http_loader;
#[cfg(test)] mod filemanager_thread;

use devtools_traits::DevtoolsControlMsg;
use hyper::server::{Handler, Listening, Server};
use net::fetch::methods::{self, FetchContext};
use net::filemanager_thread::FileManager;
use net::test::HttpState;
use net_traits::FetchTaskTarget;
use net_traits::request::Request;
use net_traits::response::Response;
use servo_url::ServoUrl;
use std::rc::Rc;
use std::sync::mpsc::{Sender, channel};

const DEFAULT_USER_AGENT: &'static str = "Such Browser. Very Layout. Wow.";

struct FetchResponseCollector {
    sender: Sender<Response>,
}

fn new_fetch_context(dc: Option<Sender<DevtoolsControlMsg>>) -> FetchContext {
    FetchContext {
        state: HttpState::new(),
        user_agent: DEFAULT_USER_AGENT.into(),
        devtools_chan: dc,
        filemanager: FileManager::new(),
    }
}
impl FetchTaskTarget for FetchResponseCollector {
    fn process_request_body(&mut self, _: &Request) {}
    fn process_request_eof(&mut self, _: &Request) {}
    fn process_response(&mut self, _: &Response) {}
    fn process_response_chunk(&mut self, _: Vec<u8>) {}
    /// Fired when the response is fully fetched
    fn process_response_eof(&mut self, response: &Response) {
        let _ = self.sender.send(response.clone());
    }
}

fn fetch(request: Request, dc: Option<Sender<DevtoolsControlMsg>>) -> Response {
    fetch_with_context(request, &new_fetch_context(dc))
}

fn fetch_with_context(request: Request, context: &FetchContext) -> Response {
    let (sender, receiver) = channel();
    let target = Box::new(FetchResponseCollector {
        sender: sender,
    });

    methods::fetch(Rc::new(request), &mut Some(target), context);

    receiver.recv().unwrap()
}

fn make_server<H: Handler + 'static>(handler: H) -> (Listening, ServoUrl) {
    // this is a Listening server because of handle_threads()
    let server = Server::http("0.0.0.0:0").unwrap().handle_threads(handler, 1).unwrap();
    let url_string = format!("http://localhost:{}", server.socket.port());
    let url = ServoUrl::parse(&url_string).unwrap();
    (server, url)
}
<|endoftext|>


<commit_before>use itertools::Itertools as _;

use rlua::{FromLua as _, Function as LuaFunction, Lua, Value as LuaValue};
use serde::Serialize;
use serde_json::Value as JsonValue;

use gerritbot_gerrit as gerrit;

const UNKNOWN_USER: &str = "<unknown user>";
const DEFAULT_FORMAT_SCRIPT: &str = include_str!("../../scripts/format.lua");

pub struct Formatter {
    lua: Lua,
}

impl Default for Formatter {
    fn default() -> Self {
        Self {
            lua: load_format_script(DEFAULT_FORMAT_SCRIPT).unwrap(),
        }
    }
}

fn load_format_script(script_source: &str) -> Result<Lua, String> {
    let lua = Lua::new();
    lua.context(|context| -> Result<(), String> {
        let globals = context.globals();
        context
            .load(script_source)
            .exec()
            .map_err(|err| format!("syntax error: {}", err))?;
        let _: LuaFunction = globals
            .get("format_approval")
            .map_err(|_| "format_approval function missing")?;
        Ok(())
    })?;
    Ok(lua)
}

fn json_to_lua<'lua>(json: &JsonValue, lua: rlua::Context<'lua>) -> rlua::Result<LuaValue<'lua>> {
    Ok(match json {
        JsonValue::Null => LuaValue::Nil,
        JsonValue::Bool(b) => LuaValue::Boolean(*b),
        JsonValue::Number(n) => {
            if let Some(n) = n.as_i64() {
                LuaValue::Integer(n)
            } else if let Some(n) = n.as_f64() {
                LuaValue::Number(n)
            } else {
                Err(rlua::Error::ToLuaConversionError {
                    from: "serde_json::Number",
                    to: "Integer",
                    message: Some(format!("value {} too large", n)),
                })?
            }
        }
        JsonValue::String(s) => lua.create_string(s).map(LuaValue::String)?,
        JsonValue::Array(values) => {
            let table = lua.create_table()?;

            for (i, value) in values.iter().enumerate() {
                table.set(LuaValue::Integer(i as i64 + 1), json_to_lua(value, lua)?)?;
            }

            LuaValue::Table(table)
        }
        JsonValue::Object(items) => {
            let table = lua.create_table()?;

            for (key, value) in items {
                let key = lua.create_string(key)?;
                let value = json_to_lua(value, lua)?;
                table.set(key, value)?;
            }

            LuaValue::Table(table)
        }
    })
}

fn to_lua_via_json<'lua, T: Serialize>(
    value: T,
    lua: rlua::Context<'lua>,
) -> Result<LuaValue<'lua>, Box<dyn std::error::Error>> {
    let json_value = serde_json::to_value(value)?;
    let lua_value = json_to_lua(&json_value, lua)?;
    Ok(lua_value)
}

impl Formatter {
    pub fn format_approval(
        &self,
        event: &gerrit::CommentAddedEvent,
        approval: &gerrit::Approval,
        is_human: bool,
    ) -> Result<Option<String>, String> {
        self.lua
            .context(|context| -> Result<Option<String>, String> {
                let globals = context.globals();

                let lua_format_approval: LuaFunction = globals
                    .get("format_approval")
                    .map_err(|_| "format_approval function missing".to_string())?;
                let lua_event = to_lua_via_json(event, context)
                    .map_err(|e| format!("failed to serialize event: {}", e))?;
                let lua_approval = to_lua_via_json(approval, context)
                    .map_err(|e| format!("failed to serialize approval: {}", e))?;
                let lua_result = lua_format_approval
                    .call::<_, LuaValue>((lua_event, lua_approval, is_human))
                    .map_err(|err| format!("lua formatting function failed: {}", err))?;

                match lua_result {
                    LuaValue::Nil => Ok(None),
                    _ => Ok(Some(String::from_lua(lua_result, context).map_err(
                        |e| format!("failed to convert formatting result to string: {}", e),
                    )?)),
                }
            })
    }

    pub fn format_comment_added(
        &self,
        event: &gerrit::CommentAddedEvent,
        is_human: bool,
    ) -> Result<Option<String>, String> {
        let messages: Vec<String> = event
            .approvals
            .iter()
            .filter(|approval| {
                approval.old_value.as_ref() != Some(&approval.value) && approval.value != "0"
            })
            .filter_map(|approval| self.format_approval(event, approval, is_human).transpose())
            .collect::<Result<_, _>>()?;

        let inline_comments = self.format_inline_comments(&event.change, &event.patchset);

        let message = if !messages.is_empty() {
            // We got some approvals
            messages.join("\n\n")
        } else if is_human && inline_comments.is_some() {
            // We did not get any approvals, but we got inline comments from a human.
            event.comment.clone()
        } else {
            return Ok(None);
        };

        Ok(Some(
            inline_comments
                .map(|c| format!("{}\n\n{}", message, c))
                .unwrap_or(message),
        ))
    }

    pub fn format_reviewer_added(
        &self,
        event: &gerrit::ReviewerAddedEvent,
    ) -> Result<String, String> {
        Ok(format!(
            "[{}]({}) ({}) 👓 Added as reviewer",
            event.change.subject,
            event.change.url,
            event
                .change
                .owner
                .username
                .as_ref()
                .map(String::as_str)
                .unwrap_or(UNKNOWN_USER)
        ))
    }

    fn format_inline_comments(
        &self,
        change: &gerrit::Change,
        patchset: &gerrit::Patchset,
    ) -> Option<String> {
        let change_number = change.number;
        let base_url = {
            let last_slash = change.url.rfind('/').unwrap();
            &change.url[..last_slash]
        };
        let patch_set_number = patchset.number;

        patchset
            .comments
            .as_ref()
            .cloned()
            .map(|mut comments| {
                comments.sort_by(|a, b| a.file.cmp(&b.file));
                comments
                    .into_iter()
                    .group_by(|c| c.file.clone())
                    .into_iter()
                    .map(|(file, comments)| -> String {
                        let line_comments = comments
                            .map(|comment| {
                                let mut lines = comment.message.split('\n');
                                let url = format!(
                                    "{}/#/c/{}/{}/{}@{}",
                                    base_url,
                                    change_number,
                                    patch_set_number,
                                    comment.file,
                                    comment.line
                                );
                                let first_line = lines.next().unwrap_or("");
                                let first_line = format!(
                                    "> [Line {}]({}) by {}: {}",
                                    comment.line,
                                    url,
                                    comment
                                        .reviewer
                                        .username
                                        .as_ref()
                                        .map(String::as_str)
                                        .unwrap_or(UNKNOWN_USER),
                                    first_line
                                );
                                let tail = lines
                                    .map(|l| format!("> {}", l))
                                    .intersperse("\n".into())
                                    .collect::<Vec<_>>()
                                    .concat();
                                format!("{}\n{}", first_line, tail)
                            })
                            .intersperse("\n".into())
                            .collect::<Vec<_>>()
                            .concat();
                        format!("`{}`\n\n{}", file, line_comments)
                    })
                    .intersperse("\n\n".into())
                    .collect::<Vec<_>>()
                    .concat()
            })
            .filter(|s| !s.is_empty())
    }
}

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

    const EVENT_JSON : &'static str = r#"
{"author":{"name":"Approver","username":"approver","email":"approver@approvers.com"},"approvals":[{"type":"Code-Review","description":"Code-Review","value":"2","oldValue":"-1"}],"comment":"Patch Set 1: Code-Review+2\n\nJust a buggy script. FAILURE\n\nAnd more problems. FAILURE","patchSet":{"number":1,"revision":"49a65998c02eda928559f2d0b586c20bc8e37b10","parents":["fb1909b4eda306985d2bbce769310e5a50a98cf5"],"ref":"refs/changes/42/42/1","uploader":{"name":"Author","email":"author@example.com","username":"Author"},"createdOn":1494165142,"author":{"name":"Author","email":"author@example.com","username":"Author"},"isDraft":false,"kind":"REWORK","sizeInsertions":0,"sizeDeletions":0},"change":{"project":"demo-project","branch":"master","id":"Ic160fa37fca005fec17a2434aadf0d9dcfbb7b14","number":49,"subject":"Some review.","owner":{"name":"Author","email":"author@example.com","username":"author"},"url":"http://localhost/42","commitMessage":"Some review.\n\nChange-Id: Ic160fa37fca005fec17a2434aadf0d9dcfbb7b14\n","status":"NEW"},"project":"demo-project","refName":"refs/heads/master","changeKey":{"id":"Ic160fa37fca005fec17a2434aadf0d9dcfbb7b14"},"type":"comment-added","eventCreatedOn":1499190282}"#;

    const CHANGE_JSON_WITH_COMMENTS : &'static str = r#"
{"project":"gerritbot-rs","branch":"master","id":"If70442f674c595a59f3e44280570e760ba3584c4","number":1,"subject":"Bump version to 0.6.0","owner":{"name":"Administrator","email":"admin@example.com","username":"admin"},"url":"http://localhost:8080/1","commitMessage":"Bump version to 0.6.0\n\nChange-Id: If70442f674c595a59f3e44280570e760ba3584c4\n","createdOn":1524584729,"lastUpdated":1524584975,"open":true,"status":"NEW","comments":[{"timestamp":1524584729,"reviewer":{"name":"Administrator","email":"admin@example.com","username":"admin"},"message":"Uploaded patch set 1."},{"timestamp":1524584975,"reviewer":{"name":"jdoe","email":"john.doe@localhost","username":"jdoe"},"message":"Patch Set 1:\n\n(1 comment)"}]}"#;

    const PATCHSET_JSON_WITH_COMMENTS : &'static str = r#"{"number":1,"revision":"3f58af760fc1e39fcc4a85b8ab6a6be032cf2ae2","parents":["578bc1e684098d2ac597e030442c3472f15ac3ad"],"ref":"refs/changes/01/1/1","uploader":{"name":"Administrator","email":"admin@example.com","username":"admin"},"createdOn":1524584729,"author":{"name":"jdoe","email":"jdoe@example.com","username":""},"isDraft":false,"kind":"REWORK","comments":[{"file":"/COMMIT_MSG","line":1,"reviewer":{"name":"jdoe","email":"john.doe@localhost","username":"jdoe"},"message":"This is a multiline\ncomment\non some change."}],"sizeInsertions":2,"sizeDeletions":-2}"#;

    fn get_event() -> gerrit::CommentAddedEvent {
        let event: Result<gerrit::Event, _> = serde_json::from_str(EVENT_JSON);
        match event.expect("failed to decode event") {
            gerrit::Event::CommentAdded(event) => event,
            event => panic!("wrong type of event: {:?}", event),
        }
    }

    fn get_change_with_comments() -> (gerrit::Change, gerrit::Patchset) {
        let change: Result<gerrit::Change, _> = serde_json::from_str(CHANGE_JSON_WITH_COMMENTS);
        assert!(change.is_ok());
        let patchset: Result<gerrit::Patchset, _> =
            serde_json::from_str(PATCHSET_JSON_WITH_COMMENTS);
        assert!(patchset.is_ok());
        (change.unwrap(), patchset.unwrap())
    }

    #[test]
    fn test_format_approval() {
        let event = get_event();
        let res = Formatter::default().format_approval(&event, &event.approvals[0], true);
        // Result<Option<String>, _> -> Result<Option<&str>, _>
        let res = res.as_ref().map(|o| o.as_ref().map(String::as_str));
        assert_eq!(
            res,
            Ok(Some("[Some review.](http://localhost/42) ([demo-project](http://localhost/q/project:demo-project+status:open)) 👍 +2 (Code-Review) from [Approver](http://localhost/q/reviewer:approver@approvers.com+status:open)\n\n> Just a buggy script. FAILURE<br>\n> And more problems. FAILURE"))
        );
    }

    #[test]
    fn format_approval_filters_specific_messages() {
        let mut event = get_event();
        event.approvals[0].approval_type = String::from("Some new type");
        let res = Formatter::default().format_approval(&event, &event.approvals[0], true);
        assert_eq!(res, Ok(None));
    }

    #[test]
    fn test_format_comments() {
        let (change, mut patchset) = get_change_with_comments();
        patchset.comments = None;
        assert_eq!(
            Formatter::default().format_inline_comments(&change, &patchset),
            None
        );

        let (change, patchset) = get_change_with_comments();
        assert_eq!(Formatter::default().format_inline_comments(&change, &patchset),
                   Some("`/COMMIT_MSG`\n\n> [Line 1](http://localhost:8080/#/c/1/1//COMMIT_MSG@1) by jdoe: This is a multiline\n> comment\n> on some change.".into()));
    }
}
<commit_msg>only expose minimal set of modules to format script<commit_after>use itertools::Itertools as _;

use rlua::{FromLua as _, Function as LuaFunction, Lua, StdLib as LuaStdLib, Value as LuaValue};
use serde::Serialize;
use serde_json::Value as JsonValue;

use gerritbot_gerrit as gerrit;

const UNKNOWN_USER: &str = "<unknown user>";
const DEFAULT_FORMAT_SCRIPT: &str = include_str!("../../scripts/format.lua");

pub struct Formatter {
    lua: Lua,
}

impl Default for Formatter {
    fn default() -> Self {
        Self {
            lua: load_format_script(DEFAULT_FORMAT_SCRIPT).unwrap(),
        }
    }
}

fn load_format_script(script_source: &str) -> Result<Lua, String> {
    let lua_std_lib = LuaStdLib::BASE | LuaStdLib::STRING | LuaStdLib::TABLE;
    let lua = Lua::new_with(lua_std_lib);
    lua.context(|context| -> Result<(), String> {
        let globals = context.globals();
        context
            .load(script_source)
            .exec()
            .map_err(|err| format!("syntax error: {}", err))?;
        let _: LuaFunction = globals
            .get("format_approval")
            .map_err(|_| "format_approval function missing")?;
        Ok(())
    })?;
    Ok(lua)
}

fn json_to_lua<'lua>(json: &JsonValue, lua: rlua::Context<'lua>) -> rlua::Result<LuaValue<'lua>> {
    Ok(match json {
        JsonValue::Null => LuaValue::Nil,
        JsonValue::Bool(b) => LuaValue::Boolean(*b),
        JsonValue::Number(n) => {
            if let Some(n) = n.as_i64() {
                LuaValue::Integer(n)
            } else if let Some(n) = n.as_f64() {
                LuaValue::Number(n)
            } else {
                Err(rlua::Error::ToLuaConversionError {
                    from: "serde_json::Number",
                    to: "Integer",
                    message: Some(format!("value {} too large", n)),
                })?
            }
        }
        JsonValue::String(s) => lua.create_string(s).map(LuaValue::String)?,
        JsonValue::Array(values) => {
            let table = lua.create_table()?;

            for (i, value) in values.iter().enumerate() {
                table.set(LuaValue::Integer(i as i64 + 1), json_to_lua(value, lua)?)?;
            }

            LuaValue::Table(table)
        }
        JsonValue::Object(items) => {
            let table = lua.create_table()?;

            for (key, value) in items {
                let key = lua.create_string(key)?;
                let value = json_to_lua(value, lua)?;
                table.set(key, value)?;
            }

            LuaValue::Table(table)
        }
    })
}

fn to_lua_via_json<'lua, T: Serialize>(
    value: T,
    lua: rlua::Context<'lua>,
) -> Result<LuaValue<'lua>, Box<dyn std::error::Error>> {
    let json_value = serde_json::to_value(value)?;
    let lua_value = json_to_lua(&json_value, lua)?;
    Ok(lua_value)
}

impl Formatter {
    pub fn format_approval(
        &self,
        event: &gerrit::CommentAddedEvent,
        approval: &gerrit::Approval,
        is_human: bool,
    ) -> Result<Option<String>, String> {
        self.lua
            .context(|context| -> Result<Option<String>, String> {
                let globals = context.globals();

                let lua_format_approval: LuaFunction = globals
                    .get("format_approval")
                    .map_err(|_| "format_approval function missing".to_string())?;
                let lua_event = to_lua_via_json(event, context)
                    .map_err(|e| format!("failed to serialize event: {}", e))?;
                let lua_approval = to_lua_via_json(approval, context)
                    .map_err(|e| format!("failed to serialize approval: {}", e))?;
                let lua_result = lua_format_approval
                    .call::<_, LuaValue>((lua_event, lua_approval, is_human))
                    .map_err(|err| format!("lua formatting function failed: {}", err))?;

                match lua_result {
                    LuaValue::Nil => Ok(None),
                    _ => Ok(Some(String::from_lua(lua_result, context).map_err(
                        |e| format!("failed to convert formatting result to string: {}", e),
                    )?)),
                }
            })
    }

    pub fn format_comment_added(
        &self,
        event: &gerrit::CommentAddedEvent,
        is_human: bool,
    ) -> Result<Option<String>, String> {
        let messages: Vec<String> = event
            .approvals
            .iter()
            .filter(|approval| {
                approval.old_value.as_ref() != Some(&approval.value) && approval.value != "0"
            })
            .filter_map(|approval| self.format_approval(event, approval, is_human).transpose())
            .collect::<Result<_, _>>()?;

        let inline_comments = self.format_inline_comments(&event.change, &event.patchset);

        let message = if !messages.is_empty() {
            // We got some approvals
            messages.join("\n\n")
        } else if is_human && inline_comments.is_some() {
            // We did not get any approvals, but we got inline comments from a human.
            event.comment.clone()
        } else {
            return Ok(None);
        };

        Ok(Some(
            inline_comments
                .map(|c| format!("{}\n\n{}", message, c))
                .unwrap_or(message),
        ))
    }

    pub fn format_reviewer_added(
        &self,
        event: &gerrit::ReviewerAddedEvent,
    ) -> Result<String, String> {
        Ok(format!(
            "[{}]({}) ({}) 👓 Added as reviewer",
            event.change.subject,
            event.change.url,
            event
                .change
                .owner
                .username
                .as_ref()
                .map(String::as_str)
                .unwrap_or(UNKNOWN_USER)
        ))
    }

    fn format_inline_comments(
        &self,
        change: &gerrit::Change,
        patchset: &gerrit::Patchset,
    ) -> Option<String> {
        let change_number = change.number;
        let base_url = {
            let last_slash = change.url.rfind('/').unwrap();
            &change.url[..last_slash]
        };
        let patch_set_number = patchset.number;

        patchset
            .comments
            .as_ref()
            .cloned()
            .map(|mut comments| {
                comments.sort_by(|a, b| a.file.cmp(&b.file));
                comments
                    .into_iter()
                    .group_by(|c| c.file.clone())
                    .into_iter()
                    .map(|(file, comments)| -> String {
                        let line_comments = comments
                            .map(|comment| {
                                let mut lines = comment.message.split('\n');
                                let url = format!(
                                    "{}/#/c/{}/{}/{}@{}",
                                    base_url,
                                    change_number,
                                    patch_set_number,
                                    comment.file,
                                    comment.line
                                );
                                let first_line = lines.next().unwrap_or("");
                                let first_line = format!(
                                    "> [Line {}]({}) by {}: {}",
                                    comment.line,
                                    url,
                                    comment
                                        .reviewer
                                        .username
                                        .as_ref()
                                        .map(String::as_str)
                                        .unwrap_or(UNKNOWN_USER),
                                    first_line
                                );
                                let tail = lines
                                    .map(|l| format!("> {}", l))
                                    .intersperse("\n".into())
                                    .collect::<Vec<_>>()
                                    .concat();
                                format!("{}\n{}", first_line, tail)
                            })
                            .intersperse("\n".into())
                            .collect::<Vec<_>>()
                            .concat();
                        format!("`{}`\n\n{}", file, line_comments)
                    })
                    .intersperse("\n\n".into())
                    .collect::<Vec<_>>()
                    .concat()
            })
            .filter(|s| !s.is_empty())
    }
}

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

    const EVENT_JSON : &'static str = r#"
{"author":{"name":"Approver","username":"approver","email":"approver@approvers.com"},"approvals":[{"type":"Code-Review","description":"Code-Review","value":"2","oldValue":"-1"}],"comment":"Patch Set 1: Code-Review+2\n\nJust a buggy script. FAILURE\n\nAnd more problems. FAILURE","patchSet":{"number":1,"revision":"49a65998c02eda928559f2d0b586c20bc8e37b10","parents":["fb1909b4eda306985d2bbce769310e5a50a98cf5"],"ref":"refs/changes/42/42/1","uploader":{"name":"Author","email":"author@example.com","username":"Author"},"createdOn":1494165142,"author":{"name":"Author","email":"author@example.com","username":"Author"},"isDraft":false,"kind":"REWORK","sizeInsertions":0,"sizeDeletions":0},"change":{"project":"demo-project","branch":"master","id":"Ic160fa37fca005fec17a2434aadf0d9dcfbb7b14","number":49,"subject":"Some review.","owner":{"name":"Author","email":"author@example.com","username":"author"},"url":"http://localhost/42","commitMessage":"Some review.\n\nChange-Id: Ic160fa37fca005fec17a2434aadf0d9dcfbb7b14\n","status":"NEW"},"project":"demo-project","refName":"refs/heads/master","changeKey":{"id":"Ic160fa37fca005fec17a2434aadf0d9dcfbb7b14"},"type":"comment-added","eventCreatedOn":1499190282}"#;

    const CHANGE_JSON_WITH_COMMENTS : &'static str = r#"
{"project":"gerritbot-rs","branch":"master","id":"If70442f674c595a59f3e44280570e760ba3584c4","number":1,"subject":"Bump version to 0.6.0","owner":{"name":"Administrator","email":"admin@example.com","username":"admin"},"url":"http://localhost:8080/1","commitMessage":"Bump version to 0.6.0\n\nChange-Id: If70442f674c595a59f3e44280570e760ba3584c4\n","createdOn":1524584729,"lastUpdated":1524584975,"open":true,"status":"NEW","comments":[{"timestamp":1524584729,"reviewer":{"name":"Administrator","email":"admin@example.com","username":"admin"},"message":"Uploaded patch set 1."},{"timestamp":1524584975,"reviewer":{"name":"jdoe","email":"john.doe@localhost","username":"jdoe"},"message":"Patch Set 1:\n\n(1 comment)"}]}"#;

    const PATCHSET_JSON_WITH_COMMENTS : &'static str = r#"{"number":1,"revision":"3f58af760fc1e39fcc4a85b8ab6a6be032cf2ae2","parents":["578bc1e684098d2ac597e030442c3472f15ac3ad"],"ref":"refs/changes/01/1/1","uploader":{"name":"Administrator","email":"admin@example.com","username":"admin"},"createdOn":1524584729,"author":{"name":"jdoe","email":"jdoe@example.com","username":""},"isDraft":false,"kind":"REWORK","comments":[{"file":"/COMMIT_MSG","line":1,"reviewer":{"name":"jdoe","email":"john.doe@localhost","username":"jdoe"},"message":"This is a multiline\ncomment\non some change."}],"sizeInsertions":2,"sizeDeletions":-2}"#;

    fn get_event() -> gerrit::CommentAddedEvent {
        let event: Result<gerrit::Event, _> = serde_json::from_str(EVENT_JSON);
        match event.expect("failed to decode event") {
            gerrit::Event::CommentAdded(event) => event,
            event => panic!("wrong type of event: {:?}", event),
        }
    }

    fn get_change_with_comments() -> (gerrit::Change, gerrit::Patchset) {
        let change: Result<gerrit::Change, _> = serde_json::from_str(CHANGE_JSON_WITH_COMMENTS);
        assert!(change.is_ok());
        let patchset: Result<gerrit::Patchset, _> =
            serde_json::from_str(PATCHSET_JSON_WITH_COMMENTS);
        assert!(patchset.is_ok());
        (change.unwrap(), patchset.unwrap())
    }

    #[test]
    fn test_format_approval() {
        let event = get_event();
        let res = Formatter::default().format_approval(&event, &event.approvals[0], true);
        // Result<Option<String>, _> -> Result<Option<&str>, _>
        let res = res.as_ref().map(|o| o.as_ref().map(String::as_str));
        assert_eq!(
            res,
            Ok(Some("[Some review.](http://localhost/42) ([demo-project](http://localhost/q/project:demo-project+status:open)) 👍 +2 (Code-Review) from [Approver](http://localhost/q/reviewer:approver@approvers.com+status:open)\n\n> Just a buggy script. FAILURE<br>\n> And more problems. FAILURE"))
        );
    }

    #[test]
    fn format_approval_filters_specific_messages() {
        let mut event = get_event();
        event.approvals[0].approval_type = String::from("Some new type");
        let res = Formatter::default().format_approval(&event, &event.approvals[0], true);
        assert_eq!(res, Ok(None));
    }

    #[test]
    fn test_format_comments() {
        let (change, mut patchset) = get_change_with_comments();
        patchset.comments = None;
        assert_eq!(
            Formatter::default().format_inline_comments(&change, &patchset),
            None
        );

        let (change, patchset) = get_change_with_comments();
        assert_eq!(Formatter::default().format_inline_comments(&change, &patchset),
                   Some("`/COMMIT_MSG`\n\n> [Line 1](http://localhost:8080/#/c/1/1//COMMIT_MSG@1) by jdoe: This is a multiline\n> comment\n> on some change.".into()));
    }
}
<|endoftext|>


<commit_before>extern crate nalgebra as na;
use na::storage::Storage;
use na::{
    convert, zero, DMatrix, DVector, Dim, Dynamic, Matrix, Matrix2x3, Real, VecStorage, Vector,
    Vector2, Vector3, Vector4, Vector5, U1,
};
use std::cmp;

enum ConvolveMode {
    Full,
    Valid,
    Same,
}

fn convolve_full<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
    vector: Vector<R, D, S>,
    kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
    let vec = vector.len();
    let ker = kernel.len();
    let newlen = vec + ker - 1;

    let mut conv = DVector::<R>::zeros(newlen);

    for i in 0..newlen {
        let u_i = if i > ker { i - ker } else { 0 };
        let u_f = cmp::min(i, vec - 1);

        if u_i == u_f {
            conv[i] += vector[u_i] * kernel[(i - u_i)];
        } else {
            for u in u_i..(u_f + 1) {
                if i - u < ker {
                    conv[i] += vector[u] * kernel[(i - u)];
                }
            }
        }
    }
    conv
}

fn convolve_valid<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
    vector: Vector<R, D, S>,
    kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
    let vec = vector.len();
    let ker = kernel.len();
    let newlen = vec - ker + 1;

    let mut conv = DVector::<R>::zeros(newlen);

    for i in 0..newlen {
        for j in 0..ker {
            conv[i] += vector[i + j] * kernel[ker - j - 1];
        }
    }
    conv
}

fn convolve_same<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
    vector: Vector<R, D, S>,
    kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
    let vec = vector.len();
    let ker = kernel.len();

    let mut conv = DVector::<R>::zeros(vec);

    for i in 0..vec {
        for j in 0..ker {
            let val = if i + j < 1 || i + j >= vec + 1 {
                zero::<R>()
            } else {
                vector[i + j - 1]
            };
            conv[i] += val * kernel[ker - j - 1];
        }
    }
    conv
}

fn convolve<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
    vector: Vector<R, D, S>,
    kernel: Vector<R, E, Q>,
    mode: Option<ConvolveMode>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
    if kernel.len() > vector.len() {
        return convolve(kernel, vector, mode);
    }

    match mode.unwrap_or(ConvolveMode::Full) {
        ConvolveMode::Full => return convolve_full(vector, kernel),
        ConvolveMode::Valid => return convolve_valid(vector, kernel),
        ConvolveMode::Same => return convolve_same(vector, kernel),
    }
}

fn main() {
    let v1 = Vector4::new(1.0, 2.0, 1.0, 0.0);
    let v2 = Vector4::new(1.0, 2.0, 5.0, 9.0);
    let x = convolve(v1, v2, Some(ConvolveMode::Same));
    println!("{:?}", x);
}
<commit_msg>All 3 modes of direct done<commit_after>extern crate nalgebra as na;
use na::storage::Storage;
use na::{zero, DVector, Dim, Dynamic, Matrix, Real, VecStorage, Vector, U1};
use std::cmp;

enum ConvolveMode {
    Full,
    Valid,
    Same,
}

fn convolve_full<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
    vector: Vector<R, D, S>,
    kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
    let vec = vector.len();
    let ker = kernel.len();
    let newlen = vec + ker - 1;

    let mut conv = DVector::<R>::zeros(newlen);

    for i in 0..newlen {
        let u_i = if i > ker { i - ker } else { 0 };
        let u_f = cmp::min(i, vec - 1);

        if u_i == u_f {
            conv[i] += vector[u_i] * kernel[(i - u_i)];
        } else {
            for u in u_i..(u_f + 1) {
                if i - u < ker {
                    conv[i] += vector[u] * kernel[(i - u)];
                }
            }
        }
    }
    conv
}

fn convolve_valid<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
    vector: Vector<R, D, S>,
    kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
    let vec = vector.len();
    let ker = kernel.len();
    let newlen = vec - ker + 1;

    let mut conv = DVector::<R>::zeros(newlen);

    for i in 0..newlen {
        for j in 0..ker {
            conv[i] += vector[i + j] * kernel[ker - j - 1];
        }
    }
    conv
}

fn convolve_same<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
    vector: Vector<R, D, S>,
    kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
    let vec = vector.len();
    let ker = kernel.len();

    let mut conv = DVector::<R>::zeros(vec);

    for i in 0..vec {
        for j in 0..ker {
            let val = if i + j < 1 || i + j >= vec + 1 {
                zero::<R>()
            } else {
                vector[i + j - 1]
            };
            conv[i] += val * kernel[ker - j - 1];
        }
    }
    conv
}

fn convolve<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
    vector: Vector<R, D, S>,
    kernel: Vector<R, E, Q>,
    mode: Option<ConvolveMode>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
    if kernel.len() > vector.len() {
        return convolve(kernel, vector, mode);
    }

    match mode.unwrap_or(ConvolveMode::Full) {
        ConvolveMode::Full => return convolve_full(vector, kernel),
        ConvolveMode::Valid => return convolve_valid(vector, kernel),
        ConvolveMode::Same => return convolve_same(vector, kernel),
    }
}

fn main() {

}
<|endoftext|>


<commit_before>//! Test map generators by displaying generated text maps in console.

extern crate calx;
extern crate rand;
extern crate world;

use calx::Prefab;
use rand::Rng;
use std::collections::HashMap;
use std::iter::FromIterator;
use world::{Room, Sector};
use world::mapgen::{self, MapGen, Point2D, Size2D};

struct TestMap {
    terrain: HashMap<Point2D, char>,
}

impl TestMap {
    pub fn new() -> TestMap {
        let mut terrain = HashMap::new();

        let sector = Sector::new(0, 0, 0);
        let sector_origin = sector.origin();
        let mapgen_origin = Point2D::zero();

        terrain.extend(
            sector
                .iter()
                .map(|loc| mapgen_origin + sector_origin.v2_at(loc).unwrap())
                .map(|p| (p, '*')),
        );

        TestMap { terrain }
    }
}

impl mapgen::Dungeon for TestMap {
    type Vault = Room;

    /// Return a random prefab room.
    fn sample_vault<R: Rng>(&mut self, rng: &mut R) -> Self::Vault { rng.gen() }

    /// Add a large open continuous region to dungeon.
    fn dig_chamber<I: IntoIterator<Item = Point2D>>(&mut self, area: I) {
        for pos in area {
            self.terrain.insert(pos, '.');
        }
    }

    /// Add a narrow corridor to dungeon.
    fn dig_corridor<I: IntoIterator<Item = Point2D>>(&mut self, path: I) {
        for pos in path {
            self.terrain.insert(pos, '▒');
        }
    }

    fn place_vault(&mut self, vault: &Self::Vault, pos: Point2D) {
        unimplemented!();
    }

    fn add_door(&mut self, pos: Point2D) { self.terrain.insert(pos, '+'); }

    fn add_up_stairs(&mut self, pos: Point2D) { self.terrain.insert(pos, '<'); }

    fn add_down_stairs(&mut self, pos: Point2D) { self.terrain.insert(pos, '>'); }
}

fn main() {
    let mut map = TestMap::new();

    let domain: Vec<Point2D> = map.terrain.keys().cloned().collect();
    mapgen::Caves.dig(&mut rand::thread_rng(), &mut map, domain);

    println!(
        "{}",
        String::from(Prefab::from_iter(
            map.terrain.iter().map(|(p, t)| (p.to_vector(), *t))
        ))
    );
}
<commit_msg>Test rooms and corridors gen<commit_after>//! Test map generators by displaying generated text maps in console.

extern crate calx;
extern crate rand;
extern crate world;

use calx::Prefab;
use rand::Rng;
use std::collections::HashMap;
use std::iter::FromIterator;
use world::{Room, Sector};
use world::mapgen::{self, MapGen, Point2D, Size2D, Vault, VaultCell};

struct TestMap {
    terrain: HashMap<Point2D, char>,
}

impl TestMap {
    pub fn new() -> TestMap {
        let mut terrain = HashMap::new();

        let sector = Sector::new(0, 0, 0);
        let sector_origin = sector.origin();
        let mapgen_origin = Point2D::zero();

        terrain.extend(
            sector
                .iter()
                .map(|loc| mapgen_origin + sector_origin.v2_at(loc).unwrap())
                .map(|p| (p, '*')),
        );

        TestMap { terrain }
    }
}

impl mapgen::Dungeon for TestMap {
    type Vault = Room;

    /// Return a random prefab room.
    fn sample_vault<R: Rng>(&mut self, rng: &mut R) -> Self::Vault { rng.gen() }

    /// Add a large open continuous region to dungeon.
    fn dig_chamber<I: IntoIterator<Item = Point2D>>(&mut self, area: I) {
        for pos in area {
            self.terrain.insert(pos, '.');
        }
    }

    /// Add a narrow corridor to dungeon.
    fn dig_corridor<I: IntoIterator<Item = Point2D>>(&mut self, path: I) {
        for pos in path {
            self.terrain.insert(pos, '▒');
        }
    }

    fn place_vault(&mut self, vault: &Self::Vault, pos: Point2D) {
        let points: Vec<(Point2D, VaultCell)> = vault.get_shape();
        for &(p, c) in &points {
            let p = p + pos.to_vector();
            if !self.terrain.contains_key(&p) {
                continue;
            }
            let c = match c {
                VaultCell::Interior => '.',
                _ => '#',
            };
            self.terrain.insert(p, c);
        }
    }

    fn add_door(&mut self, pos: Point2D) { self.terrain.insert(pos, '+'); }

    fn add_up_stairs(&mut self, pos: Point2D) { self.terrain.insert(pos, '<'); }

    fn add_down_stairs(&mut self, pos: Point2D) { self.terrain.insert(pos, '>'); }
}

fn main() {
    let mut map = TestMap::new();

    let domain: Vec<Point2D> = map.terrain.keys().cloned().collect();
    mapgen::RoomsAndCorridors.dig(&mut rand::thread_rng(), &mut map, domain);

    println!(
        "{}",
        String::from(Prefab::from_iter(
            map.terrain.iter().map(|(p, t)| (p.to_vector(), *t))
        ))
    );
}
<|endoftext|>


<commit_before>use std::ops::Deref;

use config::gobjects::GObject;
use env::Env;
use library;
use nameutil::*;
use super::*;
use super::child_properties::ChildProperties;
use super::imports::Imports;
use super::info_base::InfoBase;
use super::signatures::Signatures;
use traits::*;
use super::functions::Visibility;

#[derive(Debug, Default)]
pub struct Info {
    pub base: InfoBase,
    pub c_type: String,
    pub c_class_type: Option<String>,
    pub get_type: String,
    pub supertypes: Vec<general::StatusedTypeId>,
    pub generate_trait: bool,
    pub trait_name: String,
    pub has_constructors: bool,
    pub has_methods: bool,
    pub has_functions: bool,
    pub signals: Vec<signals::Info>,
    pub notify_signals: Vec<signals::Info>,
    pub trampolines: trampolines::Trampolines,
    pub properties: Vec<properties::Property>,
    pub child_properties: ChildProperties,
    pub signatures: Signatures,
}

impl Info {
    pub fn has_signals(&self) -> bool {
        self.signals.iter().any(|s| s.trampoline_name.is_ok())
            || self.notify_signals
                .iter()
                .any(|s| s.trampoline_name.is_ok())
    }

    pub fn has_action_signals(&self) -> bool {
        self.signals.iter().any(|s| s.action_emit_name.is_some())
    }
}

impl Deref for Info {
    type Target = InfoBase;

    fn deref(&self) -> &InfoBase {
        &self.base
    }
}

pub fn has_known_subtypes(env: &Env, class_tid: library::TypeId) -> bool {
    for child_tid in env.class_hierarchy.subtypes(class_tid) {
        let child_name = child_tid.full_name(&env.library);
        let status = env.config
            .objects
            .get(&child_name)
            .map(|o| o.status)
            .unwrap_or_default();
        if status.normal() {
            return true;
        }
    }

    false
}

pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info> {
    info!("Analyzing class {}", obj.name);
    let full_name = obj.name.clone();

    let class_tid = match env.library.find_type(0, &full_name) {
        Some(tid) => tid,
        None => return None,
    };

    let type_ = env.type_(class_tid);

    let name: String = split_namespace_name(&full_name).1.into();

    let klass: &library::Class = match type_.maybe_ref() {
        Some(klass) => klass,
        None => return None,
    };

    let mut imports = Imports::with_defined(&env.library, &name);
    imports.add("glib::translate::*", None);
    imports.add("ffi", None);
    imports.add("glib_ffi", None);
    imports.add("gobject_ffi", None);
    imports.add("std::mem", None);
    imports.add("std::ptr", None);

    let supertypes = supertypes::analyze(env, class_tid, &mut imports);

    let mut generate_trait = obj.generate_trait;
    let trait_name = obj.trait_name
        .as_ref()
        .cloned()
        .unwrap_or_else(|| format!("{}Ext", name));

    // Sanity check the user's configuration. It's unlikely that not generating
    // a trait is wanted if there are subtypes in this very crate
    if !generate_trait && has_known_subtypes(env, class_tid) {
        error!(
            "Not generating trait for {} although subtypes exist",
            full_name
        );
    }

    let mut trampolines =
        trampolines::Trampolines::with_capacity(klass.signals.len() + klass.properties.len());
    let mut signatures = Signatures::with_capacity(klass.functions.len());

    let mut functions = functions::analyze(
        env,
        &klass.functions,
        class_tid,
        generate_trait,
        obj,
        &mut imports,
        Some(&mut signatures),
        Some(deps),
    );
    let specials = special_functions::extract(&mut functions);
    // `copy` will duplicate an object while `clone` just adds a reference
    special_functions::unhide(&mut functions, &specials, special_functions::Type::Copy);
    // these are all automatically derived on objects and compare by pointer. If such functions
    // exist they will provide additional functionality
    special_functions::unhide(&mut functions, &specials, special_functions::Type::Hash);
    special_functions::unhide(&mut functions, &specials, special_functions::Type::Equal);
    special_functions::analyze_imports(&specials, &mut imports);

    let signals = signals::analyze(
        env,
        &klass.signals,
        class_tid,
        generate_trait,
        &mut trampolines,
        obj,
        &mut imports,
    );
    let (properties, notify_signals) = properties::analyze(
        env,
        &klass.properties,
        class_tid,
        generate_trait,
        &mut trampolines,
        obj,
        &mut imports,
        &signatures,
        deps,
    );

    let (version, deprecated_version) = info_base::versions(
        env,
        obj,
        &functions,
        klass.version,
        klass.deprecated_version,
    );

    let child_properties =
        child_properties::analyze(env, obj.child_properties.as_ref(), class_tid, &mut imports);

    let has_methods = functions
        .iter()
        .any(|f| f.kind == library::FunctionKind::Method);
    let has_signals = signals.iter().any(|s| s.trampoline_name.is_ok())
        || notify_signals.iter().any(|s| s.trampoline_name.is_ok());

    // There's no point in generating a trait if there are no signals, methods, properties
    // and child properties: it would be empty
    if generate_trait && !has_signals && !has_methods && properties.is_empty()
        && child_properties.is_empty()
    {
        generate_trait = false;
    }

    let has_async = functions
        .iter()
        .any(|f| f.async && f.visibility == Visibility::Public);

    if generate_trait && (!properties.is_empty() || has_signals || has_async) {
        imports.add("glib", None);
    }
    if generate_trait
        && (has_methods || !properties.is_empty() || !child_properties.is_empty() || has_signals)
    {
        imports.add("glib::object::IsA", None);
    }

    let base = InfoBase {
        full_name,
        type_id: class_tid,
        name,
        functions,
        specials,
        imports,
        version,
        deprecated_version,
        cfg_condition: obj.cfg_condition.clone(),
        concurrency: obj.concurrency,
    };

    // patch up trait methods in the symbol table
    if generate_trait {
        let mut symbols = env.symbols.borrow_mut();
        for func in base.methods() {
            if let Some(symbol) = symbols.by_c_name_mut(&func.glib_name) {
                symbol.make_trait_method(&trait_name);
            }
        }
    }

    let has_constructors = !base.constructors().is_empty();
    let has_functions = !base.functions().is_empty();

    let info = Info {
        base,
        c_type: klass.c_type.clone(),
        c_class_type: klass.c_class_type.clone(),
        get_type: klass.glib_get_type.clone(),
        supertypes,
        generate_trait,
        trait_name,
        has_constructors,
        has_methods,
        has_functions,
        signals,
        notify_signals,
        trampolines,
        properties,
        child_properties,
        signatures,
    };

    Some(info)
}

pub fn interface(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info> {
    info!("Analyzing interface {}", obj.name);
    let full_name = obj.name.clone();

    let iface_tid = match env.library.find_type(0, &full_name) {
        Some(tid) => tid,
        None => return None,
    };

    let type_ = env.type_(iface_tid);

    let name: String = split_namespace_name(&full_name).1.into();

    let iface: &library::Interface = match type_.maybe_ref() {
        Some(iface) => iface,
        None => return None,
    };

    let mut imports = Imports::with_defined(&env.library, &name);
    imports.add("glib::translate::*", None);
    imports.add("ffi", None);
    imports.add("glib::object::IsA", None);
    imports.add("glib_ffi", None);
    imports.add("gobject_ffi", None);
    imports.add("std::mem", None);
    imports.add("std::ptr", None);

    let supertypes = supertypes::analyze(env, iface_tid, &mut imports);

    let trait_name = obj.trait_name
        .as_ref()
        .cloned()
        .unwrap_or_else(|| format!("{}Ext", name));

    let mut trampolines = trampolines::Trampolines::with_capacity(iface.signals.len());
    let mut signatures = Signatures::with_capacity(iface.functions.len());

    let functions = functions::analyze(
        env,
        &iface.functions,
        iface_tid,
        true,
        obj,
        &mut imports,
        Some(&mut signatures),
        Some(deps),
    );

    let signals = signals::analyze(
        env,
        &iface.signals,
        iface_tid,
        true,
        &mut trampolines,
        obj,
        &mut imports,
    );
    let (properties, notify_signals) = properties::analyze(
        env,
        &iface.properties,
        iface_tid,
        true,
        &mut trampolines,
        obj,
        &mut imports,
        &signatures,
        deps,
    );

    let (version, deprecated_version) = info_base::versions(
        env,
        obj,
        &functions,
        iface.version,
        iface.deprecated_version,
    );

    if !properties.is_empty() {
        imports.add("glib", None);
    }

    let base = InfoBase {
        full_name,
        type_id: iface_tid,
        name,
        functions,
        specials: Default::default(),
        imports,
        version,
        deprecated_version,
        cfg_condition: obj.cfg_condition.clone(),
        concurrency: obj.concurrency,
    };

    let has_methods = !base.methods().is_empty();
    let has_functions = !base.functions().is_empty();

    let info = Info {
        base,
        c_type: iface.c_type.clone(),
        c_class_type: iface.c_class_type.clone(),
        get_type: iface.glib_get_type.clone(),
        supertypes,
        generate_trait: true,
        trait_name,
        has_methods,
        has_functions,
        signals,
        notify_signals,
        trampolines,
        properties,
        signatures,
        ..Default::default()
    };

    Some(info)
}
<commit_msg>Unhide ToString/Compare special functions for objects and don't impl the traits<commit_after>use std::ops::Deref;

use config::gobjects::GObject;
use env::Env;
use library;
use nameutil::*;
use super::*;
use super::child_properties::ChildProperties;
use super::imports::Imports;
use super::info_base::InfoBase;
use super::signatures::Signatures;
use traits::*;
use super::functions::Visibility;

#[derive(Debug, Default)]
pub struct Info {
    pub base: InfoBase,
    pub c_type: String,
    pub c_class_type: Option<String>,
    pub get_type: String,
    pub supertypes: Vec<general::StatusedTypeId>,
    pub generate_trait: bool,
    pub trait_name: String,
    pub has_constructors: bool,
    pub has_methods: bool,
    pub has_functions: bool,
    pub signals: Vec<signals::Info>,
    pub notify_signals: Vec<signals::Info>,
    pub trampolines: trampolines::Trampolines,
    pub properties: Vec<properties::Property>,
    pub child_properties: ChildProperties,
    pub signatures: Signatures,
}

impl Info {
    pub fn has_signals(&self) -> bool {
        self.signals.iter().any(|s| s.trampoline_name.is_ok())
            || self.notify_signals
                .iter()
                .any(|s| s.trampoline_name.is_ok())
    }

    pub fn has_action_signals(&self) -> bool {
        self.signals.iter().any(|s| s.action_emit_name.is_some())
    }
}

impl Deref for Info {
    type Target = InfoBase;

    fn deref(&self) -> &InfoBase {
        &self.base
    }
}

pub fn has_known_subtypes(env: &Env, class_tid: library::TypeId) -> bool {
    for child_tid in env.class_hierarchy.subtypes(class_tid) {
        let child_name = child_tid.full_name(&env.library);
        let status = env.config
            .objects
            .get(&child_name)
            .map(|o| o.status)
            .unwrap_or_default();
        if status.normal() {
            return true;
        }
    }

    false
}

pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info> {
    info!("Analyzing class {}", obj.name);
    let full_name = obj.name.clone();

    let class_tid = match env.library.find_type(0, &full_name) {
        Some(tid) => tid,
        None => return None,
    };

    let type_ = env.type_(class_tid);

    let name: String = split_namespace_name(&full_name).1.into();

    let klass: &library::Class = match type_.maybe_ref() {
        Some(klass) => klass,
        None => return None,
    };

    let mut imports = Imports::with_defined(&env.library, &name);
    imports.add("glib::translate::*", None);
    imports.add("ffi", None);
    imports.add("glib_ffi", None);
    imports.add("gobject_ffi", None);
    imports.add("std::mem", None);
    imports.add("std::ptr", None);

    let supertypes = supertypes::analyze(env, class_tid, &mut imports);

    let mut generate_trait = obj.generate_trait;
    let trait_name = obj.trait_name
        .as_ref()
        .cloned()
        .unwrap_or_else(|| format!("{}Ext", name));

    // Sanity check the user's configuration. It's unlikely that not generating
    // a trait is wanted if there are subtypes in this very crate
    if !generate_trait && has_known_subtypes(env, class_tid) {
        error!(
            "Not generating trait for {} although subtypes exist",
            full_name
        );
    }

    let mut trampolines =
        trampolines::Trampolines::with_capacity(klass.signals.len() + klass.properties.len());
    let mut signatures = Signatures::with_capacity(klass.functions.len());

    let mut functions = functions::analyze(
        env,
        &klass.functions,
        class_tid,
        generate_trait,
        obj,
        &mut imports,
        Some(&mut signatures),
        Some(deps),
    );
    let mut specials = special_functions::extract(&mut functions);
    // `copy` will duplicate an object while `clone` just adds a reference
    special_functions::unhide(&mut functions, &specials, special_functions::Type::Copy);
    // these are all automatically derived on objects and compare by pointer. If such functions
    // exist they will provide additional functionality
    for t in &[special_functions::Type::Hash,
              special_functions::Type::Equal,
              special_functions::Type::Compare,
              special_functions::Type::ToString,
    ] {
        special_functions::unhide(&mut functions, &specials, *t);
        specials.remove(t);
    }
    special_functions::analyze_imports(&specials, &mut imports);

    let signals = signals::analyze(
        env,
        &klass.signals,
        class_tid,
        generate_trait,
        &mut trampolines,
        obj,
        &mut imports,
    );
    let (properties, notify_signals) = properties::analyze(
        env,
        &klass.properties,
        class_tid,
        generate_trait,
        &mut trampolines,
        obj,
        &mut imports,
        &signatures,
        deps,
    );

    let (version, deprecated_version) = info_base::versions(
        env,
        obj,
        &functions,
        klass.version,
        klass.deprecated_version,
    );

    let child_properties =
        child_properties::analyze(env, obj.child_properties.as_ref(), class_tid, &mut imports);

    let has_methods = functions
        .iter()
        .any(|f| f.kind == library::FunctionKind::Method);
    let has_signals = signals.iter().any(|s| s.trampoline_name.is_ok())
        || notify_signals.iter().any(|s| s.trampoline_name.is_ok());

    // There's no point in generating a trait if there are no signals, methods, properties
    // and child properties: it would be empty
    if generate_trait && !has_signals && !has_methods && properties.is_empty()
        && child_properties.is_empty()
    {
        generate_trait = false;
    }

    let has_async = functions
        .iter()
        .any(|f| f.async && f.visibility == Visibility::Public);

    if generate_trait && (!properties.is_empty() || has_signals || has_async) {
        imports.add("glib", None);
    }
    if generate_trait
        && (has_methods || !properties.is_empty() || !child_properties.is_empty() || has_signals)
    {
        imports.add("glib::object::IsA", None);
    }

    let base = InfoBase {
        full_name,
        type_id: class_tid,
        name,
        functions,
        specials,
        imports,
        version,
        deprecated_version,
        cfg_condition: obj.cfg_condition.clone(),
        concurrency: obj.concurrency,
    };

    // patch up trait methods in the symbol table
    if generate_trait {
        let mut symbols = env.symbols.borrow_mut();
        for func in base.methods() {
            if let Some(symbol) = symbols.by_c_name_mut(&func.glib_name) {
                symbol.make_trait_method(&trait_name);
            }
        }
    }

    let has_constructors = !base.constructors().is_empty();
    let has_functions = !base.functions().is_empty();

    let info = Info {
        base,
        c_type: klass.c_type.clone(),
        c_class_type: klass.c_class_type.clone(),
        get_type: klass.glib_get_type.clone(),
        supertypes,
        generate_trait,
        trait_name,
        has_constructors,
        has_methods,
        has_functions,
        signals,
        notify_signals,
        trampolines,
        properties,
        child_properties,
        signatures,
    };

    Some(info)
}

pub fn interface(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info> {
    info!("Analyzing interface {}", obj.name);
    let full_name = obj.name.clone();

    let iface_tid = match env.library.find_type(0, &full_name) {
        Some(tid) => tid,
        None => return None,
    };

    let type_ = env.type_(iface_tid);

    let name: String = split_namespace_name(&full_name).1.into();

    let iface: &library::Interface = match type_.maybe_ref() {
        Some(iface) => iface,
        None => return None,
    };

    let mut imports = Imports::with_defined(&env.library, &name);
    imports.add("glib::translate::*", None);
    imports.add("ffi", None);
    imports.add("glib::object::IsA", None);
    imports.add("glib_ffi", None);
    imports.add("gobject_ffi", None);
    imports.add("std::mem", None);
    imports.add("std::ptr", None);

    let supertypes = supertypes::analyze(env, iface_tid, &mut imports);

    let trait_name = obj.trait_name
        .as_ref()
        .cloned()
        .unwrap_or_else(|| format!("{}Ext", name));

    let mut trampolines = trampolines::Trampolines::with_capacity(iface.signals.len());
    let mut signatures = Signatures::with_capacity(iface.functions.len());

    let functions = functions::analyze(
        env,
        &iface.functions,
        iface_tid,
        true,
        obj,
        &mut imports,
        Some(&mut signatures),
        Some(deps),
    );

    let signals = signals::analyze(
        env,
        &iface.signals,
        iface_tid,
        true,
        &mut trampolines,
        obj,
        &mut imports,
    );
    let (properties, notify_signals) = properties::analyze(
        env,
        &iface.properties,
        iface_tid,
        true,
        &mut trampolines,
        obj,
        &mut imports,
        &signatures,
        deps,
    );

    let (version, deprecated_version) = info_base::versions(
        env,
        obj,
        &functions,
        iface.version,
        iface.deprecated_version,
    );

    if !properties.is_empty() {
        imports.add("glib", None);
    }

    let base = InfoBase {
        full_name,
        type_id: iface_tid,
        name,
        functions,
        specials: Default::default(),
        imports,
        version,
        deprecated_version,
        cfg_condition: obj.cfg_condition.clone(),
        concurrency: obj.concurrency,
    };

    let has_methods = !base.methods().is_empty();
    let has_functions = !base.functions().is_empty();

    let info = Info {
        base,
        c_type: iface.c_type.clone(),
        c_class_type: iface.c_class_type.clone(),
        get_type: iface.glib_get_type.clone(),
        supertypes,
        generate_trait: true,
        trait_name,
        has_methods,
        has_functions,
        signals,
        notify_signals,
        trampolines,
        properties,
        signatures,
        ..Default::default()
    };

    Some(info)
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Common functionality for x86 and x86_64 CPUs
use ::{io,util};

pub struct Port(u16);

impl Port {
    /// Read a byte (8 bits) from this port
    pub unsafe fn in8(&self) -> u8 {
        let result: u8;
        asm!(  "in al, dx"
            :  "={al}"(result)
            :  "{dx}"(self.0)
            :: "intel"
             , "volatile" );
        result
    }
    /// Read a word (16 bits) from this port
    pub unsafe fn in16(&self) -> u16 {
        let result: u16;
        asm!(  "in ax, dx"
            :  "={ax}"(result)
            :  "{dx}"(self.0)
            :: "intel"
             , "volatile" );
        result
    }

    /// Read a long word (32 bits) from this port
    pub unsafe fn in32(&self) -> u32 {
        let result: u32;
        asm!(  "in eax, dx"
            :  "={eax}"(result)
            :  "{dx}"(self.0)
            :: "intel"
             , "volatile" );
        result
    }

    pub unsafe fn out8(&self, value: u8) {
         asm!(  "out dx, al"
             :: "{dx}"(self.0)
              , "{al}"(value)
             :: "intel"
              , "volatile" );
    }

    pub unsafe fn out16(&self, value: u16) {
         asm!(  "out dx, ax"
             :: "{dx}"(self.0)
              , "{ax}"(value)
             :: "intel"
              , "volatile" );
    }

    pub unsafe fn out32(&self, value: u32) {
         asm!(  "out dx, eax"
             :: "{dx}"(self.0)
              , "{eax}"(value)
             :: "intel"
              , "volatile" );
    }
}

impl io::Read for Port {
    type Error = util::Void;

    /// Reads a single byte into the given buffer
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
        unsafe {
            Ok(match &mut *buf {
                // if the length of the buffer is 0, then obviously
                // no bytes were read
                []                  => 0
                // otherwise, read one byte into the head of the buffer
              , [ref mut head, _..] => { *head = self.in8(); 1 }
            })
        }
    }

    /// Reads a new byte into each position in the buffer.
    fn read_all(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
        let mut read_bytes = 0;
        for idx in buf.iter_mut() {
            // for each index in the buffer, read another byte from the port
            unsafe { *idx = self.in8(); }
            // and increment the number of bytes read (this should be faster
            // than calling `buf.len()` later; as we only need 1 loop)
            read_bytes += 1;
        }
        Ok(read_bytes)
    }

}
<commit_msg>You can now make ports (oops)<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Common functionality for x86 and x86_64 CPUs
use ::{io,util};

pub struct Port(u16);

impl Port {

    pub const fn new(number: u16) -> Port { Port(number) }

    /// Read a byte (8 bits) from this port
    pub unsafe fn in8(&self) -> u8 {
        let result: u8;
        asm!(  "in al, dx"
            :  "={al}"(result)
            :  "{dx}"(self.0)
            :: "intel"
             , "volatile" );
        result
    }
    /// Read a word (16 bits) from this port
    pub unsafe fn in16(&self) -> u16 {
        let result: u16;
        asm!(  "in ax, dx"
            :  "={ax}"(result)
            :  "{dx}"(self.0)
            :: "intel"
             , "volatile" );
        result
    }

    /// Read a long word (32 bits) from this port
    pub unsafe fn in32(&self) -> u32 {
        let result: u32;
        asm!(  "in eax, dx"
            :  "={eax}"(result)
            :  "{dx}"(self.0)
            :: "intel"
             , "volatile" );
        result
    }

    pub unsafe fn out8(&self, value: u8) {
         asm!(  "out dx, al"
             :: "{dx}"(self.0)
              , "{al}"(value)
             :: "intel"
              , "volatile" );
    }

    pub unsafe fn out16(&self, value: u16) {
         asm!(  "out dx, ax"
             :: "{dx}"(self.0)
              , "{ax}"(value)
             :: "intel"
              , "volatile" );
    }

    pub unsafe fn out32(&self, value: u32) {
         asm!(  "out dx, eax"
             :: "{dx}"(self.0)
              , "{eax}"(value)
             :: "intel"
              , "volatile" );
    }
}

impl io::Read for Port {
    type Error = util::Void;

    /// Reads a single byte into the given buffer
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
        unsafe {
            Ok(match &mut *buf {
                // if the length of the buffer is 0, then obviously
                // no bytes were read
                []                  => 0
                // otherwise, read one byte into the head of the buffer
              , [ref mut head, _..] => { *head = self.in8(); 1 }
            })
        }
    }

    /// Reads a new byte into each position in the buffer.
    fn read_all(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
        let mut read_bytes = 0;
        for idx in buf.iter_mut() {
            // for each index in the buffer, read another byte from the port
            unsafe { *idx = self.in8(); }
            // and increment the number of bytes read (this should be faster
            // than calling `buf.len()` later; as we only need 1 loop)
            read_bytes += 1;
        }
        Ok(read_bytes)
    }

}
<|endoftext|>


<commit_before>extern crate termion;

use std::io;
use std::io::Write;

use self::termion::raw::IntoRawMode;

use super::Backend;
use buffer::Cell;
use layout::Rect;
use style::{Color, Modifier, Style};

pub struct TermionBackend<W>
where
    W: Write,
{
    stdout: W,
}

pub type RawBackend = TermionBackend<termion::raw::RawTerminal<io::Stdout>>;
pub type MouseBackend =
    TermionBackend<termion::input::MouseTerminal<termion::raw::RawTerminal<io::Stdout>>>;

impl RawBackend {
    pub fn new() -> Result<RawBackend, io::Error> {
        let raw = io::stdout().into_raw_mode()?;
        Ok(TermionBackend { stdout: raw })
    }
}

impl MouseBackend {
    pub fn new() -> Result<MouseBackend, io::Error> {
        let raw = io::stdout().into_raw_mode()?;
        let mouse = termion::input::MouseTerminal::from(raw);
        Ok(TermionBackend { stdout: mouse })
    }
}

impl<W> Backend for TermionBackend<W>
where
    W: Write,
{
    /// Clears the entire screen and move the cursor to the top left of the screen
    fn clear(&mut self) -> Result<(), io::Error> {
        write!(self.stdout, "{}", termion::clear::All)?;
        write!(self.stdout, "{}", termion::cursor::Goto(1, 1))?;
        self.stdout.flush()?;
        Ok(())
    }

    /// Hides cursor
    fn hide_cursor(&mut self) -> Result<(), io::Error> {
        write!(self.stdout, "{}", termion::cursor::Hide)?;
        self.stdout.flush()?;
        Ok(())
    }

    /// Shows cursor
    fn show_cursor(&mut self) -> Result<(), io::Error> {
        write!(self.stdout, "{}", termion::cursor::Show)?;
        self.stdout.flush()?;
        Ok(())
    }

    fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
    where
        I: Iterator<Item = (u16, u16, &'a Cell)>,
    {
        let mut string = String::with_capacity(content.size_hint().0 * 3);
        let mut style = Style::default();
        let mut last_y = 0;
        let mut last_x = 0;
        let mut inst = 0;
        for (x, y, cell) in content {
            if y != last_y || x != last_x + 1 {
                string.push_str(&format!("{}", termion::cursor::Goto(x + 1, y + 1)));
                inst += 1;
            }
            last_x = x;
            last_y = y;
            if cell.style.modifier != style.modifier {
                string.push_str(&cell.style.modifier.termion_modifier());
                style.modifier = cell.style.modifier;
                if style.modifier == Modifier::Reset {
                    style.bg = Color::Reset;
                    style.fg = Color::Reset;
                }
                inst += 1;
            }
            if cell.style.fg != style.fg {
                string.push_str(&cell.style.fg.termion_fg());
                style.fg = cell.style.fg;
                inst += 1;
            }
            if cell.style.bg != style.bg {
                string.push_str(&cell.style.bg.termion_bg());
                style.bg = cell.style.bg;
                inst += 1;
            }
            string.push_str(&cell.symbol);
            inst += 1;
        }
        debug!("{} instructions outputed.", inst);
        write!(
            self.stdout,
            "{}{}{}{}",
            string,
            Color::Reset.termion_fg(),
            Color::Reset.termion_bg(),
            Modifier::Reset.termion_modifier()
        )?;
        Ok(())
    }

    /// Return the size of the terminal
    fn size(&self) -> Result<Rect, io::Error> {
        let terminal = try!(termion::terminal_size());
        Ok(Rect {
            x: 0,
            y: 0,
            width: terminal.0,
            height: terminal.1,
        })
    }

    fn flush(&mut self) -> Result<(), io::Error> {
        try!(self.stdout.flush());
        Ok(())
    }
}

macro_rules! termion_fg {
    ($color:ident) => (
        format!("{}", termion::color::Fg(termion::color::$color))
    );
}

macro_rules! termion_fg_rgb {
    ($r:expr, $g:expr, $b:expr) => (
        format!("{}", termion::color::Fg(termion::color::Rgb($r, $g, $b)))
    );
}

macro_rules! termion_bg {
    ($color:ident) => (
        format!("{}", termion::color::Bg(termion::color::$color))
    );
}

macro_rules! termion_bg_rgb {
    ($r:expr, $g:expr, $b:expr) => (
        format!("{}", termion::color::Bg(termion::color::Rgb($r, $g, $b)))
    );
}

macro_rules! termion_modifier {
    ($style:ident) => (
        format!("{}", termion::style::$style)
    );
}

impl Color {
    pub fn termion_fg(&self) -> String {
        match *self {
            Color::Reset => termion_fg!(Reset),
            Color::Black => termion_fg!(Black),
            Color::Red => termion_fg!(Red),
            Color::Green => termion_fg!(Green),
            Color::Yellow => termion_fg!(Yellow),
            Color::Magenta => termion_fg!(Magenta),
            Color::Cyan => termion_fg!(Cyan),
            Color::Gray => termion_fg_rgb!(146, 131, 116),
            Color::DarkGray => termion_fg_rgb!(80, 73, 69),
            Color::LightRed => termion_fg!(LightRed),
            Color::LightGreen => termion_fg!(LightGreen),
            Color::LightYellow => termion_fg!(LightYellow),
            Color::LightMagenta => termion_fg!(LightMagenta),
            Color::LightCyan => termion_fg!(LightCyan),
            Color::White => termion_fg!(White),
            Color::Rgb(r, g, b) => termion_fg_rgb!(r, g, b),
        }
    }
    pub fn termion_bg(&self) -> String {
        match *self {
            Color::Reset => termion_bg!(Reset),
            Color::Black => termion_bg!(Black),
            Color::Red => termion_bg!(Red),
            Color::Green => termion_bg!(Green),
            Color::Yellow => termion_bg!(Yellow),
            Color::Magenta => termion_bg!(Magenta),
            Color::Cyan => termion_bg!(Cyan),
            Color::Gray => termion_bg_rgb!(146, 131, 116),
            Color::DarkGray => termion_bg_rgb!(80, 73, 69),
            Color::LightRed => termion_bg!(LightRed),
            Color::LightGreen => termion_bg!(LightGreen),
            Color::LightYellow => termion_bg!(LightYellow),
            Color::LightMagenta => termion_bg!(LightMagenta),
            Color::LightCyan => termion_bg!(LightCyan),
            Color::White => termion_bg!(White),
            Color::Rgb(r, g, b) => termion_bg_rgb!(r, g, b),
        }
    }
}

impl Modifier {
    pub fn termion_modifier(&self) -> String {
        match *self {
            Modifier::Blink => termion_modifier!(Blink),
            Modifier::Bold => termion_modifier!(Bold),
            Modifier::CrossedOut => termion_modifier!(CrossedOut),
            Modifier::Faint => termion_modifier!(Faint),
            Modifier::Framed => termion_modifier!(Framed),
            Modifier::Invert => termion_modifier!(Invert),
            Modifier::Italic => termion_modifier!(Italic),
            Modifier::NoBlink => termion_modifier!(NoBlink),
            Modifier::NoBold => termion_modifier!(NoBold),
            Modifier::NoCrossedOut => termion_modifier!(NoCrossedOut),
            Modifier::NoFaint => termion_modifier!(NoFaint),
            Modifier::NoInvert => termion_modifier!(NoInvert),
            Modifier::NoItalic => termion_modifier!(NoItalic),
            Modifier::NoUnderline => termion_modifier!(NoUnderline),
            Modifier::Reset => termion_modifier!(Reset),
            Modifier::Underline => termion_modifier!(Underline),
        }
    }
}
<commit_msg>[backends] Improve termion backend<commit_after>extern crate termion;

use std::io;
use std::io::Write;

use self::termion::raw::IntoRawMode;

use super::Backend;
use buffer::Cell;
use layout::Rect;
use style::{Color, Modifier, Style};

pub struct TermionBackend<W>
where
    W: Write,
{
    stdout: W,
}

pub type RawBackend = TermionBackend<termion::raw::RawTerminal<io::Stdout>>;
pub type MouseBackend =
    TermionBackend<termion::input::MouseTerminal<termion::raw::RawTerminal<io::Stdout>>>;
pub type AlternateScreenBackend =
    TermionBackend<termion::screen::AlternateScreen<termion::raw::RawTerminal<io::Stdout>>>;

impl RawBackend {
    pub fn new() -> Result<RawBackend, io::Error> {
        let raw = io::stdout().into_raw_mode()?;
        Ok(TermionBackend::with_stdout(raw))
    }
}

impl MouseBackend {
    pub fn new() -> Result<MouseBackend, io::Error> {
        let raw = io::stdout().into_raw_mode()?;
        let mouse = termion::input::MouseTerminal::from(raw);
        Ok(TermionBackend::with_stdout(mouse))
    }
}

impl AlternateScreenBackend {
    pub fn new() -> Result<AlternateScreenBackend, io::Error> {
        let raw = io::stdout().into_raw_mode()?;
        let screen = termion::screen::AlternateScreen::from(raw);
        Ok(TermionBackend::with_stdout(screen))
    }
}

impl<W> TermionBackend<W>
where
    W: Write,
{
    pub fn with_stdout(stdout: W) -> TermionBackend<W> {
        TermionBackend { stdout }
    }
}

impl<W> Write for TermionBackend<W>
where
    W: Write,
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.stdout.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.stdout.flush()
    }
}

impl<W> Backend for TermionBackend<W>
where
    W: Write,
{
    /// Clears the entire screen and move the cursor to the top left of the screen
    fn clear(&mut self) -> io::Result<()> {
        write!(self.stdout, "{}", termion::clear::All)?;
        write!(self.stdout, "{}", termion::cursor::Goto(1, 1))?;
        self.stdout.flush()
    }

    /// Hides cursor
    fn hide_cursor(&mut self) -> io::Result<()> {
        write!(self.stdout, "{}", termion::cursor::Hide)?;
        self.stdout.flush()
    }

    /// Shows cursor
    fn show_cursor(&mut self) -> io::Result<()> {
        write!(self.stdout, "{}", termion::cursor::Show)?;
        self.stdout.flush()
    }

    fn draw<'a, I>(&mut self, content: I) -> io::Result<()>
    where
        I: Iterator<Item = (u16, u16, &'a Cell)>,
    {
        let mut string = String::with_capacity(content.size_hint().0 * 3);
        let mut style = Style::default();
        let mut last_y = 0;
        let mut last_x = 0;
        let mut inst = 0;
        for (x, y, cell) in content {
            if y != last_y || x != last_x + 1 {
                string.push_str(&format!("{}", termion::cursor::Goto(x + 1, y + 1)));
                inst += 1;
            }
            last_x = x;
            last_y = y;
            if cell.style.modifier != style.modifier {
                string.push_str(&cell.style.modifier.termion_modifier());
                style.modifier = cell.style.modifier;
                if style.modifier == Modifier::Reset {
                    style.bg = Color::Reset;
                    style.fg = Color::Reset;
                }
                inst += 1;
            }
            if cell.style.fg != style.fg {
                string.push_str(&cell.style.fg.termion_fg());
                style.fg = cell.style.fg;
                inst += 1;
            }
            if cell.style.bg != style.bg {
                string.push_str(&cell.style.bg.termion_bg());
                style.bg = cell.style.bg;
                inst += 1;
            }
            string.push_str(&cell.symbol);
            inst += 1;
        }
        debug!("{} instructions outputed.", inst);
        write!(
            self.stdout,
            "{}{}{}{}",
            string,
            Color::Reset.termion_fg(),
            Color::Reset.termion_bg(),
            Modifier::Reset.termion_modifier()
        )
    }

    /// Return the size of the terminal
    fn size(&self) -> Result<Rect, io::Error> {
        let terminal = try!(termion::terminal_size());
        Ok(Rect {
            x: 0,
            y: 0,
            width: terminal.0,
            height: terminal.1,
        })
    }

    fn flush(&mut self) -> io::Result<()> {
        self.stdout.flush()
    }
}

macro_rules! termion_fg {
    ($color:ident) => (
        format!("{}", termion::color::Fg(termion::color::$color))
    );
}

macro_rules! termion_fg_rgb {
    ($r:expr, $g:expr, $b:expr) => (
        format!("{}", termion::color::Fg(termion::color::Rgb($r, $g, $b)))
    );
}

macro_rules! termion_bg {
    ($color:ident) => (
        format!("{}", termion::color::Bg(termion::color::$color))
    );
}

macro_rules! termion_bg_rgb {
    ($r:expr, $g:expr, $b:expr) => (
        format!("{}", termion::color::Bg(termion::color::Rgb($r, $g, $b)))
    );
}

macro_rules! termion_modifier {
    ($style:ident) => (
        format!("{}", termion::style::$style)
    );
}

impl Color {
    pub fn termion_fg(&self) -> String {
        match *self {
            Color::Reset => termion_fg!(Reset),
            Color::Black => termion_fg!(Black),
            Color::Red => termion_fg!(Red),
            Color::Green => termion_fg!(Green),
            Color::Yellow => termion_fg!(Yellow),
            Color::Magenta => termion_fg!(Magenta),
            Color::Cyan => termion_fg!(Cyan),
            Color::Gray => termion_fg_rgb!(146, 131, 116),
            Color::DarkGray => termion_fg_rgb!(80, 73, 69),
            Color::LightRed => termion_fg!(LightRed),
            Color::LightGreen => termion_fg!(LightGreen),
            Color::LightYellow => termion_fg!(LightYellow),
            Color::LightMagenta => termion_fg!(LightMagenta),
            Color::LightCyan => termion_fg!(LightCyan),
            Color::White => termion_fg!(White),
            Color::Rgb(r, g, b) => termion_fg_rgb!(r, g, b),
        }
    }
    pub fn termion_bg(&self) -> String {
        match *self {
            Color::Reset => termion_bg!(Reset),
            Color::Black => termion_bg!(Black),
            Color::Red => termion_bg!(Red),
            Color::Green => termion_bg!(Green),
            Color::Yellow => termion_bg!(Yellow),
            Color::Magenta => termion_bg!(Magenta),
            Color::Cyan => termion_bg!(Cyan),
            Color::Gray => termion_bg_rgb!(146, 131, 116),
            Color::DarkGray => termion_bg_rgb!(80, 73, 69),
            Color::LightRed => termion_bg!(LightRed),
            Color::LightGreen => termion_bg!(LightGreen),
            Color::LightYellow => termion_bg!(LightYellow),
            Color::LightMagenta => termion_bg!(LightMagenta),
            Color::LightCyan => termion_bg!(LightCyan),
            Color::White => termion_bg!(White),
            Color::Rgb(r, g, b) => termion_bg_rgb!(r, g, b),
        }
    }
}

impl Modifier {
    pub fn termion_modifier(&self) -> String {
        match *self {
            Modifier::Blink => termion_modifier!(Blink),
            Modifier::Bold => termion_modifier!(Bold),
            Modifier::CrossedOut => termion_modifier!(CrossedOut),
            Modifier::Faint => termion_modifier!(Faint),
            Modifier::Framed => termion_modifier!(Framed),
            Modifier::Invert => termion_modifier!(Invert),
            Modifier::Italic => termion_modifier!(Italic),
            Modifier::NoBlink => termion_modifier!(NoBlink),
            Modifier::NoBold => termion_modifier!(NoBold),
            Modifier::NoCrossedOut => termion_modifier!(NoCrossedOut),
            Modifier::NoFaint => termion_modifier!(NoFaint),
            Modifier::NoInvert => termion_modifier!(NoInvert),
            Modifier::NoItalic => termion_modifier!(NoItalic),
            Modifier::NoUnderline => termion_modifier!(NoUnderline),
            Modifier::Reset => termion_modifier!(Reset),
            Modifier::Underline => termion_modifier!(Underline),
        }
    }
}
<|endoftext|>