<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (words) bogusfile emptyfile abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstu

use crate::common::util::*;

static INPUT: &str = "lorem_ipsum.txt";

#[test]
fn test_stdin_default() {
    new_ucmd!()
        .pipe_in_fixture(INPUT)
        .run()
        .stdout_is_fixture("lorem_ipsum_default.expected");
}

#[test]
fn test_stdin_1_line_obsolete() {
    new_ucmd!()
        .args(&["-1"])
        .pipe_in_fixture(INPUT)
        .run()
        .stdout_is_fixture("lorem_ipsum_1_line.expected");
}

#[test]
fn test_stdin_1_line() {
    new_ucmd!()
        .args(&["-n", "1"])
        .pipe_in_fixture(INPUT)
        .run()
        .stdout_is_fixture("lorem_ipsum_1_line.expected");
}

#[test]
fn test_stdin_negative_23_line() {
    new_ucmd!()
        .args(&["-n", "-23"])
        .pipe_in_fixture(INPUT)
        .run()
        .stdout_is_fixture("lorem_ipsum_1_line.expected");
}

#[test]
fn test_stdin_5_chars() {
    new_ucmd!()
        .args(&["-c", "5"])
        .pipe_in_fixture(INPUT)
        .run()
        .stdout_is_fixture("lorem_ipsum_5_chars.expected");
}

#[test]
fn test_single_default() {
    new_ucmd!()
        .arg(INPUT)
        .run()
        .stdout_is_fixture("lorem_ipsum_default.expected");
}

#[test]
fn test_single_1_line_obsolete() {
    new_ucmd!()
        .args(&["-1", INPUT])
        .run()
        .stdout_is_fixture("lorem_ipsum_1_line.expected");
}

#[test]
fn test_single_1_line() {
    new_ucmd!()
        .args(&["-n", "1", INPUT])
        .run()
        .stdout_is_fixture("lorem_ipsum_1_line.expected");
}

#[test]
fn test_single_5_chars() {
    new_ucmd!()
        .args(&["-c", "5", INPUT])
        .run()
        .stdout_is_fixture("lorem_ipsum_5_chars.expected");
}

#[test]
fn test_verbose() {
    new_ucmd!()
        .args(&["-v", INPUT])
        .run()
        .stdout_is_fixture("lorem_ipsum_verbose.expected");
}

#[test]
#[ignore]
fn test_spams_newline() {
    //this test is does not mirror what GNU does
    new_ucmd!().pipe_in("a").succeeds().stdout_is("a\n");
}

#[test]
fn test_byte_syntax() {
    new_ucmd!()
        .args(&["-1c"])
        .pipe_in("abc")
        .run()
        .stdout_is("a");
}

#[test]
fn test_line_syntax() {
    new_ucmd!()
        .args(&["-n", "2048m"])
        .pipe_in("a\n")
        .run()
        .stdout_is("a\n");
}

#[test]
fn test_zero_terminated_syntax() {
    new_ucmd!()
        .args(&["-z", "-n", "1"])
        .pipe_in("x\0y")
        .run()
        .stdout_is("x\0");
}

#[test]
fn test_zero_terminated_syntax_2() {
    new_ucmd!()
        .args(&["-z", "-n", "2"])
        .pipe_in("x\0y")
        .run()
        .stdout_is("x\0y");
}

#[test]
fn test_zero_terminated_negative_lines() {
    new_ucmd!()
        .args(&["-z", "-n", "-1"])
        .pipe_in("x\0y\0z\0")
        .run()
        .stdout_is("x\0y\0");
}

#[test]
fn test_negative_byte_syntax() {
    new_ucmd!()
        .args(&["--bytes=-2"])
        .pipe_in("a\n")
        .run()
        .stdout_is("");
}

#[test]
fn test_negative_zero_lines() {
    new_ucmd!()
        .args(&["--lines=-0"])
        .pipe_in("a\nb\n")
        .succeeds()
        .stdout_is("a\nb\n");
}
#[test]
fn test_negative_zero_bytes() {
    new_ucmd!()
        .args(&["--bytes=-0"])
        .pipe_in("qwerty")
        .succeeds()
        .stdout_is("qwerty");
}
#[test]
fn test_no_such_file_or_directory() {
    new_ucmd!()
        .arg("no_such_file.toml")
        .fails()
        .stderr_contains("cannot open 'no_such_file.toml' for reading: No such file or directory");
}

/// Test that each non-existent files gets its own error message printed.
#[test]
fn test_multiple_nonexistent_files() {
    new_ucmd!()
        .args(&["bogusfile1", "bogusfile2"])
        .fails()
        .stdout_does_not_contain("==> bogusfile1 <==")
        .stderr_contains("cannot open 'bogusfile1' for reading: No such file or directory")
        .stdout_does_not_contain("==> bogusfile2 <==")
        .stderr_contains("cannot open 'bogusfile2' for reading: No such file or directory");
}

// there was a bug not caught by previous tests
// where for negative n > 3, the total amount of lines
// was correct, but it would eat from the second line
#[test]
fn test_sequence_fixture() {
    new_ucmd!()
        .args(&["-n", "-10", "sequence"])
        .run()
        .stdout_is_fixture("sequence.expected");
}
#[test]
fn test_file_backwards() {
    new_ucmd!()
        .args(&["-c", "-10", "lorem_ipsum.txt"])
        .run()
        .stdout_is_fixture("lorem_ipsum_backwards_file.expected");
}

#[test]
fn test_zero_terminated() {
    new_ucmd!()
        .args(&["-z", "zero_terminated.txt"])
        .run()
        .stdout_is_fixture("zero_terminated.expected");
}

#[test]
fn test_obsolete_extras() {
    new_ucmd!()
        .args(&["-5zv"])
        .pipe_in("1\02\03\04\05\06")
        .succeeds()
        .stdout_is("==> standard input <==\n1\02\03\04\05\0");
}

#[test]
fn test_multiple_files() {
    new_ucmd!()
        .args(&["emptyfile.txt", "emptyfile.txt"])
        .succeeds()
        .stdout_is("==> emptyfile.txt <==\n\n==> emptyfile.txt <==\n");
}

#[test]
fn test_multiple_files_with_stdin() {
    new_ucmd!()
        .args(&["emptyfile.txt", "-", "emptyfile.txt"])
        .pipe_in("hello\n")
        .succeeds()
        .stdout_is(
            "==> emptyfile.txt <==

==> standard input <==
hello

==> emptyfile.txt <==
",
        );
}

#[test]
fn test_bad_utf8() {
    let bytes: &[u8] = b"\xfc\x80\x80\x80\x80\xaf";
    new_ucmd!()
        .args(&["-c", "6"])
        .pipe_in(bytes)
        .succeeds()
        .stdout_is_bytes(bytes);
}

#[test]
fn test_bad_utf8_lines() {
    let input: &[u8] =
        b"\xfc\x80\x80\x80\x80\xaf\nb\xfc\x80\x80\x80\x80\xaf\nb\xfc\x80\x80\x80\x80\xaf";
    let output = b"\xfc\x80\x80\x80\x80\xaf\nb\xfc\x80\x80\x80\x80\xaf\n";
    new_ucmd!()
        .args(&["-n", "2"])
        .pipe_in(input)
        .succeeds()
        .stdout_is_bytes(output);
}

#[test]
fn test_head_invalid_num() {
    new_ucmd!()
        .args(&["-c", "1024R", "emptyfile.txt"])
        .fails()
        .stderr_is("head: invalid number of bytes: '1024R'");
    new_ucmd!()
        .args(&["-n", "1024R", "emptyfile.txt"])
        .fails()
        .stderr_is("head: invalid number of lines: '1024R'");
    #[cfg(not(target_pointer_width = "128"))]
    new_ucmd!()
        .args(&["-c", "1Y", "emptyfile.txt"])
        .fails()
        .stderr_is("head: invalid number of bytes: '1Y': Value too large for defined data type");
    #[cfg(not(target_pointer_width = "128"))]
    new_ucmd!()
        .args(&["-n", "1Y", "emptyfile.txt"])
        .fails()
        .stderr_is("head: invalid number of lines: '1Y': Value too large for defined data type");
    #[cfg(target_pointer_width = "32")]
    {
        let sizes = ["1000G", "10T"];
        for size in &sizes {
            new_ucmd!()
                .args(&["-c", size])
                .fails()
                .code_is(1)
                .stderr_only(format!(
                    "head: invalid number of bytes: '{}': Value too large for defined data type",
                    size
                ));
        }
    }
}

#[test]
fn test_head_num_with_undocumented_sign_bytes() {
    // tail: '-' is not documented (8.32 man pages)
    // head: '+' is not documented (8.32 man pages)
    const ALPHABET: &str = "abcdefghijklmnopqrstuvwxyz";
    new_ucmd!()
        .args(&["-c", "5"])
        .pipe_in(ALPHABET)
        .succeeds()
        .stdout_is("abcde");
    new_ucmd!()
        .args(&["-c", "-5"])
        .pipe_in(ALPHABET)
        .succeeds()
        .stdout_is("abcdefghijklmnopqrstu");
    new_ucmd!()
        .args(&["-c", "+5"])
        .pipe_in(ALPHABET)
        .succeeds()
        .stdout_is("abcde");
}
<commit_msg>tests(head): change file mode from 755 to 644<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (words) bogusfile emptyfile abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstu

use crate::common::util::*;

static INPUT: &str = "lorem_ipsum.txt";

#[test]
fn test_stdin_default() {
    new_ucmd!()
        .pipe_in_fixture(INPUT)
        .run()
        .stdout_is_fixture("lorem_ipsum_default.expected");
}

#[test]
fn test_stdin_1_line_obsolete() {
    new_ucmd!()
        .args(&["-1"])
        .pipe_in_fixture(INPUT)
        .run()
        .stdout_is_fixture("lorem_ipsum_1_line.expected");
}

#[test]
fn test_stdin_1_line() {
    new_ucmd!()
        .args(&["-n", "1"])
        .pipe_in_fixture(INPUT)
        .run()
        .stdout_is_fixture("lorem_ipsum_1_line.expected");
}

#[test]
fn test_stdin_negative_23_line() {
    new_ucmd!()
        .args(&["-n", "-23"])
        .pipe_in_fixture(INPUT)
        .run()
        .stdout_is_fixture("lorem_ipsum_1_line.expected");
}

#[test]
fn test_stdin_5_chars() {
    new_ucmd!()
        .args(&["-c", "5"])
        .pipe_in_fixture(INPUT)
        .run()
        .stdout_is_fixture("lorem_ipsum_5_chars.expected");
}

#[test]
fn test_single_default() {
    new_ucmd!()
        .arg(INPUT)
        .run()
        .stdout_is_fixture("lorem_ipsum_default.expected");
}

#[test]
fn test_single_1_line_obsolete() {
    new_ucmd!()
        .args(&["-1", INPUT])
        .run()
        .stdout_is_fixture("lorem_ipsum_1_line.expected");
}

#[test]
fn test_single_1_line() {
    new_ucmd!()
        .args(&["-n", "1", INPUT])
        .run()
        .stdout_is_fixture("lorem_ipsum_1_line.expected");
}

