<commit_before>extern crate env_logger;
extern crate gluon;
extern crate tokio;

use gluon::vm::api::{Hole, OpaqueValue, ValueRef, IO};
use gluon::{new_vm, Compiler, Thread};

#[macro_use]
mod support;

use support::*;

#[test]
fn read_file() {
    let _ = ::env_logger::try_init();

    let thread = new_vm();
    let text = r#"
        let prelude = import! std.prelude
        let array = import! std.array
        let { assert }  = import! std.test
        let io @ { ? } = import! std.io
        let { wrap } = io.applicative
        let { flat_map, (>>=) } = import! std.monad

        do file = io.open_file "Cargo.toml"
        do bytes = io.read_file file 9

        assert (array.len bytes == 9)
        assert (array.index bytes 0 #Byte== 91b) // [
        assert (array.index bytes 1 #Byte== 112b) // p

        wrap (array.index bytes 8)
        "#;
    let result = Compiler::new()
        .run_io(true)
        .run_expr::<IO<u8>>(&thread, "<top>", text);

    match result {
        Ok((IO::Value(value), _)) => assert_eq!(value, b']'),
        Ok((IO::Exception(err), _)) => assert!(false, "{}", err),
        Err(err) => assert!(false, "{}", err),
    }
}

test_expr!{ no_io_eval,
r#"
let { error } = import! std.prim
let io = import! std.io.prim
let x = io.flat_map (\x -> error "NOOOOOOOO") (io.println "1")
in { x }
"#
}

test_expr!{ io_print,
r#"
let io = import! std.io
io.print "123"
"#
}

#[test]
fn run_expr_int() {
    let _ = ::env_logger::try_init();

    let text = r#"
        let io = import! std.io
        let { flat_map } = io.monad
        do result = io.run_expr "123"
        io.applicative.wrap result.value
    "#;
    let mut vm = make_vm();
    let (result, _) = Compiler::new()
        .run_io(true)
        .run_expr::<IO<String>>(&mut vm, "<top>", text)
        .unwrap();
    match result {
        IO::Value(result) => {
            let expected = "123";
            assert_eq!(result, expected);
        }
        IO::Exception(err) => panic!("{}", err),
    }
}

test_expr!{ io run_expr_io,
r#"
let io = import! std.io.prim
io.flat_map (\x -> io.wrap 100)
            (io.run_expr "
                let io = import! \"std/io.glu\"
                io.print \"123\"
            ")
"#,
100i32
}

#[test]
fn dont_execute_io_in_run_expr_async() {
    let _ = ::env_logger::try_init();
    let vm = make_vm();
    let expr = r#"
let prelude  = import! std.prelude
let io = import! std.io
let { wrap } = io.applicative
wrap 123
"#;
    let value = Compiler::new()
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "example", expr)
        .unwrap_or_else(|err| panic!("{}", err));
    assert!(
        value.0.get_ref() != ValueRef::Int(123),
        "Unexpected {:?}",
        value.0
    );
}

#[test]
fn spawn_on_twice() {
    let _ = ::env_logger::try_init();

    let text = r#"
        let { applicative = { wrap }, monad = { flat_map } } = import! std.io
        let thread = import! std.thread

        do child = thread.new_thread ()
        do action = thread.spawn_on child (\_ -> wrap "abc")
        action
    "#;

    let mut runtime = self::tokio::runtime::Runtime::new().unwrap();
    let vm = make_vm();
    let (result, _) = runtime
        .block_on(
            Compiler::new()
                .run_io(true)
                .run_expr_async::<IO<String>>(&vm, "<top>", text),
        )
        .unwrap_or_else(|err| panic!("{}", err));
    match result {
        IO::Value(result) => {
            assert_eq!(result, "abc");
        }
        IO::Exception(err) => panic!("{}", err),
    }

    let (result, _) = runtime
        .block_on(
            Compiler::new()
                .run_io(true)
                .run_expr_async::<IO<String>>(&vm, "<top>", text),
        )
        .unwrap_or_else(|err| panic!("{}", err));
    match result {
        IO::Value(result) => {
            assert_eq!(result, "abc");
        }
        IO::Exception(err) => panic!("{}", err),
    }
}

#[test]
fn spawn_on_runexpr() {
    let _ = ::env_logger::try_init();

    let text = r#"
        let io@{ applicative = applicative@{ wrap }, monad = { flat_map }, ? } = import! std.io
        let thread = import! std.thread

        do child = thread.new_thread ()
        do action = thread.spawn_on child (\_ -> io.run_expr "123")
        do x = action
        do _ = io.println x.value
        wrap x.value
    "#;

    let mut runtime = self::tokio::runtime::Runtime::new().unwrap();
    let vm = make_vm();
    let (result, _) = runtime
        .block_on(
            Compiler::new()
                .run_io(true)
                .run_expr_async::<IO<String>>(&vm, "<top>", text),
        )
        .unwrap_or_else(|err| panic!("{}", err));
    match result {
        IO::Value(result) => {
            assert_eq!(result, "123");
        }
        IO::Exception(err) => panic!("{}", err),
    }
}

#[test]
fn spawn_on_do_action_twice() {
    let _ = ::env_logger::try_init();

    let text = r#"
        let { ? } = import! std.io
        let { ref, (<-), load } = import! std.reference
        let thread = import! std.thread
        let { wrap } = import! std.applicative
        let { join } = import! std.monad

        let counter = ref 0

        do child = thread.new_thread ()
        let action = thread.spawn_on child (\_ ->
                counter <- (load counter + 1)
                wrap ())
        do _ = join action
        do _ = join action
        wrap (load counter)
    "#;

    let mut runtime = self::tokio::runtime::Runtime::new().unwrap();
    let vm = make_vm();
    let (result, _) = runtime
        .block_on(
            Compiler::new()
                .run_io(true)
                .run_expr_async::<IO<i32>>(&vm, "<top>", text),
        )
        .unwrap_or_else(|err| panic!("{}", err));
    assert_eq!(result, IO::Value(2));
}

#[test]
fn spawn_on_force_action_twice() {
    let _ = ::env_logger::try_init();

    let text = r#"
        let { ? } = import! std.io
        let { ref, (<-), load } = import! std.reference
        let thread = import! std.thread
        let { wrap } = import! std.applicative

        let counter = ref 0

        do child = thread.new_thread ()
        do action = thread.spawn_on child (\_ ->
                counter <- (load counter + 1)
                wrap ())
        do _ = action
        do _ = action
        wrap (load counter)
    "#;

    let mut runtime = self::tokio::runtime::Runtime::new().unwrap();
    let vm = make_vm();
    let (result, _) = runtime
        .block_on(
            Compiler::new()
                .run_io(true)
                .run_expr_async::<IO<i32>>(&vm, "<top>", text),
        )
        .unwrap_or_else(|err| panic!("{}", err));
    assert_eq!(result, IO::Value(1));
}

#[test]
fn spawn_on_runexpr_in_catch() {
    let _ = ::env_logger::try_init();

    let text = r#"
        let prelude = import! std.prelude
        let io @ { ? } = import! std.io
        let { Applicative, (*>), wrap } = import! std.applicative
        let { flat_map, (>>=) } = import! std.monad
        let thread = import! std.thread

        let action =
            do eval_thread = thread.new_thread ()
            let f _ = io.run_expr "123"
            do a = thread.spawn_on eval_thread f
            do result = a
            wrap result.value
        (io.catch action wrap >>= io.println) *> wrap "123"
    "#;

    let mut runtime = self::tokio::runtime::Runtime::new().unwrap();
    let vm = make_vm();
    let (result, _) = runtime
        .block_on(
            Compiler::new()
                .run_io(true)
                .run_expr_async::<IO<String>>(&vm, "<top>", text),
        )
        .unwrap_or_else(|err| panic!("{}", err));
    match result {
        IO::Value(result) => {
            assert_eq!(result, "123");
        }
        IO::Exception(err) => panic!("{}", err),
    }

    let (result, _) = runtime
        .block_on(
            Compiler::new()
                .run_io(true)
                .run_expr_async::<IO<String>>(&vm, "<top>", text),
        )
        .unwrap_or_else(|err| panic!("{}", err));
    match result {
        IO::Value(result) => {
            assert_eq!(result, "123");
        }
        IO::Exception(err) => panic!("{}", err),
    }
}

#[test]
fn io_error_in_catch1() {
    let _ = ::env_logger::try_init();

    let expr = r#"
        let io = import! std.io
        io.catch (io.read_file_to_string "doesnotexist") (\_ -> io.applicative.wrap "error")
    "#;

    let vm = make_vm();

    let (result, _) = Compiler::new()
        .run_io(true)
        .implicit_prelude(false)
        .run_expr::<IO<String>>(&vm, "<top>", expr)
        .unwrap_or_else(|err| panic!("{}", err));
    let expected = IO::Value("error".to_string());

    assert_eq!(result, expected);
}

#[test]
fn io_error_in_catch2() {
    let _ = ::env_logger::try_init();

    let expr = r#"
        let { (*>) } = import! std.applicative
        let io @ { ? } = import! std.io
        io.catch (io.println "asd" *> io.read_file_to_string "doesnotexist") (\_ -> io.applicative.wrap "error")
    "#;

    let vm = make_vm();

    let (result, _) = Compiler::new()
        .run_io(true)
        .implicit_prelude(false)
        .run_expr::<IO<String>>(&vm, "<top>", expr)
        .unwrap_or_else(|err| panic!("{}", err));
    let expected = IO::Value("error".to_string());

    assert_eq!(result, expected);
}

<commit_msg>test: Add another io.catch test<commit_after>extern crate env_logger;
extern crate gluon;
extern crate tokio;

use gluon::vm::api::{Hole, OpaqueValue, ValueRef, IO};
use gluon::{new_vm, Compiler, Thread};

#[macro_use]
mod support;

use support::*;

#[test]
fn read_file() {
    let _ = ::env_logger::try_init();

    let thread = new_vm();
    let text = r#"
        let prelude = import! std.prelude
        let array = import! std.array
        let { assert }  = import! std.test
        let io @ { ? } = import! std.io
        let { wrap } = io.applicative
        let { flat_map, (>>=) } = import! std.monad

        do file = io.open_file "Cargo.toml"
        do bytes = io.read_file file 9

        assert (array.len bytes == 9)
        assert (array.index bytes 0 #Byte== 91b) // [
        assert (array.index bytes 1 #Byte== 112b) // p

        wrap (array.index bytes 8)
        "#;
    let result = Compiler::new()
        .run_io(true)
        .run_expr::<IO<u8>>(&thread, "<top>", text);

    match result {
        Ok((IO::Value(value), _)) => assert_eq!(value, b']'),
        Ok((IO::Exception(err), _)) => assert!(false, "{}", err),
        Err(err) => assert!(false, "{}", err),
    }
}

test_expr!{ no_io_eval,
r#"
let { error } = import! std.prim
let io = import! std.io.prim
let x = io.flat_map (\x -> error "NOOOOOOOO") (io.println "1")
in { x }
"#
}

test_expr!{ io_print,
r#"
let io = import! std.io
io.print "123"
"#
}

#[test]
fn run_expr_int() {
    let _ = ::env_logger::try_init();

    let text = r#"
        let io = import! std.io
        let { flat_map } = io.monad
        do result = io.run_expr "123"
        io.applicative.wrap result.value
    "#;
    let mut vm = make_vm();
    let (result, _) = Compiler::new()
        .run_io(true)
        .run_expr::<IO<String>>(&mut vm, "<top>", text)
        .unwrap();
    match result {
        IO::Value(result) => {
            let expected = "123";
            assert_eq!(result, expected);
        }
        IO::Exception(err) => panic!("{}", err),
    }
}

test_expr!{ io run_expr_io,
r#"
let io = import! std.io.prim
io.flat_map (\x -> io.wrap 100)
            (io.run_expr "
                let io = import! \"std/io.glu\"
                io.print \"123\"
            ")
"#,
100i32
}

#[test]
fn dont_execute_io_in_run_expr_async() {
    let _ = ::env_logger::try_init();
    let vm = make_vm();
    let expr = r#"
let prelude  = import! std.prelude
let io = import! std.io
let { wrap } = io.applicative
wrap 123
"#;
    let value = Compiler::new()
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "example", expr)
        .unwrap_or_else(|err| panic!("{}", err));
    assert!(
        value.0.get_ref() != ValueRef::Int(123),
        "Unexpected {:?}",
        value.0
    );
}

#[test]
fn spawn_on_twice() {
    let _ = ::env_logger::try_init();

    let text = r#"
        let { applicative = { wrap }, monad = { flat_map } } = import! std.io
        let thread = import! std.thread

        do child = thread.new_thread ()
        do action = thread.spawn_on child (\_ -> wrap "abc")
        action
    "#;

    let mut runtime = self::tokio::runtime::Runtime::new().unwrap();
    let vm = make_vm();
    let (result, _) = runtime
        .block_on(
            Compiler::new()
                .run_io(true)
                .run_expr_async::<IO<String>>(&vm, "<top>", text),
        )
        .unwrap_or_else(|err| panic!("{}", err));
    match result {
        IO::Value(result) => {
            assert_eq!(result, "abc");
        }
        IO::Exception(err) => panic!("{}", err),
    }

    let (result, _) = runtime
        .block_on(
            Compiler::new()
                .run_io(true)
                .run_expr_async::<IO<String>>(&vm, "<top>", text),
        )
        .unwrap_or_else(|err| panic!("{}", err));
    match result {
        IO::Value(result) => {
            assert_eq!(result, "abc");
        }
        IO::Exception(err) => panic!("{}", err),
    }
}

#[test]
fn spawn_on_runexpr() {
    let _ = ::env_logger::try_init();

    let text = r#"
        let io@{ applicative = applicative@{ wrap }, monad = { flat_map }, ? } = import! std.io
        let thread = import! std.thread

        do child = thread.new_thread ()
        do action = thread.spawn_on child (\_ -> io.run_expr "123")
        do x = action
        do _ = io.println x.value
        wrap x.value
    "#;

    let mut runtime = self::tokio::runtime::Runtime::new().unwrap();
    let vm = make_vm();
    let (result, _) = runtime
        .block_on(
            Compiler::new()
                .run_io(true)
                .run_expr_async::<IO<String>>(&vm, "<top>", text),
        )
        .unwrap_or_else(|err| panic!("{}", err));
    match result {
        IO::Value(result) => {
            assert_eq!(result, "123");
        }
        IO::Exception(err) => panic!("{}", err),
    }
}

#[test]
fn spawn_on_do_action_twice() {
    let _ = ::env_logger::try_init();

    let text = r#"
        let { ? } = import! std.io
        let { ref, (<-), load } = import! std.reference
        let thread = import! std.thread
        let { wrap } = import! std.applicative
        let { join } = import! std.monad

        let counter = ref 0

        do child = thread.new_thread ()
        let action = thread.spawn_on child (\_ ->
                counter <- (load counter + 1)
                wrap ())
        do _ = join action
        do _ = join action
        wrap (load counter)
    "#;

    let mut runtime = self::tokio::runtime::Runtime::new().unwrap();
    let vm = make_vm();
    let (result, _) = runtime
        .block_on(
            Compiler::new()
                .run_io(true)
                .run_expr_async::<IO<i32>>(&vm, "<top>", text),
        )
        .unwrap_or_else(|err| panic!("{}", err));
    assert_eq!(result, IO::Value(2));
}

#[test]
fn spawn_on_force_action_twice() {
    let _ = ::env_logger::try_init();

    let text = r#"
        let { ? } = import! std.io
        let { ref, (<-), load } = import! std.reference
        let thread = import! std.thread
        let { wrap } = import! std.applicative

        let counter = ref 0

        do child = thread.new_thread ()
        do action = thread.spawn_on child (\_ ->
                counter <- (load counter + 1)
                wrap ())
        do _ = action
        do _ = action
        wrap (load counter)
    "#;

    let mut runtime = self::tokio::runtime::Runtime::new().unwrap();
    let vm = make_vm();
    let (result, _) = runtime
        .block_on(
            Compiler::new()
                .run_io(true)
                .run_expr_async::<IO<i32>>(&vm, "<top>", text),
        )
        .unwrap_or_else(|err| panic!("{}", err));
    assert_eq!(result, IO::Value(1));
}

#[test]
fn spawn_on_runexpr_in_catch() {
    let _ = ::env_logger::try_init();

    let text = r#"
        let prelude = import! std.prelude
        let io @ { ? } = import! std.io
        let { Applicative, (*>), wrap } = import! std.applicative
        let { flat_map, (>>=) } = import! std.monad
        let thread = import! std.thread

        let action =
            do eval_thread = thread.new_thread ()
            let f _ = io.run_expr "123"
            do a = thread.spawn_on eval_thread f
            do result = a
            wrap result.value
        (io.catch action wrap >>= io.println) *> wrap "123"
    "#;

    let mut runtime = self::tokio::runtime::Runtime::new().unwrap();
    let vm = make_vm();
    let (result, _) = runtime
        .block_on(
            Compiler::new()
                .run_io(true)
                .run_expr_async::<IO<String>>(&vm, "<top>", text),
        )
        .unwrap_or_else(|err| panic!("{}", err));
    match result {
        IO::Value(result) => {
            assert_eq!(result, "123");
        }
        IO::Exception(err) => panic!("{}", err),
    }

    let (result, _) = runtime
        .block_on(
            Compiler::new()
                .run_io(true)
                .run_expr_async::<IO<String>>(&vm, "<top>", text),
        )
        .unwrap_or_else(|err| panic!("{}", err));
    match result {
        IO::Value(result) => {
            assert_eq!(result, "123");
        }
        IO::Exception(err) => panic!("{}", err),
    }
}

#[test]
fn io_error_in_catch1() {
    let _ = ::env_logger::try_init();

    let expr = r#"
        let io = import! std.io
        io.catch (io.read_file_to_string "doesnotexist") (\_ -> io.applicative.wrap "error")
    "#;

    let vm = make_vm();

    let (result, _) = Compiler::new()
        .run_io(true)
        .implicit_prelude(false)
        .run_expr::<IO<String>>(&vm, "<top>", expr)
        .unwrap_or_else(|err| panic!("{}", err));
    let expected = IO::Value("error".to_string());

    assert_eq!(result, expected);
}

#[test]
fn io_error_in_catch2() {
    let _ = ::env_logger::try_init();

    let expr = r#"
        let { (*>) } = import! std.applicative
        let io @ { ? } = import! std.io
        io.catch (io.println "asd" *> io.read_file_to_string "doesnotexist") (\_ -> io.applicative.wrap "error")
    "#;

    let vm = make_vm();

    let (result, _) = Compiler::new()
        .run_io(true)
        .implicit_prelude(false)
        .run_expr::<IO<String>>(&vm, "<top>", expr)
        .unwrap_or_else(|err| panic!("{}", err));
    let expected = IO::Value("error".to_string());

    assert_eq!(result, expected);
}

#[test]
fn io_error_in_catch3() {
    let _ = ::env_logger::try_init();

    let expr = r#"
        let io @ { ? } = import! std.io
        let { flat_map } = import! std.monad
        do _ = io.catch (io.read_file_to_string "doesnotexist") (\_ -> io.applicative.wrap "error")
        io.catch (io.read_file_to_string "doesnotexist") (\_ -> io.applicative.wrap "error2")
    "#;

    let vm = make_vm();

    let (result, _) = Compiler::new()
        .run_io(true)
        .implicit_prelude(false)
        .run_expr::<IO<String>>(&vm, "<top>", expr)
        .unwrap_or_else(|err| panic!("{}", err));
    let expected = IO::Value("error2".to_string());

    assert_eq!(result, expected);
}

<|endoftext|>


<commit_before>use super::SystemModule;
use crate::sys::{config, taskserver::Control};
use actix_web::{http::header::ContentType, HttpResponse, Responder};
use anyhow::{anyhow, Result};
use log::info;
use serde::{Deserialize, Serialize};
use tokio::select;

#[derive(Clone, Serialize, Deserialize)]
struct HttpConfig {
    enabled: bool,
    inaddr_any: bool,
}

#[actix_web::get("/")]
async fn hello() -> impl Responder {
    HttpResponse::Ok()
        .content_type(ContentType::plaintext())
        .body("Hello world!\n")
}

pub struct HttpServer {
    config: HttpConfig,
}

impl HttpServer {
    pub fn new() -> Result<Self> {
        info!("[health] initialize");

        let jsobj =
            config::get_object(&["http"]).map_or(Err(anyhow!("Config not found: http")), Ok)?;
        let config: HttpConfig = serde_json::from_value(jsobj)?;

        Ok(Self { config })
    }
}

async fn http_main_task(mut ctrl: Control) -> Result<()> {
    loop {
        let config = {
            let http = ctrl.sysmods().http.lock().await;
            http.config.clone()
        };
        let addr = if config.inaddr_any {
            "0.0.0.0"
        } else {
            "127.0.0.1"
        };
        let server = actix_web::HttpServer::new(|| actix_web::App::new().service(hello))
            .disable_signals()
            .bind(("0.0.0.0", 8080))?
            .run();

        select! {
            _ = server => {
                info!("[http] server exit (reboot)");
            },
            _ = ctrl.cancel_rx().changed() => {
                info!("[http] task cancel");
                break;
            },
        }
    }

    Ok(())
}

impl SystemModule for HttpServer {
    fn on_start(&self, ctrl: &Control) {
        info!("[http] on_start");
        if self.config.enabled {
            ctrl.spawn_oneshot_task("http", http_main_task);
        }
    }
}
<commit_msg>サーバ実行とキャンセルで select するとロックする問題を修正<commit_after>use super::SystemModule;
use crate::sys::{config, taskserver::Control};
use actix_web::{dev::ServerHandle, http::header::ContentType, HttpResponse, Responder};
use anyhow::{anyhow, Result};
use log::info;
use serde::{Deserialize, Serialize};

#[derive(Clone, Serialize, Deserialize)]
struct HttpConfig {
    enabled: bool,
    inaddr_any: bool,
}

pub struct HttpServer {
    config: HttpConfig,
    handle: Option<ServerHandle>,
}

impl HttpServer {
    pub fn new() -> Result<Self> {
        info!("[health] initialize");

        let jsobj =
            config::get_object(&["http"]).map_or(Err(anyhow!("Config not found: http")), Ok)?;
        let config: HttpConfig = serde_json::from_value(jsobj)?;

        Ok(Self {
            config,
            handle: None,
        })
    }
}

async fn http_main_task(ctrl: Control) -> Result<()> {
    let config = {
        let http = ctrl.sysmods().http.lock().await;
        http.config.clone()
    };
    let addr = if config.inaddr_any {
        "0.0.0.0"
    } else {
        "127.0.0.1"
    };

    // clone してクロージャ内に move する
    let data = AppData::new(ctrl.clone());
    // クロージャはワーカースレッドごとに複数回呼ばれる
    let server = actix_web::HttpServer::new(move || {
        actix_web::App::new().app_data(data.clone()).service(hello)
    })
    .disable_signals()
    .bind(("0.0.0.0", 8080))?
    .run();

    // self.handle にサーバ停止用のハンドルを保存する
    let mut http = ctrl.sysmods().http.lock().await;
    http.handle = Some(server.handle());
    drop(http);
    // シャットダウンが来たらハンドルでサーバを停止するタスクを生成
    ctrl.spawn_oneshot_task("http-exit", server_exit_task);

    server.await?;
    info!("[http] server exit");

    Ok(())
}

async fn server_exit_task(mut ctrl: Control) -> Result<()> {
    let mut http = ctrl.sysmods().http.lock().await;
    let handle = http.handle.take().unwrap();
    drop(http);

    let result = ctrl.cancel_rx().changed().await;

    handle.stop(true).await;

    Ok(result?)
}

impl SystemModule for HttpServer {
    fn on_start(&self, ctrl: &Control) {
        info!("[http] on_start");
        if self.config.enabled {
            ctrl.spawn_oneshot_task("http", http_main_task);
        }
    }
}

type AppData = actix_web::web::Data<Control>;

#[actix_web::get("/")]
async fn hello(ctrl: AppData) -> impl Responder {
    HttpResponse::Ok()
        .content_type(ContentType::plaintext())
        .body("Hello world!\n")
}
<|endoftext|>


<commit_before>use x86::msr::*;

bitflags! {
    pub flags LocalApicIcr: u64 {
        const ICR_VECTOR = 0xFF,

        const ICR_FIXED = 0b000 << 8,
        const ICR_SMI = 0b010 << 8,
        const ICR_NMI = 0b100 << 8,
        const ICR_INIT = 0b101 << 8,
        const ICR_START = 0b110 << 8,

        const ICR_PHYSICAL = 0 << 11,
        const ICR_LOGICAL = 1 << 11,

        const ICR_DEASSERT = 0 << 14,
        const ICR_ASSERT = 1 << 14,

        const ICR_EDGE = 0 << 15,
        const ICR_LEVEL = 1 << 15,

        const ICR_DESTINATION = 0b1111 << 56,
    }
}

/// Local APIC
#[repr(packed)]
pub struct LocalApic;

impl LocalApic {
    pub fn new() -> Self {
        unsafe { wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 10) }
        LocalApic
    }

    pub fn id(&self) -> u32 {
        unsafe { rdmsr(IA32_X2APIC_APICID) as u32 }
    }

    pub fn version(&self) -> u32 {
        unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 }
    }

    pub fn icr(&self) -> u64 {
        unsafe { rdmsr(IA32_X2APIC_ICR) }
    }

    pub fn set_icr(&mut self, value: u64) {
        unsafe { wrmsr(IA32_X2APIC_ICR, value) }
    }
}
<commit_msg>Make sure to enable xAPIC mode as well as x2APIC mode<commit_after>use x86::msr::*;

bitflags! {
    pub flags LocalApicIcr: u64 {
        const ICR_VECTOR = 0xFF,

        const ICR_FIXED = 0b000 << 8,
        const ICR_SMI = 0b010 << 8,
        const ICR_NMI = 0b100 << 8,
        const ICR_INIT = 0b101 << 8,
        const ICR_START = 0b110 << 8,

        const ICR_PHYSICAL = 0 << 11,
        const ICR_LOGICAL = 1 << 11,

        const ICR_DEASSERT = 0 << 14,
        const ICR_ASSERT = 1 << 14,

        const ICR_EDGE = 0 << 15,
        const ICR_LEVEL = 1 << 15,

        const ICR_DESTINATION = 0b1111 << 56,
    }
}

/// Local APIC
#[repr(packed)]
pub struct LocalApic;

impl LocalApic {
    pub fn new() -> Self {
        unsafe { wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 11 | 1 << 10) }
        LocalApic
    }

    pub fn id(&self) -> u32 {
        unsafe { rdmsr(IA32_X2APIC_APICID) as u32 }
    }

    pub fn version(&self) -> u32 {
        unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 }
    }

    pub fn icr(&self) -> u64 {
        unsafe { rdmsr(IA32_X2APIC_ICR) }
    }

    pub fn set_icr(&mut self, value: u64) {
        unsafe { wrmsr(IA32_X2APIC_ICR, value) }
    }
}
<|endoftext|>


