<commit_before>//! History API

use std::collections::VecDeque;
use std::collections::vec_deque;
use std::fs::File;
use std::iter::DoubleEndedIterator;
use std::ops::Index;
use std::path::Path;
#[cfg(unix)]
use libc;

use super::Result;
use config::{Config, HistoryDuplicates};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

/// Current state of the history.
pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new() -> History {
        Self::with_config(Config::default())
    }
    pub fn with_config(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Return the last history entry (i.e. previous command)
    pub fn last(&self) -> Option<&String> {
        self.entries.back()
    }

    /// Add a new entry in the history.
    pub fn add<S: AsRef<str> + Into<String>>(&mut self, line: S) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.as_ref().is_empty() ||
           (self.ignore_space && line.as_ref().chars().next().map_or(true, |c| c.is_whitespace())) {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line.as_ref() {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(line.into());
        true
    }

    /// Returns the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Returns true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is smaller
    /// than the amount of items already inside the history.
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    /// TODO append_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX30
    /// TODO history_truncate_file http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX31
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let old_umask = umask();
        let f = File::create(path);
        restore_umask(old_umask);
        let file = try!(f);
        fix_perm(&file);
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(&entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Failure
    /// Will return `Err` if path does not already exist.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1]).
    /// Return the absolute index of the nearest history entry that matches `term`.
    /// Return None if no entry contains `term` between [start, len -1] for forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(|entry| entry.contains(term));
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
                index.and_then(|index| Some(index + start))
            }
        }
    }

    /// Return a forward iterator.
    pub fn iter(&self) -> Iter {
        Iter(self.entries.iter())
    }
}

impl Index<usize> for History {
    type Output = String;

    fn index(&self, index: usize) -> &String {
        &self.entries[index]
    }
}

impl<'a> IntoIterator for &'a History {
    type Item = &'a String;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// History iterator.
pub struct Iter<'a>(vec_deque::Iter<'a, String>);

impl<'a> Iterator for Iter<'a> {
    type Item = &'a String;

    fn next(&mut self) -> Option<&'a String> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<&'a String> {
        self.0.next_back()
    }
}

#[cfg(windows)]
fn umask() -> u16 {
    0
}
#[cfg(unix)]
fn umask() -> u16 {
    unsafe { libc::umask(libc::S_IXUSR | libc::S_IRWXG | libc::S_IRWXO) }
}
#[cfg(windows)]
fn restore_umask(_: u16) {}
#[cfg(unix)]
fn restore_umask(old_umask: u16) {
    unsafe {
        libc::umask(old_umask);
    }
}

#[cfg(windows)]
fn fix_perm(file: &File) {}
#[cfg(unix)]
fn fix_perm(file: &File) {
    use std::os::unix::io::AsRawFd;
    unsafe {
        libc::fchmod(file.as_raw_fd(), libc::S_IRUSR | libc::S_IWUSR);
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use std::path::Path;
    use config::Config;
    use super::{Direction, History};

    fn init() -> History {
        let mut history = History::new();
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let history = History::new();
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder()
            .history_ignore_space(true)
            .build();
        let mut history = History::with_config(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_string()), history.last());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<commit_msg>Try to fix travis build.<commit_after>//! History API

use std::collections::VecDeque;
use std::collections::vec_deque;
use std::fs::File;
use std::iter::DoubleEndedIterator;
use std::ops::Index;
use std::path::Path;
#[cfg(unix)]
use libc;

use super::Result;
use config::{Config, HistoryDuplicates};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

/// Current state of the history.
pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new() -> History {
        Self::with_config(Config::default())
    }
    pub fn with_config(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Return the last history entry (i.e. previous command)
    pub fn last(&self) -> Option<&String> {
        self.entries.back()
    }

    /// Add a new entry in the history.
    pub fn add<S: AsRef<str> + Into<String>>(&mut self, line: S) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.as_ref().is_empty() ||
           (self.ignore_space && line.as_ref().chars().next().map_or(true, |c| c.is_whitespace())) {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line.as_ref() {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(line.into());
        true
    }

    /// Returns the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Returns true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is smaller
    /// than the amount of items already inside the history.
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    /// TODO append_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX30
    /// TODO history_truncate_file http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX31
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let old_umask = umask();
        let f = File::create(path);
        restore_umask(old_umask);
        let file = try!(f);
        fix_perm(&file);
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(&entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Failure
    /// Will return `Err` if path does not already exist.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1]).
    /// Return the absolute index of the nearest history entry that matches `term`.
    /// Return None if no entry contains `term` between [start, len -1] for forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(|entry| entry.contains(term));
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
                index.and_then(|index| Some(index + start))
            }
        }
    }

    /// Return a forward iterator.
    pub fn iter(&self) -> Iter {
        Iter(self.entries.iter())
    }
}

impl Index<usize> for History {
    type Output = String;

    fn index(&self, index: usize) -> &String {
        &self.entries[index]
    }
}

impl<'a> IntoIterator for &'a History {
    type Item = &'a String;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// History iterator.
pub struct Iter<'a>(vec_deque::Iter<'a, String>);

impl<'a> Iterator for Iter<'a> {
    type Item = &'a String;

    fn next(&mut self) -> Option<&'a String> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<&'a String> {
        self.0.next_back()
    }
}

#[cfg(windows)]
fn umask() -> u16 {
    0
}
#[cfg(unix)]
fn umask() -> libc::mode_t {
    unsafe { libc::umask(libc::S_IXUSR | libc::S_IRWXG | libc::S_IRWXO) }
}
#[cfg(windows)]
fn restore_umask(_: u16) {}
#[cfg(unix)]
fn restore_umask(old_umask: libc::mode_t) {
    unsafe {
        libc::umask(old_umask);
    }
}

#[cfg(windows)]
fn fix_perm(file: &File) {}
#[cfg(unix)]
fn fix_perm(file: &File) {
    use std::os::unix::io::AsRawFd;
    unsafe {
        libc::fchmod(file.as_raw_fd(), libc::S_IRUSR | libc::S_IWUSR);
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use std::path::Path;
    use config::Config;
    use super::{Direction, History};

    fn init() -> History {
        let mut history = History::new();
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let history = History::new();
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder()
            .history_ignore_space(true)
            .build();
        let mut history = History::with_config(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_string()), history.last());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 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.

use point::{TypedPoint2D, TypedPoint3D};
use vector::{TypedVector2D, TypedVector3D};

use num::{One, Zero};

use std::marker::PhantomData;
use std::ops::Div;

define_matrix! {
    /// Homogeneous vector in 3D space.
    pub struct HomogeneousVector<T, U> {
        pub x: T,
        pub y: T,
        pub z: T,
        pub w: T,
    }
}

impl<T, U> HomogeneousVector<T, U> {
    /// Constructor taking scalar values directly.
    #[inline]
    pub fn new(x: T, y: T, z: T, w: T) -> Self {
        HomogeneousVector { x, y, z, w, _unit: PhantomData }
    }
}

impl<T: Copy + Div<T, Output=T>, U> HomogeneousVector<T, U> {
    /// Convert into cartesian 2D point.
    ///
    /// Note: possible division by zero.
    #[inline]
    pub fn to_point2d(&self) -> TypedPoint2D<T, U> {
        TypedPoint2D::new(self.x / self.w, self.y / self.w)
    }

    /// Convert into cartesian 3D point.
    ///
    /// Note: possible division by zero.
    #[inline]
    pub fn to_point3d(&self) -> TypedPoint3D<T, U> {
        TypedPoint3D::new(self.x / self.w, self.y / self.w, self.z / self.w)
    }
}

impl<T: Zero, U> From<TypedVector2D<T, U>> for HomogeneousVector<T, U> {
    #[inline]
    fn from(v: TypedVector2D<T, U>) -> Self {
        HomogeneousVector::new(v.x, v.y, T::zero(), T::zero())
    }
}

impl<T: Zero, U> From<TypedVector3D<T, U>> for HomogeneousVector<T, U> {
    #[inline]
    fn from(v: TypedVector3D<T, U>) -> Self {
        HomogeneousVector::new(v.x, v.y, v.z, T::zero())
    }
}

impl<T: Zero + One, U> From<TypedPoint2D<T, U>> for HomogeneousVector<T, U> {
    #[inline]
    fn from(p: TypedPoint2D<T, U>) -> Self {
        HomogeneousVector::new(p.x, p.y, T::zero(), T::one())
    }
}

impl<T: One, U> From<TypedPoint3D<T, U>> for HomogeneousVector<T, U> {
    #[inline]
    fn from(p: TypedPoint3D<T, U>) -> Self {
        HomogeneousVector::new(p.x, p.y, p.z, T::one())
    }
}

#[cfg(test)]
mod homogeneous {
    use super::HomogeneousVector;
    use point::{Point2D, Point3D};

    #[test]
    fn roundtrip() {
        assert_eq!(Point2D::new(1.0, 2.0), HomogeneousVector::from(Point2D::new(1.0, 2.0)).to_point2d());
        assert_eq!(Point3D::new(1.0, -2.0, 0.1), HomogeneousVector::from(Point3D::new(1.0, -2.0, 0.1)).to_point3d());
    }
}
<commit_msg>Debug+Display on homogeneous vectors<commit_after>// Copyright 2018 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.

use point::{TypedPoint2D, TypedPoint3D};
use vector::{TypedVector2D, TypedVector3D};

use num::{One, Zero};

use std::fmt;
use std::marker::PhantomData;
use std::ops::Div;

define_matrix! {
    /// Homogeneous vector in 3D space.
    pub struct HomogeneousVector<T, U> {
        pub x: T,
        pub y: T,
        pub z: T,
        pub w: T,
    }
}

impl<T, U> HomogeneousVector<T, U> {
    /// Constructor taking scalar values directly.
    #[inline]
    pub fn new(x: T, y: T, z: T, w: T) -> Self {
        HomogeneousVector { x, y, z, w, _unit: PhantomData }
    }
}

impl<T: Copy + Div<T, Output=T>, U> HomogeneousVector<T, U> {
    /// Convert into cartesian 2D point.
    ///
    /// Note: possible division by zero.
    #[inline]
    pub fn to_point2d(&self) -> TypedPoint2D<T, U> {
        TypedPoint2D::new(self.x / self.w, self.y / self.w)
    }

    /// Convert into cartesian 3D point.
    ///
    /// Note: possible division by zero.
    #[inline]
    pub fn to_point3d(&self) -> TypedPoint3D<T, U> {
        TypedPoint3D::new(self.x / self.w, self.y / self.w, self.z / self.w)
    }
}

impl<T: Zero, U> From<TypedVector2D<T, U>> for HomogeneousVector<T, U> {
    #[inline]
    fn from(v: TypedVector2D<T, U>) -> Self {
        HomogeneousVector::new(v.x, v.y, T::zero(), T::zero())
    }
}

impl<T: Zero, U> From<TypedVector3D<T, U>> for HomogeneousVector<T, U> {
    #[inline]
    fn from(v: TypedVector3D<T, U>) -> Self {
        HomogeneousVector::new(v.x, v.y, v.z, T::zero())
    }
}

impl<T: Zero + One, U> From<TypedPoint2D<T, U>> for HomogeneousVector<T, U> {
    #[inline]
    fn from(p: TypedPoint2D<T, U>) -> Self {
        HomogeneousVector::new(p.x, p.y, T::zero(), T::one())
    }
}

impl<T: One, U> From<TypedPoint3D<T, U>> for HomogeneousVector<T, U> {
    #[inline]
    fn from(p: TypedPoint3D<T, U>) -> Self {
        HomogeneousVector::new(p.x, p.y, p.z, T::one())
    }
}

impl<T: fmt::Debug, U> fmt::Debug for HomogeneousVector<T, U> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({:?},{:?},{:?},{:?})", self.x, self.y, self.z, self.w)
    }
}

impl<T: fmt::Display, U> fmt::Display for HomogeneousVector<T, U> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "({},{},{},{})", self.x, self.y, self.z, self.w)
    }
}