#[test]
fn test_single_5_chars() {
    new_ucmd!()
        .args(&["-c", "5", INPUT])
        .run()
        .stdout_is_fixture("lorem_ipsum_5_chars.expected");
}

#[test]
fn test_verbose() {
    new_ucmd!()
        .args(&["-v", INPUT])
        .run()
        .stdout_is_fixture("lorem_ipsum_verbose.expected");
}

#[test]
#[ignore]
fn test_spams_newline() {
    //this test is does not mirror what GNU does
    new_ucmd!().pipe_in("a").succeeds().stdout_is("a\n");
}

#[test]
fn test_byte_syntax() {
    new_ucmd!()
        .args(&["-1c"])
        .pipe_in("abc")
        .run()
        .stdout_is("a");
}

#[test]
fn test_line_syntax() {
    new_ucmd!()
        .args(&["-n", "2048m"])
        .pipe_in("a\n")
        .run()
        .stdout_is("a\n");
}

#[test]
fn test_zero_terminated_syntax() {
    new_ucmd!()
        .args(&["-z", "-n", "1"])
        .pipe_in("x\0y")
        .run()
        .stdout_is("x\0");
}

#[test]
fn test_zero_terminated_syntax_2() {
    new_ucmd!()
        .args(&["-z", "-n", "2"])
        .pipe_in("x\0y")
        .run()
        .stdout_is("x\0y");
}

#[test]
fn test_zero_terminated_negative_lines() {
    new_ucmd!()
        .args(&["-z", "-n", "-1"])
        .pipe_in("x\0y\0z\0")
        .run()
        .stdout_is("x\0y\0");
}

#[test]
fn test_negative_byte_syntax() {
    new_ucmd!()
        .args(&["--bytes=-2"])
        .pipe_in("a\n")
        .run()
        .stdout_is("");
}

#[test]
fn test_negative_zero_lines() {
    new_ucmd!()
        .args(&["--lines=-0"])
        .pipe_in("a\nb\n")
        .succeeds()
        .stdout_is("a\nb\n");
}
#[test]
fn test_negative_zero_bytes() {
    new_ucmd!()
        .args(&["--bytes=-0"])
        .pipe_in("qwerty")
        .succeeds()
        .stdout_is("qwerty");
}
#[test]
fn test_no_such_file_or_directory() {
    new_ucmd!()
        .arg("no_such_file.toml")
        .fails()
        .stderr_contains("cannot open 'no_such_file.toml' for reading: No such file or directory");
}

/// Test that each non-existent files gets its own error message printed.
#[test]
fn test_multiple_nonexistent_files() {
    new_ucmd!()
        .args(&["bogusfile1", "bogusfile2"])
        .fails()
        .stdout_does_not_contain("==> bogusfile1 <==")
        .stderr_contains("cannot open 'bogusfile1' for reading: No such file or directory")
        .stdout_does_not_contain("==> bogusfile2 <==")
        .stderr_contains("cannot open 'bogusfile2' for reading: No such file or directory");
}

// there was a bug not caught by previous tests
// where for negative n > 3, the total amount of lines
// was correct, but it would eat from the second line
#[test]
fn test_sequence_fixture() {
    new_ucmd!()
        .args(&["-n", "-10", "sequence"])
        .run()
        .stdout_is_fixture("sequence.expected");
}
#[test]
fn test_file_backwards() {
    new_ucmd!()
        .args(&["-c", "-10", "lorem_ipsum.txt"])
        .run()
        .stdout_is_fixture("lorem_ipsum_backwards_file.expected");
}

#[test]
fn test_zero_terminated() {
    new_ucmd!()
        .args(&["-z", "zero_terminated.txt"])
        .run()
        .stdout_is_fixture("zero_terminated.expected");
}

#[test]
fn test_obsolete_extras() {
    new_ucmd!()
        .args(&["-5zv"])
        .pipe_in("1\02\03\04\05\06")
        .succeeds()
        .stdout_is("==> standard input <==\n1\02\03\04\05\0");
}

#[test]
fn test_multiple_files() {
    new_ucmd!()
        .args(&["emptyfile.txt", "emptyfile.txt"])
        .succeeds()
        .stdout_is("==> emptyfile.txt <==\n\n==> emptyfile.txt <==\n");
}

#[test]
fn test_multiple_files_with_stdin() {
    new_ucmd!()
        .args(&["emptyfile.txt", "-", "emptyfile.txt"])
        .pipe_in("hello\n")
        .succeeds()
        .stdout_is(
            "==> emptyfile.txt <==

==> standard input <==
hello

==> emptyfile.txt <==
",
        );
}

#[test]
fn test_bad_utf8() {
    let bytes: &[u8] = b"\xfc\x80\x80\x80\x80\xaf";
    new_ucmd!()
        .args(&["-c", "6"])
        .pipe_in(bytes)
        .succeeds()
        .stdout_is_bytes(bytes);
}

#[test]
fn test_bad_utf8_lines() {
    let input: &[u8] =
        b"\xfc\x80\x80\x80\x80\xaf\nb\xfc\x80\x80\x80\x80\xaf\nb\xfc\x80\x80\x80\x80\xaf";
    let output = b"\xfc\x80\x80\x80\x80\xaf\nb\xfc\x80\x80\x80\x80\xaf\n";
    new_ucmd!()
        .args(&["-n", "2"])
        .pipe_in(input)
        .succeeds()
        .stdout_is_bytes(output);
}

#[test]
fn test_head_invalid_num() {
    new_ucmd!()
        .args(&["-c", "1024R", "emptyfile.txt"])
        .fails()
        .stderr_is("head: invalid number of bytes: '1024R'");
    new_ucmd!()
        .args(&["-n", "1024R", "emptyfile.txt"])
        .fails()
        .stderr_is("head: invalid number of lines: '1024R'");
    #[cfg(not(target_pointer_width = "128"))]
    new_ucmd!()
        .args(&["-c", "1Y", "emptyfile.txt"])
        .fails()
        .stderr_is("head: invalid number of bytes: '1Y': Value too large for defined data type");
    #[cfg(not(target_pointer_width = "128"))]
    new_ucmd!()
        .args(&["-n", "1Y", "emptyfile.txt"])
        .fails()
        .stderr_is("head: invalid number of lines: '1Y': Value too large for defined data type");
    #[cfg(target_pointer_width = "32")]
    {
        let sizes = ["1000G", "10T"];
        for size in &sizes {
            new_ucmd!()
                .args(&["-c", size])
                .fails()
                .code_is(1)
                .stderr_only(format!(
                    "head: invalid number of bytes: '{}': Value too large for defined data type",
                    size
                ));
        }
    }
}

#[test]
fn test_head_num_with_undocumented_sign_bytes() {
    // tail: '-' is not documented (8.32 man pages)
    // head: '+' is not documented (8.32 man pages)
    const ALPHABET: &str = "abcdefghijklmnopqrstuvwxyz";
    new_ucmd!()
        .args(&["-c", "5"])
        .pipe_in(ALPHABET)
        .succeeds()
        .stdout_is("abcde");
    new_ucmd!()
        .args(&["-c", "-5"])
        .pipe_in(ALPHABET)
        .succeeds()
        .stdout_is("abcdefghijklmnopqrstu");
    new_ucmd!()
        .args(&["-c", "+5"])
        .pipe_in(ALPHABET)
        .succeeds()
        .stdout_is("abcde");
}
<|endoftext|>


<commit_before>use imp::errno as errno;

const ZMQ_HAUSNUMERO: i32 = 156384712;

pub const EACCES:           i32 = errno::EACCES;
pub const EADDRINUSE:       i32 = errno::EADDRINUSE;
pub const EAGAIN:           i32 = errno::EAGAIN;
pub const EBUSY:            i32 = errno::EBUSY;
pub const ECONNREFUSED:     i32 = errno::ECONNREFUSED;
pub const EFAULT:           i32 = errno::EFAULT;
pub const EINTR:            i32 = errno::EINTR;
pub const EHOSTUNREACH:     i32 = errno::EHOSTUNREACH;
pub const EINPROGRESS:      i32 = errno::EINPROGRESS;
pub const EINVAL:           i32 = errno::EINVAL;
pub const EMFILE:           i32 = errno::EMFILE;
pub const EMSGSIZE:         i32 = errno::EMSGSIZE;
pub const ENAMETOOLONG:     i32 = errno::ENAMETOOLONG;
pub const ENODEV:           i32 = errno::ENODEV;
pub const ENOENT:           i32 = errno::ENOENT;
pub const ENOMEM:           i32 = errno::ENOMEM;
pub const ENOTCONN:         i32 = errno::ENOTCONN;
pub const ENOTSOCK:         i32 = errno::ENOTSOCK;
pub const EPROTO:           i32 = errno::EPROTO;
pub const EPROTONOSUPPORT:  i32 = errno::EPROTONOSUPPORT;

#[cfg(not(target_os = "windows"))]
pub const ENOTSUP:          i32 = (ZMQ_HAUSNUMERO + 1);
#[cfg(target_os = "windows")]
pub const ENOTSUP:          i32 = errno::ENOTSUP;

pub const ENOBUFS:          i32 = errno::ENOBUFS;
pub const ENETDOWN:         i32 = errno::ENETDOWN;
pub const EADDRNOTAVAIL:    i32 = errno::EADDRNOTAVAIL;

// native zmq error codes
pub const EFSM:             i32 = (ZMQ_HAUSNUMERO + 51);
pub const ENOCOMPATPROTO:   i32 = (ZMQ_HAUSNUMERO + 52);
pub const ETERM:            i32 = (ZMQ_HAUSNUMERO + 53);
pub const EMTHREAD:         i32 = (ZMQ_HAUSNUMERO + 54);
<commit_msg>Align EPROTO behaviour with openbsd zmq patchset<commit_after>use imp::errno as errno;

const ZMQ_HAUSNUMERO: i32 = 156384712;

pub const EACCES:           i32 = errno::EACCES;
pub const EADDRINUSE:       i32 = errno::EADDRINUSE;
pub const EAGAIN:           i32 = errno::EAGAIN;
pub const EBUSY:            i32 = errno::EBUSY;
pub const ECONNREFUSED:     i32 = errno::ECONNREFUSED;
pub const EFAULT:           i32 = errno::EFAULT;
pub const EINTR:            i32 = errno::EINTR;
pub const EHOSTUNREACH:     i32 = errno::EHOSTUNREACH;
pub const EINPROGRESS:      i32 = errno::EINPROGRESS;
pub const EINVAL:           i32 = errno::EINVAL;
pub const EMFILE:           i32 = errno::EMFILE;
pub const EMSGSIZE:         i32 = errno::EMSGSIZE;
pub const ENAMETOOLONG:     i32 = errno::ENAMETOOLONG;
pub const ENODEV:           i32 = errno::ENODEV;
pub const ENOENT:           i32 = errno::ENOENT;
pub const ENOMEM:           i32 = errno::ENOMEM;
pub const ENOTCONN:         i32 = errno::ENOTCONN;
pub const ENOTSOCK:         i32 = errno::ENOTSOCK;
#[cfg(not(target_os = "openbsd"))]
pub const EPROTO:           i32 = errno::EPROTO;
#[cfg(target_os = "openbsd")]
pub const EPROTO:           i32 = errno::EOPNOTSUPP;
pub const EPROTONOSUPPORT:  i32 = errno::EPROTONOSUPPORT;

