<commit_before>#![feature(collections)]
extern crate ferrous_threads;
use ferrous_threads::TaskPool;
use std::sync::mpsc::{Sender, Receiver, channel};
use std::collections::BitVec;

// http://home.math.au.dk/himsen/Project1_parallel_algorithms_Torben.pdf

fn main() {
    parallel_sieve(100, 10);
    let vec = sequential_sieve(100);
    println!("# of Primes: {}", vec.len());
}

fn sequential_sieve(n: usize) -> Vec<usize> {
    let mut n_array = BitVec::from_elem(n+1, true);
    let mut primes = Vec::new();
    let sqrt_n = (n as f64).sqrt() as usize + 1;

    for i in (2..sqrt_n) {
        if !n_array.get(i).unwrap() {
            continue
        }

        primes.push(i);

        // We can start from i^2 because every composite smaller is already marked.
        let mut p = i * i;
        while p <= n {
            n_array.set(p, false);
            p = p + i;
        }
    }

    for i in ((sqrt_n)..n) {
        if n_array.get(i).unwrap() {
            primes.push(i);
        }
    }

    primes
}

fn parallel_sieve(n: usize, num_threads: u8) {
    let pool = TaskPool::new(num_threads);
    let (sn_primes, accum_primes) = channel::<Option<usize>>();

    let sqrt_n = (n as f64).sqrt() as usize + 1;

    // Ensure that the first worker has indexes from o..sqrt_n
    // Try and avoid overflow in max_workers by casting num_threads to usize instead.
    let max_workers = n / (sqrt_n + 1);
    let num_workers = if (num_threads as usize) < max_workers { num_threads as usize } else { max_workers };
    let num_workers = num_workers as u8;

    let mut sn_sieves = Vec::new();
    let mut rc_sieves = Vec::new();
    for _i in (1..num_workers) {
        let (sn, rc) = channel::<Option<usize>>();
        sn_sieves.push(sn);
        rc_sieves.push(rc);
    }

    let sn_p = sn_primes.clone();
    pool.enqueue(move || { sieve_master(n, num_workers, sn_sieves, sn_p) }).ok().expect("Could not enqueue task.");

    for (i, rc) in rc_sieves.into_iter().enumerate()  {
        let id = i as u8 + 1;
        let sn_p = sn_primes.clone();
        pool.enqueue(move || { sieve_worker(n, num_workers, id, rc, sn_p) }).ok().expect("Could not enqueue task.");
    }
    pool.enqueue(move || { prime_collector(num_workers, accum_primes) }).ok().expect("Could not enqueue task.");
}

fn sieve_master(n: usize, n_threads: u8, sn_sieves: Vec<Sender<Option<usize>>>, sn_primes: Sender<Option<usize>>) {
    let id = 0;
    let (_l, right) = bit_vec_endpoints(n, n_threads, id);
    // Start from 2.
    let left = 2;
    let mut sieve_vec = BitVec::from_elem(right - left + 1, true);
    let len = sieve_vec.len();
    for i in (0..len) {
        if sieve_vec.get(i).unwrap() {
            let prime = left + i;
            send_prime_to_workers(prime, &sn_sieves);
            sieve_vector(&mut sieve_vec, id, prime, left, right);
        }
    }

    stop_workers(&sn_sieves);
    send_primes_to_collector(&mut sieve_vec, left, &sn_primes)
}

fn send_primes_to_collector(vec: &BitVec, left: usize, sn_primes: &Sender<Option<usize>>) {
    for (i, prime) in vec.iter().enumerate() {
        if prime {
            let prime = left + i;
            assert!(sn_primes.send(Some(prime)).is_ok());
        }
    }
    assert!(sn_primes.send(None).is_ok());
}

fn stop_workers(sn_sieves: &Vec<Sender<Option<usize>>>) {
    for sn in sn_sieves.iter() {
        assert!(sn.send(None).is_ok());
    }
}

fn send_prime_to_workers(p: usize, sn_sieves: &Vec<Sender<Option<usize>>>) {
    for sn in sn_sieves.iter() {
        assert!(sn.send(Some(p)).is_ok());
    }
}

// Each worker holds indices from (id * (n / n_threads)) to ((id + 1) * (n / n_threads) - 1)
// This will change when/if we use the easy reduction of only considering odd numbers.
fn sieve_worker(n: usize, n_threads: u8, id: u8, rc_sieve: Receiver<Option<usize>>, sn_primes: Sender<Option<usize>>) {
    let (left, right) = bit_vec_endpoints(n, n_threads, id);
    let mut sieve_vec = BitVec::from_elem(right - left + 1, true);

    loop {
        let sieve_num = match rc_sieve.recv() {
            Ok(Some(num)) => num,
            Ok(None) => break,
            Err(ref e)  => panic!("{}", e),
        };

        sieve_vector(&mut sieve_vec, id, sieve_num, left, right);
    }

    send_primes_to_collector(&mut sieve_vec, left, &sn_primes)
}

fn sieve_vector(vec: &mut BitVec, id: u8, sieve_num: usize, left: usize, right: usize) {
    let offset = calc_prime_offset(sieve_num, left, right);
    if offset == -1 {
        return
    }

    let mut offset = offset as usize;

    if id == 0 {
        offset = offset + sieve_num;
    }

    let len = vec.len();
    while offset < len {
        vec.set(offset, false);
        offset = offset + sieve_num;
    }
}

fn bit_vec_endpoints(n: usize, n_threads: u8, id: u8) -> (usize, usize) {
    let i = id as usize;
    let t = n_threads as usize;
    let left_endpt = (i * n) / t;
    let right_endpt = (((i + 1) * n) / t) - 1;
    (left_endpt, right_endpt)
}

fn calc_prime_offset(prime: usize, left: usize, right: usize) -> isize {
    if left % prime == 0 {
        return 0
    }

    let res = prime - (left % prime);
    if res + left > right {
        return -1
    }

    res as isize
}

fn prime_collector(num_thrs: u8, rc_primes: Receiver<Option<usize>>) {
    let mut primes = Vec::new();
    let mut num_done = 0;

    loop {
        if num_done == num_thrs {
            break
        }

        match rc_primes.recv() {
            Ok(Some(p)) => primes.push(p),
            Ok(None) => {
                num_done = num_done + 1;
            },
            Err(ref e) => panic!("{:?}", e),
        }
    }
    println!("# of Primes: {}", primes.len());
}
<commit_msg>Make example take in an argument to specify sequential or parallel.<commit_after>#![feature(collections)]
extern crate ferrous_threads;
use ferrous_threads::TaskPool;
use std::sync::mpsc::{Sender, Receiver, channel};
use std::collections::BitVec;
use std::env;

// http://home.math.au.dk/himsen/Project1_parallel_algorithms_Torben.pdf

fn main() {
    let mut args = env::args();
    if args.len() != 2 {
        println!("Must specify either 'parallel' or 'sequential'");
        return
    }

    let arg = args.nth(1).unwrap();
    if arg == String::from_str("parallel") {
        parallel_sieve(100_000_000, 10);
    } else if arg == String::from_str("sequential") {

        let vec = sequential_sieve(100_000_000);
        println!("# of Primes: {}", vec.len());
    } else {
        println!("Must specify either 'parallel' or 'sequential'");
    }
}

fn sequential_sieve(n: usize) -> Vec<usize> {
    let mut n_array = BitVec::from_elem(n+1, true);
    let mut primes = Vec::new();
    let sqrt_n = (n as f64).sqrt() as usize + 1;

    for i in (2..sqrt_n) {
        if !n_array.get(i).unwrap() {
            continue
        }

        primes.push(i);

        // We can start from i^2 because every composite smaller is already marked.
        let mut p = i * i;
        while p <= n {
            n_array.set(p, false);
            p = p + i;
        }
    }

    for i in ((sqrt_n)..n) {
        if n_array.get(i).unwrap() {
            primes.push(i);
        }
    }

    primes
}

fn parallel_sieve(n: usize, num_threads: u8) {
    let pool = TaskPool::new(num_threads);
    let (sn_primes, accum_primes) = channel::<Option<usize>>();

    let sqrt_n = (n as f64).sqrt() as usize + 1;

    // Ensure that the first worker has indexes from o..sqrt_n
    // Try and avoid overflow in max_workers by casting num_threads to usize instead.
    let max_workers = n / (sqrt_n + 1);
    let num_workers = if (num_threads as usize) < max_workers { num_threads as usize } else { max_workers };
    let num_workers = num_workers as u8;

    let mut sn_sieves = Vec::new();
    let mut rc_sieves = Vec::new();
    for _i in (1..num_workers) {
        let (sn, rc) = channel::<Option<usize>>();
        sn_sieves.push(sn);
        rc_sieves.push(rc);
    }

    let sn_p = sn_primes.clone();
    pool.enqueue(move || { sieve_master(n, num_workers, sn_sieves, sn_p) }).ok().expect("Could not enqueue task.");

    for (i, rc) in rc_sieves.into_iter().enumerate()  {
        let id = i as u8 + 1;
        let sn_p = sn_primes.clone();
        pool.enqueue(move || { sieve_worker(n, num_workers, id, rc, sn_p) }).ok().expect("Could not enqueue task.");
    }
    pool.enqueue(move || { prime_collector(num_workers, accum_primes) }).ok().expect("Could not enqueue task.");
}

