<commit_before>extern crate tail;

use self::tail::parse_size;
use crate::common::util::*;
use std::char::from_digit;
use std::io::Write;
use std::process::{Command, Stdio};
use std::thread::sleep;
use std::time::Duration;

static FOOBAR_TXT: &'static str = "foobar.txt";
static FOOBAR_2_TXT: &'static str = "foobar2.txt";
static FOOBAR_WITH_NULL_TXT: &'static str = "foobar_with_null.txt";

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

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

#[test]
fn test_n_greater_than_number_of_lines() {
    new_ucmd!()
        .arg("-n")
        .arg("99999999")
        .arg(FOOBAR_TXT)
        .run()
        .stdout_is_fixture(FOOBAR_TXT);
}

#[test]
fn test_null_default() {
    new_ucmd!()
        .arg("-z")
        .arg(FOOBAR_WITH_NULL_TXT)
        .run()
        .stdout_is_fixture("foobar_with_null_default.expected");
}

#[test]
fn test_follow() {
    let (at, mut ucmd) = at_and_ucmd!();

    let mut child = ucmd.arg("-f").arg(FOOBAR_TXT).run_no_wait();

    let expected = at.read("foobar_single_default.expected");
    assert_eq!(read_size(&mut child, expected.len()), expected);

    // We write in a temporary copy of foobar.txt
    let expected = "line1\nline2\n";
    at.append(FOOBAR_TXT, expected);

    assert_eq!(read_size(&mut child, expected.len()), expected);

    child.kill().unwrap();
}

#[test]
fn test_follow_multiple() {
    let (at, mut ucmd) = at_and_ucmd!();
    let mut child = ucmd
        .arg("-f")
        .arg(FOOBAR_TXT)
        .arg(FOOBAR_2_TXT)
        .run_no_wait();

    let expected = at.read("foobar_follow_multiple.expected");
    assert_eq!(read_size(&mut child, expected.len()), expected);

    let first_append = "trois\n";
    at.append(FOOBAR_2_TXT, first_append);
    assert_eq!(read_size(&mut child, first_append.len()), first_append);

    let second_append = "doce\ntrece\n";
    let expected = at.read("foobar_follow_multiple_appended.expected");
    at.append(FOOBAR_TXT, second_append);
    assert_eq!(read_size(&mut child, expected.len()), expected);

    child.kill().unwrap();
}

#[test]
fn test_follow_stdin() {
    new_ucmd!()
        .arg("-f")
        .pipe_in_fixture(FOOBAR_TXT)
        .run()
        .stdout_is_fixture("follow_stdin.expected");
}

#[test]
fn test_follow_with_pid() {
    let (at, mut ucmd) = at_and_ucmd!();

    #[cfg(unix)]
    let dummy_cmd = "sh";
    #[cfg(windows)]
    let dummy_cmd = "cmd";

    let mut dummy = Command::new(dummy_cmd)
        .stdout(Stdio::null())
        .spawn()
        .unwrap();
    let pid = dummy.id();

    let mut child = ucmd
        .arg("-f")
        .arg(format!("--pid={}", pid))
        .arg(FOOBAR_TXT)
        .arg(FOOBAR_2_TXT)
        .run_no_wait();

    let expected = at.read("foobar_follow_multiple.expected");
    assert_eq!(read_size(&mut child, expected.len()), expected);

    let first_append = "trois\n";
    at.append(FOOBAR_2_TXT, first_append);
    assert_eq!(read_size(&mut child, first_append.len()), first_append);

    let second_append = "doce\ntrece\n";
    let expected = at.read("foobar_follow_multiple_appended.expected");
    at.append(FOOBAR_TXT, second_append);
    assert_eq!(read_size(&mut child, expected.len()), expected);

    // kill the dummy process and give tail time to notice this
    dummy.kill().unwrap();
    let _ = dummy.wait();
    sleep(Duration::from_secs(1));

    let third_append = "should\nbe\nignored\n";
    at.append(FOOBAR_TXT, third_append);
    assert_eq!(read_size(&mut child, 1), "\u{0}");

    // On Unix, trying to kill a process that's already dead is fine; on Windows it's an error.
    #[cfg(unix)]
    child.kill().unwrap();
    #[cfg(windows)]
    assert_eq!(child.kill().is_err(), true);
}

#[test]
fn test_single_big_args() {
    const FILE: &'static str = "single_big_args.txt";
    const EXPECTED_FILE: &'static str = "single_big_args_expected.txt";
    const LINES: usize = 1_000_000;
    const N_ARG: usize = 100_000;

    let (at, mut ucmd) = at_and_ucmd!();

    let mut big_input = at.make_file(FILE);
    for i in 0..LINES {
        write!(&mut big_input, "Line {}\n", i).expect("Could not write to FILE");
    }
    big_input.flush().expect("Could not flush FILE");

    let mut big_expected = at.make_file(EXPECTED_FILE);
    for i in (LINES - N_ARG)..LINES {
        write!(&mut big_expected, "Line {}\n", i).expect("Could not write to EXPECTED_FILE");
    }
    big_expected.flush().expect("Could not flush EXPECTED_FILE");

    ucmd.arg(FILE)
        .arg("-n")
        .arg(format!("{}", N_ARG))
        .run()
        .stdout_is(at.read(EXPECTED_FILE));
}

#[test]
fn test_bytes_single() {
    new_ucmd!()
        .arg("-c")
        .arg("10")
        .arg(FOOBAR_TXT)
        .run()
        .stdout_is_fixture("foobar_bytes_single.expected");
}

#[test]
fn test_bytes_stdin() {
    new_ucmd!()
        .arg("-c")
        .arg("13")
        .pipe_in_fixture(FOOBAR_TXT)
        .run()
        .stdout_is_fixture("foobar_bytes_stdin.expected");
}

#[test]
fn test_bytes_big() {
    const FILE: &'static str = "test_bytes_big.txt";
    const EXPECTED_FILE: &'static str = "test_bytes_big_expected.txt";
    const BYTES: usize = 1_000_000;
    const N_ARG: usize = 100_000;

    let (at, mut ucmd) = at_and_ucmd!();

    let mut big_input = at.make_file(FILE);
    for i in 0..BYTES {
        let digit = from_digit((i % 10) as u32, 10).unwrap();
        write!(&mut big_input, "{}", digit).expect("Could not write to FILE");
    }
    big_input.flush().expect("Could not flush FILE");

    let mut big_expected = at.make_file(EXPECTED_FILE);
    for i in (BYTES - N_ARG)..BYTES {
        let digit = from_digit((i % 10) as u32, 10).unwrap();
        write!(&mut big_expected, "{}", digit).expect("Could not write to EXPECTED_FILE");
    }
    big_expected.flush().expect("Could not flush EXPECTED_FILE");

    let result = ucmd
        .arg(FILE)
        .arg("-c")
        .arg(format!("{}", N_ARG))
        .run()
        .stdout;
    let expected = at.read(EXPECTED_FILE);

    assert_eq!(result.len(), expected.len());
    for (actual_char, expected_char) in result.chars().zip(expected.chars()) {
        assert_eq!(actual_char, expected_char);
    }
}

#[test]
fn test_parse_size() {
    // No suffix.
    assert_eq!(Ok(1234), parse_size("1234"));

    // kB is 1000
    assert_eq!(Ok(9 * 1000), parse_size("9kB"));

    // K is 1024
    assert_eq!(Ok(2 * 1024), parse_size("2K"));

    let suffixes = [
        ('M', 2u32),
        ('G', 3u32),
        ('T', 4u32),
        ('P', 5u32),
        ('E', 6u32),
    ];

    for &(c, exp) in &suffixes {
        let s = format!("2{}B", c);
        assert_eq!(Ok(2 * (1000 as u64).pow(exp)), parse_size(&s));

        let s = format!("2{}", c);
        assert_eq!(Ok(2 * (1024 as u64).pow(exp)), parse_size(&s));
    }

    // Sizes that are too big.
    assert!(parse_size("1Z").is_err());
    assert!(parse_size("1Y").is_err());

    // Bad number
    assert!(parse_size("328hdsf3290").is_err());
}

#[test]
fn test_lines_with_size_suffix() {
    const FILE: &'static str = "test_lines_with_size_suffix.txt";
    const EXPECTED_FILE: &'static str = "test_lines_with_size_suffix_expected.txt";
    const LINES: usize = 3_000;
    const N_ARG: usize = 2 * 1024;

    let (at, mut ucmd) = at_and_ucmd!();

    let mut big_input = at.make_file(FILE);
    for i in 0..LINES {
        writeln!(&mut big_input, "Line {}", i).expect("Could not write to FILE");
    }
    big_input.flush().expect("Could not flush FILE");

    let mut big_expected = at.make_file(EXPECTED_FILE);
    for i in (LINES - N_ARG)..LINES {
        writeln!(&mut big_expected, "Line {}", i).expect("Could not write to EXPECTED_FILE");
    }
    big_expected.flush().expect("Could not flush EXPECTED_FILE");

    ucmd.arg(FILE)
        .arg("-n")
        .arg("2K")
        .run()
        .stdout_is_fixture(EXPECTED_FILE);
}

#[test]
fn test_multiple_input_files() {
    new_ucmd!()
        .arg(FOOBAR_TXT)
        .arg(FOOBAR_2_TXT)
        .run()
        .stdout_is_fixture("foobar_follow_multiple.expected");
}

#[test]
fn test_multiple_input_files_with_suppressed_headers() {
    new_ucmd!()
        .arg(FOOBAR_TXT)
        .arg(FOOBAR_2_TXT)
        .arg("-q")
        .run()
        .stdout_is_fixture("foobar_multiple_quiet.expected");
}

#[test]
fn test_multiple_input_quiet_flag_overrides_verbose_flag_for_suppressing_headers() {
    // TODO: actually the later one should win, i.e. -qv should lead to headers being printed, -vq to them being suppressed
    new_ucmd!()
        .arg(FOOBAR_TXT)
        .arg(FOOBAR_2_TXT)
        .arg("-q")
        .arg("-v")
        .run()
        .stdout_is_fixture("foobar_multiple_quiet.expected");
}
<commit_msg>tests ~ disable failing `tail` test under windows code coverage (with future FixME)<commit_after>extern crate tail;

use self::tail::parse_size;
use crate::common::util::*;
use std::char::from_digit;
use std::io::Write;