<commit_before>    //   Copyright 2014 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#![crate_name = "snowmew-render-gfx"]
#![crate_type = "lib"]

#![feature(phase)]
#![allow(dead_code)]

//extern crate debug;

extern crate sync;
extern crate time;
extern crate libc;

extern crate opencl;
extern crate cow;
extern crate glfw;

#[phase(plugin)]
extern crate gfx_macros;
extern crate gfx;
extern crate device;
extern crate render;
extern crate genmesh;

extern crate "snowmew-core" as snowmew;
extern crate "snowmew-position" as position;
extern crate "snowmew-graphics" as graphics;
extern crate "snowmew-render-data" as render_data;

use std::collections::hashmap::HashMap;

use opencl::hl;
use sync::Arc;

use position::Positions;
use graphics::Graphics;
use snowmew::common::ObjectKey;
use snowmew::io::Window;

use graphics::geometry::{Geo, GeoTex, GeoNorm, GeoTexNorm, GeoTexNormTan};
use graphics::geometry::{VertexGeoTex, VertexGeoTexNorm};
use graphics::Drawable;

use cow::join::{join_set_to_map, join_maps};
use render_data::RenderData;

use gfx::{Device, DeviceHelper};

static VERTEX_SRC: gfx::ShaderSource = shaders! {
GLSL_150: b"
    #version 150 core
    uniform mat4 proj_mat;
    uniform mat4 view_mat;
    uniform mat4 model_mat;

    in vec3 position;
    in vec2 texture;

    out vec2 o_texture;

    void main() {
        gl_Position = proj_mat * view_mat * model_mat * vec4(position, 1.0);
        o_texture = texture;
    }
"
};