#[cfg(test)]
mod homogeneous {
    use super::HomogeneousVector;
    use point::{Point2D, Point3D};

    #[test]
    fn roundtrip() {
        assert_eq!(Point2D::new(1.0, 2.0), HomogeneousVector::from(Point2D::new(1.0, 2.0)).to_point2d());
        assert_eq!(Point3D::new(1.0, -2.0, 0.1), HomogeneousVector::from(Point3D::new(1.0, -2.0, 0.1)).to_point3d());
    }
}
<|endoftext|>


<commit_before>use ansi_term::Colour;
use fern;
use log::{Level, LevelFilter};
use std::io;
use chrono;
use std::env::var;

use error::*;

fn colored_level(level: Level) -> String {
  let color = match level {
    Level::Trace => Colour::Fixed(8),
    Level::Info => Colour::Blue,
    Level::Warn => Colour::Yellow,
    Level::Error => Colour::Red,
    _ => return level.to_string()
  };
  color.paint(level.to_string()).to_string()
}

fn colored_target(target: &str) -> String {
  let parts: Vec<&str> = target.split("::").collect();
  if parts.len() == 1 {
    return target.to_string();
  }
  let base = &parts[..parts.len() - 1];
  let target = &parts[parts.len() - 1];

  let separator = Colour::Fixed(8).paint("::").to_string();
  let mut colored = Vec::new();
  for part in base {
    colored.push(*part);
    colored.push(&separator);
  }
  colored.push(*target);
  colored.join("")
}

pub fn init_logger() -> Result<()> {
  let debug = var("LB_DEBUG").is_ok();
  fern::Dispatch::new()
    .format(|out, message, record| {
      out.finish(format_args!("[{}] [{}] {} – {}",
                              chrono::Local::now().format("%H:%M:%S"),
                              colored_level(record.level()),
                              colored_target(record.target()),
                              message))
    })
    .level(if debug { LevelFilter::Debug } else { LevelFilter::Info })
    .filter(|f| debug || f.level() < Level::Info || f.target().starts_with("lalafell"))
    .chain(io::stdout())
    .apply()
    .chain_err(|| "could not set up logger")
}
<commit_msg>fix: move debug<commit_after>use ansi_term::Colour;
use fern;
use log::{Level, LevelFilter};
use std::io;
use chrono;
use std::env::var;

use error::*;

fn colored_level(level: Level) -> String {
  let color = match level {
    Level::Trace => Colour::Fixed(8),
    Level::Info => Colour::Blue,
    Level::Warn => Colour::Yellow,
    Level::Error => Colour::Red,
    _ => return level.to_string()
  };
  color.paint(level.to_string()).to_string()
}

fn colored_target(target: &str) -> String {
  let parts: Vec<&str> = target.split("::").collect();
  if parts.len() == 1 {
    return target.to_string();
  }
  let base = &parts[..parts.len() - 1];
  let target = &parts[parts.len() - 1];

  let separator = Colour::Fixed(8).paint("::").to_string();
  let mut colored = Vec::new();
  for part in base {
    colored.push(*part);
    colored.push(&separator);
  }
  colored.push(*target);
  colored.join("")
}

pub fn init_logger() -> Result<()> {
  let debug = var("LB_DEBUG").is_ok();
  fern::Dispatch::new()
    .format(|out, message, record| {
      out.finish(format_args!("[{}] [{}] {} – {}",
                              chrono::Local::now().format("%H:%M:%S"),
                              colored_level(record.level()),
                              colored_target(record.target()),
                              message))
    })
    .level(if debug { LevelFilter::Debug } else { LevelFilter::Info })
    .filter(move |f| debug || f.level() < Level::Info || f.target().starts_with("lalafell"))
    .chain(io::stdout())
    .apply()
    .chain_err(|| "could not set up logger")
}
<|endoftext|>


<commit_before>//! Traits, implementations, and macros related to logging timely events.

extern crate time;

use std::cell::RefCell;
use std::io::Write;
use std::fs::File;

use ::Data;

use timely_communication::Allocate;
use ::progress::timestamp::RootTimestamp;
use ::progress::nested::product::Product;

use dataflow::scopes::root::Root;
use dataflow::Scope;
use dataflow::operators::capture::{EventWriter, Event, EventPusher};

use abomonation::Abomonation;

static mut precise_time_ns_delta: Option<i64> = None;

/// Returns the value of an high resolution performance counter, in nanoseconds, rebased to be
/// roughly comparable to an unix timestamp.
/// Useful for comparing and merging logs from different machines (precision is limited by the
/// precision of the wall clock base; clock skew effects should be taken into consideration).
#[inline(always)]
fn get_precise_time_ns() -> u64 {
    (time::precise_time_ns() as i64 - unsafe { precise_time_ns_delta.unwrap() }) as u64
}

/// Logs `record` in `logger` if logging is enabled.
pub fn log<T: Logger>(logger: &'static ::std::thread::LocalKey<T>, record: T::Record) {
    if cfg!(feature = "logging") {
        logger.with(|x| x.log(record));
    }
}

/// Logging methods
pub trait Logger {
    /// The type of loggable record.
    type Record;
    /// Adds `record` to the log.
    fn log(&self, record: Self::Record);
    /// Called with some frequency; behavior unspecified.
    fn flush(&self);
}

/// Logs events to an underlying writer.
pub struct EventStreamLogger<T: Data, S: Write> {
    buffer: RefCell<Vec<(T,u64)>>,
    stream: RefCell<Option<EventWriter<Product<RootTimestamp, u64>, (T,u64), S>>>,
    last_time: RefCell<u64>,
}

impl<T: Data, S: Write> Logger for EventStreamLogger<T, S> {
    type Record = T;
    #[inline]
    fn log(&self, record: T) {
        self.buffer.borrow_mut().push((record, get_precise_time_ns()));
    }
    fn flush(&self) {
        // TODO : sends progress update even if nothing happened.
        // TODO : consider a minimum interval from prior update to
        // TODO : cut down on the amount on logging, at the expense
        // TODO : of freshness on the side of the reader.
        if let Some(ref mut writer) = *self.stream.borrow_mut() {
            let time = get_precise_time_ns();
            if self.buffer.borrow().len() > 0 {
                writer.push(Event::Messages(RootTimestamp::new(*self.last_time.borrow()), self.buffer.borrow().clone()));
            }
            writer.push(Event::Progress(vec![(RootTimestamp::new(*self.last_time.borrow()),-1), (RootTimestamp::new(time), 1)]));
            *self.last_time.borrow_mut() = time;
            self.buffer.borrow_mut().clear();
        }
        else {
            panic!("logging file not initialized!!!!");
        }
    }
}

impl<T: Data, S: Write> EventStreamLogger<T, S> {
    fn new() -> EventStreamLogger<T, S> {
        EventStreamLogger {
            buffer: RefCell::new(Vec::new()),
            stream: RefCell::new(None),
            last_time: RefCell::new(0),
        }
    }
    fn set(&self, stream: S) {
        let mut stream = EventWriter::new(stream);
        stream.push(Event::Progress(vec![(RootTimestamp::new(0), 1)]));
        *self.stream.borrow_mut() = Some(stream);
    }
}

impl<T: Data, S: Write> Drop for EventStreamLogger<T, S> {
    fn drop(&mut self) {
        if let Some(ref mut writer) = *self.stream.borrow_mut() {
            if self.buffer.borrow().len() > 0 {
                writer.push(Event::Messages(RootTimestamp::new(*self.last_time.borrow()), self.buffer.borrow().clone()));
            }
            writer.push(Event::Progress(vec![(RootTimestamp::new(*self.last_time.borrow()),-1)]));
        }
        else {
            panic!("logging file not initialized!!!!");
        }
    }
}

/// Initializes logging; called as part of `Root` initialization.
pub fn initialize<A: Allocate>(root: &mut Root<A>) {

    OPERATES.with(|x| x.set(File::create(format!("logs/operates-{}.abom", root.index())).unwrap()));
    CHANNELS.with(|x| x.set(File::create(format!("logs/channels-{}.abom", root.index())).unwrap()));
    MESSAGES.with(|x| x.set(File::create(format!("logs/messages-{}.abom", root.index())).unwrap()));
    PROGRESS.with(|x| x.set(File::create(format!("logs/progress-{}.abom", root.index())).unwrap()));
    SCHEDULE.with(|x| x.set(File::create(format!("logs/schedule-{}.abom", root.index())).unwrap()));
    GUARDED_MESSAGE.with(|x| x.set(File::create(format!("logs/guarded_message-{}.abom", root.index())).unwrap()));
    GUARDED_PROGRESS.with(|x| x.set(File::create(format!("logs/guarded_progress-{}.abom", root.index())).unwrap()));

    unsafe {
        precise_time_ns_delta = Some({
            let wall_time = time::get_time();
            let wall_time_ns = wall_time.nsec as i64 + wall_time.sec * 1000000000;
            time::precise_time_ns() as i64 - wall_time_ns
        });
    }

}