static FOOBAR_TXT: &'static str = "foobar.txt";
static FOOBAR_2_TXT: &'static str = "foobar2.txt";
static FOOBAR_WITH_NULL_TXT: &'static str = "foobar_with_null.txt";

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

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

#[test]
fn test_n_greater_than_number_of_lines() {
    new_ucmd!()
        .arg("-n")
        .arg("99999999")
        .arg(FOOBAR_TXT)
        .run()
        .stdout_is_fixture(FOOBAR_TXT);
}

#[test]
fn test_null_default() {
    new_ucmd!()
        .arg("-z")
        .arg(FOOBAR_WITH_NULL_TXT)
        .run()
        .stdout_is_fixture("foobar_with_null_default.expected");
}

#[test]
fn test_follow() {
    let (at, mut ucmd) = at_and_ucmd!();

    let mut child = ucmd.arg("-f").arg(FOOBAR_TXT).run_no_wait();

    let expected = at.read("foobar_single_default.expected");
    assert_eq!(read_size(&mut child, expected.len()), expected);

    // We write in a temporary copy of foobar.txt
    let expected = "line1\nline2\n";
    at.append(FOOBAR_TXT, expected);

    assert_eq!(read_size(&mut child, expected.len()), expected);

    child.kill().unwrap();
}

#[test]
fn test_follow_multiple() {
    let (at, mut ucmd) = at_and_ucmd!();
    let mut child = ucmd
        .arg("-f")
        .arg(FOOBAR_TXT)
        .arg(FOOBAR_2_TXT)
        .run_no_wait();

    let expected = at.read("foobar_follow_multiple.expected");
    assert_eq!(read_size(&mut child, expected.len()), expected);

    let first_append = "trois\n";
    at.append(FOOBAR_2_TXT, first_append);
    assert_eq!(read_size(&mut child, first_append.len()), first_append);

    let second_append = "doce\ntrece\n";
    let expected = at.read("foobar_follow_multiple_appended.expected");
    at.append(FOOBAR_TXT, second_append);
    assert_eq!(read_size(&mut child, expected.len()), expected);

    child.kill().unwrap();
}

#[test]
fn test_follow_stdin() {
    new_ucmd!()
        .arg("-f")
        .pipe_in_fixture(FOOBAR_TXT)
        .run()
        .stdout_is_fixture("follow_stdin.expected");
}

// FixME: test PASSES for usual windows builds, but fails for coverage testing builds (likely related to the specific RUSTFLAGS '-Zpanic_abort_tests -Cpanic=abort')
#[cfg(not(windows))]
#[test]
fn test_follow_with_pid() {
    use std::process::{Command, Stdio};
    use std::thread::sleep;
    use std::time::Duration;

    let (at, mut ucmd) = at_and_ucmd!();

    #[cfg(unix)]
    let dummy_cmd = "sh";
    #[cfg(windows)]
    let dummy_cmd = "cmd";

    let mut dummy = Command::new(dummy_cmd)
        .stdout(Stdio::null())
        .spawn()
        .unwrap();
    let pid = dummy.id();

    let mut child = ucmd
        .arg("-f")
        .arg(format!("--pid={}", pid))
        .arg(FOOBAR_TXT)
        .arg(FOOBAR_2_TXT)
        .run_no_wait();

    let expected = at.read("foobar_follow_multiple.expected");
    assert_eq!(read_size(&mut child, expected.len()), expected);

    let first_append = "trois\n";
    at.append(FOOBAR_2_TXT, first_append);
    assert_eq!(read_size(&mut child, first_append.len()), first_append);

    let second_append = "doce\ntrece\n";
    let expected = at.read("foobar_follow_multiple_appended.expected");
    at.append(FOOBAR_TXT, second_append);
    assert_eq!(read_size(&mut child, expected.len()), expected);

    // kill the dummy process and give tail time to notice this
    dummy.kill().unwrap();
    let _ = dummy.wait();
    sleep(Duration::from_secs(1));

    let third_append = "should\nbe\nignored\n";
    at.append(FOOBAR_TXT, third_append);
    assert_eq!(read_size(&mut child, 1), "\u{0}");

    // On Unix, trying to kill a process that's already dead is fine; on Windows it's an error.
    #[cfg(unix)]
    child.kill().unwrap();
    #[cfg(windows)]
    assert_eq!(child.kill().is_err(), true);
}

#[test]
fn test_single_big_args() {
    const FILE: &'static str = "single_big_args.txt";
    const EXPECTED_FILE: &'static str = "single_big_args_expected.txt";
    const LINES: usize = 1_000_000;
    const N_ARG: usize = 100_000;

    let (at, mut ucmd) = at_and_ucmd!();

    let mut big_input = at.make_file(FILE);
    for i in 0..LINES {
        write!(&mut big_input, "Line {}\n", i).expect("Could not write to FILE");
    }
    big_input.flush().expect("Could not flush FILE");

    let mut big_expected = at.make_file(EXPECTED_FILE);
    for i in (LINES - N_ARG)..LINES {
        write!(&mut big_expected, "Line {}\n", i).expect("Could not write to EXPECTED_FILE");
    }
    big_expected.flush().expect("Could not flush EXPECTED_FILE");

    ucmd.arg(FILE)
        .arg("-n")
        .arg(format!("{}", N_ARG))
        .run()
        .stdout_is(at.read(EXPECTED_FILE));
}

#[test]
fn test_bytes_single() {
    new_ucmd!()
        .arg("-c")
        .arg("10")
        .arg(FOOBAR_TXT)
        .run()
        .stdout_is_fixture("foobar_bytes_single.expected");
}

#[test]
fn test_bytes_stdin() {
    new_ucmd!()
        .arg("-c")
        .arg("13")
        .pipe_in_fixture(FOOBAR_TXT)
        .run()
        .stdout_is_fixture("foobar_bytes_stdin.expected");
}

#[test]
fn test_bytes_big() {
    const FILE: &'static str = "test_bytes_big.txt";
    const EXPECTED_FILE: &'static str = "test_bytes_big_expected.txt";
    const BYTES: usize = 1_000_000;
    const N_ARG: usize = 100_000;

    let (at, mut ucmd) = at_and_ucmd!();

    let mut big_input = at.make_file(FILE);
    for i in 0..BYTES {
        let digit = from_digit((i % 10) as u32, 10).unwrap();
        write!(&mut big_input, "{}", digit).expect("Could not write to FILE");
    }
    big_input.flush().expect("Could not flush FILE");

    let mut big_expected = at.make_file(EXPECTED_FILE);
    for i in (BYTES - N_ARG)..BYTES {
        let digit = from_digit((i % 10) as u32, 10).unwrap();
        write!(&mut big_expected, "{}", digit).expect("Could not write to EXPECTED_FILE");
    }
    big_expected.flush().expect("Could not flush EXPECTED_FILE");

    let result = ucmd
        .arg(FILE)
        .arg("-c")
        .arg(format!("{}", N_ARG))
        .run()
        .stdout;
    let expected = at.read(EXPECTED_FILE);

    assert_eq!(result.len(), expected.len());
    for (actual_char, expected_char) in result.chars().zip(expected.chars()) {
        assert_eq!(actual_char, expected_char);
    }
}

#[test]
fn test_parse_size() {
    // No suffix.
    assert_eq!(Ok(1234), parse_size("1234"));

    // kB is 1000
    assert_eq!(Ok(9 * 1000), parse_size("9kB"));

    // K is 1024
    assert_eq!(Ok(2 * 1024), parse_size("2K"));

    let suffixes = [
        ('M', 2u32),
        ('G', 3u32),
        ('T', 4u32),
        ('P', 5u32),
        ('E', 6u32),
    ];

    for &(c, exp) in &suffixes {
        let s = format!("2{}B", c);
        assert_eq!(Ok(2 * (1000 as u64).pow(exp)), parse_size(&s));

        let s = format!("2{}", c);
        assert_eq!(Ok(2 * (1024 as u64).pow(exp)), parse_size(&s));
    }

    // Sizes that are too big.
    assert!(parse_size("1Z").is_err());
    assert!(parse_size("1Y").is_err());

    // Bad number
    assert!(parse_size("328hdsf3290").is_err());
}

#[test]
fn test_lines_with_size_suffix() {
    const FILE: &'static str = "test_lines_with_size_suffix.txt";
    const EXPECTED_FILE: &'static str = "test_lines_with_size_suffix_expected.txt";
    const LINES: usize = 3_000;
    const N_ARG: usize = 2 * 1024;

    let (at, mut ucmd) = at_and_ucmd!();

    let mut big_input = at.make_file(FILE);
    for i in 0..LINES {
        writeln!(&mut big_input, "Line {}", i).expect("Could not write to FILE");
    }
    big_input.flush().expect("Could not flush FILE");

    let mut big_expected = at.make_file(EXPECTED_FILE);
    for i in (LINES - N_ARG)..LINES {
        writeln!(&mut big_expected, "Line {}", i).expect("Could not write to EXPECTED_FILE");
    }
    big_expected.flush().expect("Could not flush EXPECTED_FILE");

    ucmd.arg(FILE)
        .arg("-n")
        .arg("2K")
        .run()
        .stdout_is_fixture(EXPECTED_FILE);
}

#[test]
fn test_multiple_input_files() {
    new_ucmd!()
        .arg(FOOBAR_TXT)
        .arg(FOOBAR_2_TXT)
        .run()
        .stdout_is_fixture("foobar_follow_multiple.expected");
}

#[test]
fn test_multiple_input_files_with_suppressed_headers() {
    new_ucmd!()
        .arg(FOOBAR_TXT)
        .arg(FOOBAR_2_TXT)
        .arg("-q")
        .run()
        .stdout_is_fixture("foobar_multiple_quiet.expected");
}

#[test]
fn test_multiple_input_quiet_flag_overrides_verbose_flag_for_suppressing_headers() {
    // TODO: actually the later one should win, i.e. -qv should lead to headers being printed, -vq to them being suppressed
    new_ucmd!()
        .arg(FOOBAR_TXT)
        .arg(FOOBAR_2_TXT)
        .arg("-q")
        .arg("-v")
        .run()
        .stdout_is_fixture("foobar_multiple_quiet.expected");
}
<|endoftext|>


<commit_before>#![feature(async_await)]

use std::{future::Future, pin::Pin, task::Poll, ptr};
use std::task::{Waker, RawWaker, RawWakerVTable, Context};

// See if we can run a basic `async fn`
pub async fn foo(x: &u32, y: u32) -> u32 {
    let y = &y;
    let z = 9;
    let z = &z;
    let y = async { *y + *z }.await;
    let a = 10;
    let a = &a;
    *x + y + *a
}