static FRAGMENT_SRC: gfx::ShaderSource = shaders! {
GLSL_150: b"
    #version 150 core
    uniform vec4 ka_color;
    uniform int ka_use_texture;
    uniform sampler2D ka_texture;

    in vec2 o_texture;

    out vec4 o_Color;

    void main() {
        if (1 == ka_use_texture) {
            o_Color = texture(ka_texture, o_texture);
        } else {
            o_Color = ka_color;
        }
    }
"
};

#[shader_param(MyProgram)]
struct Params {
    proj_mat: [[f32, ..4], ..4],
    view_mat: [[f32, ..4], ..4],
    model_mat: [[f32, ..4], ..4],
    ka_color: [f32, ..4],
    ka_use_texture: i32,
    ka_texture: gfx::shade::TextureParam,
}

struct Mesh {
    mesh: render::mesh::Mesh,
    index: device::BufferHandle<u32>
}

pub struct RenderManager {
    data: Params,
    graphics: gfx::Graphics<device::gl_device::GlDevice,
                            device::gl_device::GlCommandBuffer>,
    frame: render::target::Frame,
    state: render::state::DrawState,
    prog: device::Handle<u32,device::shade::ProgramInfo>,
    meshes: HashMap<ObjectKey, Mesh>,
    textures: HashMap<ObjectKey, device::TextureHandle>,
    sampler: device::SamplerHandle,
    window: Window
}

impl RenderManager {

    fn _new(mut device: gfx::GlDevice,
            window: Window,
            size: (i32, i32),
            _: Option<Arc<hl::Device>>) -> RenderManager {

        let (width, height) = size;
        let frame = gfx::Frame::new(width as u16, height as u16);
        let state = gfx::DrawState::new().depth(gfx::state::LessEqual, true);

        let sampler = device.create_sampler(
            gfx::tex::SamplerInfo::new(
                    gfx::tex::Bilinear, gfx::tex::Tile
            )
        );

        let (prog, data) = {
            let tinfo = gfx::tex::TextureInfo {
                width: 1,
                height: 1,
                depth: 1,
                levels: 1,
                kind: gfx::tex::Texture2D,
                format: gfx::tex::RGBA8,
            };

            let img_info = tinfo.to_image_info();
            let dummy_texture = device.create_texture(tinfo)
                                      .ok().expect("Failed to create texture");
            device.update_texture(&dummy_texture,
                                  &img_info,
                                  &vec![0u8, 0, 0, 0].as_slice());

            let data = Params {
                proj_mat: [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0],
                ],
                view_mat: [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0],
                ],
                model_mat: [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0],
                ],
                ka_use_texture: 0,
                ka_color: [1., 1., 1., 1.],
                ka_texture: (dummy_texture, Some(sampler))
            };
            (device.link_program(VERTEX_SRC.clone(), FRAGMENT_SRC.clone())
                  .ok().expect("Failed to link program"),
             data)
        };

        RenderManager {
            data: data,
            graphics: gfx::Graphics::new(device),
            frame: frame,
            state: state,
            prog: prog,
            meshes: HashMap::new(),
            textures: HashMap::new(),
            sampler: sampler,
            window: window
        }
    }

    fn load_meshes<RD: RenderData>(&mut self, db: &RD) {
        for (oid, vb) in db.vertex_buffer_iter() {
            if self.meshes.find(oid).is_none() {
                let mesh = match vb.vertex {
                    Geo(ref d) => {
                        println!("Geo");
                        let data: Vec<VertexGeoTex> = d.iter()
                            .map(|v| {
                                VertexGeoTex {
                                    position: v.position,
                                    texture: [0., 0.]
                                }
                            })
                            .collect();
                        self.graphics.device.create_mesh(data)
                    },
                    GeoTex(ref d) => {
                        println!("GeoTex");
                        self.graphics.device.create_mesh(d.clone())
                    },
                    GeoNorm(ref d) => {
                        let data: Vec<VertexGeoTexNorm> = d.iter()
                            .map(|v| {
                                VertexGeoTexNorm {
                                    position: v.position,
                                    texture: [0., 0.],
                                    normal: v.normal
                                }
                            })
                            .collect();
                        self.graphics.device.create_mesh(data)
                    },
                    GeoTexNorm(ref d) => {
                        println!("GeoTexNorm");
                        self.graphics.device.create_mesh(d.clone())
                    },
                    GeoTexNormTan(ref d) => {
                        println!("GeoTexNormTan");
                        self.graphics.device.create_mesh(d.clone())
                    }
                };

                let vb: Vec<u32> = vb.index.iter().map(|&x| x as u32).collect();

                let index = self.graphics.device.create_buffer_static(&vb);

                self.meshes.insert(*oid, Mesh {
                    index: index,
                    mesh: mesh
                });
            }
        }
    }

    fn load_textures<RD: RenderData>(&mut self, db: &RD) {
        for (oid, text) in db.texture_iter() {
            if self.textures.find(oid).is_none() {
                let tinfo = gfx::tex::TextureInfo {
                    width: text.width() as u16,
                    height: text.height() as u16,
                    depth: 1 as u16,
                    levels: 1,
                    kind: gfx::tex::Texture2D,
                    format: match text.depth() {
                        4 => gfx::tex::Unsigned(gfx::tex::RGBA, 8, gfx::attrib::IntNormalized),
                        3 => gfx::tex::Unsigned(gfx::tex::RGB, 8, gfx::attrib::IntNormalized),
                        _ => fail!("Unsupported color depth")
                    }
                };

                let img_info = tinfo.to_image_info();
                let texture = self.graphics.device.create_texture(tinfo)
                                         .ok().expect("Failed to create texture");
                self.graphics.device.update_texture(&texture, &img_info, &text.data().to_vec());
                self.textures.insert(*oid, texture);
            }
        }
    }

    fn create_geometry_batches<RD: RenderData>(&mut self, db: &RD, scene: ObjectKey) -> HashMap<u32, MyProgram> {
        let mut batches: HashMap<u32, MyProgram> = HashMap::new();

        for (_, draw) in join_set_to_map(db.scene_iter(scene), db.drawable_iter()) {
            if batches.contains_key(&draw.geometry) {
                continue;
            }

            let geo = db.geometry(draw.geometry).expect("failed to find geometry");
            let vb = self.meshes.find(&geo.vb).expect("Could not get vertex buffer");

            let batch: MyProgram = self.graphics.make_batch(
                &self.prog,
                &vb.mesh,
                gfx::IndexSlice32(gfx::TriangleList,
                                  vb.index,
                                  geo.offset as u32,
                                  geo.count as u32),
                &self.state
            ).unwrap();

            batches.insert(draw.geometry, batch);
        }

        return batches;
    }

    fn draw<RD: RenderData>(&mut self, db: &RD, scene: ObjectKey, camera: ObjectKey) {
        let cdata = gfx::ClearData {
            color: [0.3, 0.3, 0.3, 1.0],
            depth: 1.0,
            stencil: 0,
        };
        let start = time::precise_time_s();
        self.graphics.clear(cdata, gfx::Color | gfx::Depth, &self.frame);

        let camera_trans = db.position(camera);
        let camera = snowmew::camera::Camera::new(camera_trans);

        let proj = camera.projection_matrix(16. / 9.);
        self.data.proj_mat =
            [[proj.x.x, proj.x.y, proj.x.z, proj.x.w],
             [proj.y.x, proj.y.y, proj.y.z, proj.y.w],
             [proj.z.x, proj.z.y, proj.z.z, proj.z.w],
             [proj.w.x, proj.w.y, proj.w.z, proj.w.w]];

        let view = camera.view_matrix();
        self.data.view_mat =
            [[view.x.x, view.x.y, view.x.z, view.x.w],
             [view.y.x, view.y.y, view.y.z, view.y.w],
             [view.z.x, view.z.y, view.z.z, view.z.w],
             [view.w.x, view.w.y, view.w.z, view.w.w]];

        let batches = self.create_geometry_batches(db, scene);

        for (id, (draw, _)) in join_set_to_map(db.scene_iter(scene),
                                               join_maps(db.drawable_iter(),
                                                         db.location_iter())) {

            let mat = db.material(draw.material).expect("Could not find material");
            let model = db.position(*id);

            self.data.model_mat =
                [[model.x.x, model.x.y, model.x.z, model.x.w],
                 [model.y.x, model.y.y, model.y.z, model.y.w],
                 [model.z.x, model.z.y, model.z.z, model.z.w],
                 [model.w.x, model.w.y, model.w.z, model.w.w]];

            self.data.ka_use_texture = match mat.map_ka() {
                Some(tid) => {
                    let &texture = self.textures.find(&tid).expect("Texture not loaded");
                    self.data.ka_texture = (texture, Some(self.sampler));
                    1
                }
                None => {
                    let [r, g, b] = mat.ka();
                    self.data.ka_color = [r, g, b, 1.];
                    0
                }
            };

            self.graphics.draw(
                batches.find(&draw.geometry).expect("Missing draw"),
                &self.data,
                &self.frame
            );
        }

        self.graphics.end_frame();
        self.window.swap_buffers();
        let end = time::precise_time_s();
        println!("{0:4.3}ms", (end - start) * 1000.);
    }
}