/// Flushes logs; called by `Root::step`.
pub fn flush_logs() {
    OPERATES.with(|x| x.flush());
    CHANNELS.with(|x| x.flush());
    PROGRESS.with(|x| x.flush());
    MESSAGES.with(|x| x.flush());
    SCHEDULE.with(|x| x.flush());
    GUARDED_MESSAGE.with(|x| x.flush());
    GUARDED_PROGRESS.with(|x| x.flush());
}

// This macro is stolen from durka42's pull request, #34077, which languishes in Rust's queue.

macro_rules! thread_local {
    ($(#[$attr:meta])* static $name:ident: $t:ty = $init:expr; $($rest:tt)+) => (
        thread_local!($(#[$attr])* static $name: $t = $init);
        thread_local!($($rest)*);
    );
    ($(#[$attr:meta])* static $name:ident: $t:ty = $init:expr $(;)*) => (
        $(#[$attr])* static $name: ::std::thread::LocalKey<$t> =
            __thread_local_inner!($t, $init);
    );
    ($(#[$attr:meta])* pub static $name:ident: $t:ty = $init:expr; $($rest:tt)+) => (
        thread_local!($(#[$attr])* pub static $name: $t = $init);
        thread_local!($($rest)*);
    );
    ($(#[$attr:meta])* pub static $name:ident: $t:ty = $init:expr $(;)*) => (
        $(#[$attr])* pub static $name: ::std::thread::LocalKey<$t> =
            __thread_local_inner!($t, $init);
    );
}

thread_local!{
    /// Logs operator creation.
    pub static OPERATES: EventStreamLogger<OperatesEvent, File> = EventStreamLogger::new();
    /// Logs channel creation.
    pub static CHANNELS: EventStreamLogger<ChannelsEvent, File> = EventStreamLogger::new();
    /// Logs progress transmission.
    pub static PROGRESS: EventStreamLogger<ProgressEvent, File> = EventStreamLogger::new();
    /// Logs message transmission.
    pub static MESSAGES: EventStreamLogger<MessagesEvent, File> = EventStreamLogger::new();
    /// Logs operator scheduling.
    pub static SCHEDULE: EventStreamLogger<ScheduleEvent, File> = EventStreamLogger::new();
    /// Logs delivery of message to an operator input.
    pub static GUARDED_MESSAGE: EventStreamLogger<bool, File> = EventStreamLogger::new();
    /// Logs delivery of notification to an operator.
    pub static GUARDED_PROGRESS: EventStreamLogger<bool, File> = EventStreamLogger::new();
}

#[derive(Debug, Clone)]
/// The creation of an `Operate` implementor.
pub struct OperatesEvent {
    /// Worker-unique identifier for the operator.
    pub id: usize,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub addr: Vec<usize>,
    /// A helpful name.
    pub name: String,
}

unsafe_abomonate!(OperatesEvent : addr, name);

#[derive(Debug, Clone)]
/// The creation of a channel between operators.
pub struct ChannelsEvent {
    /// Worker-unique identifier for the channel
    pub id: usize,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub scope_addr: Vec<usize>,
    /// Source descriptor, indicating operator index and output port.
    pub source: (usize, usize),
    /// Target descriptor, indicating operator index and input port.
    pub target: (usize, usize),
}

unsafe_abomonate!(ChannelsEvent : id, scope_addr, source, target);

#[derive(Debug, Clone)]
/// Send or receive of progress information.
pub struct ProgressEvent {
    /// `true` if the event is a send, and `false` if it is a receive.
    pub is_send: bool,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub addr: Vec<usize>,
    /// List of message updates, containing Target descriptor, timestamp as string, and delta.
    pub messages: Vec<(usize, usize, String, i64)>,
    /// List of capability updates, containing Source descriptor, timestamp as string, and delta.
    pub internal: Vec<(usize, usize, String, i64)>,
}

unsafe_abomonate!(ProgressEvent : is_send, addr, messages, internal);

#[derive(Debug, Clone)]
/// Message send or receive event
pub struct MessagesEvent {
    /// `true` if send event, `false` if receive event.
    pub is_send: bool,
    /// Channel identifier
    pub channel: usize,
    /// Source worker index.
    pub source: usize,
    /// Target worker index.
    pub target: usize,
    /// Message sequence number.
    pub seq_no: usize,
    /// Number of typed records in the message.
    pub length: usize,
}

unsafe_abomonate!(MessagesEvent);

/// Records the starting and stopping of an operator.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StartStop {
    /// Operator starts.
    Start,
    /// Operator stops; did it have any activity?
    Stop {
        /// Did the operator perform non-trivial work.
        activity: bool
    },
}

impl Abomonation for StartStop { }

#[test]
fn start_stop_abomonation_roundtrip() {
    use abomonation::{encode, decode};
    fn check(data: StartStop) -> () {
        let mut bytes = Vec::new();
        unsafe {
            encode(&data, &mut bytes);
        }
        if let Some((result, remaining)) = unsafe { decode::<StartStop>(&mut bytes) } {
            assert!(result == &data);
            assert!(remaining.len() == 0);
        }
    }
    for data in vec![
        StartStop::Stop { activity: true },
        StartStop::Stop { activity: false },
        StartStop::Start,
    ] {
        check(data);
    }
}

#[derive(Debug, Clone)]
/// Operator start or stop.
pub struct ScheduleEvent {
    /// Worker-unique identifier for the operator, linkable to the identifiers in `OperatesEvent`.
    pub id: usize,
    /// `Start` if the operator is starting, `Stop` if it is stopping.
    /// activiy is true if it looks like some useful work was performed during this call (data was
    /// read or written, notifications were requested / delivered)
    pub start_stop: StartStop,
}

unsafe_abomonate!(ScheduleEvent : id, start_stop);
<commit_msg>thread_local! is now in rust std<commit_after>//! Traits, implementations, and macros related to logging timely events.

extern crate time;

use std::cell::RefCell;
use std::io::Write;
use std::fs::File;

use ::Data;

use timely_communication::Allocate;
use ::progress::timestamp::RootTimestamp;
use ::progress::nested::product::Product;

use dataflow::scopes::root::Root;
use dataflow::Scope;
use dataflow::operators::capture::{EventWriter, Event, EventPusher};

use abomonation::Abomonation;

static mut precise_time_ns_delta: Option<i64> = None;

/// Returns the value of an high resolution performance counter, in nanoseconds, rebased to be
/// roughly comparable to an unix timestamp.
/// Useful for comparing and merging logs from different machines (precision is limited by the
/// precision of the wall clock base; clock skew effects should be taken into consideration).
#[inline(always)]
fn get_precise_time_ns() -> u64 {
    (time::precise_time_ns() as i64 - unsafe { precise_time_ns_delta.unwrap() }) as u64
}

/// Logs `record` in `logger` if logging is enabled.
pub fn log<T: Logger>(logger: &'static ::std::thread::LocalKey<T>, record: T::Record) {
    if cfg!(feature = "logging") {
        logger.with(|x| x.log(record));
    }
}

/// Logging methods
pub trait Logger {
    /// The type of loggable record.
    type Record;
    /// Adds `record` to the log.
    fn log(&self, record: Self::Record);
    /// Called with some frequency; behavior unspecified.
    fn flush(&self);
}

/// Logs events to an underlying writer.
pub struct EventStreamLogger<T: Data, S: Write> {
    buffer: RefCell<Vec<(T,u64)>>,
    stream: RefCell<Option<EventWriter<Product<RootTimestamp, u64>, (T,u64), S>>>,
    last_time: RefCell<u64>,
}

impl<T: Data, S: Write> Logger for EventStreamLogger<T, S> {
    type Record = T;
    #[inline]
    fn log(&self, record: T) {
        self.buffer.borrow_mut().push((record, get_precise_time_ns()));
    }
    fn flush(&self) {
        // TODO : sends progress update even if nothing happened.
        // TODO : consider a minimum interval from prior update to
        // TODO : cut down on the amount on logging, at the expense
        // TODO : of freshness on the side of the reader.
        if let Some(ref mut writer) = *self.stream.borrow_mut() {
            let time = get_precise_time_ns();
            if self.buffer.borrow().len() > 0 {
                writer.push(Event::Messages(RootTimestamp::new(*self.last_time.borrow()), self.buffer.borrow().clone()));
            }
            writer.push(Event::Progress(vec![(RootTimestamp::new(*self.last_time.borrow()),-1), (RootTimestamp::new(time), 1)]));
            *self.last_time.borrow_mut() = time;
            self.buffer.borrow_mut().clear();
        }
        else {
            panic!("logging file not initialized!!!!");
        }
    }
}

impl<T: Data, S: Write> EventStreamLogger<T, S> {
    fn new() -> EventStreamLogger<T, S> {
        EventStreamLogger {
            buffer: RefCell::new(Vec::new()),
            stream: RefCell::new(None),
            last_time: RefCell::new(0),
        }
    }
    fn set(&self, stream: S) {
        let mut stream = EventWriter::new(stream);
        stream.push(Event::Progress(vec![(RootTimestamp::new(0), 1)]));
        *self.stream.borrow_mut() = Some(stream);
    }
}

impl<T: Data, S: Write> Drop for EventStreamLogger<T, S> {
    fn drop(&mut self) {
        if let Some(ref mut writer) = *self.stream.borrow_mut() {
            if self.buffer.borrow().len() > 0 {
                writer.push(Event::Messages(RootTimestamp::new(*self.last_time.borrow()), self.buffer.borrow().clone()));
            }
            writer.push(Event::Progress(vec![(RootTimestamp::new(*self.last_time.borrow()),-1)]));
        }
        else {
            panic!("logging file not initialized!!!!");
        }
    }
}

/// Initializes logging; called as part of `Root` initialization.
pub fn initialize<A: Allocate>(root: &mut Root<A>) {

    OPERATES.with(|x| x.set(File::create(format!("logs/operates-{}.abom", root.index())).unwrap()));
    CHANNELS.with(|x| x.set(File::create(format!("logs/channels-{}.abom", root.index())).unwrap()));
    MESSAGES.with(|x| x.set(File::create(format!("logs/messages-{}.abom", root.index())).unwrap()));
    PROGRESS.with(|x| x.set(File::create(format!("logs/progress-{}.abom", root.index())).unwrap()));
    SCHEDULE.with(|x| x.set(File::create(format!("logs/schedule-{}.abom", root.index())).unwrap()));
    GUARDED_MESSAGE.with(|x| x.set(File::create(format!("logs/guarded_message-{}.abom", root.index())).unwrap()));
    GUARDED_PROGRESS.with(|x| x.set(File::create(format!("logs/guarded_progress-{}.abom", root.index())).unwrap()));

    unsafe {
        precise_time_ns_delta = Some({
            let wall_time = time::get_time();
            let wall_time_ns = wall_time.nsec as i64 + wall_time.sec * 1000000000;
            time::precise_time_ns() as i64 - wall_time_ns
        });
    }

}

/// Flushes logs; called by `Root::step`.
pub fn flush_logs() {
    OPERATES.with(|x| x.flush());
    CHANNELS.with(|x| x.flush());
    PROGRESS.with(|x| x.flush());
    MESSAGES.with(|x| x.flush());
    SCHEDULE.with(|x| x.flush());
    GUARDED_MESSAGE.with(|x| x.flush());
    GUARDED_PROGRESS.with(|x| x.flush());
}

thread_local!{
    /// Logs operator creation.
    pub static OPERATES: EventStreamLogger<OperatesEvent, File> = EventStreamLogger::new();
    /// Logs channel creation.
    pub static CHANNELS: EventStreamLogger<ChannelsEvent, File> = EventStreamLogger::new();
    /// Logs progress transmission.
    pub static PROGRESS: EventStreamLogger<ProgressEvent, File> = EventStreamLogger::new();
    /// Logs message transmission.
    pub static MESSAGES: EventStreamLogger<MessagesEvent, File> = EventStreamLogger::new();
    /// Logs operator scheduling.
    pub static SCHEDULE: EventStreamLogger<ScheduleEvent, File> = EventStreamLogger::new();
    /// Logs delivery of message to an operator input.
    pub static GUARDED_MESSAGE: EventStreamLogger<bool, File> = EventStreamLogger::new();
    /// Logs delivery of notification to an operator.
    pub static GUARDED_PROGRESS: EventStreamLogger<bool, File> = EventStreamLogger::new();
}

#[derive(Debug, Clone)]
/// The creation of an `Operate` implementor.
pub struct OperatesEvent {
    /// Worker-unique identifier for the operator.
    pub id: usize,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub addr: Vec<usize>,
    /// A helpful name.
    pub name: String,
}

unsafe_abomonate!(OperatesEvent : addr, name);

#[derive(Debug, Clone)]
/// The creation of a channel between operators.
pub struct ChannelsEvent {
    /// Worker-unique identifier for the channel
    pub id: usize,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub scope_addr: Vec<usize>,
    /// Source descriptor, indicating operator index and output port.
    pub source: (usize, usize),
    /// Target descriptor, indicating operator index and input port.
    pub target: (usize, usize),
}

unsafe_abomonate!(ChannelsEvent : id, scope_addr, source, target);

#[derive(Debug, Clone)]
/// Send or receive of progress information.
pub struct ProgressEvent {
    /// `true` if the event is a send, and `false` if it is a receive.
    pub is_send: bool,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub addr: Vec<usize>,
    /// List of message updates, containing Target descriptor, timestamp as string, and delta.
    pub messages: Vec<(usize, usize, String, i64)>,
    /// List of capability updates, containing Source descriptor, timestamp as string, and delta.
    pub internal: Vec<(usize, usize, String, i64)>,
}

unsafe_abomonate!(ProgressEvent : is_send, addr, messages, internal);

#[derive(Debug, Clone)]
/// Message send or receive event
pub struct MessagesEvent {
    /// `true` if send event, `false` if receive event.
    pub is_send: bool,
    /// Channel identifier
    pub channel: usize,
    /// Source worker index.
    pub source: usize,
    /// Target worker index.
    pub target: usize,
    /// Message sequence number.
    pub seq_no: usize,
    /// Number of typed records in the message.
    pub length: usize,
}

unsafe_abomonate!(MessagesEvent);

/// Records the starting and stopping of an operator.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StartStop {
    /// Operator starts.
    Start,
    /// Operator stops; did it have any activity?
    Stop {
        /// Did the operator perform non-trivial work.
        activity: bool
    },
}

impl Abomonation for StartStop { }

#[test]
fn start_stop_abomonation_roundtrip() {
    use abomonation::{encode, decode};
    fn check(data: StartStop) -> () {
        let mut bytes = Vec::new();
        unsafe {
            encode(&data, &mut bytes);
        }
        if let Some((result, remaining)) = unsafe { decode::<StartStop>(&mut bytes) } {
            assert!(result == &data);
            assert!(remaining.len() == 0);
        }
    }
    for data in vec![
        StartStop::Stop { activity: true },
        StartStop::Stop { activity: false },
        StartStop::Start,
    ] {
        check(data);
    }
}

#[derive(Debug, Clone)]
/// Operator start or stop.
pub struct ScheduleEvent {
    /// Worker-unique identifier for the operator, linkable to the identifiers in `OperatesEvent`.
    pub id: usize,
    /// `Start` if the operator is starting, `Stop` if it is stopping.
    /// activiy is true if it looks like some useful work was performed during this call (data was
    /// read or written, notifications were requested / delivered)
    pub start_stop: StartStop,
}

unsafe_abomonate!(ScheduleEvent : id, start_stop);
<|endoftext|>


<commit_before>//!
//! Read Only Memory (ROM)
//!

use std::env;
use std::io::Read;
use std::fs::File;
use std::path::Path;
use addr::Address;
use mem::Addressable;

/// Generic read-only memory (ROM)
pub struct Rom {
    data: Vec<u8>,
    last_addr: u16,
}

impl Rom {
    /// Create new ROM with contents of the given file
    pub fn new<P: AsRef<Path>> (path: P) -> Rom {
        let filename = env::current_dir().unwrap().join("share").join(path);
        info!("rom: Loading ROM from {}", filename.display());
        let mut data = Vec::new();
        let mut f = match File::open(&filename) {
            Err(err) => panic!("rom: Unable to open ROM: {}", err),
            Ok(f) => f,
        };
        let len = match f.read_to_end(&mut data) {
            Err(err) => panic!("rom: Unable to load ROM: {}", err),
            Ok(0) => panic!("rom: Unable to load empty ROM"),
            Ok(len) => len,
        };
        Rom { data: data, last_addr: (len - 1) as u16 }
    }

    /// Returns the capacity of the ROM
    pub fn capacity (&self) -> usize {
        self.data.len()
    }
}

impl Addressable for Rom {
    fn get<A: Address> (&self, addr: A) -> u8 {
        if addr.to_u16() > self.last_addr {
            panic!("rom: Read beyond memory bounds ({} > {})", addr.display(), self.last_addr.display());
        }
        self.data[addr.to_u16() as usize]
    }

    fn set<A: Address> (&mut self, addr: A, _data: u8) {
        warn!("rom: Ignoring write to read-only memory ({})", addr.display());
    }
}

#[cfg(test)]
mod tests {
    use mem::Addressable;
    use super::*;

    #[test]
    fn create_with_file_contents () {
        let memory = Rom::new("c64/kernal.rom");
        assert_eq!(memory.capacity(), 8192);
    }

    #[test]
    fn read () {
        let memory = Rom::new("c64/kernal.rom");
        assert_eq!(memory.get(0x0123), 0x60);
    }

    #[test]
    fn write_does_nothing () {
        let mut memory = Rom::new("c64/kernal.rom");
        memory.set(0x0123, 0x55);
        assert!(memory.get(0x0123) != 0x55);
    }
}
<commit_msg>Ensure that a loaded ROM file fits into addressable memory<commit_after>//!
//! Read Only Memory (ROM)
//!

use std::env;
use std::io::Read;
use std::fs::File;
use std::path::Path;
use addr::Address;
use mem::Addressable;

/// Generic read-only memory (ROM)
pub struct Rom {
    data: Vec<u8>,
    last_addr: u16,
}

impl Rom {
    /// Create new ROM with contents of the given file
    pub fn new<P: AsRef<Path>> (path: P) -> Rom {
        let filename = env::current_dir().unwrap().join("share").join(path);
        info!("rom: Loading ROM from {}", filename.display());
        let mut data = Vec::new();
        let mut f = match File::open(&filename) {
            Err(err) => panic!("rom: Unable to open ROM: {}", err),
            Ok(f) => f,
        };
        let len = match f.read_to_end(&mut data) {
            Err(err) => panic!("rom: Unable to load ROM: {}", err),
            Ok(0) => panic!("rom: Unable to load empty ROM"),
            Ok(len) if len > 65536 => panic!("rom: Unable to load ROM larger 64k"),
            Ok(len) => len,
        };
        Rom { data: data, last_addr: (len - 1) as u16 }
    }

    /// Returns the capacity of the ROM
    pub fn capacity (&self) -> usize {
        self.data.len()
    }
}

impl Addressable for Rom {
    fn get<A: Address> (&self, addr: A) -> u8 {
        if addr.to_u16() > self.last_addr {
            panic!("rom: Read beyond memory bounds ({} > {})", addr.display(), self.last_addr.display());
        }
        self.data[addr.to_u16() as usize]
    }

    fn set<A: Address> (&mut self, addr: A, _data: u8) {
        warn!("rom: Ignoring write to read-only memory ({})", addr.display());
    }
}

#[cfg(test)]
mod tests {
    use mem::Addressable;
    use super::*;

    #[test]
    fn create_with_file_contents () {
        let memory = Rom::new("c64/kernal.rom");
        assert_eq!(memory.capacity(), 8192);
    }

    #[test]
    fn read () {
        let memory = Rom::new("c64/kernal.rom");
        assert_eq!(memory.get(0x0123), 0x60);
    }

    #[test]
    fn write_does_nothing () {
        let mut memory = Rom::new("c64/kernal.rom");
        memory.set(0x0123, 0x55);
        assert!(memory.get(0x0123) != 0x55);
    }
}
<|endoftext|>


<commit_before>use std::{iter, thread};
use std::sync::atomic::{AtomicIsize, AtomicUsize, Ordering};
use comm;
use config;
use player::Player;
use field::{Pos, Field};
use trajectories_pruning::TrajectoriesPruning;
use common;

const MINIMAX_STR: &'static str = "minimax";

fn alpha_beta(field: &mut Field, depth: u32, last_pos: Pos, player: Player, trajectories_pruning: &TrajectoriesPruning, mut alpha: i32, beta: i32, empty_board: &mut Vec<u32>) -> i32 {
  let enemy = player.next();
  if common::is_last_move_stupid(field, last_pos, enemy) {
    return i32::max_value();
  }
  if depth == 0 {
    return field.score(player);
  }
  let moves = trajectories_pruning.calculate_moves(empty_board);
  if moves.is_empty() {
    return field.score(player);
  }
  for pos in moves {
    field.put_point(pos, player);
    let next_trajectories_pruning = TrajectoriesPruning::new_from_last(field, enemy, depth - 1, empty_board, trajectories_pruning, pos);
    let mut cur_estimation = -alpha_beta(field, depth - 1, pos, enemy, &next_trajectories_pruning, -alpha - 1, -alpha, empty_board);
    if cur_estimation > alpha && cur_estimation < beta {
      cur_estimation = -alpha_beta(field, depth - 1, pos, enemy, &next_trajectories_pruning, -beta, -cur_estimation, empty_board);
    }
    field.undo();
    if cur_estimation > alpha {
      alpha = cur_estimation;
      if alpha >= beta {
        break;
      }
    }
  }
  alpha
}

pub fn minimax(field: &mut Field, player: Player, depth: u32) -> Option<Pos> {
  if depth == 0 {
    return None;
  }
  let mut empty_board = iter::repeat(0u32).take(field.length()).collect();
  let trajectories_pruning = TrajectoriesPruning::new(field, player, depth, &mut empty_board);
  let moves = trajectories_pruning.calculate_moves(&mut empty_board);
  debug!(target: MINIMAX_STR, "Moves in consideration: {:?}.", moves.iter().map(|&pos| (field.to_x(pos), field.to_y(pos))).collect::<Vec<(u32, u32)>>());
  let (producer, consumer) = comm::spmc::unbounded::new();
  for pos in moves {
    producer.send(pos).ok();
  }
  let threads_count = config::threads_count();
  let alpha = AtomicIsize::new((i32::min_value() + 1) as isize);
  let best_move = AtomicUsize::new(0);
  let mut guards = Vec::with_capacity(threads_count);
  for _ in 0 .. threads_count {
    guards.push(thread::scoped(|| {
      let local_consumer = consumer.clone();
      let mut local_field = field.clone();
      let mut local_empty_board = iter::repeat(0u32).take(field.length()).collect();
      let enemy = player.next();
      while let Some(pos) = local_consumer.recv_async().ok() {
        local_field.put_point(pos, player);
        let next_trajectories_pruning = TrajectoriesPruning::new_from_last(&mut local_field, enemy, depth - 1, &mut local_empty_board, &trajectories_pruning, pos);
        let cur_alpha = alpha.load(Ordering::SeqCst) as i32;
        let mut cur_estimation = -alpha_beta(&mut local_field, depth - 1, pos, enemy, &next_trajectories_pruning, -cur_alpha - 1, -cur_alpha, &mut local_empty_board);
        if cur_estimation > cur_alpha {
          cur_estimation = -alpha_beta(&mut local_field, depth - 1, pos, enemy, &next_trajectories_pruning, i32::min_value() + 1, -cur_estimation, &mut local_empty_board);
        }
        local_field.undo();
        loop {
          let last_pos = best_move.load(Ordering::SeqCst);
          let last_alpha = alpha.load(Ordering::SeqCst);
          if cur_estimation > last_alpha as i32 {
            if alpha.compare_and_swap(last_alpha, cur_estimation as isize, Ordering::SeqCst) == last_alpha && best_move.compare_and_swap(last_pos, pos, Ordering::SeqCst) == last_pos {
              debug!(target: MINIMAX_STR, "Estimation for move ({0}, {1}) is {2}.", field.to_x(pos), field.to_y(pos), cur_estimation);
              break;
            }
          } else {
            debug!(target: MINIMAX_STR, "{0} for move ({1}, {2}) is {3}.", if cur_estimation > cur_alpha { "Estimation" } else { "Upper bound of estimation" }, field.to_x(pos), field.to_y(pos), cur_estimation);
            break;
          }
        }
      }
    }));
  }
  drop(guards);
  let result = best_move.load(Ordering::SeqCst);
  if result != 0 {
    info!(target: MINIMAX_STR, "Best move is ({0}, {1}), estimation is {2}.", field.to_x(result), field.to_y(result), alpha.load(Ordering::SeqCst));
    Some(result)
  } else {
    None
  }
}
<commit_msg>TODO added.<commit_after>use std::{iter, thread};
use std::sync::atomic::{AtomicIsize, AtomicUsize, Ordering};
use comm;
use config;
use player::Player;
use field::{Pos, Field};
use trajectories_pruning::TrajectoriesPruning;
use common;

const MINIMAX_STR: &'static str = "minimax";

fn alpha_beta(field: &mut Field, depth: u32, last_pos: Pos, player: Player, trajectories_pruning: &TrajectoriesPruning, mut alpha: i32, beta: i32, empty_board: &mut Vec<u32>) -> i32 {
  let enemy = player.next();
  if common::is_last_move_stupid(field, last_pos, enemy) {
    return i32::max_value();
  }
  if depth == 0 {
    return field.score(player);
  }
  let moves = trajectories_pruning.calculate_moves(empty_board);
  if moves.is_empty() {
    return field.score(player);
  }
  for pos in moves {
    field.put_point(pos, player); //TODO: is_penult_move_stuped
    let next_trajectories_pruning = TrajectoriesPruning::new_from_last(field, enemy, depth - 1, empty_board, trajectories_pruning, pos);
    let mut cur_estimation = -alpha_beta(field, depth - 1, pos, enemy, &next_trajectories_pruning, -alpha - 1, -alpha, empty_board);
    if cur_estimation > alpha && cur_estimation < beta {
      cur_estimation = -alpha_beta(field, depth - 1, pos, enemy, &next_trajectories_pruning, -beta, -cur_estimation, empty_board);
    }
    field.undo();
    if cur_estimation > alpha {
      alpha = cur_estimation;
      if alpha >= beta {
        break;
      }
    }
  }
  alpha
}

pub fn minimax(field: &mut Field, player: Player, depth: u32) -> Option<Pos> {
  if depth == 0 {
    return None;
  }
  let mut empty_board = iter::repeat(0u32).take(field.length()).collect();
  let trajectories_pruning = TrajectoriesPruning::new(field, player, depth, &mut empty_board);
  let moves = trajectories_pruning.calculate_moves(&mut empty_board);
  debug!(target: MINIMAX_STR, "Moves in consideration: {:?}.", moves.iter().map(|&pos| (field.to_x(pos), field.to_y(pos))).collect::<Vec<(u32, u32)>>());
  let (producer, consumer) = comm::spmc::unbounded::new();
  for pos in moves {
    producer.send(pos).ok();
  }
  let threads_count = config::threads_count();
  let alpha = AtomicIsize::new((i32::min_value() + 1) as isize);
  let best_move = AtomicUsize::new(0);
  let mut guards = Vec::with_capacity(threads_count);
  for _ in 0 .. threads_count {
    guards.push(thread::scoped(|| {
      let local_consumer = consumer.clone();
      let mut local_field = field.clone();
      let mut local_empty_board = iter::repeat(0u32).take(field.length()).collect();
      let enemy = player.next();
      while let Some(pos) = local_consumer.recv_async().ok() {
        local_field.put_point(pos, player);
        let next_trajectories_pruning = TrajectoriesPruning::new_from_last(&mut local_field, enemy, depth - 1, &mut local_empty_board, &trajectories_pruning, pos);
        let cur_alpha = alpha.load(Ordering::SeqCst) as i32;
        let mut cur_estimation = -alpha_beta(&mut local_field, depth - 1, pos, enemy, &next_trajectories_pruning, -cur_alpha - 1, -cur_alpha, &mut local_empty_board);
        if cur_estimation > cur_alpha {
          cur_estimation = -alpha_beta(&mut local_field, depth - 1, pos, enemy, &next_trajectories_pruning, i32::min_value() + 1, -cur_estimation, &mut local_empty_board);
        }
        local_field.undo();
        loop {
          let last_pos = best_move.load(Ordering::SeqCst);
          let last_alpha = alpha.load(Ordering::SeqCst);
          if cur_estimation > last_alpha as i32 {
            if alpha.compare_and_swap(last_alpha, cur_estimation as isize, Ordering::SeqCst) == last_alpha && best_move.compare_and_swap(last_pos, pos, Ordering::SeqCst) == last_pos {
              debug!(target: MINIMAX_STR, "Estimation for move ({0}, {1}) is {2}.", field.to_x(pos), field.to_y(pos), cur_estimation);
              break;
            }
          } else {
            debug!(target: MINIMAX_STR, "{0} for move ({1}, {2}) is {3}.", if cur_estimation > cur_alpha { "Estimation" } else { "Upper bound of estimation" }, field.to_x(pos), field.to_y(pos), cur_estimation);
            break;
          }
        }
      }
    }));
  }
  drop(guards);
  let result = best_move.load(Ordering::SeqCst);
  if result != 0 {
    info!(target: MINIMAX_STR, "Best move is ({0}, {1}), estimation is {2}.", field.to_x(result), field.to_y(result), alpha.load(Ordering::SeqCst));
    Some(result)
  } else {
    None
  }
}
<|endoftext|>


<commit_before>pub type Project = String;

<commit_msg>Document Project type<commit_after>/// Typedef for Project type.
pub type Project = String;

<|endoftext|>


<commit_before>// Copyright 2015 The Athena Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error::Error;
use std::fs;
use std::fs::{PathExt, File};
use std::fmt;
use std::fmt::{Display, Formatter};
use std::io::Write;
use std::path::PathBuf;

use git;

// ### File Templates ###

static PROJ_TOML: &'static str =
r#"[game]
name = "{{game_name}}"
version = "0.0.1"
authors = ["{{author_name}}"]"#;

static GITIGNORE: &'static str =
r#"/athena"#;

// ### Create Error ###

#[derive(Debug)]
pub enum ZeusProjectError {
    AlreadyExists,
    NotAZeusProject
}

impl Error for ZeusProjectError {
    fn description(&self) -> &str {
        match *self {
            ZeusProjectError::AlreadyExists => "Already Exists",
            ZeusProjectError::NotAZeusProject => "Not a Zeus Project"
        }
    }
}

impl Display for ZeusProjectError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let message = match *self {
            ZeusProjectError::AlreadyExists => "Destination path already exists.",
            ZeusProjectError::NotAZeusProject => "Destination is not a Zeus project."
        };

        return write!(f, "{}", message);
    }
}

// ### Zeus Project ###

#[derive(Debug)]
pub struct ZeusProject {
    directory: PathBuf
}

impl ZeusProject {
    // ## Constructors ##

    pub fn create(target_dir: PathBuf) -> Result<ZeusProject, ZeusProjectError> {
        // Sanity check the path
        if target_dir.exists() { return Err(ZeusProjectError::AlreadyExists); }

        // Create the actual project
        let project = ZeusProject {
            directory: target_dir
        };

        // Create the directory for this project
        fs::create_dir_all(project.directory.clone()).unwrap();

        // Generate the sample project file
        // TODO: Use some templating library
        let proj_toml = str::replace(PROJ_TOML, "{{game_name}}", "My Game");
        let proj_toml = str::replace(&proj_toml, "{{author_name}}", "Jane Doe");

        // Create basic
        project.create_file("Zeus.toml", &proj_toml);
        project.create_file(".gitignore", GITIGNORE);

        return Ok(project);
    }

    pub fn open(target_dir: PathBuf) -> Result<ZeusProject, ZeusProjectError> {
        // Sanity check the path
        let mut toml_path = target_dir.clone();
        toml_path.push("Zeus.toml");
        if !toml_path.exists() { return Err(ZeusProjectError::NotAZeusProject); }

        // We're in a valid project
        let project = ZeusProject {
            directory: target_dir
        };

        return Ok(project);
    }

    // ## Helpers Functions ##

    pub fn build_editor(&self) {
        self.redownload_athena();
    }

    fn redownload_athena(&self) {
        let mut athena_dir = self.directory.clone();
        athena_dir.push("athena");

        // Delete the old folder if it exists
        if athena_dir.exists() {
            // Set readonly on all files and directories to false
            for file in fs::walk_dir(&athena_dir).unwrap() {
                let path = file.unwrap().path();
                let mut permissions = fs::metadata(&path).unwrap().permissions();
                permissions.set_readonly(false);
                fs::set_permissions(&path, permissions).unwrap();
            }

            // Actually remove the directory
            fs::remove_dir_all(&athena_dir).unwrap();
        }

        // Clone in the latest version of Athena
        // TODO: Actually clone athena instead of zeus right now for testing
        let athena_dir_str = athena_dir.to_str().unwrap();
        git::clone("https://github.com/athena-org/zeus.git", athena_dir_str, "develop").unwrap();
    }

    fn create_file(&self, name: &str, data: &str) {
        let mut path = self.directory.clone();
        path.push(name);
        let mut file = File::create(path).unwrap();
        file.write_all(&data.as_bytes()).unwrap();
    }
}
<commit_msg>Update toml template with more example information<commit_after>// Copyright 2015 The Athena Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error::Error;
use std::fs;
use std::fs::{PathExt, File};
use std::fmt;
use std::fmt::{Display, Formatter};
use std::io::Write;
use std::path::PathBuf;

use git;

// ### File Templates ###

static PROJ_TOML: &'static str =
r#"[game]
name = "{{game_name}}"
version = "0.0.1"
zeus_version = "develop"
athena_version = "develop"
authors = ["{{author_name}}"]"#;

static GITIGNORE: &'static str =
r#"/athena"#;

// ### Create Error ###

#[derive(Debug)]
pub enum ZeusProjectError {
    AlreadyExists,
    NotAZeusProject
}

impl Error for ZeusProjectError {
    fn description(&self) -> &str {
        match *self {
            ZeusProjectError::AlreadyExists => "Already Exists",
            ZeusProjectError::NotAZeusProject => "Not a Zeus Project"
        }
    }
}

impl Display for ZeusProjectError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let message = match *self {
            ZeusProjectError::AlreadyExists => "Destination path already exists.",
            ZeusProjectError::NotAZeusProject => "Destination is not a Zeus project."
        };

        return write!(f, "{}", message);
    }
}

// ### Zeus Project ###

#[derive(Debug)]
pub struct ZeusProject {
    directory: PathBuf
}

impl ZeusProject {
    // ## Constructors ##

    pub fn create(target_dir: PathBuf) -> Result<ZeusProject, ZeusProjectError> {
        // Sanity check the path
        if target_dir.exists() { return Err(ZeusProjectError::AlreadyExists); }

        // Create the actual project
        let project = ZeusProject {
            directory: target_dir
        };

        // Create the directory for this project
        fs::create_dir_all(project.directory.clone()).unwrap();

        // Generate the sample project file
        // TODO: Use some templating library
        let proj_toml = str::replace(PROJ_TOML, "{{game_name}}", "My Game");
        let proj_toml = str::replace(&proj_toml, "{{author_name}}", "Jane Doe");

        // Create basic
        project.create_file("Zeus.toml", &proj_toml);
        project.create_file(".gitignore", GITIGNORE);

        return Ok(project);
    }

    pub fn open(target_dir: PathBuf) -> Result<ZeusProject, ZeusProjectError> {
        // Sanity check the path
        let mut toml_path = target_dir.clone();
        toml_path.push("Zeus.toml");
        if !toml_path.exists() { return Err(ZeusProjectError::NotAZeusProject); }

        // We're in a valid project
        let project = ZeusProject {
            directory: target_dir
        };

        return Ok(project);
    }

    // ## Helpers Functions ##

    pub fn build_editor(&self) {
        self.redownload_athena();
    }

    fn redownload_athena(&self) {
        let mut athena_dir = self.directory.clone();
        athena_dir.push("athena");

        // Delete the old folder if it exists
        if athena_dir.exists() {
            // Set readonly on all files and directories to false
            for file in fs::walk_dir(&athena_dir).unwrap() {
                let path = file.unwrap().path();
                let mut permissions = fs::metadata(&path).unwrap().permissions();
                permissions.set_readonly(false);
                fs::set_permissions(&path, permissions).unwrap();
            }

            // Actually remove the directory
            fs::remove_dir_all(&athena_dir).unwrap();
        }

        // Clone in the latest version of Athena
        // TODO: Actually clone athena instead of zeus right now for testing
        let athena_dir_str = athena_dir.to_str().unwrap();
        git::clone("https://github.com/athena-org/zeus.git", athena_dir_str, "develop").unwrap();
    }

    fn create_file(&self, name: &str, data: &str) {
        let mut path = self.directory.clone();
        path.push(name);
        let mut file = File::create(path).unwrap();
        file.write_all(&data.as_bytes()).unwrap();
    }
}
<|endoftext|>


<commit_before>use hyper;
use signers::sigv4::SigV4;
use credentials::Credentials;

#[derive(Debug)]
pub struct APIClient {
    signer: Option<SigV4>
}

impl APIClient {
    pub fn new(creds: Credentials, region: &str, service: &str) -> APIClient{
        let sig = SigV4::new();
        let sig = sig.credentials(creds);
        let sig = sig.region(region);
        let sig = sig.service(service);

        let host = format!("{}.{}.amazonaws.com", service, region);
        let sig = sig.header(("Host", &host));

        APIClient {
            signer: Some(sig)
        }
    }
}
<commit_msg>"Working" GET request for ec2<commit_after>use hyper::Client;
use hyper::client::Response;
use hyper::Result as HyperResult;
use signers::sigv4::SigV4;
use credentials::Credentials;

#[derive(Debug)]
pub struct ApiClient {
    signer: SigV4,
    endpoint: String
}

impl ApiClient {
    pub fn new(creds: Credentials, region: &str, service: &str) -> ApiClient{
        let sig = SigV4::new();
        let sig = sig.credentials(creds);
        let sig = sig.region(region);
        let sig = sig.service(service);

        let host = format!("{}.{}.amazonaws.com", service, region);
        let sig = sig.header(("Host", &host));

        ApiClient {
            signer: sig,
            endpoint: format!("https://{}/", host)
        }
    }

    pub fn get(self, action: &str) -> HyperResult<Response>{
        let sig = self.signer.clone();
        let sig = sig.method("GET");
        let sig = sig.path("/");
        let query = format!("Action={}&Version=2015-04-15", action);
        let sig = sig.query(&query);
        let url = format!("{}?{}", self.endpoint, query);

        let headers = sig.as_headers();
        let mut client = Client::new();
        let res = client.get(&url).headers(headers).send();
        res
    }
}

#[cfg(test)]
mod tests {
    use super::ApiClient;
    use credentials::Credentials;

    #[test]
    fn test_new_apiclient() {
        let cred = Credentials::new().path("fixtures/credentials.ini").load();
        let region = "eu-west-1";
        let service = "ec2";

        let client = ApiClient::new(cred, region, service);
        assert_eq!(client.endpoint, "https://ec2.eu-west-1.amazonaws.com/")
    }
}
<|endoftext|>


<commit_before>// Use the stuff we need to
use std::{io, slice, str};

use bytes::BytesMut;

use httparse;

/// The result of an incoming request
pub struct Request {
    method: Slice,
    path: Slice,
    version: u8,
    headers: Vec<(Slice, Slice)>,
    data: BytesMut,
    body: BytesMut,
}

// Store start position and data length
type Slice = (usize, usize);

pub struct RequestHeaders<'req> {
    headers: slice::Iter<'req, (Slice, Slice)>,
    req: &'req Request,
}

impl Request {
    /// Returns the request method
    pub fn method(&self) -> &str {
        str::from_utf8(self.slice(&self.method)).unwrap()
    }

    /// Returns the requested path
    pub fn path(&self) -> &str {
        str::from_utf8(self.slice(&self.path)).unwrap()
    }

    /// Returns the requested HTTP Version
    pub fn version(&self) -> u8 {
        self.version
    }

    /// Return our Request headers
    pub fn headers(&self) -> RequestHeaders {
        RequestHeaders {
            headers: self.headers.iter(),
            req: self,
        }
    }

    /// Get the request raw data wit a given length
    pub fn slice(&self, slice: &Slice) -> &[u8] {
        &self.data[slice.0..slice.1]
    }

    /// Get raw request
    pub fn data(&self) -> &BytesMut {
        &self.data
    }

    /// Get raw body
    pub fn body(&self) -> &BytesMut {
        &self.body
    }
}

/// Decode the given raw HTTP request
pub fn decode(buf: &mut BytesMut) -> io::Result<Option<Request>> {
    // Extract the details as slices
    let (method, path, version, headers, amt) = {
        // Parse with httparse
        let mut headers = [httparse::EMPTY_HEADER; 16];
        let mut r = httparse::Request::new(&mut headers);
        let status = try!(r.parse(buf).map_err(|e| {
            let msg = format!("failed to parse http request: {:?}", e);
            io::Error::new(io::ErrorKind::Other, msg)
        }));

        // Get the request body data
        let amt = match status {
            httparse::Status::Complete(amt) => amt,
            httparse::Status::Partial => return Ok(None),
        };

        // Convert raw data to slice
        let toslice = |a: &[u8]| {
            let start = a.as_ptr() as usize - buf.as_ptr() as usize;
            assert!(start < buf.len());
            (start, start + a.len())
        };

        // Return the slices
        (toslice(r.method.unwrap().as_bytes()),
         toslice(r.path.unwrap().as_bytes()),
         r.version.unwrap(),
         // Convert headers to slices
         r.headers
             .iter()
             .map(|h| (toslice(h.name.as_bytes()), toslice(h.value)))
             .collect(),
         amt)
    };

    // Create a new Request object
    Ok(Request {
               method: method,
               path: path,
               version: version,
               headers: headers,
               data: buf.split_to(amt),
               body: buf.clone(),
           }
           .into())
}

impl<'req> Iterator for RequestHeaders<'req> {
    type Item = (&'req str, &'req [u8]);

    fn next(&mut self) -> Option<(&'req str, &'req [u8])> {
        self.headers
            .next()
            .map(|&(ref a, ref b)| {
                     let a = self.req.slice(a);
                     let b = self.req.slice(b);
                     (str::from_utf8(a).unwrap(), b)
                 })
    }
}
<commit_msg>Clear buffer<commit_after>// Use the stuff we need to
use std::{io, slice, str};

use bytes::BytesMut;

use httparse;

/// The result of an incoming request
pub struct Request {
    method: Slice,
    path: Slice,
    version: u8,
    headers: Vec<(Slice, Slice)>,
    data: BytesMut,
    body: BytesMut,
}

// Store start position and data length
type Slice = (usize, usize);

pub struct RequestHeaders<'req> {
    headers: slice::Iter<'req, (Slice, Slice)>,
    req: &'req Request,
}

impl Request {
    /// Returns the request method
    pub fn method(&self) -> &str {
        str::from_utf8(self.slice(&self.method)).unwrap()
    }

    /// Returns the requested path
    pub fn path(&self) -> &str {
        str::from_utf8(self.slice(&self.path)).unwrap()
    }

    /// Returns the requested HTTP Version
    pub fn version(&self) -> u8 {
        self.version
    }

    /// Return our Request headers
    pub fn headers(&self) -> RequestHeaders {
        RequestHeaders {
            headers: self.headers.iter(),
            req: self,
        }
    }

    /// Get the request raw data wit a given length
    pub fn slice(&self, slice: &Slice) -> &[u8] {
        &self.data[slice.0..slice.1]
    }

    /// Get raw request
    pub fn data(&self) -> &BytesMut {
        &self.data
    }

    /// Get raw body
    pub fn body(&self) -> &BytesMut {
        &self.body
    }
}

/// Decode the given raw HTTP request
pub fn decode(buf: &mut BytesMut) -> io::Result<Option<Request>> {
    // Extract the details as slices
    let (method, path, version, headers, amt) = {
        // Parse with httparse
        let mut headers = [httparse::EMPTY_HEADER; 16];
        let mut r = httparse::Request::new(&mut headers);
        let status = try!(r.parse(buf).map_err(|e| {
            let msg = format!("failed to parse http request: {:?}", e);
            io::Error::new(io::ErrorKind::Other, msg)
        }));

        // Get the request body data
        let amt = match status {
            httparse::Status::Complete(amt) => amt,
            httparse::Status::Partial => return Ok(None),
        };

        // Convert raw data to slice
        let toslice = |a: &[u8]| {
            let start = a.as_ptr() as usize - buf.as_ptr() as usize;
            assert!(start < buf.len());
            (start, start + a.len())
        };

        // Return the slices
        (toslice(r.method.unwrap().as_bytes()),
         toslice(r.path.unwrap().as_bytes()),
         r.version.unwrap(),
         // Convert headers to slices
         r.headers
             .iter()
             .map(|h| (toslice(h.name.as_bytes()), toslice(h.value)))
             .collect(),
         amt)
    };

    let request = Request {
               method: method,
               path: path,
               version: version,
               headers: headers,
               data: buf.split_to(amt),
               body: buf.clone(),
           };

    // Clear buffer for next request
    buf.clear();

    // Create a new Request object
    Ok(request.into())
}

impl<'req> Iterator for RequestHeaders<'req> {
    type Item = (&'req str, &'req [u8]);

    fn next(&mut self) -> Option<(&'req str, &'req [u8])> {
        self.headers
            .next()
            .map(|&(ref a, ref b)| {
                     let a = self.req.slice(a);
                     let b = self.req.slice(b);
                     (str::from_utf8(a).unwrap(), b)
                 })
    }
}
<|endoftext|>


<commit_before>//! Module for decoding RFC 2047 strings
// use for to_ascii_lowercase
use std::ascii::AsciiExt;
use std::num::from_str_radix;
use rustc_serialize::base64::FromBase64;

use encoding::label::encoding_from_whatwg_label;
use encoding::DecoderTrap;

/// Decode an RFC 2047 string (`s`) into a Rust String.
///
/// Will accept either "Q" encoding (RFC 2047 Section 4.2) or
/// "B" encoding (BASE64)
#[unstable]
pub fn decode_rfc2047(s: &str) -> Option<String> {
    let parts: Vec<&str> = s.split('?').collect();
    if parts.len() != 5 || parts[0] != "=" || parts[4] != "=" {
        None
    } else {
        let charset = parts[1].to_ascii_lowercase();
        let encoding = parts[2].to_ascii_lowercase();
        let content = parts[3];

        let bytes = match encoding.as_slice() {
            "q" => decode_q_encoding(content),
            "b" => decode_base64_encoding(content),
            _ => panic!("Unknown encoding type"),
        };

        // XXX: Relies on WHATWG labels, rather than MIME labels for
        // charset. Consider adding mapping upstream.
        let decoder = encoding_from_whatwg_label(charset.as_slice());

        match (bytes, decoder) {
            (Ok(b), Some(d)) => {
                d.decode(&b[], DecoderTrap::Replace).ok()
            }
            _ => None,
        }
    }
}

#[stable]
pub fn decode_q_encoding(s: &str) -> Result<Vec<u8>, String> {
    let mut result = Vec::new();

    let mut pos = 0us;

    while pos < s.len() {
        let c = s.char_range_at(pos);
        pos = match c.ch {
            '=' => {
                let mut inner_pos = c.next;
                let mut hex_string = String::new();
                for _ in 0..2 {
                    let hex_digit_char = s.char_range_at(inner_pos);
                    hex_string.push(hex_digit_char.ch);
                    inner_pos = hex_digit_char.next;
                }
                // = followed by a newline means a continuation
                if hex_string.as_slice() != "\r\n" {
                    match from_str_radix(hex_string.as_slice(), 16us) {
                        Ok(char_val) => { result.push(char_val) },
                        Err(e) => { return Err(format!("'{}' is not a hex number: {}", hex_string, e)) },
                    }
                }
                inner_pos
            }
            _ => {
                result.push(c.ch as u8);
                c.next
            }
        }
    }

    Ok(result)
}

fn decode_base64_encoding(s: &str) -> Result<Vec<u8>, String> {
    match s.from_base64() {
        Ok(bytes) => Ok(bytes),
        Err(_) => Err("Failed to base64 decode".to_string()),
    }
}

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

    struct DecodeTest<'s> {
        input: &'s str,
        output: &'s str,
    }

    #[test]
    fn test_decode() {
        let tests = [
            DecodeTest {
                input: "=?ISO-8859-1?Q?Test=20text?=",
                output: "Test text"
            },
            DecodeTest {
                input: "=?ISO-8859-1?b?VGVzdCB0ZXh0?=",
                output: "Test text"
            },
            DecodeTest {
                input: "=?utf-8?b?44GT44KT44Gr44Gh44Gv44CC?=",
                output: "こんにちは。"
            },
        ];

        for t in tests.iter() {
            assert_eq!(decode_rfc2047(t.input).unwrap(), t.output.to_string());
        }
    }

    #[test]
    fn test_decode_failure() {
        let tests = [
            // Invalid base64
            "=?ISO-8859-1?b?-?=",
            // Not valid RFC 2047
            "=?Doesn't end with equals",
            // Unknown charset
            "=?NOCHARSET?q?foo?=",
        ];

        for t in tests.iter() {
            println!("{}", t);
            assert!(decode_rfc2047(*t).is_none());
        }
    }
}
<commit_msg>Nightly fixes<commit_after>//! Module for decoding RFC 2047 strings
// use for to_ascii_lowercase
use std::ascii::AsciiExt;
use std::num::from_str_radix;
use rustc_serialize::base64::FromBase64;

