<commit_before>//! Binary lambda calculus execution

use lambda_calculus::*;
use binary_encoding::from_binary;
use lambda_encoding::{encode, decode};
use self::Error::*;

/// An error that can occur during BLC execution.
#[derive(Debug, PartialEq)]
pub enum Error {
    /// invalid BLC program
    InvalidProgram,
    /// invalid BLC argument
    InvalidArgument
}

/// The type of input for BLC execution.
pub enum Input<'a> {
    /// no input parameter
    Nothing,
    /// BLC input
    Binary(&'a [u8]),
    /// unencoded byte input
    Bytes(&'a [u8])
}

/// Executes a binary lambda calculus program, optionally feeding it the given argument.
///
/// # Example
/// ```
/// use blc::execution::run;
/// use blc::execution::Input::Bytes;
///
/// let reverse_blc = b"0001011001000110100000000001011100111110111100001011011110110000010";
///
/// assert_eq!(run(&*reverse_blc, Bytes(b"herp derp")), Ok("pred preh".into()));
/// ```
pub fn run(blc_program: &[u8], input: Input) -> Result<String, Error> {
    let program = from_binary(blc_program);
    if program.is_err() { return Err(InvalidProgram) }
    let program = program.unwrap(); // safe

    let calculation = match input {
        Input::Nothing     => beta(program, NOR, 0),
        Input::Bytes(arg)  => beta(app(program, encode(arg)), NOR, 0),
        Input::Binary(arg) => {
            let arg = from_binary(arg);
            if arg.is_ok() {
                beta(app(program, arg.unwrap()), NOR, 0) // safe
            } else {
                return Err(InvalidArgument)
            }
        }
    };

    Ok(decode(calculation))
}

#[cfg(test)]
mod test {
    use super::*;
    use binary_encoding::{decompress, to_binary};
    use lambda_calculus::data::num::church::{is_zero, rem};

    #[test]
    fn id() {
        let id_compressed = b" ";
        let id_blc        = decompress(&*id_compressed);
        let input         = b"herp derp";

        assert_eq!(run(&*id_blc, Input::Bytes(&*input)).unwrap(), "herp derp".to_owned());
    }

    #[test]
    fn sort() {
        let sort_compressed =
            [0x15, 0x46, 0x84, 0x06, 0x05, 0x46, 0x81, 0x60, 0x15, 0xfb, 0xec, 0x2f, 0x80, 0x01,
             0x5b, 0xf9, 0x7f, 0x0b, 0x7e, 0xf7, 0x2f, 0xec, 0x2d, 0xfb, 0x80, 0x56, 0x05, 0xfd,
             0x85, 0xbb, 0x76, 0x11, 0x5d, 0x50, 0x5c, 0x00, 0xbe, 0x7f, 0xc1, 0x2b, 0xff, 0x0f,
             0xfc, 0x2c, 0x1b, 0x72, 0xbf, 0xf0, 0xff, 0xc2, 0xc1, 0x6d, 0x34, 0x50, 0x40];

        let sort_blc = decompress(&sort_compressed);
        let input  = b"3241";

        assert_eq!(run(&*sort_blc, Input::Bytes(&*input)).unwrap(), "1234".to_owned());
    }

    #[test]
    fn quine() {
        // program code from https://tromp.github.io/cl/Binary_lambda_calculus.html#A_quine
        let quine_blc = b"000101100100011010000000000001011\
            011110010111100111111011111011010";
        let input = b"hurr";

        assert_eq!(run(&quine_blc[..], Input::Bytes(&input[..])), Ok("hurrhurr".to_owned()));
    }

    #[test]
    fn inflating() {
        // program code from http://www.ioccc.org/2012/tromp/inflate.Blc
        let inflate_compressed =
            [0x44, 0x44, 0x68, 0x16, 0x01, 0x79, 0x1a, 0x00, 0x16, 0x7f, 0xfb, 0xcb, 0xcf, 0xdf,
             0x65, 0xfb, 0xed, 0x0f, 0x3c, 0xe7, 0x3c, 0xf3, 0xc2, 0xd8, 0x20, 0x58, 0x2c, 0x0b,
             0x06, 0xc0];

        let inflate_blc = decompress(&inflate_compressed);
        let s_compressed = [0x1, 0x7a, 0x74];

        assert_eq!(run(&*inflate_blc, Input::Bytes(&s_compressed[..])).unwrap(), "000000010111101001110100".to_owned());
    }

    #[test]
    fn deflating() {
        // program code from http://www.ioccc.org/2012/tromp/deflate.Blc
        let deflate_compressed =
            [0x44, 0x68, 0x16, 0x05, 0x7e, 0x01, 0x17, 0x00, 0xbe, 0x55, 0xff, 0xf0, 0x0d, 0xc1,
             0x8b, 0xb2, 0xc1, 0xb0, 0xf8, 0x7c, 0x2d, 0xd8, 0x05, 0x9e, 0x09, 0x7f, 0xbf, 0xb1,
             0x48, 0x39, 0xce, 0x81, 0xce, 0x80];

        let deflate_blc = decompress(&deflate_compressed);
        let s_blc = b"00000001011110100111010";

        assert_eq!(run(&*deflate_blc, Input::Bytes(&s_blc[..])).unwrap().as_bytes(), [0x1, 0x7a, 0x74]);
    }

    #[test]
    fn fizz_buzz() {
        let fizzbuzz_single =
            abs(
                app!(
                    is_zero(),
                    app!(rem(), Var(1), 15.into_church()),
                    encode(&b"FizzBuzz"[..]),
                    app!(
                        is_zero(),
                        app!(rem(), Var(1), 3.into_church()),
                        encode(&b"Fizz"[..]),
                        app!(
                            is_zero(),
                            app!(rem(), Var(1), 5.into_church()),
                            encode(&b"Buzz"[..]),
                            Var(1)
                        )
                    )
                )
            );
        let fizzbuzz_blc = to_binary(&fizzbuzz_single);

        assert_eq!(run(&*fizzbuzz_blc, Input::Binary(&to_binary(&1.into_church()))).unwrap(),  "(λλ21)");
        assert_eq!(run(&*fizzbuzz_blc, Input::Binary(&to_binary(&2.into_church()))).unwrap(),  "(λλ2(21))");
        assert_eq!(run(&*fizzbuzz_blc, Input::Binary(&to_binary(&3.into_church()))).unwrap(),  "Fizz");
        assert_eq!(run(&*fizzbuzz_blc, Input::Binary(&to_binary(&4.into_church()))).unwrap(),  "(λλ2(2(2(21))))");
        assert_eq!(run(&*fizzbuzz_blc, Input::Binary(&to_binary(&5.into_church()))).unwrap(),  "Buzz");
        assert_eq!(run(&*fizzbuzz_blc, Input::Binary(&to_binary(&15.into_church()))).unwrap(), "FizzBuzz");
    }

/*
    #[test] /* WIP; this one parses properly, but doesn't return the expected result */
    fn hilbert() {
        // program code from http://www.ioccc.org/2012/tromp/hilbert.Blc
        let hilbert_compressed =
            [0x18, 0x18, 0x18, 0x18, 0x11, 0x11, 0x54, 0x68, 0x06, 0x04, 0x15, 0x5f, 0xf0, 0x41,
             0x9d, 0xf9, 0xde, 0x16, 0xff, 0xfe, 0x5f, 0x3f, 0xef, 0xf6, 0x15, 0xff, 0x94, 0x68,
             0x40, 0x58, 0x11, 0x7e, 0x05, 0xcb, 0xfe, 0xbc, 0xbf, 0xee, 0x86, 0xcb, 0x94, 0x68,
             0x16, 0x00, 0x5c, 0x0b, 0xfa, 0xcb, 0xfb, 0xf7, 0x1a, 0x85, 0xe0, 0x5c, 0xf4, 0x14,
             0xd5, 0xfe, 0x08, 0x18, 0x0b, 0x04, 0x8d, 0x08, 0x00, 0xe0, 0x78, 0x01, 0x64, 0x45,
             0xff, 0xe5, 0xff, 0x7f, 0xff, 0xfe, 0x5f, 0xff, 0x2f, 0xc0, 0x2f, 0x7a, 0xd9, 0x7f,
             0x5b, 0xff, 0xff, 0xfb, 0xff, 0xfc, 0xaa, 0xff, 0xf7, 0x81, 0x7f, 0xfa, 0xdf, 0x76,
             0x69, 0x54, 0x68, 0x06, 0x01, 0x57, 0xf7, 0xe1, 0x60, 0x5c, 0x13, 0xfe, 0x80, 0xb2,
             0x2c, 0x18, 0x58, 0x1b, 0xfe, 0x5c, 0x10, 0x42, 0xff, 0x80, 0x5d, 0xee, 0xc0, 0x6c,
             0x2c, 0x0c, 0x06, 0x08, 0x19, 0x1a, 0x00, 0x16, 0x7f, 0xbc, 0xbc, 0xfd, 0xf6, 0x5f,
             0x7c, 0x0a, 0x20];

        let hilbert_blc = decompress(&hilbert_compressed);
        let arg = b"1234";

        assert_eq!(run(&hilbert_blc[..], Bytes(&arg[..])), Ok("WIP".into()));
    }
*/
/*
    #[test] /* WIP; this just returns λ1 */
    fn brainfuck() {
        // program code from http://www.ioccc.org/2012/tromp/bf.Blc
        let bf_interpreter_compressed =
            [0x44, 0x51, 0xa1, 0x01, 0x84, 0x55, 0xd5, 0x02, 0xb7, 0x70, 0x30, 0x22, 0xff, 0x32,
             0xf0, 0x00, 0xbf, 0xf9, 0x85, 0x7f, 0x5e, 0xe1, 0x6f, 0x95, 0x7f, 0x7d, 0xee, 0xc0,
             0xe5, 0x54, 0x68, 0x00, 0x58, 0x55, 0xfd, 0xfb, 0xe0, 0x45, 0x57, 0xfd, 0xeb, 0xfb,
             0xf0, 0xb6, 0xf0, 0x2f, 0xd6, 0x07, 0xe1, 0x6f, 0x73, 0xd7, 0xf1, 0x14, 0xbc, 0xc0,
             0x0b, 0xff, 0x2e, 0x1f, 0xa1, 0x6f, 0x66, 0x17, 0xe8, 0x5b, 0xef, 0x2f, 0xcf, 0xff,
             0x13, 0xff, 0xe1, 0xca, 0x34, 0x20, 0x0a, 0xc8, 0xd0, 0x0b, 0x99, 0xee, 0x1f, 0xe5,
             0xff, 0x7f, 0x5a, 0x6a, 0x1f, 0xff, 0x0f, 0xff, 0x87, 0x9d, 0x04, 0xd0, 0xab, 0x00,
             0x05, 0xdb, 0x23, 0x40, 0xb7, 0x3b, 0x28, 0xcc, 0xc0, 0xb0, 0x6c, 0x0e, 0x74, 0x10];

        let bf_interpreter_blc = decompress(&bf_interpreter_compressed);
        let bf_hello =
            b"++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";

        assert_eq!(run(&bf_interpreter_blc, Bytes(&bf_hello[..])), Ok("Hello World!".into()));
    }
*/
}
<commit_msg>execution::Input::Binary > ::Bits<commit_after>//! Binary lambda calculus execution

use lambda_calculus::*;
use binary_encoding::from_binary;
use lambda_encoding::{encode, decode};
use self::Error::*;

/// An error that can occur during BLC execution.
#[derive(Debug, PartialEq)]
pub enum Error {
    /// invalid BLC program
    InvalidProgram,
    /// invalid BLC argument
    InvalidArgument
}

/// The type of input for BLC execution.
pub enum Input<'a> {
    /// no input parameter
    Nothing,
    /// BLC input
    Bits(&'a [u8]),
    /// unencoded byte input
    Bytes(&'a [u8])
}

/// Executes a binary lambda calculus program, optionally feeding it the given argument.
///
/// # Example
/// ```
/// use blc::execution::run;
/// use blc::execution::Input::Bytes;
///
/// let reverse_blc = b"0001011001000110100000000001011100111110111100001011011110110000010";
///
/// assert_eq!(run(&*reverse_blc, Bytes(b"herp derp")), Ok("pred preh".into()));
/// ```
pub fn run(blc_program: &[u8], input: Input) -> Result<String, Error> {
    let program = from_binary(blc_program);
    if program.is_err() { return Err(InvalidProgram) }
    let program = program.unwrap(); // safe

    let calculation = match input {
        Input::Nothing     => beta(program, NOR, 0),
        Input::Bytes(arg)  => beta(app(program, encode(arg)), NOR, 0),
        Input::Bits(arg) => {
            let arg = from_binary(arg);
            if arg.is_ok() {
                beta(app(program, arg.unwrap()), NOR, 0) // safe
            } else {
                return Err(InvalidArgument)
            }
        }
    };

    Ok(decode(calculation))
}

#[cfg(test)]
mod test {
    use super::*;
    use binary_encoding::{decompress, to_binary};
    use lambda_calculus::data::num::church::{is_zero, rem};

    #[test]
    fn id() {
        let id_compressed = b" ";
        let id_blc        = decompress(&*id_compressed);
        let input         = b"herp derp";

        assert_eq!(run(&*id_blc, Input::Bytes(&*input)).unwrap(), "herp derp".to_owned());
    }

    #[test]
    fn sort() {
        let sort_compressed =
            [0x15, 0x46, 0x84, 0x06, 0x05, 0x46, 0x81, 0x60, 0x15, 0xfb, 0xec, 0x2f, 0x80, 0x01,
             0x5b, 0xf9, 0x7f, 0x0b, 0x7e, 0xf7, 0x2f, 0xec, 0x2d, 0xfb, 0x80, 0x56, 0x05, 0xfd,
             0x85, 0xbb, 0x76, 0x11, 0x5d, 0x50, 0x5c, 0x00, 0xbe, 0x7f, 0xc1, 0x2b, 0xff, 0x0f,
             0xfc, 0x2c, 0x1b, 0x72, 0xbf, 0xf0, 0xff, 0xc2, 0xc1, 0x6d, 0x34, 0x50, 0x40];

        let sort_blc = decompress(&sort_compressed);
        let input  = b"3241";

        assert_eq!(run(&*sort_blc, Input::Bytes(&*input)).unwrap(), "1234".to_owned());
    }

    #[test]
    fn quine() {
        // program code from https://tromp.github.io/cl/Binary_lambda_calculus.html#A_quine
        let quine_blc = b"000101100100011010000000000001011\
            011110010111100111111011111011010";
        let input = b"hurr";

        assert_eq!(run(&quine_blc[..], Input::Bytes(&input[..])), Ok("hurrhurr".to_owned()));
    }

    #[test]
    fn inflating() {
        // program code from http://www.ioccc.org/2012/tromp/inflate.Blc
        let inflate_compressed =
            [0x44, 0x44, 0x68, 0x16, 0x01, 0x79, 0x1a, 0x00, 0x16, 0x7f, 0xfb, 0xcb, 0xcf, 0xdf,
             0x65, 0xfb, 0xed, 0x0f, 0x3c, 0xe7, 0x3c, 0xf3, 0xc2, 0xd8, 0x20, 0x58, 0x2c, 0x0b,
             0x06, 0xc0];

        let inflate_blc = decompress(&inflate_compressed);
        let s_compressed = [0x1, 0x7a, 0x74];

        assert_eq!(run(&*inflate_blc, Input::Bytes(&s_compressed[..])).unwrap(), "000000010111101001110100".to_owned());
    }

    #[test]
    fn deflating() {
        // program code from http://www.ioccc.org/2012/tromp/deflate.Blc
        let deflate_compressed =
            [0x44, 0x68, 0x16, 0x05, 0x7e, 0x01, 0x17, 0x00, 0xbe, 0x55, 0xff, 0xf0, 0x0d, 0xc1,
             0x8b, 0xb2, 0xc1, 0xb0, 0xf8, 0x7c, 0x2d, 0xd8, 0x05, 0x9e, 0x09, 0x7f, 0xbf, 0xb1,
             0x48, 0x39, 0xce, 0x81, 0xce, 0x80];

        let deflate_blc = decompress(&deflate_compressed);
        let s_blc = b"00000001011110100111010";

        assert_eq!(run(&*deflate_blc, Input::Bytes(&s_blc[..])).unwrap().as_bytes(), [0x1, 0x7a, 0x74]);
    }

    #[test]
    fn fizz_buzz() {
        let fizzbuzz_single =
            abs(
                app!(
                    is_zero(),
                    app!(rem(), Var(1), 15.into_church()),
                    encode(&b"FizzBuzz"[..]),
                    app!(
                        is_zero(),
                        app!(rem(), Var(1), 3.into_church()),
                        encode(&b"Fizz"[..]),
                        app!(
                            is_zero(),
                            app!(rem(), Var(1), 5.into_church()),
                            encode(&b"Buzz"[..]),
                            Var(1)
                        )
                    )
                )
            );
        let fizzbuzz_blc = to_binary(&fizzbuzz_single);

        assert_eq!(run(&*fizzbuzz_blc, Input::Bits(&to_binary(&1.into_church()))).unwrap(),  "(λλ21)");
        assert_eq!(run(&*fizzbuzz_blc, Input::Bits(&to_binary(&2.into_church()))).unwrap(),  "(λλ2(21))");
        assert_eq!(run(&*fizzbuzz_blc, Input::Bits(&to_binary(&3.into_church()))).unwrap(),  "Fizz");
        assert_eq!(run(&*fizzbuzz_blc, Input::Bits(&to_binary(&4.into_church()))).unwrap(),  "(λλ2(2(2(21))))");
        assert_eq!(run(&*fizzbuzz_blc, Input::Bits(&to_binary(&5.into_church()))).unwrap(),  "Buzz");
        assert_eq!(run(&*fizzbuzz_blc, Input::Bits(&to_binary(&15.into_church()))).unwrap(), "FizzBuzz");
    }

/*
    #[test] /* WIP; this one parses properly, but doesn't return the expected result */
    fn hilbert() {
        // program code from http://www.ioccc.org/2012/tromp/hilbert.Blc
        let hilbert_compressed =
            [0x18, 0x18, 0x18, 0x18, 0x11, 0x11, 0x54, 0x68, 0x06, 0x04, 0x15, 0x5f, 0xf0, 0x41,
             0x9d, 0xf9, 0xde, 0x16, 0xff, 0xfe, 0x5f, 0x3f, 0xef, 0xf6, 0x15, 0xff, 0x94, 0x68,
             0x40, 0x58, 0x11, 0x7e, 0x05, 0xcb, 0xfe, 0xbc, 0xbf, 0xee, 0x86, 0xcb, 0x94, 0x68,
             0x16, 0x00, 0x5c, 0x0b, 0xfa, 0xcb, 0xfb, 0xf7, 0x1a, 0x85, 0xe0, 0x5c, 0xf4, 0x14,
             0xd5, 0xfe, 0x08, 0x18, 0x0b, 0x04, 0x8d, 0x08, 0x00, 0xe0, 0x78, 0x01, 0x64, 0x45,
             0xff, 0xe5, 0xff, 0x7f, 0xff, 0xfe, 0x5f, 0xff, 0x2f, 0xc0, 0x2f, 0x7a, 0xd9, 0x7f,
             0x5b, 0xff, 0xff, 0xfb, 0xff, 0xfc, 0xaa, 0xff, 0xf7, 0x81, 0x7f, 0xfa, 0xdf, 0x76,
             0x69, 0x54, 0x68, 0x06, 0x01, 0x57, 0xf7, 0xe1, 0x60, 0x5c, 0x13, 0xfe, 0x80, 0xb2,
             0x2c, 0x18, 0x58, 0x1b, 0xfe, 0x5c, 0x10, 0x42, 0xff, 0x80, 0x5d, 0xee, 0xc0, 0x6c,
             0x2c, 0x0c, 0x06, 0x08, 0x19, 0x1a, 0x00, 0x16, 0x7f, 0xbc, 0xbc, 0xfd, 0xf6, 0x5f,
             0x7c, 0x0a, 0x20];

        let hilbert_blc = decompress(&hilbert_compressed);
        let arg = b"1234";

        assert_eq!(run(&hilbert_blc[..], Bytes(&arg[..])), Ok("WIP".into()));
    }
*/
/*
    #[test] /* WIP; this just returns λ1 */
    fn brainfuck() {
        // program code from http://www.ioccc.org/2012/tromp/bf.Blc
        let bf_interpreter_compressed =
            [0x44, 0x51, 0xa1, 0x01, 0x84, 0x55, 0xd5, 0x02, 0xb7, 0x70, 0x30, 0x22, 0xff, 0x32,
             0xf0, 0x00, 0xbf, 0xf9, 0x85, 0x7f, 0x5e, 0xe1, 0x6f, 0x95, 0x7f, 0x7d, 0xee, 0xc0,
             0xe5, 0x54, 0x68, 0x00, 0x58, 0x55, 0xfd, 0xfb, 0xe0, 0x45, 0x57, 0xfd, 0xeb, 0xfb,
             0xf0, 0xb6, 0xf0, 0x2f, 0xd6, 0x07, 0xe1, 0x6f, 0x73, 0xd7, 0xf1, 0x14, 0xbc, 0xc0,
             0x0b, 0xff, 0x2e, 0x1f, 0xa1, 0x6f, 0x66, 0x17, 0xe8, 0x5b, 0xef, 0x2f, 0xcf, 0xff,
             0x13, 0xff, 0xe1, 0xca, 0x34, 0x20, 0x0a, 0xc8, 0xd0, 0x0b, 0x99, 0xee, 0x1f, 0xe5,
             0xff, 0x7f, 0x5a, 0x6a, 0x1f, 0xff, 0x0f, 0xff, 0x87, 0x9d, 0x04, 0xd0, 0xab, 0x00,
             0x05, 0xdb, 0x23, 0x40, 0xb7, 0x3b, 0x28, 0xcc, 0xc0, 0xb0, 0x6c, 0x0e, 0x74, 0x10];

        let bf_interpreter_blc = decompress(&bf_interpreter_compressed);
        let bf_hello =
            b"++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";

        assert_eq!(run(&bf_interpreter_blc, Bytes(&bf_hello[..])), Ok("Hello World!".into()));
    }
*/
}
<|endoftext|>


<commit_before>pub use self::cargo_clean::{clean, CleanOptions};
pub use self::cargo_compile::{compile, compile_with_exec, compile_ws, CompileOptions};
pub use self::cargo_compile::{CompileFilter, CompileMode, MessageFormat, Packages};
pub use self::cargo_read_manifest::{read_package, read_packages};
pub use self::cargo_rustc::{compile_targets, Compilation, Kind, Unit};
pub use self::cargo_rustc::{Context, is_bad_artifact_name};
pub use self::cargo_rustc::{BuildOutput, BuildConfig, TargetConfig};
pub use self::cargo_rustc::{Executor, DefaultExecutor};
pub use self::cargo_run::run;
pub use self::cargo_install::{install, install_list, uninstall};
pub use self::cargo_new::{new, init, NewOptions, VersionControl};
pub use self::cargo_doc::{doc, DocOptions};
pub use self::cargo_generate_lockfile::{generate_lockfile};
pub use self::cargo_generate_lockfile::{update_lockfile};
pub use self::cargo_generate_lockfile::UpdateOptions;
pub use self::lockfile::{load_pkg_lockfile, write_pkg_lockfile};
pub use self::cargo_test::{run_tests, run_benches, TestOptions};
pub use self::cargo_package::{package, PackageOpts};
pub use self::registry::{publish, registry_configuration, RegistryConfig};
pub use self::registry::{registry_login, search, http_proxy_exists, http_handle};
pub use self::registry::{modify_owners, yank, OwnersOptions, PublishOpts};
pub use self::cargo_fetch::fetch;
pub use self::cargo_pkgid::pkgid;
pub use self::resolve::{resolve_ws, resolve_ws_precisely, resolve_with_previous};
pub use self::cargo_output_metadata::{output_metadata, OutputMetadataOptions, ExportInfo};

mod cargo_clean;
mod cargo_compile;
mod cargo_doc;
mod cargo_fetch;
mod cargo_generate_lockfile;
mod cargo_install;
mod cargo_new;
mod cargo_output_metadata;
mod cargo_package;
mod cargo_pkgid;
mod cargo_read_manifest;
mod cargo_run;
mod cargo_rustc;
mod cargo_test;
mod lockfile;
mod registry;
mod resolve;
<commit_msg>Auto merge of #4382 - Xanewok:expose-filter-rule, r=alexcrichton<commit_after>pub use self::cargo_clean::{clean, CleanOptions};
pub use self::cargo_compile::{compile, compile_with_exec, compile_ws, CompileOptions};
pub use self::cargo_compile::{CompileFilter, CompileMode, FilterRule, MessageFormat, Packages};
pub use self::cargo_read_manifest::{read_package, read_packages};
pub use self::cargo_rustc::{compile_targets, Compilation, Kind, Unit};
pub use self::cargo_rustc::{Context, is_bad_artifact_name};
pub use self::cargo_rustc::{BuildOutput, BuildConfig, TargetConfig};
pub use self::cargo_rustc::{Executor, DefaultExecutor};
pub use self::cargo_run::run;
pub use self::cargo_install::{install, install_list, uninstall};
pub use self::cargo_new::{new, init, NewOptions, VersionControl};
pub use self::cargo_doc::{doc, DocOptions};
pub use self::cargo_generate_lockfile::{generate_lockfile};
pub use self::cargo_generate_lockfile::{update_lockfile};
pub use self::cargo_generate_lockfile::UpdateOptions;
pub use self::lockfile::{load_pkg_lockfile, write_pkg_lockfile};
pub use self::cargo_test::{run_tests, run_benches, TestOptions};
pub use self::cargo_package::{package, PackageOpts};
pub use self::registry::{publish, registry_configuration, RegistryConfig};
pub use self::registry::{registry_login, search, http_proxy_exists, http_handle};
pub use self::registry::{modify_owners, yank, OwnersOptions, PublishOpts};
pub use self::cargo_fetch::fetch;
pub use self::cargo_pkgid::pkgid;
pub use self::resolve::{resolve_ws, resolve_ws_precisely, resolve_with_previous};
pub use self::cargo_output_metadata::{output_metadata, OutputMetadataOptions, ExportInfo};

mod cargo_clean;
mod cargo_compile;
mod cargo_doc;
mod cargo_fetch;
mod cargo_generate_lockfile;
mod cargo_install;
mod cargo_new;
mod cargo_output_metadata;
mod cargo_package;
mod cargo_pkgid;
mod cargo_read_manifest;
mod cargo_run;
mod cargo_rustc;
mod cargo_test;
mod lockfile;
mod registry;
mod resolve;
<|endoftext|>


<commit_before>use int::Int;

/// Returns `a` raised to the power `b`
macro_rules! pow {
    ($a: expr, $b: expr) => ({
        let (mut a, mut b) = ($a, $b);
        let recip = b < 0;
        let mut r = 1.0;
        loop {
            if (b & 1) != 0 {
                r *= a;
            }
            b = b.aborting_div(2);
            if b == 0 {
                break;
            }
            a *= a;
        }

        if recip {
            1.0 / r
        } else {
            r
        }
    })
}

intrinsics! {
    pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 {
        pow!(a, b)
    }

    pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 {
        pow!(a, b)
    }
}
<commit_msg>Don't use a macro for pow calculation<commit_after>use int::Int;
use float::Float;

trait Pow: Float {
    /// Returns `a` raised to the power `b`
    fn pow(self, mut b: i32) -> Self {
        let mut a = self;
        let recip = b < 0;
        let mut r = Self::ONE;
        loop {
            if (b & 1) != 0 {
                r *= a;
            }
            b = b.aborting_div(2);
            if b == 0 {
                break;
            }
            a *= a;
        }

        if recip {
            Self::ONE / r
        } else {
            r
        }
    }
}

impl Pow for f32 {}
impl Pow for f64 {}

intrinsics! {
    pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 {
        a.pow(b)
    }

    pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 {
        a.pow(b)
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::collections::HashMap;

use url::Url;
use hyper::{self, Client};
use hyper::client::{Request, Response};
use hyper::method::Method;
use rustc_serialize::json::{self, Json, Object};
use rustc_serialize::Encodable;
use multipart::client::Multipart;

use errors::WeChatError;
use types::WeChatResult;
use session::SessionStore;

#[derive(Debug, Clone)]
pub struct WeChatClient<T: SessionStore> {
    pub appid: String,
    pub secret: String,
    pub session: T,
}

impl<T: SessionStore> WeChatClient<T> {

    #[inline]
    pub fn new<S: Into<String>>(appid: S, secret: S, session: T) -> WeChatClient<T> {
        WeChatClient {
            appid: appid.into(),
            secret: secret.into(),
            session: session,
        }
    }

    #[inline]
    pub fn with_access_token<S: Into<String>>(appid: S, secret: S, access_token: S, session: T) -> WeChatClient<T> {
        let appid = appid.into();
        let secret = secret.into();
        let client = Self::new(appid.clone(), secret, session);
        let token_key = format!("{}_access_token", appid);
        client.session.set(&token_key, access_token.into(), None);
        client
    }

    #[inline]
    pub fn access_token(&self) -> String {
        let token_key = format!("{}_access_token", self.appid);
        let token: String = self.session.get(&token_key, Some("".to_owned())).unwrap();
        token
    }

    pub fn request<D: Encodable>(&self, method: Method, url: &str, params: Vec<(&str, &str)>, data: &D) -> WeChatResult<Response> {
        let mut http_url = if !(url.starts_with("http://") || url.starts_with("https://")) {
            let mut url_string = "https://api.weixin.qq.com/cgi-bin/".to_owned();
            url_string = url_string + url;
            Url::parse(&url_string).unwrap()
        } else {
            Url::parse(url).unwrap()
        };
        let access_token = self.access_token();
        let mut querys = params.clone();
        if !access_token.is_empty() {
            debug!("Using access_token: {}", access_token);
            querys.push(("access_token", &access_token));
        }
        http_url.set_query_from_pairs(querys.into_iter());
        let body = match json::encode(data) {
            Ok(text) => text,
            Err(_) => "".to_owned(),
        };
        let client = Client::new();
        let req = if method == Method::Post {
            client.post(http_url).body(&body)
        } else {
            client.get(http_url)
        };
        let res = match req.send() {
            Ok(_res) => _res,
            Err(_) => {
                error!("Send request error");
                return Err(WeChatError::ClientError { errcode: -1, errmsg: "Send request error".to_owned() });
            }
        };
        if res.status != hyper::Ok {
            error!("Response status error");
            return Err(WeChatError::ClientError { errcode: -2, errmsg: "Response status error".to_owned() })
        }
        Ok(res)

    }

    pub fn upload_file<R: Read>(&self, url: &str, params: Vec<(&str, &str)>, files: &mut HashMap<String, &mut R>) -> WeChatResult<Json> {
        if self.access_token().is_empty() {
            self.fetch_access_token();
        }

        let mut http_url = if !(url.starts_with("http://") || url.starts_with("https://")) {
            let mut url_string = "https://api.weixin.qq.com/cgi-bin/".to_owned();
            url_string = url_string + url;
            Url::parse(&url_string).unwrap()
        } else {
            Url::parse(url).unwrap()
        };
        let access_token = self.access_token();
        let mut querys = params.clone();
        if !access_token.is_empty() {
            debug!("Using access_token: {}", access_token);
            querys.push(("access_token", &access_token));
        }
        http_url.set_query_from_pairs(querys.into_iter());
        let request = Request::new(Method::Post, http_url).unwrap();
        let mut req = Multipart::from_request(request).unwrap();
        for (name, stream) in files.iter_mut() {
            req.write_stream(name, stream, None, None);
        }
        let mut res = match req.send() {
            Ok(_res) => _res,
            Err(_) => {
                error!("Send request error");
                return Err(WeChatError::ClientError { errcode: -1, errmsg: "Send request error".to_owned() });
            }
        };
        if res.status != hyper::Ok {
            error!("Response status error");
            return Err(WeChatError::ClientError { errcode: -2, errmsg: "Response status error".to_owned() })
        }
        self.json_decode(&mut res)
    }

    #[inline]
    fn json_decode(&self, res: &mut Response) -> WeChatResult<Json> {
        let obj = match Json::from_reader(res) {
            Ok(decoded) => { decoded },
            Err(_) => {
                error!("Json decode error");
                return Err(WeChatError::ClientError { errcode: -3, errmsg: "Json decode error".to_owned() });
            }
        };
        match obj.find("errcode") {
            Some(code) => {
                let errcode = code.as_i64().unwrap();
                if errcode != 0 {
                    let errmsg = match obj.find("errmsg") {
                        Some(msg) => {
                            msg.as_string().unwrap()
                        },
                        None => { "" }
                    };
                    return Err(WeChatError::ClientError { errcode: errcode as i32, errmsg: errmsg.to_owned() });
                }
            },
            None => {},
        }
        Ok(obj)
    }

    #[inline]
    pub fn post<D: Encodable>(&self, url: &str, params: Vec<(&str, &str)>, data: &D) -> WeChatResult<Json> {
        if self.access_token().is_empty() {
            self.fetch_access_token();
        }
        let mut res = try!(self.request(Method::Post, url, params, data));
        self.json_decode(&mut res)
    }

    #[inline]
    pub fn get(&self, url: &str, params: Vec<(&str, &str)>) -> WeChatResult<Json> {
        if self.access_token().is_empty() {
            self.fetch_access_token();
        }
        let mut res = try!(self.request(Method::Get, url, params, &Object::new()));
        self.json_decode(&mut res)
    }

    pub fn fetch_access_token(&self) -> Option<String> {
        let res = self.request(
            Method::Get,
            "token",
            vec![
                ("grant_type", "client_credential"),
                ("appid", &self.appid),
                ("secret", &self.secret),
            ],
            &Object::new()
        );
        let mut raw_data = match res {
            Ok(raw) => raw,
            Err(_) => { return None; },
        };
        let data = match self.json_decode(&mut raw_data) {
            Ok(data) => data,
            Err(_) => { return None; },
        };
        let token = match data.find("access_token") {
            Some(token) => token,
            None => { return None; }
        };
        let token_str = match *token {
            Json::String(ref v) => {
                let token_key = format!("{}_access_token", self.appid);
                self.session.set(&token_key, v.to_owned(), Some(7200usize));
                Some(format!("{}", v))
            },
            _ => None,
        };
        token_str
    }
}
<commit_msg>Use expires_in return instead of hardcode 7200 seconds<commit_after>use std::io::Read;
use std::collections::HashMap;

use url::Url;
use hyper::{self, Client};
use hyper::client::{Request, Response};
use hyper::method::Method;
use rustc_serialize::json::{self, Json, Object};
use rustc_serialize::Encodable;
use multipart::client::Multipart;

use errors::WeChatError;
use types::WeChatResult;
use session::SessionStore;

#[derive(Debug, Clone)]
pub struct WeChatClient<T: SessionStore> {
    pub appid: String,
    pub secret: String,
    pub session: T,
}

impl<T: SessionStore> WeChatClient<T> {

    #[inline]
    pub fn new<S: Into<String>>(appid: S, secret: S, session: T) -> WeChatClient<T> {
        WeChatClient {
            appid: appid.into(),
            secret: secret.into(),
            session: session,
        }
    }

    #[inline]
    pub fn with_access_token<S: Into<String>>(appid: S, secret: S, access_token: S, session: T) -> WeChatClient<T> {
        let appid = appid.into();
        let secret = secret.into();
        let client = Self::new(appid.clone(), secret, session);
        let token_key = format!("{}_access_token", appid);
        client.session.set(&token_key, access_token.into(), None);
        client
    }

    #[inline]
    pub fn access_token(&self) -> String {
        let token_key = format!("{}_access_token", self.appid);
        let token: String = self.session.get(&token_key, Some("".to_owned())).unwrap();
        token
    }

    pub fn request<D: Encodable>(&self, method: Method, url: &str, params: Vec<(&str, &str)>, data: &D) -> WeChatResult<Response> {
        let mut http_url = if !(url.starts_with("http://") || url.starts_with("https://")) {
            let mut url_string = "https://api.weixin.qq.com/cgi-bin/".to_owned();
            url_string = url_string + url;
            Url::parse(&url_string).unwrap()
        } else {
            Url::parse(url).unwrap()
        };
        let access_token = self.access_token();
        let mut querys = params.clone();
        if !access_token.is_empty() {
            debug!("Using access_token: {}", access_token);
            querys.push(("access_token", &access_token));
        }
        http_url.set_query_from_pairs(querys.into_iter());
        let body = match json::encode(data) {
            Ok(text) => text,
            Err(_) => "".to_owned(),
        };
        let client = Client::new();
        let req = if method == Method::Post {
            client.post(http_url).body(&body)
        } else {
            client.get(http_url)
        };
        let res = match req.send() {
            Ok(_res) => _res,
            Err(_) => {
                error!("Send request error");
                return Err(WeChatError::ClientError { errcode: -1, errmsg: "Send request error".to_owned() });
            }
        };
        if res.status != hyper::Ok {
            error!("Response status error");
            return Err(WeChatError::ClientError { errcode: -2, errmsg: "Response status error".to_owned() })
        }
        Ok(res)

    }

    pub fn upload_file<R: Read>(&self, url: &str, params: Vec<(&str, &str)>, files: &mut HashMap<String, &mut R>) -> WeChatResult<Json> {
        if self.access_token().is_empty() {
            self.fetch_access_token();
        }

        let mut http_url = if !(url.starts_with("http://") || url.starts_with("https://")) {
            let mut url_string = "https://api.weixin.qq.com/cgi-bin/".to_owned();
            url_string = url_string + url;
            Url::parse(&url_string).unwrap()
        } else {
            Url::parse(url).unwrap()
        };
        let access_token = self.access_token();
        let mut querys = params.clone();
        if !access_token.is_empty() {
            debug!("Using access_token: {}", access_token);
            querys.push(("access_token", &access_token));
        }
        http_url.set_query_from_pairs(querys.into_iter());
        let request = Request::new(Method::Post, http_url).unwrap();
        let mut req = Multipart::from_request(request).unwrap();
        for (name, stream) in files.iter_mut() {
            req.write_stream(name, stream, None, None);
        }
        let mut res = match req.send() {
            Ok(_res) => _res,
            Err(_) => {
                error!("Send request error");
                return Err(WeChatError::ClientError { errcode: -1, errmsg: "Send request error".to_owned() });
            }
        };
        if res.status != hyper::Ok {
            error!("Response status error");
            return Err(WeChatError::ClientError { errcode: -2, errmsg: "Response status error".to_owned() })
        }
        self.json_decode(&mut res)
    }

    #[inline]
    fn json_decode(&self, res: &mut Response) -> WeChatResult<Json> {
        let obj = match Json::from_reader(res) {
            Ok(decoded) => { decoded },
            Err(_) => {
                error!("Json decode error");
                return Err(WeChatError::ClientError { errcode: -3, errmsg: "Json decode error".to_owned() });
            }
        };
        match obj.find("errcode") {
            Some(code) => {
                let errcode = code.as_i64().unwrap();
                if errcode != 0 {
                    let errmsg = match obj.find("errmsg") {
                        Some(msg) => {
                            msg.as_string().unwrap()
                        },
                        None => { "" }
                    };
                    return Err(WeChatError::ClientError { errcode: errcode as i32, errmsg: errmsg.to_owned() });
                }
            },
            None => {},
        }
        Ok(obj)
    }

    #[inline]
    pub fn post<D: Encodable>(&self, url: &str, params: Vec<(&str, &str)>, data: &D) -> WeChatResult<Json> {
        if self.access_token().is_empty() {
            self.fetch_access_token();
        }
        let mut res = try!(self.request(Method::Post, url, params, data));
        self.json_decode(&mut res)
    }

    #[inline]
    pub fn get(&self, url: &str, params: Vec<(&str, &str)>) -> WeChatResult<Json> {
        if self.access_token().is_empty() {
            self.fetch_access_token();
        }
        let mut res = try!(self.request(Method::Get, url, params, &Object::new()));
        self.json_decode(&mut res)
    }

    pub fn fetch_access_token(&self) -> Option<String> {
        let res = self.request(
            Method::Get,
            "token",
            vec![
                ("grant_type", "client_credential"),
                ("appid", &self.appid),
                ("secret", &self.secret),
            ],
            &Object::new()
        );
        let mut raw_data = match res {
            Ok(raw) => raw,
            Err(_) => { return None; },
        };
        let data = match self.json_decode(&mut raw_data) {
            Ok(data) => data,
            Err(_) => { return None; },
        };
        let token = match data.find("access_token") {
            Some(token) => token,
            None => { return None; }
        };
        let expires_in = match data.find("expires_in") {
            Some(expires) => expires.as_u64().unwrap() as usize,
            None => 7200usize,
        };
        let token_str = match *token {
            Json::String(ref v) => {
                let token_key = format!("{}_access_token", self.appid);
                self.session.set(&token_key, v.to_owned(), Some(expires_in));
                Some(format!("{}", v))
            },
            _ => None,
        };
        token_str
    }
}
<|endoftext|>


<commit_before>use rustyline;
use rustyline::line_buffer::LineBuffer;

pub struct CustomCompletion {
    commands: Vec<&'static str>,
    hinter: rustyline::hint::HistoryHinter,
}

impl CustomCompletion {
    pub fn new() -> Self {
        let commands: Vec<&str> = vec!["help", "items", "projs", "quit"];

        Self {
            commands,
            hinter: rustyline::hint::HistoryHinter {},
        }
    }
}

impl rustyline::completion::Completer for CustomCompletion {
    type Candidate = String;

    fn complete(
        &self,
        line: &str,
        pos: usize,
        _ctx: &rustyline::Context<'_>,
    ) -> rustyline::Result<(usize, Vec<String>)> {
        let mut completions: Vec<String> = Vec::new();
        for command in &self.commands {
            if command.starts_with(line) {
                completions.push(command.to_string());
            }
        }

        Ok((pos, completions))
    }

    fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) {
        line.update(elected, start);
    }
}

impl rustyline::hint::Hinter for CustomCompletion {
    fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
        self.hinter.hint(line, pos, ctx)
    }
}

impl rustyline::Helper for CustomCompletion {}

impl rustyline::highlight::Highlighter for CustomCompletion {}

// Tests

#[cfg(test)]
use rustyline::completion::Completer;

#[cfg(test)]
fn verify_completion(input: &str, expected_completion: &str) {
    let hist = rustyline::history::History::new();
    let ctx = rustyline::Context::new(&hist);

    let completer = CustomCompletion::new();
    assert_eq!(
        completer.complete(input, 0, &ctx).unwrap(),
        (0, vec![String::from(expected_completion)])
    );
}

#[test]
fn completion_test_items() {
    // Verify that the completion for i completes to items.
    verify_completion("i", "items");
    verify_completion("ite", "items");
}

#[test]
fn completion_test_quit() {
    // Verify that the completion for q completes to quit.
    verify_completion("q", "quit");
    verify_completion("qui", "quit");
}

#[test]
fn completion_test_help() {
    // Verify that the completion for h completes to help.
    verify_completion("h", "help");
    verify_completion("he", "help");
}

#[test]
fn completion_test_projects() {
    // Verify that the completion for p completes to projs.
    verify_completion("p", "projs");
    verify_completion("pro", "projs");
}
<commit_msg>Completion: Implement new rustyline validator trait for our completer.<commit_after>use rustyline;
use rustyline::line_buffer::LineBuffer;

pub struct CustomCompletion {
    commands: Vec<&'static str>,
    hinter: rustyline::hint::HistoryHinter,
}

impl CustomCompletion {
    pub fn new() -> Self {
        let commands: Vec<&str> = vec!["help", "items", "projs", "quit"];

        Self {
            commands,
            hinter: rustyline::hint::HistoryHinter {},
        }
    }
}

impl rustyline::completion::Completer for CustomCompletion {
    type Candidate = String;

    fn complete(
        &self,
        line: &str,
        pos: usize,
        _ctx: &rustyline::Context<'_>,
    ) -> rustyline::Result<(usize, Vec<String>)> {
        let mut completions: Vec<String> = Vec::new();
        for command in &self.commands {
            if command.starts_with(line) {
                completions.push(command.to_string());
            }
        }

        Ok((pos, completions))
    }

    fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) {
        line.update(elected, start);
    }
}

impl rustyline::hint::Hinter for CustomCompletion {
    fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
        self.hinter.hint(line, pos, ctx)
    }
}