impl<RD: RenderData+Send> snowmew::Render<RD> for RenderManager {
    fn update(&mut self, db: RD, scene: ObjectKey, camera: ObjectKey) {
        self.load_meshes(&db);
        self.load_textures(&db);
        self.draw(&db, scene, camera);
    }
}

impl<RD: RenderData+Send> snowmew::RenderFactory<RD, RenderManager> for RenderFactory {
    fn init(self: Box<RenderFactory>,
            io: &snowmew::IOManager,
            window: Window,
            size: (i32, i32),
            cl: Option<Arc<hl::Device>>) -> RenderManager {

        window.make_context_current();

        let mut device = gfx::GlDevice::new(|s| io.get_proc_address(s));
        RenderManager::_new(device, window, size, cl)
    }
}

pub struct RenderFactory;

impl RenderFactory {
    pub fn new() -> RenderFactory { RenderFactory }
}<commit_msg>update render-gfx<commit_after>    //   Copyright 2014 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#![crate_name = "snowmew-render-gfx"]
#![crate_type = "lib"]

#![feature(phase)]
#![allow(dead_code)]

//extern crate debug;

extern crate sync;
extern crate time;
extern crate libc;

extern crate opencl;
extern crate cow;
extern crate glfw;

#[phase(plugin)]
extern crate gfx_macros;
extern crate gfx;
extern crate device;
extern crate render;
extern crate genmesh;

extern crate "snowmew-core" as snowmew;
extern crate "snowmew-position" as position;
extern crate "snowmew-graphics" as graphics;
extern crate "snowmew-render-data" as render_data;

use std::collections::hashmap::HashMap;

use opencl::hl;
use sync::Arc;

use position::Positions;
use graphics::Graphics;
use snowmew::common::ObjectKey;
use snowmew::io::Window;

use graphics::geometry::{Geo, GeoTex, GeoNorm, GeoTexNorm, GeoTexNormTan};
use graphics::geometry::{VertexGeoTex, VertexGeoTexNorm};
use graphics::Drawable;

use cow::join::{join_set_to_map, join_maps};
use render_data::RenderData;

use gfx::{Device, DeviceHelper};

static VERTEX_SRC: gfx::ShaderSource = shaders! {
GLSL_150: b"
    #version 150 core
    uniform mat4 proj_mat;
    uniform mat4 view_mat;
    uniform mat4 model_mat;

    in vec3 position;
    in vec2 texture;

    out vec2 o_texture;

    void main() {
        gl_Position = proj_mat * view_mat * model_mat * vec4(position, 1.0);
        o_texture = texture;
    }
"
};

static FRAGMENT_SRC: gfx::ShaderSource = shaders! {
GLSL_150: b"
    #version 150 core
    uniform vec4 ka_color;
    uniform int ka_use_texture;
    uniform sampler2D ka_texture;

    in vec2 o_texture;

    out vec4 o_Color;

    void main() {
        if (1 == ka_use_texture) {
            o_Color = texture(ka_texture, o_texture);
        } else {
            o_Color = ka_color;
        }
    }
"
};

#[shader_param(MyProgram)]
struct Params {
    proj_mat: [[f32, ..4], ..4],
    view_mat: [[f32, ..4], ..4],
    model_mat: [[f32, ..4], ..4],
    ka_color: [f32, ..4],
    ka_use_texture: i32,
    ka_texture: gfx::shade::TextureParam,
}

struct Mesh {
    mesh: render::mesh::Mesh,
    index: device::BufferHandle<u32>
}

pub struct RenderManager {
    data: Params,
    graphics: gfx::Graphics<device::gl_device::GlDevice,
                            device::gl_device::GlCommandBuffer>,
    frame: render::target::Frame,
    state: render::state::DrawState,
    prog: device::Handle<u32,device::shade::ProgramInfo>,
    meshes: HashMap<ObjectKey, Mesh>,
    textures: HashMap<ObjectKey, device::TextureHandle>,
    sampler: device::SamplerHandle,
    window: Window
}

impl RenderManager {

    fn _new(mut device: gfx::GlDevice,
            window: Window,
            size: (i32, i32),
            _: Option<Arc<hl::Device>>) -> RenderManager {

        let (width, height) = size;
        let frame = gfx::Frame::new(width as u16, height as u16);
        let state = gfx::DrawState::new().depth(gfx::state::LessEqual, true);

        let sampler = device.create_sampler(
            gfx::tex::SamplerInfo::new(
                    gfx::tex::Bilinear, gfx::tex::Tile
            )
        );

        let (prog, data) = {
            let tinfo = gfx::tex::TextureInfo {
                width: 1,
                height: 1,
                depth: 1,
                levels: 1,
                kind: gfx::tex::Texture2D,
                format: gfx::tex::RGBA8,
            };

            let img_info = tinfo.to_image_info();
            let dummy_texture = device.create_texture(tinfo)
                                      .ok().expect("Failed to create texture");
            device.update_texture(&dummy_texture,
                                  &img_info,
                                  vec![0u8, 0, 0, 0].as_slice());

            let data = Params {
                proj_mat: [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0],
                ],
                view_mat: [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0],
                ],
                model_mat: [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0],
                ],
                ka_use_texture: 0,
                ka_color: [1., 1., 1., 1.],
                ka_texture: (dummy_texture, Some(sampler))
            };
            (device.link_program(VERTEX_SRC.clone(), FRAGMENT_SRC.clone())
                  .ok().expect("Failed to link program"),
             data)
        };

        RenderManager {
            data: data,
            graphics: gfx::Graphics::new(device),
            frame: frame,
            state: state,
            prog: prog,
            meshes: HashMap::new(),
            textures: HashMap::new(),
            sampler: sampler,
            window: window
        }
    }

    fn load_meshes<RD: RenderData>(&mut self, db: &RD) {
        for (oid, vb) in db.vertex_buffer_iter() {
            if self.meshes.find(oid).is_none() {
                let mesh = match vb.vertex {
                    Geo(ref d) => {
                        println!("Geo");
                        let data: Vec<VertexGeoTex> = d.iter()
                            .map(|v| {
                                VertexGeoTex {
                                    position: v.position,
                                    texture: [0., 0.]
                                }
                            })
                            .collect();
                        self.graphics.device.create_mesh(data.as_slice())
                    },
                    GeoTex(ref d) => {
                        println!("GeoTex");
                        self.graphics.device.create_mesh(d.as_slice())
                    },
                    GeoNorm(ref d) => {
                        let data: Vec<VertexGeoTexNorm> = d.iter()
                            .map(|v| {
                                VertexGeoTexNorm {
                                    position: v.position,
                                    texture: [0., 0.],
                                    normal: v.normal
                                }
                            })
                            .collect();
                        self.graphics.device.create_mesh(data.as_slice())
                    },
                    GeoTexNorm(ref d) => {
                        println!("GeoTexNorm");
                        self.graphics.device.create_mesh(d.as_slice())
                    },
                    GeoTexNormTan(ref d) => {
                        println!("GeoTexNormTan");
                        self.graphics.device.create_mesh(d.as_slice())
                    }
                };

                let vb: Vec<u32> = vb.index.iter().map(|&x| x as u32).collect();

                let index = self.graphics.device.create_buffer_static(vb.as_slice());

                self.meshes.insert(*oid, Mesh {
                    index: index,
                    mesh: mesh
                });
            }
        }
    }

    fn load_textures<RD: RenderData>(&mut self, db: &RD) {
        for (oid, text) in db.texture_iter() {
            if self.textures.find(oid).is_none() {
                let tinfo = gfx::tex::TextureInfo {
                    width: text.width() as u16,
                    height: text.height() as u16,
                    depth: 1 as u16,
                    levels: 1,
                    kind: gfx::tex::Texture2D,
                    format: match text.depth() {
                        4 => gfx::tex::Unsigned(gfx::tex::RGBA, 8, gfx::attrib::IntNormalized),
                        3 => gfx::tex::Unsigned(gfx::tex::RGB, 8, gfx::attrib::IntNormalized),
                        _ => fail!("Unsupported color depth")
                    }
                };

                let img_info = tinfo.to_image_info();
                let texture = self.graphics.device.create_texture(tinfo)
                                         .ok().expect("Failed to create texture");
                self.graphics.device.update_texture(&texture, &img_info, text.data());
                self.textures.insert(*oid, texture);
            }
        }
    }

    fn create_geometry_batches<RD: RenderData>(&mut self, db: &RD, scene: ObjectKey) -> HashMap<u32, MyProgram> {
        let mut batches: HashMap<u32, MyProgram> = HashMap::new();

        for (_, draw) in join_set_to_map(db.scene_iter(scene), db.drawable_iter()) {
            if batches.contains_key(&draw.geometry) {
                continue;
            }

            let geo = db.geometry(draw.geometry).expect("failed to find geometry");
            let vb = self.meshes.find(&geo.vb).expect("Could not get vertex buffer");

            let batch: MyProgram = self.graphics.make_batch(
                &self.prog,
                &vb.mesh,
                gfx::IndexSlice32(gfx::TriangleList,
                                  vb.index,
                                  geo.offset as u32,
                                  geo.count as u32),
                &self.state
            ).unwrap();

            batches.insert(draw.geometry, batch);
        }

        return batches;
    }

    fn draw<RD: RenderData>(&mut self, db: &RD, scene: ObjectKey, camera: ObjectKey) {
        let cdata = gfx::ClearData {
            color: [0.3, 0.3, 0.3, 1.0],
            depth: 1.0,
            stencil: 0,
        };
        let start = time::precise_time_s();
        self.graphics.clear(cdata, gfx::Color | gfx::Depth, &self.frame);

        let camera_trans = db.position(camera);
        let camera = snowmew::camera::Camera::new(camera_trans);

        let proj = camera.projection_matrix(16. / 9.);
        self.data.proj_mat =
            [[proj.x.x, proj.x.y, proj.x.z, proj.x.w],
             [proj.y.x, proj.y.y, proj.y.z, proj.y.w],
             [proj.z.x, proj.z.y, proj.z.z, proj.z.w],
             [proj.w.x, proj.w.y, proj.w.z, proj.w.w]];

        let view = camera.view_matrix();
        self.data.view_mat =
            [[view.x.x, view.x.y, view.x.z, view.x.w],
             [view.y.x, view.y.y, view.y.z, view.y.w],
             [view.z.x, view.z.y, view.z.z, view.z.w],
             [view.w.x, view.w.y, view.w.z, view.w.w]];

        let batches = self.create_geometry_batches(db, scene);

        for (id, (draw, _)) in join_set_to_map(db.scene_iter(scene),
                                               join_maps(db.drawable_iter(),
                                                         db.location_iter())) {

            let mat = db.material(draw.material).expect("Could not find material");
            let model = db.position(*id);

            self.data.model_mat =
                [[model.x.x, model.x.y, model.x.z, model.x.w],
                 [model.y.x, model.y.y, model.y.z, model.y.w],
                 [model.z.x, model.z.y, model.z.z, model.z.w],
                 [model.w.x, model.w.y, model.w.z, model.w.w]];

            self.data.ka_use_texture = match mat.map_ka() {
                Some(tid) => {
                    let &texture = self.textures.find(&tid).expect("Texture not loaded");
                    self.data.ka_texture = (texture, Some(self.sampler));
                    1
                }
                None => {
                    let [r, g, b] = mat.ka();
                    self.data.ka_color = [r, g, b, 1.];
                    0
                }
            };

            self.graphics.draw(
                batches.find(&draw.geometry).expect("Missing draw"),
                &self.data,
                &self.frame
            );
        }

        self.graphics.end_frame();
        self.window.swap_buffers();
        let end = time::precise_time_s();
        println!("{0:4.3}ms", (end - start) * 1000.);
    }
}