use encoding::label::encoding_from_whatwg_label;
use encoding::DecoderTrap;

/// Decode an RFC 2047 string (`s`) into a Rust String.
///
/// Will accept either "Q" encoding (RFC 2047 Section 4.2) or
/// "B" encoding (BASE64)
#[unstable]
pub fn decode_rfc2047(s: &str) -> Option<String> {
    let parts: Vec<&str> = s.split('?').collect();
    if parts.len() != 5 || parts[0] != "=" || parts[4] != "=" {
        None
    } else {
        let charset = parts[1].to_ascii_lowercase();
        let encoding = parts[2].to_ascii_lowercase();
        let content = parts[3];

        let bytes = match encoding.as_slice() {
            "q" => decode_q_encoding(content),
            "b" => decode_base64_encoding(content),
            _ => panic!("Unknown encoding type"),
        };

        // XXX: Relies on WHATWG labels, rather than MIME labels for
        // charset. Consider adding mapping upstream.
        let decoder = encoding_from_whatwg_label(charset.as_slice());

        match (bytes, decoder) {
            (Ok(b), Some(d)) => {
                d.decode(&b[], DecoderTrap::Replace).ok()
            }
            _ => None,
        }
    }
}

#[stable]
pub fn decode_q_encoding(s: &str) -> Result<Vec<u8>, String> {
    let mut result = Vec::new();

    let mut pos = 0us;

    while pos < s.len() {
        let c = s.char_range_at(pos);
        pos = match c.ch {
            '=' => {
                let mut inner_pos = c.next;
                let mut hex_string = String::new();
                for _ in 0..2 {
                    let hex_digit_char = s.char_range_at(inner_pos);
                    hex_string.push(hex_digit_char.ch);
                    inner_pos = hex_digit_char.next;
                }
                // = followed by a newline means a continuation
                if hex_string.as_slice() != "\r\n" {
                    match from_str_radix(hex_string.as_slice(), 16) {
                        Ok(char_val) => { result.push(char_val) },
                        Err(e) => { return Err(format!("'{}' is not a hex number: {}", hex_string, e)) },
                    }
                }
                inner_pos
            }
            _ => {
                result.push(c.ch as u8);
                c.next
            }
        }
    }

    Ok(result)
}