#[cfg(not(target_os = "windows"))]
pub const ENOTSUP:          i32 = (ZMQ_HAUSNUMERO + 1);
#[cfg(target_os = "windows")]
pub const ENOTSUP:          i32 = errno::ENOTSUP;

pub const ENOBUFS:          i32 = errno::ENOBUFS;
pub const ENETDOWN:         i32 = errno::ENETDOWN;
pub const EADDRNOTAVAIL:    i32 = errno::EADDRNOTAVAIL;

// native zmq error codes
pub const EFSM:             i32 = (ZMQ_HAUSNUMERO + 51);
pub const ENOCOMPATPROTO:   i32 = (ZMQ_HAUSNUMERO + 52);
pub const ETERM:            i32 = (ZMQ_HAUSNUMERO + 53);
pub const EMTHREAD:         i32 = (ZMQ_HAUSNUMERO + 54);
<|endoftext|>


<commit_before>extern crate image;
extern crate calx_window;
extern crate calx_cache;
extern crate calx_draw;

use calx_cache::{AtlasBuilder, Atlas, AtlasItem, tilesheet_bounds, subimage};
use calx_window::{WindowBuilder, Window, Event, Key};
use calx_draw::Buffer;

struct Context {
    pub window: Window,
    pub buffer: Buffer,
    pub tiles: Vec<AtlasItem>,
}

impl Context {
    pub fn new() -> Context {
        let window = WindowBuilder::new().set_title("Calx demo").build();
        let mut atlas_builder = AtlasBuilder::new();

        // Solid color as the default element.
        assert!(atlas_builder.push_solid() == Default::default());

        let mut sheet = image::load_from_memory(include_bytes!("../assets/font.png")).unwrap();
        let bounds = tilesheet_bounds(&sheet);

        let Atlas {
            image: img,
            items: tiles,
        } = atlas_builder.build();

        let buffer = Buffer::new(&window.display, img);
        Context {
            window: window,
            buffer: buffer,
            tiles: tiles,
        }
    }
}

fn main() {
    let mut ctx = Context::new();

    'top: loop {
        for e in ctx.window.events().into_iter() {
            match e {
                Event::Quit => break 'top,
                Event::KeyPress(Key::Escape) => break 'top,
                _ => (),
            }
        }

        ctx.window.end_frame();
    }
}
<commit_msg>Initial work on screen drawing with demo<commit_after>extern crate image;
extern crate glium;
extern crate calx_window;
extern crate calx_cache;
extern crate calx_draw;

use std::char;
use glium::Surface;
use calx_cache::{AtlasBuilder, Atlas, AtlasItem, ImageStore, Font};
use calx_window::{WindowBuilder, Window, Event, Key};
use calx_draw::Buffer;

struct Context {
    pub window: Window,
    pub buffer: Buffer,
    pub tiles: Vec<AtlasItem>,
    pub font: Font<usize>,
}

impl Context {
    pub fn new() -> Context {
        let window = WindowBuilder::new().set_title("Calx demo").build();
        let mut atlas_builder = AtlasBuilder::new();

        // Solid color as the default element.
        assert!(atlas_builder.add_solid_image() == Default::default());

        // Load font into atlas.
        const DATA: &'static [u8] = include_bytes!("../assets/font.png");
        let font = Font::new(&mut image::load_from_memory(DATA).unwrap(),
                             &(32..128)
                                  .map(|i| char::from_u32(i).unwrap())
                                  .collect::<String>(),
                             &mut atlas_builder);

        let Atlas {
            image: img,
            items: tiles,
        } = atlas_builder.build();

        let buffer = Buffer::new(&window.display, img);

        Context {
            window: window,
            buffer: buffer,
            tiles: tiles,
            font: font,
        }
    }

    pub fn end_frame(&mut self) {
        let display = self.window.display.clone();
        let buffer = &mut self.buffer;

        self.window.draw(|target| {
            target.clear_color(0.4, 0.6, 0.9, 0.0);
            target.clear_depth(1.0);
            buffer.flush(&display, target);
        });

        self.window.end_frame();
    }
}

fn main() {
    let mut ctx = Context::new();

    'top: loop {
        for e in ctx.window.events().into_iter() {
            match e {
                Event::Quit => break 'top,
                Event::KeyPress(Key::Escape) => break 'top,
                _ => (),
            }
        }

        ctx.end_frame();
    }
}
<|endoftext|>


<commit_before>//! Treiber stacks.

use std::sync::atomic;
use std::ptr;
use {Atomic, Guard};

/// A Treiber stack.
///
/// Treiber stacks are one way to implement concurrent LIFO stack.
///
/// Treiber stacks builds on linked lists. They are lock-free and non-blocking. It can be compared
/// to transactional memory in that it repeats operations, if another thread changes it while.
///
/// The ABA problem is of course addressed through the API of this crate.
pub struct Treiber<T> {
    /// The head node.
    head: Atomic<Node<T>>,
}

impl<T> Drop for Treiber<T> {
    fn drop(&mut self) {
        // Due to the nature of Treiber stacks, there are no active guards of things within the
        // structure. They're all gone, thus we can safely mess with the inner structure.

        unsafe {
            let ptr = *self.head.get_inner_mut().get_mut();

            if !ptr.is_null() {
                // Call destructors on the stack.
                (*ptr).destroy();
                // Finally deallocate the pointer itself.
                drop(Box::from_raw(ptr));
            }
        }
    }
}

impl<T> Treiber<T> {
    /// Create a new, empty Treiber stack.
    pub fn new() -> Treiber<T> {
        Treiber {
            head: Atomic::default(),
        }
    }

    /// Pop an item from the stack.
    // TODO: Change this return type.
    pub fn pop(&self) -> Option<Guard<T>> {
        // TODO: Use `catch {}` here when it lands.
        // Read the head snapshot.
        let mut snapshot = self.head.load(atomic::Ordering::Acquire);

        // Unless the head snapshot is `None`, try to replace it with the tail.
        while let Some(node) = snapshot {
            // Attempt to replace the head with the tail of the head.
            match unsafe {
                self.head.compare_and_swap_raw(
                    node.as_raw(),
                    node.next as *mut Node<T>,
                    atomic::Ordering::Release,
                )
            } {
                // It succeeded; return the item.
                Ok(_) => return Some(node.map(|x| &x.item)),
                // It failed, update the head snapshot and continue.
                Err(new) => snapshot = new,
            }
        }

        // As the head was empty, there is nothing to pop.
        None
    }

    /// Push an item to the stack.
    pub fn push(&self, item: T)
    where T: 'static {
        // Load the head snapshot.
        let mut snapshot = self.head.load(atomic::Ordering::Relaxed);
        let mut snapshot_ptr: Option<*const Node<T>>;

        // TODO: Use `catch {}` here when it lands.
        // Construct a node, which will be the new head.
        let mut node = Box::new(Node {
            item: item,
            // Placeholder; we will replace it with an actual value in the loop.
            next: ptr::null(),
        });

        loop {
            // Derive the nullable snapshot pointer from the head snapshot.
            snapshot_ptr = snapshot.as_ref().map(Guard::as_raw);
            // Construct the next-pointer of the new node from the head snapshot.
            node.next = snapshot_ptr.unwrap_or(ptr::null());

            // TODO: This should be something that ignores the guard creation when the CAS
            //       succeeds, because it's expensive to do and not used anyway. It should be easy
            //       enough to implement, but I am struggling to come up with a good name for the
            //       method.

            // CAS from the read pointer to the new head.
            match self.head.compare_and_swap(snapshot_ptr, Some(node), atomic::Ordering::Release) {
                // If it succeeds, the item has been pushed.
                Ok(_) => break,
                // If it fails, we will retry the CAS with updated values.
                Err((new_head, Some(node2))) => {
                    // Update the head snapshot.
                    snapshot = new_head;
                    // Put the box we gave back to the variable where it belongs.
                    node = node2;
                },
                // This should never be reached as we gave an argument which was unconditionally
                // `Some`.
                _ => unreachable!(),
            }
        }
    }
}

/// A node in the stack.
struct Node<T> {
    /// The data this node holds.
    item: T,
    /// The next node.
    next: *const Node<T>,
}