impl rustyline::validate::Validator for CustomCompletion {}

impl rustyline::Helper for CustomCompletion {}

impl rustyline::highlight::Highlighter for CustomCompletion {}

// Tests

#[cfg(test)]
use rustyline::completion::Completer;

#[cfg(test)]
fn verify_completion(input: &str, expected_completion: &str) {
    let hist = rustyline::history::History::new();
    let ctx = rustyline::Context::new(&hist);

    let completer = CustomCompletion::new();
    assert_eq!(
        completer.complete(input, 0, &ctx).unwrap(),
        (0, vec![String::from(expected_completion)])
    );
}

#[test]
fn completion_test_items() {
    // Verify that the completion for i completes to items.
    verify_completion("i", "items");
    verify_completion("ite", "items");
}

#[test]
fn completion_test_quit() {
    // Verify that the completion for q completes to quit.
    verify_completion("q", "quit");
    verify_completion("qui", "quit");
}

#[test]
fn completion_test_help() {
    // Verify that the completion for h completes to help.
    verify_completion("h", "help");
    verify_completion("he", "help");
}

#[test]
fn completion_test_projects() {
    // Verify that the completion for p completes to projs.
    verify_completion("p", "projs");
    verify_completion("pro", "projs");
}
<|endoftext|>


<commit_before>use std::iter::repeat;
use std::ops::{Index, RangeFull};
use std::fmt::Debug;

