<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![allow(clippy::integer_arithmetic)]

use crate::{utils, Result};
use std::{
    io::{self, Write},
    num::NonZeroUsize,
    panic::{catch_unwind, AssertUnwindSafe},
    path::Path,
    process,
    sync::mpsc::{channel, Sender},
    thread,
};
use structopt::{clap::arg_enum, StructOpt};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

#[derive(Debug, StructOpt)]
#[structopt(about = "Datatest-harness for running data-driven tests")]
struct TestOpts {
    /// The FILTER string is tested against the name of all tests, and only those tests whose names
    /// contain the filter are run.
    filter: Option<String>,
    #[structopt(long = "exact")]
    /// Exactly match filters rather than by substring
    filter_exact: bool,
    #[structopt(long, default_value = "32", env = "RUST_TEST_THREADS")]
    /// Number of threads used for running tests in parallel
    test_threads: NonZeroUsize,
    #[structopt(short = "q", long)]
    /// Output minimal information
    quiet: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    nocapture: bool,
    #[structopt(long)]
    /// List all tests
    list: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    ignored: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    include_ignored: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    force_run_in_process: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    exclude_should_panic: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    test: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    bench: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    logfile: Option<String>,
    #[structopt(long, number_of_values = 1)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    skip: Vec<String>,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    show_output: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    color: Option<String>,
    #[structopt(long)]
    /// Configure formatting of output:
    ///   pretty = Print verbose output;
    ///   terse = Display one character per test;
    ///   (json is unsupported, exists for compatibility with the default test harness)
    #[structopt(possible_values = &Format::variants(), default_value, case_insensitive = true)]
    format: Format,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    report_time: Option<String>,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    ensure_time: bool,
}

arg_enum! {
    #[derive(Debug, Eq, PartialEq)]
    enum Format {
        Pretty,
        Terse,
        Json,
    }
}

impl Default for Format {
    fn default() -> Self {
        Format::Pretty
    }
}

pub fn runner(reqs: &[Requirements]) {
    let options = TestOpts::from_args();

    let tests: Vec<Test> = reqs.iter().flat_map(|req| req.expand()).collect();

    if options.list {
        for test in &tests {
            println!("{}: test", test.name);
        }

        if options.format == Format::Pretty {
            println!();
            println!("{} tests, 0 benchmarks", tests.len());
        }
        return;
    }

    match run_tests(options, tests) {
        Ok(true) => {}
        Ok(false) => process::exit(101),
        Err(e) => {
            eprintln!("error: io error when running tests: {:?}", e);
            process::exit(101);
        }
    }
}

struct Test {
    testfn: Box<dyn Fn() -> Result<()> + Send>,
    name: String,
}

enum TestResult {
    Ok,
    Failed,
    FailedWithMsg(String),
}

fn run_tests(options: TestOpts, tests: Vec<Test>) -> io::Result<bool> {
    let total = tests.len();

    // Filter out tests
    let mut remaining = match &options.filter {
        None => tests,
        Some(filter) => tests
            .into_iter()
            .filter(|test| {
                if options.filter_exact {
                    test.name == filter[..]
                } else {
                    test.name.contains(&filter[..])
                }
            })
            .rev()
            .collect(),
    };

    let filtered_out = total - remaining.len();
    let mut summary = TestSummary::new(total, filtered_out);

    if !options.quiet {
        summary.write_starting_msg()?;
    }

    let (tx, rx) = channel();

    let mut pending = 0;
    while pending > 0 || !remaining.is_empty() {
        while pending < options.test_threads.get() && !remaining.is_empty() {
            let test = remaining.pop().unwrap();
            run_test(test, tx.clone());
            pending += 1;
        }

        let (name, result) = rx.recv().unwrap();
        summary.handle_result(name, result)?;

        pending -= 1;
    }

    // Write Test Summary
    if !options.quiet {
        summary.write_summary()?;
    }

    Ok(summary.success())
}

fn run_test(test: Test, channel: Sender<(String, TestResult)>) {
    let Test { name, testfn } = test;

    let cfg = thread::Builder::new().name(name.clone());
    cfg.spawn(move || {
        let result = match catch_unwind(AssertUnwindSafe(|| testfn())) {
            Ok(Ok(())) => TestResult::Ok,
            Ok(Err(e)) => TestResult::FailedWithMsg(format!("{:?}", e)),
            Err(_) => TestResult::Failed,
        };

        channel.send((name, result)).unwrap();
    })
    .unwrap();
}

struct TestSummary {
    stdout: StandardStream,
    total: usize,
    filtered_out: usize,
    passed: usize,
    failed: Vec<String>,
}

impl TestSummary {
    fn new(total: usize, filtered_out: usize) -> Self {
        Self {
            stdout: StandardStream::stdout(ColorChoice::Auto),
            total,
            filtered_out,
            passed: 0,
            failed: Vec::new(),
        }
    }

    fn handle_result(&mut self, name: String, result: TestResult) -> io::Result<()> {
        write!(self.stdout, "test {} ... ", name)?;
        match result {
            TestResult::Ok => {
                self.passed += 1;
                self.write_ok()?;
            }
            TestResult::Failed => {
                self.failed.push(name);
                self.write_failed()?;
            }
            TestResult::FailedWithMsg(msg) => {
                self.failed.push(name);
                self.write_failed()?;
                writeln!(self.stdout)?;

                write!(self.stdout, "Error: {}", msg)?;
            }
        }
        writeln!(self.stdout)?;
        Ok(())
    }