impl<RD: RenderData+Send> snowmew::Render<RD> for RenderManager {
    fn update(&mut self, db: RD, scene: ObjectKey, camera: ObjectKey) {
        self.load_meshes(&db);
        self.load_textures(&db);
        self.draw(&db, scene, camera);
    }
}

impl<RD: RenderData+Send> snowmew::RenderFactory<RD, RenderManager> for RenderFactory {
    fn init(self: Box<RenderFactory>,
            io: &snowmew::IOManager,
            window: Window,
            size: (i32, i32),
            cl: Option<Arc<hl::Device>>) -> RenderManager {

        window.make_context_current();

        let mut device = gfx::GlDevice::new(|s| io.get_proc_address(s));
        RenderManager::_new(device, window, size, cl)
    }
}

pub struct RenderFactory;

impl RenderFactory {
    pub fn new() -> RenderFactory { RenderFactory }
}<|endoftext|>


<commit_before>extern crate rand;

use super::utils::types::{ Sha256Digest, Address, U256 };
use super::utils::bls::{ PublicKey, Keypair };
use super::rlp::{ RlpStream, Encodable };

use self::rand::thread_rng;

pub struct ValidatorRecord {
    pub pubkey: PublicKey,
    pub withdrawal_shard: u16,
    pub withdrawal_address: Address,
    pub randao_commitment: Sha256Digest,
    pub balance: U256,
    pub switch_dynasty: u64
}

impl ValidatorRecord {
    pub fn new(pubkey: PublicKey,
               withdrawal_shard: u16,
               withdrawal_address: Address,
               randao_commitment: Sha256Digest,
               balance: U256,
               switch_dynasty: u64)
        -> Self
    {
        Self {
            pubkey,
            withdrawal_shard,
            withdrawal_address,
            randao_commitment,
            balance,
            switch_dynasty
        }
    }

    pub fn zero_with_thread_rand_pub_key() -> Self {
        let mut rng = thread_rng();
        let keypair = Keypair::generate(&mut rng);
        Self {
            pubkey: keypair.public,
            withdrawal_shard: 0,
            withdrawal_address: Address::zero(),
            randao_commitment: Sha256Digest::zero(),
            balance: U256::zero(),
            switch_dynasty: 0
        }
    }
}

/*
 * RLP Encoding
 */
impl Encodable for ValidatorRecord {
    fn rlp_append(&self, s: &mut RlpStream) {
        // s.append(&self.pubkey);      // TODO: serialize this
        s.append(&self.withdrawal_shard);
        s.append(&self.withdrawal_address);
        s.append(&self.randao_commitment);
        s.append(&self.balance);
        s.append(&self.switch_dynasty);
    }
}

#[cfg(test)]
mod tests {
    use super::super::rlp;
    extern crate rand;

    use super::*;
    use super::super::
        utils::test_helpers::get_dangerous_test_keypair;

    #[test]
    fn test_new() {
        let keypair = get_dangerous_test_keypair();;
        let withdrawal_shard = 1;
        let withdrawal_address = Address::random();
        let randao_commitment = Sha256Digest::random();
        let balance = U256::from(100);
        let switch_dynasty = 10;

        let v = ValidatorRecord::new(
            keypair.public,
            withdrawal_shard,
            withdrawal_address,
            randao_commitment,
            balance,
            switch_dynasty);
        // TODO: figure out how to compare keys
        // assert_eq!(v.pubkey, keypair.public);
        assert_eq!(v.withdrawal_shard, withdrawal_shard);
        assert_eq!(v.withdrawal_address, withdrawal_address);
        assert_eq!(v.randao_commitment, randao_commitment);
        assert_eq!(v.balance, balance);
        assert_eq!(v.switch_dynasty, switch_dynasty);
    }

    #[test]
    fn test_rlp_serialization() {
        let keypair = get_dangerous_test_keypair();
        let v = ValidatorRecord {
            pubkey: keypair.public,
            withdrawal_shard: 100,
            withdrawal_address: Address::zero(),
            randao_commitment: Sha256Digest::zero(),
            balance: U256::from(120),
            switch_dynasty: 30
        };
        let e = rlp::encode(&v);
        assert_eq!(e.len(), 57);    // TODO: fix when pubkey is serialized
        // TODO: test for serialized pubkey
        assert_eq!(e[0], 100);
        assert_eq!(e[1], 148);
        assert_eq!(e[2..22], [0; 20]);
        assert_eq!(e[22], 160);
        assert_eq!(e[23..55], [0; 32]);
        assert_eq!(e[55], 120);
        assert_eq!(e[56], 30);
    }
}
<commit_msg>Add Clone for validator_record (req. crate update)<commit_after>extern crate rand;

use super::utils::types::{ Sha256Digest, Address, U256 };
use super::utils::bls::{ PublicKey, Keypair };
use super::rlp::{ RlpStream, Encodable };

use self::rand::thread_rng;

pub struct ValidatorRecord {
    pub pubkey: PublicKey,
    pub withdrawal_shard: u16,
    pub withdrawal_address: Address,
    pub randao_commitment: Sha256Digest,
    pub balance: U256,
    pub switch_dynasty: u64
}

impl ValidatorRecord {
    pub fn new(pubkey: PublicKey,
               withdrawal_shard: u16,
               withdrawal_address: Address,
               randao_commitment: Sha256Digest,
               balance: U256,
               switch_dynasty: u64)
        -> Self
    {
        Self {
            pubkey,
            withdrawal_shard,
            withdrawal_address,
            randao_commitment,
            balance,
            switch_dynasty
        }
    }

    pub fn zero_with_thread_rand_pub_key() -> Self {
        let mut rng = thread_rng();
        let keypair = Keypair::generate(&mut rng);
        Self {
            pubkey: keypair.public,
            withdrawal_shard: 0,
            withdrawal_address: Address::zero(),
            randao_commitment: Sha256Digest::zero(),
            balance: U256::zero(),
            switch_dynasty: 0
        }
    }
}

impl Clone for ValidatorRecord {
    fn clone(&self) -> ValidatorRecord {
        ValidatorRecord {
            pubkey: self.pubkey.clone(),
            ..*self

        }
    }
}

/*
 * RLP Encoding
 */
impl Encodable for ValidatorRecord {
    fn rlp_append(&self, s: &mut RlpStream) {
        // s.append(&self.pubkey);      // TODO: serialize this
        s.append(&self.withdrawal_shard);
        s.append(&self.withdrawal_address);
        s.append(&self.randao_commitment);
        s.append(&self.balance);
        s.append(&self.switch_dynasty);
    }
}

#[cfg(test)]
mod tests {
    use super::super::rlp;
    extern crate rand;

    use super::*;
    use super::super::
        utils::test_helpers::get_dangerous_test_keypair;

    #[test]
    fn test_new() {
        let keypair = get_dangerous_test_keypair();;
        let withdrawal_shard = 1;
        let withdrawal_address = Address::random();
        let randao_commitment = Sha256Digest::random();
        let balance = U256::from(100);
        let switch_dynasty = 10;

        let v = ValidatorRecord::new(
            keypair.public,
            withdrawal_shard,
            withdrawal_address,
            randao_commitment,
            balance,
            switch_dynasty);
        // TODO: figure out how to compare keys
        // assert_eq!(v.pubkey, keypair.public);
        assert_eq!(v.withdrawal_shard, withdrawal_shard);
        assert_eq!(v.withdrawal_address, withdrawal_address);
        assert_eq!(v.randao_commitment, randao_commitment);
        assert_eq!(v.balance, balance);
        assert_eq!(v.switch_dynasty, switch_dynasty);
    }