fn decode_base64_encoding(s: &str) -> Result<Vec<u8>, String> {
    match s.from_base64() {
        Ok(bytes) => Ok(bytes),
        Err(_) => Err("Failed to base64 decode".to_string()),
    }
}

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

    struct DecodeTest<'s> {
        input: &'s str,
        output: &'s str,
    }

    #[test]
    fn test_decode() {
        let tests = [
            DecodeTest {
                input: "=?ISO-8859-1?Q?Test=20text?=",
                output: "Test text"
            },
            DecodeTest {
                input: "=?ISO-8859-1?b?VGVzdCB0ZXh0?=",
                output: "Test text"
            },
            DecodeTest {
                input: "=?utf-8?b?44GT44KT44Gr44Gh44Gv44CC?=",
                output: "こんにちは。"
            },
        ];

        for t in tests.iter() {
            assert_eq!(decode_rfc2047(t.input).unwrap(), t.output.to_string());
        }
    }

    #[test]
    fn test_decode_failure() {
        let tests = [
            // Invalid base64
            "=?ISO-8859-1?b?-?=",
            // Not valid RFC 2047
            "=?Doesn't end with equals",
            // Unknown charset
            "=?NOCHARSET?q?foo?=",
        ];

        for t in tests.iter() {
            println!("{}", t);
            assert!(decode_rfc2047(*t).is_none());
        }
    }
}
<|endoftext|>