fn sieve_master(n: usize, n_threads: u8, sn_sieves: Vec<Sender<Option<usize>>>, sn_primes: Sender<Option<usize>>) {
    let id = 0;
    let (_l, right) = bit_vec_endpoints(n, n_threads, id);
    // Start from 2.
    let left = 2;
    let mut sieve_vec = BitVec::from_elem(right - left + 1, true);
    let len = sieve_vec.len();
    for i in (0..len) {
        if sieve_vec.get(i).unwrap() {
            let prime = left + i;
            send_prime_to_workers(prime, &sn_sieves);
            sieve_vector(&mut sieve_vec, id, prime, left, right);
        }
    }

    stop_workers(&sn_sieves);
    send_primes_to_collector(&mut sieve_vec, left, &sn_primes)
}

fn send_primes_to_collector(vec: &BitVec, left: usize, sn_primes: &Sender<Option<usize>>) {
    for (i, prime) in vec.iter().enumerate() {
        if prime {
            let prime = left + i;
            assert!(sn_primes.send(Some(prime)).is_ok());
        }
    }
    assert!(sn_primes.send(None).is_ok());
}

fn stop_workers(sn_sieves: &Vec<Sender<Option<usize>>>) {
    for sn in sn_sieves.iter() {
        assert!(sn.send(None).is_ok());
    }
}

fn send_prime_to_workers(p: usize, sn_sieves: &Vec<Sender<Option<usize>>>) {
    for sn in sn_sieves.iter() {
        assert!(sn.send(Some(p)).is_ok());
    }
}

// Each worker holds indices from (id * (n / n_threads)) to ((id + 1) * (n / n_threads) - 1)
// This will change when/if we use the easy reduction of only considering odd numbers.
fn sieve_worker(n: usize, n_threads: u8, id: u8, rc_sieve: Receiver<Option<usize>>, sn_primes: Sender<Option<usize>>) {
    let (left, right) = bit_vec_endpoints(n, n_threads, id);
    let mut sieve_vec = BitVec::from_elem(right - left + 1, true);

    loop {
        let sieve_num = match rc_sieve.recv() {
            Ok(Some(num)) => num,
            Ok(None) => break,
            Err(ref e)  => panic!("{}", e),
        };

        sieve_vector(&mut sieve_vec, id, sieve_num, left, right);
    }

    send_primes_to_collector(&mut sieve_vec, left, &sn_primes)
}

fn sieve_vector(vec: &mut BitVec, id: u8, sieve_num: usize, left: usize, right: usize) {
    let offset = calc_prime_offset(sieve_num, left, right);
    if offset == -1 {
        return
    }

    let mut offset = offset as usize;

    if id == 0 {
        offset = offset + sieve_num;
    }

    let len = vec.len();
    while offset < len {
        vec.set(offset, false);
        offset = offset + sieve_num;
    }
}

fn bit_vec_endpoints(n: usize, n_threads: u8, id: u8) -> (usize, usize) {
    let i = id as usize;
    let t = n_threads as usize;
    let left_endpt = (i * n) / t;
    let right_endpt = (((i + 1) * n) / t) - 1;
    (left_endpt, right_endpt)
}

fn calc_prime_offset(prime: usize, left: usize, right: usize) -> isize {
    if left % prime == 0 {
        return 0
    }

    let res = prime - (left % prime);
    if res + left > right {
        return -1
    }

    res as isize
}

fn prime_collector(num_thrs: u8, rc_primes: Receiver<Option<usize>>) {
    let mut primes = Vec::new();
    let mut num_done = 0;

    loop {
        if num_done == num_thrs {
            break
        }

        match rc_primes.recv() {
            Ok(Some(p)) => primes.push(p),
            Ok(None) => {
                num_done = num_done + 1;
            },
            Err(ref e) => panic!("{:?}", e),
        }
    }
    println!("# of Primes: {}", primes.len());
}
<|endoftext|>


<commit_before>#[crate_id(name="cat", vers="1.0.0", author="Seldaek")];
#[feature(managed_boxes)];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern crate getopts;

use std::os;
use std::io::{print, stdin, stdout, File};

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        getopts::optflag("A", "show-all", "equivalent to -vET"),
        getopts::optflag("b", "number-nonblank", "number nonempty output lines, overrides -n"),
        getopts::optflag("e", "", "equivalent to -vE"),
        getopts::optflag("E", "show-ends", "display $ at end of each line"),
        getopts::optflag("n", "number", "number all output lines"),
        getopts::optflag("s", "squeeze-blank", "suppress repeated empty output lines"),
        getopts::optflag("t", "", "equivalent to -vT"),
        getopts::optflag("T", "show-tabs", "display TAB characters as ^I"),
        getopts::optflag("v", "show-nonprinting", "use ^ and M- notation, except for LF (\\n) and TAB (\\t)"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => fail!("Invalid options\n{}", f.to_err_msg())
    };
    if matches.opt_present("help") {
        println!("cat 1.0.0");
        println!("");
        println!("Usage:");
        println!("  {0:s} [OPTION]... [FILE]...", program);
        println!("");
        print(getopts::usage("Concatenate FILE(s), or standard input, to standard output.", opts));
        println!("");
        println!("With no FILE, or when FILE is -, read standard input.");
        return;
    }
    if matches.opt_present("version") {
        println!("cat 1.0.0");
        return;
    }

    let mut number_mode = NumberNone;
    if matches.opt_present("number") {
        number_mode = NumberAll;
    }
    if matches.opt_present("number-nonblank") {
        number_mode = NumberNonEmpty;
    }
    let show_nonprint = matches.opts_present([~"show-nonprinting", ~"show-all", ~"t", ~"e"]);
    let show_ends = matches.opts_present([~"show-ends", ~"show-all", ~"e"]);
    let show_tabs = matches.opts_present([~"show-tabs",  ~"show-all", ~"t"]);
    let squeeze_blank = matches.opt_present("squeeze-blank");
    let mut files = matches.free;
    if files.is_empty() {
        files = ~[~"-"];
    }

    exec(files, number_mode, show_nonprint, show_ends, show_tabs, squeeze_blank);
}

#[deriving(Eq)]
pub enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

static TAB: u8 = '\t' as u8;
#[allow(dead_code)]
static CR: u8 = '\r' as u8;
static LF: u8 = '\n' as u8;

#[cfg(windows)]
fn is_newline_char(byte: u8) -> bool {
    byte == LF || byte == CR
}

#[cfg(unix)]
fn is_newline_char(byte: u8) -> bool {
    byte == LF
}

pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_ends: bool, show_tabs: bool, squeeze_blank: bool) {
    let mut writer = stdout();

    if NumberNone != number || show_nonprint || show_ends || show_tabs || squeeze_blank {
        let mut counter: uint = 1;
        let is_numbering = number == NumberAll || number == NumberNonEmpty;

        for path in files.iter() {
            let mut reader = match open(path.to_owned()) {
                Some(f) => f,
                None => { continue }
            };

            let mut at_line_start = true;
            let mut buf = [0, .. 2];
            loop {
                // reading from a TTY seems to raise a condition on
                // EOF, rather than return Some(0) like a file.
                match reader.read(buf) {
                    Ok(n) if n != 0 => {
                        for byte in buf.slice_to(n).iter() {
                            if at_line_start && (number == NumberAll || (number == NumberNonEmpty && !is_newline_char(*byte))) {
                                match write!(&mut writer as &mut Writer, "{0:6u}\t", counter) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                                counter += 1;
                                at_line_start = false;
                            }
                            if is_numbering && *byte == LF {
                                at_line_start = true;
                            }
                            if show_tabs && *byte == TAB {
                                match writer.write(bytes!("^I")) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                            } else if show_ends && *byte == LF {
                                match writer.write(bytes!("$\n")) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                            } else if show_nonprint && (*byte < 32 || *byte >= 127) && !is_newline_char(*byte) {
                                let mut byte = *byte;
                                if byte >= 128 {
                                    match writer.write(bytes!("M-")) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                    byte = byte - 128;
                                }
                                if byte < 32 {
                                    match writer.write(['^' as u8, byte + 64]) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                } else if byte == 127 {
                                    match writer.write(['^' as u8, byte - 64]) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                } else {
                                    match writer.write([byte]) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                }
                            } else {
                                match writer.write([*byte]) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                            }
                        }
                    },
                    _ => break
                }
            }
        }
        return;
    }

    let mut buf = [0, .. 100000];
    // passthru mode
    for path in files.iter() {
        let mut reader = match open(path.to_owned()) {
            Some(f) => f,
            None => { continue }
        };

        loop {
            // reading from a TTY seems to raise a condition on EOF,
            // rather than return Some(0) like a file.
            match reader.read(buf) {
                Ok(n) if n != 0 => {
                    match writer.write(buf.slice_to(n)) {
                        Ok(_) => (), Err(err) => fail!("{}", err)
                    }
                }, _ => break
            }
        }
    }
}

fn open(path: ~str) -> Option<~Reader> {
    if "-" == path {
        return Some(~stdin() as ~Reader);
    }

    match File::open(&std::path::Path::new(path.as_slice())) {
        Ok(fd) => return Some(~fd as ~Reader),
        Err(e) => fail!("cat: {0:s}: {1:s}", path, e.to_str())
    }
}
/* vim: set ai ts=4 sw=4 sts=4 et : */
<commit_msg>Use raw stdin/stdio.<commit_after>#[crate_id(name="cat", vers="1.0.0", author="Seldaek")];
#[feature(managed_boxes)];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern crate getopts;