    #[test]
    fn test_rlp_serialization() {
        let keypair = get_dangerous_test_keypair();
        let v = ValidatorRecord {
            pubkey: keypair.public,
            withdrawal_shard: 100,
            withdrawal_address: Address::zero(),
            randao_commitment: Sha256Digest::zero(),
            balance: U256::from(120),
            switch_dynasty: 30
        };
        let e = rlp::encode(&v);
        assert_eq!(e.len(), 57);    // TODO: fix when pubkey is serialized
        // TODO: test for serialized pubkey
        assert_eq!(e[0], 100);
        assert_eq!(e[1], 148);
        assert_eq!(e[2..22], [0; 20]);
        assert_eq!(e[22], 160);
        assert_eq!(e[23..55], [0; 32]);
        assert_eq!(e[55], 120);
        assert_eq!(e[56], 30);
    }
}
<|endoftext|>


<commit_before>use byteorder::{BigEndian, ByteOrder};
use std::io;

const HEADER_LENGTH: usize = 2;
const MAX_DATAGRAM_LENGTH: usize = 1 << 16;
const MAX_BLOCK_LENGTH: usize = HEADER_LENGTH + MAX_DATAGRAM_LENGTH;

const TAG: &'static str = "DatagramBuffer";

/// Circular buffer to store datagrams (preserving their boundaries).
///
/// ```text
///     circularBufferLength
/// |<------------------------->| extra space for storing the last datagram in one block
/// +---------------------------+------+
/// |                           |      |
/// |[D4]     [  D1  ][ D2 ][  D3  ]   |
/// +---------------------------+------+
///     ^     ^
///  head     tail
/// ```
pub struct DatagramBuffer {
    buf: Box<[u8]>,
    head: usize,
    tail: usize,
    circular_buffer_length: usize,
}

impl DatagramBuffer {
    pub fn new(capacity: usize) -> DatagramBuffer {
        DatagramBuffer {
            buf: vec![0; capacity + MAX_BLOCK_LENGTH].into_boxed_slice(),
            head: 0,
            tail: 0,
            circular_buffer_length: capacity + 1,
        }
    }

    pub fn is_empty(&self) -> bool {
        self.head == self.tail
    }

    pub fn has_enough_space_for(&self, datagram_length: usize) -> bool {
        if self.head >= self.tail {
            // there is at least the extra space for storing 1 packet
            return true;
        }
        let remaining = self.tail - self.head + 1;
        HEADER_LENGTH + datagram_length < remaining
    }

    pub fn write_to<W: io::Write>(&mut self, destination: &mut W) -> io::Result<()> {
        let length = self.read_length() as usize;
        let source_slice = &self.buf[self.tail..self.tail + length];
        self.tail += length;
        if self.tail >= self.circular_buffer_length {
            self.tail = 0;
        }
        let w = destination.write(source_slice)?;
        if w != length {
            error!(target: TAG, "Cannot write the whole datagram to the buffer (only {}/{})", w, length);
            return Err(io::Error::new(io::ErrorKind::Other, "Cannot write the whole datagram"))
        }
        Ok(())
    }

    pub fn read_from(&mut self, source: &[u8]) -> io::Result<()> {
        let length = source.len();
        assert!(length <= MAX_DATAGRAM_LENGTH, "Datagram length may not be greater than {} bytes", MAX_DATAGRAM_LENGTH);
        if !self.has_enough_space_for(length) {
            return Err(io::Error::new(io::ErrorKind::Other, "Datagram buffer is full"));
        }
        self.write_length(length as u16);
        let target_slice = &mut self.buf[self.head..self.head + length];
        target_slice.copy_from_slice(source);
        self.head += length;
        if self.head >= self.circular_buffer_length {
            self.head = 0;
        }
        Ok(())
    }

    fn read_length(&mut self) -> u16 {
        self.tail += 2;
        BigEndian::read_u16(&self.buf[self.tail - 2..self.tail])
    }

    fn write_length(&mut self, length: u16) {
        BigEndian::write_u16(&mut self.buf[self.head..self.head + 2], length);
        self.head += 2;
    }
}
<commit_msg>Add DatagramBuffer tests<commit_after>use byteorder::{BigEndian, ByteOrder};
use std::io;

const HEADER_LENGTH: usize = 2;
const MAX_DATAGRAM_LENGTH: usize = 1 << 16;
const MAX_BLOCK_LENGTH: usize = HEADER_LENGTH + MAX_DATAGRAM_LENGTH;

const TAG: &'static str = "DatagramBuffer";

/// Circular buffer to store datagrams (preserving their boundaries).
///
/// ```text
///     circularBufferLength
/// |<------------------------->| extra space for storing the last datagram in one block
/// +---------------------------+------+
/// |                           |      |
/// |[D4]     [  D1  ][ D2 ][  D3  ]   |
/// +---------------------------+------+
///     ^     ^
///  head     tail
/// ```
pub struct DatagramBuffer {
    buf: Box<[u8]>,
    head: usize,
    tail: usize,
    circular_buffer_length: usize,
}

impl DatagramBuffer {
    pub fn new(capacity: usize) -> DatagramBuffer {
        DatagramBuffer {
            buf: vec![0; capacity + MAX_BLOCK_LENGTH].into_boxed_slice(),
            head: 0,
            tail: 0,
            circular_buffer_length: capacity + 1,
        }
    }

    pub fn is_empty(&self) -> bool {
        self.head == self.tail
    }

    pub fn has_enough_space_for(&self, datagram_length: usize) -> bool {
        if self.head >= self.tail {
            // there is at least the extra space for storing 1 packet
            return true;
        }
        let remaining = self.tail - self.head + 1;
        HEADER_LENGTH + datagram_length < remaining
    }

    pub fn write_to<W: io::Write>(&mut self, destination: &mut W) -> io::Result<()> {
        let length = self.read_length() as usize;
        let source_slice = &self.buf[self.tail..self.tail + length];
        self.tail += length;
        if self.tail >= self.circular_buffer_length {
            self.tail = 0;
        }
        let w = destination.write(source_slice)?;
        if w != length {
            error!(target: TAG, "Cannot write the whole datagram to the buffer (only {}/{})", w, length);
            return Err(io::Error::new(io::ErrorKind::Other, "Cannot write the whole datagram"))
        }
        Ok(())
    }

    pub fn read_from(&mut self, source: &[u8]) -> io::Result<()> {
        let length = source.len();
        assert!(length <= MAX_DATAGRAM_LENGTH, "Datagram length may not be greater than {} bytes", MAX_DATAGRAM_LENGTH);
        if !self.has_enough_space_for(length) {
            return Err(io::Error::new(io::ErrorKind::Other, "Datagram buffer is full"));
        }
        self.write_length(length as u16);
        let target_slice = &mut self.buf[self.head..self.head + length];
        target_slice.copy_from_slice(source);
        self.head += length;
        if self.head >= self.circular_buffer_length {
            self.head = 0;
        }
        Ok(())
    }

    fn read_length(&mut self) -> u16 {
        self.tail += 2;
        BigEndian::read_u16(&self.buf[self.tail - 2..self.tail])
    }

    fn write_length(&mut self, length: u16) {
        BigEndian::write_u16(&mut self.buf[self.head..self.head + 2], length);
        self.head += 2;
    }
}

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

    fn create_datagram(length: u8) -> Vec<u8> {
        (0..length).collect()
    }

    #[test]
    fn bufferize_datagram() {
        let datagram = create_datagram(5);
        let mut datagram_buffer = DatagramBuffer::new(9);

        let mut cursor = io::Cursor::new(vec![]);
        datagram_buffer.read_from(&datagram);
        datagram_buffer.write_to(&mut cursor).unwrap();

        assert_eq!(cursor.get_ref(), &datagram);
    }

    #[test]
    fn split_datagrams_at_boundaries() {
        let mut datagram_buffer = DatagramBuffer::new(32);

        let datagram5 = create_datagram(5);
        let datagram0 = create_datagram(0);
        let datagram3 = create_datagram(3);
        let datagram4 = create_datagram(4);

        datagram_buffer.read_from(&datagram5);
        datagram_buffer.read_from(&datagram0);
        datagram_buffer.read_from(&datagram3);
        datagram_buffer.read_from(&datagram4);

        let mut cursor = io::Cursor::new(vec![]);
        datagram_buffer.write_to(&mut cursor).unwrap();
        assert_eq!(cursor.get_ref(), &datagram5);

        let mut cursor = io::Cursor::new(vec![]);
        datagram_buffer.write_to(&mut cursor).unwrap();
        assert_eq!(cursor.get_ref(), &datagram0);

        let mut cursor = io::Cursor::new(vec![]);
        datagram_buffer.write_to(&mut cursor).unwrap();
        assert_eq!(cursor.get_ref(), &datagram3);

        let mut cursor = io::Cursor::new(vec![]);
        datagram_buffer.write_to(&mut cursor).unwrap();
        assert_eq!(cursor.get_ref(), &datagram4);
    }

    #[test]
    fn circular() {
        let datagram5 = create_datagram(5);
        let datagram3 = create_datagram(3);

        let mut datagram_buffer = DatagramBuffer::new(14);

        // write and consume 10 bytes
        datagram_buffer.read_from(&create_datagram(10));
        {
            // write and forget
            let mut cursor = io::Cursor::new(vec![]);
            datagram_buffer.write_to(&mut cursor);
        }

        // DatagramBuffer is expected to store the whole datagram (even if it exceeds its "capacity")
        datagram_buffer.read_from(&datagram5).unwrap();
        datagram_buffer.read_from(&datagram3).unwrap();

        let mut cursor = io::Cursor::new(vec![]);
        datagram_buffer.write_to(&mut cursor).unwrap();
        assert_eq!(cursor.get_ref(), &datagram5);

        let mut cursor = io::Cursor::new(vec![]);
        datagram_buffer.write_to(&mut cursor).unwrap();
        assert_eq!(cursor.get_ref(), &datagram3);
    }
}
<|endoftext|>


<commit_before>use crate::combox::{CoClass, ComBoxData};
use crate::raw::RawComPtr;
use crate::{type_system::TypeSystem, IID};

pub trait ComImpl<TInterface: ?Sized, TS: TypeSystem>
where
    TInterface: ComInterface<TS>,
{
    fn vtable() -> &'static TInterface::VTable;
}

pub trait ComClass<TInterface: ?Sized, TS: TypeSystem>: CoClass + Sized
{
    fn offset() -> usize;
    unsafe fn get_box<'a>(vtable: RawComPtr) -> &'a mut ComBoxData<Self>
    {
        let offset = Self::offset();
        let self_ptr = (vtable as usize - offset) as *mut _;
        &mut *self_ptr
    }
}

pub trait VTableFor<I: ?Sized, S, TS: TypeSystem>: ComInterface<TS>
{
    const VTABLE: Self::VTable;
}

pub trait ComInterface<TS: TypeSystem>
{
    type VTable: 'static;
    fn iid() -> &'static IID;
}

pub trait HasTypeInfo
{
    fn gather_type_info() -> Vec<crate::typelib::TypeInfo>;
}

pub trait InterfaceHasTypeInfo
{
    fn gather_type_info() -> Vec<crate::typelib::TypeInfo>;
}
<commit_msg>Remove ComImpl attribute<commit_after>use crate::combox::{CoClass, ComBoxData};
use crate::raw::RawComPtr;
use crate::{type_system::TypeSystem, IID};

pub trait ComClass<TInterface: ?Sized, TS: TypeSystem>: CoClass + Sized
{
    fn offset() -> usize;
    unsafe fn get_box<'a>(vtable: RawComPtr) -> &'a mut ComBoxData<Self>
    {
        let offset = Self::offset();
        let self_ptr = (vtable as usize - offset) as *mut _;
        &mut *self_ptr
    }
}

pub trait VTableFor<I: ?Sized, S, TS: TypeSystem>: ComInterface<TS>
{
    const VTABLE: Self::VTable;
}