impl<T> Node<T> {
    /// Destroy the node and its precessors.
    ///
    /// # Safety
    ///
    /// As this can be called multiple times, it is marked unsafe.
    unsafe fn destroy(&mut self) {
        // FIXME: Since this is recursive (and although it is likely optimized out), there might be
        //        cases where this leads to stack overflow, given correct compilation flags and
        //        sufficiently many elements.

        // Recursively drop the next node, if it exists.
        if !self.next.is_null() {
            drop(Box::from_raw(self.next as *mut Node<T>));
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;
    use std::sync::Arc;
    use std::sync::atomic::AtomicUsize;

    #[derive(Clone)]
    struct Dropper {
        d: Arc<AtomicUsize>,
    }

    impl Drop for Dropper {
        fn drop(&mut self) {
            self.d.fetch_add(1, atomic::Ordering::Relaxed);
        }
    }

    #[test]
    fn simple1() {
        let stack = Treiber::new();

        stack.push(1);
        stack.push(200);
        stack.push(44);

        assert_eq!(*stack.pop().unwrap(), 44);
        assert_eq!(*stack.pop().unwrap(), 200);
        assert_eq!(*stack.pop().unwrap(), 1);
        assert!(stack.pop().is_none());

        ::gc();
    }

    #[test]
    fn simple2() {
        let stack = Treiber::new();

        for _ in 0..16 {
            stack.push(1);
            stack.push(200);
            stack.push(44);

            assert_eq!(*stack.pop().unwrap(), 44);
            assert_eq!(*stack.pop().unwrap(), 200);
            stack.push(20000);

            assert_eq!(*stack.pop().unwrap(), 20000);
            assert_eq!(*stack.pop().unwrap(), 1);

            assert!(stack.pop().is_none());
            assert!(stack.pop().is_none());
            assert!(stack.pop().is_none());
            assert!(stack.pop().is_none());
        }

        ::gc();
    }

    #[test]
    fn simple3() {
        let stack = Treiber::new();

        for i in 0..10000 {
            stack.push(i);
        }

        for i in (0..10000).rev() {
            assert_eq!(*stack.pop().unwrap(), i);
        }

        for i in 0..10000 {
            stack.push(i);
        }

        for i in (0..10000).rev() {
            assert_eq!(*stack.pop().unwrap(), i);
        }

        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
    }

    #[test]
    fn push_pop() {
        let stack = Arc::new(Treiber::new());
        let mut j = Vec::new();
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for _ in 0..10_000_000 {
                    s.push(23);
                    assert_eq!(*s.pop().unwrap(), 23);
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }
    }

    #[test]
    fn increment() {
        let stack = Arc::new(Treiber::<u64>::new());
        stack.push(0);
        let mut j = Vec::new();

        // 16 times, we add the numbers from 0 to 1000 to the only element in the stack.
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for n in 0..1001 {
                    loop {
                        if let Some(x) = s.pop() {
                            s.push(*x + n);
                            break;
                        }
                    }
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }

        assert_eq!(*stack.pop().unwrap(), 16 * 1000 * 1001 / 2);
    }

    #[test]
    fn sum() {
        let stack = Arc::new(Treiber::<i64>::new());
        let mut j = Vec::new();

        for _ in 0..1000 {
            stack.push(10);
        }

        // We preserve the sum of the stack's elements.
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for _ in 0..100000 {
                    loop {
                        if let Some(a) = s.pop() {
                            loop {
                                if let Some(b) = s.pop() {
                                    s.push(*a + 1);
                                    s.push(*b - 1);

                                    break;
                                }
                            }

                            break;
                        }
                    }
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }

        let mut sum = 0;
        while let Some(x) = stack.pop() {
            sum += *x;
        }
        assert_eq!(sum, 10000);
    }

    #[test]
    fn drop() {
        let drops = Arc::new(AtomicUsize::default());
        let stack = Arc::new(Treiber::new());

        let d = Dropper {
            d: drops.clone(),
        };

        let mut j = Vec::new();
        for _ in 0..16 {
            let d = d.clone();
            let stack = stack.clone();

            j.push(thread::spawn(move || {
                for _ in 0..20 {
                    stack.push(d.clone());
                }

                stack.pop();
                stack.pop();
            }))
        }

        for i in j {
            i.join().unwrap();
        }

        ::gc();
        // The 16 are for the `d` variable in the loop above.
        assert_eq!(drops.load(atomic::Ordering::Relaxed), 32 + 16);

        // Drop the last arc.
        let _ = stack;
        ::gc();

        assert_eq!(drops.load(atomic::Ordering::Relaxed), 200 + 16);
    }
}
<commit_msg>Ensure that `conc::Treiber::drop` doesnt cause double-drop of the inner.<commit_after>//! Treiber stacks.

use std::sync::atomic;
use std::ptr;
use {Atomic, Guard};

/// A Treiber stack.
///
/// Treiber stacks are one way to implement concurrent LIFO stack.
///
/// Treiber stacks builds on linked lists. They are lock-free and non-blocking. It can be compared
/// to transactional memory in that it repeats operations, if another thread changes it while.
///
/// The ABA problem is of course addressed through the API of this crate.
pub struct Treiber<T> {
    /// The head node.
    head: Atomic<Node<T>>,
}

impl<T> Drop for Treiber<T> {
    fn drop(&mut self) {
        // Due to the nature of Treiber stacks, there are no active guards of things within the
        // structure. They're all gone, thus we can safely mess with the inner structure.

        unsafe {
            let ptr = self.head.get_inner_mut().get_mut();

            if !ptr.is_null() {
                // Call destructors on the stack.
                (**ptr).destroy();
                // Finally deallocate the pointer itself.
                drop(Box::from_raw(*ptr));
                // Set it to null to prevent `Atomic`'s destructor from running.
                *ptr = ptr::null_mut();
            }
        }
    }
}

impl<T> Treiber<T> {
    /// Create a new, empty Treiber stack.
    pub fn new() -> Treiber<T> {
        Treiber {
            head: Atomic::default(),
        }
    }

    /// Pop an item from the stack.
    // TODO: Change this return type.
    pub fn pop(&self) -> Option<Guard<T>> {
        // TODO: Use `catch {}` here when it lands.
        // Read the head snapshot.
        let mut snapshot = self.head.load(atomic::Ordering::Acquire);

        // Unless the head snapshot is `None`, try to replace it with the tail.
        while let Some(node) = snapshot {
            // Attempt to replace the head with the tail of the head.
            match unsafe {
                self.head.compare_and_swap_raw(
                    node.as_raw(),
                    node.next as *mut Node<T>,
                    atomic::Ordering::Release,
                )
            } {
                // It succeeded; return the item.
                Ok(_) => return Some(node.map(|x| &x.item)),
                // It failed, update the head snapshot and continue.
                Err(new) => snapshot = new,
            }
        }

        // As the head was empty, there is nothing to pop.
        None
    }

    /// Push an item to the stack.
    pub fn push(&self, item: T)
    where T: 'static {
        // Load the head snapshot.
        let mut snapshot = self.head.load(atomic::Ordering::Relaxed);
        let mut snapshot_ptr: Option<*const Node<T>>;

        // TODO: Use `catch {}` here when it lands.
        // Construct a node, which will be the new head.
        let mut node = Box::new(Node {
            item: item,
            // Placeholder; we will replace it with an actual value in the loop.
            next: ptr::null(),
        });

        loop {
            // Derive the nullable snapshot pointer from the head snapshot.
            snapshot_ptr = snapshot.as_ref().map(Guard::as_raw);
            // Construct the next-pointer of the new node from the head snapshot.
            node.next = snapshot_ptr.unwrap_or(ptr::null());

            // TODO: This should be something that ignores the guard creation when the CAS
            //       succeeds, because it's expensive to do and not used anyway. It should be easy
            //       enough to implement, but I am struggling to come up with a good name for the
            //       method.

            // CAS from the read pointer to the new head.
            match self.head.compare_and_swap(snapshot_ptr, Some(node), atomic::Ordering::Release) {
                // If it succeeds, the item has been pushed.
                Ok(_) => break,
                // If it fails, we will retry the CAS with updated values.
                Err((new_head, Some(node2))) => {
                    // Update the head snapshot.
                    snapshot = new_head;
                    // Put the box we gave back to the variable where it belongs.
                    node = node2;
                },
                // This should never be reached as we gave an argument which was unconditionally
                // `Some`.
                _ => unreachable!(),
            }
        }
    }
}

/// A node in the stack.
struct Node<T> {
    /// The data this node holds.
    item: T,
    /// The next node.
    next: *const Node<T>,
}

impl<T> Node<T> {
    /// Destroy the node and its precessors.
    ///
    /// # Safety
    ///
    /// As this can be called multiple times, it is marked unsafe.
    unsafe fn destroy(&mut self) {
        // FIXME: Since this is recursive (and although it is likely optimized out), there might be
        //        cases where this leads to stack overflow, given correct compilation flags and
        //        sufficiently many elements.

        // Recursively drop the next node, if it exists.
        if !self.next.is_null() {
            drop(Box::from_raw(self.next as *mut Node<T>));
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;
    use std::sync::Arc;
    use std::sync::atomic::AtomicUsize;

    #[derive(Clone)]
    struct Dropper {
        d: Arc<AtomicUsize>,
    }

    impl Drop for Dropper {
        fn drop(&mut self) {
            self.d.fetch_add(1, atomic::Ordering::Relaxed);
        }
    }

    #[test]
    fn simple1() {
        let stack = Treiber::new();

        stack.push(1);
        stack.push(200);
        stack.push(44);

        assert_eq!(*stack.pop().unwrap(), 44);
        assert_eq!(*stack.pop().unwrap(), 200);
        assert_eq!(*stack.pop().unwrap(), 1);
        assert!(stack.pop().is_none());

        ::gc();
    }

    #[test]
    fn simple2() {
        let stack = Treiber::new();

        for _ in 0..16 {
            stack.push(1);
            stack.push(200);
            stack.push(44);

            assert_eq!(*stack.pop().unwrap(), 44);
            assert_eq!(*stack.pop().unwrap(), 200);
            stack.push(20000);

            assert_eq!(*stack.pop().unwrap(), 20000);
            assert_eq!(*stack.pop().unwrap(), 1);

            assert!(stack.pop().is_none());
            assert!(stack.pop().is_none());
            assert!(stack.pop().is_none());
            assert!(stack.pop().is_none());
        }

        ::gc();
    }

    #[test]
    fn simple3() {
        let stack = Treiber::new();

        for i in 0..10000 {
            stack.push(i);
        }

        for i in (0..10000).rev() {
            assert_eq!(*stack.pop().unwrap(), i);
        }

        for i in 0..10000 {
            stack.push(i);
        }

        for i in (0..10000).rev() {
            assert_eq!(*stack.pop().unwrap(), i);
        }

        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
    }

    #[test]
    fn push_pop() {
        let stack = Arc::new(Treiber::new());
        let mut j = Vec::new();
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for _ in 0..10_000_000 {
                    s.push(23);
                    assert_eq!(*s.pop().unwrap(), 23);
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }
    }

    #[test]
    fn increment() {
        let stack = Arc::new(Treiber::<u64>::new());
        stack.push(0);
        let mut j = Vec::new();

        // 16 times, we add the numbers from 0 to 1000 to the only element in the stack.
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for n in 0..1001 {
                    loop {
                        if let Some(x) = s.pop() {
                            s.push(*x + n);
                            break;
                        }
                    }
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }

        assert_eq!(*stack.pop().unwrap(), 16 * 1000 * 1001 / 2);
    }

    #[test]
    fn sum() {
        let stack = Arc::new(Treiber::<i64>::new());
        let mut j = Vec::new();

        for _ in 0..1000 {
            stack.push(10);
        }

        // We preserve the sum of the stack's elements.
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for _ in 0..100000 {
                    loop {
                        if let Some(a) = s.pop() {
                            loop {
                                if let Some(b) = s.pop() {
                                    s.push(*a + 1);
                                    s.push(*b - 1);

                                    break;
                                }
                            }

                            break;
                        }
                    }
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }

        let mut sum = 0;
        while let Some(x) = stack.pop() {
            sum += *x;
        }
        assert_eq!(sum, 10000);
    }

    #[test]
    fn drop() {
        let drops = Arc::new(AtomicUsize::default());
        let stack = Arc::new(Treiber::new());

        let d = Dropper {
            d: drops.clone(),
        };

        let mut j = Vec::new();
        for _ in 0..16 {
            let d = d.clone();
            let stack = stack.clone();

            j.push(thread::spawn(move || {
                for _ in 0..20 {
                    stack.push(d.clone());
                }

                stack.pop();
                stack.pop();
            }))
        }

        for i in j {
            i.join().unwrap();
        }

        ::gc();
        // The 16 are for the `d` variable in the loop above.
        assert_eq!(drops.load(atomic::Ordering::Relaxed), 32 + 16);

        // Drop the last arc.
        let _ = stack;
        ::gc();

        assert_eq!(drops.load(atomic::Ordering::Relaxed), 200 + 16);
    }
}
<|endoftext|>


<commit_before>#![feature(test, i128_type)]

extern crate test;
use test::Bencher;

extern crate rand;
extern crate speck;

use rand::Rng;

use rand::OsRng;

use speck::Key;

#[bench]
fn encrypt(mut bencher: &mut Bencher) {
    let (key, block) = gen_test();

    bencher.iter(|| test::black_box(key.encrypt_block(block)));
}

#[bench]
fn decrypt(mut bencher: &mut Bencher) {
    let (key, block) = gen_test();

    bencher.iter(|| test::black_box(key.decrypt_block(block)));
}

fn gen_test() -> (Key, u128) {
    let mut rng = OsRng::new().unwrap();

    (Key::new(rng.gen()), rng.gen())
}
<commit_msg>Fixed last commit.<commit_after>#![feature(test, i128_type)]

extern crate test;
use test::Bencher;

extern crate rand;
extern crate speck;

use rand::Rng;
use rand::OsRng;

use speck::Key;

#[bench]
fn encrypt(mut bencher: &mut Bencher) {
    let (key, block) = gen_test();

    bencher.iter(|| test::black_box(key.encrypt_block(block)));
}

#[bench]
fn decrypt(mut bencher: &mut Bencher) {
    let (key, block) = gen_test();

    bencher.iter(|| test::black_box(key.decrypt_block(block)));
}

fn gen_test() -> (Key, u128) {
    let mut rng = OsRng::new().unwrap();

    (Key::new(rng.gen()), rng.gen())
}
<|endoftext|>


<commit_before>// Copyright 2018 The Grin Developers
// 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.

//! Logging wrapper to be used throughout all crates in the workspace
use std::ops::Deref;
use Mutex;

use backtrace::Backtrace;
use std::{panic, thread};

use types::{LogLevel, LoggingConfig};

use log::{LevelFilter, Record};
use log4rs;
use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender;
use log4rs::append::rolling_file::{
	policy::compound::roll::fixed_window::FixedWindowRoller,
	policy::compound::trigger::size::SizeTrigger, policy::compound::CompoundPolicy,
	RollingFileAppender,
};
use log4rs::append::Append;
use log4rs::config::{Appender, Config, Root};
use log4rs::encode::pattern::PatternEncoder;
use log4rs::filter::{threshold::ThresholdFilter, Filter, Response};

fn convert_log_level(in_level: &LogLevel) -> LevelFilter {
	match *in_level {
		LogLevel::Info => LevelFilter::Info,
		LogLevel::Warning => LevelFilter::Warn,
		LogLevel::Debug => LevelFilter::Debug,
		LogLevel::Trace => LevelFilter::Trace,
		LogLevel::Error => LevelFilter::Error,
	}
}

lazy_static! {
	/// Flag to observe whether logging was explicitly initialised (don't output otherwise)
	static ref WAS_INIT: Mutex<bool> = Mutex::new(false);
	/// Flag to observe whether tui is running, and we therefore don't want to attempt to write
	/// panics to stdout
	static ref TUI_RUNNING: Mutex<bool> = Mutex::new(false);
	/// Static Logging configuration, should only be set once, before first logging call
	static ref LOGGING_CONFIG: Mutex<LoggingConfig> = Mutex::new(LoggingConfig::default());
}

/// This filter is rejecting messages that doesn't start with "grin"
/// in order to save log space for only Grin-related records
#[derive(Debug)]
struct GrinFilter;

impl Filter for GrinFilter {
	fn filter(&self, record: &Record) -> Response {
		if let Some(module_path) = record.module_path() {
			if module_path.starts_with("grin") {
				return Response::Neutral;
			}
		}

		Response::Reject
	}
}

/// Initialize the logger with the given configuration
pub fn init_logger(config: Option<LoggingConfig>) {
	if let Some(c) = config {
		let level_stdout = convert_log_level(&c.stdout_log_level);
		let level_file = convert_log_level(&c.file_log_level);
		let level_minimum;

		// Determine minimum logging level for Root logger
		if level_stdout > level_file {
			level_minimum = level_stdout;
		} else {
			level_minimum = level_file;
		}

		// Start logger
		let stdout = ConsoleAppender::builder()
			.encoder(Box::new(PatternEncoder::default()))
			.build();

		let mut root = Root::builder();

		let mut appenders = vec![];

		if c.log_to_stdout {
			let filter = Box::new(ThresholdFilter::new(level_stdout));
			appenders.push(
				Appender::builder()
					.filter(filter)
					.filter(Box::new(GrinFilter))
					.build("stdout", Box::new(stdout)),
			);

			root = root.appender("stdout");
		}

		if c.log_to_file {
			// If maximum log size is specified, use rolling file appender
			// or use basic one otherwise
			let filter = Box::new(ThresholdFilter::new(level_file));
			let file: Box<Append> = {
				if let Some(size) = c.log_max_size {
					let roller = FixedWindowRoller::builder()
						.build(&format!("{}.{{}}.gz", c.log_file_path), 32)
						.unwrap();
					let trigger = SizeTrigger::new(size);

					let policy = CompoundPolicy::new(Box::new(trigger), Box::new(roller));

					Box::new(
						RollingFileAppender::builder()
							.append(c.log_file_append)
							.encoder(Box::new(PatternEncoder::new("{d} {l} {M} - {m}{n}")))
							.build(c.log_file_path, Box::new(policy))
							.unwrap(),
					)
				} else {
					Box::new(
						FileAppender::builder()
							.append(c.log_file_append)
							.encoder(Box::new(PatternEncoder::new("{d} {l} {M} - {m}{n}")))
							.build(c.log_file_path)
							.unwrap(),
					)
				}
			};

			appenders.push(
				Appender::builder()
					.filter(filter)
					.filter(Box::new(GrinFilter))
					.build("file", file),
			);
			root = root.appender("file");
		}

		let config = Config::builder()
			.appenders(appenders)
			.build(root.build(level_minimum))
			.unwrap();

		let _ = log4rs::init_config(config).unwrap();

		info!(
			"log4rs is initialized, file level: {:?}, stdout level: {:?}, min. level: {:?}",
			level_file, level_stdout, level_minimum
		);

		// Logger configuration successfully injected into LOGGING_CONFIG...
		let mut was_init_ref = WAS_INIT.lock();
		*was_init_ref = true;
	}
	send_panic_to_log();
}

/// Initializes the logger for unit and integration tests
pub fn init_test_logger() {
	let mut was_init_ref = WAS_INIT.lock();
	if *was_init_ref.deref() {
		return;
	}
	let mut logger = LoggingConfig::default();
	logger.log_to_file = false;
	logger.stdout_log_level = LogLevel::Debug;
	let mut config_ref = LOGGING_CONFIG.lock();
	*config_ref = logger;
	*was_init_ref = true;
}

/// hook to send panics to logs as well as stderr
fn send_panic_to_log() {
	panic::set_hook(Box::new(|info| {
		let backtrace = Backtrace::new();

		let thread = thread::current();
		let thread = thread.name().unwrap_or("unnamed");

		let msg = match info.payload().downcast_ref::<&'static str>() {
			Some(s) => *s,
			None => match info.payload().downcast_ref::<String>() {
				Some(s) => &**s,
				None => "Box<Any>",
			},
		};

		match info.location() {
			Some(location) => {
				error!(
					"\nthread '{}' panicked at '{}': {}:{}{:?}\n\n",
					thread,
					msg,
					location.file(),
					location.line(),
					backtrace
				);
			}
			None => error!("thread '{}' panicked at '{}'{:?}", thread, msg, backtrace),
		}
		//also print to stderr
		let tui_running = TUI_RUNNING.lock().clone();
		if !tui_running {
			eprintln!(
				"Thread '{}' panicked with message:\n\"{}\"\nSee grin.log for further details.",
				thread, msg
			);
		}
	}));
}
<commit_msg>Fix path to log file in panic message (#1815)<commit_after>// Copyright 2018 The Grin Developers
// 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.

//! Logging wrapper to be used throughout all crates in the workspace
use std::ops::Deref;
use Mutex;

use backtrace::Backtrace;
use std::{panic, thread};

use types::{LogLevel, LoggingConfig};

use log::{LevelFilter, Record};
use log4rs;
use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender;
use log4rs::append::rolling_file::{
	policy::compound::roll::fixed_window::FixedWindowRoller,
	policy::compound::trigger::size::SizeTrigger, policy::compound::CompoundPolicy,
	RollingFileAppender,
};
use log4rs::append::Append;
use log4rs::config::{Appender, Config, Root};
use log4rs::encode::pattern::PatternEncoder;
use log4rs::filter::{threshold::ThresholdFilter, Filter, Response};

fn convert_log_level(in_level: &LogLevel) -> LevelFilter {
	match *in_level {
		LogLevel::Info => LevelFilter::Info,
		LogLevel::Warning => LevelFilter::Warn,
		LogLevel::Debug => LevelFilter::Debug,
		LogLevel::Trace => LevelFilter::Trace,
		LogLevel::Error => LevelFilter::Error,
	}
}

lazy_static! {
	/// Flag to observe whether logging was explicitly initialised (don't output otherwise)
	static ref WAS_INIT: Mutex<bool> = Mutex::new(false);
	/// Flag to observe whether tui is running, and we therefore don't want to attempt to write
	/// panics to stdout
	static ref TUI_RUNNING: Mutex<bool> = Mutex::new(false);
	/// Static Logging configuration, should only be set once, before first logging call
	static ref LOGGING_CONFIG: Mutex<LoggingConfig> = Mutex::new(LoggingConfig::default());
}

/// This filter is rejecting messages that doesn't start with "grin"
/// in order to save log space for only Grin-related records
#[derive(Debug)]
struct GrinFilter;

impl Filter for GrinFilter {
	fn filter(&self, record: &Record) -> Response {
		if let Some(module_path) = record.module_path() {
			if module_path.starts_with("grin") {
				return Response::Neutral;
			}
		}

		Response::Reject
	}
}

/// Initialize the logger with the given configuration
pub fn init_logger(config: Option<LoggingConfig>) {
	if let Some(c) = config {
		// Save current logging configuration
		let mut config_ref = LOGGING_CONFIG.lock();
		*config_ref = c.clone();

		let level_stdout = convert_log_level(&c.stdout_log_level);
		let level_file = convert_log_level(&c.file_log_level);
		let level_minimum;

		// Determine minimum logging level for Root logger
		if level_stdout > level_file {
			level_minimum = level_stdout;
		} else {
			level_minimum = level_file;
		}

		// Start logger
		let stdout = ConsoleAppender::builder()
			.encoder(Box::new(PatternEncoder::default()))
			.build();

		let mut root = Root::builder();

		let mut appenders = vec![];

		if c.log_to_stdout {
			let filter = Box::new(ThresholdFilter::new(level_stdout));
			appenders.push(
				Appender::builder()
					.filter(filter)
					.filter(Box::new(GrinFilter))
					.build("stdout", Box::new(stdout)),
			);

			root = root.appender("stdout");
		}

		if c.log_to_file {
			// If maximum log size is specified, use rolling file appender
			// or use basic one otherwise
			let filter = Box::new(ThresholdFilter::new(level_file));
			let file: Box<Append> = {
				if let Some(size) = c.log_max_size {
					let roller = FixedWindowRoller::builder()
						.build(&format!("{}.{{}}.gz", c.log_file_path), 32)
						.unwrap();
					let trigger = SizeTrigger::new(size);

					let policy = CompoundPolicy::new(Box::new(trigger), Box::new(roller));

					Box::new(
						RollingFileAppender::builder()
							.append(c.log_file_append)
							.encoder(Box::new(PatternEncoder::new("{d} {l} {M} - {m}{n}")))
							.build(c.log_file_path, Box::new(policy))
							.unwrap(),
					)
				} else {
					Box::new(
						FileAppender::builder()
							.append(c.log_file_append)
							.encoder(Box::new(PatternEncoder::new("{d} {l} {M} - {m}{n}")))
							.build(c.log_file_path)
							.unwrap(),
					)
				}
			};

			appenders.push(
				Appender::builder()
					.filter(filter)
					.filter(Box::new(GrinFilter))
					.build("file", file),
			);
			root = root.appender("file");
		}

		let config = Config::builder()
			.appenders(appenders)
			.build(root.build(level_minimum))
			.unwrap();

		let _ = log4rs::init_config(config).unwrap();

		info!(
			"log4rs is initialized, file level: {:?}, stdout level: {:?}, min. level: {:?}",
			level_file, level_stdout, level_minimum
		);

		// Mark logger as initialized
		let mut was_init_ref = WAS_INIT.lock();
		*was_init_ref = true;
	}

	send_panic_to_log();
}

/// Initializes the logger for unit and integration tests
pub fn init_test_logger() {
	let mut was_init_ref = WAS_INIT.lock();
	if *was_init_ref.deref() {
		return;
	}
	let mut logger = LoggingConfig::default();
	logger.log_to_file = false;
	logger.stdout_log_level = LogLevel::Debug;
	let mut config_ref = LOGGING_CONFIG.lock();
	*config_ref = logger;
	*was_init_ref = true;
}

/// hook to send panics to logs as well as stderr
fn send_panic_to_log() {
	panic::set_hook(Box::new(|info| {
		let backtrace = Backtrace::new();

		let thread = thread::current();
		let thread = thread.name().unwrap_or("unnamed");

		let msg = match info.payload().downcast_ref::<&'static str>() {
			Some(s) => *s,
			None => match info.payload().downcast_ref::<String>() {
				Some(s) => &**s,
				None => "Box<Any>",
			},
		};

		match info.location() {
			Some(location) => {
				error!(
					"\nthread '{}' panicked at '{}': {}:{}{:?}\n\n",
					thread,
					msg,
					location.file(),
					location.line(),
					backtrace
				);
			}
			None => error!("thread '{}' panicked at '{}'{:?}", thread, msg, backtrace),
		}
		//also print to stderr
		let tui_running = TUI_RUNNING.lock().clone();
		if !tui_running {
			let config = LOGGING_CONFIG.lock();

			eprintln!(
				"Thread '{}' panicked with message:\n\"{}\"\nSee {} for further details.",
				thread, msg, config.log_file_path
			);
		}
	}));
}
<|endoftext|>


<commit_before>//
// Copyright 2018 The Project Oak Authors
//
// 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.
//

use byteorder::{ReadBytesExt, WriteBytesExt};
use log::{debug, error};
use protobuf::ProtobufEnum;
use serde::{Deserialize, Serialize};

// Re-export ABI constants that are also visible as part of the SDK API.
pub use oak_abi::{ChannelReadStatus, OakStatus};

pub mod grpc;
pub mod io;
pub mod proto;
pub mod rand;
pub mod storage;

#[cfg(test)]
mod tests;

#[cfg(test)]
use assert_matches::assert_matches;
#[cfg(test)]
use serial_test_derive::serial;

/// Handle used to identify read or write channel halves.
///
/// These handles are used for all host function calls.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Handle {
    id: u64,
}

/// Serialize a `Handle` as the invalid handle value.
impl serde::Serialize for Handle {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_u64(oak_abi::INVALID_HANDLE)
    }
}