use super::point::Point;
use super::number::NumberOps;

#[derive(Debug)]
pub struct Ring<T> {
   v: Vec<T>,
   start: usize,
   end: usize,
}

impl<T> Ring<T> where T: Default + Clone + Debug {
   #[inline]
   pub fn new(capacity: usize) -> Self {
      let v = repeat(T::default()).take(capacity).collect();

      Ring { v: v, start: 0, end: 0 }
   }

   #[inline]
   pub fn len(&self) -> usize {
      self.end - self.start
   }

   #[inline]
   pub fn last(&self) -> Option<&T> {
      if self.start == self.end {
         None
      } else {
         Some(unsafe {
            self.v.get_unchecked(self.end - 1)
         })
      }
   }

   #[inline]
   pub fn start(&self) -> usize {
      self.start
   }

   #[inline]
   pub fn end(&self) -> usize {
      self.end
   }

   #[inline]
   pub fn consume_at(&mut self, marker: usize) {
      self.start = marker;
   }

   #[inline]
   pub fn consume(&mut self) {
      self.start = self.end;
   }

   #[inline]
   pub fn reserve(&mut self, additional: usize) {
      self.v.reserve(additional);
   }

   #[inline]
   pub fn rewind(&mut self, extra: usize) {
      if extra > (self.v.len() - self.end) {
         if self.start != self.end {
            for i in 0..(self.end - self.start) {
               self.v[i] = self.v[self.start + i].clone();
            }
         }

         self.end -= self.start;
         self.start = 0;
      }
   }