    fn write_ok(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
        write!(self.stdout, "ok")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_failed(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
        write!(self.stdout, "FAILED")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_starting_msg(&mut self) -> io::Result<()> {
        writeln!(self.stdout)?;
        writeln!(
            self.stdout,
            "running {} tests",
            self.total - self.filtered_out
        )?;
        Ok(())
    }

    fn write_summary(&mut self) -> io::Result<()> {
        // Print out the failing tests
        if !self.failed.is_empty() {
            writeln!(self.stdout)?;
            writeln!(self.stdout, "failures:")?;
            for name in &self.failed {
                writeln!(self.stdout, "    {}", name)?;
            }
        }

        writeln!(self.stdout)?;
        write!(self.stdout, "test result: ")?;
        if self.failed.is_empty() {
            self.write_ok()?;
        } else {
            self.write_failed()?;
        }
        writeln!(
            self.stdout,
            ". {} passed; {} failed; {} filtered out",
            self.passed,
            self.failed.len(),
            self.filtered_out
        )?;
        writeln!(self.stdout)?;
        Ok(())
    }

    fn success(&self) -> bool {
        self.failed.is_empty()
    }
}

pub struct Requirements {
    test: fn(&Path) -> Result<()>,
    test_name: String,
    root: String,
    pattern: String,
}

impl Requirements {
    pub fn new(
        test: fn(&Path) -> Result<()>,
        test_name: String,
        root: String,
        pattern: String,
    ) -> Self {
        Self {
            test,
            test_name,
            root,
            pattern,
        }
    }

    /// Generate standard test descriptors ([`test::TestDescAndFn`]) from the descriptor of
    /// `#[datatest::files(..)]`.
    ///
    /// Scans all files in a given directory, finds matching ones and generates a test descriptor
    /// for each of them.
    fn expand(&self) -> Vec<Test> {
        let root = Path::new(&self.root).to_path_buf();

        let re = regex::Regex::new(&self.pattern)
            .unwrap_or_else(|_| panic!("invalid regular expression: '{}'", self.pattern));

        let tests: Vec<_> = utils::iterate_directory(&root)
            .filter_map(|path| {
                let input_path = path.to_string_lossy();
                if re.is_match(&input_path) {
                    let testfn = self.test;
                    let name = utils::derive_test_name(&root, &path, &self.test_name);
                    let testfn = Box::new(move || (testfn)(&path));

                    Some(Test { testfn, name })
                } else {
                    None
                }
            })
            .collect();

        // We want to avoid silent fails due to typos in regexp!
        if tests.is_empty() {
            panic!(
                "no test cases found for test '{}'. Scanned directory: '{}' with pattern '{}'",
                self.test_name, self.root, self.pattern,
            );
        }

        tests
    }
}
<commit_msg>[datatest-stable] handle the --ignored flag<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![allow(clippy::integer_arithmetic)]

use crate::{utils, Result};
use std::{
    io::{self, Write},
    num::NonZeroUsize,
    panic::{catch_unwind, AssertUnwindSafe},
    path::Path,
    process,
    sync::mpsc::{channel, Sender},
    thread,
};
use structopt::{clap::arg_enum, StructOpt};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

#[derive(Debug, StructOpt)]
#[structopt(about = "Datatest-harness for running data-driven tests")]
struct TestOpts {
    /// The FILTER string is tested against the name of all tests, and only those tests whose names
    /// contain the filter are run.
    filter: Option<String>,
    #[structopt(long = "exact")]
    /// Exactly match filters rather than by substring
    filter_exact: bool,
    #[structopt(long, default_value = "32", env = "RUST_TEST_THREADS")]
    /// Number of threads used for running tests in parallel
    test_threads: NonZeroUsize,
    #[structopt(short = "q", long)]
    /// Output minimal information
    quiet: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    nocapture: bool,
    #[structopt(long)]
    /// List all tests
    list: bool,
    #[structopt(long)]
    /// List or run ignored tests (always empty: it is currently not possible to mark tests as
    /// ignored)
    ignored: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    include_ignored: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    force_run_in_process: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    exclude_should_panic: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    test: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    bench: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    logfile: Option<String>,
    #[structopt(long, number_of_values = 1)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    skip: Vec<String>,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    show_output: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    color: Option<String>,
    #[structopt(long)]
    /// Configure formatting of output:
    ///   pretty = Print verbose output;
    ///   terse = Display one character per test;
    ///   (json is unsupported, exists for compatibility with the default test harness)
    #[structopt(possible_values = &Format::variants(), default_value, case_insensitive = true)]
    format: Format,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    report_time: Option<String>,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    ensure_time: bool,
}

arg_enum! {
    #[derive(Debug, Eq, PartialEq)]
    enum Format {
        Pretty,
        Terse,
        Json,
    }
}

impl Default for Format {
    fn default() -> Self {
        Format::Pretty
    }
}

pub fn runner(reqs: &[Requirements]) {
    let options = TestOpts::from_args();

    let tests: Vec<Test> = if options.ignored {
        // Currently impossible to mark tests as ignored.
        // TODO: add support for this in the future, probably by supporting an "ignored" dir
        vec![]
    } else {
        reqs.iter().flat_map(|req| req.expand()).collect()
    };

    if options.list {
        for test in &tests {
            println!("{}: test", test.name);
        }

        if options.format == Format::Pretty {
            println!();
            println!("{} tests, 0 benchmarks", tests.len());
        }
        return;
    }

    match run_tests(options, tests) {
        Ok(true) => {}
        Ok(false) => process::exit(101),
        Err(e) => {
            eprintln!("error: io error when running tests: {:?}", e);
            process::exit(101);
        }
    }
}

struct Test {
    testfn: Box<dyn Fn() -> Result<()> + Send>,
    name: String,
}

enum TestResult {
    Ok,
    Failed,
    FailedWithMsg(String),
}

fn run_tests(options: TestOpts, tests: Vec<Test>) -> io::Result<bool> {
    let total = tests.len();

    // Filter out tests
    let mut remaining = match &options.filter {
        None => tests,
        Some(filter) => tests
            .into_iter()
            .filter(|test| {
                if options.filter_exact {
                    test.name == filter[..]
                } else {
                    test.name.contains(&filter[..])
                }
            })
            .rev()
            .collect(),
    };

    let filtered_out = total - remaining.len();
    let mut summary = TestSummary::new(total, filtered_out);

    if !options.quiet {
        summary.write_starting_msg()?;
    }

    let (tx, rx) = channel();

    let mut pending = 0;
    while pending > 0 || !remaining.is_empty() {
        while pending < options.test_threads.get() && !remaining.is_empty() {
            let test = remaining.pop().unwrap();
            run_test(test, tx.clone());
            pending += 1;
        }

        let (name, result) = rx.recv().unwrap();
        summary.handle_result(name, result)?;

        pending -= 1;
    }

    // Write Test Summary
    if !options.quiet {
        summary.write_summary()?;
    }

    Ok(summary.success())
}

fn run_test(test: Test, channel: Sender<(String, TestResult)>) {
    let Test { name, testfn } = test;

    let cfg = thread::Builder::new().name(name.clone());
    cfg.spawn(move || {
        let result = match catch_unwind(AssertUnwindSafe(|| testfn())) {
            Ok(Ok(())) => TestResult::Ok,
            Ok(Err(e)) => TestResult::FailedWithMsg(format!("{:?}", e)),
            Err(_) => TestResult::Failed,
        };

        channel.send((name, result)).unwrap();
    })
    .unwrap();
}

struct TestSummary {
    stdout: StandardStream,
    total: usize,
    filtered_out: usize,
    passed: usize,
    failed: Vec<String>,
}

impl TestSummary {
    fn new(total: usize, filtered_out: usize) -> Self {
        Self {
            stdout: StandardStream::stdout(ColorChoice::Auto),
            total,
            filtered_out,
            passed: 0,
            failed: Vec::new(),
        }
    }

    fn handle_result(&mut self, name: String, result: TestResult) -> io::Result<()> {
        write!(self.stdout, "test {} ... ", name)?;
        match result {
            TestResult::Ok => {
                self.passed += 1;
                self.write_ok()?;
            }
            TestResult::Failed => {
                self.failed.push(name);
                self.write_failed()?;
            }
            TestResult::FailedWithMsg(msg) => {
                self.failed.push(name);
                self.write_failed()?;
                writeln!(self.stdout)?;

                write!(self.stdout, "Error: {}", msg)?;
            }
        }
        writeln!(self.stdout)?;
        Ok(())
    }

    fn write_ok(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
        write!(self.stdout, "ok")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_failed(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
        write!(self.stdout, "FAILED")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_starting_msg(&mut self) -> io::Result<()> {
        writeln!(self.stdout)?;
        writeln!(
            self.stdout,
            "running {} tests",
            self.total - self.filtered_out
        )?;
        Ok(())
    }

    fn write_summary(&mut self) -> io::Result<()> {
        // Print out the failing tests
        if !self.failed.is_empty() {
            writeln!(self.stdout)?;
            writeln!(self.stdout, "failures:")?;
            for name in &self.failed {
                writeln!(self.stdout, "    {}", name)?;
            }
        }

        writeln!(self.stdout)?;
        write!(self.stdout, "test result: ")?;
        if self.failed.is_empty() {
            self.write_ok()?;
        } else {
            self.write_failed()?;
        }
        writeln!(
            self.stdout,
            ". {} passed; {} failed; {} filtered out",
            self.passed,
            self.failed.len(),
            self.filtered_out
        )?;
        writeln!(self.stdout)?;
        Ok(())
    }

    fn success(&self) -> bool {
        self.failed.is_empty()
    }
}

pub struct Requirements {
    test: fn(&Path) -> Result<()>,
    test_name: String,
    root: String,
    pattern: String,
}

impl Requirements {
    pub fn new(
        test: fn(&Path) -> Result<()>,
        test_name: String,
        root: String,
        pattern: String,
    ) -> Self {
        Self {
            test,
            test_name,
            root,
            pattern,
        }
    }

    /// Generate standard test descriptors ([`test::TestDescAndFn`]) from the descriptor of
    /// `#[datatest::files(..)]`.
    ///
    /// Scans all files in a given directory, finds matching ones and generates a test descriptor
    /// for each of them.
    fn expand(&self) -> Vec<Test> {
        let root = Path::new(&self.root).to_path_buf();

        let re = regex::Regex::new(&self.pattern)
            .unwrap_or_else(|_| panic!("invalid regular expression: '{}'", self.pattern));

        let tests: Vec<_> = utils::iterate_directory(&root)
            .filter_map(|path| {
                let input_path = path.to_string_lossy();
                if re.is_match(&input_path) {
                    let testfn = self.test;
                    let name = utils::derive_test_name(&root, &path, &self.test_name);
                    let testfn = Box::new(move || (testfn)(&path));

                    Some(Test { testfn, name })
                } else {
                    None
                }
            })
            .collect();

        // We want to avoid silent fails due to typos in regexp!
        if tests.is_empty() {
            panic!(
                "no test cases found for test '{}'. Scanned directory: '{}' with pattern '{}'",
                self.test_name, self.root, self.pattern,
            );
        }

        tests
    }
}
<|endoftext|>


<commit_before>use ffi;

use Push;
use PushGuard;
use AsMutLua;

use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use std::mem;

fn push_iter<L, V, I>(mut lua: L, iterator: I) -> PushGuard<L>
                      where L: AsMutLua, V: for<'b> Push<&'b mut L>, I: Iterator<Item=V>
{
    // creating empty table
    unsafe { ffi::lua_newtable(lua.as_mut_lua().0) };

    for (index, elem) in iterator.enumerate() {
        let size = {
            let pushed_cnt = elem.push_to_lua(&mut lua);

            let size = pushed_cnt.size;
            unsafe { mem::forget(pushed_cnt) };
            size
        };

        match size {
            0 => continue,
            1 => {
                let index = index as u32;
                index.push_to_lua(&mut lua);
                unsafe { ffi::lua_insert(lua.as_mut_lua().0, -2) }
                unsafe { ffi::lua_settable(lua.as_mut_lua().0, -3) }
            },
            2 => unsafe { ffi::lua_settable(lua.as_mut_lua().0, -3) },
            _ => unreachable!()
        }
    }

    PushGuard { lua: lua, size: 1 }
}

fn push_rec_iter<L, V, I>(mut lua: L, iterator: I) -> PushGuard<L>
                          where L: AsMutLua, V: for<'a> Push<&'a mut L>, I: Iterator<Item=V>
{
    let (nrec, _) = iterator.size_hint();

    // creating empty table with pre-allocated non-array elements
    unsafe { ffi::lua_createtable(lua.as_mut_lua().0, 0, nrec as i32) };

    for elem in iterator {
        let size = {
            let pushed_cnt = elem.push_to_lua(&mut lua);
            let size = pushed_cnt.size;
            unsafe { mem::forget(pushed_cnt) };
            size
        };

        match size {
            0 => continue,
            2 => unsafe { ffi::lua_settable(lua.as_mut_lua().0, -3) },
            _ => unreachable!()
        }
    }

    PushGuard { lua: lua, size: 1 }
}

impl<L, T> Push<L> for Vec<T> where L: AsMutLua, T: for<'a> Push<&'a mut L> {
    fn push_to_lua(self, lua: L) -> PushGuard<L> {
        push_iter(lua, self.into_iter())
    }
}

impl<'a, L, T> Push<L> for &'a [T] where L: AsMutLua, T: Clone + for<'b> Push<&'b mut L> {
    fn push_to_lua(self, lua: L) -> PushGuard<L> {
        push_iter(lua, self.iter().map(|e| e.clone()))
    }
}

impl<L, K, V> Push<L> for HashMap<K, V> where L: AsMutLua, K: for<'a, 'b> Push<&'a mut &'b mut L> + Eq + Hash, V: for<'a, 'b> Push<&'a mut &'b mut L> {
    fn push_to_lua(self, lua: L) -> PushGuard<L> {
        push_rec_iter(lua, self.into_iter())
    }
}

impl<L, K> Push<L> for HashSet<K> where L: AsMutLua, K: for<'a, 'b> Push<&'a mut &'b mut L> + Eq + Hash {
    fn push_to_lua(self, lua: L) -> PushGuard<L> {
        use std::iter;
        push_rec_iter(lua, self.into_iter().zip(iter::repeat(true)))
    }
}
<commit_msg>Fix push_iter implementation in rust_tables<commit_after>use ffi;

use Push;
use PushGuard;
use AsMutLua;

use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use std::iter;
use std::mem;

fn push_iter<L, V, I>(mut lua: L, iterator: I) -> PushGuard<L>
                      where L: AsMutLua, V: for<'b> Push<&'b mut L>, I: Iterator<Item=V>
{
    // creating empty table
    unsafe { ffi::lua_newtable(lua.as_mut_lua().0) };

    for (elem, index) in iterator.zip(iter::count(1, 1)) {
        let size = elem.push_to_lua(&mut lua).forget();

        match size {
            0 => continue,
            1 => {
                let index = index as u32;
                index.push_to_lua(&mut lua).forget();
                unsafe { ffi::lua_insert(lua.as_mut_lua().0, -2) }
                unsafe { ffi::lua_settable(lua.as_mut_lua().0, -3) }
            },
            2 => unsafe { ffi::lua_settable(lua.as_mut_lua().0, -3) },
            _ => unreachable!()
        }
    }

    PushGuard { lua: lua, size: 1 }
}

fn push_rec_iter<L, V, I>(mut lua: L, iterator: I) -> PushGuard<L>
                          where L: AsMutLua, V: for<'a> Push<&'a mut L>, I: Iterator<Item=V>
{
    let (nrec, _) = iterator.size_hint();

    // creating empty table with pre-allocated non-array elements
    unsafe { ffi::lua_createtable(lua.as_mut_lua().0, 0, nrec as i32) };

    for elem in iterator {
        let size = elem.push_to_lua(&mut lua).forget();

        match size {
            0 => continue,
            2 => unsafe { ffi::lua_settable(lua.as_mut_lua().0, -3) },
            _ => unreachable!()
        }
    }

    PushGuard { lua: lua, size: 1 }
}

impl<L, T> Push<L> for Vec<T> where L: AsMutLua, T: for<'a> Push<&'a mut L> {
    fn push_to_lua(self, lua: L) -> PushGuard<L> {
        push_iter(lua, self.into_iter())
    }
}

impl<'a, L, T> Push<L> for &'a [T] where L: AsMutLua, T: Clone + for<'b> Push<&'b mut L> {
    fn push_to_lua(self, lua: L) -> PushGuard<L> {
        push_iter(lua, self.iter().map(|e| e.clone()))
    }
}

impl<L, K, V> Push<L> for HashMap<K, V> where L: AsMutLua, K: for<'a, 'b> Push<&'a mut &'b mut L> + Eq + Hash, V: for<'a, 'b> Push<&'a mut &'b mut L> {
    fn push_to_lua(self, lua: L) -> PushGuard<L> {
        push_rec_iter(lua, self.into_iter())
    }
}

impl<L, K> Push<L> for HashSet<K> where L: AsMutLua, K: for<'a, 'b> Push<&'a mut &'b mut L> + Eq + Hash {
    fn push_to_lua(self, lua: L) -> PushGuard<L> {
        use std::iter;
        push_rec_iter(lua, self.into_iter().zip(iter::repeat(true)))
    }
}
<|endoftext|>


<commit_before>#![warn(unused_results)]

use data_encoding::{DecodeKind, Encoding};
use getopts::Options;
use std::fs::File;
use std::io::{Read, Write};

macro_rules! check {
    ($e: expr, $c: expr) => {
        if !$c {
            return Err($e);
        }
    };
}

#[derive(Debug)]
pub enum Error {
    ParseOpts(getopts::Fail),
    ExtraArgs(Vec<String>),
    Cmdline(String),
    Decode(data_encoding::DecodeError),
    Builder(data_encoding::SpecificationError),
    IO(String, std::io::Error),
    Read(std::io::Error),
    Write(std::io::Error),
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use self::Error::*;
        match self {
            ParseOpts(ref e) => e.fmt(f),
            ExtraArgs(ref a) => write!(f, "Unexpected arguments {:?}", a),
            Cmdline(ref m) => write!(f, "{}", m),
            Decode(ref e) => e.fmt(f),
            Builder(ref e) => e.fmt(f),
            IO(ref p, ref e) => write!(f, "{}: {}", p, e),
            Read(ref e) => write!(f, "Read error: {}", e),
            Write(ref e) => write!(f, "Write error: {}", e),
        }
    }
}

type Result<T> = std::result::Result<T, Error>;

fn floor(x: usize, d: usize) -> usize {
    x / d * d
}
fn ceil(x: usize, d: usize) -> usize {
    floor(x + d - 1, d)
}

#[test]
fn floor_ceil() {
    assert_eq!(floor(10, 5), 10);
    assert_eq!(floor(13, 5), 10);
    assert_eq!(floor(15, 5), 15);
    assert_eq!(ceil(10, 5), 10);
    assert_eq!(ceil(13, 5), 15);
    assert_eq!(ceil(15, 5), 15);
}

fn encode_block(base: &Encoding) -> usize {
    match base.bit_width() {
        1 | 2 | 4 => 1,
        3 | 6 => 3,
        5 => 5,
        _ => unreachable!(),
    }
}
fn decode_block(base: &Encoding) -> usize {
    encode_block(base) * 8 / base.bit_width()
}

pub fn encode<R: Read, W: Write>(
    base: &Encoding, wrap: usize, mut reader: R, mut writer: W, size: usize,
) -> Result<()> {
    let block = if wrap == 0 {
        encode_block(base)
    } else {
        assert_eq!(wrap * base.bit_width() % 8, 0);
        wrap * base.bit_width() / 8
    };
    assert_eq!(block % encode_block(base), 0);
    assert!(size >= block);
    let mut input = vec![0u8; size];
    let mut output = vec![0u8; base.encode_len(size)];
    let mut rest = 0;
    loop {
        let ilen = reader.read(&mut input[rest ..]).map_err(Error::Read)?;
        let next = if ilen == 0 { rest } else { floor(rest + ilen, block) };
        let olen = base.encode_len(next);
        base.encode_mut(&input[0 .. next], &mut output[0 .. olen]);
        writer.write_all(&output[0 .. olen]).map_err(Error::Write)?;
        if ilen == 0 {
            return Ok(());
        }
        rest = rest + ilen - next;
        for i in 0 .. rest {
            input[i] = input[next + i];
        }
    }
}

pub fn decode<R, W>(base: &Encoding, mut reader: R, mut writer: W, size: usize) -> Result<()>
where
    R: Read,
    W: Write,
{
    let block = decode_block(base);
    assert!(size >= block);
    let mut input = vec![0u8; size];
    let mut output = vec![0u8; base.decode_len(ceil(size, block)).unwrap()];
    let mut pos = 0;
    let mut rest = 0;
    loop {
        let ilen = reader.read(&mut input[rest ..]).map_err(Error::Read)?;
        let next = if ilen == 0 { rest } else { floor(rest + ilen, block) };
        let mlen = base.decode_len(next).map_err(|mut error| {
            error.position += pos;
            Error::Decode(error)
        })?;
        let (next, olen) = match base.decode_mut(&input[0 .. next], &mut output[0 .. mlen]) {
            Ok(olen) => (next, olen),
            Err(mut partial) => {
                if partial.error.kind != DecodeKind::Length {
                    partial.error.position += pos;
                    return Err(Error::Decode(partial.error));
                }
                assert_ne!(ilen, 0);
                (partial.read, partial.written)
            }
        };
        writer.write_all(&output[0 .. olen]).map_err(Error::Write)?;
        rest = rest + ilen - next;
        if ilen == 0 {
            return Ok(());
        }
        for i in 0 .. rest {
            input[i] = input[next + i];
        }
        pos += next;
    }
}

fn main() {
    let (program, args): (_, Vec<_>) = {
        let mut i = std::env::args();
        match i.next() {
            None => ("data-encoding".into(), vec![]),
            Some(p) => (p, i.collect()),
        }
    };
    let program = program.rsplit('/').next().unwrap_or(&program);

    if let Err(e) = wrapped_main(program, args) {
        let _ = writeln!(&mut std::io::stderr(), "{}: {}", program, e);
        std::process::exit(1)
    }
}

fn wrapped_main(program: &str, args: Vec<String>) -> Result<()> {
    let mut opts = Options::new();
    let _ = opts
        .reqopt("m", "mode", "{encode|decode|specification} or any prefix of those", "<mode>")
        .optopt("b", "base", "{16|hex|32|32hex|64|64url}", "<base>")
        .optopt("i", "input", "read from <file> instead of standard input", "<file>")
        .optopt("o", "output", "write to <file> instead of standard output", "<file>")
        .optopt("", "block", "read blocks of about <size> bytes", "<size>")
        .optopt("p", "padding", "pad with <padding>", "<padding>")
        .optopt("g", "ignore", "when decoding, ignore characters in <ignore>", "<ignore>")
        .optopt("w", "width", "when encoding, wrap every <cols> characters", "<cols>")
        .optopt("s", "separator", "when encoding, wrap with <separator>", "<separator>")
        .optopt("", "symbols", "define a custom base using <symbols>", "<symbols>")
        .optopt("", "translate", "when decoding, translate <new> as <old>", "<new><old>")
        .optflag("", "ignore_trailing_bits", "when decoding, ignore non-zero trailing bits")
        .optflag("", "least_significant_bit_first", "use least significant bit first bit-order");

    if args.len() == 1 && (args[0] == "--help" || args[0] == "-h") {
        let brief = format!(
            r"Usage: {program} --mode=<mode> --base=<base> [<options>]
Usage: {program} --mode=<mode> --symbols=<symbols> [<options>]",
            program = program
        );
        print!(
            "{0}
Examples:
    # Using the RFC4648 base64 encoding
    {1} -menc -b64   # Encode without padding
    {1} -me -b64 -p= # Encode with padding
    {1} -mdec -b64   # Decode without padding
    {1} -md -b64 -p= # Decode with padding

    # Encode using the MIME base64 encoding
    {1} -me -b64 -p= -w76 -s$'\\r\\n'

    # Show base information for the permissive hexadecimal encoding
    {1} --mode=specification --base=hex

    # Decode using the DNSCurve base32 encoding
    {1} --mode=decode \\
        --symbols=0123456789bcdfghjklmnpqrstuvwxyz \\
        --translate=BCDFGHJKLMNPQRSTUVWXYZbcdfghjklmnpqrstuvwxyz \\
        --least_significant_bit_first
",
            opts.usage(&brief),
            program
        );
        return Ok(());
    }

    if args.len() == 1 && (args[0] == "--version" || args[0] == "-v") {
        println!("{}", env!("CARGO_PKG_VERSION"));
        return Ok(());
    }

    let matches = opts.parse(&args).map_err(Error::ParseOpts)?;
    check!(Error::ExtraArgs(matches.free), matches.free.is_empty());

    let mut spec = match matches.opt_str("base") {
        None => {
            let mut spec = data_encoding::Specification::new();
            spec.symbols = matches
                .opt_str("symbols")
                .ok_or_else(|| Error::Cmdline("Base or symbols must be provided".into()))?;
            spec
        }
        Some(base) => {
            check!(
                Error::Cmdline("Base and symbols are incompatible".into()),
                !matches.opt_present("symbols")
            );
            match base.as_str() {
                "16" => data_encoding::HEXUPPER.specification(),
                "hex" => data_encoding::HEXLOWER_PERMISSIVE.specification(),
                "32" => data_encoding::BASE32.specification(),
                "32hex" => data_encoding::BASE32HEX.specification(),
                "64" => data_encoding::BASE64.specification(),
                "64url" => data_encoding::BASE64URL.specification(),
                _ => return Err(Error::Cmdline("Invalid base".into())),
            }
        }
    };
    if let Some(padding) = matches.opt_str("padding") {
        let mut chars = padding.chars();
        spec.padding = chars.next();
        check!(Error::Cmdline("Empty padding".into()), spec.padding.is_some());
        check!(Error::Cmdline("Padding must be a character".into()), chars.next().is_none());
    } else {
        spec.padding = None;
    }
    if let Some(mut newold) = matches.opt_str("translate") {
        let invalid_translate = Error::Cmdline("Invalid translate".into());
        check!(invalid_translate, newold.len() % 2 == 0);
        let len = newold.len() / 2;
        check!(invalid_translate, newold.is_char_boundary(len));
        spec.translate.to = newold.split_off(len);
        spec.translate.from = newold;
    }
    if matches.opt_present("ignore_trailing_bits") {
        spec.check_trailing_bits = false;
    }
    if matches.opt_present("least_significant_bit_first") {
        spec.bit_order = data_encoding::BitOrder::LeastSignificantFirst;
    }
    if let Some(ignore) = matches.opt_str("ignore") {
        spec.ignore.push_str(ignore.as_str());
    }
    if let Some(width) = matches.opt_str("width") {
        spec.wrap.width =
            width.parse().map_err(|_| Error::Cmdline("Invalid width value".into()))?;
    }
    if let Some(separator) = matches.opt_str("separator") {
        spec.wrap.separator.push_str(separator.as_str());
    }
    let base = spec.encoding().map_err(Error::Builder)?;

    let mode = match matches.opt_str("mode").unwrap().as_str() {
        "" => return Err(Error::Cmdline("Empty mode".into())),
        x if "encode".starts_with(x) => true,
        x if "decode".starts_with(x) => false,
        x if "specification".starts_with(x) => {
            println!("{:#?}", base.specification());
            return Ok(());
        }
        _ => return Err(Error::Cmdline("Invalid mode".into())),
    };

    let input: Box<dyn Read>;
    if let Some(file) = matches.opt_str("input") {
        input = Box::new(File::open(&file).map_err(|e| Error::IO(file, e))?);
    } else {
        input = Box::new(std::io::stdin());
    };

    let mut output: Box<dyn Write>;
    if let Some(file) = matches.opt_str("output") {
        output = Box::new(File::create(&file).map_err(|e| Error::IO(file, e))?);
    } else {
        output = stdout();
    }
    output = Box::new(std::io::BufWriter::new(output));

    let size = matches
        .opt_str("block")
        .unwrap_or_else(|| "15360".to_owned())
        .parse()
        .map_err(|_| Error::Cmdline("Invalid block value".into()))?;
    check!(Error::Cmdline("Block value must be greater or equal than 8".into()), size >= 8);

    if mode {
        encode(&base, spec.wrap.width, input, output, size)
    } else {
        decode(&base, input, output, size)
    }
}

// TODO: Change (and inline) the following lines when Stdout does not
// go through a LineWriter anymore.
#[cfg(target_os = "linux")]
fn stdout() -> Box<dyn Write> {
    Box::new(unsafe { <File as std::os::unix::io::FromRawFd>::from_raw_fd(1) })
}
#[cfg(not(target_os = "linux"))]
fn stdout() -> Box<dyn Write> {
    Box::new(std::io::stdout())
}
<commit_msg>Fix clippy warnings<commit_after>#![warn(unused_results)]

use data_encoding::{DecodeKind, Encoding};
use getopts::Options;
use std::fs::File;
use std::io::{Read, Write};

macro_rules! check {
    ($e: expr, $c: expr) => {
        if !$c {
            return Err($e);
        }
    };
}

#[derive(Debug)]
pub enum Error {
    ParseOpts(getopts::Fail),
    ExtraArgs(Vec<String>),
    Cmdline(String),
    Decode(data_encoding::DecodeError),
    Builder(data_encoding::SpecificationError),
    IO(String, std::io::Error),
    Read(std::io::Error),
    Write(std::io::Error),
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use self::Error::*;
        match self {
            ParseOpts(ref e) => e.fmt(f),
            ExtraArgs(ref a) => write!(f, "Unexpected arguments {:?}", a),
            Cmdline(ref m) => write!(f, "{}", m),
            Decode(ref e) => e.fmt(f),
            Builder(ref e) => e.fmt(f),
            IO(ref p, ref e) => write!(f, "{}: {}", p, e),
            Read(ref e) => write!(f, "Read error: {}", e),
            Write(ref e) => write!(f, "Write error: {}", e),
        }
    }
}

type Result<T> = std::result::Result<T, Error>;

fn floor(x: usize, d: usize) -> usize {
    x / d * d
}
fn ceil(x: usize, d: usize) -> usize {
    floor(x + d - 1, d)
}

#[test]
fn floor_ceil() {
    assert_eq!(floor(10, 5), 10);
    assert_eq!(floor(13, 5), 10);
    assert_eq!(floor(15, 5), 15);
    assert_eq!(ceil(10, 5), 10);
    assert_eq!(ceil(13, 5), 15);
    assert_eq!(ceil(15, 5), 15);
}

fn encode_block(base: &Encoding) -> usize {
    match base.bit_width() {
        1 | 2 | 4 => 1,
        3 | 6 => 3,
        5 => 5,
        _ => unreachable!(),
    }
}
fn decode_block(base: &Encoding) -> usize {
    encode_block(base) * 8 / base.bit_width()
}

pub fn encode<R: Read, W: Write>(
    base: &Encoding, wrap: usize, mut reader: R, mut writer: W, size: usize,
) -> Result<()> {
    let block = if wrap == 0 {
        encode_block(base)
    } else {
        assert_eq!(wrap * base.bit_width() % 8, 0);
        wrap * base.bit_width() / 8
    };
    assert_eq!(block % encode_block(base), 0);
    assert!(size >= block);
    let mut input = vec![0u8; size];
    let mut output = vec![0u8; base.encode_len(size)];
    let mut rest = 0;
    loop {
        let ilen = reader.read(&mut input[rest ..]).map_err(Error::Read)?;
        let next = if ilen == 0 { rest } else { floor(rest + ilen, block) };
        let olen = base.encode_len(next);
        base.encode_mut(&input[0 .. next], &mut output[0 .. olen]);
        writer.write_all(&output[0 .. olen]).map_err(Error::Write)?;
        if ilen == 0 {
            return Ok(());
        }
        rest = rest + ilen - next;
        for i in 0 .. rest {
            input[i] = input[next + i];
        }
    }
}

pub fn decode<R, W>(base: &Encoding, mut reader: R, mut writer: W, size: usize) -> Result<()>
where
    R: Read,
    W: Write,
{
    let block = decode_block(base);
    assert!(size >= block);
    let mut input = vec![0u8; size];
    let mut output = vec![0u8; base.decode_len(ceil(size, block)).unwrap()];
    let mut pos = 0;
    let mut rest = 0;
    loop {
        let ilen = reader.read(&mut input[rest ..]).map_err(Error::Read)?;
        let next = if ilen == 0 { rest } else { floor(rest + ilen, block) };
        let mlen = base.decode_len(next).map_err(|mut error| {
            error.position += pos;
            Error::Decode(error)
        })?;
        let (next, olen) = match base.decode_mut(&input[0 .. next], &mut output[0 .. mlen]) {
            Ok(olen) => (next, olen),
            Err(mut partial) => {
                if partial.error.kind != DecodeKind::Length {
                    partial.error.position += pos;
                    return Err(Error::Decode(partial.error));
                }
                assert_ne!(ilen, 0);
                (partial.read, partial.written)
            }
        };
        writer.write_all(&output[0 .. olen]).map_err(Error::Write)?;
        rest = rest + ilen - next;
        if ilen == 0 {
            return Ok(());
        }
        for i in 0 .. rest {
            input[i] = input[next + i];
        }
        pos += next;
    }
}

fn main() {
    let (program, args): (_, Vec<_>) = {
        let mut i = std::env::args();
        match i.next() {
            None => ("data-encoding".into(), vec![]),
            Some(p) => (p, i.collect()),
        }
    };
    let program = program.rsplit('/').next().unwrap_or(&program);

    if let Err(e) = wrapped_main(program, args) {
        let _ = writeln!(&mut std::io::stderr(), "{}: {}", program, e);
        std::process::exit(1)
    }
}

fn wrapped_main(program: &str, args: Vec<String>) -> Result<()> {
    let mut opts = Options::new();
    let _ = opts
        .reqopt("m", "mode", "{encode|decode|specification} or any prefix of those", "<mode>")
        .optopt("b", "base", "{16|hex|32|32hex|64|64url}", "<base>")
        .optopt("i", "input", "read from <file> instead of standard input", "<file>")
        .optopt("o", "output", "write to <file> instead of standard output", "<file>")
        .optopt("", "block", "read blocks of about <size> bytes", "<size>")
        .optopt("p", "padding", "pad with <padding>", "<padding>")
        .optopt("g", "ignore", "when decoding, ignore characters in <ignore>", "<ignore>")
        .optopt("w", "width", "when encoding, wrap every <cols> characters", "<cols>")
        .optopt("s", "separator", "when encoding, wrap with <separator>", "<separator>")
        .optopt("", "symbols", "define a custom base using <symbols>", "<symbols>")
        .optopt("", "translate", "when decoding, translate <new> as <old>", "<new><old>")
        .optflag("", "ignore_trailing_bits", "when decoding, ignore non-zero trailing bits")
        .optflag("", "least_significant_bit_first", "use least significant bit first bit-order");

    if args.len() == 1 && (args[0] == "--help" || args[0] == "-h") {
        let brief = format!(
            r"Usage: {program} --mode=<mode> --base=<base> [<options>]
Usage: {program} --mode=<mode> --symbols=<symbols> [<options>]",
            program = program
        );
        print!(
            "{0}
Examples:
    # Using the RFC4648 base64 encoding
    {1} -menc -b64   # Encode without padding
    {1} -me -b64 -p= # Encode with padding
    {1} -mdec -b64   # Decode without padding
    {1} -md -b64 -p= # Decode with padding

    # Encode using the MIME base64 encoding
    {1} -me -b64 -p= -w76 -s$'\\r\\n'

    # Show base information for the permissive hexadecimal encoding
    {1} --mode=specification --base=hex

    # Decode using the DNSCurve base32 encoding
    {1} --mode=decode \\
        --symbols=0123456789bcdfghjklmnpqrstuvwxyz \\
        --translate=BCDFGHJKLMNPQRSTUVWXYZbcdfghjklmnpqrstuvwxyz \\
        --least_significant_bit_first
",
            opts.usage(&brief),
            program
        );
        return Ok(());
    }

    if args.len() == 1 && (args[0] == "--version" || args[0] == "-v") {
        println!("{}", env!("CARGO_PKG_VERSION"));
        return Ok(());
    }

    let matches = opts.parse(&args).map_err(Error::ParseOpts)?;
    check!(Error::ExtraArgs(matches.free), matches.free.is_empty());

    let mut spec = match matches.opt_str("base") {
        None => {
            let mut spec = data_encoding::Specification::new();
            spec.symbols = matches
                .opt_str("symbols")
                .ok_or_else(|| Error::Cmdline("Base or symbols must be provided".into()))?;
            spec
        }
        Some(base) => {
            check!(
                Error::Cmdline("Base and symbols are incompatible".into()),
                !matches.opt_present("symbols")
            );
            match base.as_str() {
                "16" => data_encoding::HEXUPPER.specification(),
                "hex" => data_encoding::HEXLOWER_PERMISSIVE.specification(),
                "32" => data_encoding::BASE32.specification(),
                "32hex" => data_encoding::BASE32HEX.specification(),
                "64" => data_encoding::BASE64.specification(),
                "64url" => data_encoding::BASE64URL.specification(),
                _ => return Err(Error::Cmdline("Invalid base".into())),
            }
        }
    };
    if let Some(padding) = matches.opt_str("padding") {
        let mut chars = padding.chars();
        spec.padding = chars.next();
        check!(Error::Cmdline("Empty padding".into()), spec.padding.is_some());
        check!(Error::Cmdline("Padding must be a character".into()), chars.next().is_none());
    } else {
        spec.padding = None;
    }
    if let Some(mut newold) = matches.opt_str("translate") {
        let invalid_translate = Error::Cmdline("Invalid translate".into());
        check!(invalid_translate, newold.len() % 2 == 0);
        let len = newold.len() / 2;
        check!(invalid_translate, newold.is_char_boundary(len));
        spec.translate.to = newold.split_off(len);
        spec.translate.from = newold;
    }
    if matches.opt_present("ignore_trailing_bits") {
        spec.check_trailing_bits = false;
    }
    if matches.opt_present("least_significant_bit_first") {
        spec.bit_order = data_encoding::BitOrder::LeastSignificantFirst;
    }
    if let Some(ignore) = matches.opt_str("ignore") {
        spec.ignore.push_str(ignore.as_str());
    }
    if let Some(width) = matches.opt_str("width") {
        spec.wrap.width =
            width.parse().map_err(|_| Error::Cmdline("Invalid width value".into()))?;
    }
    if let Some(separator) = matches.opt_str("separator") {
        spec.wrap.separator.push_str(separator.as_str());
    }
    let base = spec.encoding().map_err(Error::Builder)?;

    let mode = match matches.opt_str("mode").unwrap().as_str() {
        "" => return Err(Error::Cmdline("Empty mode".into())),
        x if "encode".starts_with(x) => true,
        x if "decode".starts_with(x) => false,
        x if "specification".starts_with(x) => {
            println!("{:#?}", base.specification());
            return Ok(());
        }
        _ => return Err(Error::Cmdline("Invalid mode".into())),
    };

    let input: Box<dyn Read> = if let Some(file) = matches.opt_str("input") {
        Box::new(File::open(&file).map_err(|e| Error::IO(file, e))?)
    } else {
        Box::new(std::io::stdin())
    };

    let mut output: Box<dyn Write> = if let Some(file) = matches.opt_str("output") {
        Box::new(File::create(&file).map_err(|e| Error::IO(file, e))?)
    } else {
        stdout()
    };
    output = Box::new(std::io::BufWriter::new(output));

    let size = matches
        .opt_str("block")
        .unwrap_or_else(|| "15360".to_owned())
        .parse()
        .map_err(|_| Error::Cmdline("Invalid block value".into()))?;
    check!(Error::Cmdline("Block value must be greater or equal than 8".into()), size >= 8);

    if mode {
        encode(&base, spec.wrap.width, input, output, size)
    } else {
        decode(&base, input, output, size)
    }
}

// TODO: Change (and inline) the following lines when Stdout does not
// go through a LineWriter anymore.
#[cfg(target_os = "linux")]
fn stdout() -> Box<dyn Write> {
    Box::new(unsafe { <File as std::os::unix::io::FromRawFd>::from_raw_fd(1) })
}
#[cfg(not(target_os = "linux"))]
fn stdout() -> Box<dyn Write> {
    Box::new(std::io::stdout())
}
<|endoftext|>


<commit_before><commit_msg>Changed OpApply location to be at the operator<commit_after><|endoftext|>


<commit_before>#![feature(test)]

extern crate dft;
extern crate test;

use dft::{Operation, Plan, Transform, c64};
use test::{Bencher, black_box};

#[bench] fn complex_transform_0004(bencher: &mut Bencher) { complex_transform(   4, bencher); }
#[bench] fn complex_transform_0016(bencher: &mut Bencher) { complex_transform(  16, bencher); }
#[bench] fn complex_transform_0064(bencher: &mut Bencher) { complex_transform(  64, bencher); }
#[bench] fn complex_transform_0256(bencher: &mut Bencher) { complex_transform( 256, bencher); }
#[bench] fn complex_transform_1024(bencher: &mut Bencher) { complex_transform(1024, bencher); }
#[bench] fn complex_transform_4096(bencher: &mut Bencher) { complex_transform(4096, bencher); }

#[bench] fn real_transform_0004(bencher: &mut Bencher) { real_transform(   4, bencher); }
#[bench] fn real_transform_0016(bencher: &mut Bencher) { real_transform(  16, bencher); }
#[bench] fn real_transform_0064(bencher: &mut Bencher) { real_transform(  64, bencher); }
#[bench] fn real_transform_0256(bencher: &mut Bencher) { real_transform( 256, bencher); }
#[bench] fn real_transform_1024(bencher: &mut Bencher) { real_transform(1024, bencher); }
#[bench] fn real_transform_4096(bencher: &mut Bencher) { real_transform(4096, bencher); }

fn complex_transform(size: usize, bencher: &mut Bencher) {
    let mut data = vec![c64::new(42.0, 69.0); size];
    let plan = Plan::new(Operation::Forward, size);
    bencher.iter(|| black_box(data.transform(&plan)));
}

fn real_transform(size: usize, bencher: &mut Bencher) {
    let mut data = vec![42.0; 2 * size];
    let plan = Plan::new(Operation::Forward, 2 * size);
    bencher.iter(|| black_box(data.transform(&plan)));
}
<commit_msg>Add a pair of 8192 benchmarks<commit_after>#![feature(test)]

extern crate dft;
extern crate test;

use dft::{Operation, Plan, Transform, c64};
use test::{Bencher, black_box};

#[bench] fn complex_0004(bencher: &mut Bencher) { complex(   4, bencher); }
#[bench] fn complex_0016(bencher: &mut Bencher) { complex(  16, bencher); }
#[bench] fn complex_0064(bencher: &mut Bencher) { complex(  64, bencher); }
#[bench] fn complex_0256(bencher: &mut Bencher) { complex( 256, bencher); }
#[bench] fn complex_1024(bencher: &mut Bencher) { complex(1024, bencher); }
#[bench] fn complex_4096(bencher: &mut Bencher) { complex(4096, bencher); }
#[bench] fn complex_8192(bencher: &mut Bencher) { complex(8192, bencher); }

#[bench] fn real_0004(bencher: &mut Bencher) { real(   4, bencher); }
#[bench] fn real_0016(bencher: &mut Bencher) { real(  16, bencher); }
#[bench] fn real_0064(bencher: &mut Bencher) { real(  64, bencher); }
#[bench] fn real_0256(bencher: &mut Bencher) { real( 256, bencher); }
#[bench] fn real_1024(bencher: &mut Bencher) { real(1024, bencher); }
#[bench] fn real_4096(bencher: &mut Bencher) { real(4096, bencher); }
#[bench] fn real_8192(bencher: &mut Bencher) { real(8192, bencher); }

fn complex(size: usize, bencher: &mut Bencher) {
    let mut data = vec![c64::new(42.0, 69.0); size];
    let plan = Plan::new(Operation::Forward, size);
    bencher.iter(|| black_box(data.transform(&plan)));
}

fn real(size: usize, bencher: &mut Bencher) {
    let mut data = vec![42.0; 2 * size];
    let plan = Plan::new(Operation::Forward, 2 * size);
    bencher.iter(|| black_box(data.transform(&plan)));
}
<|endoftext|>


<commit_before>use std::net::{TcpListener, TcpStream};

pub struct Server;

impl Server {
    pub fn new() -> Server {

        Server
    }
}
<commit_msg>remove<commit_after><|endoftext|>


<commit_before>pub use winit::os::unix::x11::{XError, XNotSupported, XConnection};

use api::glx::ffi;

use CreationError;
use std::{mem, ptr};
use std::sync::{Arc};

use winit;
use winit::os::unix::WindowExt;
use winit::os::unix::WindowBuilderExt;

use Api;
use ContextError;
use GlAttributes;
use GlContext;
use GlRequest;
use PixelFormat;
use PixelFormatRequirements;

use std::ffi::CString;

use api::glx::Context as GlxContext;
use api::egl;
use api::egl::Context as EglContext;
use api::glx::ffi::glx::Glx;
use api::egl::ffi::egl::Egl;
use api::dlopen;

struct GlxOrEgl {
    glx: Option<Glx>,
    egl: Option<Egl>,
}

impl GlxOrEgl {
    fn new() -> GlxOrEgl {
        // TODO: use something safer than raw "dlopen"
        let glx = {
            let mut libglx = unsafe {
                dlopen::dlopen(b"libGL.so.1\0".as_ptr() as *const _, dlopen::RTLD_NOW)
            };
            if libglx.is_null() {
                libglx = unsafe {
                    dlopen::dlopen(b"libGL.so\0".as_ptr() as *const _, dlopen::RTLD_NOW)
                };
            }
            if libglx.is_null() {
                None
            } else {
                Some(Glx::load_with(|sym| {
                    let sym = CString::new(sym).unwrap();
                    unsafe { dlopen::dlsym(libglx, sym.as_ptr()) }
                }))
            }
        };
        // TODO: use something safer than raw "dlopen"
        let egl = {
            let mut libegl = unsafe {
                dlopen::dlopen(b"libEGL.so.1\0".as_ptr() as *const _, dlopen::RTLD_NOW)
            };
            if libegl.is_null() {
                libegl = unsafe {
                    dlopen::dlopen(b"libEGL.so\0".as_ptr() as *const _, dlopen::RTLD_NOW)
                };
            }
            if libegl.is_null() {
                None
            } else {
                Some(Egl::load_with(|sym| {
                    let sym = CString::new(sym).unwrap();
                    unsafe { dlopen::dlsym(libegl, sym.as_ptr()) }
                }))
            }
        };
        GlxOrEgl {
            glx: glx,
            egl: egl,
        }
    }
}

enum Context {
    Glx(GlxContext),
    Egl(EglContext),
    None,
}

pub struct Window {
    display: Arc<XConnection>,
    colormap: ffi::Colormap,
    context: Context,
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

impl Drop for Window {
    fn drop(&mut self) {
        unsafe {
            // we don't call MakeCurrent(0, 0) because we are not sure that the context
            // is still the current one
            self.context = Context::None;

            (self.display.xlib.XFreeColormap)(self.display.display, self.colormap);
        }
    }
}

impl Window {
    pub fn new(
        pf_reqs: &PixelFormatRequirements,
        opengl: &GlAttributes<&Window>,
        winit_builder: winit::WindowBuilder,
    ) -> Result<(Window, winit::Window), CreationError> {
        use api::glx::ffi::Xlib;
        use winit::NativeMonitorId;

        let xlib = Xlib::open().unwrap();
        let display = unsafe { (xlib.XOpenDisplay)(ptr::null()) };
        let screen_id = match winit_builder.window.monitor {
            Some(ref m) => match m.get_native_identifier() {
                NativeMonitorId::Numeric(monitor) => monitor as i32,
                _ => panic!(),
            },
            _ => unsafe { (xlib.XDefaultScreen)(display) },
        };

        // start the context building process
        enum Prototype<'a> {
            Glx(::api::glx::ContextPrototype<'a>),
            Egl(::api::egl::ContextPrototype<'a>),
        }
        let builder_clone_opengl_glx = opengl.clone().map_sharing(|_| unimplemented!());      // FIXME:
        let builder_clone_opengl_egl = opengl.clone().map_sharing(|_| unimplemented!());      // FIXME:
        let backend = GlxOrEgl::new();
        let context = match opengl.version {
            GlRequest::Latest | GlRequest::Specific(Api::OpenGl, _) | GlRequest::GlThenGles { .. } => {
                // GLX should be preferred over EGL, otherwise crashes may occur
                // on X11 – issue #314
                if let Some(ref glx) = backend.glx {
                    Prototype::Glx(try!(GlxContext::new(
                        glx.clone(),
                        &xlib,
                        pf_reqs,
                        &builder_clone_opengl_glx,
                        display,
                        screen_id,
                    )))
                } else if let Some(ref egl) = backend.egl {
                    Prototype::Egl(try!(EglContext::new(
                            egl.clone(),
                        pf_reqs,
                        &builder_clone_opengl_egl,
                        egl::NativeDisplay::X11(Some(display as *const _)),
                    )))
                } else {
                    return Err(CreationError::NotSupported);
                }
            },
            GlRequest::Specific(Api::OpenGlEs, _) => {
                if let Some(ref egl) = backend.egl {
                    Prototype::Egl(try!(EglContext::new(
                        egl.clone(),
                        pf_reqs,
                        &builder_clone_opengl_egl,
                        egl::NativeDisplay::X11(Some(display as *const _)),
                    )))
                } else {
                    return Err(CreationError::NotSupported);
                }
            },
            GlRequest::Specific(_, _) => {
                return Err(CreationError::NotSupported);
            },
        };

        // getting the `visual_infos` (a struct that contains information about the visual to use)
        let visual_infos = match context {
            Prototype::Glx(ref p) => p.get_visual_infos().clone(),
            Prototype::Egl(ref p) => {
                unsafe {
                    let mut template: ffi::XVisualInfo = mem::zeroed();
                    template.visualid = p.get_native_visual_id() as ffi::VisualID;

                    let mut num_visuals = 0;
                    let vi = (xlib.XGetVisualInfo)(display, ffi::VisualIDMask,
                                                           &mut template, &mut num_visuals);
                    // display.check_errors().expect("Failed to call XGetVisualInfo");
                    assert!(!vi.is_null());
                    assert!(num_visuals == 1);

                    let vi_copy = ptr::read(vi as *const _);
                    (xlib.XFree)(vi as *mut _);
                    vi_copy
                }
            },
        };

        let winit_window = winit_builder
            .with_visual(&visual_infos as *const _)
            .with_screen(screen_id)
            .build().unwrap();
        let display = winit_window.get_xlib_xconnection().unwrap();

        let xlib_window = winit_window.get_xlib_window().unwrap();
        // finish creating the OpenGL context
        let context = match context {
            Prototype::Glx(ctxt) => {
                Context::Glx(try!(ctxt.finish(xlib_window as _)))
            },
            Prototype::Egl(ctxt) => {
                Context::Egl(try!(ctxt.finish(xlib_window)))
            },
        };

        // getting the root window
        let root = unsafe { (display.xlib.XDefaultRootWindow)(display.display) };
        display.check_errors().expect("Failed to get root window");

        // creating the color map
        let cmap = unsafe {
            let cmap = (display.xlib.XCreateColormap)(display.display, root,
                                                      visual_infos.visual as *mut _,
                                                      ffi::AllocNone);
            display.check_errors().expect("Failed to call XCreateColormap");
            cmap
        };

        Ok((Window {
            display: display.clone(),
            context: context,
            colormap: cmap,
        },
        winit_window))
    }
}

impl GlContext for Window {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        match self.context {
            Context::Glx(ref ctxt) => ctxt.make_current(),
            Context::Egl(ref ctxt) => ctxt.make_current(),
            Context::None => Ok(())
        }
    }

    #[inline]
    fn is_current(&self) -> bool {
        match self.context {
            Context::Glx(ref ctxt) => ctxt.is_current(),
            Context::Egl(ref ctxt) => ctxt.is_current(),
            Context::None => panic!()
        }
    }

    #[inline]
    fn get_proc_address(&self, addr: &str) -> *const () {
        match self.context {
            Context::Glx(ref ctxt) => ctxt.get_proc_address(addr),
            Context::Egl(ref ctxt) => ctxt.get_proc_address(addr),
            Context::None => ptr::null()
        }
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        match self.context {
            Context::Glx(ref ctxt) => ctxt.swap_buffers(),
            Context::Egl(ref ctxt) => ctxt.swap_buffers(),
            Context::None => Ok(())
        }
    }

    #[inline]
    fn get_api(&self) -> Api {
        match self.context {
            Context::Glx(ref ctxt) => ctxt.get_api(),
            Context::Egl(ref ctxt) => ctxt.get_api(),
            Context::None => panic!()
        }
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        match self.context {
            Context::Glx(ref ctxt) => ctxt.get_pixel_format(),
            Context::Egl(ref ctxt) => ctxt.get_pixel_format(),
            Context::None => panic!()
        }
    }
}
<commit_msg>Use winits XConnection when creating x11 window<commit_after>pub use winit::os::unix::x11::{XError, XNotSupported, XConnection};

use api::glx::ffi;

use CreationError;
use std::{mem, ptr};
use std::sync::{Arc};

use winit;
use winit::os::unix::WindowExt;
use winit::os::unix::WindowBuilderExt;
use winit::os::unix::get_x11_xconnection;
use winit::NativeMonitorId;

use Api;
use ContextError;
use GlAttributes;
use GlContext;
use GlRequest;
use PixelFormat;
use PixelFormatRequirements;

use std::ffi::CString;

use api::glx::Context as GlxContext;
use api::egl;
use api::egl::Context as EglContext;
use api::glx::ffi::glx::Glx;
use api::egl::ffi::egl::Egl;
use api::dlopen;

struct GlxOrEgl {
    glx: Option<Glx>,
    egl: Option<Egl>,
}

impl GlxOrEgl {
    fn new() -> GlxOrEgl {
        // TODO: use something safer than raw "dlopen"
        let glx = {
            let mut libglx = unsafe {
                dlopen::dlopen(b"libGL.so.1\0".as_ptr() as *const _, dlopen::RTLD_NOW)
            };
            if libglx.is_null() {
                libglx = unsafe {
                    dlopen::dlopen(b"libGL.so\0".as_ptr() as *const _, dlopen::RTLD_NOW)
                };
            }
            if libglx.is_null() {
                None
            } else {
                Some(Glx::load_with(|sym| {
                    let sym = CString::new(sym).unwrap();
                    unsafe { dlopen::dlsym(libglx, sym.as_ptr()) }
                }))
            }
        };
        // TODO: use something safer than raw "dlopen"
        let egl = {
            let mut libegl = unsafe {
                dlopen::dlopen(b"libEGL.so.1\0".as_ptr() as *const _, dlopen::RTLD_NOW)
            };
            if libegl.is_null() {
                libegl = unsafe {
                    dlopen::dlopen(b"libEGL.so\0".as_ptr() as *const _, dlopen::RTLD_NOW)
                };
            }
            if libegl.is_null() {
                None
            } else {
                Some(Egl::load_with(|sym| {
                    let sym = CString::new(sym).unwrap();
                    unsafe { dlopen::dlsym(libegl, sym.as_ptr()) }
                }))
            }
        };
        GlxOrEgl {
            glx: glx,
            egl: egl,
        }
    }
}

enum Context {
    Glx(GlxContext),
    Egl(EglContext),
    None,
}

pub struct Window {
    display: Arc<XConnection>,
    colormap: ffi::Colormap,
    context: Context,
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

impl Drop for Window {
    fn drop(&mut self) {
        unsafe {
            // we don't call MakeCurrent(0, 0) because we are not sure that the context
            // is still the current one
            self.context = Context::None;

            (self.display.xlib.XFreeColormap)(self.display.display, self.colormap);
        }
    }
}

impl Window {
    pub fn new(
        pf_reqs: &PixelFormatRequirements,
        opengl: &GlAttributes<&Window>,
        winit_builder: winit::WindowBuilder,
    ) -> Result<(Window, winit::Window), CreationError> {
        let display = get_x11_xconnection().unwrap();
        let screen_id = match winit_builder.window.monitor {
            Some(ref m) => match m.get_native_identifier() {
                NativeMonitorId::Numeric(monitor) => monitor as i32,
                _ => panic!(),
            },
            _ => unsafe { (display.xlib.XDefaultScreen)(display.display) },
        };

        // start the context building process
        enum Prototype<'a> {
            Glx(::api::glx::ContextPrototype<'a>),
            Egl(::api::egl::ContextPrototype<'a>),
        }
        let builder_clone_opengl_glx = opengl.clone().map_sharing(|_| unimplemented!());      // FIXME:
        let builder_clone_opengl_egl = opengl.clone().map_sharing(|_| unimplemented!());      // FIXME:
        let backend = GlxOrEgl::new();
        let context = match opengl.version {
            GlRequest::Latest | GlRequest::Specific(Api::OpenGl, _) | GlRequest::GlThenGles { .. } => {
                // GLX should be preferred over EGL, otherwise crashes may occur
                // on X11 – issue #314
                if let Some(ref glx) = backend.glx {
                    Prototype::Glx(try!(GlxContext::new(
                        glx.clone(),
                        &display.xlib,
                        pf_reqs,
                        &builder_clone_opengl_glx,
                        display.display,
                        screen_id,
                    )))
                } else if let Some(ref egl) = backend.egl {
                    Prototype::Egl(try!(EglContext::new(
                            egl.clone(),
                        pf_reqs,
                        &builder_clone_opengl_egl,
                        egl::NativeDisplay::X11(Some(display.display as *const _)),
                    )))
                } else {
                    return Err(CreationError::NotSupported);
                }
            },
            GlRequest::Specific(Api::OpenGlEs, _) => {
                if let Some(ref egl) = backend.egl {
                    Prototype::Egl(try!(EglContext::new(
                        egl.clone(),
                        pf_reqs,
                        &builder_clone_opengl_egl,
                        egl::NativeDisplay::X11(Some(display.display as *const _)),
                    )))
                } else {
                    return Err(CreationError::NotSupported);
                }
            },
            GlRequest::Specific(_, _) => {
                return Err(CreationError::NotSupported);
            },
        };

        // getting the `visual_infos` (a struct that contains information about the visual to use)
        let visual_infos = match context {
            Prototype::Glx(ref p) => p.get_visual_infos().clone(),
            Prototype::Egl(ref p) => {
                unsafe {
                    let mut template: ffi::XVisualInfo = mem::zeroed();
                    template.visualid = p.get_native_visual_id() as ffi::VisualID;

                    let mut num_visuals = 0;
                    let vi = (display.xlib.XGetVisualInfo)(display.display, ffi::VisualIDMask,
                                                           &mut template, &mut num_visuals);
                    display.check_errors().expect("Failed to call XGetVisualInfo");
                    assert!(!vi.is_null());
                    assert!(num_visuals == 1);

                    let vi_copy = ptr::read(vi as *const _);
                    (display.xlib.XFree)(vi as *mut _);
                    vi_copy
                }
            },
        };

        let winit_window = winit_builder
            .with_x11_visual(&visual_infos as *const _)
            .with_x11_screen(screen_id)
            .build().unwrap();

        let xlib_window = winit_window.get_xlib_window().unwrap();
        // finish creating the OpenGL context
        let context = match context {
            Prototype::Glx(ctxt) => {
                Context::Glx(try!(ctxt.finish(xlib_window as _)))
            },
            Prototype::Egl(ctxt) => {
                Context::Egl(try!(ctxt.finish(xlib_window)))
            },
        };

        // getting the root window
        let root = unsafe { (display.xlib.XDefaultRootWindow)(display.display) };
        display.check_errors().expect("Failed to get root window");

        // creating the color map
        let cmap = unsafe {
            let cmap = (display.xlib.XCreateColormap)(display.display, root,
                                                      visual_infos.visual as *mut _,
                                                      ffi::AllocNone);
            display.check_errors().expect("Failed to call XCreateColormap");
            cmap
        };

        Ok((Window {
            display: display.clone(),
            context: context,
            colormap: cmap,
        },
        winit_window))
    }
}

impl GlContext for Window {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        match self.context {
            Context::Glx(ref ctxt) => ctxt.make_current(),
            Context::Egl(ref ctxt) => ctxt.make_current(),
            Context::None => Ok(())
        }
    }

    #[inline]
    fn is_current(&self) -> bool {
        match self.context {
            Context::Glx(ref ctxt) => ctxt.is_current(),
            Context::Egl(ref ctxt) => ctxt.is_current(),
            Context::None => panic!()
        }
    }

    #[inline]
    fn get_proc_address(&self, addr: &str) -> *const () {
        match self.context {
            Context::Glx(ref ctxt) => ctxt.get_proc_address(addr),
            Context::Egl(ref ctxt) => ctxt.get_proc_address(addr),
            Context::None => ptr::null()
        }
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        match self.context {
            Context::Glx(ref ctxt) => ctxt.swap_buffers(),
            Context::Egl(ref ctxt) => ctxt.swap_buffers(),
            Context::None => Ok(())
        }
    }

    #[inline]
    fn get_api(&self) -> Api {
        match self.context {
            Context::Glx(ref ctxt) => ctxt.get_api(),
            Context::Egl(ref ctxt) => ctxt.get_api(),
            Context::None => panic!()
        }
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        match self.context {
            Context::Glx(ref ctxt) => ctxt.get_pixel_format(),
            Context::Egl(ref ctxt) => ctxt.get_pixel_format(),
            Context::None => panic!()
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Do not include logical volumes in VG textmap if there are none<commit_after><|endoftext|>


<commit_before>
/// Should be implemented by contexts that have rectangle information.
pub trait RelativeRectangle<'a> {
    /// Shrinks the current rectangle equally by all sides.
    fn margin(&'a self, m: f64) -> Self;

    /// Expands the current rectangle equally by all sides.
    #[inline(always)]
    fn expand(&'a self, m: f64) -> Self {
        self.margin(-m)
    }

    /// Moves to a relative rectangle using the current rectangle as tile.
    fn rel(&'a self, x: f64, y: f64) -> Self;

    /// Moves to the above rectangle using the current rectangle as tile.
    #[inline(always)]
    fn up(&'a self) -> Self {
        self.rel(0.0, 1.0)
    }

    /// Moves to the left rectangle using the current rectangle as tile.
    #[inline(always)]
    fn left(&'a self) -> Self {
        self.rel(-1.0, 0.0)
    }

    /// Moves to the right rectangle using the current rectangle as tile.
    #[inline(always)]
    fn right(&'a self) -> Self {
        self.rel(1.0, 0.0)
    }
}

<commit_msg>Added `down`<commit_after>
/// Should be implemented by contexts that have rectangle information.
pub trait RelativeRectangle<'a> {
    /// Shrinks the current rectangle equally by all sides.
    fn margin(&'a self, m: f64) -> Self;

    /// Expands the current rectangle equally by all sides.
    #[inline(always)]
    fn expand(&'a self, m: f64) -> Self {
        self.margin(-m)
    }

    /// Moves to a relative rectangle using the current rectangle as tile.
    fn rel(&'a self, x: f64, y: f64) -> Self;

    /// Moves to the rectangle above using the current rectangle as tile.
    #[inline(always)]
    fn up(&'a self) -> Self {
        self.rel(0.0, 1.0)
    }

    /// Moves to the left rectangle using the current rectangle as tile.
    #[inline(always)]
    fn left(&'a self) -> Self {
        self.rel(-1.0, 0.0)
    }

    /// Moves to the right rectangle using the current rectangle as tile.
    #[inline(always)]
    fn right(&'a self) -> Self {
        self.rel(1.0, 0.0)
    }

    /// Moves to the rectangle below using the current rectangle as tile.
    #[inline(always)]
    fn down(&'a self) -> Self {
        self.rel(0.0, -1.0)
    }
}

<|endoftext|>


<commit_before>use std::fmt::Write;
use std::convert::Into;
use llvm::builder::Builder;
use llvm::value::Value;
use common::types::Ty;

macro_rules! encode_value(
  ($name:ident, $ty:ty) => (
    #[allow(dead_code)]
    pub extern "C" fn $name(buf: &mut String, val: $ty) {
      write!(buf, "{}", val).unwrap();
    }
  );
);

encode_value!(encode_i8, i8);
encode_value!(encode_i16, i16);
encode_value!(encode_i32, i32);
encode_value!(encode_i64, i64);
encode_value!(encode_f32, f32);
encode_value!(encode_f64, f64);

pub fn write<V: Into<Value>>(buf: &mut String, val: &V) {
}<commit_msg>Implement ValuePrint, writing out the value string representation into buffer.<commit_after>use std::fmt::Write;
use std::convert::Into;
use llvm::{self, JitCompiler};
use llvm::builder::Builder;
use llvm::value::{Function, Value};

use common::types::Ty;
use exec::processor::to_llvm_ty;

macro_rules! encode_value(
  ($name:ident, $ty:ty) => (
    #[allow(dead_code)]
    pub extern "C" fn $name(buf: &mut String, val: $ty) {
      write!(buf, "{}", val).unwrap();
    }
  );
);

encode_value!(encode_i8, i8);
encode_value!(encode_i16, i16);
encode_value!(encode_i32, i32);
encode_value!(encode_i64, i64);
encode_value!(encode_f32, f32);
encode_value!(encode_f64, f64);

pub struct ValuePrint<'a> {
  jit: &'a JitCompiler,
  rstr_ty: llvm::Ty
}

impl<'a> ValuePrint<'a> {
  fn new(jit: &JitCompiler) -> ValuePrint {
    ValuePrint {
      jit: jit,
      rstr_ty: jit.get_ty("RustStringRef")
        .expect("RustStringRef does not exist.")
        .pointer_ty()
    }
  }

  // void processor(*RustStringRef)
  fn create_fn_proto(&self, bld: &Builder, val_ty: &Ty) -> Function {
    self.jit.create_func_prototype(
      "processor",
      &self.rstr_ty,
      &[to_llvm_ty(self.jit, val_ty)],
      Some(bld))
  }

  fn build(&self, bld: &Builder, val_ty: &Ty) -> Function {
    let print_fn = self.create_fn_proto(bld, val_ty);

    let encode_fn_name = match *val_ty {
      Ty::I8  => "encode_i8",
      Ty::I16 => "encode_i16",
      Ty::I32 => "encode_i32",
      Ty::I64 => "encode_i64",
      Ty::F32 => "encode_f32",
      Ty::F64 => "encode_f64",
    };

    let encode_fn = self.jit.get_func(encode_fn_name).unwrap();
    bld.create_call(&encode_fn, &[&print_fn.arg(0).into()]);

    print_fn
  }

  fn print(&self, bld: &Builder, val_fn: &Value, ty: &Ty, buf: &mut String) {
    let print_fn = &self.build(bld, ty);
    let fn_ptr: fn(&mut String) = unsafe {
      ::std::mem::transmute(
        self.jit.get_func_ptr(print_fn)
          .expect("Value Print function does not exist.")
      )
    };
    fn_ptr(buf);
  }
}<|endoftext|>