<commit_before>pub mod builtins;

use std::collections::HashMap;
use std::path::PathBuf;
use std::io;
use std::io::{Read, Write};
use std::collections::hash_map::Entry;

#[derive(PartialEq, Debug, Clone)]
pub struct State {
    cwd: PathBuf,
    environment: HashMap<String, String>,
    aliases: HashMap<String, String>,
    argv: Vec<String>,
    argc: usize,
}

impl State {
    pub fn new(cwd: String) -> State {
        State{
            cwd: PathBuf::from(cwd),
            environment: HashMap::new(),
            aliases: HashMap::new(),
            argv: Vec::new(),
            argc: 0,
        }
    }
}

pub fn run(initial_state: State) {
    let mut builtins = builtins::load();
    let mut s = initial_state.clone();

    println!("Welcome to rsh! {:?}", s);

    loop {

        print!("{} -> ", s.cwd.to_str().unwrap());

        // this forces the prompt to print
        io::stdout().flush();

        // read the user input
        let mut input = String::new();
        io::stdin().read_line(&mut input).unwrap();

        s.argv = input.split_whitespace().
            map(|s| s.to_string() ).
            collect();
        s.argc = s.argv.len();

        print!("\n");
        println!("Input: {}\nState: {:?}", input, s);

        let first_arg = s.argv.get(0).unwrap().clone();
        if let Entry::Occupied(f) = builtins.entry(String::from(first_arg)) {
            let bn = f.get();
            s = bn(s.clone());
        }
    }
}
<commit_msg>Add newline before PROMPT line<commit_after>pub mod builtins;