use std::os;
use std::io::{print, File};
use std::io::stdio::{stdout_raw, stdin_raw};

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        getopts::optflag("A", "show-all", "equivalent to -vET"),
        getopts::optflag("b", "number-nonblank", "number nonempty output lines, overrides -n"),
        getopts::optflag("e", "", "equivalent to -vE"),
        getopts::optflag("E", "show-ends", "display $ at end of each line"),
        getopts::optflag("n", "number", "number all output lines"),
        getopts::optflag("s", "squeeze-blank", "suppress repeated empty output lines"),
        getopts::optflag("t", "", "equivalent to -vT"),
        getopts::optflag("T", "show-tabs", "display TAB characters as ^I"),
        getopts::optflag("v", "show-nonprinting", "use ^ and M- notation, except for LF (\\n) and TAB (\\t)"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => fail!("Invalid options\n{}", f.to_err_msg())
    };
    if matches.opt_present("help") {
        println!("cat 1.0.0");
        println!("");
        println!("Usage:");
        println!("  {0:s} [OPTION]... [FILE]...", program);
        println!("");
        print(getopts::usage("Concatenate FILE(s), or standard input, to standard output.", opts));
        println!("");
        println!("With no FILE, or when FILE is -, read standard input.");
        return;
    }
    if matches.opt_present("version") {
        println!("cat 1.0.0");
        return;
    }

    let mut number_mode = NumberNone;
    if matches.opt_present("number") {
        number_mode = NumberAll;
    }
    if matches.opt_present("number-nonblank") {
        number_mode = NumberNonEmpty;
    }
    let show_nonprint = matches.opts_present([~"show-nonprinting", ~"show-all", ~"t", ~"e"]);
    let show_ends = matches.opts_present([~"show-ends", ~"show-all", ~"e"]);
    let show_tabs = matches.opts_present([~"show-tabs",  ~"show-all", ~"t"]);
    let squeeze_blank = matches.opt_present("squeeze-blank");
    let mut files = matches.free;
    if files.is_empty() {
        files = ~[~"-"];
    }

    exec(files, number_mode, show_nonprint, show_ends, show_tabs, squeeze_blank);
}

#[deriving(Eq)]
pub enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

static TAB: u8 = '\t' as u8;
#[allow(dead_code)]
static CR: u8 = '\r' as u8;
static LF: u8 = '\n' as u8;

#[cfg(windows)]
fn is_newline_char(byte: u8) -> bool {
    byte == LF || byte == CR
}

#[cfg(unix)]
fn is_newline_char(byte: u8) -> bool {
    byte == LF
}

pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_ends: bool, show_tabs: bool, squeeze_blank: bool) {
    let mut writer = stdout_raw();

    if NumberNone != number || show_nonprint || show_ends || show_tabs || squeeze_blank {
        let mut counter: uint = 1;
        let is_numbering = number == NumberAll || number == NumberNonEmpty;

        for path in files.iter() {
            let mut reader = match open(path.to_owned()) {
                Some(f) => f,
                None => { continue }
            };

            let mut at_line_start = true;
            let mut buf = [0, .. 2];
            loop {
                // reading from a TTY seems to raise a condition on
                // EOF, rather than return Some(0) like a file.
                match reader.read(buf) {
                    Ok(n) if n != 0 => {
                        for byte in buf.slice_to(n).iter() {
                            if at_line_start && (number == NumberAll || (number == NumberNonEmpty && !is_newline_char(*byte))) {
                                match write!(&mut writer as &mut Writer, "{0:6u}\t", counter) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                                counter += 1;
                                at_line_start = false;
                            }
                            if is_numbering && *byte == LF {
                                at_line_start = true;
                            }
                            if show_tabs && *byte == TAB {
                                match writer.write(bytes!("^I")) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                            } else if show_ends && *byte == LF {
                                match writer.write(bytes!("$\n")) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                            } else if show_nonprint && (*byte < 32 || *byte >= 127) && !is_newline_char(*byte) {
                                let mut byte = *byte;
                                if byte >= 128 {
                                    match writer.write(bytes!("M-")) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                    byte = byte - 128;
                                }
                                if byte < 32 {
                                    match writer.write(['^' as u8, byte + 64]) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                } else if byte == 127 {
                                    match writer.write(['^' as u8, byte - 64]) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                } else {
                                    match writer.write([byte]) {
                                        Ok(_) => (), Err(err) => fail!("{}", err)
                                    };
                                }
                            } else {
                                match writer.write([*byte]) {
                                    Ok(_) => (), Err(err) => fail!("{}", err)
                                };
                            }
                        }
                    },
                    _ => break
                }
            }
        }
        return;
    }

    let mut buf = [0, .. 100000];
    // passthru mode
    for path in files.iter() {
        let mut reader = match open(path.to_owned()) {
            Some(f) => f,
            None => { continue }
        };

        loop {
            // reading from a TTY seems to raise a condition on EOF,
            // rather than return Some(0) like a file.
            match reader.read(buf) {
                Ok(n) if n != 0 => {
                    match writer.write(buf.slice_to(n)) {
                        Ok(_) => (), Err(err) => fail!("{}", err)
                    }
                }, _ => break
            }
        }
    }
}

fn open(path: ~str) -> Option<~Reader> {
    if "-" == path {
        return Some(~stdin_raw() as ~Reader);
    }

    match File::open(&std::path::Path::new(path.as_slice())) {
        Ok(fd) => return Some(~fd as ~Reader),
        Err(e) => fail!("cat: {0:s}: {1:s}", path, e.to_str())
    }
}
/* vim: set ai ts=4 sw=4 sts=4 et : */
<|endoftext|>


<commit_before>/*
 * Cymbalum, Molecular Simulation in Rust
 * Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
*/
#![allow(non_snake_case)]
//! Testing physical properties of a Lennard-Jones gaz of Helium.
extern crate cymbalum;
use self::cymbalum::*;

use std::sync::{Once, ONCE_INIT};
static START: Once = ONCE_INIT;

use std::path::Path;

fn get_universe() -> Universe {
    let data_dir = Path::new(file!()).parent().unwrap();
    let configuration = data_dir.join("data").join("helium.xyz");
    let mut universe = Universe::from_file(configuration.to_str().unwrap()).unwrap();
    universe.set_cell(UnitCell::cubic(10.0));

    let mut velocities = BoltzmanVelocities::new(units::from(300.0, "K").unwrap());
    velocities.init(&mut universe);
    return universe;
}

fn get_universe_with_interaction() -> Universe {
    let mut universe = get_universe();
    universe.add_pair_interaction("He", "He",
        Box::new(LennardJones{
            sigma: units::from(2.0, "A").unwrap(),
            epsilon: units::from(0.2, "kJ/mol").unwrap()
        })
    );

    return universe;
}

#[test]
fn constant_energy_velocity_verlet() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = get_universe_with_interaction();
    let mut simulation = Simulation::new(
        MolecularDynamics::from_integrator(
            VelocityVerlet::new(units::from(1.0, "fs").unwrap())
        )
    );
    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();
    assert!(f64::abs(E_initial - E_final)/E_final < 1e-3);
}

#[test]
fn constant_energy_verlet() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = get_universe_with_interaction();
    let mut simulation = Simulation::new(
        MolecularDynamics::from_integrator(
            Verlet::new(units::from(1.0, "fs").unwrap())
        )
    );
    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();
    assert!(f64::abs(E_initial - E_final)/E_final < 1e-2);
}

#[test]
fn constant_energy_leap_frog() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = get_universe_with_interaction();
    let mut simulation = Simulation::new(
        MolecularDynamics::from_integrator(
            LeapFrog::new(units::from(1.0, "fs").unwrap())
        )
    );
    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();
    assert!(f64::abs(E_initial - E_final)/E_final < 1e-3);
}

#[test]
fn perfect_gaz() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = get_universe_with_interaction();
    let mut simulation = Simulation::new(
        MolecularDynamics::from_integrator(
            VelocityVerlet::new(units::from(1.0, "fs").unwrap())
        )
    );

    // dilating the universe!
    for particle in universe.iter_mut() {
        let pos = particle.position().clone();
        particle.set_position(10.0 * pos);
    }
    universe.set_cell(UnitCell::cubic(100.0));

    simulation.run(&mut universe, 1000);
    let P = universe.pressure();
    let V = universe.volume();
    let T = universe.temperature();
    let N = universe.size() as f64;

    assert!(f64::abs(P * V - N * constants::K_BOLTZMANN * T) < 1e-3);
}

#[test]
fn berendsen_barostat() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = get_universe_with_interaction();
    let barostat = BerendsenBarostat::new(units::from(1.0, "fs").unwrap(),
                                          units::from(5000.0, "bar").unwrap()
                                          ).timestep(100.0);
    let mut md = MolecularDynamics::from_integrator(barostat);
    md.add_control(BerendsenThermostat::new(units::from(300.0, "K").unwrap(), 10.0));
    let mut simulation = Simulation::new(md);

    simulation.run(&mut universe, 5000);
    let P = universe.pressure();
    let T = universe.temperature();

    assert!(f64::abs(P - units::from(5000.0, "bar").unwrap())/P < 8e-2);
    assert!(f64::abs(T - units::from(300.0, "K").unwrap())/T < 1e-2);
}

#[test]
fn cutoff_computation() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = get_universe();

    universe.add_pair_interaction("He", "He",
        Box::new(CutoffComputation::new(
            Box::new(LennardJones{
                sigma: units::from(2.0, "A").unwrap(),
                epsilon: units::from(0.2, "kJ/mol").unwrap()
            }),
            units::from(7.0, "A").unwrap()
        ))
    );

    let mut simulation = Simulation::new(
        MolecularDynamics::from_integrator(
            VelocityVerlet::new(units::from(1.0, "fs").unwrap())
        )
    );
    simulation.run(&mut universe, 100);

    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();
    assert!(f64::abs(E_initial - E_final)/E_final < 1e-3);
}