async fn add(x: u32, y: u32) -> u32 {
    async { x + y }.await
}

async fn build_aggregate(a: u32, b: u32, c: u32, d: u32) -> u32 {
    let x = (add(a, b).await, add(c, d).await);
    x.0 + x.1
}

enum Never {}
fn never() -> Never {
    panic!()
}

async fn includes_never(crash: bool, x: u32) -> u32 {
    let mut result = async { x * x }.await;
    if !crash {
        return result;
    }
    #[allow(unused)]
    let bad = never();
    result *= async { x + x }.await;
    drop(bad);
    result
}

fn raw_waker_clone(_this: *const ()) -> RawWaker {
    panic!("unimplemented");
}
fn raw_waker_wake(_this: *const ()) {
    panic!("unimplemented");
}
fn raw_waker_wake_by_ref(_this: *const ()) {
    panic!("unimplemented");
}
fn raw_waker_drop(_this: *const ()) {}

static RAW_WAKER: RawWakerVTable = RawWakerVTable::new(
    raw_waker_clone,
    raw_waker_wake,
    raw_waker_wake_by_ref,
    raw_waker_drop,
);

fn main() {
    let x = 5;
    let mut fut = foo(&x, 7);
    let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) };
    let mut context = Context::from_waker(&waker);
    assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(31));

    let mut fut = build_aggregate(1, 2, 3, 4);
    let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) };
    let mut context = Context::from_waker(&waker);
    assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(10));

    let mut fut = includes_never(false, 4);
    let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) };
    let mut context = Context::from_waker(&waker);
    assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(16));
}
<commit_msg>simplify async-fn tests<commit_after>#![feature(async_await)]

use std::{future::Future, pin::Pin, task::Poll, ptr};
use std::task::{Waker, RawWaker, RawWakerVTable, Context};

// See if we can run a basic `async fn`
pub async fn foo(x: &u32, y: u32) -> u32 {
    let y = &y;
    let z = 9;
    let z = &z;
    let y = async { *y + *z }.await;
    let a = 10;
    let a = &a;
    *x + y + *a
}

async fn add(x: u32, y: u32) -> u32 {
    async { x + y }.await
}

async fn build_aggregate(a: u32, b: u32, c: u32, d: u32) -> u32 {
    let x = (add(a, b).await, add(c, d).await);
    x.0 + x.1
}

enum Never {}
fn never() -> Never {
    panic!()
}

async fn includes_never(crash: bool, x: u32) -> u32 {
    let mut result = async { x * x }.await;
    if !crash {
        return result;
    }
    #[allow(unused)]
    let bad = never();
    result *= async { x + x }.await;
    drop(bad);
    result
}

fn run_fut(mut fut: impl Future<Output=u32>, output: u32) {
    fn raw_waker_clone(_this: *const ()) -> RawWaker {
        panic!("unimplemented");
    }
    fn raw_waker_wake(_this: *const ()) {
        panic!("unimplemented");
    }
    fn raw_waker_wake_by_ref(_this: *const ()) {
        panic!("unimplemented");
    }
    fn raw_waker_drop(_this: *const ()) {}

    static RAW_WAKER: RawWakerVTable = RawWakerVTable::new(
        raw_waker_clone,
        raw_waker_wake,
        raw_waker_wake_by_ref,
        raw_waker_drop,
    );

    let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) };
    let mut context = Context::from_waker(&waker);
    assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(output));
}

fn main() {
    let x = 5;
    run_fut(foo(&x, 7), 31);

    run_fut(build_aggregate(1, 2, 3, 4), 10);

    run_fut(includes_never(false, 4), 16);
}
<|endoftext|>


<commit_before>#![feature(
    async_await,
    await_macro,
)]

use std::{future::Future, pin::Pin, task::Poll, ptr};
use std::task::{Waker, RawWaker, RawWakerVTable, Context};

// See if we can run a basic `async fn`
pub async fn foo(x: &u32, y: u32) -> u32 {
    let y = &y;
    let z = 9;
    let z = &z;
    let y = await!(async { *y + *z });
    let a = 10;
    let a = &a;
    *x + y + *a
}

fn raw_waker_clone(_this: *const ()) -> RawWaker {
    panic!("unimplemented");
}
fn raw_waker_wake(_this: *const ()) {
    panic!("unimplemented");
}
fn raw_waker_wake_by_ref(_this: *const ()) {
    panic!("unimplemented");
}
fn raw_waker_drop(_this: *const ()) {}

static RAW_WAKER: RawWakerVTable = RawWakerVTable::new(
    raw_waker_clone,
    raw_waker_wake,
    raw_waker_wake_by_ref,
    raw_waker_drop,
);

fn main() {
    let x = 5;
    let mut fut = foo(&x, 7);
    let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) };
    let mut context = Context::from_waker(&waker);
    assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(31));
}
<commit_msg>Auto merge of #868 - JohnTitor:adjust-async-await-test, r=RalfJung<commit_after>#![feature(async_await)]

use std::{future::Future, pin::Pin, task::Poll, ptr};
use std::task::{Waker, RawWaker, RawWakerVTable, Context};

// See if we can run a basic `async fn`
pub async fn foo(x: &u32, y: u32) -> u32 {
    let y = &y;
    let z = 9;
    let z = &z;
    let y = async { *y + *z }.await;
    let a = 10;
    let a = &a;
    *x + y + *a
}

fn raw_waker_clone(_this: *const ()) -> RawWaker {
    panic!("unimplemented");
}
fn raw_waker_wake(_this: *const ()) {
    panic!("unimplemented");
}
fn raw_waker_wake_by_ref(_this: *const ()) {
    panic!("unimplemented");
}
fn raw_waker_drop(_this: *const ()) {}

static RAW_WAKER: RawWakerVTable = RawWakerVTable::new(
    raw_waker_clone,
    raw_waker_wake,
    raw_waker_wake_by_ref,
    raw_waker_drop,
);

fn main() {
    let x = 5;
    let mut fut = foo(&x, 7);
    let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) };
    let mut context = Context::from_waker(&waker);
    assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(31));
}
<|endoftext|>


<commit_before>extern crate limonite;

use limonite::codegen::llvm::LLVMGenerator;
use limonite::syntax::expr::{Expr, ExprWrapper};
use limonite::syntax::op::InfixOp;
use limonite::syntax::literals::Literals;

use std::mem::transmute;

macro_rules! block {
    ($($args:tt)*) => {
        ExprWrapper::default(Expr::Block(vec![$($args)*]))
    }
}

macro_rules! var {
    ($arg:expr) => {
        ExprWrapper::default(Expr::Var($arg.into()))
    }
}

macro_rules! ret {
    ($arg:expr) => {
        ExprWrapper::default(Expr::Return($arg))
    }
}

macro_rules! u8 {
    ($arg:tt) => {
        ExprWrapper::default(Expr::Literal(Literals::U8Num($arg)))
    }
}

macro_rules! string {
    ($arg:tt) => {
        ExprWrapper::default(Expr::Literal(Literals::UTF8String($arg.into())))
    }
}

macro_rules! op {
    ($left_arg:expr, + $right_arg:expr) => {
        ExprWrapper::default(Expr::InfixOp(InfixOp::Add, $left_arg, $right_arg))
    };
    ($left_arg:expr, = $right_arg:expr) => {
        ExprWrapper::default(Expr::Assign($left_arg, $right_arg))
    };
    ($left_arg:expr, < $right_arg:expr) => {
        ExprWrapper::default(Expr::InfixOp(InfixOp::Lt, $left_arg, $right_arg))
    };
    ($left_arg:expr, > $right_arg:expr) => {
        ExprWrapper::default(Expr::InfixOp(InfixOp::Gt, $left_arg, $right_arg))
    };
}

macro_rules! assign {
    ($left_arg:expr, = $right_arg:expr) => {
        ExprWrapper::default(Expr::Assign($left_arg, $right_arg))
    };
    ($left_arg:expr, += $right_arg:expr) => {
        ExprWrapper::default(Expr::Assign($left_arg, ExprWrapper::default(Expr::InfixOp(InfixOp::Add, $left_arg, $right_arg))))
    };
    ($left_arg:expr, -= $right_arg:expr) => {
        ExprWrapper::default(Expr::Assign($left_arg, ExprWrapper::default(Expr::InfixOp(InfixOp::Sub, $left_arg, $right_arg))))
    };
}

#[test]
fn test_sum_function() {
    // Creates a limonite function that looks like:
    // fn add_two_ints(left: u64, right: u64) -> u64,
    //     return left + right;

    let sum = op!(var!("left"), + var!("right"));
    let ast_body = ret!(Some(sum));
    let fn_args = vec![("left".into(), "u64".into()), ("right".into(), "u64".into())];
    let ast = ExprWrapper::default(Expr::FnDecl("add_two_ints".into(), fn_args, Some("u64".into()), ast_body));

    let mut llvm_generator = LLVMGenerator::new();

    llvm_generator.add_module(ast, false, false);
    llvm_generator.initialize(true);

    let address = llvm_generator.get_function_address("add_two_ints").expect("Could not find function address");

    let add_two_ints: extern "C" fn(u64, u64) -> u64 = unsafe { transmute(address) };

    assert_eq!(add_two_ints(456, 987), 1443);
}

#[test]
fn test_while_lt_increment_u8() {
    // Creates a limonite function that looks like:
    // fn inc_until() -> u8,
    //     var i = 0u8;
    //
    //     while i < 10,
    //         i += 1
    //
    //     return i

    let var_decl = ExprWrapper::default(Expr::VarDecl(false, "i".into(), Some("u8".into()), u8!(0)));
    let loop_cond = op!(var!("i"), < u8!(10));
    let loop_body = assign!(var!("i"), += u8!(1));
    let while_loop = ExprWrapper::default(Expr::WhileLoop(loop_cond, loop_body));
    let ret = ret!(Some(var!("i")));
    let body = block![
        var_decl,
        while_loop,
        ret
    ];
    let ast = ExprWrapper::default(Expr::FnDecl("inc_until".into(), Vec::new(), Some("u8".into()), body));

    let mut llvm_generator = LLVMGenerator::new();

    llvm_generator.add_module(ast, false, false);
    llvm_generator.initialize(true);

    let address = llvm_generator.get_function_address("inc_until").expect("Could not find function address");

    let inc_until: extern "C" fn() -> u8 = unsafe { transmute(address) };

    assert_eq!(inc_until(), 10);
}