use std::collections::HashMap;
use std::path::PathBuf;
use std::io;
use std::io::{Read, Write};
use std::collections::hash_map::Entry;

#[derive(PartialEq, Debug, Clone)]
pub struct State {
    cwd: PathBuf,
    environment: HashMap<String, String>,
    aliases: HashMap<String, String>,
    argv: Vec<String>,
    argc: usize,
}

impl State {
    pub fn new(cwd: String) -> State {
        State {
            cwd: PathBuf::from(cwd),
            environment: HashMap::new(),
            aliases: HashMap::new(),
            argv: Vec::new(),
            argc: 0,
        }
    }
}

pub fn run(initial_state: State) {
    let mut builtins = builtins::load();
    let mut s = initial_state.clone();

    println!("Welcome to rsh! {:?}", s);

    loop {

        print!("\n");
        print!("{} -> ", s.cwd.to_str().unwrap());

        // this forces the prompt to print
        io::stdout().flush();

        // read the user input
        let mut input = String::new();
        io::stdin().read_line(&mut input).unwrap();

        s.argv = input.split_whitespace()
            .map(|s| s.to_string())
            .collect();
        s.argc = s.argv.len();

        print!("\n");
        println!("Input: {}\nState: {:?}", input, s);

        let first_arg = s.argv.get(0).unwrap().clone();
        if let Entry::Occupied(f) = builtins.entry(String::from(first_arg)) {
            let bn = f.get();
            s = bn(s.clone());
        }
    }
}
<|endoftext|>


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

