<commit_before>#![crate_name = "cat"]
#![feature(unsafe_destructor)]

/*
 * 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::io::{print, File};
use std::io::stdio::{stdout_raw, stdin_raw, stderr};
use std::io::{IoResult};
use std::ptr::{copy_nonoverlapping_memory};

pub fn uumain(args: Vec<String>) -> int {
    let program = args[0].as_slice();
    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)
    };
    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).as_slice());
        println!("");
        println!("With no FILE, or when FILE is -, read standard input.");
        return 0;
    }
    if matches.opt_present("version") {
        println!("cat 1.0.0");
        return 0;
    }

    let mut number_mode = NumberNone;
    if matches.opt_present("n") {
        number_mode = NumberAll;
    }
    if matches.opt_present("b") {
        number_mode = NumberNonEmpty;
    }
    let show_nonprint = matches.opts_present(["A".to_string(), "e".to_string(),
                                              "t".to_string(), "v".to_string()]);
    let show_ends = matches.opts_present(["E".to_string(), "A".to_string(),
                                          "e".to_string()]);
    let show_tabs = matches.opts_present(["A".to_string(), "T".to_string(),
                                          "t".to_string()]);
    let squeeze_blank = matches.opt_present("s");
    let mut files = matches.free;
    if files.is_empty() {
        files.push("-".to_string());
    }

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

    0
}

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

fn write_lines(files: Vec<String>, number: NumberingMode, squeeze_blank: bool,
               show_ends: bool) {

    let mut line_counter: uint = 1;

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

        let mut in_buf  = [0, .. 1024 * 31];
        let mut out_buf = [0, .. 1024 * 64];
        let mut writer = UnsafeWriter::new(out_buf.as_mut_slice(), stdout_raw());
        let mut at_line_start = true;
        loop {
            let n = match reader.read(in_buf) {
                Ok(n) if n != 0 => n,
                _ => break,
            };
            let in_buf = in_buf.slice_to(n);
            let mut buf_pos = range(0, n);
            loop {
                writer.possibly_flush();
                let pos = match buf_pos.next() {
                    Some(p) => p,
                    None => break,
                };
                if in_buf[pos] == '\n' as u8 {
                    if !at_line_start || !squeeze_blank {
                        if at_line_start && number == NumberAll {
                            (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    continue;
                }
                if at_line_start && number != NumberNone {
                    (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                    line_counter += 1;
                }
                match in_buf.slice_from(pos).iter().position(|c| *c == '\n' as u8) {
                    Some(p) => {
                        writer.write(in_buf.slice(pos, pos + p)).unwrap();
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                        buf_pos = range(pos + p + 1, n);
                        at_line_start = true;
                    },
                    None => {
                        writer.write(in_buf.slice_from(pos)).unwrap();
                        at_line_start = false;
                        break;
                    }
                };
            }
        }
    }
}

fn write_bytes(files: Vec<String>, number: NumberingMode, squeeze_blank: bool,
               show_ends: bool, show_nonprint: bool, show_tabs: bool) {

    let mut line_counter: uint = 1;

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

        // Flush all 1024 iterations.
        let mut flush_counter = range(0u, 1024);

        let mut in_buf  = [0, .. 1024 * 32];
        let mut out_buf = [0, .. 1024 * 64];
        let mut writer = UnsafeWriter::new(out_buf.as_mut_slice(), stdout_raw());
        let mut at_line_start = true;
        loop {
            let n = match reader.read(in_buf) {
                Ok(n) if n != 0 => n,
                _ => break,
            };
            for &byte in in_buf.slice_to(n).iter() {
                if flush_counter.next().is_none() {
                    writer.possibly_flush();
                    flush_counter = range(0u, 1024);
                }
                if byte == '\n' as u8 {
                    if !at_line_start || !squeeze_blank {
                        if at_line_start && number == NumberAll {
                            (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    continue;
                }
                if at_line_start && number != NumberNone {
                    (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                    line_counter += 1;
                    at_line_start = false;
                }
                // This code is slow because of the many branches. cat in glibc avoids
                // this by having the whole loop inside show_nonprint.
                if byte == '\t' as u8 {
                    if show_tabs {
                        writer.write_str("^I")
                    } else {
                        writer.write_u8(byte)
                    }
                } else if show_nonprint {
                    let byte = match byte {
                        128 .. 255 => {
                            writer.write_str("M-").unwrap();
                            byte - 128
                        },
                        _ => byte,
                    };
                    match byte {
                        0 .. 31 => writer.write(['^' as u8, byte + 64]),
                        127     => writer.write(['^' as u8, byte - 64]),
                        _       => writer.write_u8(byte),
                    }
                } else {
                    writer.write_u8(byte)
                }.unwrap();
            }
        }
    }
}

fn write_fast(files: Vec<String>) {
    let mut writer = stdout_raw();
    let mut in_buf = [0, .. 1024 * 64];

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

        loop {
            match reader.read(in_buf) {
                Ok(n) if n != 0 => {
                    // This interface is completely broken.
                    writer.write(in_buf.slice_to(n)).unwrap();
                },
                _ => break
            }
        }
    }
}

fn exec(files: Vec<String>, number: NumberingMode, show_nonprint: bool,
        show_ends: bool, show_tabs: bool, squeeze_blank: bool) {

    if show_nonprint || show_tabs {
        write_bytes(files, number, squeeze_blank, show_ends, show_nonprint, show_tabs);
    } else if number != NumberNone || squeeze_blank || show_ends {
        write_lines(files, number, squeeze_blank, show_ends);
    } else {
        write_fast(files);
    }
}

fn open(path: &str) -> Option<(Box<Reader>, bool)> {
    if path == "-" {
        let stdin = stdin_raw();
        let interactive = stdin.isatty();
        return Some((box stdin as Box<Reader>, interactive));
    }

    match File::open(&std::path::Path::new(path)) {
        Ok(f) => Some((box f as Box<Reader>, false)),
        Err(e) => {
            (writeln!(stderr(), "cat: {0:s}: {1:s}", path, e.to_string())).unwrap();
            None
        },
    }
}

struct UnsafeWriter<'a, W> {
    inner: W,
    buf: &'a mut [u8],
    pos: uint,
    threshold: uint,
}

impl<'a, W: Writer> UnsafeWriter<'a, W> {
    fn new(buf: &'a mut [u8], inner: W) -> UnsafeWriter<'a, W> {
        let threshold = buf.len()/2;
        UnsafeWriter {
            inner: inner,
            buf: buf,
            pos: 0,
            threshold: threshold,
        }
    }

    fn flush_buf(&mut self) -> IoResult<()> {
        if self.pos != 0 {
            let ret = self.inner.write(self.buf.slice_to(self.pos));
            self.pos = 0;
            ret
        } else {
            Ok(())
        }
    }

    fn possibly_flush(&mut self) {
        if self.pos > self.threshold {
            self.inner.write(self.buf.slice_to(self.pos)).unwrap();
            self.pos = 0;
        }
    }
}

#[inline(never)]
fn fail() -> ! {
    fail!("assertion failed");
}

impl<'a, W: Writer> Writer for UnsafeWriter<'a, W> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        let dst = self.buf.slice_from_mut(self.pos);
        if buf.len() > dst.len() {
            fail();
        }
        unsafe {
            copy_nonoverlapping_memory(dst.as_mut_ptr(), buf.as_ptr(), buf.len())
        }
        self.pos += buf.len();
        Ok(())
    }

    fn flush(&mut self) -> IoResult<()> {
        self.flush_buf().and_then(|()| self.inner.flush())
    }
}

#[unsafe_destructor]
impl<'a, W: Writer> Drop for UnsafeWriter<'a, W> {
    fn drop(&mut self) {
        let _ = self.flush_buf();
    }
}

/* vim: set ai ts=4 sw=4 sts=4 et : */
<commit_msg>cat: range pattern now should use three dots.<commit_after>#![crate_name = "cat"]
#![feature(unsafe_destructor)]