#[test]
fn test_while_gt_decrement_u8() {
    // Creates a limonite function that looks like:
    // fn dec_until() -> u8,
    //     var i = 10u8;
    //
    //     while i > 0,
    //         i -= 1
    //
    //     return i

    let var_decl = ExprWrapper::default(Expr::VarDecl(false, "i".into(), Some("u8".into()), u8!(10)));
    let loop_cond = op!(var!("i"), > u8!(0));
    let loop_body = assign!(var!("i"), -= u8!(1));
    let while_loop = ExprWrapper::default(Expr::WhileLoop(loop_cond, loop_body));
    let ret = ret!(Some(var!("i")));
    let body = block![
        var_decl,
        while_loop,
        ret
    ];
    let ast = ExprWrapper::default(Expr::FnDecl("dec_until".into(), Vec::new(), Some("u8".into()), body));

    let mut llvm_generator = LLVMGenerator::new();

    llvm_generator.add_module(ast, false, false);
    llvm_generator.initialize(true);

    let address = llvm_generator.get_function_address("dec_until").expect("Could not find function address");

    let dec_until: extern "C" fn() -> u8 = unsafe { transmute(address) };

    assert_eq!(dec_until(), 0);
}

#[test]
fn test_hello_world() {
    // Creates a limonite function that looks like:
    // fn hello_world(),
    //     var s = "Hello, World!";
    //     print(s)
    //     return

    let var_decl = ExprWrapper::default(Expr::VarDecl(false, "s".into(), Some("std.string.String".into()), string!("Hello, World!")));
    let print_call = ExprWrapper::default(Expr::FnCall("print".into(), vec![var!("s")]));
    let ret = ret!(None);

    let body = block![
        var_decl,
        print_call,
        ret,
    ];
    let ast = ExprWrapper::default(Expr::FnDecl("hello_world".into(), Vec::new(), None, body));

    let mut llvm_generator = LLVMGenerator::new();

    llvm_generator.add_module(ast, false, true);
    llvm_generator.initialize(true);

    let address = llvm_generator.get_function_address("hello_world").expect("Could not find function address");

    let hello_world: extern "C" fn() = unsafe { transmute(address) };

    // REVIEW: Is there a way to capture stdout to ensure the right text is being printed?

    hello_world();
}
<commit_msg>Simplified return macro<commit_after>extern crate limonite;

use limonite::codegen::llvm::LLVMGenerator;
use limonite::syntax::expr::{Expr, ExprWrapper};
use limonite::syntax::op::InfixOp;
use limonite::syntax::literals::Literals;

use std::mem::transmute;

macro_rules! block {
    ($($args:tt)*) => {
        ExprWrapper::default(Expr::Block(vec![$($args)*]))
    }
}

macro_rules! var {
    ($arg:expr) => {
        ExprWrapper::default(Expr::Var($arg.into()))
    }
}

macro_rules! ret {
    () => {
        ExprWrapper::default(Expr::Return(None))
    };
    ($arg:expr) => {
        ExprWrapper::default(Expr::Return(Some($arg)))
    };
}

macro_rules! u8 {
    ($arg:tt) => {
        ExprWrapper::default(Expr::Literal(Literals::U8Num($arg)))
    }
}

macro_rules! string {
    ($arg:tt) => {
        ExprWrapper::default(Expr::Literal(Literals::UTF8String($arg.into())))
    }
}

macro_rules! op {
    ($left_arg:expr, + $right_arg:expr) => {
        ExprWrapper::default(Expr::InfixOp(InfixOp::Add, $left_arg, $right_arg))
    };
    ($left_arg:expr, = $right_arg:expr) => {
        ExprWrapper::default(Expr::Assign($left_arg, $right_arg))
    };
    ($left_arg:expr, < $right_arg:expr) => {
        ExprWrapper::default(Expr::InfixOp(InfixOp::Lt, $left_arg, $right_arg))
    };
    ($left_arg:expr, > $right_arg:expr) => {
        ExprWrapper::default(Expr::InfixOp(InfixOp::Gt, $left_arg, $right_arg))
    };
}

macro_rules! assign {
    ($left_arg:expr, = $right_arg:expr) => {
        ExprWrapper::default(Expr::Assign($left_arg, $right_arg))
    };
    ($left_arg:expr, += $right_arg:expr) => {
        ExprWrapper::default(Expr::Assign($left_arg, ExprWrapper::default(Expr::InfixOp(InfixOp::Add, $left_arg, $right_arg))))
    };
    ($left_arg:expr, -= $right_arg:expr) => {
        ExprWrapper::default(Expr::Assign($left_arg, ExprWrapper::default(Expr::InfixOp(InfixOp::Sub, $left_arg, $right_arg))))
    };
}

#[test]
fn test_sum_function() {
    // Creates a limonite function that looks like:
    // fn add_two_ints(left: u64, right: u64) -> u64,
    //     return left + right;

    let ret = ret!(op!(var!("left"), + var!("right")));
    let fn_args = vec![("left".into(), "u64".into()), ("right".into(), "u64".into())];
    let ast = ExprWrapper::default(Expr::FnDecl("add_two_ints".into(), fn_args, Some("u64".into()), ret));

    let mut llvm_generator = LLVMGenerator::new();

    llvm_generator.add_module(ast, false, false);
    llvm_generator.initialize(true);

    let address = llvm_generator.get_function_address("add_two_ints").expect("Could not find function address");

    let add_two_ints: extern "C" fn(u64, u64) -> u64 = unsafe { transmute(address) };

    assert_eq!(add_two_ints(456, 987), 1443);
}

#[test]
fn test_while_lt_increment_u8() {
    // Creates a limonite function that looks like:
    // fn inc_until() -> u8,
    //     var i = 0u8;
    //
    //     while i < 10,
    //         i += 1
    //
    //     return i

    let var_decl = ExprWrapper::default(Expr::VarDecl(false, "i".into(), Some("u8".into()), u8!(0)));
    let loop_cond = op!(var!("i"), < u8!(10));
    let loop_body = assign!(var!("i"), += u8!(1));
    let while_loop = ExprWrapper::default(Expr::WhileLoop(loop_cond, loop_body));
    let ret = ret!(var!("i"));
    let body = block![
        var_decl,
        while_loop,
        ret
    ];
    let ast = ExprWrapper::default(Expr::FnDecl("inc_until".into(), Vec::new(), Some("u8".into()), body));

    let mut llvm_generator = LLVMGenerator::new();

    llvm_generator.add_module(ast, false, false);
    llvm_generator.initialize(true);

    let address = llvm_generator.get_function_address("inc_until").expect("Could not find function address");

    let inc_until: extern "C" fn() -> u8 = unsafe { transmute(address) };

    assert_eq!(inc_until(), 10);
}

#[test]
fn test_while_gt_decrement_u8() {
    // Creates a limonite function that looks like:
    // fn dec_until() -> u8,
    //     var i = 10u8;
    //
    //     while i > 0,
    //         i -= 1
    //
    //     return i

    let var_decl = ExprWrapper::default(Expr::VarDecl(false, "i".into(), Some("u8".into()), u8!(10)));
    let loop_cond = op!(var!("i"), > u8!(0));
    let loop_body = assign!(var!("i"), -= u8!(1));
    let while_loop = ExprWrapper::default(Expr::WhileLoop(loop_cond, loop_body));
    let ret = ret!(var!("i"));
    let body = block![
        var_decl,
        while_loop,
        ret
    ];
    let ast = ExprWrapper::default(Expr::FnDecl("dec_until".into(), Vec::new(), Some("u8".into()), body));

    let mut llvm_generator = LLVMGenerator::new();

    llvm_generator.add_module(ast, false, false);
    llvm_generator.initialize(true);

    let address = llvm_generator.get_function_address("dec_until").expect("Could not find function address");

    let dec_until: extern "C" fn() -> u8 = unsafe { transmute(address) };

    assert_eq!(dec_until(), 0);
}

#[test]
fn test_hello_world() {
    // Creates a limonite function that looks like:
    // fn hello_world(),
    //     var s = "Hello, World!";
    //     print(s)
    //     return

    let var_decl = ExprWrapper::default(Expr::VarDecl(false, "s".into(), Some("std.string.String".into()), string!("Hello, World!")));
    let print_call = ExprWrapper::default(Expr::FnCall("print".into(), vec![var!("s")]));

    let body = block![
        var_decl,
        print_call,
        ret!(),
    ];
    let ast = ExprWrapper::default(Expr::FnDecl("hello_world".into(), Vec::new(), None, body));

    let mut llvm_generator = LLVMGenerator::new();

    llvm_generator.add_module(ast, false, true);
    llvm_generator.initialize(true);

    let address = llvm_generator.get_function_address("hello_world").expect("Could not find function address");

    let hello_world: extern "C" fn() = unsafe { transmute(address) };

    // REVIEW: Is there a way to capture stdout to ensure the right text is being printed?

    hello_world();
}
<|endoftext|>


<commit_before>extern crate serde;

use serde::json::{self, Value};
use serde::json::error::*;
use std::io::{ErrorKind, Read, Write};

fn die<T: std::error::Error>(e: T) -> ! {
    writeln!(&mut std::io::stderr(), "error: {:?}", e).ok();
    std::process::exit(1)
}

fn main() {
    let args: Vec<_> = std::env::args().collect();
    let mut reader = match args.len() {
        1 => Box::new(std::io::stdin()) as Box<Read>,
        2 => {
            match std::fs::File::open(&args[1]) {
                Ok(f) => Box::new(f) as Box<Read>,
                Err(e) => die(e)
            }
        },
        _ => die(std::io::Error::new(ErrorKind::InvalidInput, "too many args"))
    };
    let mut string = String::new();
    reader.read_to_string(&mut string).ok().unwrap();
    if string.len() == 0 {
        println!("Got nothing from stdin");
        return;
    }
    let data: Value = match json::from_str(&string) {
        Ok(v) => v,
        Err(Error::SyntaxError(ErrorCode::ExpectedSomeValue, _, _)) => {
            string = string.replace("infoCallback(", "").replace(");", "");
            match json::from_str(&string) {
                Ok(v) => v,
                Err(e) => die(e)
            }
        },
        Err(e) => die(e)
    };
    match json::ser::to_string_pretty(&data) {
        Ok(v) => print!("{}", v),
        Err(e) => die(e)
    };
}