   #[inline]
   pub fn push(&mut self, value: T) {
      self.v[self.end] = value;
      self.end += 1;
   }

   #[inline]
   pub fn next_index(&self, index: usize) -> usize {
      let index = index + 1;
      if index == self.end {
         self.start
      } else {
         index
      }
   }

   #[inline]
   pub fn prev_index(&self, index: usize) -> usize {
      if index == self.start {
         self.end - 1
      } else {
         self.start - 1
      }
   }
}

impl<T> Index<usize> for Ring<T> {
   type Output = T;

   #[inline]
   fn index(&self, index: usize) -> &T {
      &self.v[index]
   }
}

impl<T> Index<RangeFull> for Ring<T> {
   type Output = [T];

   #[inline]
   fn index(&self, _index: RangeFull) -> &[T] {
      &self.v[self.start..self.end]
   }
}

#[inline]
pub fn h_down_intersect(y: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.y > y {
      if p1.y < y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
   } else {
      if p1.y > y && p2.y < y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
      points.push(p2);
   }
}

#[inline]
pub fn h_up_intersect(y: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.y < y {
      if p1.y > y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
   } else {
      if p1.y < y && p2.y > y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
      points.push(p2);
   }
}

#[inline]
pub fn v_left_intersect(x: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.x > x {
      if p1.x < x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
   } else {
      if p1.x > x && p2.x < x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
      points.push(p2);
   }
}