/*
 * 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::io::{print, File};
use std::io::stdio::{stdout_raw, stdin_raw, stderr};
use std::io::{IoResult};
use std::ptr::{copy_nonoverlapping_memory};

pub fn uumain(args: Vec<String>) -> int {
    let program = args[0].as_slice();
    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)
    };
    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).as_slice());
        println!("");
        println!("With no FILE, or when FILE is -, read standard input.");
        return 0;
    }
    if matches.opt_present("version") {
        println!("cat 1.0.0");
        return 0;
    }

    let mut number_mode = NumberNone;
    if matches.opt_present("n") {
        number_mode = NumberAll;
    }
    if matches.opt_present("b") {
        number_mode = NumberNonEmpty;
    }
    let show_nonprint = matches.opts_present(["A".to_string(), "e".to_string(),
                                              "t".to_string(), "v".to_string()]);
    let show_ends = matches.opts_present(["E".to_string(), "A".to_string(),
                                          "e".to_string()]);
    let show_tabs = matches.opts_present(["A".to_string(), "T".to_string(),
                                          "t".to_string()]);
    let squeeze_blank = matches.opt_present("s");
    let mut files = matches.free;
    if files.is_empty() {
        files.push("-".to_string());
    }

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

    0
}

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

fn write_lines(files: Vec<String>, number: NumberingMode, squeeze_blank: bool,
               show_ends: bool) {

    let mut line_counter: uint = 1;

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

        let mut in_buf  = [0, .. 1024 * 31];
        let mut out_buf = [0, .. 1024 * 64];
        let mut writer = UnsafeWriter::new(out_buf.as_mut_slice(), stdout_raw());
        let mut at_line_start = true;
        loop {
            let n = match reader.read(in_buf) {
                Ok(n) if n != 0 => n,
                _ => break,
            };
            let in_buf = in_buf.slice_to(n);
            let mut buf_pos = range(0, n);
            loop {
                writer.possibly_flush();
                let pos = match buf_pos.next() {
                    Some(p) => p,
                    None => break,
                };
                if in_buf[pos] == '\n' as u8 {
                    if !at_line_start || !squeeze_blank {
                        if at_line_start && number == NumberAll {
                            (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    continue;
                }
                if at_line_start && number != NumberNone {
                    (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                    line_counter += 1;
                }
                match in_buf.slice_from(pos).iter().position(|c| *c == '\n' as u8) {
                    Some(p) => {
                        writer.write(in_buf.slice(pos, pos + p)).unwrap();
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                        buf_pos = range(pos + p + 1, n);
                        at_line_start = true;
                    },
                    None => {
                        writer.write(in_buf.slice_from(pos)).unwrap();
                        at_line_start = false;
                        break;
                    }
                };
            }
        }
    }
}

fn write_bytes(files: Vec<String>, number: NumberingMode, squeeze_blank: bool,
               show_ends: bool, show_nonprint: bool, show_tabs: bool) {

    let mut line_counter: uint = 1;

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

        // Flush all 1024 iterations.
        let mut flush_counter = range(0u, 1024);

        let mut in_buf  = [0, .. 1024 * 32];
        let mut out_buf = [0, .. 1024 * 64];
        let mut writer = UnsafeWriter::new(out_buf.as_mut_slice(), stdout_raw());
        let mut at_line_start = true;
        loop {
            let n = match reader.read(in_buf) {
                Ok(n) if n != 0 => n,
                _ => break,
            };
            for &byte in in_buf.slice_to(n).iter() {
                if flush_counter.next().is_none() {
                    writer.possibly_flush();
                    flush_counter = range(0u, 1024);
                }
                if byte == '\n' as u8 {
                    if !at_line_start || !squeeze_blank {
                        if at_line_start && number == NumberAll {
                            (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    continue;
                }
                if at_line_start && number != NumberNone {
                    (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                    line_counter += 1;
                    at_line_start = false;
                }
                // This code is slow because of the many branches. cat in glibc avoids
                // this by having the whole loop inside show_nonprint.
                if byte == '\t' as u8 {
                    if show_tabs {
                        writer.write_str("^I")
                    } else {
                        writer.write_u8(byte)
                    }
                } else if show_nonprint {
                    let byte = match byte {
                        128 ... 255 => {
                            writer.write_str("M-").unwrap();
                            byte - 128
                        },
                        _ => byte,
                    };
                    match byte {
                        0 ... 31 => writer.write(['^' as u8, byte + 64]),
                        127      => writer.write(['^' as u8, byte - 64]),
                        _        => writer.write_u8(byte),
                    }
                } else {
                    writer.write_u8(byte)
                }.unwrap();
            }
        }
    }
}

fn write_fast(files: Vec<String>) {
    let mut writer = stdout_raw();
    let mut in_buf = [0, .. 1024 * 64];

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

        loop {
            match reader.read(in_buf) {
                Ok(n) if n != 0 => {
                    // This interface is completely broken.
                    writer.write(in_buf.slice_to(n)).unwrap();
                },
                _ => break
            }
        }
    }
}

fn exec(files: Vec<String>, number: NumberingMode, show_nonprint: bool,
        show_ends: bool, show_tabs: bool, squeeze_blank: bool) {

    if show_nonprint || show_tabs {
        write_bytes(files, number, squeeze_blank, show_ends, show_nonprint, show_tabs);
    } else if number != NumberNone || squeeze_blank || show_ends {
        write_lines(files, number, squeeze_blank, show_ends);
    } else {
        write_fast(files);
    }
}

fn open(path: &str) -> Option<(Box<Reader>, bool)> {
    if path == "-" {
        let stdin = stdin_raw();
        let interactive = stdin.isatty();
        return Some((box stdin as Box<Reader>, interactive));
    }

    match File::open(&std::path::Path::new(path)) {
        Ok(f) => Some((box f as Box<Reader>, false)),
        Err(e) => {
            (writeln!(stderr(), "cat: {0:s}: {1:s}", path, e.to_string())).unwrap();
            None
        },
    }
}

struct UnsafeWriter<'a, W> {
    inner: W,
    buf: &'a mut [u8],
    pos: uint,
    threshold: uint,
}

impl<'a, W: Writer> UnsafeWriter<'a, W> {
    fn new(buf: &'a mut [u8], inner: W) -> UnsafeWriter<'a, W> {
        let threshold = buf.len()/2;
        UnsafeWriter {
            inner: inner,
            buf: buf,
            pos: 0,
            threshold: threshold,
        }
    }

    fn flush_buf(&mut self) -> IoResult<()> {
        if self.pos != 0 {
            let ret = self.inner.write(self.buf.slice_to(self.pos));
            self.pos = 0;
            ret
        } else {
            Ok(())
        }
    }

    fn possibly_flush(&mut self) {
        if self.pos > self.threshold {
            self.inner.write(self.buf.slice_to(self.pos)).unwrap();
            self.pos = 0;
        }
    }
}

#[inline(never)]
fn fail() -> ! {
    fail!("assertion failed");
}

impl<'a, W: Writer> Writer for UnsafeWriter<'a, W> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        let dst = self.buf.slice_from_mut(self.pos);
        if buf.len() > dst.len() {
            fail();
        }
        unsafe {
            copy_nonoverlapping_memory(dst.as_mut_ptr(), buf.as_ptr(), buf.len())
        }
        self.pos += buf.len();
        Ok(())
    }

    fn flush(&mut self) -> IoResult<()> {
        self.flush_buf().and_then(|()| self.inner.flush())
    }
}

#[unsafe_destructor]
impl<'a, W: Writer> Drop for UnsafeWriter<'a, W> {
    fn drop(&mut self) {
        let _ = self.flush_buf();
    }
}

/* vim: set ai ts=4 sw=4 sts=4 et : */
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{Display, Formatter};
use std::fmt::Error as FmtError;

/// Error codes
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum AfError {
    /// The function returned successfully
    SUCCESS            =   0,
    // 100-199 Errors in environment
    /// The system or device ran out of memory
    ERR_NO_MEM         = 101,
    /// There was an error in the device driver
    ERR_DRIVER         = 102,
    /// There was an error with the runtime environment
    ERR_RUNTIME        = 103,
    // 200-299 Errors in input parameters
    /// The input array is not a valid af_array object
    ERR_INVALID_ARRAY  = 201,
    /// One of the function arguments is incorrect
    ERR_ARG            = 202,
    /// The size is incorrect
    ERR_SIZE           = 203,
    /// The type is not suppported by this function
    ERR_TYPE           = 204,
    /// The type of the input arrays are not compatible
    ERR_DIFF_TYPE      = 205,
    /// Function does not support GFOR / batch mode
    ERR_BATCH          = 207,
    /// Input does not belong to the current device
    ERR_DEVICE         = 208,
    // 300-399 Errors for missing software features
    /// The option is not supported
    ERR_NOT_SUPPORTED  = 301,
    /// This build of ArrayFire does not support this feature
    ERR_NOT_CONFIGURED = 302,
    // 400-499 Errors for missing hardware features
    /// This device does not support double
    ERR_NO_DBL         = 401,
    /// This build of ArrayFire was not built with graphics or this device does
    /// not support graphics
    ERR_NO_GFX         = 402,
    // 900-999 Errors from upstream libraries and runtimes
    /// There was an internal error either in ArrayFire or in a project
    /// upstream
    ERR_INTERNAL       = 998,
    /// Unknown Error
    ERR_UNKNOWN        = 999
}

/// Compute/Acceleration Backend
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Backend {
    /// Default backend order: OpenCL -> CUDA -> CPU
    DEFAULT = 0,
    /// CPU a.k.a sequential algorithms
    CPU     = 1,
    /// CUDA Compute Backend
    CUDA    = 2,
    /// OpenCL Compute Backend
    OPENCL  = 4
}

impl Display for Backend {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        let text = match *self {
            Backend::OPENCL  => "OpenCL",
            Backend::CUDA    => "Cuda",
            Backend::CPU     => "CPU",
            Backend::DEFAULT => "Default",
        };
        write!(f, "{}", text)
    }
}

impl Display for AfError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{}", self.description())
    }
}

impl Error for AfError {
    fn description(&self) -> &str {
        match *self {
            AfError::SUCCESS => "Function returned successfully",
            AfError::ERR_NO_MEM => "The system or device ran out of memory",
            AfError::ERR_DRIVER => "Device driver error",
            AfError::ERR_RUNTIME => "Error in runtime environment",
            AfError::ERR_INVALID_ARRAY => "Input is not a valid Array Object",
            AfError::ERR_ARG => "One of the function arguments is incorrect",
            AfError::ERR_SIZE => "The size is incorrect",
            AfError::ERR_TYPE => "The type is not supported by this function",
            AfError::ERR_DIFF_TYPE => "The type of input arrays are not compatible",
            AfError::ERR_BATCH => "Function does not support GFOR / batch mode",
            AfError::ERR_DEVICE => "Array does not belong to device",
            AfError::ERR_NOT_SUPPORTED => "The option is not supported",
            AfError::ERR_NOT_CONFIGURED => "This build of ArrayFire does not support this feature",
            AfError::ERR_NO_DBL => "This device does not support double",
            AfError::ERR_NO_GFX => "This build of ArrayFire was not built with graphics or this device does not support graphics",
            AfError::ERR_INTERNAL => "There was an internal error in either ArrayFire or upstream project",
            AfError::ERR_UNKNOWN => "Unkown Error",
        }
    }
}

/// Types of Array data type
#[derive(Copy, Clone)]
pub enum Aftype {
    /// 32 bit float
    F32 = 0,
    /// 32 bit complex float
    C32 = 1,
    /// 64 bit float
    F64 = 2,
    /// 64 bit complex float
    C64 = 3,
    /// 8 bit boolean
    B8  = 4,
    /// 32 bit signed integer
    S32 = 5,
    /// 32 bit unsigned integer
    U32 = 6,
    /// 8 bit unsigned integer
    U8  = 7,
    /// 64 bit signed integer
    S64 = 8,
    /// 64 bit unsigned integer
    U64 = 9,
    /// 16 bit signed integer
    S16 = 10,
    /// 16 bit unsigned integer
    U16 = 11,
}

/// Dictates the interpolation method to be used by a function
#[derive(Copy, Clone)]
pub enum InterpType {
    /// Nearest Neighbor interpolation method
    NEAREST = 0,
    /// Linear interpolation method
    LINEAR  = 1,
    /// Bilinear interpolation method
    BILINEAR= 2,
    /// Cubic interpolation method
    CUBIC   = 3,
}

/// Helps determine how to pad kernels along borders
#[derive(Copy, Clone)]
pub enum BorderType {
    /// Pad using zeros
    ZERO = 0,
    /// Pad using mirrored values along border
    SYMMETRIC = 1,
}

/// Used by `regions` function to identify type of connectivity
#[derive(Copy, Clone)]
pub enum Connectivity {
    /// North-East-South-West (N-E-S-W) connectivity from given pixel/point
    FOUR = 4,
    /// N-NE-E-SE-S-SW-W-NW connectivity from given pixel/point
    EIGHT = 8
}