<commit_msg>rust: remove unnecessary check<commit_after>extern crate serde;

use serde::json::{self, Value};
use serde::json::error::*;
use std::io::{ErrorKind, Read, Write};

fn die<T: std::error::Error>(e: T) -> ! {
    writeln!(&mut std::io::stderr(), "error: {:?}", e).ok();
    std::process::exit(1)
}

fn main() {
    let args: Vec<_> = std::env::args().collect();
    let mut reader = match args.len() {
        1 => Box::new(std::io::stdin()) as Box<Read>,
        2 => {
            match std::fs::File::open(&args[1]) {
                Ok(f) => Box::new(f) as Box<Read>,
                Err(e) => die(e)
            }
        },
        _ => die(std::io::Error::new(ErrorKind::InvalidInput, "too many args"))
    };
    let mut string = String::new();
    reader.read_to_string(&mut string).ok().unwrap();
    let data: Value = match json::from_str(&string) {
        Ok(v) => v,
        Err(Error::SyntaxError(ErrorCode::ExpectedSomeValue, _, _)) => {
            string = string.replace("infoCallback(", "").replace(");", "");
            match json::from_str(&string) {
                Ok(v) => v,
                Err(e) => die(e)
            }
        },
        Err(e) => die(e)
    };
    match json::ser::to_string_pretty(&data) {
        Ok(v) => print!("{}", v),
        Err(e) => die(e)
    };
}

<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
use super::{ElfResult, ElfWord, Section, section};

use core::{fmt, mem};

pub trait Header {
    type Word: ElfWord;

    /// Attempt to extract an ELF file header from a slice of bytes.
    /// TODO: should this be a From impl maybe?
    //          - eliza, 03/08/2017
    fn from_slice<'a>(input: &'a [u8]) -> ElfResult<&'a Self>;

    /// Attempt to extract a section header from a slice of bytes.
    /// TODO: can/should the index be `usize`?
    //          - eliza, 03/08/2017
    fn parse_section<'a>(&'a self, input: &'a [u8], idx: u16)
                            -> ElfResult<&'a Section>;

    // Field accessors -------------------------------------------
    fn ident(&self) -> Ident;
    fn get_type(&self) -> Type;
    fn machine(&self) -> Machine;
    /// Offset of the program entry point
    fn entry_point(&self) -> usize;
    /// Offset of the start of program headers
    fn ph_offset(&self) -> usize;
    /// Offset of the start of [section header]s.
    ///
    /// [section header]: ../section/struct.Header.html
    fn sh_offset(&self) -> usize;
    /// TODO: can this return the flags type?
    //          - eliza, 03/08/2017
    fn flags(&self) -> u32;
    fn sh_str_idx(&self) -> usize;

}

/// An ELF file header
#[derive(Copy, Clone, Debug)]
#[repr(C, packed)]
pub struct HeaderRepr<W: ElfWord> {
    /// the ELF [file identifier](struct.Ident.html)
    pub ident: Ident
  , elftype: TypeRepr
  , pub machine: Machine
  , /// Program entry point
    /// TODO: getters for turning these into `usize`?
    //          - eliza, 03/08/2017
    entry_point: W
  , /// Offset for start of program headers
    ph_offset: W
  , /// Offset for start of [section header]s.
    /// [section header]: ../section/struct.Header.html
    sh_offset: W
  , pub flags: u32
  , pub header_size: u16
  , pub ph_entry_size: u16
  , pub ph_count: u16
  , pub sh_entry_size: u16
  , pub sh_count: u16
  , /// Index of the section header string table
    sh_str_idx: u16
}

/// FIXME(style): generate more stuff with macros/use `macro_attr` to derive
///               these...
//                  - eliza, 03/08/2017
macro_rules! impl_getters {
    ($(#[$attr:meta])* pub fn $name:ident(&self) -> $ty:ident; $($rest:tt)*) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ($(#[$attr:meta])* fn $name:ident(&self) -> $ty:ident; $($rest:tt)*) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ( $(#[$attr:meta])* pub fn $name: ident (&self)-> $ty: ident; ) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
    };
    ( $(#[$attr:meta])* fn $name: ident (&self)-> $ty: ident; ) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
    };
    () => {};
}

impl Header for HeaderRepr<u64> {
    type Word = u64;

    /// Attempt to extract an ELF file header from a slice of bytes.
    /// TODO: can this also be macro-generated?
    ///         - eliza, 03/08/2017
    fn from_slice<'a>(input: &'a [u8]) -> ElfResult<&'a Self> {
        if input.len() < mem::size_of::<Self>() {
            Err("Input too short to extract ELF header")
        } else {
            unsafe { Ok(&super::extract_from_slice::<Self>(input, 0, 1)[0]) }
        }
    }

    /// Attempt to extract a section header from a slice of bytes.
    /// TODO: can this also be macro-generated?
    ///         - eliza, 03/08/2017
    fn parse_section<'a>(&'a self, input: &'a [u8], idx: u16)
                            -> ElfResult<&'a Section>
    {
        if idx < section::SHN_LORESERVE {
            Err("Cannot parse reserved section.")
        } else {
            let start: u64// start offset for section
                = self.sh_offset + idx as u64 * self.sh_entry_size as u64;
            let end: u64 // end offset for section
                = start + self.sh_entry_size as u64;
            let raw
                = &input[start as usize .. end as usize];

            match self.ident.class {
                Class::None => Err("Invalid ELF class (ELFCLASSNONE).")
              , Class::Elf32 => Err("Cannot parse 32-bit section from 64-bit \
                                     ELF file.")
              , Class::Elf64 => unsafe {
                    Ok(&*(raw as *const [u8] as *const u8 as *const Section))
                }
            }
        }
    }

    #[inline] fn get_type(&self) -> Type { self.elftype.as_type() }

    impl_getters! {
        #[doc = "Index for the start of [section header]s. \
                 [section header]: ../section/struct.Header.html"]
        fn sh_offset(&self) -> usize;
        #[doc = "Index for the start of program headers"]
        fn ph_offset(&self) -> usize;
        #[doc = "Index for the program entry point"]
        fn entry_point(&self) -> usize;
        #[doc = "Index of the section header [string table] \
                 [string table]: ../section/struct.StrTable.html"]
        fn sh_str_idx(&self) -> usize;
        fn flags(&self) -> u32;
        fn ident(&self) -> Ident;
        fn machine(&self) -> Machine;
    }

}

impl Header for HeaderRepr<u32> {

    type Word = u32;
    /// Attempt to extract an ELF file header from a slice of bytes.
    fn from_slice<'a>(input: &'a [u8]) -> ElfResult<&'a Self> {
        if input.len() < mem::size_of::<Self>() {
            Err("Input too short to extract ELF header")
        } else {
            unsafe { Ok(&super::extract_from_slice::<Self>(input, 0, 1)[0]) }
        }
    }

    /// Attempt to extract a section header from a slice of bytes.
    fn parse_section<'a>(&'a self, input: &'a [u8], idx: u16)
                            -> ElfResult<&'a Section>
    {
        if idx < section::SHN_LORESERVE {
            Err("Cannot parse reserved section.")
        } else {
            let start: u32// start offset for section
                = self.sh_offset + idx as u32 * self.sh_entry_size as u32;
            let end: u32 // end offset for section
                = start + self.sh_entry_size as u32;
            let raw
                = &input[start as usize .. end as usize];

            match self.ident.class {
                Class::None => Err("Invalid ELF class (ELFCLASSNONE).")
              , Class::Elf32 => unsafe {
                    Ok(&*(raw as *const [u8] as *const u8 as *const Section))
                }
              , Class::Elf64 => Err("Cannot parse 64-bit section from 32-bit \
                                     ELF file.")
            }
        }
    }

    #[inline] fn get_type(&self) -> Type { self.elftype.as_type() }

    impl_getters! {
        #[doc = "Index for the start of [section header]s. \
                 [section header]: ../section/struct.Header.html"]
        fn sh_offset(&self) -> usize;
        #[doc = "Index for the start of program headers"]
        fn ph_offset(&self) -> usize;
        #[doc = "Index for the program entry point"]
        fn entry_point(&self) -> usize;
        #[doc = "Index of the section header [string table] \
                 [string table]: ../section/struct.StrTable.html"]
        fn sh_str_idx(&self) -> usize;
        fn flags(&self) -> u32;
        fn ident(&self) -> Ident;
        fn machine(&self) -> Machine;
    }

}

/// ELF header magic
pub const MAGIC: Magic = [0x7f, b'E', b'L', b'F'];

/// Type of header magic
pub type Magic = [u8; 4];

/// ELF identifier (`e_ident` in the ELF standard)
#[derive(Copy, Clone, Debug)]
#[repr(C, packed)]
pub struct Ident {
    /// ELF magic numbers. Must be equal to the [ELF magic], `[0x7, E, L, F]`.
    ///
    /// [ELF magic]: constant.MAGIC.html
    pub magic: Magic
  , /// ELF [file class](enum.Class.html) (32- or 64-bit)
    pub class: Class
  , /// ELF [data encoding](enum.DataEncoding.html) (big- or little-endian)
    pub encoding: DataEncoding
  , /// ELF file [version](enum.Version.html)
    pub version: Version
  , /// What [operating system ABI] this file was compiled for.
    ///
    /// [operating system ABI]: enum.OsAbi.html
    pub abi: OsAbi
  , /// ABI version (often this is just padding)
    pub abi_version: u8
  , _padding: [u8; 7]
}

impl Ident {
    #[inline] pub fn check_magic(&self) -> bool { self.magic == MAGIC }

    /// Returns true if the identifier section identifies a valid ELF file.
    #[inline] pub fn is_valid(&self) -> bool {
        // the ELF magic number is correct
        self.check_magic() &&
        // the file class is either 32- or 64-bits
        self.class.is_valid() &&
        // the data encoding is either big- or little-endian
        self.encoding.is_valid()
    }
}

/// Identifies the class of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum Class {
    /// Invalid ELF class file (`ELFCLASSNONE` in the standard)
    None  = 0
  , /// 32-bit ELF file (`ELFCLASS32` in the standard)
    Elf32 = 1
  , /// 64-bit ELF file (`ELFCLASS64` in the standard)
    Elf64 = 2
}

impl Class {
    /// Returns true if the class field for this file is valid.
    #[inline]
    pub fn is_valid(&self) -> bool {
        match *self { Class::None => false
                    , _ => true
                    }
    }
}