struct HandleVisitor;

/// Deserialize a `Handle` as the invalid handle value. Most likely, it will have been serialized to
/// an invalid handle in the first place anyways, but we are being extra cautions and even if the
/// serialized value was modified, we make sure that the resulting `Handle` is invalid.
impl<'de> serde::de::Visitor<'de> for HandleVisitor {
    type Value = Handle;
    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        formatter.write_str("a handle type")
    }

    fn visit_u64<E>(self, _v: u64) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(Handle::invalid())
    }
}

impl<'de> serde::Deserialize<'de> for Handle {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_u64(HandleVisitor)
    }
}

impl Handle {
    /// When using the Oak SDK, this method should not need to be called directly
    /// as `Handles` are directly provided via functions such as `channel_create`.
    pub fn from_raw(id: u64) -> Handle {
        Handle { id }
    }

    /// Check this handle is valid.
    pub fn is_valid(self) -> bool {
        self.id != oak_abi::INVALID_HANDLE
    }

    /// Returns an intentionally invalid handle.
    pub fn invalid() -> Handle {
        Handle {
            id: oak_abi::INVALID_HANDLE,
        }
    }

    /// Pack a slice of `Handles` into the Wasm host ABI format.
    fn pack(handles: &[Handle]) -> Vec<u8> {
        let mut packed = Vec::with_capacity(handles.len() * 8);
        for handle in handles {
            packed
                .write_u64::<byteorder::LittleEndian>(handle.id)
                .unwrap();
        }
        packed
    }