#[test]
fn table_computation() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = get_universe();

    universe.add_pair_interaction("He", "He",
        Box::new(TableComputation::new(
            Box::new(LennardJones{
                sigma: units::from(2.0, "A").unwrap(),
                epsilon: units::from(0.2, "kJ/mol").unwrap()
            }),
            1000,
            units::from(7.0, "A").unwrap()
        ))
    );

    let mut simulation = Simulation::new(
        MolecularDynamics::from_integrator(
            VelocityVerlet::new(units::from(1.0, "fs").unwrap())
        )
    );
    simulation.run(&mut universe, 100);

    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();
    assert!(f64::abs(E_initial - E_final)/E_final < 1e-3);
}
<commit_msg>Faster berendsen test by removing the thermostat<commit_after>/*
 * Cymbalum, Molecular Simulation in Rust
 * Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
*/
#![allow(non_snake_case)]
//! Testing physical properties of a Lennard-Jones gaz of Helium.
extern crate cymbalum;
use self::cymbalum::*;

use std::sync::{Once, ONCE_INIT};
static START: Once = ONCE_INIT;

use std::path::Path;

fn get_universe() -> Universe {
    let data_dir = Path::new(file!()).parent().unwrap();
    let configuration = data_dir.join("data").join("helium.xyz");
    let mut universe = Universe::from_file(configuration.to_str().unwrap()).unwrap();
    universe.set_cell(UnitCell::cubic(10.0));

    let mut velocities = BoltzmanVelocities::new(units::from(300.0, "K").unwrap());
    velocities.init(&mut universe);
    return universe;
}

fn get_universe_with_interaction() -> Universe {
    let mut universe = get_universe();
    universe.add_pair_interaction("He", "He",
        Box::new(LennardJones{
            sigma: units::from(2.0, "A").unwrap(),
            epsilon: units::from(0.2, "kJ/mol").unwrap()
        })
    );

    return universe;
}

#[test]
fn constant_energy_velocity_verlet() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = get_universe_with_interaction();
    let mut simulation = Simulation::new(
        MolecularDynamics::from_integrator(
            VelocityVerlet::new(units::from(1.0, "fs").unwrap())
        )
    );
    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();
    assert!(f64::abs(E_initial - E_final)/E_final < 1e-3);
}

#[test]
fn constant_energy_verlet() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = get_universe_with_interaction();
    let mut simulation = Simulation::new(
        MolecularDynamics::from_integrator(
            Verlet::new(units::from(1.0, "fs").unwrap())
        )
    );
    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();
    assert!(f64::abs(E_initial - E_final)/E_final < 1e-2);
}

#[test]
fn constant_energy_leap_frog() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = get_universe_with_interaction();
    let mut simulation = Simulation::new(
        MolecularDynamics::from_integrator(
            LeapFrog::new(units::from(1.0, "fs").unwrap())
        )
    );
    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();
    assert!(f64::abs(E_initial - E_final)/E_final < 1e-3);
}

#[test]
fn perfect_gaz() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = get_universe_with_interaction();
    let mut simulation = Simulation::new(
        MolecularDynamics::from_integrator(
            VelocityVerlet::new(units::from(1.0, "fs").unwrap())
        )
    );

    // dilating the universe!
    for particle in universe.iter_mut() {
        let pos = particle.position().clone();
        particle.set_position(10.0 * pos);
    }
    universe.set_cell(UnitCell::cubic(100.0));

    simulation.run(&mut universe, 1000);
    let P = universe.pressure();
    let V = universe.volume();
    let T = universe.temperature();
    let N = universe.size() as f64;

    assert!(f64::abs(P * V - N * constants::K_BOLTZMANN * T) < 1e-3);
}

#[test]
fn berendsen_barostat() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = get_universe_with_interaction();
    let mut simulation = Simulation::new(
        MolecularDynamics::from_integrator(
            BerendsenBarostat::new(
                units::from(1.0, "fs").unwrap(),
                units::from(5000.0, "bar").unwrap()
            )
        )
    );

    simulation.run(&mut universe, 1000);
    let pressure = units::from(5000.0, "bar").unwrap();
    assert!(f64::abs(universe.pressure() - pressure)/pressure < 5e-2);
}

#[test]
fn cutoff_computation() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = get_universe();

    universe.add_pair_interaction("He", "He",
        Box::new(CutoffComputation::new(
            Box::new(LennardJones{
                sigma: units::from(2.0, "A").unwrap(),
                epsilon: units::from(0.2, "kJ/mol").unwrap()
            }),
            units::from(7.0, "A").unwrap()
        ))
    );

    let mut simulation = Simulation::new(
        MolecularDynamics::from_integrator(
            VelocityVerlet::new(units::from(1.0, "fs").unwrap())
        )
    );
    simulation.run(&mut universe, 100);

    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();
    assert!(f64::abs(E_initial - E_final)/E_final < 1e-3);
}

#[test]
fn table_computation() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = get_universe();

    universe.add_pair_interaction("He", "He",
        Box::new(TableComputation::new(
            Box::new(LennardJones{
                sigma: units::from(2.0, "A").unwrap(),
                epsilon: units::from(0.2, "kJ/mol").unwrap()
            }),
            1000,
            units::from(7.0, "A").unwrap()
        ))
    );

    let mut simulation = Simulation::new(
        MolecularDynamics::from_integrator(
            VelocityVerlet::new(units::from(1.0, "fs").unwrap())
        )
    );
    simulation.run(&mut universe, 100);

    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();
    assert!(f64::abs(E_initial - E_final)/E_final < 1e-3);
}
<|endoftext|>


<commit_before>use std::io::{self, prelude::Write};
use std::time::Duration;

use super::OutputFormatter;
use crate::{
    console::{ConsoleTestState, OutputLocation},
    test_result::TestResult,
    time,
    types::{TestDesc, TestType},
};

pub struct JunitFormatter<T> {
    out: OutputLocation<T>,
    results: Vec<(TestDesc, TestResult, Duration)>,
}

impl<T: Write> JunitFormatter<T> {
    pub fn new(out: OutputLocation<T>) -> Self {
        Self { out, results: Vec::new() }
    }

    fn write_message(&mut self, s: &str) -> io::Result<()> {
        assert!(!s.contains('\n'));

        self.out.write_all(s.as_ref())
    }
}

impl<T: Write> OutputFormatter for JunitFormatter<T> {
    fn write_run_start(&mut self, _test_count: usize) -> io::Result<()> {
        // We write xml header on run start
        self.write_message(&"<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
    }

    fn write_test_start(&mut self, _desc: &TestDesc) -> io::Result<()> {
        // We do not output anything on test start.
        Ok(())
    }

    fn write_timeout(&mut self, _desc: &TestDesc) -> io::Result<()> {
        // We do not output anything on test timeout.
        Ok(())
    }

    fn write_result(
        &mut self,
        desc: &TestDesc,
        result: &TestResult,
        exec_time: Option<&time::TestExecTime>,
        _stdout: &[u8],
        _state: &ConsoleTestState,
    ) -> io::Result<()> {
        // Because the testsuit node holds some of the information as attributes, we can't write it
        // until all of the tests has ran. Instead of writting every result as they come in, we add
        // them to a Vec and write them all at once when run is complete.
        let duration = exec_time.map(|t| t.0).unwrap_or_default();
        self.results.push((desc.clone(), result.clone(), duration));
        Ok(())
    }
    fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
        self.write_message("<testsuites>")?;

        self.write_message(&*format!(
            "<testsuite name=\"test\" package=\"test\" id=\"0\" \
             errors=\"0\" \
             failures=\"{}\" \
             tests=\"{}\" \
             skipped=\"{}\" \
             >",
            state.failed, state.total, state.ignored
        ))?;
        for (desc, result, duration) in std::mem::replace(&mut self.results, Vec::new()) {
            let (class_name, test_name) = parse_class_name(&desc);
            match result {
                TestResult::TrIgnored => { /* no-op */ }
                TestResult::TrFailed => {
                    self.write_message(&*format!(
                        "<testcase classname=\"{}\" \
                         name=\"{}\" time=\"{}\">",
                        class_name,
                        test_name,
                        duration.as_secs_f64()
                    ))?;
                    self.write_message("<failure type=\"assert\"/>")?;
                    self.write_message("</testcase>")?;
                }

                TestResult::TrFailedMsg(ref m) => {
                    self.write_message(&*format!(
                        "<testcase classname=\"{}\" \
                         name=\"{}\" time=\"{}\">",
                        class_name,
                        test_name,
                        duration.as_secs_f64()
                    ))?;
                    self.write_message(&*format!("<failure message=\"{}\" type=\"assert\"/>", m))?;
                    self.write_message("</testcase>")?;
                }

                TestResult::TrTimedFail => {
                    self.write_message(&*format!(
                        "<testcase classname=\"{}\" \
                         name=\"{}\" time=\"{}\">",
                        class_name,
                        test_name,
                        duration.as_secs_f64()
                    ))?;
                    self.write_message("<failure type=\"timeout\"/>")?;
                    self.write_message("</testcase>")?;
                }

                TestResult::TrBench(ref b) => {
                    self.write_message(&*format!(
                        "<testcase classname=\"benchmark::{}\" \
                         name=\"{}\" time=\"{}\" />",
                        class_name, test_name, b.ns_iter_summ.sum
                    ))?;
                }

                TestResult::TrOk | TestResult::TrAllowedFail => {
                    self.write_message(&*format!(
                        "<testcase classname=\"{}\" \
                         name=\"{}\" time=\"{}\"/>",
                        class_name,
                        test_name,
                        duration.as_secs_f64()
                    ))?;
                }
            }
        }
        self.write_message("<system-out/>")?;
        self.write_message("<system-err/>")?;
        self.write_message("</testsuite>")?;
        self.write_message("</testsuites>")?;

        Ok(state.failed == 0)
    }
}