pub trait ComInterface<TS: TypeSystem>
{
    type VTable: 'static;
    fn iid() -> &'static IID;
}

pub trait HasTypeInfo
{
    fn gather_type_info() -> Vec<crate::typelib::TypeInfo>;
}

pub trait InterfaceHasTypeInfo
{
    fn gather_type_info() -> Vec<crate::typelib::TypeInfo>;
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Benoit Benedetti <benoit.benedetti@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

/* last synced with: logname (GNU coreutils) 8.22 */

// spell-checker:ignore (ToDO) getlogin userlogin

#[macro_use]
extern crate uucore;

use std::ffi::CStr;
use uucore::InvalidEncodingHandling;

use clap::{crate_version, App};

extern "C" {
    // POSIX requires using getlogin (or equivalent code)
    pub fn getlogin() -> *const libc::c_char;
}

fn get_userlogin() -> Option<String> {
    unsafe {
        let login: *const libc::c_char = getlogin();
        if login.is_null() {
            None
        } else {
            Some(String::from_utf8_lossy(CStr::from_ptr(login).to_bytes()).to_string())
        }
    }
}

static SUMMARY: &str = "Print user's login name";

fn usage() -> &'static str {
    uucore::execution_phrase()
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();

    let _ = uu_app().usage(usage()).get_matches_from(args);

    match get_userlogin() {
        Some(userlogin) => println!("{}", userlogin),
        None => show_error!("no login name"),
    }

    0
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(SUMMARY)
}
<commit_msg>logname: return UResult from uumain() function<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Benoit Benedetti <benoit.benedetti@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

/* last synced with: logname (GNU coreutils) 8.22 */

// spell-checker:ignore (ToDO) getlogin userlogin

#[macro_use]
extern crate uucore;

use clap::{crate_version, App};
use std::ffi::CStr;
use uucore::error::UResult;
use uucore::InvalidEncodingHandling;

extern "C" {
    // POSIX requires using getlogin (or equivalent code)
    pub fn getlogin() -> *const libc::c_char;
}

fn get_userlogin() -> Option<String> {
    unsafe {
        let login: *const libc::c_char = getlogin();
        if login.is_null() {
            None
        } else {
            Some(String::from_utf8_lossy(CStr::from_ptr(login).to_bytes()).to_string())
        }
    }
}

static SUMMARY: &str = "Print user's login name";

fn usage() -> &'static str {
    uucore::execution_phrase()
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();

    let _ = uu_app().usage(usage()).get_matches_from(args);

    match get_userlogin() {
        Some(userlogin) => println!("{}", userlogin),
        None => show_error!("no login name"),
    }

    Ok(())
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(SUMMARY)
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use nom::{IResult,digit};

use std::str;
use std::str::FromStr;

named!(parens<i64>, ws!(delimited!( tag!("("), expr, tag!(")") )) );

named!(factor<i64>, alt!(
    map_res!(
      map_res!(
        ws!(digit),
        str::from_utf8
      ),
      FromStr::from_str
    )
  | parens
  )
);

named!(term <i64>, chain!(
    mut acc: factor  ~
             many0!(
               alt!(
                 tap!(mul: preceded!(tag!("*"), factor) => acc = acc * mul) |
                 tap!(div: preceded!(tag!("/"), factor) => acc = acc / div)
               )
             ),
    || { return acc }
  )
);

named!(expr <i64>, chain!(
    mut acc: term  ~
             many0!(
               alt!(
                 tap!(add: preceded!(tag!("+"), term) => acc = acc + add) |
                 tap!(sub: preceded!(tag!("-"), term) => acc = acc - sub)
               )
             ),
    || { return acc }
  )
);

#[test]
fn factor_test() {
  assert_eq!(factor(&b"3"[..]), IResult::Done(&b""[..], 3));
  assert_eq!(factor(&b" 12"[..]), IResult::Done(&b""[..], 12));
  assert_eq!(factor(&b"537  "[..]), IResult::Done(&b""[..], 537));
  assert_eq!(factor(&b"  24   "[..]), IResult::Done(&b""[..], 24));
}

#[test]
fn term_test() {
  assert_eq!(term(&b" 12 *2 /  3"[..]), IResult::Done(&b""[..], 8));
  assert_eq!(term(&b" 2* 3  *2 *2 /  3"[..]), IResult::Done(&b""[..], 8));
  assert_eq!(term(&b" 48 /  3/2"[..]), IResult::Done(&b""[..], 8));
}

#[test]
fn expr_test() {
  assert_eq!(expr(&b" 1 +  2 "[..]), IResult::Done(&b""[..], 3));
  assert_eq!(expr(&b" 12 + 6 - 4+  3"[..]), IResult::Done(&b""[..], 17));
  assert_eq!(expr(&b" 1 + 2*3 + 4"[..]), IResult::Done(&b""[..], 11));
}

#[test]
fn parens_test() {
  assert_eq!(expr(&b" (  2 )"[..]), IResult::Done(&b""[..], 2));
  assert_eq!(expr(&b" 2* (  3 + 4 ) "[..]), IResult::Done(&b""[..], 14));
  assert_eq!(expr(&b"  2*2 / ( 5 - 1) + 3"[..]), IResult::Done(&b""[..], 4));
}
<commit_msg>tests/arithmetic: don't use chain!<commit_after>#[macro_use]
extern crate nom;

use nom::{IResult,digit};

use std::str;
use std::str::FromStr;

named!(parens<i64>, ws!(delimited!( tag!("("), expr, tag!(")") )) );

named!(factor<i64>, alt!(
    map_res!(
      map_res!(
        ws!(digit),
        str::from_utf8
      ),
      FromStr::from_str
    )
  | parens
  )
);

named!(term <i64>, do_parse!(
    init: factor >>
    res:  fold_many0!(
        pair!(alt!(tag!("*") | tag!("/")), factor),
        init,
        |acc, (op, val): (&[u8], i64)| {
            if (op[0] as char) == '*' { acc * val } else { acc / val }
        }
    ) >>
    (res)
  )
);

named!(expr <i64>, do_parse!(
    init: term >>
    res:  fold_many0!(
        pair!(alt!(tag!("+") | tag!("-")), term),
        init,
        |acc, (op, val): (&[u8], i64)| {
            if (op[0] as char) == '+' { acc + val } else { acc - val }
        }
    ) >>
    (res)
  )
);

#[test]
fn factor_test() {
  assert_eq!(factor(&b"3"[..]), IResult::Done(&b""[..], 3));
  assert_eq!(factor(&b" 12"[..]), IResult::Done(&b""[..], 12));
  assert_eq!(factor(&b"537  "[..]), IResult::Done(&b""[..], 537));
  assert_eq!(factor(&b"  24   "[..]), IResult::Done(&b""[..], 24));
}

#[test]
fn term_test() {
  assert_eq!(term(&b" 12 *2 /  3"[..]), IResult::Done(&b""[..], 8));
  assert_eq!(term(&b" 2* 3  *2 *2 /  3"[..]), IResult::Done(&b""[..], 8));
  assert_eq!(term(&b" 48 /  3/2"[..]), IResult::Done(&b""[..], 8));
}

#[test]
fn expr_test() {
  assert_eq!(expr(&b" 1 +  2 "[..]), IResult::Done(&b""[..], 3));
  assert_eq!(expr(&b" 12 + 6 - 4+  3"[..]), IResult::Done(&b""[..], 17));
  assert_eq!(expr(&b" 1 + 2*3 + 4"[..]), IResult::Done(&b""[..], 11));
}

#[test]
fn parens_test() {
  assert_eq!(expr(&b" (  2 )"[..]), IResult::Done(&b""[..], 2));
  assert_eq!(expr(&b" 2* (  3 + 4 ) "[..]), IResult::Done(&b""[..], 14));
  assert_eq!(expr(&b"  2*2 / ( 5 - 1) + 3"[..]), IResult::Done(&b""[..], 4));
}
<|endoftext|>


<commit_before>//! Pass timing.
//!
//! This modules provides facilities for timing the execution of individual compilation passes.

use std::fmt;

pub use self::details::{TimingToken, PassTimes, take_current, add_to_current};

// Each pass that can be timed is predefined with the `define_passes!` macro. Each pass has a
// snake_case name and a plain text description used when printing out the timing report.
//
// This macro defines:
//
// - A C-style enum containing all the pass names and a `NoPass` variant.
// - A usize constant with the number of defined passes.
// - A const array of pass descriptions.
// - A public function per pass used to start the timing of that pass.
macro_rules! define_passes {
    { $enum:ident, $num_passes:ident, $descriptions:ident;
      $($pass:ident: $desc:expr,)+
    } => {
        #[allow(non_camel_case_types)]
        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
        enum $enum { $($pass,)+ NoPass }

        const $num_passes: usize = $enum::NoPass as usize;

        const $descriptions: [&str; $num_passes] = [ $($desc),+ ];

        $(
            #[doc=$desc]
            pub fn $pass() -> TimingToken {
                details::start_pass($enum::$pass)
            }
        )+
    }
}

// Pass definitions.
define_passes!{
    Pass, NUM_PASSES, DESCRIPTIONS;

    process_file: "Processing test file",
    parse_text: "Parsing textual Cretonne IL",
    wasm_translate_module: "Translate WASM module",
    wasm_translate_function: "Translate WASM function",

    verifier: "Verify Cretonne IL",
    verify_cssa: "Verify CSSA",
    verify_liveness: "Verify live ranges",
    verify_locations: "Verify value locations",
    verify_flags: "Verify CPU flags",

    compile: "Compilation passes",
    flowgraph: "Control flow graph",
    domtree: "Dominator tree",
    loop_analysis: "Loop analysis",
    legalize: "Legalization",
    gvn: "Global value numbering",
    licm: "Loop invariant code motion",
    unreachable_code: "Remove unreachable blocks",

    regalloc: "Register allocation",
    ra_liveness: "RA liveness analysis",
    ra_cssa: "RA coalescing CSSA",
    ra_spilling: "RA spilling",
    ra_reload: "RA reloading",
    ra_coloring: "RA coloring",

    prologue_epilogue: "Prologue/epilogue insertion",
    binemit: "Binary machine code emission",
    layout_renumber: "Layout full renumbering",
}

impl Pass {
    pub fn idx(self) -> usize {
        self as usize
    }
}

impl fmt::Display for Pass {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match DESCRIPTIONS.get(self.idx()) {
            Some(s) => f.write_str(s),
            None => f.write_str("<no pass>"),
        }
    }
}

/// Implementation details.
///
/// This whole module can be gated on a `cfg` feature to provide a dummy implementation for
/// performance-sensitive builds or restricted environments. The dummy implementation must provide
/// `TimingToken` and `PassTimes` types and `take_current`, `add_to_current`, and `start_pass` functions.
#[cfg(not(feature = "no_std"))]
mod details {
    use super::{Pass, NUM_PASSES, DESCRIPTIONS};
    use std::cell::{Cell, RefCell};
    use std::fmt;
    use std::mem;
    use std::time::{Instant, Duration};

    /// A timing token is responsible for timing the currently running pass. Timing starts when it
    /// is created and ends when it is dropped.
    ///
    /// Multiple passes can be active at the same time, but they must be started and stopped in a
    /// LIFO fashion.
    pub struct TimingToken {
        /// Start time for this pass.
        start: Instant,

        // Pass being timed by this token.
        pass: Pass,

        // The previously active pass which will be restored when this token is dropped.
        prev: Pass,
    }

    /// Accumulated timing information for a single pass.
    #[derive(Default)]
    struct PassTime {
        /// Total time spent running this pas including children.
        total: Duration,