/// Identifies the data encoding of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum DataEncoding {
    /// Invalid data encoding (`ELFDATANONE` in the standard)
    None  = 0
  , /// Twos-complement little-endian data encoding
    /// (`ELFDATA2LSB` in the standard)
    LittleEndian = 1
  , /// Twos-complement big-endian data encoding
    /// (`ELFDATA2MSB` in the standard)
    BigEndian = 2
}

impl DataEncoding {
    /// Returns true if the data encoding field for this file is valid.
    #[inline]
    pub fn is_valid(&self) -> bool {
        match *self { DataEncoding::None => false
                    , _ => true
                    }
    }
}

/// Operating system ABI
#[derive(Copy, Clone, Debug)]
#[repr(u8)]
pub enum OsAbi { /// Ox00 also represents "none"
                 SystemV = 0x00
               , HpUx    = 0x01
               , NetBsd  = 0x02
               , Linux   = 0x03
               , Solaris = 0x06
               , Aix     = 0x07
               , Irix    = 0x08
               , FreeBsd = 0x09
               , OpenBsd = 0x0C
               , OpenVms = 0x0D
               }

/// Identifies the version of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum Version { None = 0, Current = 1 }

#[derive(Clone, Copy, PartialEq)]
struct TypeRepr(u16);

impl TypeRepr {
    pub fn as_type(&self) -> Type {
        match self.0 {
            0 => Type::None
          , 1 => Type::Relocatable
          , 2 => Type::Executable
          , 3 => Type::SharedObject
          , 4 => Type::Core
          , anything => Type::Other(anything)
        }
    }
}

impl fmt::Debug for TypeRepr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_type().fmt(f)
    }
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Type { None
              , Relocatable
              , Executable
              , SharedObject
              , Core
              , Other(u16)
              }

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u16)]
pub enum Machine { None    = 0
                 , Sparc   = 0x02
                 , X86     = 0x03
                 , Mips    = 0x08
                 , PowerPc = 0x14
                 , Arm     = 0x28
                 , SuperH  = 0x2A
                 , Ia64    = 0x32
                 , X86_64  = 0x3E
                 , AArch64 = 0xB7
                 }
<commit_msg>feat(elf): add getters for more file header fields<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
use super::{ElfResult, ElfWord, Section, section};

use core::{fmt, mem};

pub trait Header {
    type Word: ElfWord;

    /// Attempt to extract an ELF file header from a slice of bytes.
    /// TODO: should this be a From impl maybe?
    //          - eliza, 03/08/2017
    fn from_slice<'a>(input: &'a [u8]) -> ElfResult<&'a Self>;

    /// Attempt to extract a section header from a slice of bytes.
    /// TODO: can/should the index be `usize`?
    //          - eliza, 03/08/2017
    fn parse_section<'a>(&'a self, input: &'a [u8], idx: u16)
                            -> ElfResult<&'a Section>;

    // Field accessors -------------------------------------------
    fn ident(&self) -> Ident;
    fn get_type(&self) -> Type;
    fn machine(&self) -> Machine;
    /// Offset of the program entry point
    fn entry_point(&self) -> usize;
    /// Offset of the start of program headers
    fn ph_offset(&self) -> usize;
    /// Number of program headers.
    fn ph_count(&self) -> usize;
    /// Size of a program header.
    /// TODO: add function for using this and `ph_count` to make a memrange
    ///       representing the program header entries?
    //          - eliza, 03/08/2017
    fn ph_entry_size(&self) -> usize;
    /// Offset of the start of [section header]s.
    ///
    /// [section header]: ../section/struct.Header.html
    fn sh_offset(&self) -> usize;
    /// Number of [section header]s.
    ///
    /// [section header]: ../section/struct.Header.html
    fn sh_count(&self) -> usize;
    /// Size of a [section header].
    ///
    /// [section header]: ../section/struct.Header.html
    /// TODO: add function for using this and `sh_count` to make a memrange
    ///       representing the section header entries?
    //          - eliza, 03/08/2017
    fn sh_entry_size(&self) -> usize;
    /// TODO: can this return the flags type?
    //          - eliza, 03/08/2017
    fn flags(&self) -> u32;
    /// Index of the section header [string table].
    ///
    /// [string table]: ../section/struct.StrTable.html"]
    fn sh_str_idx(&self) -> usize;

}

/// An ELF file header
#[derive(Copy, Clone, Debug)]
#[repr(C, packed)]
pub struct HeaderRepr<W: ElfWord> {
    /// the ELF [file identifier](struct.Ident.html)
    pub ident: Ident
  , elftype: TypeRepr
  , pub machine: Machine
  , /// Program entry point
    /// TODO: getters for turning these into `usize`?
    //          - eliza, 03/08/2017
    entry_point: W
  , /// Offset for start of program headers
    ph_offset: W
  , /// Offset for start of [section header]s.
    /// [section header]: ../section/struct.Header.html
    sh_offset: W
  , pub flags: u32
  , pub header_size: u16
  , pub ph_entry_size: u16
  , pub ph_count: u16
  , pub sh_entry_size: u16
  , pub sh_count: u16
  , /// Index of the section header string table
    sh_str_idx: u16
}

/// FIXME(style): generate more stuff with macros/use `macro_attr` to derive
///               these...
//                  - eliza, 03/08/2017
macro_rules! impl_getters {
    ($(#[$attr:meta])* pub fn $name:ident(&self) -> $ty:ident; $($rest:tt)*) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ($(#[$attr:meta])* fn $name:ident(&self) -> $ty:ident; $($rest:tt)*) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ( $(#[$attr:meta])* pub fn $name: ident (&self)-> $ty: ident; ) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
    };
    ( $(#[$attr:meta])* fn $name: ident (&self)-> $ty: ident; ) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
    };
    () => {};
}

impl Header for HeaderRepr<u64> {
    type Word = u64;

    /// Attempt to extract an ELF file header from a slice of bytes.
    /// TODO: can this also be macro-generated?
    ///         - eliza, 03/08/2017
    fn from_slice<'a>(input: &'a [u8]) -> ElfResult<&'a Self> {
        if input.len() < mem::size_of::<Self>() {
            Err("Input too short to extract ELF header")
        } else {
            unsafe { Ok(&super::extract_from_slice::<Self>(input, 0, 1)[0]) }
        }
    }

    /// Attempt to extract a section header from a slice of bytes.
    /// TODO: can this also be macro-generated?
    ///         - eliza, 03/08/2017
    fn parse_section<'a>(&'a self, input: &'a [u8], idx: u16)
                            -> ElfResult<&'a Section>
    {
        if idx < section::SHN_LORESERVE {
            Err("Cannot parse reserved section.")
        } else {
            let start: u64// start offset for section
                = self.sh_offset + idx as u64 * self.sh_entry_size as u64;
            let end: u64 // end offset for section
                = start + self.sh_entry_size as u64;
            let raw
                = &input[start as usize .. end as usize];

            match self.ident.class {
                Class::None => Err("Invalid ELF class (ELFCLASSNONE).")
              , Class::Elf32 => Err("Cannot parse 32-bit section from 64-bit \
                                     ELF file.")
              , Class::Elf64 => unsafe {
                    Ok(&*(raw as *const [u8] as *const u8 as *const Section))
                }
            }
        }
    }

    #[inline] fn get_type(&self) -> Type { self.elftype.as_type() }

    impl_getters! {
        #[doc = "Index for the start of [section header]s. \
                 [section header]: ../section/struct.Header.html"]
        fn sh_offset(&self) -> usize;
        fn sh_entry_size(&self) -> usize;
        fn sh_count(&self) -> usize;

        #[doc = "Index for the start of program headers"]
        fn ph_offset(&self) -> usize;
        fn ph_entry_size(&self) -> usize;
        fn ph_count(&self) -> usize;

        #[doc = "Index for the program entry point"]
        fn entry_point(&self) -> usize;
        #[doc = "Index of the section header [string table] \
                 [string table]: ../section/struct.StrTable.html"]
        fn sh_str_idx(&self) -> usize;
        fn flags(&self) -> u32;
        fn ident(&self) -> Ident;
        fn machine(&self) -> Machine;
    }

}

impl Header for HeaderRepr<u32> {

    type Word = u32;
    /// Attempt to extract an ELF file header from a slice of bytes.
    fn from_slice<'a>(input: &'a [u8]) -> ElfResult<&'a Self> {
        if input.len() < mem::size_of::<Self>() {
            Err("Input too short to extract ELF header")
        } else {
            unsafe { Ok(&super::extract_from_slice::<Self>(input, 0, 1)[0]) }
        }
    }

    /// Attempt to extract a section header from a slice of bytes.
    fn parse_section<'a>(&'a self, input: &'a [u8], idx: u16)
                            -> ElfResult<&'a Section>
    {
        if idx < section::SHN_LORESERVE {
            Err("Cannot parse reserved section.")
        } else {
            let start: u32// start offset for section
                = self.sh_offset + idx as u32 * self.sh_entry_size as u32;
            let end: u32 // end offset for section
                = start + self.sh_entry_size as u32;
            let raw
                = &input[start as usize .. end as usize];

            match self.ident.class {
                Class::None => Err("Invalid ELF class (ELFCLASSNONE).")
              , Class::Elf32 => unsafe {
                    Ok(&*(raw as *const [u8] as *const u8 as *const Section))
                }
              , Class::Elf64 => Err("Cannot parse 64-bit section from 32-bit \
                                     ELF file.")
            }
        }
    }

    #[inline] fn get_type(&self) -> Type { self.elftype.as_type() }

    impl_getters! {
        #[doc = "Index for the start of [section header]s. \
                 [section header]: ../section/struct.Header.html"]
        fn sh_offset(&self) -> usize;
        fn sh_entry_size(&self) -> usize;
        fn sh_count(&self) -> usize;

        #[doc = "Index for the start of program headers"]
        fn ph_offset(&self) -> usize;
        fn ph_entry_size(&self) -> usize;
        fn ph_count(&self) -> usize;

        #[doc = "Index for the program entry point"]
        fn entry_point(&self) -> usize;
        #[doc = "Index of the section header [string table] \
                 [string table]: ../section/struct.StrTable.html"]
        fn sh_str_idx(&self) -> usize;
        fn flags(&self) -> u32;
        fn ident(&self) -> Ident;
        fn machine(&self) -> Machine;
    }

}

/// ELF header magic
pub const MAGIC: Magic = [0x7f, b'E', b'L', b'F'];

/// Type of header magic
pub type Magic = [u8; 4];