extern crate log;
use log::{LogRecord, LogLevel, LogLevelFilter, LogMetadata, SetLoggerError};

pub use cli::CliConfig;
pub use configuration::Configuration as Cfg;

use storage::Store;

pub struct ImagLogger {
    lvl: LogLevel,
}

impl ImagLogger {

    pub fn new(lvl: LogLevel) -> ImagLogger {
        ImagLogger {
            lvl: lvl,
        }
    }

    pub fn init(cfg: &Cfg, config: &CliConfig) -> Result<(), SetLoggerError> {
        let lvl = if config.is_debugging() || cfg.is_debugging() {
            LogLevelFilter::Debug
        } else if config.is_verbose() || cfg.is_debugging() {
            LogLevelFilter::Info
        } else {
            LogLevelFilter::Error
        };

        log::set_logger(|max_log_lvl| {
            max_log_lvl.set(lvl);
            debug!("Init logger with: {}", lvl);
            Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
        })
    }

}

impl log::Log for ImagLogger {

    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.lvl
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            println!("[{}]: {}", record.level(), record.args());
        }
    }
}

pub struct Runtime<'a> {
    pub config : CliConfig<'a>,
    pub configuration : Cfg,
    pub store : Store,
}

impl<'a> Runtime<'a> {

    pub fn new(cfg: Cfg, config : CliConfig<'a>) -> Runtime<'a> {
        let sp = config.store_path().unwrap_or(cfg.store_path());
        Runtime {
            config: config,
            configuration: cfg,
            store: Store::new(sp),
        }
    }

    pub fn is_verbose(&self) -> bool {
        self.config.is_verbose() || self.configuration.is_verbose()
    }

    pub fn is_debugging(&self) -> bool {
        self.config.is_debugging() || self.configuration.is_verbose()
    }

    pub fn store_path(&self) -> String {
        self.config.store_path().unwrap_or(self.configuration.store_path())
    }

    pub fn store(&self) -> &Store {
        &self.store
    }

    pub fn get_rtp(&self) -> String {
        if let Some(rtp) = self.config.get_rtp() {
            rtp
        } else {
            self.configuration.get_rtp()
        }
    }

    pub fn editor(&self) -> String {
        use std::env::var;

        if let Some(editor) = self.config.editor() {
            editor
        } else if let Some(editor) = self.configuration.editor() {
            editor
        } else if let Ok(editor) = var("EDITOR") {
            editor
        } else {
            String::from("vim")
        }
    }

}

impl<'a> Debug for Runtime<'a> {

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

}

<commit_msg>runtime.rs: Add options to editor string<commit_after>use std::fmt::{Debug, Formatter, Error};

extern crate log;
use log::{LogRecord, LogLevel, LogLevelFilter, LogMetadata, SetLoggerError};

pub use cli::CliConfig;
pub use configuration::Configuration as Cfg;

use storage::Store;

pub struct ImagLogger {
    lvl: LogLevel,
}

impl ImagLogger {

    pub fn new(lvl: LogLevel) -> ImagLogger {
        ImagLogger {
            lvl: lvl,
        }
    }

    pub fn init(cfg: &Cfg, config: &CliConfig) -> Result<(), SetLoggerError> {
        let lvl = if config.is_debugging() || cfg.is_debugging() {
            LogLevelFilter::Debug
        } else if config.is_verbose() || cfg.is_debugging() {
            LogLevelFilter::Info
        } else {
            LogLevelFilter::Error
        };

        log::set_logger(|max_log_lvl| {
            max_log_lvl.set(lvl);
            debug!("Init logger with: {}", lvl);
            Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
        })
    }

}

impl log::Log for ImagLogger {

    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.lvl
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            println!("[{}]: {}", record.level(), record.args());
        }
    }
}

pub struct Runtime<'a> {
    pub config : CliConfig<'a>,
    pub configuration : Cfg,
    pub store : Store,
}

impl<'a> Runtime<'a> {

    pub fn new(cfg: Cfg, config : CliConfig<'a>) -> Runtime<'a> {
        let sp = config.store_path().unwrap_or(cfg.store_path());
        Runtime {
            config: config,
            configuration: cfg,
            store: Store::new(sp),
        }
    }

    pub fn is_verbose(&self) -> bool {
        self.config.is_verbose() || self.configuration.is_verbose()
    }

    pub fn is_debugging(&self) -> bool {
        self.config.is_debugging() || self.configuration.is_verbose()
    }

    pub fn store_path(&self) -> String {
        self.config.store_path().unwrap_or(self.configuration.store_path())
    }

    pub fn store(&self) -> &Store {
        &self.store
    }

    pub fn get_rtp(&self) -> String {
        if let Some(rtp) = self.config.get_rtp() {
            rtp
        } else {
            self.configuration.get_rtp()
        }
    }

    pub fn editor(&self) -> String {
        use std::env::var;

        if let Some(editor) = self.config.editor() {
            editor + &self.config.editor_opts()[..]
        } else if let Some(editor) = self.configuration.editor() {
            editor + &self.configuration.editor_opts()[..]
        } else if let Ok(editor) = var("EDITOR") {
            editor
        } else {
            String::from("vim")
        }
    }

}

impl<'a> Debug for Runtime<'a> {

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

}

<|endoftext|>