/// Helps determine the size of output of convolution
#[derive(Copy, Clone)]
pub enum ConvMode {
    /// Default convolution mode where output size is same as input size
    DEFAULT = 0,
    /// Output of convolution is expanded based on signal and filter sizes
    EXPAND  = 1,
}

/// Helps determine if convolution is in Spatial or Frequency domain
#[derive(Copy, Clone)]
pub enum ConvDomain {
    /// ArrayFire chooses whether the convolution will be in spatial domain or frequency domain
    AUTO     = 0,
    /// Convoltion in spatial domain
    SPATIAL  = 1,
    /// Convolution in frequency domain
    FREQUENCY= 2,
}

/// Error metric used by `matchTemplate` function
#[derive(Copy, Clone)]
pub enum MatchType {
    /// Sum of Absolute Differences
    SAD = 0,
    /// Zero-mean Sum of Absolute Differences
    ZSAD= 1,
    /// Locally scaled Sum of Absolute Differences
    LSAD= 2,
    /// Sum of Squared Differences
    SSD = 3,
    /// Zero-mean Sum of Squared Differences
    ZSSD= 4,
    /// Localy scaled Sum of Squared Differences
    LSSD= 5,
    /// Normalized Cross Correlation
    NCC = 6,
    /// Zero-mean Normalized Cross Correlation
    ZNCC= 7,
    /// Sum of Hamming Distances
    SHD = 8,
}

/// Identify the color space of given image(Array)
#[derive(Copy, Clone)]
pub enum ColorSpace {
    /// Grayscale color space
    GRAY = 0,
    /// Red-Green-Blue color space
    RGB  = 1,
    /// Hue-Saturation-value color space
    HSV  = 2,
}

/// Helps determine the type of a Matrix
#[derive(Copy, Clone)]
pub enum MatProp {
    /// Default (no-op)
    NONE,
    /// Data needs to be transposed
    TRANS,
    /// Data needs to be conjugate transposed
    CTRANS,
    /// Matrix is upper triangular
    UPPER,
    /// Matrix is lower triangular
    LOWER,
    /// Matrix diagonal has unitary values
    DIAGUNIT,
    /// Matrix is symmetric
    SYM,
    /// Matrix is positive definite
    POSDEF,
    /// Matrix is orthogonal
    ORTHOG,
    /// Matrix is tri-diagonal
    TRIDIAG,
    /// Matrix is block-diagonal
    BLOCKDIAG,
}

/// Norm type
#[allow(non_camel_case_types)]
#[derive(Copy, Clone)]
pub enum NormType {
    /// Treats input as a vector and return sum of absolute values
    VECTOR_1    = 0,
    /// Treats input as vector and return max of absolute values
    VECTOR_INF  = 1,
    /// Treats input as vector and returns euclidean norm
    VECTOR_2    = 2,
    /// Treats input as vector and returns the p-norm
    VECTOR_P    = 3,
    /// Return the max of column sums
    MATRIX_1    = 4,
    /// Return the max of row sums
    MATRIX_INF  = 5,
    /// Returns the max singular value (Currently not supported)
    MATRIX_2    = 6,
    /// Returns Lpq-norm
    MATRIX_L_PQ = 7,
}

/// Dictates what color map is used for Image rendering
#[repr(C)]
#[derive(Copy, Clone)]
pub enum ColorMap {
    /// Default color map is grayscale range [0-1]
    DEFAULT = 0,
    /// Visible spectrum color map
    SPECTRUM= 1,
    /// Colors
    COLORS  = 2,
    /// Red hue map
    RED     = 3,
    /// Mood color map
    MOOD    = 4,
    /// Heat color map
    HEAT    = 5,
    /// Blue hue map
    BLUE    = 6,
}

/// YCbCr Standards
#[repr(C)]
#[derive(Copy, Clone)]
pub enum YCCStd {
    /// ITU-R BT.601 (formerly CCIR 601) standard
    YCC_601 = 601,
    /// ITU-R BT.709 standard
    YCC_709 = 709,
    /// ITU-R BT.2020 standard
    YCC_2020 = 2020,
}

/// Homography type
#[repr(C)]
#[derive(Copy, Clone)]
pub enum HomographyType {
    /// RANdom SAmple Consensus algorithm
    RANSAC = 0,
    /// Least Median of Squares
    LMEDS  = 1,
}

/// Plotting markers
#[repr(C)]
#[derive(Copy, Clone)]
pub enum MarkerType {
    NONE     = 0,
    POINT    = 1,
    CIRCLE   = 2,
    SQUARE   = 3,
    TRIANGLE = 4,
    CROSS    = 5,
    PLUS     = 6,
    STAR     = 7
}
<commit_msg>add clone and partialeq to all enums<commit_after>use std::error::Error;
use std::fmt::{Display, Formatter};
use std::fmt::Error as FmtError;

/// Error codes
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum AfError {
    /// The function returned successfully
    SUCCESS            =   0,
    // 100-199 Errors in environment
    /// The system or device ran out of memory
    ERR_NO_MEM         = 101,
    /// There was an error in the device driver
    ERR_DRIVER         = 102,
    /// There was an error with the runtime environment
    ERR_RUNTIME        = 103,
    // 200-299 Errors in input parameters
    /// The input array is not a valid af_array object
    ERR_INVALID_ARRAY  = 201,
    /// One of the function arguments is incorrect
    ERR_ARG            = 202,
    /// The size is incorrect
    ERR_SIZE           = 203,
    /// The type is not suppported by this function
    ERR_TYPE           = 204,
    /// The type of the input arrays are not compatible
    ERR_DIFF_TYPE      = 205,
    /// Function does not support GFOR / batch mode
    ERR_BATCH          = 207,
    /// Input does not belong to the current device
    ERR_DEVICE         = 208,
    // 300-399 Errors for missing software features
    /// The option is not supported
    ERR_NOT_SUPPORTED  = 301,
    /// This build of ArrayFire does not support this feature
    ERR_NOT_CONFIGURED = 302,
    // 400-499 Errors for missing hardware features
    /// This device does not support double
    ERR_NO_DBL         = 401,
    /// This build of ArrayFire was not built with graphics or this device does
    /// not support graphics
    ERR_NO_GFX         = 402,
    // 900-999 Errors from upstream libraries and runtimes
    /// There was an internal error either in ArrayFire or in a project
    /// upstream
    ERR_INTERNAL       = 998,
    /// Unknown Error
    ERR_UNKNOWN        = 999
}

/// Compute/Acceleration Backend
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Backend {
    /// Default backend order: OpenCL -> CUDA -> CPU
    DEFAULT = 0,
    /// CPU a.k.a sequential algorithms
    CPU     = 1,
    /// CUDA Compute Backend
    CUDA    = 2,
    /// OpenCL Compute Backend
    OPENCL  = 4
}

impl Display for Backend {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        let text = match *self {
            Backend::OPENCL  => "OpenCL",
            Backend::CUDA    => "Cuda",
            Backend::CPU     => "CPU",
            Backend::DEFAULT => "Default",
        };
        write!(f, "{}", text)
    }
}

impl Display for AfError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{}", self.description())
    }
}

impl Error for AfError {
    fn description(&self) -> &str {
        match *self {
            AfError::SUCCESS => "Function returned successfully",
            AfError::ERR_NO_MEM => "The system or device ran out of memory",
            AfError::ERR_DRIVER => "Device driver error",
            AfError::ERR_RUNTIME => "Error in runtime environment",
            AfError::ERR_INVALID_ARRAY => "Input is not a valid Array Object",
            AfError::ERR_ARG => "One of the function arguments is incorrect",
            AfError::ERR_SIZE => "The size is incorrect",
            AfError::ERR_TYPE => "The type is not supported by this function",
            AfError::ERR_DIFF_TYPE => "The type of input arrays are not compatible",
            AfError::ERR_BATCH => "Function does not support GFOR / batch mode",
            AfError::ERR_DEVICE => "Array does not belong to device",
            AfError::ERR_NOT_SUPPORTED => "The option is not supported",
            AfError::ERR_NOT_CONFIGURED => "This build of ArrayFire does not support this feature",
            AfError::ERR_NO_DBL => "This device does not support double",
            AfError::ERR_NO_GFX => "This build of ArrayFire was not built with graphics or this device does not support graphics",
            AfError::ERR_INTERNAL => "There was an internal error in either ArrayFire or upstream project",
            AfError::ERR_UNKNOWN => "Unkown Error",
        }
    }
}

/// Types of Array data type
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Aftype {
    /// 32 bit float
    F32 = 0,
    /// 32 bit complex float
    C32 = 1,
    /// 64 bit float
    F64 = 2,
    /// 64 bit complex float
    C64 = 3,
    /// 8 bit boolean
    B8  = 4,
    /// 32 bit signed integer
    S32 = 5,
    /// 32 bit unsigned integer
    U32 = 6,
    /// 8 bit unsigned integer
    U8  = 7,
    /// 64 bit signed integer
    S64 = 8,
    /// 64 bit unsigned integer
    U64 = 9,
    /// 16 bit signed integer
    S16 = 10,
    /// 16 bit unsigned integer
    U16 = 11,
}

/// Dictates the interpolation method to be used by a function
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum InterpType {
    /// Nearest Neighbor interpolation method
    NEAREST = 0,
    /// Linear interpolation method
    LINEAR  = 1,
    /// Bilinear interpolation method
    BILINEAR= 2,
    /// Cubic interpolation method
    CUBIC   = 3,
}

/// Helps determine how to pad kernels along borders
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum BorderType {
    /// Pad using zeros
    ZERO = 0,
    /// Pad using mirrored values along border
    SYMMETRIC = 1,
}

/// Used by `regions` function to identify type of connectivity
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Connectivity {
    /// North-East-South-West (N-E-S-W) connectivity from given pixel/point
    FOUR = 4,
    /// N-NE-E-SE-S-SW-W-NW connectivity from given pixel/point
    EIGHT = 8
}

/// Helps determine the size of output of convolution
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ConvMode {
    /// Default convolution mode where output size is same as input size
    DEFAULT = 0,
    /// Output of convolution is expanded based on signal and filter sizes
    EXPAND  = 1,
}

/// Helps determine if convolution is in Spatial or Frequency domain
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ConvDomain {
    /// ArrayFire chooses whether the convolution will be in spatial domain or frequency domain
    AUTO     = 0,
    /// Convoltion in spatial domain
    SPATIAL  = 1,
    /// Convolution in frequency domain
    FREQUENCY= 2,
}