        /// Time spent running in child passes.
        child: Duration,
    }

    /// Accumulated timing for all passes.
    #[derive(Default)]
    pub struct PassTimes {
        pass: [PassTime; NUM_PASSES],
    }

    impl fmt::Display for PassTimes {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            writeln!(f, "======== ========  ==================================")?;
            writeln!(f, "   Total     Self  Pass")?;
            writeln!(f, "-------- --------  ----------------------------------")?;
            for (time, desc) in self.pass.iter().zip(&DESCRIPTIONS) {
                // Omit passes that haven't run.
                if time.total == Duration::default() {
                    continue;
                }

                // Write a duration as secs.milis, trailing space.
                fn fmtdur(mut dur: Duration, f: &mut fmt::Formatter) -> fmt::Result {
                    // Round to nearest ms by adding 500us.
                    dur += Duration::new(0, 500_000);
                    let ms = dur.subsec_nanos() / 1_000_000;
                    write!(f, "{:4}.{:03} ", dur.as_secs(), ms)
                }

                fmtdur(time.total, f)?;
                if let Some(s) = time.total.checked_sub(time.child) {
                    fmtdur(s, f)?;
                }
                writeln!(f, " {}", desc)?;
            }
            writeln!(f, "======== ========  ==================================")
        }
    }

    /// Information about passes in a single thread.
    thread_local!{
        static CURRENT_PASS: Cell<Pass> = Cell::new(Pass::NoPass);
        static PASS_TIME: RefCell<PassTimes> = RefCell::new(Default::default());
    }

    /// Start timing `pass` as a child of the currently running pass, if any.
    ///
    /// This function is called by the publicly exposed pass functions.
    pub(super) fn start_pass(pass: Pass) -> TimingToken {
        let prev = CURRENT_PASS.with(|p| p.replace(pass));
        dbg!("timing: Starting {}, (during {})", pass, prev);
        TimingToken {
            start: Instant::now(),
            pass,
            prev,
        }
    }

    /// Dropping a timing token indicated the end of the pass.
    impl Drop for TimingToken {
        fn drop(&mut self) {
            let duration = self.start.elapsed();
            dbg!("timing: Ending {}", self.pass);
            let old_cur = CURRENT_PASS.with(|p| p.replace(self.prev));
            assert_eq!(self.pass, old_cur, "Timing tokens dropped out of order");
            PASS_TIME.with(|rc| {
                let mut table = rc.borrow_mut();
                table.pass[self.pass.idx()].total += duration;
                if let Some(parent) = table.pass.get_mut(self.prev.idx()) {
                    parent.child += duration;
                }
            })
        }
    }

    /// Take the current accumulated pass timings and reset the timings for the current thread.
    pub fn take_current() -> PassTimes {
        PASS_TIME.with(|rc| mem::replace(&mut *rc.borrow_mut(), Default::default()))
    }

    /// Add `timings` to the accumulated timings for the current thread.
    pub fn add_to_current(times: PassTimes) {
        PASS_TIME.with(|rc| for (a, b) in rc.borrow_mut().pass.iter_mut().zip(
            &times.pass,
        )
        {
            a.total += b.total;
            a.child += b.child;
        })
    }
}

/// Dummy `debug` implementation
#[cfg(feature = "no_std")]
mod details {
    use super::Pass;
    /// Dummy `TimingToken`
    pub struct TimingToken;
    /// Dummy `PassTimes`
    pub struct PassTimes;
    /// Returns dummy `PassTimes`
    pub fn take_current() -> PassTimes {
        PassTimes
    }
    /// does nothing
    pub fn add_to_current(_times: PassTimes) { }

    /// does nothing
    pub(super) fn start_pass(_pass: Pass) -> TimingToken {
        TimingToken
    }
}

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

    #[test]
    fn display() {
        assert_eq!(Pass::NoPass.to_string(), "<no pass>");
        assert_eq!(Pass::regalloc.to_string(), "Register allocation");
    }
}
<commit_msg>Fixed formatting issues<commit_after>//! Pass timing.
//!
//! This modules provides facilities for timing the execution of individual compilation passes.

use std::fmt;

pub use self::details::{TimingToken, PassTimes, take_current, add_to_current};

// Each pass that can be timed is predefined with the `define_passes!` macro. Each pass has a
// snake_case name and a plain text description used when printing out the timing report.
//
// This macro defines:
//
// - A C-style enum containing all the pass names and a `NoPass` variant.
// - A usize constant with the number of defined passes.
// - A const array of pass descriptions.
// - A public function per pass used to start the timing of that pass.
macro_rules! define_passes {
    { $enum:ident, $num_passes:ident, $descriptions:ident;
      $($pass:ident: $desc:expr,)+
    } => {
        #[allow(non_camel_case_types)]
        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
        enum $enum { $($pass,)+ NoPass }

        const $num_passes: usize = $enum::NoPass as usize;

        const $descriptions: [&str; $num_passes] = [ $($desc),+ ];

        $(
            #[doc=$desc]
            pub fn $pass() -> TimingToken {
                details::start_pass($enum::$pass)
            }
        )+
    }
}

// Pass definitions.
define_passes!{
    Pass, NUM_PASSES, DESCRIPTIONS;

    process_file: "Processing test file",
    parse_text: "Parsing textual Cretonne IL",
    wasm_translate_module: "Translate WASM module",
    wasm_translate_function: "Translate WASM function",

    verifier: "Verify Cretonne IL",
    verify_cssa: "Verify CSSA",
    verify_liveness: "Verify live ranges",
    verify_locations: "Verify value locations",
    verify_flags: "Verify CPU flags",

    compile: "Compilation passes",
    flowgraph: "Control flow graph",
    domtree: "Dominator tree",
    loop_analysis: "Loop analysis",
    legalize: "Legalization",
    gvn: "Global value numbering",
    licm: "Loop invariant code motion",
    unreachable_code: "Remove unreachable blocks",

    regalloc: "Register allocation",
    ra_liveness: "RA liveness analysis",
    ra_cssa: "RA coalescing CSSA",
    ra_spilling: "RA spilling",
    ra_reload: "RA reloading",
    ra_coloring: "RA coloring",

    prologue_epilogue: "Prologue/epilogue insertion",
    binemit: "Binary machine code emission",
    layout_renumber: "Layout full renumbering",
}

impl Pass {
    pub fn idx(self) -> usize {
        self as usize
    }
}

impl fmt::Display for Pass {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match DESCRIPTIONS.get(self.idx()) {
            Some(s) => f.write_str(s),
            None => f.write_str("<no pass>"),
        }
    }
}

/// Implementation details.
///
/// This whole module can be gated on a `cfg` feature to provide a dummy implementation for
/// performance-sensitive builds or restricted environments. The dummy implementation must provide
/// `TimingToken` and `PassTimes` types and `take_current`, `add_to_current`, and `start_pass` funcs
#[cfg(not(feature = "no_std"))]
mod details {
    use super::{Pass, NUM_PASSES, DESCRIPTIONS};
    use std::cell::{Cell, RefCell};
    use std::fmt;
    use std::mem;
    use std::time::{Instant, Duration};

    /// A timing token is responsible for timing the currently running pass. Timing starts when it
    /// is created and ends when it is dropped.
    ///
    /// Multiple passes can be active at the same time, but they must be started and stopped in a
    /// LIFO fashion.
    pub struct TimingToken {
        /// Start time for this pass.
        start: Instant,

        // Pass being timed by this token.
        pass: Pass,

        // The previously active pass which will be restored when this token is dropped.
        prev: Pass,
    }

    /// Accumulated timing information for a single pass.
    #[derive(Default)]
    struct PassTime {
        /// Total time spent running this pas including children.
        total: Duration,

        /// Time spent running in child passes.
        child: Duration,
    }

    /// Accumulated timing for all passes.
    #[derive(Default)]
    pub struct PassTimes {
        pass: [PassTime; NUM_PASSES],
    }

    impl fmt::Display for PassTimes {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            writeln!(f, "======== ========  ==================================")?;
            writeln!(f, "   Total     Self  Pass")?;
            writeln!(f, "-------- --------  ----------------------------------")?;
            for (time, desc) in self.pass.iter().zip(&DESCRIPTIONS) {
                // Omit passes that haven't run.
                if time.total == Duration::default() {
                    continue;
                }

                // Write a duration as secs.milis, trailing space.
                fn fmtdur(mut dur: Duration, f: &mut fmt::Formatter) -> fmt::Result {
                    // Round to nearest ms by adding 500us.
                    dur += Duration::new(0, 500_000);
                    let ms = dur.subsec_nanos() / 1_000_000;
                    write!(f, "{:4}.{:03} ", dur.as_secs(), ms)
                }

                fmtdur(time.total, f)?;
                if let Some(s) = time.total.checked_sub(time.child) {
                    fmtdur(s, f)?;
                }
                writeln!(f, " {}", desc)?;
            }
            writeln!(f, "======== ========  ==================================")
        }
    }

    /// Information about passes in a single thread.
    thread_local!{
        static CURRENT_PASS: Cell<Pass> = Cell::new(Pass::NoPass);
        static PASS_TIME: RefCell<PassTimes> = RefCell::new(Default::default());
    }

    /// Start timing `pass` as a child of the currently running pass, if any.
    ///
    /// This function is called by the publicly exposed pass functions.
    pub(super) fn start_pass(pass: Pass) -> TimingToken {
        let prev = CURRENT_PASS.with(|p| p.replace(pass));
        dbg!("timing: Starting {}, (during {})", pass, prev);
        TimingToken {
            start: Instant::now(),
            pass,
            prev,
        }
    }

    /// Dropping a timing token indicated the end of the pass.
    impl Drop for TimingToken {
        fn drop(&mut self) {
            let duration = self.start.elapsed();
            dbg!("timing: Ending {}", self.pass);
            let old_cur = CURRENT_PASS.with(|p| p.replace(self.prev));
            assert_eq!(self.pass, old_cur, "Timing tokens dropped out of order");
            PASS_TIME.with(|rc| {
                let mut table = rc.borrow_mut();
                table.pass[self.pass.idx()].total += duration;
                if let Some(parent) = table.pass.get_mut(self.prev.idx()) {
                    parent.child += duration;
                }
            })
        }
    }

    /// Take the current accumulated pass timings and reset the timings for the current thread.
    pub fn take_current() -> PassTimes {
        PASS_TIME.with(|rc| mem::replace(&mut *rc.borrow_mut(), Default::default()))
    }

    /// Add `timings` to the accumulated timings for the current thread.
    pub fn add_to_current(times: PassTimes) {
        PASS_TIME.with(|rc| for (a, b) in rc.borrow_mut().pass.iter_mut().zip(
            &times.pass,
        )
        {
            a.total += b.total;
            a.child += b.child;
        })
    }
}

/// Dummy `debug` implementation
#[cfg(feature = "no_std")]
mod details {
    use super::Pass;
    /// Dummy `TimingToken`
    pub struct TimingToken;
    /// Dummy `PassTimes`
    pub struct PassTimes;
    /// Returns dummy `PassTimes`
    pub fn take_current() -> PassTimes {
        PassTimes
    }
    /// does nothing
    pub fn add_to_current(_times: PassTimes) {}

    /// does nothing
    pub(super) fn start_pass(_pass: Pass) -> TimingToken {
        TimingToken
    }
}

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

    #[test]
    fn display() {
        assert_eq!(Pass::NoPass.to_string(), "<no pass>");
        assert_eq!(Pass::regalloc.to_string(), "Register allocation");
    }
}
<|endoftext|>