fn parse_class_name(desc: &TestDesc) -> (String, String) {
    match desc.test_type {
        TestType::UnitTest => parse_class_name_unit(desc),
        TestType::DocTest => parse_class_name_doc(desc),
        TestType::IntegrationTest => parse_class_name_integration(desc),
        TestType::Unknown => (String::from("unknown"), String::from(desc.name.as_slice())),
    }
}

fn parse_class_name_unit(desc: &TestDesc) -> (String, String) {
    // Module path => classname
    // Function name => name
    let module_segments: Vec<&str> = desc.name.as_slice().split("::").collect();
    let (class_name, test_name) = match module_segments[..] {
        [test] => (String::from("crate"), String::from(test)),
        [ref path @ .., test] => (path.join("::"), String::from(test)),
        [..] => unreachable!(),
    };
    (class_name, test_name)
}

fn parse_class_name_doc(desc: &TestDesc) -> (String, String) {
    // File path => classname
    // Line # => test name
    let segments: Vec<&str> = desc.name.as_slice().split(" - ").collect();
    let (class_name, test_name) = match segments[..] {
        [file, line] => (String::from(file.trim()), String::from(line.trim())),
        [..] => unreachable!(),
    };
    (class_name, test_name)
}

fn parse_class_name_integration(desc: &TestDesc) -> (String, String) {
    (String::from("integration"), String::from(desc.name.as_slice()))
}
<commit_msg>make junit output more consistent with default format<commit_after>use std::io::{self, prelude::Write};
use std::time::Duration;

use super::OutputFormatter;
use crate::{
    console::{ConsoleTestState, OutputLocation},
    test_result::TestResult,
    time,
    types::{TestDesc, TestType},
};

pub struct JunitFormatter<T> {
    out: OutputLocation<T>,
    results: Vec<(TestDesc, TestResult, Duration)>,
}

impl<T: Write> JunitFormatter<T> {
    pub fn new(out: OutputLocation<T>) -> Self {
        Self { out, results: Vec::new() }
    }

    fn write_message(&mut self, s: &str) -> io::Result<()> {
        assert!(!s.contains('\n'));

        self.out.write_all(s.as_ref())
    }
}

impl<T: Write> OutputFormatter for JunitFormatter<T> {
    fn write_run_start(&mut self, _test_count: usize) -> io::Result<()> {
        // We write xml header on run start
        self.out.write_all("\n".as_bytes())?;
        self.write_message("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
    }

    fn write_test_start(&mut self, _desc: &TestDesc) -> io::Result<()> {
        // We do not output anything on test start.
        Ok(())
    }

    fn write_timeout(&mut self, _desc: &TestDesc) -> io::Result<()> {
        // We do not output anything on test timeout.
        Ok(())
    }

    fn write_result(
        &mut self,
        desc: &TestDesc,
        result: &TestResult,
        exec_time: Option<&time::TestExecTime>,
        _stdout: &[u8],
        _state: &ConsoleTestState,
    ) -> io::Result<()> {
        // Because the testsuit node holds some of the information as attributes, we can't write it
        // until all of the tests has ran. Instead of writting every result as they come in, we add
        // them to a Vec and write them all at once when run is complete.
        let duration = exec_time.map(|t| t.0).unwrap_or_default();
        self.results.push((desc.clone(), result.clone(), duration));
        Ok(())
    }
    fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
        self.write_message("<testsuites>")?;

        self.write_message(&*format!(
            "<testsuite name=\"test\" package=\"test\" id=\"0\" \
             errors=\"0\" \
             failures=\"{}\" \
             tests=\"{}\" \
             skipped=\"{}\" \
             >",
            state.failed, state.total, state.ignored
        ))?;
        for (desc, result, duration) in std::mem::replace(&mut self.results, Vec::new()) {
            let (class_name, test_name) = parse_class_name(&desc);
            match result {
                TestResult::TrIgnored => { /* no-op */ }
                TestResult::TrFailed => {
                    self.write_message(&*format!(
                        "<testcase classname=\"{}\" \
                         name=\"{}\" time=\"{}\">",
                        class_name,
                        test_name,
                        duration.as_secs_f64()
                    ))?;
                    self.write_message("<failure type=\"assert\"/>")?;
                    self.write_message("</testcase>")?;
                }

                TestResult::TrFailedMsg(ref m) => {
                    self.write_message(&*format!(
                        "<testcase classname=\"{}\" \
                         name=\"{}\" time=\"{}\">",
                        class_name,
                        test_name,
                        duration.as_secs_f64()
                    ))?;
                    self.write_message(&*format!("<failure message=\"{}\" type=\"assert\"/>", m))?;
                    self.write_message("</testcase>")?;
                }

                TestResult::TrTimedFail => {
                    self.write_message(&*format!(
                        "<testcase classname=\"{}\" \
                         name=\"{}\" time=\"{}\">",
                        class_name,
                        test_name,
                        duration.as_secs_f64()
                    ))?;
                    self.write_message("<failure type=\"timeout\"/>")?;
                    self.write_message("</testcase>")?;
                }

                TestResult::TrBench(ref b) => {
                    self.write_message(&*format!(
                        "<testcase classname=\"benchmark::{}\" \
                         name=\"{}\" time=\"{}\" />",
                        class_name, test_name, b.ns_iter_summ.sum
                    ))?;
                }

                TestResult::TrOk | TestResult::TrAllowedFail => {
                    self.write_message(&*format!(
                        "<testcase classname=\"{}\" \
                         name=\"{}\" time=\"{}\"/>",
                        class_name,
                        test_name,
                        duration.as_secs_f64()
                    ))?;
                }
            }
        }
        self.write_message("<system-out/>")?;
        self.write_message("<system-err/>")?;
        self.write_message("</testsuite>")?;
        self.write_message("</testsuites>")?;

        self.out.write_all("\n\n".as_bytes())?;

        Ok(state.failed == 0)
    }
}

fn parse_class_name(desc: &TestDesc) -> (String, String) {
    match desc.test_type {
        TestType::UnitTest => parse_class_name_unit(desc),
        TestType::DocTest => parse_class_name_doc(desc),
        TestType::IntegrationTest => parse_class_name_integration(desc),
        TestType::Unknown => (String::from("unknown"), String::from(desc.name.as_slice())),
    }
}

fn parse_class_name_unit(desc: &TestDesc) -> (String, String) {
    // Module path => classname
    // Function name => name
    let module_segments: Vec<&str> = desc.name.as_slice().split("::").collect();
    let (class_name, test_name) = match module_segments[..] {
        [test] => (String::from("crate"), String::from(test)),
        [ref path @ .., test] => (path.join("::"), String::from(test)),
        [..] => unreachable!(),
    };
    (class_name, test_name)
}

fn parse_class_name_doc(desc: &TestDesc) -> (String, String) {
    // File path => classname
    // Line # => test name
    let segments: Vec<&str> = desc.name.as_slice().split(" - ").collect();
    let (class_name, test_name) = match segments[..] {
        [file, line] => (String::from(file.trim()), String::from(line.trim())),
        [..] => unreachable!(),
    };
    (class_name, test_name)
}

fn parse_class_name_integration(desc: &TestDesc) -> (String, String) {
    (String::from("integration"), String::from(desc.name.as_slice()))
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

pub fn heading(content: &str) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}\n===========================================================================================================", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn subheading(content: &str) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}\n-----------------------------------------------------------------------------------------------------------", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn progress(content: String) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn info(content: String) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn error(content: String) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Red))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn list(items: Vec<&str>) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "") {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    items
        .iter()
        .for_each(|content| match writeln!(&mut stdout, "- {}", content) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        })
}

pub fn pause() {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Yellow))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    loop {
        let prompt = "Enter 'Done' when ready to continue:";

        match writeln!(&mut stdout, "\n{}", prompt) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }

        let mut input = String::new();

        match io::stdin().read_line(&mut input) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }

        if input.contains("Done") {
            match stdout.reset() {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            break;
        } else {
            continue;
        }
    }
}
<commit_msg>Automate underline heading logic<commit_after>use std::io::{self, Write};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

pub fn heading(content: &str) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}\n{}", content, underline(content, "=")) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn subheading(content: &str) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}\n{}", content, underline(content, "-")) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn progress(content: String) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn info(content: String) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn error(content: String) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Red))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn list(items: Vec<&str>) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "") {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    items
        .iter()
        .for_each(|content| match writeln!(&mut stdout, "- {}", content) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        })
}

pub fn pause() {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Yellow))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    loop {
        let prompt = "Enter 'Done' when ready to continue:";

        match writeln!(&mut stdout, "\n{}", prompt) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }

        let mut input = String::new();

        match io::stdin().read_line(&mut input) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }

        if input.contains("Done") {
            match stdout.reset() {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            break;
        } else {
            continue;
        }
    }
}

fn underline(content: &str, symbol: &str) -> String {
    content.chars().map(|_| symbol).collect()
}
<|endoftext|>