/// Error metric used by `matchTemplate` function
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum MatchType {
    /// Sum of Absolute Differences
    SAD = 0,
    /// Zero-mean Sum of Absolute Differences
    ZSAD= 1,
    /// Locally scaled Sum of Absolute Differences
    LSAD= 2,
    /// Sum of Squared Differences
    SSD = 3,
    /// Zero-mean Sum of Squared Differences
    ZSSD= 4,
    /// Localy scaled Sum of Squared Differences
    LSSD= 5,
    /// Normalized Cross Correlation
    NCC = 6,
    /// Zero-mean Normalized Cross Correlation
    ZNCC= 7,
    /// Sum of Hamming Distances
    SHD = 8,
}

/// Identify the color space of given image(Array)
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ColorSpace {
    /// Grayscale color space
    GRAY = 0,
    /// Red-Green-Blue color space
    RGB  = 1,
    /// Hue-Saturation-value color space
    HSV  = 2,
}

/// Helps determine the type of a Matrix
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum MatProp {
    /// Default (no-op)
    NONE,
    /// Data needs to be transposed
    TRANS,
    /// Data needs to be conjugate transposed
    CTRANS,
    /// Matrix is upper triangular
    UPPER,
    /// Matrix is lower triangular
    LOWER,
    /// Matrix diagonal has unitary values
    DIAGUNIT,
    /// Matrix is symmetric
    SYM,
    /// Matrix is positive definite
    POSDEF,
    /// Matrix is orthogonal
    ORTHOG,
    /// Matrix is tri-diagonal
    TRIDIAG,
    /// Matrix is block-diagonal
    BLOCKDIAG,
}

/// Norm type
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum NormType {
    /// Treats input as a vector and return sum of absolute values
    VECTOR_1    = 0,
    /// Treats input as vector and return max of absolute values
    VECTOR_INF  = 1,
    /// Treats input as vector and returns euclidean norm
    VECTOR_2    = 2,
    /// Treats input as vector and returns the p-norm
    VECTOR_P    = 3,
    /// Return the max of column sums
    MATRIX_1    = 4,
    /// Return the max of row sums
    MATRIX_INF  = 5,
    /// Returns the max singular value (Currently not supported)
    MATRIX_2    = 6,
    /// Returns Lpq-norm
    MATRIX_L_PQ = 7,
}

/// Dictates what color map is used for Image rendering
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ColorMap {
    /// Default color map is grayscale range [0-1]
    DEFAULT = 0,
    /// Visible spectrum color map
    SPECTRUM= 1,
    /// Colors
    COLORS  = 2,
    /// Red hue map
    RED     = 3,
    /// Mood color map
    MOOD    = 4,
    /// Heat color map
    HEAT    = 5,
    /// Blue hue map
    BLUE    = 6,
}

/// YCbCr Standards
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum YCCStd {
    /// ITU-R BT.601 (formerly CCIR 601) standard
    YCC_601 = 601,
    /// ITU-R BT.709 standard
    YCC_709 = 709,
    /// ITU-R BT.2020 standard
    YCC_2020 = 2020,
}

/// Homography type
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum HomographyType {
    /// RANdom SAmple Consensus algorithm
    RANSAC = 0,
    /// Least Median of Squares
    LMEDS  = 1,
}

/// Plotting markers
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum MarkerType {
    NONE     = 0,
    POINT    = 1,
    CIRCLE   = 2,
    SQUARE   = 3,
    TRIANGLE = 4,
    CROSS    = 5,
    PLUS     = 6,
    STAR     = 7
}
<|endoftext|>


<commit_before>#[macro_use]
mod macros;
mod error;

use expr::Expr;
use scope::Scope;
use self::error::{ExpandError, ExpandErrorCode};

#[derive(Debug, PartialEq, Clone)]
pub enum Node {
    Number(f64),
    String(String),
    Symbol(String),
    List(Vec<Node>),
}

type ExpandResult = Result<Expr, ExpandError>;

impl Node {
    pub fn expand(&self, scope: &mut Scope) -> ExpandResult {
        match self {
            &Node::Number(n) => {
                Ok(Expr::Number(n))
            },
            &Node::String(ref s) => {
                Ok(Expr::String(s.clone()))
            },
            &Node::Symbol(ref s) => {
                Ok(Expr::Symbol(s.clone()))
            },
            &Node::List(ref l) => {
                if let Node::Symbol(ref n) = l[0] {
                    match &n[..] {
                        "def" => {
                            self.expand_def(scope)
                        },
                        "fn" => {
                            self.expand_fn(scope)
                        },
                        "macro" => {
                            self.expand_macro(scope)
                        },
                        "quote" => {
                            self.expand_quote(scope)
                        },
                        "unquote" => {
                            self.expand_unquote(scope)
                        },
                        _ => {
                            self.expand_call(scope)
                        }
                    }
                } else {
                    Node::error(ExpandErrorCode::UnknownError)
                }
            },
        }
    }

    fn expand_quoted(&self, scope: &mut Scope) -> ExpandResult {
        match self {
            &Node::List(ref l) => {
                if l.len() > 0 && Node::Symbol("unquote".to_string()) == l[0] {
                    self.expand_unquote(scope)
                } else {
                    let mut v = vec![];
                    for i in l {
                        v.push(try!(i.expand_quoted(scope)));
                    }
                    Ok(Expr::List(v))
                }
            },
            _ => {
                self.expand(scope)
            }
        }
    }

    fn expand_def(&self, scope: &mut Scope) -> ExpandResult {
        if let &Node::List(ref l) = self {
            if l.len() == 3 {
                if let Node::Symbol(ref n) = l[1] {
                    Ok(Expr::Def {
                        sym: n.clone(),
                        expr: Box::new(try!(l[2].expand(scope))),
                    })
                } else {
                    Node::error(ExpandErrorCode::UnknownError)
                }
            } else {
                Node::error(ExpandErrorCode::UnknownError)
            }
        } else {
            Node::error(ExpandErrorCode::UnknownError)
        }
    }

    fn expand_fn(&self, scope: &mut Scope) -> ExpandResult {
        if let &Node::List(ref l) = self {
            if l.len() >= 3 {
                if let Node::List(ref params) = l[1] {
                    let mut fn_params = vec![];
                    for p in params {
                        fn_params.push(try!(p.expand(scope)))
                    }
                    let mut fn_body = vec![];
                    for be in &l[2..] {
                        fn_body.push(try!(be.expand(scope)))
                    }
                    Ok(Expr::Fn {
                        params: fn_params,
                        body: fn_body,
                    })
                } else {
                    Node::error(ExpandErrorCode::UnknownError)
                }
            } else {
                Node::error(ExpandErrorCode::UnknownError)
            }
        } else {
            Node::error(ExpandErrorCode::UnknownError)
        }
    }

    fn expand_macro(&self, scope: &mut Scope) -> ExpandResult {
        if let &Node::List(ref l) = self {
            if l.len() >= 3 {
                if let Node::List(ref params) = l[1] {
                    let mut macro_params = vec![];
                    for p in params {
                        macro_params.push(try!(p.expand(scope)))
                    }
                    let mut macro_body = vec![];
                    for be in &l[2..] {
                        macro_body.push(try!(be.expand(scope)))
                    }
                    Ok(Expr::Macro {
                        params: macro_params,
                        body: macro_body,
                    })
                } else {
                    Node::error(ExpandErrorCode::UnknownError)
                }
            } else {
                Node::error(ExpandErrorCode::UnknownError)
            }
        } else {
            Node::error(ExpandErrorCode::UnknownError)
        }
    }

    fn expand_quote(&self, scope: &mut Scope) -> ExpandResult {
        if let &Node::List(ref l) = self {
            if l.len() == 2 {
                Ok(Expr::Call {
                    name: "quote".to_string(),
                    args: vec![try!(l[1].expand_quoted(scope))],
                })
            } else {
                Node::error(ExpandErrorCode::UnknownError)
            }
        } else {
            Node::error(ExpandErrorCode::UnknownError)
        }
    }

    fn expand_unquote(&self, scope: &mut Scope) -> ExpandResult {
        if let &Node::List(ref l) = self {
            if l.len() == 2 {
                Ok(Expr::Call {
                    name: "unquote".to_string(),
                    args: vec![try!(l[1].expand(scope))],
                })
            } else {
                Node::error(ExpandErrorCode::UnknownError)
            }
        } else {
            Node::error(ExpandErrorCode::UnknownError)
        }
    }

    fn expand_call(&self, scope: &mut Scope) -> ExpandResult {
        if let &Node::List(ref l) = self {
            if let Node::Symbol(ref name) = l[0] {
                let mut args = vec![];
                for a in &l[1..] {
                    args.push(try!(a.expand(scope)))
                }
                let call = Expr::Call {
                    name: name.clone(),
                    args: args
                };
                let is_macro = match scope.get(name) {
                    Some(&Expr::Macro { .. }) => true,
                    _ => false
                };
                if is_macro {
                    Ok(try!(call.eval(scope)))
                } else {
                    Ok(call)
                }
            } else {
                Node::error(ExpandErrorCode::UnknownError)
            }
        } else {
            Node::error(ExpandErrorCode::UnknownError)
        }
    }