#[inline]
pub fn v_right_intersect(x: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.x < x {
      if p1.x > x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
   } else {
      if p1.x < x && p2.x > x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
      points.push(p2);
   }
}

#[inline]
pub fn h_intersect(y: i64, p1: Point, p2: Point) -> i64 {
   p1.x + ((p2.x - p1.x) * (y - p1.y)).rounding_div(p2.y - p1.y)
}

#[inline]
pub fn v_intersect(x: i64, p1: Point, p2: Point) -> i64 {
   p1.y + ((p2.y - p1.y) * (x - p1.x)).rounding_div(p2.x - p1.x)
}

pub fn hv_clip<F>(intersect: F, at: i64, points: &mut Ring<Point>) where
   F: Fn(i64, Point, Point, &mut Ring<Point>),
{
   let start = points.start();
   let end = points.end();

   points.rewind(2 * (end - start));

   let rewinded_end = points.end();

   let mut p1 = points[end-1];

   for i in start..end {
      let p2 = points[i];

      intersect(at, p1, p2, points);

      p1 = p2;
   }

   points.consume_at(rewinded_end);
}

pub fn hv_split<F>(split: F, at: i64, write: &mut Ring<Point>, read_write: &mut Ring<Point>) where
   F: Fn(i64, Point, Point, &mut Ring<Point>, &mut Ring<Point>),
{
   let start = read_write.start();
   let end = read_write.end();

   let double = 2 * (end - start);
   read_write.rewind(double);
   write.rewind(double);

   let rewinded_end = read_write.end();

   assert!(end - start > 2);

   let mut p1 = read_write[end-1];

   for i in start..end {
      let p2 = read_write[i];

      split(at, p1, p2, write, read_write);

      p1 = p2;
   }

   read_write.consume_at(rewinded_end);
}

#[inline]
pub fn h_split_edge(y: i64, p1: Point, p2: Point, down: &mut Ring<Point>, up: &mut Ring<Point>) {
   if p2.y > y {
      if p1.y < y {
         let intersection = Point::new(h_intersect(y, p1, p2), y);
         down.push(intersection);
         up.push(intersection);
      }
      up.push(p2);
   } else if p2.y < y {
      if p1.y > y {
         let intersection = Point::new(h_intersect(y, p1, p2), y);
         down.push(intersection);
         up.push(intersection);
      }
      down.push(p2);
   } else {
      down.push(p2);
      up.push(p2);
   }
}

#[inline]
pub fn v_split_edge(x: i64, p1: Point, p2: Point, left: &mut Ring<Point>, right: &mut Ring<Point>) {
   if p2.x > x {
      if p1.x < x {
         let intersection = Point::new(x, v_intersect(x, p1, p2));
         left.push(intersection);
         right.push(intersection);
      }
      right.push(p2);
   } else if p2.x < x {
      if p1.x > x {
         let intersection = Point::new(x, v_intersect(x, p1, p2));
         left.push(intersection);
         right.push(intersection);
      }
      left.push(p2);
   } else {
      left.push(p2);
      right.push(p2);
   }
}

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

   use super::super::point::Point;

   use super::*;

   #[bench]
   fn bench_clip(b: &mut Bencher) {
      let mut points = Ring::new(1024 * 256);

      b.iter(|| {
         for _ in 0..1000 {
            points.consume();

            points.push(Point::new(50, 50));
            points.push(Point::new(100, 200));
            points.push(Point::new(150, 100));

            hv_clip(h_down_intersect, 150, &mut points);

            hv_clip(h_up_intersect, 80, &mut points);

            hv_clip(v_right_intersect, 70, &mut points);

            hv_clip(v_left_intersect, 140, &mut points);
         }
      });
   }

   #[test]
   fn test_clip() {
      let mut points = Ring::new(30);

      points.push(Point::new(50, 50));
      points.push(Point::new(100, 200));
      points.push(Point::new(150, 100));

      hv_clip(h_down_intersect, 150, &mut points);

      hv_clip(h_up_intersect, 80, &mut points);

      hv_clip(v_right_intersect, 70, &mut points);

      hv_clip(v_left_intersect, 140, &mut points);

      assert_eq!(points[..].len(), 7);

      assert_eq!(&points[..], [
         Point::new(140, 95),
         Point::new(110, 80),
         Point::new(70, 80),
         Point::new(70, 110),
         Point::new(83, 150),
         Point::new(125, 150),
         Point::new(140, 120),
      ]);
   }
}
<commit_msg>hv_split not crashing on 1 or 2 points input<commit_after>use std::iter::repeat;
use std::ops::{Index, RangeFull};
use std::fmt::Debug;

use super::point::Point;
use super::number::NumberOps;

#[derive(Debug)]
pub struct Ring<T> {
   v: Vec<T>,
   start: usize,
   end: usize,
}

impl<T> Ring<T> where T: Default + Clone + Debug {
   #[inline]
   pub fn new(capacity: usize) -> Self {
      let v = repeat(T::default()).take(capacity).collect();

      Ring { v: v, start: 0, end: 0 }
   }

   #[inline]
   pub fn len(&self) -> usize {
      self.end - self.start
   }

   #[inline]
   pub fn last(&self) -> Option<&T> {
      if self.start == self.end {
         None
      } else {
         Some(unsafe {
            self.v.get_unchecked(self.end - 1)
         })
      }
   }

   #[inline]
   pub fn start(&self) -> usize {
      self.start
   }

   #[inline]
   pub fn end(&self) -> usize {
      self.end
   }

   #[inline]
   pub fn consume_at(&mut self, marker: usize) {
      self.start = marker;
   }

   #[inline]
   pub fn consume(&mut self) {
      self.start = self.end;
   }

   #[inline]
   pub fn reserve(&mut self, additional: usize) {
      self.v.reserve(additional);
   }

   #[inline]
   pub fn rewind(&mut self, extra: usize) {
      if extra > (self.v.len() - self.end) {
         if self.start != self.end {
            for i in 0..(self.end - self.start) {
               self.v[i] = self.v[self.start + i].clone();
            }
         }

         self.end -= self.start;
         self.start = 0;
      }
   }

   #[inline]
   pub fn push(&mut self, value: T) {
      self.v[self.end] = value;
      self.end += 1;
   }

   #[inline]
   pub fn next_index(&self, index: usize) -> usize {
      let index = index + 1;
      if index == self.end {
         self.start
      } else {
         index
      }
   }

   #[inline]
   pub fn prev_index(&self, index: usize) -> usize {
      if index == self.start {
         self.end - 1
      } else {
         self.start - 1
      }
   }
}

impl<T> Index<usize> for Ring<T> {
   type Output = T;

   #[inline]
   fn index(&self, index: usize) -> &T {
      &self.v[index]
   }
}

impl<T> Index<RangeFull> for Ring<T> {
   type Output = [T];

   #[inline]
   fn index(&self, _index: RangeFull) -> &[T] {
      &self.v[self.start..self.end]
   }
}

#[inline]
pub fn h_down_intersect(y: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.y > y {
      if p1.y < y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
   } else {
      if p1.y > y && p2.y < y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
      points.push(p2);
   }
}

#[inline]
pub fn h_up_intersect(y: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.y < y {
      if p1.y > y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
   } else {
      if p1.y < y && p2.y > y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
      points.push(p2);
   }
}

#[inline]
pub fn v_left_intersect(x: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.x > x {
      if p1.x < x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
   } else {
      if p1.x > x && p2.x < x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
      points.push(p2);
   }
}

#[inline]
pub fn v_right_intersect(x: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.x < x {
      if p1.x > x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
   } else {
      if p1.x < x && p2.x > x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
      points.push(p2);
   }
}

#[inline]
pub fn h_intersect(y: i64, p1: Point, p2: Point) -> i64 {
   p1.x + ((p2.x - p1.x) * (y - p1.y)).rounding_div(p2.y - p1.y)
}

#[inline]
pub fn v_intersect(x: i64, p1: Point, p2: Point) -> i64 {
   p1.y + ((p2.y - p1.y) * (x - p1.x)).rounding_div(p2.x - p1.x)
}

pub fn hv_clip<F>(intersect: F, at: i64, points: &mut Ring<Point>) where
   F: Fn(i64, Point, Point, &mut Ring<Point>),
{
   let start = points.start();
   let end = points.end();

   points.rewind(2 * (end - start));

   let rewinded_end = points.end();

   let mut p1 = points[end-1];

   for i in start..end {
      let p2 = points[i];

      intersect(at, p1, p2, points);

      p1 = p2;
   }

   points.consume_at(rewinded_end);
}

pub fn hv_split<F>(split: F, at: i64, write: &mut Ring<Point>, read_write: &mut Ring<Point>) where
   F: Fn(i64, Point, Point, &mut Ring<Point>, &mut Ring<Point>),
{
   let start = read_write.start();
   let end = read_write.end();

   if end - start <= 2 {
      read_write.consume();
      return;
   }

   let double = 2 * (end - start);
   read_write.rewind(double);
   write.rewind(double);

   let rewinded_end = read_write.end();

   let mut p1 = read_write[end-1];

   for i in start..end {
      let p2 = read_write[i];

      split(at, p1, p2, write, read_write);

      p1 = p2;
   }

   read_write.consume_at(rewinded_end);
}

#[inline]
pub fn h_split_edge(y: i64, p1: Point, p2: Point, down: &mut Ring<Point>, up: &mut Ring<Point>) {
   if p2.y > y {
      if p1.y < y {
         let intersection = Point::new(h_intersect(y, p1, p2), y);
         down.push(intersection);
         up.push(intersection);
      }
      up.push(p2);
   } else if p2.y < y {
      if p1.y > y {
         let intersection = Point::new(h_intersect(y, p1, p2), y);
         down.push(intersection);
         up.push(intersection);
      }
      down.push(p2);
   } else {
      down.push(p2);
      up.push(p2);
   }
}