<commit_before>use std::fs;
use std::io::Read;
use std::env;
use std::path::PathBuf;

use regex::Regex;
use failure::Error;

use utils::vcs;
use utils::xcode::InfoPlist;
use utils::cordova::CordovaConfig;

pub fn get_cordova_release_name(path: Option<PathBuf>) -> Result<Option<String>, Error> {
    let here = path.map_or(env::current_dir()?, |p| p.into());
    let platform = match here.file_name().and_then(|x| x.to_str()) {
        Some("android") => "android",
        Some("ios") => "ios",
        _ => return Ok(None),
    };
    let base = match here.parent().and_then(|x| x.parent()) {
        Some(path) => path,
        None => return Ok(None),
    };

    let path = base.join("config.xml");
    if_chain! {
        if let Ok(md) = path.metadata();
        if md.is_file();
        if let Ok(Some(config)) = CordovaConfig::load(path);
        then {
            match platform {
                "android" => Ok(Some(config.android_release_name())),
                "ios" => Ok(Some(config.ios_release_name())),
                _ => unreachable!(),
            }
        } else {
            Ok(None)
        }
    }
}

pub fn get_xcode_release_name(plist: Option<InfoPlist>) -> Result<Option<String>, Error> {
    // if we are executed from within xcode, then we can use the environment
    // based discovery to get a release name without any interpolation.
    if let Some(plist) = plist.or(InfoPlist::discover_from_env()?) {
        return Ok(Some(plist.get_release_name()));
    }

    Ok(None)
}