    /// Unpack a slice of Handles from the Wasm host ABI format.
    fn unpack(bytes: &[u8], handle_count: u32, handles: &mut Vec<Handle>) {
        handles.clear();
        let mut reader = std::io::Cursor::new(bytes);
        for _ in 0..handle_count {
            handles.push(Handle {
                id: reader.read_u64::<byteorder::LittleEndian>().unwrap(),
            });
        }
    }
}

/// Wrapper for a handle to the read half of a channel.
///
/// For use when the underlying [`Handle`] is known to be for a receive half.
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub struct ReadHandle {
    pub handle: Handle,
}

/// Wrapper for a handle to the send half of a channel.
///
/// For use when the underlying [`Handle`] is known to be for a send half.
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub struct WriteHandle {
    pub handle: Handle,
}

// Build a chunk of memory that is suitable for passing to oak_abi::wait_on_channels,
// holding the given collection of channel handles.
fn new_handle_space(handles: &[ReadHandle]) -> Vec<u8> {
    let mut space = Vec::with_capacity(oak_abi::SPACE_BYTES_PER_HANDLE * handles.len());
    for handle in handles {
        space
            .write_u64::<byteorder::LittleEndian>(handle.handle.id)
            .unwrap();
        space.push(0x00);
    }
    space
}

// Prepare a handle space for polling by clearing all of the message-pending
// indicator bytes.
fn prep_handle_space(space: &mut [u8]) {
    let count = space.len() / 8;
    for i in 0..count {
        space[i * oak_abi::SPACE_BYTES_PER_HANDLE + (oak_abi::SPACE_BYTES_PER_HANDLE - 1)] = 0;
    }
}

/// Wait for one or more of the provided handles to become ready for reading
/// from.  On success, the returned vector of [`ChannelReadStatus`] values
/// will be in 1-1 correspondence with the passed-in vector of [`Handle`]s.
///
/// This is a convenience wrapper around the [`oak_abi::wait_on_channels`] host
/// function. This version is easier to use in Rust but is less efficient
/// (because the notification space is re-created on each invocation).
pub fn wait_on_channels(handles: &[ReadHandle]) -> Result<Vec<ChannelReadStatus>, OakStatus> {
    let mut space = new_handle_space(handles);
    unsafe {
        let status = oak_abi::wait_on_channels(space.as_mut_ptr(), handles.len() as u32);
        match OakStatus::from_i32(status as i32) {
            Some(OakStatus::OK) => (),
            Some(err) => return Err(err),
            None => return Err(OakStatus::OAK_STATUS_UNSPECIFIED),
        }
        let mut results = Vec::with_capacity(handles.len());
        for i in 0..handles.len() {
            match space
                .get(i * oak_abi::SPACE_BYTES_PER_HANDLE + (oak_abi::SPACE_BYTES_PER_HANDLE - 1))
                .cloned()
                .map(i32::from)
                .and_then(ChannelReadStatus::from_i32)
            {
                Some(status) => results.push(status),
                None => return Err(OakStatus::OAK_STATUS_UNSPECIFIED),
            }
        }
        Ok(results)
    }
}

/// Read a message from a channel without blocking.
///
/// It also returns an error if the underlying channel is empty (i.e. not ready to read).
///
/// The provided vectors for received data and associated handles will be
/// resized to accomodate the information in the message; any data already
/// held in the vectors will be overwritten.
pub fn channel_read(
    half: ReadHandle,
    buf: &mut Vec<u8>,
    handles: &mut Vec<Handle>,
) -> Result<(), OakStatus> {
    // Try reading from the channel twice: first with provided vectors, making
    // use of their available capacity, then with vectors whose capacity has
    // been extended to meet size requirements.

    // We cannot deserialize directly into the handles vector because `Handle`
    // may not have the correct memory layout, so create a separate buffer with
    // equivalent capacity.
    let mut handles_buf = Vec::with_capacity(handles.capacity() * 8);
    for resized in &[false, true] {
        let mut actual_size: u32 = 0;
        let mut actual_handle_count: u32 = 0;
        let status = OakStatus::from_i32(unsafe {
            oak_abi::channel_read(
                half.handle.id,
                buf.as_mut_ptr(),
                buf.capacity(),
                &mut actual_size,
                handles_buf.as_mut_ptr(),
                handles_buf.capacity() as u32 / 8, // Handle count, not byte count
                &mut actual_handle_count,
            ) as i32
        });

        match status {
            Some(s) => match s {
                OakStatus::OK | OakStatus::ERR_CHANNEL_EMPTY => {
                    unsafe {
                        // The read operation succeeded, and overwrote some fraction
                        // of the vectors' available capacity with returned data (possibly
                        // zero).  As the data is already present in the vectors, set
                        // their length to match what's available.
                        buf.set_len(actual_size as usize);
                        // actual_handle_count is number of handles not bytes
                        handles_buf.set_len(actual_handle_count as usize * 8);
                    }
                    Handle::unpack(&handles_buf, actual_handle_count, handles);
                    if s == OakStatus::OK {
                        return Ok(());
                    } else {
                        return Err(s);
                    }
                }

                OakStatus::ERR_BUFFER_TOO_SMALL | OakStatus::ERR_HANDLE_SPACE_TOO_SMALL
                    if !(*resized) =>
                {
                    // Extend the vectors to be large enough for the message
                    debug!(
                        "Got space for {} bytes, need {}",
                        buf.capacity(),
                        actual_size
                    );
                    if (actual_size as usize) > buf.capacity() {
                        let extra = (actual_size as usize) - buf.len();
                        buf.reserve(extra);
                    }

                    let handles_capacity = handles_buf.capacity() / 8;
                    debug!(
                        "Got space for {} handles, need {}",
                        handles_capacity, actual_handle_count
                    );
                    if (actual_handle_count as usize) > handles_capacity {
                        let extra = (actual_handle_count as usize * 8) - handles_buf.len();
                        handles_buf.reserve(extra);
                    }

                    // Try again with a buffer resized to cope with expected size of data.
                    continue;
                }

                s => {
                    return Err(s);
                }
            },
            None => {
                return Err(OakStatus::ERR_INTERNAL);
            }
        }
    }
    error!("unreachable code reached");
    Err(OakStatus::ERR_INTERNAL)
}