#[inline]
pub fn v_split_edge(x: i64, p1: Point, p2: Point, left: &mut Ring<Point>, right: &mut Ring<Point>) {
   if p2.x > x {
      if p1.x < x {
         let intersection = Point::new(x, v_intersect(x, p1, p2));
         left.push(intersection);
         right.push(intersection);
      }
      right.push(p2);
   } else if p2.x < x {
      if p1.x > x {
         let intersection = Point::new(x, v_intersect(x, p1, p2));
         left.push(intersection);
         right.push(intersection);
      }
      left.push(p2);
   } else {
      left.push(p2);
      right.push(p2);
   }
}

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

   use super::super::point::Point;

   use super::*;

   #[bench]
   fn bench_clip(b: &mut Bencher) {
      let mut points = Ring::new(1024 * 256);

      b.iter(|| {
         for _ in 0..1000 {
            points.consume();

            points.push(Point::new(50, 50));
            points.push(Point::new(100, 200));
            points.push(Point::new(150, 100));

            hv_clip(h_down_intersect, 150, &mut points);

            hv_clip(h_up_intersect, 80, &mut points);

            hv_clip(v_right_intersect, 70, &mut points);

            hv_clip(v_left_intersect, 140, &mut points);
         }
      });
   }

   #[test]
   fn test_clip() {
      let mut points = Ring::new(30);

      points.push(Point::new(50, 50));
      points.push(Point::new(100, 200));
      points.push(Point::new(150, 100));

      hv_clip(h_down_intersect, 150, &mut points);

      hv_clip(h_up_intersect, 80, &mut points);

      hv_clip(v_right_intersect, 70, &mut points);

      hv_clip(v_left_intersect, 140, &mut points);

      assert_eq!(points[..].len(), 7);

      assert_eq!(&points[..], [
         Point::new(140, 95),
         Point::new(110, 80),
         Point::new(70, 80),
         Point::new(70, 110),
         Point::new(83, 150),
         Point::new(125, 150),
         Point::new(140, 120),
      ]);
   }
}
<|endoftext|>


<commit_before>use sys;
use sys::{VALUE};

use super::{CheckResult, FromRuby, ToRuby, ToRubyResult};

impl<T: FromRuby> FromRuby for Vec<T> {
    type Checked = Vec<T::Checked>;

    fn from_ruby(value: VALUE) -> CheckResult<Self::Checked> {
        if unsafe { sys::RB_TYPE_P(value, sys::T_ARRAY) } {
            // Make sure we can actually do the conversions for the values.
            let len = unsafe { sys::RARRAY_LEN(value) };
            let mut checked = Vec::with_capacity(len as usize);
            for i in 0..len {
                let val = unsafe { sys::rb_ary_entry(value, i) };
                match T::from_ruby(val) {
                    Ok(v) => checked.push(v),
                    Err(e) => type_error!(format!("Failed to convert value for Vec<T>: {}", e)),
                }
            }
            Ok(checked)
        } else {
            type_error!(value, "an array")
        }
    }

    fn from_checked(checked: Self::Checked) -> Self {
        checked.into_iter().map(T::from_checked).collect()
    }
}

impl<T: ToRuby> ToRuby for Vec<T> {
    fn to_ruby(self) -> ToRubyResult {
        let ary = unsafe { sys::rb_ary_new_capa(self.len() as isize) };
        for item in self {
            unsafe { sys::rb_ary_push(ary, item.to_ruby()?); }
        }
        Ok(ary)
    }
}
<commit_msg>Improve error message<commit_after>use sys;
use sys::{VALUE};

use super::{CheckResult, FromRuby, ToRuby, ToRubyResult};
use super::super::{inspect};

impl<T: FromRuby> FromRuby for Vec<T> {
    type Checked = Vec<T::Checked>;

    fn from_ruby(value: VALUE) -> CheckResult<Self::Checked> {
        if unsafe { sys::RB_TYPE_P(value, sys::T_ARRAY) } {
            // Make sure we can actually do the conversions for the values.
            let len = unsafe { sys::RARRAY_LEN(value) };
            let mut checked = Vec::with_capacity(len as usize);

            for i in 0..len {
                let val = unsafe { sys::rb_ary_entry(value, i) };
                match T::from_ruby(val) {
                    Ok(v) => checked.push(v),
                    Err(e) => type_error!(format!("Failed to convert {}, element {} has the wrong type: {}", inspect(value), i, e)),
                }
            }

            Ok(checked)
        } else {
            type_error!(value, "an array")
        }
    }

    fn from_checked(checked: Self::Checked) -> Self {
        checked.into_iter().map(T::from_checked).collect()
    }
}

impl<T: ToRuby> ToRuby for Vec<T> {
    fn to_ruby(self) -> ToRubyResult {
        let ary = unsafe { sys::rb_ary_new_capa(self.len() as isize) };
        for item in self {
            unsafe { sys::rb_ary_push(ary, item.to_ruby()?); }
        }
        Ok(ary)
    }
}
<|endoftext|>


<commit_before>extern crate libc;
use self::libc::*;

use low_level as ll;
use error::Error;
use device::Device;
use context::Context;
use event::{Event, EventStatus, EventLike};
use kernel::Kernel;
use mem::Mem;

use std::ptr;
use std::mem::{size_of, transmute};

pub struct CommandQueue {
    pub id: ll::CommandQueue,
}

pub struct ReadLock<'a, T: Sized + 'a> {
    #[allow(dead_code)]
    sl: &'a [T],
    evt: Event,
}

pub struct WriteLock<'a, T: Sized + 'a> {
    #[allow(dead_code)]
    sl: &'a mut [T],
    evt: Event,
}

impl<'a, T: Sized> Drop for ReadLock<'a, T> {
    fn drop(self: &mut Self) -> () {
        self.evt.wait().ok().expect(
            "error waiting to finish write for ReadLock");
    }
}

impl<'a, T: Sized> EventLike for ReadLock<'a, T> {
    fn status(self: &Self) -> Result<EventStatus, Error> {
        self.evt.status()
    }

    fn wait(self: &Self) -> Result<(), Error> {
        self.evt.wait()
    }
}

impl<'a, T: Sized> Drop for WriteLock<'a, T> {
    fn drop(self: &mut Self) -> () {
        self.evt.wait().ok().expect(
            "error waiting to finish write for ReadLock");
    }
}

impl<'a, T: Sized> EventLike for WriteLock<'a, T> {
    fn status(self: &Self) -> Result<EventStatus, Error> {
        self.evt.status()
    }

    fn wait(self: &Self) -> Result<(), Error> {
        self.evt.wait()
    }
}

impl CommandQueue {
    pub fn new(context: Context,
               device: Device) -> Result<CommandQueue, Error> {
        let props: c_ulong = if try!(device.out_of_order_supported()) {
            1
        } else {
            0
        };
        let id = unsafe {
            let mut err: i32 = 0;
            let id = ll::clCreateCommandQueue(context.id,
                                              device.id,
                                              props,
                                              &mut err);
            try!(Error::check(err));
            id
        };
        Ok(CommandQueue{ id: id })
    }

    fn get_info(self: &Self, param: u32) -> Result<*mut c_void, Error> {
        let mut tr: *mut c_void = ptr::null_mut();
        unsafe {
            try!(Error::check(ll::clGetCommandQueueInfo(self.id,
                                                   param,
                                                   size_of::<*mut c_void>() as size_t,
                                                   transmute(&mut tr),
                                                   ptr::null_mut())));
        }
        Ok(tr)
    }

    pub fn context(self: &Self) -> Result<Context, Error> {
        let val = try!(self.get_info(0x1090));
        let id = unsafe { transmute(val) };
        unsafe {
            try!(Error::check(ll::clRetainContext(id)));
        }
        Ok(Context{id: id})
    }

    pub fn device(self: &Self) -> Result<Device, Error> {
        let val = try!(self.get_info(0x1091));
        let id = unsafe { transmute(val) };
        Ok(Device{id: id})
    }

    fn alloc_ll_buffer(self: &Self,
                    flags: c_ulong,
                    size_bytes: usize) -> Result<ll::Mem, Error> {
        let context = try!(self.context());
        let id = unsafe {
            let mut err: i32 = 0;
            let id = ll::clCreateBuffer(context.id,
                                        flags,
                                        size_bytes as size_t,
                                        ptr::null_mut(),
                                        &mut err);
            try!(Error::check(err));
            id
        };
        Ok(id)
    }

    fn write_buffer_raw<T: Sized>(self: &Self,
                       buf: &mut Mem,
                       offset: usize,
                       size: usize,
                       data: &[T]) -> Result<Event, Error> {
        let mut event_id: ll::Event = ptr::null_mut();
        let host_ptr = &data[0] as *const T;
        let wait_list: Vec<ll::Event> = buf.write_events();
        let wait_size = wait_list.len() as u32;

        let wait_list_ptr: *const ll::Event = match wait_size {
            0 => ptr::null(),
            _ => &wait_list[0],
        };

        unsafe {
            try!(Error::check(ll::clEnqueueWriteBuffer(self.id,
                                                       buf.id,
                                                       0, // don't block
                                                       offset as size_t,
                                                       size as size_t,
                                                       transmute(host_ptr),
                                                       wait_size,
                                                       wait_list_ptr,
                                                       &mut event_id)));
        }

        let event = Event{id: event_id};
        buf.register_write(event.clone());
        Ok(event)
    }

    fn read_buffer_raw<T: Sized>(self: &Self,
                                 buf: &Mem,
                                 offset: usize,
                                 size: usize,
                                 data: &mut [T]) -> Result<Event, Error> {
        let mut event_id: ll::Event = ptr::null_mut();
        let host_ptr = &mut data[0] as *mut T;
        let wait_list: Vec<ll::Event> = buf.read_events();
        let wait_size = wait_list.len() as u32;

        let wait_list_ptr: *const ll::Event = match wait_size {
            0 => ptr::null(),
            _ => &wait_list[0],
        };

        unsafe {
            try!(Error::check(ll::clEnqueueReadBuffer(self.id,
                                                      buf.id,
                                                      0, // don't block,
                                                      offset as size_t,
                                                      size as size_t,
                                                      transmute(host_ptr),
                                                      wait_size,
                                                      wait_list_ptr,
                                                      &mut event_id)));
        }

        let event = Event{id: event_id};
        buf.register_read(event.clone());
        Ok(event)
    }

    pub fn create_buffer(self: &Self,
                               size_bytes: usize) -> Result<Mem, Error> {
        let id = try!(self.alloc_ll_buffer(0, size_bytes));
        let mut tr = Mem::new(id);
        // one-byte write to place buffer on device and ensure
        // allocated memory is okay
        let _ = try!(self.write_buffer_raw(&mut tr,
                                           0,
                                           1,
                                           &[self]));
        Ok(tr)
    }

    pub fn write_buffer<'a, 'b, T: Sized + 'a>(self: &Self,
                                  mem: &'b mut Mem,
                                  slice: &'a [T]) -> Result<ReadLock<'a, T>, Error> {
        let size_bytes = size_of::<T>()*slice.len();
        let evt = try!(self.write_buffer_raw(mem,
                                             0,
                                             size_bytes,
                                             slice));
        Ok(ReadLock{ evt: evt, sl: slice })
    }

    pub fn read_buffer<'a, T: Sized>(self: &Self,
                                 mem: &Mem,
                                 slice: &'a mut [T]) -> Result<WriteLock<'a, T>, Error> {
        let size_bytes = size_of::<T>()*slice.len();
        let evt = try!(self.read_buffer_raw(mem,
                                            0,
                                            size_bytes,
                                            slice));
        Ok(WriteLock{ evt: evt, sl: slice })
    }

    fn next_mul(self: &Self, global: usize, local: usize) -> usize {
        if local % global == 0 {
            global
        } else {
            ((global/local)+1)*local
        }
    }