/// ELF identifier (`e_ident` in the ELF standard)
#[derive(Copy, Clone, Debug)]
#[repr(C, packed)]
pub struct Ident {
    /// ELF magic numbers. Must be equal to the [ELF magic], `[0x7, E, L, F]`.
    ///
    /// [ELF magic]: constant.MAGIC.html
    pub magic: Magic
  , /// ELF [file class](enum.Class.html) (32- or 64-bit)
    pub class: Class
  , /// ELF [data encoding](enum.DataEncoding.html) (big- or little-endian)
    pub encoding: DataEncoding
  , /// ELF file [version](enum.Version.html)
    pub version: Version
  , /// What [operating system ABI] this file was compiled for.
    ///
    /// [operating system ABI]: enum.OsAbi.html
    pub abi: OsAbi
  , /// ABI version (often this is just padding)
    pub abi_version: u8
  , _padding: [u8; 7]
}

impl Ident {
    #[inline] pub fn check_magic(&self) -> bool { self.magic == MAGIC }

    /// Returns true if the identifier section identifies a valid ELF file.
    #[inline] pub fn is_valid(&self) -> bool {
        // the ELF magic number is correct
        self.check_magic() &&
        // the file class is either 32- or 64-bits
        self.class.is_valid() &&
        // the data encoding is either big- or little-endian
        self.encoding.is_valid()
    }
}

/// Identifies the class of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum Class {
    /// Invalid ELF class file (`ELFCLASSNONE` in the standard)
    None  = 0
  , /// 32-bit ELF file (`ELFCLASS32` in the standard)
    Elf32 = 1
  , /// 64-bit ELF file (`ELFCLASS64` in the standard)
    Elf64 = 2
}

impl Class {
    /// Returns true if the class field for this file is valid.
    #[inline]
    pub fn is_valid(&self) -> bool {
        match *self { Class::None => false
                    , _ => true
                    }
    }
}

/// Identifies the data encoding of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum DataEncoding {
    /// Invalid data encoding (`ELFDATANONE` in the standard)
    None  = 0
  , /// Twos-complement little-endian data encoding
    /// (`ELFDATA2LSB` in the standard)
    LittleEndian = 1
  , /// Twos-complement big-endian data encoding
    /// (`ELFDATA2MSB` in the standard)
    BigEndian = 2
}

impl DataEncoding {
    /// Returns true if the data encoding field for this file is valid.
    #[inline]
    pub fn is_valid(&self) -> bool {
        match *self { DataEncoding::None => false
                    , _ => true
                    }
    }
}

/// Operating system ABI
#[derive(Copy, Clone, Debug)]
#[repr(u8)]
pub enum OsAbi { /// Ox00 also represents "none"
                 SystemV = 0x00
               , HpUx    = 0x01
               , NetBsd  = 0x02
               , Linux   = 0x03
               , Solaris = 0x06
               , Aix     = 0x07
               , Irix    = 0x08
               , FreeBsd = 0x09
               , OpenBsd = 0x0C
               , OpenVms = 0x0D
               }

/// Identifies the version of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum Version { None = 0, Current = 1 }

#[derive(Clone, Copy, PartialEq)]
struct TypeRepr(u16);

impl TypeRepr {
    pub fn as_type(&self) -> Type {
        match self.0 {
            0 => Type::None
          , 1 => Type::Relocatable
          , 2 => Type::Executable
          , 3 => Type::SharedObject
          , 4 => Type::Core
          , anything => Type::Other(anything)
        }
    }
}

impl fmt::Debug for TypeRepr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_type().fmt(f)
    }
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Type { None
              , Relocatable
              , Executable
              , SharedObject
              , Core
              , Other(u16)
              }

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u16)]
pub enum Machine { None    = 0
                 , Sparc   = 0x02
                 , X86     = 0x03
                 , Mips    = 0x08
                 , PowerPc = 0x14
                 , Arm     = 0x28
                 , SuperH  = 0x2A
                 , Ia64    = 0x32
                 , X86_64  = 0x3E
                 , AArch64 = 0xB7
                 }
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! This module contains various useful pattern matching algorithms.
//! The implementations are based on the lecture notes
//! "Algorithmen auf Sequenzen", Kopczynski, Marschall, Martin and Rahmann, 2008 - 2015.
//!
//! * Algorithm of Horspool: fastest for a sufficiently large alphabet
//! * Shift And algorithm: fast for patterns with less than 64 symbols and very small alphabets.
//! * BNDM algorithm: fast for patterns with less than 64 symbols.
//! * BOM algorithm: fast for long patterns and small alphabet.
//! * KMP algorithm: the classical ancestor.
//! * Ukkonens algorithm: approximate pattern matching with dynamic programming.
//! * Myers algorithm: linear-time approximate pattern matching with edit distance for small patterns

pub mod shift_and;
pub mod kmp;
pub mod bom;
pub mod horspool;
pub mod bndm;
pub mod ukkonen;
pub mod myers;
<commit_msg>Added note about twoway crate.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! This module contains various useful pattern matching algorithms.
//! The implementations are based on the lecture notes
//! "Algorithmen auf Sequenzen", Kopczynski, Marschall, Martin and Rahmann, 2008 - 2015.
//!
//! * Algorithm of Horspool: fastest for a sufficiently large alphabet
//! * Shift And algorithm: fast for patterns with less than 64 symbols and very small alphabets.
//! * BNDM algorithm: fast for patterns with less than 64 symbols.
//! * BOM algorithm: fast for long patterns and small alphabet.
//! * KMP algorithm: the classical ancestor.
//! * Ukkonens algorithm: approximate pattern matching with dynamic programming.
//! * Myers algorithm: linear-time approximate pattern matching with edit distance for small patterns
//!
//! Another fast pattern matching algorithm is available in the twoway crate: https://crates.io/crates/twoway

pub mod shift_and;
pub mod kmp;
pub mod bom;
pub mod horspool;
pub mod bndm;
pub mod ukkonen;
pub mod myers;
<|endoftext|>


<commit_before>use std::collections::BTreeSet;

use value::Value;
use relation::{Relation, IndexSelect, ViewSelect};
use primitive::{Primitive, resolve_as_scalar};
use std::cmp::{min, max};

#[derive(Clone, Debug)]
pub struct Table {
    pub insert: Option<IndexSelect>,
    pub remove: Option<IndexSelect>,
}

#[derive(Clone, Debug)]
pub struct Union {
    pub selects: Vec<IndexSelect>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ConstraintOp {
    EQ,
    NEQ,
    LT,
    GT,
    LTE,
    GTE,
}

#[derive(Clone, Debug)]
pub struct Constraint {
    pub left: usize,
    pub op: ConstraintOp,
    pub right: usize,
}

impl Constraint {
    fn is_satisfied_by(&self, state: &[&Value]) -> bool {
        match self.op {
            ConstraintOp::EQ => state[self.left] == state[self.right],
            ConstraintOp::NEQ => state[self.left] != state[self.right],
            ConstraintOp::LT => state[self.left] < state[self.right],
            ConstraintOp::GT => state[self.left] > state[self.right],
            ConstraintOp::LTE => state[self.left] <= state[self.right],
            ConstraintOp::GTE => state[self.left] >= state[self.right],
        }
    }
}

#[derive(Clone, Debug)]
pub enum JoinSource {
    Relation{
        input: usize
    },
    Primitive{
        primitive: Primitive,
        arguments: Vec<usize>,
    },
}

#[derive(Clone, Debug)]
pub struct Join {
    pub constants: Vec<Value>,
    pub sources: Vec<JoinSource>,
    pub constraints: Vec<Vec<Constraint>>,
    pub select: ViewSelect,
}

#[derive(Clone, Debug)]
pub struct Reducer {
    pub primitive: Primitive,
    pub arguments: Vec<usize>,
}

#[derive(Clone, Debug)]
pub struct Aggregate {
    pub constants: Vec<Value>,
    pub outer: IndexSelect,
    pub inner: IndexSelect,
    pub limit_from: Option<usize>,
    pub limit_to: Option<usize>,
    pub reducers: Vec<Reducer>,
    pub selects_inner: bool,
    pub select: ViewSelect,
}

#[derive(Clone, Debug)]
pub enum View {
    Table(Table),
    Union(Union),
    Join(Join),
    Aggregate(Aggregate),
}

fn push_all<'a>(state: &mut Vec<&'a Value>, input: &'a Vec<Value>) {
    for value in input.iter() {
        state.push(value);
    }
}

fn pop_all<'a>(state: &mut Vec<&'a Value>, input: &'a Vec<Value>) {
    for _ in input.iter() {
        state.pop();
    }
}

fn join_step<'a>(join: &'a Join, ix: usize, inputs: &[&'a Relation], state: &mut Vec<&'a Value>, index: &mut BTreeSet<Vec<Value>>) {
    if ix == join.sources.len() {
        index.insert(join.select.select(&state[..]));
    } else {
        match join.sources[ix] {
            JoinSource::Relation{input} => {
                for values in inputs[input].index.iter() {
                    push_all(state, values);
                    if join.constraints[ix].iter().all(|constraint| constraint.is_satisfied_by(&state[..])) {
                        join_step(join, ix+1, inputs, state, index)
                    }
                    pop_all(state, values);
                }
            }
            JoinSource::Primitive{ref primitive, ref arguments, ..} => {
                for values in primitive.eval_from_join(&arguments[..], &state[..]).into_iter() {
                    // promise the borrow checker that we will pop values before we exit this scope
                    let values = unsafe { ::std::mem::transmute::<&Vec<Value>, &'a Vec<Value>>(&values) };
                    push_all(state, values);
                    if join.constraints[ix].iter().all(|constraint| constraint.is_satisfied_by(&state[..])) {
                        join_step(join, ix+1, inputs, state, index)
                    }
                    pop_all(state, values);
                }
            }
        }
    }
}

fn aggregate_step<'a>(aggregate: &Aggregate, input_sets: &'a [&[Vec<Value>]], state: &mut Vec<&'a Value>, index: &mut BTreeSet<Vec<Value>>) {
    if input_sets.len() == 0 {
        index.insert(aggregate.select.select(&state[..]));
    } else {
        for values in input_sets[0].iter() {
            push_all(state, values);
            aggregate_step(aggregate, &input_sets[1..], state, index);
            pop_all(state, values);
        }
    }
}