/// Write a message to a channel.
pub fn channel_write(half: WriteHandle, buf: &[u8], handles: &[Handle]) -> Result<(), OakStatus> {
    let handle_buf = Handle::pack(handles);
    let status = OakStatus::from_i32(unsafe {
        oak_abi::channel_write(
            half.handle.id,
            buf.as_ptr(),
            buf.len(),
            handle_buf.as_ptr(),
            handles.len() as u32, // Number of handles, not bytes
        ) as i32
    });
    result_from_status(status, ())
}

/// Create a new unidirectional channel.
///
/// On success, returns [`WriteHandle`] and a [`ReadHandle`] values for the
/// write and read halves (respectively).
pub fn channel_create() -> Result<(WriteHandle, ReadHandle), OakStatus> {
    let mut write = WriteHandle {
        handle: Handle::invalid(),
    };
    let mut read = ReadHandle {
        handle: Handle::invalid(),
    };
    let status = OakStatus::from_i32(unsafe {
        oak_abi::channel_create(
            &mut write.handle.id as *mut u64,
            &mut read.handle.id as *mut u64,
        )
    } as i32);
    result_from_status(status, (write, read))
}

/// Close the specified channel [`Handle`].
pub fn channel_close(handle: Handle) -> Result<(), OakStatus> {
    let status = OakStatus::from_i32(unsafe { oak_abi::channel_close(handle.id) as i32 });
    result_from_status(status, ())
}

/// Create a new Node running the configuration identified by `config_name`,
/// passing it the given handle.
pub fn node_create(config_name: &str, half: ReadHandle) -> Result<(), OakStatus> {
    let status = OakStatus::from_i32(unsafe {
        oak_abi::node_create(config_name.as_ptr(), config_name.len(), half.handle.id) as i32
    });
    result_from_status(status, ())
}

/// Fill a buffer with random data.
pub fn random_get(buf: &mut [u8]) -> Result<(), OakStatus> {
    let status =
        OakStatus::from_i32(unsafe { oak_abi::random_get(buf.as_mut_ptr(), buf.len()) as i32 });
    result_from_status(status, ())
}

/// Convert a status obtained from `OakStatus::from_i32` to a `Result`. If the status is `OK` then
/// return the provided value as `Result::Ok`, otherwise return the status as `Result::Err`.
pub fn result_from_status<T>(status: Option<OakStatus>, val: T) -> Result<T, OakStatus> {
    match status {
        Some(OakStatus::OK) => Ok(val),
        Some(status) => Err(status),
        None => Err(OakStatus::OAK_STATUS_UNSPECIFIED),
    }
}

/// Install a panic hook that logs [panic information].
///
/// Logs panic infomation to the logging channel, if one is set.
///
/// [panic information]: std::panic::PanicInfo
pub fn set_panic_hook() {
    std::panic::set_hook(Box::new(|panic_info| {
        let msg = panic_info
            .payload()
            .downcast_ref::<&str>()
            .unwrap_or(&"<UNKNOWN MESSAGE>");
        let (file, line) = match panic_info.location() {
            Some(location) => (location.file(), location.line()),
            None => ("<UNKNOWN FILE>", 0),
        };
        error!(
            "panic occurred in file '{}' at line {}: {}",
            file, line, msg
        );
    }));
}
<commit_msg>Support additional panic hook payload types (#485)<commit_after>//
// Copyright 2018 The Project Oak Authors
//
// 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.
//

use byteorder::{ReadBytesExt, WriteBytesExt};
use log::{debug, error};
use protobuf::ProtobufEnum;
use serde::{Deserialize, Serialize};

// Re-export ABI constants that are also visible as part of the SDK API.
pub use oak_abi::{ChannelReadStatus, OakStatus};

pub mod grpc;
pub mod io;
pub mod proto;
pub mod rand;
pub mod storage;

#[cfg(test)]
mod tests;

#[cfg(test)]
use assert_matches::assert_matches;
#[cfg(test)]
use serial_test_derive::serial;

/// Handle used to identify read or write channel halves.
///
/// These handles are used for all host function calls.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Handle {
    id: u64,
}

/// Serialize a `Handle` as the invalid handle value.
impl serde::Serialize for Handle {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_u64(oak_abi::INVALID_HANDLE)
    }
}

struct HandleVisitor;

/// Deserialize a `Handle` as the invalid handle value. Most likely, it will have been serialized to
/// an invalid handle in the first place anyways, but we are being extra cautions and even if the
/// serialized value was modified, we make sure that the resulting `Handle` is invalid.
impl<'de> serde::de::Visitor<'de> for HandleVisitor {
    type Value = Handle;
    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        formatter.write_str("a handle type")
    }

    fn visit_u64<E>(self, _v: u64) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(Handle::invalid())
    }
}

impl<'de> serde::Deserialize<'de> for Handle {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_u64(HandleVisitor)
    }
}

impl Handle {
    /// When using the Oak SDK, this method should not need to be called directly
    /// as `Handles` are directly provided via functions such as `channel_create`.
    pub fn from_raw(id: u64) -> Handle {
        Handle { id }
    }

    /// Check this handle is valid.
    pub fn is_valid(self) -> bool {
        self.id != oak_abi::INVALID_HANDLE
    }

    /// Returns an intentionally invalid handle.
    pub fn invalid() -> Handle {
        Handle {
            id: oak_abi::INVALID_HANDLE,
        }
    }

    /// Pack a slice of `Handles` into the Wasm host ABI format.
    fn pack(handles: &[Handle]) -> Vec<u8> {
        let mut packed = Vec::with_capacity(handles.len() * 8);
        for handle in handles {
            packed
                .write_u64::<byteorder::LittleEndian>(handle.id)
                .unwrap();
        }
        packed
    }

    /// Unpack a slice of Handles from the Wasm host ABI format.
    fn unpack(bytes: &[u8], handle_count: u32, handles: &mut Vec<Handle>) {
        handles.clear();
        let mut reader = std::io::Cursor::new(bytes);
        for _ in 0..handle_count {
            handles.push(Handle {
                id: reader.read_u64::<byteorder::LittleEndian>().unwrap(),
            });
        }
    }
}

/// Wrapper for a handle to the read half of a channel.
///
/// For use when the underlying [`Handle`] is known to be for a receive half.
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub struct ReadHandle {
    pub handle: Handle,
}

/// Wrapper for a handle to the send half of a channel.
///
/// For use when the underlying [`Handle`] is known to be for a send half.
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub struct WriteHandle {
    pub handle: Handle,
}

// Build a chunk of memory that is suitable for passing to oak_abi::wait_on_channels,
// holding the given collection of channel handles.
fn new_handle_space(handles: &[ReadHandle]) -> Vec<u8> {
    let mut space = Vec::with_capacity(oak_abi::SPACE_BYTES_PER_HANDLE * handles.len());
    for handle in handles {
        space
            .write_u64::<byteorder::LittleEndian>(handle.handle.id)
            .unwrap();
        space.push(0x00);
    }
    space
}

// Prepare a handle space for polling by clearing all of the message-pending
// indicator bytes.
fn prep_handle_space(space: &mut [u8]) {
    let count = space.len() / 8;
    for i in 0..count {
        space[i * oak_abi::SPACE_BYTES_PER_HANDLE + (oak_abi::SPACE_BYTES_PER_HANDLE - 1)] = 0;
    }
}

/// Wait for one or more of the provided handles to become ready for reading
/// from.  On success, the returned vector of [`ChannelReadStatus`] values
/// will be in 1-1 correspondence with the passed-in vector of [`Handle`]s.
///
/// This is a convenience wrapper around the [`oak_abi::wait_on_channels`] host
/// function. This version is easier to use in Rust but is less efficient
/// (because the notification space is re-created on each invocation).
pub fn wait_on_channels(handles: &[ReadHandle]) -> Result<Vec<ChannelReadStatus>, OakStatus> {
    let mut space = new_handle_space(handles);
    unsafe {
        let status = oak_abi::wait_on_channels(space.as_mut_ptr(), handles.len() as u32);
        match OakStatus::from_i32(status as i32) {
            Some(OakStatus::OK) => (),
            Some(err) => return Err(err),
            None => return Err(OakStatus::OAK_STATUS_UNSPECIFIED),
        }
        let mut results = Vec::with_capacity(handles.len());
        for i in 0..handles.len() {
            match space
                .get(i * oak_abi::SPACE_BYTES_PER_HANDLE + (oak_abi::SPACE_BYTES_PER_HANDLE - 1))
                .cloned()
                .map(i32::from)
                .and_then(ChannelReadStatus::from_i32)
            {
                Some(status) => results.push(status),
                None => return Err(OakStatus::OAK_STATUS_UNSPECIFIED),
            }
        }
        Ok(results)
    }
}

/// Read a message from a channel without blocking.
///
/// It also returns an error if the underlying channel is empty (i.e. not ready to read).
///
/// The provided vectors for received data and associated handles will be
/// resized to accomodate the information in the message; any data already
/// held in the vectors will be overwritten.
pub fn channel_read(
    half: ReadHandle,
    buf: &mut Vec<u8>,
    handles: &mut Vec<Handle>,
) -> Result<(), OakStatus> {
    // Try reading from the channel twice: first with provided vectors, making
    // use of their available capacity, then with vectors whose capacity has
    // been extended to meet size requirements.

    // We cannot deserialize directly into the handles vector because `Handle`
    // may not have the correct memory layout, so create a separate buffer with
    // equivalent capacity.
    let mut handles_buf = Vec::with_capacity(handles.capacity() * 8);
    for resized in &[false, true] {
        let mut actual_size: u32 = 0;
        let mut actual_handle_count: u32 = 0;
        let status = OakStatus::from_i32(unsafe {
            oak_abi::channel_read(
                half.handle.id,
                buf.as_mut_ptr(),
                buf.capacity(),
                &mut actual_size,
                handles_buf.as_mut_ptr(),
                handles_buf.capacity() as u32 / 8, // Handle count, not byte count
                &mut actual_handle_count,
            ) as i32
        });

        match status {
            Some(s) => match s {
                OakStatus::OK | OakStatus::ERR_CHANNEL_EMPTY => {
                    unsafe {
                        // The read operation succeeded, and overwrote some fraction
                        // of the vectors' available capacity with returned data (possibly
                        // zero).  As the data is already present in the vectors, set
                        // their length to match what's available.
                        buf.set_len(actual_size as usize);
                        // actual_handle_count is number of handles not bytes
                        handles_buf.set_len(actual_handle_count as usize * 8);
                    }
                    Handle::unpack(&handles_buf, actual_handle_count, handles);
                    if s == OakStatus::OK {
                        return Ok(());
                    } else {
                        return Err(s);
                    }
                }

                OakStatus::ERR_BUFFER_TOO_SMALL | OakStatus::ERR_HANDLE_SPACE_TOO_SMALL
                    if !(*resized) =>
                {
                    // Extend the vectors to be large enough for the message
                    debug!(
                        "Got space for {} bytes, need {}",
                        buf.capacity(),
                        actual_size
                    );
                    if (actual_size as usize) > buf.capacity() {
                        let extra = (actual_size as usize) - buf.len();
                        buf.reserve(extra);
                    }

                    let handles_capacity = handles_buf.capacity() / 8;
                    debug!(
                        "Got space for {} handles, need {}",
                        handles_capacity, actual_handle_count
                    );
                    if (actual_handle_count as usize) > handles_capacity {
                        let extra = (actual_handle_count as usize * 8) - handles_buf.len();
                        handles_buf.reserve(extra);
                    }

                    // Try again with a buffer resized to cope with expected size of data.
                    continue;
                }

                s => {
                    return Err(s);
                }
            },
            None => {
                return Err(OakStatus::ERR_INTERNAL);
            }
        }
    }
    error!("unreachable code reached");
    Err(OakStatus::ERR_INTERNAL)
}