    fn error(code: ExpandErrorCode) -> ExpandResult {
        Err(ExpandError::new(code))
    }
}

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

    #[test]
    fn test_expand_number() {
        let ref mut scope = Scope::new_std();
        let num = 1_f64;
        assert_eq!(e_number!(num), n_number!(num).expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_string() {
        let ref mut scope = Scope::new_std();
        let s = "rust is wonderful";
        assert_eq!(e_string!(s), n_string!(s).expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_symbol() {
        let ref mut scope = Scope::new_std();
        let s = "+";
        assert_eq!(e_symbol!(s), n_symbol!(s).expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_fn() {
        let ref mut scope = Scope::new_std();
        let e = e_fn!([e_symbol!("a")],
                      [e_call!["+", e_symbol!("a"), e_number!(1_f64)]]);
        let n = n_list![n_symbol!("fn"),
                        n_list![n_symbol!("a")],
                        n_list![n_symbol!("+"), n_symbol!("a"), n_number!(1_f64)]];
        assert_eq!(e, n.expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_macro() {
        let ref mut scope = Scope::new_std();
        let e = e_macro!([e_symbol!("a")],
                         [e_call!["+", e_symbol!("a"), e_number!(1_f64)]]);
        let n = n_list![n_symbol!("macro"),
                        n_list![n_symbol!("a")],
                        n_list![n_symbol!("+"), n_symbol!("a"), n_number!(1_f64)]];
        assert_eq!(e, n.expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_def() {
        let ref mut scope = Scope::new_std();
        let e = e_def!["a", e_number![1_f64]];
        let n = n_list![n_symbol!["def"], n_symbol!["a"], n_number![1_f64]];
        assert_eq!(e, n.expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_call_fn() {
        let ref mut scope = Scope::new_std();
        let e = e_call!["+", e_symbol!["a"], e_number![1_f64]];
        let n = n_list![n_symbol!["+"], n_symbol!["a"], n_number![1_f64]];
        assert_eq!(e, n.expand(scope).ok().unwrap());
    }

    #[test]
    fn expand_call_macro() {
        let ref mut scope = Scope::new_std();
        let m = e_def!["m", e_macro![[e_symbol!["a"], e_symbol!["b"]],
                                     [e_call!["+", e_symbol!["a"], e_symbol!["b"]]]]];
        m.eval(scope).ok().unwrap();
        let e = e_number![3.];
        let n = n_list![n_symbol!["m"], n_number![1.], n_number![2.]];
        assert_eq!(e, n.expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_quote() {
        let ref mut scope = Scope::new_std();
        let n = n_list![n_symbol!["quote"], n_symbol!["a"]];
        assert_eq!(e_call!["quote", e_symbol!["a"]], n.expand(scope).ok().unwrap());
        let n = n_list![n_symbol!["quote"],
                        n_list![n_symbol!["+"], n_symbol!["a"], n_symbol!["b"]]];
        assert_eq!(e_call!["quote", e_list![e_symbol!["+"], e_symbol!["a"], e_symbol!["b"]]],
                   n.expand(scope).ok().unwrap());
    }
}
<commit_msg>Add expand unquote test case<commit_after>#[macro_use]
mod macros;
mod error;

use expr::Expr;
use scope::Scope;
use self::error::{ExpandError, ExpandErrorCode};

#[derive(Debug, PartialEq, Clone)]
pub enum Node {
    Number(f64),
    String(String),
    Symbol(String),
    List(Vec<Node>),
}

type ExpandResult = Result<Expr, ExpandError>;

impl Node {
    pub fn expand(&self, scope: &mut Scope) -> ExpandResult {
        match self {
            &Node::Number(n) => {
                Ok(Expr::Number(n))
            },
            &Node::String(ref s) => {
                Ok(Expr::String(s.clone()))
            },
            &Node::Symbol(ref s) => {
                Ok(Expr::Symbol(s.clone()))
            },
            &Node::List(ref l) => {
                if let Node::Symbol(ref n) = l[0] {
                    match &n[..] {
                        "def" => {
                            self.expand_def(scope)
                        },
                        "fn" => {
                            self.expand_fn(scope)
                        },
                        "macro" => {
                            self.expand_macro(scope)
                        },
                        "quote" => {
                            self.expand_quote(scope)
                        },
                        "unquote" => {
                            self.expand_unquote(scope)
                        },
                        _ => {
                            self.expand_call(scope)
                        }
                    }
                } else {
                    Node::error(ExpandErrorCode::UnknownError)
                }
            },
        }
    }

    fn expand_quoted(&self, scope: &mut Scope) -> ExpandResult {
        match self {
            &Node::List(ref l) => {
                if l.len() > 0 && Node::Symbol("unquote".to_string()) == l[0] {
                    self.expand_unquote(scope)
                } else {
                    let mut v = vec![];
                    for i in l {
                        v.push(try!(i.expand_quoted(scope)));
                    }
                    Ok(Expr::List(v))
                }
            },
            _ => {
                self.expand(scope)
            }
        }
    }

    fn expand_def(&self, scope: &mut Scope) -> ExpandResult {
        if let &Node::List(ref l) = self {
            if l.len() == 3 {
                if let Node::Symbol(ref n) = l[1] {
                    Ok(Expr::Def {
                        sym: n.clone(),
                        expr: Box::new(try!(l[2].expand(scope))),
                    })
                } else {
                    Node::error(ExpandErrorCode::UnknownError)
                }
            } else {
                Node::error(ExpandErrorCode::UnknownError)
            }
        } else {
            Node::error(ExpandErrorCode::UnknownError)
        }
    }

    fn expand_fn(&self, scope: &mut Scope) -> ExpandResult {
        if let &Node::List(ref l) = self {
            if l.len() >= 3 {
                if let Node::List(ref params) = l[1] {
                    let mut fn_params = vec![];
                    for p in params {
                        fn_params.push(try!(p.expand(scope)))
                    }
                    let mut fn_body = vec![];
                    for be in &l[2..] {
                        fn_body.push(try!(be.expand(scope)))
                    }
                    Ok(Expr::Fn {
                        params: fn_params,
                        body: fn_body,
                    })
                } else {
                    Node::error(ExpandErrorCode::UnknownError)
                }
            } else {
                Node::error(ExpandErrorCode::UnknownError)
            }
        } else {
            Node::error(ExpandErrorCode::UnknownError)
        }
    }

    fn expand_macro(&self, scope: &mut Scope) -> ExpandResult {
        if let &Node::List(ref l) = self {
            if l.len() >= 3 {
                if let Node::List(ref params) = l[1] {
                    let mut macro_params = vec![];
                    for p in params {
                        macro_params.push(try!(p.expand(scope)))
                    }
                    let mut macro_body = vec![];
                    for be in &l[2..] {
                        macro_body.push(try!(be.expand(scope)))
                    }
                    Ok(Expr::Macro {
                        params: macro_params,
                        body: macro_body,
                    })
                } else {
                    Node::error(ExpandErrorCode::UnknownError)
                }
            } else {
                Node::error(ExpandErrorCode::UnknownError)
            }
        } else {
            Node::error(ExpandErrorCode::UnknownError)
        }
    }

    fn expand_quote(&self, scope: &mut Scope) -> ExpandResult {
        if let &Node::List(ref l) = self {
            if l.len() == 2 {
                Ok(Expr::Call {
                    name: "quote".to_string(),
                    args: vec![try!(l[1].expand_quoted(scope))],
                })
            } else {
                Node::error(ExpandErrorCode::UnknownError)
            }
        } else {
            Node::error(ExpandErrorCode::UnknownError)
        }
    }

    fn expand_unquote(&self, scope: &mut Scope) -> ExpandResult {
        if let &Node::List(ref l) = self {
            if l.len() == 2 {
                Ok(Expr::Call {
                    name: "unquote".to_string(),
                    args: vec![try!(l[1].expand(scope))],
                })
            } else {
                Node::error(ExpandErrorCode::UnknownError)
            }
        } else {
            Node::error(ExpandErrorCode::UnknownError)
        }
    }

    fn expand_call(&self, scope: &mut Scope) -> ExpandResult {
        if let &Node::List(ref l) = self {
            if let Node::Symbol(ref name) = l[0] {
                let mut args = vec![];
                for a in &l[1..] {
                    args.push(try!(a.expand(scope)))
                }
                let call = Expr::Call {
                    name: name.clone(),
                    args: args
                };
                let is_macro = match scope.get(name) {
                    Some(&Expr::Macro { .. }) => true,
                    _ => false
                };
                if is_macro {
                    Ok(try!(call.eval(scope)))
                } else {
                    Ok(call)
                }
            } else {
                Node::error(ExpandErrorCode::UnknownError)
            }
        } else {
            Node::error(ExpandErrorCode::UnknownError)
        }
    }

    fn error(code: ExpandErrorCode) -> ExpandResult {
        Err(ExpandError::new(code))
    }
}

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

    #[test]
    fn test_expand_number() {
        let ref mut scope = Scope::new_std();
        let num = 1_f64;
        assert_eq!(e_number!(num), n_number!(num).expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_string() {
        let ref mut scope = Scope::new_std();
        let s = "rust is wonderful";
        assert_eq!(e_string!(s), n_string!(s).expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_symbol() {
        let ref mut scope = Scope::new_std();
        let s = "+";
        assert_eq!(e_symbol!(s), n_symbol!(s).expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_fn() {
        let ref mut scope = Scope::new_std();
        let e = e_fn!([e_symbol!("a")],
                      [e_call!["+", e_symbol!("a"), e_number!(1_f64)]]);
        let n = n_list![n_symbol!("fn"),
                        n_list![n_symbol!("a")],
                        n_list![n_symbol!("+"), n_symbol!("a"), n_number!(1_f64)]];
        assert_eq!(e, n.expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_macro() {
        let ref mut scope = Scope::new_std();
        let e = e_macro!([e_symbol!("a")],
                         [e_call!["+", e_symbol!("a"), e_number!(1_f64)]]);
        let n = n_list![n_symbol!("macro"),
                        n_list![n_symbol!("a")],
                        n_list![n_symbol!("+"), n_symbol!("a"), n_number!(1_f64)]];
        assert_eq!(e, n.expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_def() {
        let ref mut scope = Scope::new_std();
        let e = e_def!["a", e_number![1_f64]];
        let n = n_list![n_symbol!["def"], n_symbol!["a"], n_number![1_f64]];
        assert_eq!(e, n.expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_call_fn() {
        let ref mut scope = Scope::new_std();
        let e = e_call!["+", e_symbol!["a"], e_number![1_f64]];
        let n = n_list![n_symbol!["+"], n_symbol!["a"], n_number![1_f64]];
        assert_eq!(e, n.expand(scope).ok().unwrap());
    }

    #[test]
    fn expand_call_macro() {
        let ref mut scope = Scope::new_std();
        let m = e_def!["m", e_macro![[e_symbol!["a"], e_symbol!["b"]],
                                     [e_call!["+", e_symbol!["a"], e_symbol!["b"]]]]];
        m.eval(scope).ok().unwrap();
        let e = e_number![3.];
        let n = n_list![n_symbol!["m"], n_number![1.], n_number![2.]];
        assert_eq!(e, n.expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_quote() {
        let ref mut scope = Scope::new_std();
        let n = n_list![n_symbol!["quote"], n_symbol!["a"]];
        assert_eq!(e_call!["quote", e_symbol!["a"]], n.expand(scope).ok().unwrap());
        let n = n_list![n_symbol!["quote"],
                        n_list![n_symbol!["+"], n_symbol!["a"], n_symbol!["b"]]];
        assert_eq!(e_call!["quote", e_list![e_symbol!["+"], e_symbol!["a"], e_symbol!["b"]]],
                   n.expand(scope).ok().unwrap());
    }

    #[test]
    fn test_expand_unquote() {
        let ref mut scope = Scope::new_std();
        let n = n_list![n_symbol!["quote"], n_list![n_symbol!["a"],
                                                    n_list![n_symbol!["unquote"], n_symbol!["b"]]]];
        let expected_result = e_call!["quote", e_list![e_symbol!["a"],
                                               e_call!["unquote", e_symbol!["b"]]]];
        assert_eq!(expected_result, n.expand(scope).ok().unwrap());
    }
}
<|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.

// this file defines CGFloat, as well as stubbed data types.
extern crate core_foundation;

pub use libc;
pub use base::{CGError, boolean_t};
pub use geometry::{CGRect, CGPoint, CGSize};

pub type CGDirectDisplayID = libc::uint32_t;
pub type CGWindowID        = libc::uint32_t;

pub const kCGNullWindowID: CGWindowID = 0 as CGWindowID;

pub const kCGWindowListOptionAll:          libc::uint32_t        = 0;
pub const kCGWindowListOptionOnScreenOnly: libc::uint32_t        = 1 << 0;
pub const kCGWindowListOptionOnScreenAboveWindow: libc::uint32_t = 1 << 1;
pub const kCGWindowListOptionOnScreenBelowWindow: libc::uint32_t = 1 << 2;
pub const kCGWindowListOptionIncludingWindow:  libc::uint32_t    = 1 << 3;
pub const kCGWindowListExcludeDesktopElements: libc::uint32_t    = 1 << 4;

pub enum CGWindowListOption {
    kCGWindowListOptionAll,
    kCGWindowListOptionOnScreenOnly,
    kCGWindowListOptionOnScreenAboveWindow,
    kCGWindowListOptionOnScreenBelowWindow,
    kCGWindowListOptionIncludingWindow,
    kCGWindowListExcludeDesktopElements,
}

pub use core_foundation::dictionary::{ CFDictionary, CFDictionaryRef };
pub use core_foundation::array::{ CFArray, CFArrayRef };

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    pub fn CGMainDisplayID() -> CGDirectDisplayID;
    pub fn CGDisplayIsActive(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAlwaysInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAsleep(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsBuiltin(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInHWMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsMain(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsOnline(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsStereo(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayMirrorsDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayPrimaryDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayRotation(display: CGDirectDisplayID) -> libc::c_double;
    pub fn CGDisplayScreenSize(display: CGDirectDisplayID) -> CGSize;
    pub fn CGDisplaySerialNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUnitNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUsesOpenGLAcceleration(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayVendorNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGGetActiveDisplayList(max_displays: libc::uint32_t,
                                  active_displays: *mut CGDirectDisplayID,
                                  display_count: *mut libc::uint32_t) -> CGError;
    pub fn CGDisplayModelNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayPixelsHigh(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayPixelsWide(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayBounds(display: CGDirectDisplayID) -> CGRect;

    // mouse stuff
    pub fn CGDisplayHideCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayShowCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayMoveCursorToPoint(display: CGDirectDisplayID, point: CGPoint) -> CGError;
    pub fn CGWarpMouseCursorPosition(point: CGPoint) -> CGError;
    pub fn CGAssociateMouseAndMouseCursorPosition(connected: bool) -> CGError;

    // Window Services Reference
    pub fn CGWindowListCopyWindowInfo(option: CGWindowListOption, relativeToWindow: CGWindowID ) -> CFArrayRef;

}
<commit_msg>add some display api.<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.

// this file defines CGFloat, as well as stubbed data types.
extern crate core_foundation;
// extern crate core_foundation_sys;

pub use libc;
pub use base::{CGError, boolean_t};
pub use geometry::{CGRect, CGPoint, CGSize};

pub type CGDirectDisplayID = libc::uint32_t;
pub type CGWindowID        = libc::uint32_t;

pub const kCGNullWindowID: CGWindowID = 0 as CGWindowID;

pub type CGWindowListOption = libc::uint32_t;

pub const kCGWindowListOptionAll:              CGWindowListOption    = 0;
pub const kCGWindowListOptionOnScreenOnly:     CGWindowListOption    = 1 << 0;
pub const kCGWindowListOptionOnScreenAboveWindow: CGWindowListOption = 1 << 1;
pub const kCGWindowListOptionOnScreenBelowWindow: CGWindowListOption = 1 << 2;
pub const kCGWindowListOptionIncludingWindow:  CGWindowListOption    = 1 << 3;
pub const kCGWindowListExcludeDesktopElements: CGWindowListOption    = 1 << 4;

pub use core_foundation::dictionary::{ CFDictionary, CFDictionaryRef, CFDictionaryGetValueIfPresent };
pub use core_foundation::array::{ CFArray, CFArrayRef };
pub use core_foundation::array::{ CFArrayGetCount, CFArrayGetValueAtIndex };
pub use core_foundation::base::{  CFIndex, CFRelease, CFTypeRef };

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    pub fn CGMainDisplayID() -> CGDirectDisplayID;
    pub fn CGDisplayIsActive(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAlwaysInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAsleep(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsBuiltin(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInHWMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsMain(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsOnline(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsStereo(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayMirrorsDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayPrimaryDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayRotation(display: CGDirectDisplayID) -> libc::c_double;
    pub fn CGDisplayScreenSize(display: CGDirectDisplayID) -> CGSize;
    pub fn CGDisplaySerialNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUnitNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUsesOpenGLAcceleration(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayVendorNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGGetActiveDisplayList(max_displays: libc::uint32_t,
                                  active_displays: *mut CGDirectDisplayID,
                                  display_count: *mut libc::uint32_t) -> CGError;
    pub fn CGDisplayModelNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayPixelsHigh(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayPixelsWide(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayBounds(display: CGDirectDisplayID) -> CGRect;

    // mouse stuff
    pub fn CGDisplayHideCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayShowCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayMoveCursorToPoint(display: CGDirectDisplayID, point: CGPoint) -> CGError;
    pub fn CGWarpMouseCursorPosition(point: CGPoint) -> CGError;
    pub fn CGAssociateMouseAndMouseCursorPosition(connected: bool) -> CGError;

    // Window Services Reference
    pub fn CGWindowListCopyWindowInfo(option: CGWindowListOption, relativeToWindow: CGWindowID ) -> CFArrayRef;

}
<|endoftext|>


<commit_before>
use ndarray::*;
use ndarray_linalg::*;
use super::traits::*;

pub struct TimeSeries<'a, TEO, S>
    where S: DataMut,
          TEO: TimeEvolution + 'a
{
    state: ArrayBase<S, TEO::Dim>,
    buf: TEO::Buffer,
    teo: &'a TEO,
}

pub fn time_series<'a, TEO, S>(x0: ArrayBase<S, TEO::Dim>, teo: &'a TEO) -> TimeSeries<'a, TEO, S>
    where S: DataMut,
          TEO: TimeEvolution
{
    TimeSeries {
        state: x0,
        buf: teo.new_buffer(),
        teo: teo,
    }
}

impl<'a, TEO, A, S> TimeSeries<'a, TEO, S>
    where A: Scalar,
          S: DataMut<Elem = A> + DataClone,
          TEO: TimeEvolution<Scalar = A>
{
    pub fn iterate(&mut self) {
        self.teo.iterate(&mut self.state, &mut self.buf);
    }
}

impl<'a, TEO, A, S> Iterator for TimeSeries<'a, TEO, S>
    where A: Scalar,
          S: DataMut<Elem = A> + DataClone,
          TEO: TimeEvolution<Scalar = A>
{
    type Item = ArrayBase<S, TEO::Dim>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iterate();
        Some(self.state.clone())
    }
}

/// N-step adaptor
///
/// ```rust
/// use eom::*;
/// let teo = explicit::rk4(ode::Lorenz63::default(), 0.01);
/// let nstep = nstep(teo, 10);
/// ```
pub struct NStep<TEO> {
    teo: TEO,
    n: usize,
}

pub fn nstep<TEO>(teo: TEO, n: usize) -> NStep<TEO> {
    NStep { teo, n }
}

impl<TEO> ModelSpec for NStep<TEO>
    where TEO: ModelSpec
{
    type Scalar = TEO::Scalar;
    type Dim = TEO::Dim;

    fn model_size(&self) -> <Self::Dim as Dimension>::Pattern {
        self.teo.model_size()
    }
}

impl<TEO> TimeStep for NStep<TEO>
    where TEO: TimeStep
{
    type Time = TEO::Time;

    fn get_dt(&self) -> Self::Time {
        self.teo.get_dt() * into_scalar(self.n as f64)
    }

    fn set_dt(&mut self, dt: Self::Time) {
        self.teo.set_dt(dt / into_scalar(self.n as f64));
    }
}

impl<TEO> BufferSpec for NStep<TEO>
    where TEO: BufferSpec
{
    type Buffer = TEO::Buffer;
    fn new_buffer(&self) -> Self::Buffer {
        self.teo.new_buffer()
    }
}

impl<TEO> TimeEvolution for NStep<TEO>
    where TEO: TimeEvolution
{
    fn iterate<'a, S>(&self,
                      x: &'a mut ArrayBase<S, TEO::Dim>,
                      buf: &mut Self::Buffer)
                      -> &'a mut ArrayBase<S, TEO::Dim>
        where S: DataMut<Elem = TEO::Scalar>
    {
        for _ in 0..self.n {
            self.teo.iterate(x, buf);
        }
        x
    }
}
<commit_msg>Drop buffer from adaptor<commit_after>
use ndarray::*;
use ndarray_linalg::*;
use super::traits::*;

pub struct TimeSeries<'a, TEO, S>
    where S: DataMut,
          TEO: TimeEvolution + 'a
{
    state: ArrayBase<S, TEO::Dim>,
    teo: &'a mut TEO,
}

pub fn time_series<'a, TEO, S>(x0: ArrayBase<S, TEO::Dim>,
                               teo: &'a mut TEO)
                               -> TimeSeries<'a, TEO, S>
    where S: DataMut,
          TEO: TimeEvolution
{
    TimeSeries {
        state: x0,
        teo: teo,
    }
}

impl<'a, TEO, A, S> TimeSeries<'a, TEO, S>
    where A: Scalar,
          S: DataMut<Elem = A> + DataClone,
          TEO: TimeEvolution<Scalar = A>
{
    pub fn iterate(&mut self) {
        self.teo.iterate(&mut self.state);
    }
}

impl<'a, TEO, A, S> Iterator for TimeSeries<'a, TEO, S>
    where A: Scalar,
          S: DataMut<Elem = A> + DataClone,
          TEO: TimeEvolution<Scalar = A>
{
    type Item = ArrayBase<S, TEO::Dim>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iterate();
        Some(self.state.clone())
    }
}

/// N-step adaptor
///
/// ```rust
/// use eom::*;
/// let teo = explicit::rk4(ode::Lorenz63::default(), 0.01);
/// let nstep = nstep(teo, 10);
/// ```
pub struct NStep<TEO> {
    teo: TEO,
    n: usize,
}

pub fn nstep<TEO>(teo: TEO, n: usize) -> NStep<TEO> {
    NStep { teo, n }
}

impl<TEO> ModelSpec for NStep<TEO>
    where TEO: ModelSpec
{
    type Scalar = TEO::Scalar;
    type Dim = TEO::Dim;

    fn model_size(&self) -> <Self::Dim as Dimension>::Pattern {
        self.teo.model_size()
    }
}

impl<TEO> TimeStep for NStep<TEO>
    where TEO: TimeStep
{
    type Time = TEO::Time;

    fn get_dt(&self) -> Self::Time {
        self.teo.get_dt() * into_scalar(self.n as f64)
    }

    fn set_dt(&mut self, dt: Self::Time) {
        self.teo.set_dt(dt / into_scalar(self.n as f64));
    }
}

impl<TEO> TimeEvolution for NStep<TEO>
    where TEO: TimeEvolution
{
    fn iterate<'a, S>(&mut self,
                      x: &'a mut ArrayBase<S, TEO::Dim>)
                      -> &'a mut ArrayBase<S, TEO::Dim>
        where S: DataMut<Elem = TEO::Scalar>
    {
        for _ in 0..self.n {
            self.teo.iterate(x);
        }
        x
    }
}
<|endoftext|>


<commit_before>//! Simple module to store files in database.
//!
//! cratesfyi is generating more than 5 million files, they are small and mostly html files.
//! They are using so many inodes and it is better to store them in database instead of
//! filesystem. This module is adding files into database and retrieving them.

use std::path::{PathBuf, Path};
use postgres::Connection;
use rustc_serialize::json::{Json, ToJson};
use std::fs;
use std::io::Read;
use error::Result;
use failure::err_msg;
use rusoto_s3::{S3, PutObjectRequest, GetObjectRequest, S3Client};
use rusoto_core::region::Region;
use rusoto_credential::EnvironmentProvider;

fn get_file_list_from_dir<P: AsRef<Path>>(path: P,
                                          files: &mut Vec<PathBuf>)
                                          -> Result<()> {
    let path = path.as_ref();

    for file in try!(path.read_dir()) {
        let file = try!(file);

        if try!(file.file_type()).is_file() {
            files.push(file.path());
        } else if try!(file.file_type()).is_dir() {
            try!(get_file_list_from_dir(file.path(), files));
        }
    }

    Ok(())
}

pub fn get_file_list<P: AsRef<Path>>(path: P) -> Result<Vec<PathBuf>> {
    let path = path.as_ref();
    let mut files = Vec::new();

    if !path.exists() {
        return Err(err_msg("File not found"));
    } else if path.is_file() {
        files.push(PathBuf::from(path.file_name().unwrap()));
    } else if path.is_dir() {
        try!(get_file_list_from_dir(path, &mut files));
        for file_path in &mut files {
            // We want the paths in this list to not be {path}/bar.txt but just bar.txt
            *file_path = PathBuf::from(file_path.strip_prefix(path).unwrap());
        }
    }

    Ok(files)
}

pub struct Blob {
    pub path: String,
    pub mime: String,
    pub date_updated: time::Timespec,
    pub content: Vec<u8>,
}

pub fn get_path(conn: &Connection, path: &str) -> Option<Blob> {
    if let Some(client) = s3_client() {
        let res = client.get_object(GetObjectRequest {
            bucket: "rust-docs-rs".into(),
            key: path.into(),
            ..Default::default()
        }).sync();

        let res = match res {
            Ok(r) => r,
            Err(err) => {
                return None;
            }
        };

        let mut b = res.body.unwrap().into_blocking_read();
        let mut content = Vec::new();
        b.read_to_end(&mut content).unwrap();

        let last_modified = res.last_modified.unwrap();
        let last_modified = time::strptime(&last_modified, "%a, %d %b %Y %H:%M:%S %Z")
            .unwrap_or_else(|e| panic!("failed to parse {:?} as timespec: {:?}", last_modified, e))
            .to_timespec();

        Some(Blob {
            path: path.into(),
            mime: res.content_type.unwrap(),
            date_updated: last_modified,
            content,
        })
    } else {
        let rows = conn.query("SELECT path, mime, date_updated, content
                            FROM files
                            WHERE path = $1", &[&path]).unwrap();

        if rows.len() == 0 {
            None
        } else {
            let row = rows.get(0);

            Some(Blob {
                path: row.get(0),
                mime: row.get(1),
                date_updated: row.get(2),
                content: row.get(3),
            })
        }
    }
}

fn s3_client() -> Option<S3Client> {
    // If AWS keys aren't configured, then presume we should use the DB exclusively
    // for file storage.
    if std::env::var_os("AWS_ACCESS_KEY_ID").is_none() {
        return None;
    }
    Some(S3Client::new_with(
        rusoto_core::request::HttpClient::new().unwrap(),
        EnvironmentProvider::default(),
        std::env::var("S3_ENDPOINT").ok().map(|e| Region::Custom {
            name: "us-west-1".to_owned(),
            endpoint: e,
        }).unwrap_or(Region::UsWest1),
    ))
}

/// Adds files into database and returns list of files with their mime type in Json
pub fn add_path_into_database<P: AsRef<Path>>(conn: &Connection,
                                              prefix: &str,
                                              path: P)
                                              -> Result<Json> {
    use magic::{Cookie, flags};
    let cookie = try!(Cookie::open(flags::MIME_TYPE));
    try!(cookie.load::<&str>(&[]));

    let trans = try!(conn.transaction());
    let mut client = s3_client();
    let mut file_list_with_mimes: Vec<(String, PathBuf)> = Vec::new();

    for file_path in try!(get_file_list(&path)) {
        let (path, content, mime) = {
            let path = Path::new(path.as_ref()).join(&file_path);
            // Some files have insufficient permissions (like .lock file created by cargo in
            // documentation directory). We are skipping this files.
            let mut file = match fs::File::open(path) {
                Ok(f) => f,
                Err(_) => continue,
            };
            let mut content: Vec<u8> = Vec::new();
            try!(file.read_to_end(&mut content));
            let bucket_path = Path::new(prefix).join(&file_path)
                .into_os_string().into_string().unwrap();

            let mime = {
                let mime = try!(cookie.buffer(&content));
                // css's are causing some problem in browsers
                // magic will return text/plain for css file types
                // convert them to text/css
                // do the same for javascript files
                if mime == "text/plain" {
                    let e = file_path.extension().unwrap_or_default();
                    if e == "css" {
                        "text/css".to_owned()
                    } else if e == "js" {
                        "application/javascript".to_owned()
                    } else {
                        mime.to_owned()
                    }
                } else {
                    mime.to_owned()
                }
            };

            let content: Option<Vec<u8>> = if let Some(client) = &mut client {
                let mut attempts = 0;
                loop {
                    let s3_res = client.put_object(PutObjectRequest {
                        bucket: "rust-docs-rs".into(),
                        key: bucket_path.clone(),
                        body: Some(content.clone().into()),
                        content_type: Some(mime.clone()),
                        ..Default::default()
                    }).sync();
                    attempts += 1;
                    match s3_res {
                        // we've successfully uploaded the content, so steal it;
                        // we don't want to put it in the DB
                        Ok(_) => break None,
                        // Since s3 was configured, we want to panic on failure to upload.
                        Err(e) => {
                            log::error!("failed to upload to {}: {:?}", bucket_path, e);
                            // Get a new client, in case the old one's connection is stale.
                            // AWS will kill our connection if it's alive for too long; this avoids
                            // that preventing us from building the crate entirely.
                            *client = s3_client().unwrap();
                            if attempts > 3 {
                                panic!("failed to upload 3 times, exiting");
                            } else {
                                continue;
                            }
                        },
                    }
                }
            } else {
                Some(content.clone().into())
            };

            file_list_with_mimes.push((mime.clone(), file_path.clone()));

            (
                bucket_path,
                content,
                mime,
            )
        };

        // If AWS credentials are configured, don't insert/update the database
        if client.is_none() {
            // check if file already exists in database
            let rows = try!(conn.query("SELECT COUNT(*) FROM files WHERE path = $1", &[&path]));

            let content = content.expect("content never None if client is None");

            if rows.get(0).get::<usize, i64>(0) == 0 {
                try!(trans.query("INSERT INTO files (path, mime, content) VALUES ($1, $2, $3)",
                                &[&path, &mime, &content]));
            } else {
                try!(trans.query("UPDATE files SET mime = $2, content = $3, date_updated = NOW() \
                                WHERE path = $1",
                                &[&path, &mime, &content]));
            }
        }
    }

    try!(trans.commit());

    file_list_to_json(file_list_with_mimes)
}

fn file_list_to_json(file_list: Vec<(String, PathBuf)>) -> Result<Json> {

    let mut file_list_json: Vec<Json> = Vec::new();

    for file in file_list {
        let mut v: Vec<String> = Vec::new();
        v.push(file.0.clone());
        v.push(file.1.into_os_string().into_string().unwrap());
        file_list_json.push(v.to_json());
    }

    Ok(file_list_json.to_json())
}

pub fn move_to_s3(conn: &Connection, n: usize) -> Result<usize> {
    let trans = try!(conn.transaction());
    let client = s3_client().expect("configured s3");

    let rows = try!(trans.query(
            &format!("SELECT path, mime, content FROM files WHERE content != E'in-s3' LIMIT {}", n),
            &[]));
    let count = rows.len();

    let mut rt = ::tokio::runtime::current_thread::Runtime::new().unwrap();
    let mut futures = Vec::new();
    for row in &rows {
        let path: String = row.get(0);
        let mime: String = row.get(1);
        let content: Vec<u8> = row.get(2);
        let path_1 = path.clone();
        futures.push(client.put_object(PutObjectRequest {
            bucket: "rust-docs-rs".into(),
            key: path.clone(),
            body: Some(content.into()),
            content_type: Some(mime),
            ..Default::default()
        }).map(move |_| {
            path_1
        }).map_err(move |e| {
            panic!("failed to upload to {}: {:?}", path, e)
        }));
    }

    use ::futures::future::Future;
    match rt.block_on(::futures::future::join_all(futures)) {
        Ok(paths) => {
            let statement = trans.prepare("DELETE FROM files WHERE path = $1").unwrap();
            for path in paths {
                statement.execute(&[&path]).unwrap();
            }
        }
        Err(e) => {
            panic!("results err: {:?}", e);
        }
    }

    try!(trans.commit());

    Ok(count)
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use std::env;
    use super::get_file_list;

    #[test]
    fn test_get_file_list() {
        let _ = env_logger::try_init();

        let files = get_file_list(env::current_dir().unwrap());
        assert!(files.is_ok());
        assert!(files.unwrap().len() > 0);

        let files = get_file_list(env::current_dir().unwrap().join("Cargo.toml")).unwrap();
        assert_eq!(files[0], std::path::Path::new("Cargo.toml"));
    }
}
<commit_msg>Remove unused variable<commit_after>//! Simple module to store files in database.
//!
//! cratesfyi is generating more than 5 million files, they are small and mostly html files.
//! They are using so many inodes and it is better to store them in database instead of
//! filesystem. This module is adding files into database and retrieving them.

use std::path::{PathBuf, Path};
use postgres::Connection;
use rustc_serialize::json::{Json, ToJson};
use std::fs;
use std::io::Read;
use error::Result;
use failure::err_msg;
use rusoto_s3::{S3, PutObjectRequest, GetObjectRequest, S3Client};
use rusoto_core::region::Region;
use rusoto_credential::EnvironmentProvider;

fn get_file_list_from_dir<P: AsRef<Path>>(path: P,
                                          files: &mut Vec<PathBuf>)
                                          -> Result<()> {
    let path = path.as_ref();

    for file in try!(path.read_dir()) {
        let file = try!(file);

        if try!(file.file_type()).is_file() {
            files.push(file.path());
        } else if try!(file.file_type()).is_dir() {
            try!(get_file_list_from_dir(file.path(), files));
        }
    }

    Ok(())
}

pub fn get_file_list<P: AsRef<Path>>(path: P) -> Result<Vec<PathBuf>> {
    let path = path.as_ref();
    let mut files = Vec::new();

    if !path.exists() {
        return Err(err_msg("File not found"));
    } else if path.is_file() {
        files.push(PathBuf::from(path.file_name().unwrap()));
    } else if path.is_dir() {
        try!(get_file_list_from_dir(path, &mut files));
        for file_path in &mut files {
            // We want the paths in this list to not be {path}/bar.txt but just bar.txt
            *file_path = PathBuf::from(file_path.strip_prefix(path).unwrap());
        }
    }

    Ok(files)
}

pub struct Blob {
    pub path: String,
    pub mime: String,
    pub date_updated: time::Timespec,
    pub content: Vec<u8>,
}

pub fn get_path(conn: &Connection, path: &str) -> Option<Blob> {
    if let Some(client) = s3_client() {
        let res = client.get_object(GetObjectRequest {
            bucket: "rust-docs-rs".into(),
            key: path.into(),
            ..Default::default()
        }).sync();

        let res = match res {
            Ok(r) => r,
            Err(_) => {
                return None;
            }
        };

        let mut b = res.body.unwrap().into_blocking_read();
        let mut content = Vec::new();
        b.read_to_end(&mut content).unwrap();

        let last_modified = res.last_modified.unwrap();
        let last_modified = time::strptime(&last_modified, "%a, %d %b %Y %H:%M:%S %Z")
            .unwrap_or_else(|e| panic!("failed to parse {:?} as timespec: {:?}", last_modified, e))
            .to_timespec();

        Some(Blob {
            path: path.into(),
            mime: res.content_type.unwrap(),
            date_updated: last_modified,
            content,
        })
    } else {
        let rows = conn.query("SELECT path, mime, date_updated, content
                            FROM files
                            WHERE path = $1", &[&path]).unwrap();

        if rows.len() == 0 {
            None
        } else {
            let row = rows.get(0);

            Some(Blob {
                path: row.get(0),
                mime: row.get(1),
                date_updated: row.get(2),
                content: row.get(3),
            })
        }
    }
}

fn s3_client() -> Option<S3Client> {
    // If AWS keys aren't configured, then presume we should use the DB exclusively
    // for file storage.
    if std::env::var_os("AWS_ACCESS_KEY_ID").is_none() {
        return None;
    }
    Some(S3Client::new_with(
        rusoto_core::request::HttpClient::new().unwrap(),
        EnvironmentProvider::default(),
        std::env::var("S3_ENDPOINT").ok().map(|e| Region::Custom {
            name: "us-west-1".to_owned(),
            endpoint: e,
        }).unwrap_or(Region::UsWest1),
    ))
}

/// Adds files into database and returns list of files with their mime type in Json
pub fn add_path_into_database<P: AsRef<Path>>(conn: &Connection,
                                              prefix: &str,
                                              path: P)
                                              -> Result<Json> {
    use magic::{Cookie, flags};
    let cookie = try!(Cookie::open(flags::MIME_TYPE));
    try!(cookie.load::<&str>(&[]));

    let trans = try!(conn.transaction());
    let mut client = s3_client();
    let mut file_list_with_mimes: Vec<(String, PathBuf)> = Vec::new();

    for file_path in try!(get_file_list(&path)) {
        let (path, content, mime) = {
            let path = Path::new(path.as_ref()).join(&file_path);
            // Some files have insufficient permissions (like .lock file created by cargo in
            // documentation directory). We are skipping this files.
            let mut file = match fs::File::open(path) {
                Ok(f) => f,
                Err(_) => continue,
            };
            let mut content: Vec<u8> = Vec::new();
            try!(file.read_to_end(&mut content));
            let bucket_path = Path::new(prefix).join(&file_path)
                .into_os_string().into_string().unwrap();

            let mime = {
                let mime = try!(cookie.buffer(&content));
                // css's are causing some problem in browsers
                // magic will return text/plain for css file types
                // convert them to text/css
                // do the same for javascript files
                if mime == "text/plain" {
                    let e = file_path.extension().unwrap_or_default();
                    if e == "css" {
                        "text/css".to_owned()
                    } else if e == "js" {
                        "application/javascript".to_owned()
                    } else {
                        mime.to_owned()
                    }
                } else {
                    mime.to_owned()
                }
            };

            let content: Option<Vec<u8>> = if let Some(client) = &mut client {
                let mut attempts = 0;
                loop {
                    let s3_res = client.put_object(PutObjectRequest {
                        bucket: "rust-docs-rs".into(),
                        key: bucket_path.clone(),
                        body: Some(content.clone().into()),
                        content_type: Some(mime.clone()),
                        ..Default::default()
                    }).sync();
                    attempts += 1;
                    match s3_res {
                        // we've successfully uploaded the content, so steal it;
                        // we don't want to put it in the DB
                        Ok(_) => break None,
                        // Since s3 was configured, we want to panic on failure to upload.
                        Err(e) => {
                            log::error!("failed to upload to {}: {:?}", bucket_path, e);
                            // Get a new client, in case the old one's connection is stale.
                            // AWS will kill our connection if it's alive for too long; this avoids
                            // that preventing us from building the crate entirely.
                            *client = s3_client().unwrap();
                            if attempts > 3 {
                                panic!("failed to upload 3 times, exiting");
                            } else {
                                continue;
                            }
                        },
                    }
                }
            } else {
                Some(content.clone().into())
            };

            file_list_with_mimes.push((mime.clone(), file_path.clone()));

            (
                bucket_path,
                content,
                mime,
            )
        };

        // If AWS credentials are configured, don't insert/update the database
        if client.is_none() {
            // check if file already exists in database
            let rows = try!(conn.query("SELECT COUNT(*) FROM files WHERE path = $1", &[&path]));

            let content = content.expect("content never None if client is None");

            if rows.get(0).get::<usize, i64>(0) == 0 {
                try!(trans.query("INSERT INTO files (path, mime, content) VALUES ($1, $2, $3)",
                                &[&path, &mime, &content]));
            } else {
                try!(trans.query("UPDATE files SET mime = $2, content = $3, date_updated = NOW() \
                                WHERE path = $1",
                                &[&path, &mime, &content]));
            }
        }
    }

    try!(trans.commit());

    file_list_to_json(file_list_with_mimes)
}

fn file_list_to_json(file_list: Vec<(String, PathBuf)>) -> Result<Json> {

    let mut file_list_json: Vec<Json> = Vec::new();

    for file in file_list {
        let mut v: Vec<String> = Vec::new();
        v.push(file.0.clone());
        v.push(file.1.into_os_string().into_string().unwrap());
        file_list_json.push(v.to_json());
    }

    Ok(file_list_json.to_json())
}

pub fn move_to_s3(conn: &Connection, n: usize) -> Result<usize> {
    let trans = try!(conn.transaction());
    let client = s3_client().expect("configured s3");

    let rows = try!(trans.query(
            &format!("SELECT path, mime, content FROM files WHERE content != E'in-s3' LIMIT {}", n),
            &[]));
    let count = rows.len();

    let mut rt = ::tokio::runtime::current_thread::Runtime::new().unwrap();
    let mut futures = Vec::new();
    for row in &rows {
        let path: String = row.get(0);
        let mime: String = row.get(1);
        let content: Vec<u8> = row.get(2);
        let path_1 = path.clone();
        futures.push(client.put_object(PutObjectRequest {
            bucket: "rust-docs-rs".into(),
            key: path.clone(),
            body: Some(content.into()),
            content_type: Some(mime),
            ..Default::default()
        }).map(move |_| {
            path_1
        }).map_err(move |e| {
            panic!("failed to upload to {}: {:?}", path, e)
        }));
    }

    use ::futures::future::Future;
    match rt.block_on(::futures::future::join_all(futures)) {
        Ok(paths) => {
            let statement = trans.prepare("DELETE FROM files WHERE path = $1").unwrap();
            for path in paths {
                statement.execute(&[&path]).unwrap();
            }
        }
        Err(e) => {
            panic!("results err: {:?}", e);
        }
    }

    try!(trans.commit());

    Ok(count)
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use std::env;
    use super::get_file_list;

    #[test]
    fn test_get_file_list() {
        let _ = env_logger::try_init();

        let files = get_file_list(env::current_dir().unwrap());
        assert!(files.is_ok());
        assert!(files.unwrap().len() > 0);

        let files = get_file_list(env::current_dir().unwrap().join("Cargo.toml")).unwrap();
        assert_eq!(files[0], std::path::Path::new("Cargo.toml"));
    }
}
<|endoftext|>