    pub fn run( self: &Self,
                kernel: &mut Kernel,
                local_size: (usize, usize, usize),
                global_size: (usize, usize, usize)) -> Result<Event, Error> {
        let events = kernel.run_events();
        let global_size_fixed = (self.next_mul(global_size.0, local_size.0),
                                self.next_mul(global_size.1, local_size.1),
                                self.next_mul(global_size.2, local_size.2));

        let local_vec = vec!(local_size.0 as size_t,
                             local_size.1 as size_t,
                             local_size.2 as size_t);
        let global_vec = vec!(global_size_fixed.0 as size_t,
                              global_size_fixed.1 as size_t,
                              global_size_fixed.2 as size_t);

        let mut event_id: ll::Event = ptr::null_mut();
        unsafe {
            try!(Error::check(ll::clEnqueueNDRangeKernel(self.id,
                                                         kernel.id,
                                                         3,
                                                         ptr::null(),
                                                         &global_vec[0],
                                                         &local_vec[0],
                                                         events.len() as u32,
                                                         &events[0],
                                                         &mut event_id)));
        }
        let event = Event{id: event_id};

        try!(kernel.register_run(event.clone()));
        Ok(event)
    }
}

impl Drop for CommandQueue {
    fn drop(self: &mut Self) -> () {
        unsafe {
            Error::check(ll::clReleaseCommandQueue(self.id))
                .ok().expect("Error releasing command queue");
        }
    }
}

impl Clone for CommandQueue {
    fn clone(self: &Self) -> Self {
        unsafe {
            Error::check(ll::clRetainCommandQueue(self.id))
                .ok().expect("Error retaining command queue");
        }
        CommandQueue{ id: self.id }
    }
}

<commit_msg>fixes workgroup size bug<commit_after>extern crate libc;
use self::libc::*;

use low_level as ll;
use error::Error;
use device::Device;
use context::Context;
use event::{Event, EventStatus, EventLike};
use kernel::Kernel;
use mem::Mem;

use std::ptr;
use std::mem::{size_of, transmute};

pub struct CommandQueue {
    pub id: ll::CommandQueue,
}

pub struct ReadLock<'a, T: Sized + 'a> {
    #[allow(dead_code)]
    sl: &'a [T],
    evt: Event,
}

pub struct WriteLock<'a, T: Sized + 'a> {
    #[allow(dead_code)]
    sl: &'a mut [T],
    evt: Event,
}

impl<'a, T: Sized> Drop for ReadLock<'a, T> {
    fn drop(self: &mut Self) -> () {
        self.evt.wait().ok().expect(
            "error waiting to finish write for ReadLock");
    }
}

impl<'a, T: Sized> EventLike for ReadLock<'a, T> {
    fn status(self: &Self) -> Result<EventStatus, Error> {
        self.evt.status()
    }

    fn wait(self: &Self) -> Result<(), Error> {
        self.evt.wait()
    }
}

impl<'a, T: Sized> Drop for WriteLock<'a, T> {
    fn drop(self: &mut Self) -> () {
        self.evt.wait().ok().expect(
            "error waiting to finish write for ReadLock");
    }
}

impl<'a, T: Sized> EventLike for WriteLock<'a, T> {
    fn status(self: &Self) -> Result<EventStatus, Error> {
        self.evt.status()
    }

    fn wait(self: &Self) -> Result<(), Error> {
        self.evt.wait()
    }
}

impl CommandQueue {
    pub fn new(context: Context,
               device: Device) -> Result<CommandQueue, Error> {
        let props: c_ulong = if try!(device.out_of_order_supported()) {
            1
        } else {
            0
        };
        let id = unsafe {
            let mut err: i32 = 0;
            let id = ll::clCreateCommandQueue(context.id,
                                              device.id,
                                              props,
                                              &mut err);
            try!(Error::check(err));
            id
        };
        Ok(CommandQueue{ id: id })
    }

    fn get_info(self: &Self, param: u32) -> Result<*mut c_void, Error> {
        let mut tr: *mut c_void = ptr::null_mut();
        unsafe {
            try!(Error::check(ll::clGetCommandQueueInfo(self.id,
                                                   param,
                                                   size_of::<*mut c_void>() as size_t,
                                                   transmute(&mut tr),
                                                   ptr::null_mut())));
        }
        Ok(tr)
    }

    pub fn context(self: &Self) -> Result<Context, Error> {
        let val = try!(self.get_info(0x1090));
        let id = unsafe { transmute(val) };
        unsafe {
            try!(Error::check(ll::clRetainContext(id)));
        }
        Ok(Context{id: id})
    }

    pub fn device(self: &Self) -> Result<Device, Error> {
        let val = try!(self.get_info(0x1091));
        let id = unsafe { transmute(val) };
        Ok(Device{id: id})
    }

    fn alloc_ll_buffer(self: &Self,
                    flags: c_ulong,
                    size_bytes: usize) -> Result<ll::Mem, Error> {
        let context = try!(self.context());
        let id = unsafe {
            let mut err: i32 = 0;
            let id = ll::clCreateBuffer(context.id,
                                        flags,
                                        size_bytes as size_t,
                                        ptr::null_mut(),
                                        &mut err);
            try!(Error::check(err));
            id
        };
        Ok(id)
    }

    fn write_buffer_raw<T: Sized>(self: &Self,
                       buf: &mut Mem,
                       offset: usize,
                       size: usize,
                       data: &[T]) -> Result<Event, Error> {
        let mut event_id: ll::Event = ptr::null_mut();
        let host_ptr = &data[0] as *const T;
        let wait_list: Vec<ll::Event> = buf.write_events();
        let wait_size = wait_list.len() as u32;

        let wait_list_ptr: *const ll::Event = match wait_size {
            0 => ptr::null(),
            _ => &wait_list[0],
        };

        unsafe {
            try!(Error::check(ll::clEnqueueWriteBuffer(self.id,
                                                       buf.id,
                                                       0, // don't block
                                                       offset as size_t,
                                                       size as size_t,
                                                       transmute(host_ptr),
                                                       wait_size,
                                                       wait_list_ptr,
                                                       &mut event_id)));
        }

        let event = Event{id: event_id};
        buf.register_write(event.clone());
        Ok(event)
    }

    fn read_buffer_raw<T: Sized>(self: &Self,
                                 buf: &Mem,
                                 offset: usize,
                                 size: usize,
                                 data: &mut [T]) -> Result<Event, Error> {
        let mut event_id: ll::Event = ptr::null_mut();
        let host_ptr = &mut data[0] as *mut T;
        let wait_list: Vec<ll::Event> = buf.read_events();
        let wait_size = wait_list.len() as u32;

        let wait_list_ptr: *const ll::Event = match wait_size {
            0 => ptr::null(),
            _ => &wait_list[0],
        };

        unsafe {
            try!(Error::check(ll::clEnqueueReadBuffer(self.id,
                                                      buf.id,
                                                      0, // don't block,
                                                      offset as size_t,
                                                      size as size_t,
                                                      transmute(host_ptr),
                                                      wait_size,
                                                      wait_list_ptr,
                                                      &mut event_id)));
        }

        let event = Event{id: event_id};
        buf.register_read(event.clone());
        Ok(event)
    }

    pub fn create_buffer(self: &Self,
                               size_bytes: usize) -> Result<Mem, Error> {
        let id = try!(self.alloc_ll_buffer(0, size_bytes));
        let mut tr = Mem::new(id);
        // one-byte write to place buffer on device and ensure
        // allocated memory is okay
        let _ = try!(self.write_buffer_raw(&mut tr,
                                           0,
                                           1,
                                           &[self]));
        Ok(tr)
    }

    pub fn write_buffer<'a, 'b, T: Sized + 'a>(self: &Self,
                                  mem: &'b mut Mem,
                                  slice: &'a [T]) -> Result<ReadLock<'a, T>, Error> {
        let size_bytes = size_of::<T>()*slice.len();
        let evt = try!(self.write_buffer_raw(mem,
                                             0,
                                             size_bytes,
                                             slice));
        Ok(ReadLock{ evt: evt, sl: slice })
    }

    pub fn read_buffer<'a, T: Sized>(self: &Self,
                                 mem: &Mem,
                                 slice: &'a mut [T]) -> Result<WriteLock<'a, T>, Error> {
        let size_bytes = size_of::<T>()*slice.len();
        let evt = try!(self.read_buffer_raw(mem,
                                            0,
                                            size_bytes,
                                            slice));
        Ok(WriteLock{ evt: evt, sl: slice })
    }

    fn next_mul(self: &Self, global: usize, local: usize) -> usize {
        if global % local == 0 {
            global
        } else {
            ((global/local)+1)*local
        }
    }

    pub fn run( self: &Self,
                kernel: &mut Kernel,
                local_size: (usize, usize, usize),
                global_size: (usize, usize, usize)) -> Result<Event, Error> {
        let events = kernel.run_events();
        let global_size_fixed = (self.next_mul(global_size.0, local_size.0),
                                self.next_mul(global_size.1, local_size.1),
                                self.next_mul(global_size.2, local_size.2));

        let local_vec = vec!(local_size.0 as size_t,
                             local_size.1 as size_t,
                             local_size.2 as size_t);
        let global_vec = vec!(global_size_fixed.0 as size_t,
                              global_size_fixed.1 as size_t,
                              global_size_fixed.2 as size_t);

        let mut event_id: ll::Event = ptr::null_mut();
        unsafe {
            try!(Error::check(ll::clEnqueueNDRangeKernel(self.id,
                                                         kernel.id,
                                                         3,
                                                         ptr::null(),
                                                         &global_vec[0],
                                                         &local_vec[0],
                                                         events.len() as u32,
                                                         &events[0],
                                                         &mut event_id)));
        }
        let event = Event{id: event_id};

        try!(kernel.register_run(event.clone()));
        Ok(event)
    }
}

impl Drop for CommandQueue {
    fn drop(self: &mut Self) -> () {
        unsafe {
            Error::check(ll::clReleaseCommandQueue(self.id))
                .ok().expect("Error releasing command queue");
        }
    }
}

impl Clone for CommandQueue {
    fn clone(self: &Self) -> Self {
        unsafe {
            Error::check(ll::clRetainCommandQueue(self.id))
                .ok().expect("Error retaining command queue");
        }
        CommandQueue{ id: self.id }
    }
}

<|endoftext|>


<commit_before>use libc::{uint64_t, int64_t, c_void, c_char, c_double};
use std::ffi::CString;
use std::ptr;
use energymon_sys::energymon::EnergyMon;

#[link(name = "hbt-acc-pow")]
extern {
    fn heartbeat_acc_pow_init(parent: *mut c_void,
                              window_size: uint64_t,
                              buffer_depth: uint64_t,
                              log_name: *const c_char,
                              num_energy_impls: uint64_t,
                              energy_impls: *mut EnergyMon) -> *mut c_void;

    fn heartbeat_acc(hb: *mut c_void,
                     user_tag: uint64_t,
                     work: uint64_t,
                     accuracy: c_double,
                     hb_prev: *mut c_void) -> int64_t;

    fn heartbeat_finish(hb: *mut c_void);

    fn hb_get_user_tag(hb: *const c_void) -> uint64_t;

    fn hb_get_window_rate(hb: *const c_void) -> c_double;

    fn hb_get_window_power(hb: *const c_void) -> c_double;
}

pub struct Heartbeat {
    pub hb: *mut c_void,
}