/// Write a message to a channel.
pub fn channel_write(half: WriteHandle, buf: &[u8], handles: &[Handle]) -> Result<(), OakStatus> {
    let handle_buf = Handle::pack(handles);
    let status = OakStatus::from_i32(unsafe {
        oak_abi::channel_write(
            half.handle.id,
            buf.as_ptr(),
            buf.len(),
            handle_buf.as_ptr(),
            handles.len() as u32, // Number of handles, not bytes
        ) as i32
    });
    result_from_status(status, ())
}

/// Create a new unidirectional channel.
///
/// On success, returns [`WriteHandle`] and a [`ReadHandle`] values for the
/// write and read halves (respectively).
pub fn channel_create() -> Result<(WriteHandle, ReadHandle), OakStatus> {
    let mut write = WriteHandle {
        handle: Handle::invalid(),
    };
    let mut read = ReadHandle {
        handle: Handle::invalid(),
    };
    let status = OakStatus::from_i32(unsafe {
        oak_abi::channel_create(
            &mut write.handle.id as *mut u64,
            &mut read.handle.id as *mut u64,
        )
    } as i32);
    result_from_status(status, (write, read))
}

/// Close the specified channel [`Handle`].
pub fn channel_close(handle: Handle) -> Result<(), OakStatus> {
    let status = OakStatus::from_i32(unsafe { oak_abi::channel_close(handle.id) as i32 });
    result_from_status(status, ())
}

/// Create a new Node running the configuration identified by `config_name`,
/// passing it the given handle.
pub fn node_create(config_name: &str, half: ReadHandle) -> Result<(), OakStatus> {
    let status = OakStatus::from_i32(unsafe {
        oak_abi::node_create(config_name.as_ptr(), config_name.len(), half.handle.id) as i32
    });
    result_from_status(status, ())
}

/// Fill a buffer with random data.
pub fn random_get(buf: &mut [u8]) -> Result<(), OakStatus> {
    let status =
        OakStatus::from_i32(unsafe { oak_abi::random_get(buf.as_mut_ptr(), buf.len()) as i32 });
    result_from_status(status, ())
}

/// Convert a status obtained from `OakStatus::from_i32` to a `Result`. If the status is `OK` then
/// return the provided value as `Result::Ok`, otherwise return the status as `Result::Err`.
pub fn result_from_status<T>(status: Option<OakStatus>, val: T) -> Result<T, OakStatus> {
    match status {
        Some(OakStatus::OK) => Ok(val),
        Some(status) => Err(status),
        None => Err(OakStatus::OAK_STATUS_UNSPECIFIED),
    }
}

/// Install a panic hook that logs [panic information].
///
/// Logs panic infomation to the logging channel, if one is set.
///
/// [panic information]: std::panic::PanicInfo
pub fn set_panic_hook() {
    std::panic::set_hook(Box::new(|panic_info| {
        let payload = panic_info.payload();
        // The payload can be a static string slice or a string, depending on how panic was called.
        // Code for extracting the message is inspired by the rust default panic hook:
        // https://github.com/rust-lang/rust/blob/master/src/libstd/panicking.rs#L188-L194
        let msg = match payload.downcast_ref::<&'static str>() {
            Some(content) => *content,
            None => match payload.downcast_ref::<String>() {
                Some(content) => &content[..],
                None => "<UNKNOWN MESSAGE>",
            },
        };
        let (file, line) = match panic_info.location() {
            Some(location) => (location.file(), location.line()),
            None => ("<UNKNOWN FILE>", 0),
        };
        error!(
            "panic occurred in file '{}' at line {}: {}",
            file, line, msg
        );
    }));
}
<|endoftext|>


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

use perlin_core::index::Index;

pub struct HierarchyField<T: Hash + Eq> {
    pub hierarchy: Hierarchy<T>,
    pub index: Index<T>,
}

impl<T: Hash + Eq + Clone + Ord> HierarchyField<T> {
    pub fn new(index: Index<T>) -> Self {
        HierarchyField {
            hierarchy: Hierarchy::new(),
            index
        }
    }

    pub fn commit(&mut self) {
        self.index.commit();
    }
}

pub struct Hierarchy<T>(HashMap<T, Vec<T>>, Vec<T>);

impl<T: Hash + Eq + Clone> Hierarchy<T> {
    pub fn new() -> Self {
        Hierarchy(HashMap::new(), vec![])
    }

    pub fn add_element(&mut self, term: T, parent: Option<T>) {
        if self.0.contains_key(&term) {
            panic!("Hierarchy element already exists!");
        }

        self.0.insert(term.clone(), vec![]).unwrap();

        if let Some(parent) = parent {
            if let Some(parent_node) = self.0.get_mut(&parent) {
                parent_node.push(term);
            } else {
                panic!("Added hierarchical elements in wrong order!");
            }
        } else {
            self.1.push(term.clone());
        }
    }

    pub fn get_child_terms(&self, term: T) -> Option<&[T]> {
        if let Some(node) = self.0.get(&term) {
            Some(&node)
        } else {
            None
        }
    }

    pub fn get_root_terms(&self) -> &[T] {
        &self.1
    }
}
<commit_msg>add deref to hierarchyfield<commit_after>use std::hash::Hash;
use std::ops::{Deref, DerefMut};
use std::collections::HashMap;

use perlin_core::index::Index;

pub struct HierarchyField<T: Hash + Eq> {
    pub hierarchy: Hierarchy<T>,
    pub index: Index<T>,
}

impl<T: Hash + Eq + Clone + Ord> HierarchyField<T> {
    pub fn new(index: Index<T>) -> Self {
        HierarchyField {
            hierarchy: Hierarchy::new(),
            index
        }
    }

    pub fn commit(&mut self) {
        self.index.commit();
    }
}

pub struct Hierarchy<T>(HashMap<T, Vec<T>>, Vec<T>);

impl<T: Hash + Eq + Clone> Hierarchy<T> {
    pub fn new() -> Self {
        Hierarchy(HashMap::new(), vec![])
    }

    pub fn add_element(&mut self, term: T, parent: Option<T>) {
        if self.0.contains_key(&term) {
            panic!("Hierarchy element already exists!");
        }

        self.0.insert(term.clone(), vec![]).unwrap();

        if let Some(parent) = parent {
            if let Some(parent_node) = self.0.get_mut(&parent) {
                parent_node.push(term);
            } else {
                panic!("Added hierarchical elements in wrong order!");
            }
        } else {
            self.1.push(term.clone());
        }
    }

    pub fn get_child_terms(&self, term: T) -> Option<&[T]> {
        if let Some(node) = self.0.get(&term) {
            Some(&node)
        } else {
            None
        }
    }

    pub fn get_root_terms(&self) -> &[T] {
        &self.1
    }
}

impl<T: Hash + Eq> DerefMut for HierarchyField<T> {
    fn deref_mut(&mut self) -> &mut Index<T> {
        &mut self.index
    }
}

impl<T: Hash + Eq> Deref for HierarchyField<T> {
    type Target = Index<T>;
    fn deref(&self) -> &Index<T> {
        &self.index
    }
}
<|endoftext|>


<commit_before>extern crate game_state;

// OpenGL Renderer
//#[macro_use]
extern crate glium;

extern crate cgmath;
#[macro_use] extern crate vulkano;
extern crate winit;
extern crate vulkano_win;
extern crate glsl_to_spirv;
extern crate vulkano_shaders;
extern crate time;
extern crate image;

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

mod renderer;

use game_state::state::{
    State,
    RenderAccess,
    WindowAccess,
};

use renderer::vulkan::{
    VulkanRenderer,
    DrawMode, // TODO: extract this to renderer::
};

#[no_mangle]
pub extern "C" fn mod_rendering_load( state: &mut State ) {
    assert!(state.get_renderers().len() == 0);
    /*
    state.add_renderer(
        Box::new(VulkanRenderer::new("Wireframe Renderer (vulkan)", 640, 480, DrawMode::Wireframe )),
    );
    */
    let events_loop = state.get_events_loop().clone();
    let windows = state.get_windows().iter().map(|x| x.clone()).collect::<Vec<Arc<_>>>();

    for w in windows {
        println!("Adding renderer for window provided.");
        state.add_renderer(
            Box::new(
                VulkanRenderer::new((w, events_loop.clone()), DrawMode::Colored)
            ),
        );
    }

    state.on_render_load();
}

#[no_mangle]
pub extern "C" fn mod_rendering_tick(state: &mut State) {
    // queue each existing render layers for rendering
    state.push_render_layers();
    state.present_all();
}

#[no_mangle]
pub extern "C" fn mod_rendering_unload(state: &mut State ) {

    state.on_render_unload();
}
<commit_msg>remove commented code<commit_after>extern crate game_state;

// OpenGL Renderer
//#[macro_use]
extern crate glium;

extern crate cgmath;
#[macro_use] extern crate vulkano;
extern crate winit;
extern crate vulkano_win;
extern crate glsl_to_spirv;
extern crate vulkano_shaders;
extern crate time;
extern crate image;

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

mod renderer;

use game_state::state::{
    State,
    RenderAccess,
    WindowAccess,
};

use renderer::vulkan::{
    VulkanRenderer,
    DrawMode, // TODO: extract this to renderer::
};

#[no_mangle]
pub extern "C" fn mod_rendering_load( state: &mut State ) {
    assert!(state.get_renderers().len() == 0);
    let events_loop = state.get_events_loop().clone();
    let windows = state.get_windows().iter().map(|x| x.clone()).collect::<Vec<Arc<_>>>();

    for w in windows {
        println!("Adding renderer for window provided.");
        state.add_renderer(
            Box::new(
                VulkanRenderer::new((w, events_loop.clone()), DrawMode::Colored)
            ),
        );
    }

    state.on_render_load();
}

#[no_mangle]
pub extern "C" fn mod_rendering_tick(state: &mut State) {
    // queue each existing render layers for rendering
    state.push_render_layers();
    state.present_all();
}

#[no_mangle]
pub extern "C" fn mod_rendering_unload(state: &mut State ) {

    state.on_render_unload();
}
<|endoftext|>