impl View {
    pub fn run(&self, old_output: &Relation, inputs: &[&Relation]) -> Option<Relation> {
        match *self {
            View::Table(_) => None,
            View::Union(ref union) => {
                assert_eq!(union.selects.len(), inputs.len());
                let mut output = Relation::new(
                    old_output.view.clone(),
                    old_output.fields.clone(),
                    old_output.names.clone()
                    );
                for select in union.selects.iter() {
                    for values in select.select(&inputs[..]) {
                        output.index.insert(values);
                    }
                }
                Some(output)
            }
            View::Join(ref join) => {
                let mut output = Relation::new(
                    old_output.view.clone(),
                    old_output.fields.clone(),
                    old_output.names.clone()
                    );
                let mut tuples = Vec::with_capacity(join.sources.len());
                join_step(join, 0, inputs, &mut tuples, &mut output.index);
                Some(output)
            }
            View::Aggregate(ref aggregate) => {
                let mut output = Relation::new(
                    old_output.view.clone(),
                    old_output.fields.clone(),
                    old_output.names.clone()
                    );
                let mut outer = aggregate.outer.select(&inputs[..]);
                let mut inner = aggregate.inner.select(&inputs[..]);
                outer.sort();
                outer.dedup();
                inner.sort();
                let constants = &aggregate.constants[..];
                let mut group_start = 0;
                for outer_values in outer.into_iter() {
                    let mut group_end = group_start;
                    while (group_end < inner.len())
                    && (inner[group_end][0..outer_values.len()] == outer_values[..]) {
                        group_end += 1;
                    }
                    let (group, output_values) = {
                        let limit_from = match aggregate.limit_from {
                            None => group_start,
                            Some(ix) => group_start
                                + resolve_as_scalar(ix, constants, &outer_values[..]).as_usize(),
                        };
                        let limit_to = match aggregate.limit_to {
                            None => group_end,
                            Some(ix) => group_start
                                + resolve_as_scalar(ix, constants, &outer_values[..]).as_usize(),
                        };
                        let limit_from = min(max(limit_from, group_start), group_end);
                        let limit_to = min(max(limit_to, limit_from), group_end);
                        let group = &inner[limit_from..limit_to];
                        let output_values = aggregate.reducers.iter().map(|reducer| {
                            reducer.primitive.eval_from_aggregate(&reducer.arguments[..], constants, &outer_values[..], group)
                        }).collect::<Vec<_>>();
                        (group, output_values)
                    };
                    let null = Value::Null;
                    let mut output_sets = vec![];
                    let mut state = outer_values.iter().collect::<Vec<_>>();
                    if aggregate.selects_inner {
                        output_sets.push(group);
                    } else {
                        // nasty hack - fill null values for inner so that the ixes work out right
                        for _ in aggregate.inner.mapping.iter() {
                            state.push(&null);
                        }
                    }
                    for output in output_values.iter() {
                        output_sets.push(output);
                    }
                    aggregate_step(aggregate, &output_sets[..], &mut state, &mut output.index);
                    group_start = group_end;
                }
                Some(output)
            }
        }
    }
}<commit_msg>Include constants in aggregate state<commit_after>use std::collections::BTreeSet;

use value::Value;
use relation::{Relation, IndexSelect, ViewSelect};
use primitive::{Primitive, resolve_as_scalar};
use std::cmp::{min, max};

#[derive(Clone, Debug)]
pub struct Table {
    pub insert: Option<IndexSelect>,
    pub remove: Option<IndexSelect>,
}

#[derive(Clone, Debug)]
pub struct Union {
    pub selects: Vec<IndexSelect>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ConstraintOp {
    EQ,
    NEQ,
    LT,
    GT,
    LTE,
    GTE,
}

#[derive(Clone, Debug)]
pub struct Constraint {
    pub left: usize,
    pub op: ConstraintOp,
    pub right: usize,
}

impl Constraint {
    fn is_satisfied_by(&self, state: &[&Value]) -> bool {
        match self.op {
            ConstraintOp::EQ => state[self.left] == state[self.right],
            ConstraintOp::NEQ => state[self.left] != state[self.right],
            ConstraintOp::LT => state[self.left] < state[self.right],
            ConstraintOp::GT => state[self.left] > state[self.right],
            ConstraintOp::LTE => state[self.left] <= state[self.right],
            ConstraintOp::GTE => state[self.left] >= state[self.right],
        }
    }
}

#[derive(Clone, Debug)]
pub enum JoinSource {
    Relation{
        input: usize
    },
    Primitive{
        primitive: Primitive,
        arguments: Vec<usize>,
    },
}

#[derive(Clone, Debug)]
pub struct Join {
    pub constants: Vec<Value>,
    pub sources: Vec<JoinSource>,
    pub constraints: Vec<Vec<Constraint>>,
    pub select: ViewSelect,
}

#[derive(Clone, Debug)]
pub struct Reducer {
    pub primitive: Primitive,
    pub arguments: Vec<usize>,
}

#[derive(Clone, Debug)]
pub struct Aggregate {
    pub constants: Vec<Value>,
    pub outer: IndexSelect,
    pub inner: IndexSelect,
    pub limit_from: Option<usize>,
    pub limit_to: Option<usize>,
    pub reducers: Vec<Reducer>,
    pub selects_inner: bool,
    pub select: ViewSelect,
}

#[derive(Clone, Debug)]
pub enum View {
    Table(Table),
    Union(Union),
    Join(Join),
    Aggregate(Aggregate),
}

fn push_all<'a>(state: &mut Vec<&'a Value>, input: &'a Vec<Value>) {
    for value in input.iter() {
        state.push(value);
    }
}

fn pop_all<'a>(state: &mut Vec<&'a Value>, input: &'a Vec<Value>) {
    for _ in input.iter() {
        state.pop();
    }
}

fn join_step<'a>(join: &'a Join, ix: usize, inputs: &[&'a Relation], state: &mut Vec<&'a Value>, index: &mut BTreeSet<Vec<Value>>) {
    if ix == join.sources.len() {
        index.insert(join.select.select(&state[..]));
    } else {
        match join.sources[ix] {
            JoinSource::Relation{input} => {
                for values in inputs[input].index.iter() {
                    push_all(state, values);
                    if join.constraints[ix].iter().all(|constraint| constraint.is_satisfied_by(&state[..])) {
                        join_step(join, ix+1, inputs, state, index)
                    }
                    pop_all(state, values);
                }
            }
            JoinSource::Primitive{ref primitive, ref arguments, ..} => {
                for values in primitive.eval_from_join(&arguments[..], &state[..]).into_iter() {
                    // promise the borrow checker that we will pop values before we exit this scope
                    let values = unsafe { ::std::mem::transmute::<&Vec<Value>, &'a Vec<Value>>(&values) };
                    push_all(state, values);
                    if join.constraints[ix].iter().all(|constraint| constraint.is_satisfied_by(&state[..])) {
                        join_step(join, ix+1, inputs, state, index)
                    }
                    pop_all(state, values);
                }
            }
        }
    }
}

fn aggregate_step<'a>(aggregate: &Aggregate, input_sets: &'a [&[Vec<Value>]], state: &mut Vec<&'a Value>, index: &mut BTreeSet<Vec<Value>>) {
    if input_sets.len() == 0 {
        index.insert(aggregate.select.select(&state[..]));
    } else {
        for values in input_sets[0].iter() {
            push_all(state, values);
            aggregate_step(aggregate, &input_sets[1..], state, index);
            pop_all(state, values);
        }
    }
}

impl View {
    pub fn run(&self, old_output: &Relation, inputs: &[&Relation]) -> Option<Relation> {
        match *self {
            View::Table(_) => None,
            View::Union(ref union) => {
                assert_eq!(union.selects.len(), inputs.len());
                let mut output = Relation::new(
                    old_output.view.clone(),
                    old_output.fields.clone(),
                    old_output.names.clone()
                    );
                for select in union.selects.iter() {
                    for values in select.select(&inputs[..]) {
                        output.index.insert(values);
                    }
                }
                Some(output)
            }
            View::Join(ref join) => {
                let mut output = Relation::new(
                    old_output.view.clone(),
                    old_output.fields.clone(),
                    old_output.names.clone()
                    );
                let mut tuples = Vec::with_capacity(join.sources.len());
                join_step(join, 0, inputs, &mut tuples, &mut output.index);
                Some(output)
            }
            View::Aggregate(ref aggregate) => {
                let mut output = Relation::new(
                    old_output.view.clone(),
                    old_output.fields.clone(),
                    old_output.names.clone()
                    );
                let mut outer = aggregate.outer.select(&inputs[..]);
                let mut inner = aggregate.inner.select(&inputs[..]);
                outer.sort();
                outer.dedup();
                inner.sort();
                let constants = &aggregate.constants[..];
                let mut group_start = 0;
                for outer_values in outer.into_iter() {
                    let mut group_end = group_start;
                    while (group_end < inner.len())
                    && (inner[group_end][0..outer_values.len()] == outer_values[..]) {
                        group_end += 1;
                    }
                    let (group, output_values) = {
                        let limit_from = match aggregate.limit_from {
                            None => group_start,
                            Some(ix) => group_start
                                + resolve_as_scalar(ix, constants, &outer_values[..]).as_usize(),
                        };
                        let limit_to = match aggregate.limit_to {
                            None => group_end,
                            Some(ix) => group_start
                                + resolve_as_scalar(ix, constants, &outer_values[..]).as_usize(),
                        };
                        let limit_from = min(max(limit_from, group_start), group_end);
                        let limit_to = min(max(limit_to, limit_from), group_end);
                        let group = &inner[limit_from..limit_to];
                        let output_values = aggregate.reducers.iter().map(|reducer| {
                            reducer.primitive.eval_from_aggregate(&reducer.arguments[..], constants, &outer_values[..], group)
                        }).collect::<Vec<_>>();
                        (group, output_values)
                    };
                    let mut output_sets = vec![];
                    let null = Value::Null;
                    if aggregate.selects_inner {
                        output_sets.push(group);
                    } else {
                        // nasty hack - fill null values for inner so that the ixes work out right
                        for _ in aggregate.inner.mapping.iter() {
                            state.push(&null);
                        }
                    }
                    for output in output_values.iter() {
                        output_sets.push(output);
                    }
                    let mut state = constants.iter().chain(outer_values.iter()).collect::<Vec<_>>();
                    aggregate_step(aggregate, &output_sets[..], &mut state, &mut output.index);
                    group_start = group_end;
                }
                Some(output)
            }
        }
    }
}<|endoftext|>