pub fn infer_gradle_release_name(path: Option<PathBuf>) -> Result<Option<String>, Error> {
    lazy_static! {
        static ref APP_ID_RE: Regex = Regex::new(
            r#"applicationId\s+["']([^"']*)["']"#).unwrap();
        static ref VERSION_NAME_RE: Regex = Regex::new(
            r#"versionName\s+["']([^"']*)["']"#).unwrap();
    }

    let mut contents = String::new();
    let mut here = path.map_or(env::current_dir()?, |p| p.into());
    loop {
        if_chain! {
            if let Ok(build_md) = here.join("build.gradle").metadata();
            if build_md.is_file();
            if let Ok(app_md) = here.join("app/build.gradle").metadata();
            if app_md.is_file();
            if let Ok(mut f) = fs::File::open(here.join("app/build.gradle"));
            if f.read_to_string(&mut contents).is_ok();
            if let Some(app_id_caps) = APP_ID_RE.captures(&contents);
            if let Some(version_caps) = VERSION_NAME_RE.captures(&contents);
            then {
                return Ok(Some(format!("{}-{}", &app_id_caps[1], &version_caps[1])));
            }
        }
        if !here.pop() {
            break;
        }
    }

    Ok(None)
}

/// Detects the release name for the current working directory.
pub fn detect_release_name() -> Result<String, Error> {
    // cordova release detection first.
    if let Some(release) = get_cordova_release_name(None)? {
        return Ok(release);
    }

    // for now only execute this on macs.  The reason is that this uses
    // xcodebuild which does not exist anywhere but there.
    if_chain! {
        if cfg!(target_os="macos");
        if let Some(release) = get_xcode_release_name(None)?;
        then {
            return Ok(release)
        }
    }

    // For android we badly parse gradle files.  We do this because most of the
    // time now people set the ids and versions in the gradle files instead of
    // the xml manifests.
    if let Some(release) = infer_gradle_release_name(None)? {
        return Ok(release);
    }

    if let Ok(head) = vcs::find_head() {
        Ok(head)
    } else {
        bail!("Could not automatically determine release name");
    }
}
<commit_msg>feat(releases): Detect HEROKU_SLUG_COMMIT in propose-version (#298)<commit_after>use std::fs;
use std::io::Read;
use std::env;
use std::path::PathBuf;

use regex::Regex;
use failure::Error;

use utils::vcs;
use utils::xcode::InfoPlist;
use utils::cordova::CordovaConfig;

pub fn get_cordova_release_name(path: Option<PathBuf>) -> Result<Option<String>, Error> {
    let here = path.map_or(env::current_dir()?, |p| p.into());
    let platform = match here.file_name().and_then(|x| x.to_str()) {
        Some("android") => "android",
        Some("ios") => "ios",
        _ => return Ok(None),
    };
    let base = match here.parent().and_then(|x| x.parent()) {
        Some(path) => path,
        None => return Ok(None),
    };

    let path = base.join("config.xml");
    if_chain! {
        if let Ok(md) = path.metadata();
        if md.is_file();
        if let Ok(Some(config)) = CordovaConfig::load(path);
        then {
            match platform {
                "android" => Ok(Some(config.android_release_name())),
                "ios" => Ok(Some(config.ios_release_name())),
                _ => unreachable!(),
            }
        } else {
            Ok(None)
        }
    }
}

pub fn get_xcode_release_name(plist: Option<InfoPlist>) -> Result<Option<String>, Error> {
    // if we are executed from within xcode, then we can use the environment
    // based discovery to get a release name without any interpolation.
    if let Some(plist) = plist.or(InfoPlist::discover_from_env()?) {
        return Ok(Some(plist.get_release_name()));
    }

    Ok(None)
}

pub fn infer_gradle_release_name(path: Option<PathBuf>) -> Result<Option<String>, Error> {
    lazy_static! {
        static ref APP_ID_RE: Regex = Regex::new(
            r#"applicationId\s+["']([^"']*)["']"#).unwrap();
        static ref VERSION_NAME_RE: Regex = Regex::new(
            r#"versionName\s+["']([^"']*)["']"#).unwrap();
    }

    let mut contents = String::new();
    let mut here = path.map_or(env::current_dir()?, |p| p.into());
    loop {
        if_chain! {
            if let Ok(build_md) = here.join("build.gradle").metadata();
            if build_md.is_file();
            if let Ok(app_md) = here.join("app/build.gradle").metadata();
            if app_md.is_file();
            if let Ok(mut f) = fs::File::open(here.join("app/build.gradle"));
            if f.read_to_string(&mut contents).is_ok();
            if let Some(app_id_caps) = APP_ID_RE.captures(&contents);
            if let Some(version_caps) = VERSION_NAME_RE.captures(&contents);
            then {
                return Ok(Some(format!("{}-{}", &app_id_caps[1], &version_caps[1])));
            }
        }
        if !here.pop() {
            break;
        }
    }

    Ok(None)
}

/// Detects the release name for the current working directory.
pub fn detect_release_name() -> Result<String, Error> {
    // cordova release detection first.
    if let Some(release) = get_cordova_release_name(None)? {
        return Ok(release);
    }

    // try heroku: https://docs.sentry.io/integrations/heroku/#configure-releases
    if let Ok(release) = env::var("HEROKU_SLUG_COMMIT") {
        if !release.is_empty() {
            return Ok(release);
        }
    }

    // for now only execute this on macs.  The reason is that this uses
    // xcodebuild which does not exist anywhere but there.
    if_chain! {
        if cfg!(target_os="macos");
        if let Some(release) = get_xcode_release_name(None)?;
        then {
            return Ok(release)
        }
    }

    // For android we badly parse gradle files.  We do this because most of the
    // time now people set the ids and versions in the gradle files instead of
    // the xml manifests.
    if let Some(release) = infer_gradle_release_name(None)? {
        return Ok(release);
    }

    if let Ok(head) = vcs::find_head() {
        Ok(head)
    } else {
        bail!("Could not automatically determine release name");
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation of cross-process surfaces for Linux. This uses X pixmaps.

use platform::surface::NativeSurfaceMethods;
use texturegl::Texture;

use extra::arc::Arc;
use geom::size::Size2D;
use opengles::glx::{GLXFBConfig, GLXDrawable, GLXPixmap, GLX_BIND_TO_TEXTURE_RGBA_EXT};
use opengles::glx::{GLX_DEPTH_SIZE, GLX_DRAWABLE_TYPE, GLX_FRONT_EXT, GLX_PIXMAP_BIT, GLX_RGBA};
use opengles::glx::{GLX_TEXTURE_2D_EXT, GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT};
use opengles::glx::{GLX_TEXTURE_TARGET_EXT, glXChooseVisual, glXCreatePixmap, glXDestroyPixmap};
use opengles::glx::{glXGetFBConfigs, glXGetProcAddress, glXGetFBConfigAttrib, glXGetFBConfigs};
use opengles::glx::{glXGetVisualFromFBConfig};
use opengles::glx;
use opengles::gl2::NO_ERROR;
use opengles::gl2;
use std::cast;
use std::libc::{c_char, c_int, c_uint, c_void};
use std::ptr;
use xlib::xlib::{Display, Pixmap, XCloseDisplay, XCreateGC, XCreateImage, XCreatePixmap};
use xlib::xlib::{XDefaultScreen, XFreePixmap, XGetGeometry, XOpenDisplay, XPutImage, XRootWindow};
use xlib::xlib::{XVisualInfo, ZPixmap};

/// The display and visual info. This is needed in order to upload on the painting side. This holds
/// a *strong* reference to the display and will close it when done.
///
/// FIXME(pcwalton): Mark nonsendable and noncopyable.
pub struct NativePaintingGraphicsContext {
    display: *Display,
    visual_info: *XVisualInfo,
}

impl NativePaintingGraphicsContext {
    #[fixed_stack_segment]
    pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext {
        unsafe {
            let display = XOpenDisplay(*metadata);

            // FIXME(pcwalton): It would be more robust to actually have the compositor pass the
            // visual.
            let compositor_visual_info =
                NativeCompositingGraphicsContext::compositor_visual_info(display);

            NativePaintingGraphicsContext {
                display: display,
                visual_info: compositor_visual_info,
            }
        }
    }
}

impl Drop for NativePaintingGraphicsContext {
    #[fixed_stack_segment]
    fn drop(&mut self) {
        unsafe {
            let _ = XCloseDisplay(self.display);
        }
    }
}

/// The display, visual info, and framebuffer configuration. This is needed in order to bind to a
/// texture on the compositor side. This holds only a *weak* reference to the display and does not
/// close it.
///
/// FIXME(pcwalton): Unchecked weak references are bad and can violate memory safety. This is hard
/// to fix because the Display is given to us by the native windowing system, but we should fix it
/// someday.
///
/// FIXME(pcwalton): Mark nonsendable.
pub struct NativeCompositingGraphicsContext {
    display: *Display,
    visual_info: *XVisualInfo,
    framebuffer_configuration: GLXFBConfig,
}

impl NativeCompositingGraphicsContext {
    /// Chooses the compositor visual info using the same algorithm that the compositor uses.
    ///
    /// FIXME(pcwalton): It would be more robust to actually have the compositor pass the visual.
    #[fixed_stack_segment]
    fn compositor_visual_info(display: *Display) -> *XVisualInfo {
        unsafe {
            let glx_display: *glx::Display = cast::transmute(display);
            let screen = XDefaultScreen(display);
            let attributes = [ GLX_RGBA, GLX_DEPTH_SIZE, 24, 0 ];
            let compositor_visual_info = glXChooseVisual(glx_display, screen, &attributes[0]);
            cast::transmute(compositor_visual_info)
        }
    }

    /// Creates a native graphics context from the given X display connection. This uses GLX. Only
    /// the compositor is allowed to call this.
    #[fixed_stack_segment]
    pub fn from_display(display: *Display) -> NativeCompositingGraphicsContext {
        unsafe {
            // FIXME(pcwalton): It would be more robust to actually have the compositor pass the
            // visual.
            let compositor_visual_info =
                NativeCompositingGraphicsContext::compositor_visual_info(display);
            let compositor_visual_id = (*compositor_visual_info).visualid;

            // Choose an FB config.
            let glx_display = cast::transmute(display);
            let screen = XDefaultScreen(display);
            let mut fbconfig_count = 0;
            let fbconfigs = glXGetFBConfigs(glx_display, screen, &mut fbconfig_count);
            let mut fbconfig_index = None;
            for i in range(0, fbconfig_count) {
                let fbconfig = *ptr::offset(fbconfigs, i as int);
                let visual_info = glXGetVisualFromFBConfig(glx_display, fbconfig);
                let visual_info: *XVisualInfo = cast::transmute(visual_info);
                if visual_info == ptr::null() || (*visual_info).visualid != compositor_visual_id {
                    continue
                }

                let mut value = 0;
                glXGetFBConfigAttrib(glx_display, fbconfig, GLX_DRAWABLE_TYPE, &mut value);
                if (value & GLX_PIXMAP_BIT) == 0 {
                    continue
                }

                glXGetFBConfigAttrib(glx_display,
                                     fbconfig,
                                     GLX_BIND_TO_TEXTURE_RGBA_EXT,
                                     &mut value);
                if value == 0 {
                    continue
                }

                fbconfig_index = Some(i);
                break
            }

            let framebuffer_configuration = match fbconfig_index {
                None => fail!("No appropriate framebuffer config found!"),
                Some(index) => *ptr::offset(fbconfigs, index as int),
            };

            NativeCompositingGraphicsContext {
                display: display,
                visual_info: compositor_visual_info,
                framebuffer_configuration: framebuffer_configuration,
            }
        }
    }
}

/// The X display string.
pub type NativeGraphicsMetadata = *c_char;

#[deriving(Eq)]
pub enum NativeSurfaceTransientData {
    NoTransientData,
    RenderTaskTransientData(*Display, *XVisualInfo),
}

pub struct NativeSurface {
    /// The pixmap.
    pixmap: Pixmap,

    /// Whether this pixmap will leak if the destructor runs. This is for debugging purposes.
    will_leak: bool,
}

impl Drop for NativeSurface {
    fn drop(&mut self) {
        if self.will_leak {
            fail!("You should have disposed of the pixmap properly with destroy()! This pixmap \
                   will leak!");
        }
    }
}

impl NativeSurface {
    #[fixed_stack_segment]
    pub fn from_pixmap(pixmap: Pixmap) -> NativeSurface {
        NativeSurface {
            pixmap: pixmap,
            will_leak: true,
        }
    }
}

impl NativeSurfaceMethods for NativeSurface {
    #[fixed_stack_segment]
    fn new(native_context: &NativePaintingGraphicsContext, size: Size2D<i32>, stride: i32)
           -> NativeSurface {
        unsafe {
            // Create the pixmap.
            let screen = XDefaultScreen(native_context.display);
            let window = XRootWindow(native_context.display, screen);

            let pixmap = XCreatePixmap(native_context.display,
                                       window,
                                       size.width as c_uint,
                                       size.height as c_uint,
                                       ((stride / size.width) * 8) as c_uint);

            NativeSurface::from_pixmap(pixmap)
        }
    }

    /// This may only be called on the compositor side.
    #[fixed_stack_segment]
    fn bind_to_texture(&self,
                       native_context: &NativeCompositingGraphicsContext,
                       texture: &Texture,
                       size: Size2D<int>) {
        unsafe {
            // Create the GLX pixmap.
            //
            // FIXME(pcwalton): RAII for exception safety?
            let pixmap_attributes = [
                GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
                GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
                0
            ];
            let glx_display = cast::transmute(native_context.display);
            let glx_pixmap = glXCreatePixmap(glx_display,
                                             native_context.framebuffer_configuration,
                                             self.pixmap,
                                             &pixmap_attributes[0]);

            let glXBindTexImageEXT: extern "C" fn(*Display, GLXDrawable, c_int, *c_int) =
                cast::transmute(glXGetProcAddress(cast::transmute(&"glXBindTexImageEXT\x00"[0])));
            assert!(glXBindTexImageEXT as *c_void != ptr::null());
            let _bound = texture.bind();
            glXBindTexImageEXT(native_context.display,
                               cast::transmute(glx_pixmap),
                               GLX_FRONT_EXT,
                               ptr::null());
            assert_eq!(gl2::get_error(), NO_ERROR);

            // FIXME(pcwalton): Recycle these for speed?
            glXDestroyPixmap(glx_display, glx_pixmap);
        }
    }

    /// This may only be called on the painting side.
    #[fixed_stack_segment]
    fn upload(&self, graphics_context: &NativePaintingGraphicsContext, data: &[u8]) {
        unsafe {
            // Ensure that we're running on the render task. Take the display.
            let pixmap = self.pixmap;

            // Figure out the width, height, and depth of the pixmap.
            let mut root_window = 0;
            let mut x = 0;
            let mut y = 0;
            let mut width = 0;
            let mut height = 0;
            let mut border_width = 0;
            let mut depth = 0;
            let _ = XGetGeometry(graphics_context.display,
                                 cast::transmute(pixmap),
                                 &mut root_window,
                                 &mut x,
                                 &mut y,
                                 &mut width,
                                 &mut height,
                                 &mut border_width,
                                 &mut depth);

            // Create the image.
            let image = XCreateImage(graphics_context.display,
                                     (*graphics_context.visual_info).visual,
                                     depth,
                                     ZPixmap,
                                     0,
                                     cast::transmute(&data[0]),
                                     width as c_uint,
                                     height as c_uint,
                                     32,
                                     0);

            // Create the X graphics context.
            let gc = XCreateGC(graphics_context.display, pixmap, 0, ptr::null());

            // Draw the image.
            let _ = XPutImage(graphics_context.display,
                              pixmap,
                              gc,
                              image,
                              0,
                              0,
                              0,
                              0,
                              width,
                              height);
        }
    }

    fn get_id(&self) -> int {
        self.pixmap as int
    }

    #[fixed_stack_segment]
    fn destroy(&mut self, graphics_context: &NativePaintingGraphicsContext) {
        unsafe {
            assert!(self.pixmap != 0);
            XFreePixmap(graphics_context.display, self.pixmap);
            self.mark_wont_leak()
        }
    }

    fn mark_will_leak(&mut self) {
        self.will_leak = true
    }

    fn mark_wont_leak(&mut self) {
        self.will_leak = false
    }
}

<commit_msg>Remove unused bogus import<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation of cross-process surfaces for Linux. This uses X pixmaps.

use platform::surface::NativeSurfaceMethods;
use texturegl::Texture;

use geom::size::Size2D;
use opengles::glx::{GLXFBConfig, GLXDrawable, GLXPixmap, GLX_BIND_TO_TEXTURE_RGBA_EXT};
use opengles::glx::{GLX_DEPTH_SIZE, GLX_DRAWABLE_TYPE, GLX_FRONT_EXT, GLX_PIXMAP_BIT, GLX_RGBA};
use opengles::glx::{GLX_TEXTURE_2D_EXT, GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT};
use opengles::glx::{GLX_TEXTURE_TARGET_EXT, glXChooseVisual, glXCreatePixmap, glXDestroyPixmap};
use opengles::glx::{glXGetFBConfigs, glXGetProcAddress, glXGetFBConfigAttrib, glXGetFBConfigs};
use opengles::glx::{glXGetVisualFromFBConfig};
use opengles::glx;
use opengles::gl2::NO_ERROR;
use opengles::gl2;
use std::cast;
use std::libc::{c_char, c_int, c_uint, c_void};
use std::ptr;
use xlib::xlib::{Display, Pixmap, XCloseDisplay, XCreateGC, XCreateImage, XCreatePixmap};
use xlib::xlib::{XDefaultScreen, XFreePixmap, XGetGeometry, XOpenDisplay, XPutImage, XRootWindow};
use xlib::xlib::{XVisualInfo, ZPixmap};

/// The display and visual info. This is needed in order to upload on the painting side. This holds
/// a *strong* reference to the display and will close it when done.
///
/// FIXME(pcwalton): Mark nonsendable and noncopyable.
pub struct NativePaintingGraphicsContext {
    display: *Display,
    visual_info: *XVisualInfo,
}

impl NativePaintingGraphicsContext {
    #[fixed_stack_segment]
    pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext {
        unsafe {
            let display = XOpenDisplay(*metadata);

            // FIXME(pcwalton): It would be more robust to actually have the compositor pass the
            // visual.
            let compositor_visual_info =
                NativeCompositingGraphicsContext::compositor_visual_info(display);

            NativePaintingGraphicsContext {
                display: display,
                visual_info: compositor_visual_info,
            }
        }
    }
}

impl Drop for NativePaintingGraphicsContext {
    #[fixed_stack_segment]
    fn drop(&mut self) {
        unsafe {
            let _ = XCloseDisplay(self.display);
        }
    }
}

/// The display, visual info, and framebuffer configuration. This is needed in order to bind to a
/// texture on the compositor side. This holds only a *weak* reference to the display and does not
/// close it.
///
/// FIXME(pcwalton): Unchecked weak references are bad and can violate memory safety. This is hard
/// to fix because the Display is given to us by the native windowing system, but we should fix it
/// someday.
///
/// FIXME(pcwalton): Mark nonsendable.
pub struct NativeCompositingGraphicsContext {
    display: *Display,
    visual_info: *XVisualInfo,
    framebuffer_configuration: GLXFBConfig,
}

impl NativeCompositingGraphicsContext {
    /// Chooses the compositor visual info using the same algorithm that the compositor uses.
    ///
    /// FIXME(pcwalton): It would be more robust to actually have the compositor pass the visual.
    #[fixed_stack_segment]
    fn compositor_visual_info(display: *Display) -> *XVisualInfo {
        unsafe {
            let glx_display: *glx::Display = cast::transmute(display);
            let screen = XDefaultScreen(display);
            let attributes = [ GLX_RGBA, GLX_DEPTH_SIZE, 24, 0 ];
            let compositor_visual_info = glXChooseVisual(glx_display, screen, &attributes[0]);
            cast::transmute(compositor_visual_info)
        }
    }

    /// Creates a native graphics context from the given X display connection. This uses GLX. Only
    /// the compositor is allowed to call this.
    #[fixed_stack_segment]
    pub fn from_display(display: *Display) -> NativeCompositingGraphicsContext {
        unsafe {
            // FIXME(pcwalton): It would be more robust to actually have the compositor pass the
            // visual.
            let compositor_visual_info =
                NativeCompositingGraphicsContext::compositor_visual_info(display);
            let compositor_visual_id = (*compositor_visual_info).visualid;

            // Choose an FB config.
            let glx_display = cast::transmute(display);
            let screen = XDefaultScreen(display);
            let mut fbconfig_count = 0;
            let fbconfigs = glXGetFBConfigs(glx_display, screen, &mut fbconfig_count);
            let mut fbconfig_index = None;
            for i in range(0, fbconfig_count) {
                let fbconfig = *ptr::offset(fbconfigs, i as int);
                let visual_info = glXGetVisualFromFBConfig(glx_display, fbconfig);
                let visual_info: *XVisualInfo = cast::transmute(visual_info);
                if visual_info == ptr::null() || (*visual_info).visualid != compositor_visual_id {
                    continue
                }

                let mut value = 0;
                glXGetFBConfigAttrib(glx_display, fbconfig, GLX_DRAWABLE_TYPE, &mut value);
                if (value & GLX_PIXMAP_BIT) == 0 {
                    continue
                }

                glXGetFBConfigAttrib(glx_display,
                                     fbconfig,
                                     GLX_BIND_TO_TEXTURE_RGBA_EXT,
                                     &mut value);
                if value == 0 {
                    continue
                }

                fbconfig_index = Some(i);
                break
            }

            let framebuffer_configuration = match fbconfig_index {
                None => fail!("No appropriate framebuffer config found!"),
                Some(index) => *ptr::offset(fbconfigs, index as int),
            };

            NativeCompositingGraphicsContext {
                display: display,
                visual_info: compositor_visual_info,
                framebuffer_configuration: framebuffer_configuration,
            }
        }
    }
}

/// The X display string.
pub type NativeGraphicsMetadata = *c_char;

#[deriving(Eq)]
pub enum NativeSurfaceTransientData {
    NoTransientData,
    RenderTaskTransientData(*Display, *XVisualInfo),
}

pub struct NativeSurface {
    /// The pixmap.
    pixmap: Pixmap,

    /// Whether this pixmap will leak if the destructor runs. This is for debugging purposes.
    will_leak: bool,
}

impl Drop for NativeSurface {
    fn drop(&mut self) {
        if self.will_leak {
            fail!("You should have disposed of the pixmap properly with destroy()! This pixmap \
                   will leak!");
        }
    }
}

impl NativeSurface {
    #[fixed_stack_segment]
    pub fn from_pixmap(pixmap: Pixmap) -> NativeSurface {
        NativeSurface {
            pixmap: pixmap,
            will_leak: true,
        }
    }
}

impl NativeSurfaceMethods for NativeSurface {
    #[fixed_stack_segment]
    fn new(native_context: &NativePaintingGraphicsContext, size: Size2D<i32>, stride: i32)
           -> NativeSurface {
        unsafe {
            // Create the pixmap.
            let screen = XDefaultScreen(native_context.display);
            let window = XRootWindow(native_context.display, screen);

            let pixmap = XCreatePixmap(native_context.display,
                                       window,
                                       size.width as c_uint,
                                       size.height as c_uint,
                                       ((stride / size.width) * 8) as c_uint);

            NativeSurface::from_pixmap(pixmap)
        }
    }

    /// This may only be called on the compositor side.
    #[fixed_stack_segment]
    fn bind_to_texture(&self,
                       native_context: &NativeCompositingGraphicsContext,
                       texture: &Texture,
                       size: Size2D<int>) {
        unsafe {
            // Create the GLX pixmap.
            //
            // FIXME(pcwalton): RAII for exception safety?
            let pixmap_attributes = [
                GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
                GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
                0
            ];
            let glx_display = cast::transmute(native_context.display);
            let glx_pixmap = glXCreatePixmap(glx_display,
                                             native_context.framebuffer_configuration,
                                             self.pixmap,
                                             &pixmap_attributes[0]);

            let glXBindTexImageEXT: extern "C" fn(*Display, GLXDrawable, c_int, *c_int) =
                cast::transmute(glXGetProcAddress(cast::transmute(&"glXBindTexImageEXT\x00"[0])));
            assert!(glXBindTexImageEXT as *c_void != ptr::null());
            let _bound = texture.bind();
            glXBindTexImageEXT(native_context.display,
                               cast::transmute(glx_pixmap),
                               GLX_FRONT_EXT,
                               ptr::null());
            assert_eq!(gl2::get_error(), NO_ERROR);

            // FIXME(pcwalton): Recycle these for speed?
            glXDestroyPixmap(glx_display, glx_pixmap);
        }
    }

    /// This may only be called on the painting side.
    #[fixed_stack_segment]
    fn upload(&self, graphics_context: &NativePaintingGraphicsContext, data: &[u8]) {
        unsafe {
            // Ensure that we're running on the render task. Take the display.
            let pixmap = self.pixmap;

            // Figure out the width, height, and depth of the pixmap.
            let mut root_window = 0;
            let mut x = 0;
            let mut y = 0;
            let mut width = 0;
            let mut height = 0;
            let mut border_width = 0;
            let mut depth = 0;
            let _ = XGetGeometry(graphics_context.display,
                                 cast::transmute(pixmap),
                                 &mut root_window,
                                 &mut x,
                                 &mut y,
                                 &mut width,
                                 &mut height,
                                 &mut border_width,
                                 &mut depth);

            // Create the image.
            let image = XCreateImage(graphics_context.display,
                                     (*graphics_context.visual_info).visual,
                                     depth,
                                     ZPixmap,
                                     0,
                                     cast::transmute(&data[0]),
                                     width as c_uint,
                                     height as c_uint,
                                     32,
                                     0);

            // Create the X graphics context.
            let gc = XCreateGC(graphics_context.display, pixmap, 0, ptr::null());

            // Draw the image.
            let _ = XPutImage(graphics_context.display,
                              pixmap,
                              gc,
                              image,
                              0,
                              0,
                              0,
                              0,
                              width,
                              height);
        }
    }

    fn get_id(&self) -> int {
        self.pixmap as int
    }

    #[fixed_stack_segment]
    fn destroy(&mut self, graphics_context: &NativePaintingGraphicsContext) {
        unsafe {
            assert!(self.pixmap != 0);
            XFreePixmap(graphics_context.display, self.pixmap);
            self.mark_wont_leak()
        }
    }

    fn mark_will_leak(&mut self) {
        self.will_leak = true
    }

    fn mark_wont_leak(&mut self) {
        self.will_leak = false
    }
}

<|endoftext|>