impl Heartbeat {
    pub fn new(parent: Option<&mut Heartbeat>,
               window_size: u64,
               buffer_depth: u64,
               log_name: &str,
               energy_impl: Option<&mut EnergyMon>) -> Result<Heartbeat, String> {
        let parent = match parent {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        let num_energy_impls: u64;
        let mut em: *mut EnergyMon;
        if energy_impl.is_some() {
            num_energy_impls = 1;
            em = energy_impl.unwrap();
        } else {
            num_energy_impls = 0;
            em = ptr::null_mut();
        }
        let heart = unsafe {
            heartbeat_acc_pow_init(parent, window_size, buffer_depth,
                                   CString::new(log_name).unwrap().as_ptr(),
                                   num_energy_impls, em)
        };
        if heart.is_null() {
            return Err("Failed to initialize heartbeat".to_string());
        }
        Ok(Heartbeat { hb: heart, })
    }

    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     accuracy: f64,
                     hb_prev: Option<&Heartbeat>) -> i64 {
        let hb_prev = match hb_prev {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        unsafe {
            heartbeat_acc(self.hb, tag, work, accuracy, hb_prev)
        }
    }

    pub fn get_tag(&mut self) -> u64 {
        unsafe {
            hb_get_user_tag(self.hb)
        }
    }

    pub fn get_window_perf(&mut self) -> f64 {
        unsafe {
            hb_get_window_rate(self.hb)
        }
    }

    pub fn get_window_pwr(&mut self) -> f64 {
        unsafe {
            hb_get_window_power(self.hb)
        }
    }
}

impl Drop for Heartbeat {
    fn drop(&mut self) {
        unsafe {
            heartbeat_finish(self.hb);
        }
    }
}

#[test]
fn test_no_energymon() {
    let mut hb = Heartbeat::new(None, 20, 20, "heartbeat.log", None).unwrap();
    hb.heartbeat(0, 1, 0.0, None);
}
<commit_msg>log file name is now an Option<commit_after>use libc::{uint64_t, int64_t, c_void, c_char, c_double};
use std::ffi::CString;
use std::ptr;
use energymon_sys::energymon::EnergyMon;

#[link(name = "hbt-acc-pow")]
extern {
    fn heartbeat_acc_pow_init(parent: *mut c_void,
                              window_size: uint64_t,
                              buffer_depth: uint64_t,
                              log_name: *const c_char,
                              num_energy_impls: uint64_t,
                              energy_impls: *mut EnergyMon) -> *mut c_void;

    fn heartbeat_acc(hb: *mut c_void,
                     user_tag: uint64_t,
                     work: uint64_t,
                     accuracy: c_double,
                     hb_prev: *mut c_void) -> int64_t;

    fn heartbeat_finish(hb: *mut c_void);

    fn hb_get_user_tag(hb: *const c_void) -> uint64_t;

    fn hb_get_window_rate(hb: *const c_void) -> c_double;

    fn hb_get_window_power(hb: *const c_void) -> c_double;
}

pub struct Heartbeat {
    pub hb: *mut c_void,
}

impl Heartbeat {
    pub fn new(parent: Option<&mut Heartbeat>,
               window_size: u64,
               buffer_depth: u64,
               log_name: Option<&str>,
               energy_impl: Option<&mut EnergyMon>) -> Result<Heartbeat, String> {
        let parent = match parent {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        let log_name = match log_name {
          Some(n) => CString::new(n).unwrap().as_ptr(),
          None => ptr::null(),
        };
        let num_energy_impls: u64;
        let mut em: *mut EnergyMon;
        if energy_impl.is_some() {
            num_energy_impls = 1;
            em = energy_impl.unwrap();
        } else {
            num_energy_impls = 0;
            em = ptr::null_mut();
        }
        let heart = unsafe {
            heartbeat_acc_pow_init(parent, window_size, buffer_depth, log_name,
                                   num_energy_impls, em)
        };
        if heart.is_null() {
            return Err("Failed to initialize heartbeat".to_string());
        }
        Ok(Heartbeat { hb: heart, })
    }

    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     accuracy: f64,
                     hb_prev: Option<&Heartbeat>) -> i64 {
        let hb_prev = match hb_prev {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        unsafe {
            heartbeat_acc(self.hb, tag, work, accuracy, hb_prev)
        }
    }

    pub fn get_tag(&mut self) -> u64 {
        unsafe {
            hb_get_user_tag(self.hb)
        }
    }

    pub fn get_window_perf(&mut self) -> f64 {
        unsafe {
            hb_get_window_rate(self.hb)
        }
    }

    pub fn get_window_pwr(&mut self) -> f64 {
        unsafe {
            hb_get_window_power(self.hb)
        }
    }
}

impl Drop for Heartbeat {
    fn drop(&mut self) {
        unsafe {
            heartbeat_finish(self.hb);
        }
    }
}

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

    #[test]
    fn test_no_energymon() {
        let mut hb = Heartbeat::new(None, 20, 20, None, None).unwrap();
        hb.heartbeat(0, 1, 0.0, None);
    }
}
<|endoftext|>


<commit_before>use std::fmt::{Debug, Formatter, Error};
use std::path::Path;

use config::reader::from_file;
use config::types::Config as Cfg;
use cli::CliConfig;

/**
 * Configuration object which represents the configuration file.
 *
 * It gets passed a CliConfig object on ::new(), retreives some data from this one which is then
 * provided as default value to the callee if there is no value for it in the configuration.
 *
 * TODO: Setup is kinda ugly, as we re-use data from the CLI, which is the job of the Runtime
 * object later.
 */
pub struct Configuration {
    pub rtp         : String,
    pub store_sub   : String,
    pub verbose     : bool,
    pub debugging   : bool,
    pub editor      : Option<String>,
    pub editor_opts : String,
}

impl Configuration {

    pub fn new(config: &CliConfig) -> Configuration {
        let rtp = rtp_path(config).or(default_path());

        let mut verbose     = false;
        let mut debugging   = false;
        let mut store_sub   = String::from("/store");
        let mut editor      = None;
        let mut editor_opts = String::from("");

        if let Some(cfg) = fetch_config(rtp.clone()) {
            if let Some(v) = cfg.lookup_boolean("verbose") {
                verbose = v;
            }
            if let Some(d) = cfg.lookup_boolean("debug") {
                debugging = d;
            }
            if let Some(s) = cfg.lookup_str("store") {
                store_sub = String::from(s);
            }
            if let Some(s) = cfg.lookup_str("editor") {
                editor = Some(String::from(s));
            }
            if let Some(s) = cfg.lookup_str("editor-opts") {
                editor_opts = String::from(s);
            }
        }

        let runtimepath = rtp.unwrap_or(String::from("/tmp/"));

        debug!("Building configuration");
        debug!("  - verbose    : {}", verbose);
        debug!("  - debugging  : {}", debugging);
        debug!("  - store sub  : {}", store_sub);
        debug!("  - runtimepath: {}", runtimepath);
        debug!("  - editor     : {:?}", editor);
        debug!("  - editor-opts: {}", editor_opts);

        Configuration {
            verbose: verbose,
            debugging: debugging,
            store_sub: store_sub,
            rtp: runtimepath,
            editor: editor,
            editor_opts: editor_opts,
        }
    }

    /**
     * Check whether the configuration says we should run verbose
     */
    pub fn is_verbose(&self) -> bool {
        self.verbose
    }

    /**
     * Check whether the configuration says we should run in debugging
     */
    pub fn is_debugging(&self) -> bool {
        self.debugging
    }

    /**
     * Get the store path the configuration configured
     */
    pub fn store_path(&self) -> String {
        format!("{}{}", self.rtp, self.store_sub)
    }

    /**
     * Get the runtime path the configuration configured
     */
    pub fn get_rtp(&self) -> String {
        self.rtp.clone()
    }

    pub fn editor(&self) -> Option<String> {
        self.editor.clone()
    }

    pub fn editor_opts(&self) -> &String {
        &self.editor_opts
    }

}

/**
 * Helper to get the runtimepath from the CLI
 */
fn rtp_path(config: &CliConfig) -> Option<String> {
    config.cli_matches.value_of("rtp")
                      .and_then(|s| Some(String::from(s)))
}

fn fetch_config(rtp: Option<String>) -> Option<Cfg> {
    rtp.and_then(|r| from_file(Path::new(&(r.clone() + "/config"))).ok())
}

/**
 * Default runtime path, if available.
 */
fn default_path() -> Option<String> {
    use std::env::home_dir;

    home_dir().and_then(|mut buf| {
        buf.push("/.imag");
        buf.to_str().map(|s| String::from(s))
    })

}

impl Debug for Configuration {

    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "Configuration (verbose: {}, debugging: {}, rtp: {}, store path: {})",
            self.is_verbose(),
            self.is_debugging(),
            self.get_rtp(),
            self.store_path()
            )
    }

}

<commit_msg>Refactor configuration: Simplify codebase<commit_after>use std::fmt::{Debug, Formatter, Error};
use std::path::Path;

use config::reader::from_file;
use config::types::Config as Cfg;
use cli::CliConfig;

/**
 * Configuration object which represents the configuration file.
 *
 * It gets passed a CliConfig object on ::new(), retreives some data from this one which is then
 * provided as default value to the callee if there is no value for it in the configuration.
 *
 * TODO: Setup is kinda ugly, as we re-use data from the CLI, which is the job of the Runtime
 * object later.
 */
pub struct Configuration {
    pub rtp         : String,
    pub store_sub   : String,
    pub verbose     : bool,
    pub debugging   : bool,
    pub editor      : Option<String>,
    pub editor_opts : String,
}

impl Configuration {

    pub fn new(config: &CliConfig) -> Configuration {
        let rtp = rtp_path(config).or(default_path()).unwrap_or(String::from("/tmp/"));

        let cfg = fetch_config(&rtp);

        let verbose     = cfg.lookup_boolean("verbose").unwrap_or(false);
        let debugging   = cfg.lookup_boolean("debug").unwrap_or(false);
        let store_sub   = String::from(cfg.lookup_str("store").unwrap_or("/store"));
        let editor      = cfg.lookup_str("editor").map(String::from);
        let editor_opts = String::from(cfg.lookup_str("editor-opts").unwrap_or(""));

        debug!("Building configuration");
        debug!("  - verbose    : {}", verbose);
        debug!("  - debugging  : {}", debugging);
        debug!("  - store sub  : {}", store_sub);
        debug!("  - runtimepath: {}", rtp);
        debug!("  - editor     : {:?}", editor);
        debug!("  - editor-opts: {}", editor_opts);

        Configuration {
            verbose: verbose,
            debugging: debugging,
            store_sub: store_sub,
            rtp: rtp,
            editor: editor,
            editor_opts: editor_opts,
        }
    }

    /**
     * Check whether the configuration says we should run verbose
     */
    pub fn is_verbose(&self) -> bool {
        self.verbose
    }

    /**
     * Check whether the configuration says we should run in debugging
     */
    pub fn is_debugging(&self) -> bool {
        self.debugging
    }

    /**
     * Get the store path the configuration configured
     */
    pub fn store_path(&self) -> String {
        format!("{}{}", self.rtp, self.store_sub)
    }

    /**
     * Get the runtime path the configuration configured
     */
    pub fn get_rtp(&self) -> String {
        self.rtp.clone()
    }

    pub fn editor(&self) -> Option<String> {
        self.editor.clone()
    }

    pub fn editor_opts(&self) -> &String {
        &self.editor_opts
    }

}

/**
 * Helper to get the runtimepath from the CLI
 */
fn rtp_path(config: &CliConfig) -> Option<String> {
    config.cli_matches.value_of("rtp")
                      .and_then(|s| Some(String::from(s)))
}

fn fetch_config(rtp: &String) -> Cfg {
    use std::process::exit;

    let configpath = format!("{}{}", rtp, "/config");
    from_file(Path::new(&configpath)).map_err(|e| {
        println!("Error loading config at '{}' -> {:?}", configpath, e);
        println!("Exiting now.");
        exit(1)
    }).unwrap()
}

/**
 * Default runtime path, if available.
 */
fn default_path() -> Option<String> {
    use std::env::home_dir;

    home_dir().and_then(|mut buf| {
        buf.push("/.imag");
        buf.to_str().map(|s| String::from(s))
    })

}

impl Debug for Configuration {

    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "Configuration (verbose: {}, debugging: {}, rtp: {}, store path: {})",
            self.is_verbose(),
            self.is_debugging(),
            self.get_rtp(),
            self.store_path()
            )
    }

}

<|endoftext|>