<commit_before>use crate::progress::ProgressBar;

/// Wraps an iterator to display its progress.
pub trait ProgressIterator
where
    Self: Sized + Iterator,
{
    /// Wrap an iterator with default styling. Attempt to guess iterator
    /// length using `Iterator::size_hint`.
    fn progress(self) -> ProgressBarIter<Self> {
        let n = match self.size_hint() {
            (_, Some(n)) => n as u64,
            _ => 0,
        };
        self.progress_count(n)
    }

    /// Wrap an iterator with an explicit element count.
    fn progress_count(self, len: u64) -> ProgressBarIter<Self> {
        self.progress_with(ProgressBar::new(len))
    }

    /// Wrap an iterator with a custom progress bar.
    fn progress_with(self, progress: ProgressBar) -> ProgressBarIter<Self>;
}

/// Wraps an iterator to display its progress.
pub struct ProgressBarIter<T> {
    it: T,
    progress: ProgressBar,
}

impl<S, T: Iterator<Item = S>> Iterator for ProgressBarIter<T> {
    type Item = S;

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.it.next();

        if next.is_some() {
            self.progress.inc(1);
        } else {
            self.progress.finish();
        }

        next
    }
}

impl<S, T: Iterator<Item = S>> ProgressIterator for T {
    fn progress_with(self, progress: ProgressBar) -> ProgressBarIter<Self> {
        ProgressBarIter { it: self, progress }
    }
}

#[cfg(feature = "rayon")]
pub mod rayon_support {
    use super::*;
    use rayon::iter::{
        plumbing::Consumer, plumbing::Folder, plumbing::UnindexedConsumer, ParallelIterator,
    };
    use std::sync::{Arc, Mutex};

    pub struct ParProgressBarIter<T> {
        it: T,
        progress: Arc<Mutex<ProgressBar>>,
    }

    /// Wraps a Rayon parallel iterator.
    ///
    /// See [`ProgressIterator`](trait.ProgressIterator.html) for method
    /// documentation.
    pub trait ParallelProgressIterator
    where
        Self: Sized,
    {
        fn progress_with(self, progress: ProgressBar) -> ParProgressBarIter<Self>;

        fn progress_count(self, len: u64) -> ParProgressBarIter<Self> {
            self.progress_with(ProgressBar::new(len))
        }

        fn progress(self) -> ParProgressBarIter<Self> {
            self.progress_count(0)
        }
    }

    impl<S: Send, T: ParallelIterator<Item = S>> ParallelProgressIterator for T {
        fn progress_with(self, progress: ProgressBar) -> ParProgressBarIter<Self> {
            ParProgressBarIter {
                it: self,
                progress: Arc::new(Mutex::new(progress)),
            }
        }
    }

    struct ProgressConsumer<C> {
        base: C,
        progress: Arc<Mutex<ProgressBar>>,
    }

    impl<C> ProgressConsumer<C> {
        fn new(base: C, progress: Arc<Mutex<ProgressBar>>) -> Self {
            ProgressConsumer { base, progress }
        }
    }

    impl<T, C: Consumer<T>> Consumer<T> for ProgressConsumer<C> {
        type Folder = ProgressFolder<C::Folder>;
        type Reducer = C::Reducer;
        type Result = C::Result;

        fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
            let (left, right, reducer) = self.base.split_at(index);
            (
                ProgressConsumer::new(left, self.progress.clone()),
                ProgressConsumer::new(right, self.progress.clone()),
                reducer,
            )
        }

        fn into_folder(self) -> Self::Folder {
            ProgressFolder {
                base: self.base.into_folder(),
                progress: self.progress.clone(),
            }
        }

        fn full(&self) -> bool {
            self.base.full()
        }
    }

    impl<T, C: UnindexedConsumer<T>> UnindexedConsumer<T> for ProgressConsumer<C> {
        fn split_off_left(&self) -> Self {
            ProgressConsumer::new(self.base.split_off_left(), self.progress.clone())
        }

        fn to_reducer(&self) -> Self::Reducer {
            self.base.to_reducer()
        }
    }

    struct ProgressFolder<C> {
        base: C,
        progress: Arc<Mutex<ProgressBar>>,
    }

    impl<T, C: Folder<T>> Folder<T> for ProgressFolder<C> {
        type Result = C::Result;

        fn consume(self, item: T) -> Self {
            self.progress.lock().unwrap().inc(1);
            ProgressFolder {
                base: self.base.consume(item),
                progress: self.progress,
            }
        }

        fn complete(self) -> C::Result {
            self.base.complete()
        }

        fn full(&self) -> bool {
            self.base.full()
        }
    }

    impl<S: Send, T: ParallelIterator<Item = S>> ParallelIterator for ParProgressBarIter<T> {
        type Item = S;

        fn drive_unindexed<C: UnindexedConsumer<Self::Item>>(self, consumer: C) -> C::Result {
            let consumer1 = ProgressConsumer::new(consumer, self.progress.clone());
            self.it.drive_unindexed(consumer1)
        }
    }

    #[cfg(test)]
    mod test {
        use super::ParProgressBarIter;
        use crate::iter::rayon_support::ParallelProgressIterator;
        use crate::progress::ProgressBar;
        use rayon::iter::{IntoParallelRefIterator, ParallelIterator};

        #[test]
        fn it_can_wrap_a_parallel_iterator() {
            let v = vec![1, 2, 3];
            let wrap = |it: ParProgressBarIter<_>| {
                assert_eq!(it.map(|x| x * 2).collect::<Vec<_>>(), vec![2, 4, 6]);
            };

            wrap(v.par_iter().progress());
            wrap(v.par_iter().progress_count(3));
            wrap({
                let pb = ProgressBar::new(v.len() as u64);
                v.par_iter().progress_with(pb)
            });
        }
    }
}

#[cfg(test)]
mod test {
    use crate::iter::{ProgressBarIter, ProgressIterator};
    use crate::progress::ProgressBar;

    #[test]
    fn it_can_wrap_an_iterator() {
        let v = vec![1, 2, 3];
        let wrap = |it: ProgressBarIter<_>| {
            assert_eq!(it.map(|x| x * 2).collect::<Vec<_>>(), vec![2, 4, 6]);
        };

        wrap(v.iter().progress());
        wrap(v.iter().progress_count(3));
        wrap({
            let pb = ProgressBar::new(v.len() as u64);
            v.iter().progress_with(pb)
        });
    }
}
<commit_msg>Extend rayon related documentation<commit_after>use crate::progress::ProgressBar;

/// Wraps an iterator to display its progress.
pub trait ProgressIterator
where
    Self: Sized + Iterator,
{
    /// Wrap an iterator with default styling. Attempt to guess iterator
    /// length using `Iterator::size_hint`.
    fn progress(self) -> ProgressBarIter<Self> {
        let n = match self.size_hint() {
            (_, Some(n)) => n as u64,
            _ => 0,
        };
        self.progress_count(n)
    }

    /// Wrap an iterator with an explicit element count.
    fn progress_count(self, len: u64) -> ProgressBarIter<Self> {
        self.progress_with(ProgressBar::new(len))
    }

    /// Wrap an iterator with a custom progress bar.
    fn progress_with(self, progress: ProgressBar) -> ProgressBarIter<Self>;
}

/// Wraps an iterator to display its progress.
pub struct ProgressBarIter<T> {
    it: T,
    progress: ProgressBar,
}

impl<S, T: Iterator<Item = S>> Iterator for ProgressBarIter<T> {
    type Item = S;

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.it.next();

        if next.is_some() {
            self.progress.inc(1);
        } else {
            self.progress.finish();
        }

        next
    }
}

impl<S, T: Iterator<Item = S>> ProgressIterator for T {
    fn progress_with(self, progress: ProgressBar) -> ProgressBarIter<Self> {
        ProgressBarIter { it: self, progress }
    }
}

#[cfg(feature = "rayon")]
pub mod rayon_support {
    use super::*;
    use rayon::iter::{
        plumbing::Consumer, plumbing::Folder, plumbing::UnindexedConsumer, ParallelIterator,
    };
    use std::sync::{Arc, Mutex};

    pub struct ParProgressBarIter<T> {
        it: T,
        progress: Arc<Mutex<ProgressBar>>,
    }

    /// Wraps a Rayon parallel iterator.
    ///
    /// See [`ProgressIterator`](trait.ProgressIterator.html) for method
    /// documentation.
    pub trait ParallelProgressIterator
    where
        Self: Sized,
    {
        /// Wrap an iterator with a custom progress bar.
        fn progress_with(self, progress: ProgressBar) -> ParProgressBarIter<Self>;

        /// Wrap an iterator with an explicit element count.
        fn progress_count(self, len: u64) -> ParProgressBarIter<Self> {
            self.progress_with(ProgressBar::new(len))
        }

        /// Wrap an iterator with default styling. Contrary to `std::iter::Iterator`,
        /// `ParallelProgressIterator` does not have a `size_hint` function. Due to this
        /// the resulting progress bar will always show a length of `0` as there is no
        /// way to determine the iterator's length without consuming it in the process.
        fn progress(self) -> ParProgressBarIter<Self> {
            self.progress_count(0)
        }
    }

    impl<S: Send, T: ParallelIterator<Item = S>> ParallelProgressIterator for T {
        fn progress_with(self, progress: ProgressBar) -> ParProgressBarIter<Self> {
            ParProgressBarIter {
                it: self,
                progress: Arc::new(Mutex::new(progress)),
            }
        }
    }

    struct ProgressConsumer<C> {
        base: C,
        progress: Arc<Mutex<ProgressBar>>,
    }

    impl<C> ProgressConsumer<C> {
        fn new(base: C, progress: Arc<Mutex<ProgressBar>>) -> Self {
            ProgressConsumer { base, progress }
        }
    }

    impl<T, C: Consumer<T>> Consumer<T> for ProgressConsumer<C> {
        type Folder = ProgressFolder<C::Folder>;
        type Reducer = C::Reducer;
        type Result = C::Result;

        fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
            let (left, right, reducer) = self.base.split_at(index);
            (
                ProgressConsumer::new(left, self.progress.clone()),
                ProgressConsumer::new(right, self.progress.clone()),
                reducer,
            )
        }

        fn into_folder(self) -> Self::Folder {
            ProgressFolder {
                base: self.base.into_folder(),
                progress: self.progress.clone(),
            }
        }

        fn full(&self) -> bool {
            self.base.full()
        }
    }

    impl<T, C: UnindexedConsumer<T>> UnindexedConsumer<T> for ProgressConsumer<C> {
        fn split_off_left(&self) -> Self {
            ProgressConsumer::new(self.base.split_off_left(), self.progress.clone())
        }

        fn to_reducer(&self) -> Self::Reducer {
            self.base.to_reducer()
        }
    }

    struct ProgressFolder<C> {
        base: C,
        progress: Arc<Mutex<ProgressBar>>,
    }

    impl<T, C: Folder<T>> Folder<T> for ProgressFolder<C> {
        type Result = C::Result;

        fn consume(self, item: T) -> Self {
            self.progress.lock().unwrap().inc(1);
            ProgressFolder {
                base: self.base.consume(item),
                progress: self.progress,
            }
        }

        fn complete(self) -> C::Result {
            self.base.complete()
        }

        fn full(&self) -> bool {
            self.base.full()
        }
    }

    impl<S: Send, T: ParallelIterator<Item = S>> ParallelIterator for ParProgressBarIter<T> {
        type Item = S;

        fn drive_unindexed<C: UnindexedConsumer<Self::Item>>(self, consumer: C) -> C::Result {
            let consumer1 = ProgressConsumer::new(consumer, self.progress.clone());
            self.it.drive_unindexed(consumer1)
        }
    }

    #[cfg(test)]
    mod test {
        use super::ParProgressBarIter;
        use crate::iter::rayon_support::ParallelProgressIterator;
        use crate::progress::ProgressBar;
        use rayon::iter::{IntoParallelRefIterator, ParallelIterator};

        #[test]
        fn it_can_wrap_a_parallel_iterator() {
            let v = vec![1, 2, 3];
            let wrap = |it: ParProgressBarIter<_>| {
                assert_eq!(it.map(|x| x * 2).collect::<Vec<_>>(), vec![2, 4, 6]);
            };

            wrap(v.par_iter().progress());
            wrap(v.par_iter().progress_count(3));
            wrap({
                let pb = ProgressBar::new(v.len() as u64);
                v.par_iter().progress_with(pb)
            });
        }
    }
}

#[cfg(test)]
mod test {
    use crate::iter::{ProgressBarIter, ProgressIterator};
    use crate::progress::ProgressBar;

    #[test]
    fn it_can_wrap_an_iterator() {
        let v = vec![1, 2, 3];
        let wrap = |it: ProgressBarIter<_>| {
            assert_eq!(it.map(|x| x * 2).collect::<Vec<_>>(), vec![2, 4, 6]);
        };

        wrap(v.iter().progress());
        wrap(v.iter().progress_count(3));
        wrap({
            let pb = ProgressBar::new(v.len() as u64);
            v.iter().progress_with(pb)
        });
    }
}
<|endoftext|>


<commit_before>use core::Node;
use core::Tree;

// XXX: name
enum Item<T> {
    Left(T),
    Right(T),
}
pub struct Iter<'a, K: 'a, V: 'a> {
    stack: Vec<Item<&'a Node<K, V>>>,
}
impl<'a, K: 'a, V: 'a> Iter<'a, K, V> {
    pub fn new(tree: &'a Tree<K, V>) -> Self {
        if let Some(root) = tree.root.as_ref() {
            Iter { stack: vec![Item::Left(root)] }
        } else {
            Iter { stack: vec![] }
        }
    }
}
impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> {
    type Item = (&'a K, &'a V);
    fn next(&mut self) -> Option<Self::Item> {
        while let Some(e) = self.stack.pop() {
            match e {
                Item::Left(e) => {
                    self.stack.push(Item::Right(e));
                    if let Some(child) = e.lft.as_ref() {
                        self.stack.push(Item::Left(child));
                    }
                }
                Item::Right(e) => {
                    if let Some(child) = e.rgt.as_ref() {
                        self.stack.push(Item::Left(child));
                    }
                    return Some((&e.key, &e.val));
                }
            }
        }
        None
    }
}

pub struct IntoIter<K, V> {
    stack: Vec<Item<Node<K, V>>>,
}
impl<K, V> IntoIter<K, V> {
    pub fn new(mut tree: Tree<K, V>) -> Self {
        if let Some(root) = tree.root.take() {
            IntoIter { stack: vec![Item::Left(*root)] }
        } else {
            IntoIter { stack: vec![] }
        }
    }
}
impl<K, V> Iterator for IntoIter<K, V> {
    type Item = (K, V);
    fn next(&mut self) -> Option<Self::Item> {
        while let Some(e) = self.stack.pop() {
            match e {
                Item::Left(mut e) => {
                    let lft = e.lft.take();
                    self.stack.push(Item::Right(e));
                    if let Some(child) = lft {
                        self.stack.push(Item::Left(*child));
                    }
                }
                Item::Right(mut e) => {
                    if let Some(child) = e.rgt.take() {
                        self.stack.push(Item::Left(*child));
                    }
                    return Some((e.key, e.val));
                }
            }
        }
        None
    }
}

enum Item2<K, V, T> {
    Left(T),
    Right((K, V), Option<T>),
}

pub struct IterMut<'a, K: 'a, V: 'a> {
    stack: Vec<Item2<&'a K, &'a mut V, &'a mut Node<K, V>>>,
}
impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> {
    pub fn new(tree: &'a mut Tree<K, V>) -> Self {
        if let Some(root) = tree.root.as_mut() {
            IterMut { stack: vec![Item2::Left(root)] }
        } else {
            IterMut { stack: vec![] }
        }
    }
}
impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> {
    type Item = (&'a K, &'a mut V);
    fn next(&mut self) -> Option<Self::Item> {
        while let Some(e) = self.stack.pop() {
            match e {
                Item2::Left(e) => {
                    use std::borrow::BorrowMut;
                    self.stack
                        .push(Item2::Right((&e.key, &mut e.val),
                                           e.rgt.as_mut().map(|r| r.borrow_mut())));
                    if let Some(child) = e.lft.as_mut() {
                        self.stack.push(Item2::Left(child));
                    }
                }
                Item2::Right(e, rgt) => {
                    if let Some(child) = rgt {
                        self.stack.push(Item2::Left(child));
                    }
                    return Some(e);
                }
            }
        }
        None
    }
}
<commit_msg>Refactor iter module<commit_after>//! Iterators for splay tree
use core::Node;
use core::Tree;

enum Visit<E, N> {
    Elem(E),
    Node(N),
}

pub struct Iter<'a, K: 'a, V: 'a> {
    stack: Vec<Visit<(&'a K, &'a V), &'a Node<K, V>>>,
}
impl<'a, K: 'a, V: 'a> Iter<'a, K, V> {
    pub fn new(tree: &'a Tree<K, V>) -> Self {
        if let Some(root) = tree.root.as_ref() {
            Iter { stack: vec![Visit::Node(root)] }
        } else {
            Iter { stack: vec![] }
        }
    }
}
impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> {
    type Item = (&'a K, &'a V);
    fn next(&mut self) -> Option<Self::Item> {
        while let Some(v) = self.stack.pop() {
            match v {
                Visit::Node(n) => {
                    n.rgt.as_ref().map(|rgt| self.stack.push(Visit::Node(rgt)));
                    self.stack.push(Visit::Elem((&n.key, &n.val)));
                    n.lft.as_ref().map(|lft| self.stack.push(Visit::Node(lft)));
                }
                Visit::Elem(e) => {
                    return Some(e);
                }
            }
        }
        None
    }
}

pub struct IntoIter<K, V> {
    stack: Vec<Visit<(K, V), Node<K, V>>>,
}
impl<K, V> IntoIter<K, V> {
    pub fn new(tree: Tree<K, V>) -> Self {
        if let Some(root) = tree.root {
            IntoIter { stack: vec![Visit::Node(*root)] }
        } else {
            IntoIter { stack: vec![] }
        }
    }
}
impl<K, V> Iterator for IntoIter<K, V> {
    type Item = (K, V);
    fn next(&mut self) -> Option<Self::Item> {
        while let Some(v) = self.stack.pop() {
            match v {
                Visit::Node(mut n) => {
                    n.rgt.take().map(|rgt| self.stack.push(Visit::Node(*rgt)));
                    self.stack.push(Visit::Elem((n.key, n.val)));
                    n.lft.take().map(|lft| self.stack.push(Visit::Node(*lft)));
                }
                Visit::Elem(e) => {
                    return Some(e);
                }
            }
        }
        None
    }
}

pub struct IterMut<'a, K: 'a, V: 'a> {
    stack: Vec<Visit<(&'a K, &'a mut V), &'a mut Node<K, V>>>,
}
impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> {
    pub fn new(tree: &'a mut Tree<K, V>) -> Self {
        if let Some(root) = tree.root.as_mut() {
            IterMut { stack: vec![Visit::Node(root)] }
        } else {
            IterMut { stack: vec![] }
        }
    }
}
impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> {
    type Item = (&'a K, &'a mut V);
    fn next(&mut self) -> Option<Self::Item> {
        while let Some(v) = self.stack.pop() {
            match v {
                Visit::Node(n) => {
                    n.rgt.as_mut().map(|rgt| self.stack.push(Visit::Node(rgt)));
                    self.stack.push(Visit::Elem((&n.key, &mut n.val)));
                    n.lft.as_mut().map(|lft| self.stack.push(Visit::Node(lft)));
                }
                Visit::Elem(e) => {
                    return Some(e);
                }
            }
        }
        None
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

use chrono::{DateTime, Duration, Utc};
use std::fs::{self, File, OpenOptions};
use std::io::{self, Write};
use std::path::{Path, PathBuf};

/// Adds `Duration` to the initial date and time.
fn compute_rotation_time(initial: &DateTime<Utc>, timespan: Duration) -> DateTime<Utc> {
    *initial + timespan
}

/// Rotates file path with given timestamp.
fn rotation_file_path_with_timestamp(
    file_path: impl AsRef<Path>,
    timestamp: &DateTime<Utc>,
) -> PathBuf {
    let file_path = file_path.as_ref();
    let file_name = file_path
        .file_name()
        .and_then(|x| x.to_str())
        .expect("Log file name was not valid.");
    file_path.with_file_name(format!(
        "{}.{}",
        file_name,
        timestamp.format("%Y-%m-%d-%H:%M:%S")
    ))
}

/// Opens log file with append mode. Creates a new log file if it doesn't exist.
fn open_log_file(path: impl AsRef<Path>) -> io::Result<File> {
    let path = path.as_ref();
    let parent = path
        .parent()
        .expect("Unable to get parent directory of log file");
    if !parent.is_dir() {
        fs::create_dir_all(parent)?
    }
    OpenOptions::new().append(true).create(true).open(path)
}

/// This FileLogger rotates logs according to a time span.
/// After rotating, the original log file would be renamed to "{original name}.{%Y-%m-%d-%H:%M:%S}"
/// Note: log file will *not* be compressed or otherwise modified.
pub struct RotatingFileLogger {
    rotation_timespan: Duration,
    next_rotation_time: DateTime<Utc>,
    file_path: PathBuf,
    file: Option<File>,
}

impl RotatingFileLogger {
    pub fn new(file_path: impl AsRef<Path>, rotation_timespan: Duration) -> io::Result<Self> {
        let file_path = file_path.as_ref().to_path_buf();
        let file = Some(open_log_file(&file_path)?);
        let file_attr = fs::metadata(&file_path)?;
        let file_modified_time = file_attr.modified().unwrap().into();
        let next_rotation_time = compute_rotation_time(&file_modified_time, rotation_timespan);
        Ok(Self {
            next_rotation_time,
            file_path,
            rotation_timespan,
            file,
        })
    }

    /// Opens log file with append mode. Creates a new file if it doesn't exist.
    fn open(&mut self) -> io::Result<()> {
        self.file = Some(open_log_file(&self.file_path)?);
        Ok(())
    }

    fn should_rotate(&mut self) -> bool {
        Utc::now() > self.next_rotation_time
    }

    /// Rotates the current file and updates the next rotation time.
    fn rotate(&mut self) -> io::Result<()> {
        self.close()?;
        let new_path = rotation_file_path_with_timestamp(&self.file_path, &Utc::now());
        fs::rename(&self.file_path, &new_path)?;
        self.update_rotation_time();
        self.open()
    }

    /// Updates the next rotation time.
    fn update_rotation_time(&mut self) {
        let now = Utc::now();
        self.next_rotation_time = compute_rotation_time(&now, self.rotation_timespan);
    }

    /// Flushes and closes log file, without rotation.
    fn close(&mut self) -> io::Result<()> {
        assert!(self.file.is_some());
        self.file.take().unwrap().flush()
    }
}

impl Write for RotatingFileLogger {
    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
        assert!(self.file.is_some());
        self.file.as_mut().unwrap().write(bytes)
    }

    fn flush(&mut self) -> io::Result<()> {
        if self.should_rotate() {
            self.rotate()?;
        };
        assert!(self.file.is_some());
        self.file.as_mut().unwrap().flush()
    }
}

impl Drop for RotatingFileLogger {
    fn drop(&mut self) {
        self.close().unwrap()
    }
}

#[cfg(test)]
mod tests {
    use std::fs::OpenOptions;
    use std::io::prelude::*;
    use std::path::Path;

    use chrono::{Duration, Utc};
    use tempdir::TempDir;
    use utime;

    use super::{rotation_file_path_with_timestamp, RotatingFileLogger};

    fn file_exists(file: impl AsRef<Path>) -> bool {
        let path = file.as_ref();
        path.exists() && path.is_file()
    }

    #[test]
    fn test_rotating_file_logger() {
        let tmp_dir = TempDir::new("").unwrap();
        let log_file = tmp_dir
            .path()
            .join("test_rotating_file_logger.log")
            .to_str()
            .unwrap()
            .to_string();
        // create a file with mtime == one day ago
        {
            let mut file = OpenOptions::new()
                .append(true)
                .create(true)
                .open(&log_file)
                .unwrap();
            file.write_all(b"hello world!").unwrap();
        }
        let now = Utc::now();
        let one_day = Duration::days(1);
        let one_day_ago = now - one_day;
        let one_day_ago_ts = one_day_ago.timestamp() as u64;
        utime::set_file_times(&log_file, one_day_ago_ts, one_day_ago_ts).unwrap();
        // initialize the logger
        let mut logger = RotatingFileLogger::new(&log_file, one_day).unwrap();
        assert!(logger.should_rotate());
        logger.rotate().unwrap();
        // check the rotated file exist
        let rotated_file = rotation_file_path_with_timestamp(&log_file, &now);
        assert!(file_exists(&rotated_file));
        assert!(!logger.should_rotate());
    }

    #[test]
    fn test_close_file_logger() {
        let tmp_dir = TempDir::new("").unwrap();
        let log_file = tmp_dir
            .path()
            .join("test_close_file_logger.log")
            .to_str()
            .unwrap()
            .to_string();
        let one_day = Duration::days(1);

        let mut logger = RotatingFileLogger::new(&log_file, one_day).unwrap();
        // Handles written amount returned.
        let _ = logger.write(b"write before close").unwrap();
        logger.flush().unwrap();
        logger.close().unwrap();
        assert!(::panic_hook::recover_safe(|| logger.write(b"write after close")).is_err());
        assert!(::panic_hook::recover_safe(|| logger.flush()).is_err());
        assert!(::panic_hook::recover_safe(|| logger.close()).is_err());
        // Reopens file, otherwise `close()` will fail in assertion when `drop()`.
        logger.open().unwrap();
        drop(logger);
    }
}
<commit_msg>util: avoid panic in RotatingFileLogger (#4492)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

use chrono::{DateTime, Duration, Utc};
use std::fs::{self, File, OpenOptions};
use std::io::{self, Write};
use std::path::{Path, PathBuf};

/// Adds `Duration` to the initial date and time.
fn compute_rotation_time(initial: &DateTime<Utc>, timespan: Duration) -> DateTime<Utc> {
    *initial + timespan
}

/// Rotates file path with given timestamp.
fn rotation_file_path_with_timestamp(
    file_path: impl AsRef<Path>,
    timestamp: &DateTime<Utc>,
) -> PathBuf {
    let mut file_path = file_path.as_ref().as_os_str().to_os_string();
    file_path.push(format!(".{}", timestamp.format("%Y-%m-%d-%H:%M:%S")));
    file_path.into()
}

/// Opens log file with append mode. Creates a new log file if it doesn't exist.
fn open_log_file(path: impl AsRef<Path>) -> io::Result<File> {
    let path = path.as_ref();
    let parent = path
        .parent()
        .expect("Unable to get parent directory of log file");
    if !parent.is_dir() {
        fs::create_dir_all(parent)?
    }
    OpenOptions::new().append(true).create(true).open(path)
}

/// This FileLogger rotates logs according to a time span.
/// After rotating, the original log file would be renamed to "{original name}.{%Y-%m-%d-%H:%M:%S}"
/// Note: log file will *not* be compressed or otherwise modified.
pub struct RotatingFileLogger {
    rotation_timespan: Duration,
    next_rotation_time: DateTime<Utc>,
    file_path: PathBuf,
    file: File,
}

impl RotatingFileLogger {
    pub fn new(file_path: impl AsRef<Path>, rotation_timespan: Duration) -> io::Result<Self> {
        let file_path = file_path.as_ref().to_path_buf();
        let file = open_log_file(&file_path)?;
        let file_attr = fs::metadata(&file_path)?;
        let file_modified_time = file_attr.modified().unwrap().into();
        let next_rotation_time = compute_rotation_time(&file_modified_time, rotation_timespan);
        Ok(Self {
            next_rotation_time,
            file_path,
            rotation_timespan,
            file,
        })
    }

    fn should_rotate(&mut self) -> bool {
        Utc::now() > self.next_rotation_time
    }

    /// Rotates the current file and updates the next rotation time.
    fn rotate(&mut self) -> io::Result<()> {
        self.flush()?;

        // Note: renaming files while they're open only works on Linux and macOS.
        let new_path = rotation_file_path_with_timestamp(&self.file_path, &Utc::now());
        fs::rename(&self.file_path, new_path)?;
        let new_file = open_log_file(&self.file_path)?;
        self.update_rotation_time();
        self.file = new_file;
        Ok(())
    }

    /// Updates the next rotation time.
    fn update_rotation_time(&mut self) {
        let now = Utc::now();
        self.next_rotation_time = compute_rotation_time(&now, self.rotation_timespan);
    }

    /// Flushes the log file, without rotation.
    fn flush(&mut self) -> io::Result<()> {
        self.file.flush()
    }
}

impl Write for RotatingFileLogger {
    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
        self.file.write(bytes)
    }

    fn flush(&mut self) -> io::Result<()> {
        if self.should_rotate() {
            self.rotate()?;
        };
        self.file.flush()
    }
}

impl Drop for RotatingFileLogger {
    fn drop(&mut self) {
        let _ = self.file.flush();
    }
}

#[cfg(test)]
mod tests {
    use std::fs::OpenOptions;
    use std::io::prelude::*;
    use std::path::Path;

    use chrono::{Duration, Utc};
    use tempdir::TempDir;
    use utime;

    use super::{rotation_file_path_with_timestamp, RotatingFileLogger};

    fn file_exists(file: impl AsRef<Path>) -> bool {
        let path = file.as_ref();
        path.exists() && path.is_file()
    }

    #[test]
    fn test_rotating_file_logger() {
        let tmp_dir = TempDir::new("").unwrap();
        let log_file = tmp_dir
            .path()
            .join("test_rotating_file_logger.log")
            .to_str()
            .unwrap()
            .to_string();
        // create a file with mtime == one day ago
        {
            let mut file = OpenOptions::new()
                .append(true)
                .create(true)
                .open(&log_file)
                .unwrap();
            file.write_all(b"hello world!").unwrap();
        }
        let now = Utc::now();
        let one_day = Duration::days(1);
        let one_day_ago = now - one_day;
        let one_day_ago_ts = one_day_ago.timestamp() as u64;
        utime::set_file_times(&log_file, one_day_ago_ts, one_day_ago_ts).unwrap();
        // initialize the logger
        let mut logger = RotatingFileLogger::new(&log_file, one_day).unwrap();
        assert!(logger.should_rotate());
        logger.rotate().unwrap();
        // check the rotated file exist
        let rotated_file = rotation_file_path_with_timestamp(&log_file, &now);
        assert!(file_exists(&rotated_file));
        assert!(!logger.should_rotate());
    }

    #[test]
    fn test_failing_to_rotate_file_will_not_cause_panic() {
        let tmp_dir = TempDir::new("").unwrap();
        let log_file = tmp_dir.path().join("test_rotating_file_logger.log");
        let mut logger = RotatingFileLogger::new(&log_file, Duration::days(1)).unwrap();
        // delete the log_file so rotation fails.
        std::fs::remove_file(&log_file).unwrap();
        logger.rotate().unwrap_err();
        // dropping the logger still should not panic.
        drop(logger);
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::rc::Rc;

use color::Color;
use linear::Vector2;

pub trait Widget {
  fn get_rect(&self) -> Rect;
}

pub trait WidgetContainer: Widget {
  fn get_widgets(&self) -> &[Rc<Widget>];
  fn add_widget(&mut self, widget: Rc<Widget>);
}

type Px = u32;
type Pos = Vector2<Px>;

pub mod layout {
  pub struct Horizontal;
  pub struct Vertical;
  pub struct Floating;
}

// Upper-left is origin.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Rect {
  lower: Pos,
  upper: Pos
}

impl Rect {
  pub fn new(upper_left: Pos, w: Px, h: Px) -> Self {
    Rect {
      lower: Pos::new(upper_left.x, upper_left.y + h),
      upper: Pos::new(upper_left.x + w, upper_left.y)
    }
  }
}

pub struct FillRectWidget<L> {
  color: Color,
  rect: Rect,
  widgets: Vec<Rc<Widget>>,
  _l: PhantomData<L>
}

impl<L> FillRectWidget<L> {
  pub fn new(rect: Rect, color: Color) -> Self {
    FillRectWidget {
      color: color,
      rect: rect,
      widgets: Vec::new(),
      _l: PhantomData
    }
  }
}

impl<L> Widget for FillRectWidget<L> {
  fn get_rect(&self) -> Rect {
    self.rect.clone()
  }
}

impl<L> WidgetContainer for FillRectWidget<L> {
  fn get_widgets(&self) -> &[Rc<Widget>] {
    &self.widgets
  }

  fn add_widget(&mut self, widget: Rc<Widget>) {
    self.widgets.push(widget);
  }
}

pub struct TopWidget<L> {
  rect: Rect,
  widgets: Vec<Rc<Widget>>,
  _l: PhantomData<L>
}

impl<L> TopWidget<L> {
  pub fn new(w: Px, h: Px) -> Self {
    TopWidget {
      rect: Rect::new(Pos::new(0, 0), w, h),
      widgets: Vec::new(),
      _l: PhantomData
    }
  }

}

impl<L> Widget for TopWidget<L> {
  fn get_rect(&self) -> Rect {
    self.rect.clone()
  }
}

impl<L> WidgetContainer for TopWidget<L> {
  fn get_widgets(&self) -> &[Rc<Widget>] {
    &self.widgets
  }

  fn add_widget(&mut self, widget: Rc<Widget>) {
    self.widgets.push(widget);
  }
}

fn test() {
  let mut top = TopWidget::<layout::Vertical>::new(100, 100);
  let fill = FillRectWidget::<layout::Floating>::new(Rect::new(Pos::new(0, 0), 10, 10), Color::new(1., 0., 0.));

  top.add_widget(Rc::new(fill));
}
<commit_msg>Removed gui.rs. We’ll be replacing it by an iteratable module hierarchy.<commit_after><|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate rustc_interface;
extern crate rustc_driver;
extern crate rustc_session;
extern crate rustc_span;

use rustc_session::DiagnosticOutput;
use rustc_session::config::{Input, Options, OutputType, OutputTypes};
use rustc_interface::interface;
use rustc_span::source_map::FileName;

use std::path::PathBuf;

fn main() {
    let src = r#"
    fn main() {}
    "#;

    let args: Vec<String> = std::env::args().collect();

    if args.len() < 4 {
        panic!("expected rustc path");
    }

    let tmpdir = PathBuf::from(&args[1]);

    let mut sysroot = PathBuf::from(&args[3]);
    sysroot.pop();
    sysroot.pop();

    compile(src.to_string(), tmpdir.join("out"), sysroot.clone());

    compile(src.to_string(), tmpdir.join("out"), sysroot.clone());
}

fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
    let mut opts = Options::default();
    opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
    opts.maybe_sysroot = Some(sysroot);

    if let Ok(linker) = std::env::var("RUSTC_LINKER") {
        opts.cg.linker = Some(linker.into());
    }

    let name = FileName::anon_source_code(&code);
    let input = Input::Str { name, input: code };

    let config = interface::Config {
        opts,
        crate_cfg: Default::default(),
        input,
        input_path: None,
        output_file: Some(output),
        output_dir: None,
        file_loader: None,
        diagnostic_output: DiagnosticOutput::Default,
        stderr: None,
        lint_caps: Default::default(),
        parse_sess_created: None,
        register_lints: None,
        override_queries: None,
        make_codegen_backend: None,
        registry: rustc_driver::diagnostics_registry(),
    };

    interface::run_compiler(config, |compiler| {
        // This runs all the passes prior to linking, too.
        let linker = compiler.enter(|queries| {
            queries.linker()
        });
        if let Ok(linker) = linker {
            linker.link();
        }
    });
}
<commit_msg>Fix test.<commit_after>#![feature(rustc_private)]

extern crate rustc_interface;
extern crate rustc_driver;
extern crate rustc_session;
extern crate rustc_span;

use rustc_session::DiagnosticOutput;
use rustc_session::config::{Input, Options, OutputType, OutputTypes};
use rustc_interface::interface;
use rustc_span::source_map::FileName;

use std::path::PathBuf;

fn main() {
    let src = r#"
    fn main() {}
    "#;

    let args: Vec<String> = std::env::args().collect();

    if args.len() < 4 {
        panic!("expected rustc path");
    }

    let tmpdir = PathBuf::from(&args[1]);

    let mut sysroot = PathBuf::from(&args[3]);
    sysroot.pop();
    sysroot.pop();

    compile(src.to_string(), tmpdir.join("out"), sysroot.clone());

    compile(src.to_string(), tmpdir.join("out"), sysroot.clone());
}

fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
    let mut opts = Options::default();
    opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
    opts.maybe_sysroot = Some(sysroot);

    if let Ok(linker) = std::env::var("RUSTC_LINKER") {
        opts.cg.linker = Some(linker.into());
    }

    let name = FileName::anon_source_code(&code);
    let input = Input::Str { name, input: code };

    let config = interface::Config {
        opts,
        crate_cfg: Default::default(),
        input,
        input_path: None,
        output_file: Some(output),
        output_dir: None,
        temps_dir: None,
        file_loader: None,
        diagnostic_output: DiagnosticOutput::Default,
        stderr: None,
        lint_caps: Default::default(),
        parse_sess_created: None,
        register_lints: None,
        override_queries: None,
        make_codegen_backend: None,
        registry: rustc_driver::diagnostics_registry(),
    };

    interface::run_compiler(config, |compiler| {
        // This runs all the passes prior to linking, too.
        let linker = compiler.enter(|queries| {
            queries.linker()
        });
        if let Ok(linker) = linker {
            linker.link();
        }
    });
}
<|endoftext|>


<commit_before>use std::io;

use crate::backend::Backend;
use crate::buffer::Cell;
use crate::layout::Rect;
use crate::style::{Color, Modifier, Style};
use crate::symbols::{bar, block};
#[cfg(unix)]
use crate::symbols::{line, DOT};
#[cfg(unix)]
use pancurses::ToChtype;
use unicode_segmentation::UnicodeSegmentation;

pub struct CursesBackend {
    curses: easycurses::EasyCurses,
}

impl CursesBackend {
    pub fn new() -> Option<CursesBackend> {
        let curses = easycurses::EasyCurses::initialize_system()?;
        Some(CursesBackend { curses })
    }

    pub fn with_curses(curses: easycurses::EasyCurses) -> CursesBackend {
        CursesBackend { curses }
    }

    pub fn get_curses(&self) -> &easycurses::EasyCurses {
        &self.curses
    }

    pub fn get_curses_mut(&mut self) -> &mut easycurses::EasyCurses {
        &mut self.curses
    }
}

impl Backend for CursesBackend {
    fn draw<'a, I>(&mut self, content: I) -> io::Result<()>
    where
        I: Iterator<Item = (u16, u16, &'a Cell)>,
    {
        let mut last_col = 0;
        let mut last_row = 0;
        let mut style = Style {
            fg: Color::Reset,
            bg: Color::Reset,
            modifier: Modifier::Reset,
        };
        let mut curses_style = CursesStyle {
            fg: easycurses::Color::White,
            bg: easycurses::Color::Black,
            attribute: pancurses::Attribute::Normal,
        };
        let mut update_color = false;
        for (col, row, cell) in content {
            // eprintln!("{:?}", cell);
            if row != last_row || col != last_col + 1 {
                self.curses.move_rc(row as i32, col as i32);
            }
            last_col = col;
            last_row = row;
            if cell.style.modifier != style.modifier {
                if curses_style.attribute != pancurses::Attribute::Normal {
                    self.curses.win.attroff(curses_style.attribute);
                }
                let attribute: pancurses::Attribute = cell.style.modifier.into();
                self.curses.win.attron(attribute);
                curses_style.attribute = attribute;
                style.modifier = cell.style.modifier;
            };
            if cell.style.fg != style.fg {
                update_color = true;
                if let Some(ccolor) = cell.style.fg.into() {
                    style.fg = cell.style.fg;
                    curses_style.fg = ccolor;
                } else {
                    style.fg = Color::White;
                    curses_style.fg = easycurses::Color::White;
                }
            };
            if cell.style.bg != style.bg {
                update_color = true;
                if let Some(ccolor) = cell.style.bg.into() {
                    style.bg = cell.style.bg;
                    curses_style.bg = ccolor;
                } else {
                    style.bg = Color::Black;
                    curses_style.bg = easycurses::Color::Black;
                }
            };
            if update_color {
                self.curses
                    .set_color_pair(easycurses::ColorPair::new(curses_style.fg, curses_style.bg));
            };
            update_color = false;
            draw(&mut self.curses, cell.symbol.as_str());
        }
        self.curses.win.attrset(pancurses::Attribute::Normal);
        self.curses.set_color_pair(easycurses::ColorPair::new(
            easycurses::Color::White,
            easycurses::Color::Black,
        ));
        Ok(())
    }
    fn hide_cursor(&mut self) -> io::Result<()> {
        self.curses
            .set_cursor_visibility(easycurses::CursorVisibility::Invisible);
        Ok(())
    }
    fn show_cursor(&mut self) -> io::Result<()> {
        self.curses
            .set_cursor_visibility(easycurses::CursorVisibility::Visible);
        Ok(())
    }
    fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
        let (x, y) = self.curses.get_cursor_rc();
        Ok((x as u16, y as u16))
    }
    fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
        self.curses.move_rc(x as i32, y as i32);
        Ok(())
    }
    fn clear(&mut self) -> io::Result<()> {
        self.curses.clear();
        // self.curses.refresh();
        Ok(())
    }
    fn size(&self) -> Result<Rect, io::Error> {
        let (nrows, ncols) = self.curses.get_row_col_count();
        Ok(Rect::new(0, 0, ncols as u16, nrows as u16))
    }
    fn flush(&mut self) -> io::Result<()> {
        self.curses.refresh();
        Ok(())
    }
}

struct CursesStyle {
    fg: easycurses::Color,
    bg: easycurses::Color,
    attribute: pancurses::Attribute,
}

#[cfg(unix)]
/// Deals with lack of unicode support for ncurses on unix
fn draw(curses: &mut easycurses::EasyCurses, symbol: &str) {
    for grapheme in symbol.graphemes(true) {
        let ch = match grapheme {
            line::TOP_RIGHT => pancurses::ACS_URCORNER(),
            line::VERTICAL => pancurses::ACS_VLINE(),
            line::HORIZONTAL => pancurses::ACS_HLINE(),
            line::TOP_LEFT => pancurses::ACS_ULCORNER(),
            line::BOTTOM_RIGHT => pancurses::ACS_LRCORNER(),
            line::BOTTOM_LEFT => pancurses::ACS_LLCORNER(),
            line::VERTICAL_LEFT => pancurses::ACS_RTEE(),
            line::VERTICAL_RIGHT => pancurses::ACS_LTEE(),
            line::HORIZONTAL_DOWN => pancurses::ACS_TTEE(),
            line::HORIZONTAL_UP => pancurses::ACS_BTEE(),
            block::FULL => pancurses::ACS_BLOCK(),
            block::SEVEN_EIGHTHS => pancurses::ACS_BLOCK(),
            block::THREE_QUATERS => pancurses::ACS_BLOCK(),
            block::FIVE_EIGHTHS => pancurses::ACS_BLOCK(),
            block::HALF => pancurses::ACS_BLOCK(),
            block::THREE_EIGHTHS => ' '.into(),
            block::ONE_QUATER => ' '.into(),
            block::ONE_EIGHTH => ' '.into(),
            bar::SEVEN_EIGHTHS => pancurses::ACS_BLOCK(),
            bar::THREE_QUATERS => pancurses::ACS_BLOCK(),
            bar::FIVE_EIGHTHS => pancurses::ACS_BLOCK(),
            bar::HALF => pancurses::ACS_BLOCK(),
            bar::THREE_EIGHTHS => pancurses::ACS_S9(),
            bar::ONE_QUATER => pancurses::ACS_S9(),
            bar::ONE_EIGHTH => pancurses::ACS_S9(),
            DOT => pancurses::ACS_BULLET(),
            unicode_char => {
                if unicode_char.is_ascii() {
                    let mut chars = unicode_char.chars();
                    if let Some(ch) = chars.next() {
                        ch.to_chtype()
                    } else {
                        pancurses::ACS_BLOCK()
                    }
                } else {
                    pancurses::ACS_BLOCK()
                }
            }
        };
        curses.win.addch(ch);
    }
}

#[cfg(windows)]
fn draw(curses: &mut easycurses::EasyCurses, symbol: &str) {
    for grapheme in symbol.graphemes(true) {
        let ch = match grapheme {
            block::SEVEN_EIGHTHS => block::FULL,
            block::THREE_QUATERS => block::FULL,
            block::FIVE_EIGHTHS => block::HALF,
            block::THREE_EIGHTHS => block::HALF,
            block::ONE_QUATER => block::HALF,
            block::ONE_EIGHTH => " ",
            bar::SEVEN_EIGHTHS => bar::FULL,
            bar::THREE_QUATERS => bar::FULL,
            bar::FIVE_EIGHTHS => bar::HALF,
            bar::THREE_EIGHTHS => bar::HALF,
            bar::ONE_QUATER => bar::HALF,
            bar::ONE_EIGHTH => " ",
            ch => ch,
        };
        // curses.win.addch(ch);
        curses.print(ch);
    }
}

impl From<Color> for Option<easycurses::Color> {
    fn from(color: Color) -> Option<easycurses::Color> {
        match color {
            Color::Reset => None,
            Color::Black => Some(easycurses::Color::Black),
            Color::Red | Color::LightRed => Some(easycurses::Color::Red),
            Color::Green | Color::LightGreen => Some(easycurses::Color::Green),
            Color::Yellow | Color::LightYellow => Some(easycurses::Color::Yellow),
            Color::Magenta | Color::LightMagenta => Some(easycurses::Color::Magenta),
            Color::Cyan | Color::LightCyan => Some(easycurses::Color::Cyan),
            Color::White | Color::Gray | Color::DarkGray => Some(easycurses::Color::White),
            Color::Blue | Color::LightBlue => Some(easycurses::Color::Blue),
            Color::Rgb(_, _, _) => None,
        }
    }
}

impl From<Modifier> for pancurses::Attribute {
    fn from(modifier: Modifier) -> pancurses::Attribute {
        match modifier {
            Modifier::Blink => pancurses::Attribute::Blink,
            Modifier::Bold => pancurses::Attribute::Bold,
            Modifier::CrossedOut => pancurses::Attribute::Strikeout,
            Modifier::Faint => pancurses::Attribute::Dim,
            Modifier::Invert => pancurses::Attribute::Reverse,
            Modifier::Italic => pancurses::Attribute::Italic,
            Modifier::Underline => pancurses::Attribute::Underline,
            _ => pancurses::Attribute::Normal,
        }
    }
}
<commit_msg>fix(backend/curses): use chtype to achieve platform agnostic conversion of graphemes<commit_after>use std::io;

use crate::backend::Backend;
use crate::buffer::Cell;
use crate::layout::Rect;
use crate::style::{Color, Modifier, Style};
use crate::symbols::{bar, block};
#[cfg(unix)]
use crate::symbols::{line, DOT};
#[cfg(unix)]
use pancurses::{chtype, ToChtype};
use unicode_segmentation::UnicodeSegmentation;

pub struct CursesBackend {
    curses: easycurses::EasyCurses,
}

impl CursesBackend {
    pub fn new() -> Option<CursesBackend> {
        let curses = easycurses::EasyCurses::initialize_system()?;
        Some(CursesBackend { curses })
    }

    pub fn with_curses(curses: easycurses::EasyCurses) -> CursesBackend {
        CursesBackend { curses }
    }

    pub fn get_curses(&self) -> &easycurses::EasyCurses {
        &self.curses
    }

    pub fn get_curses_mut(&mut self) -> &mut easycurses::EasyCurses {
        &mut self.curses
    }
}

impl Backend for CursesBackend {
    fn draw<'a, I>(&mut self, content: I) -> io::Result<()>
    where
        I: Iterator<Item = (u16, u16, &'a Cell)>,
    {
        let mut last_col = 0;
        let mut last_row = 0;
        let mut style = Style {
            fg: Color::Reset,
            bg: Color::Reset,
            modifier: Modifier::Reset,
        };
        let mut curses_style = CursesStyle {
            fg: easycurses::Color::White,
            bg: easycurses::Color::Black,
            attribute: pancurses::Attribute::Normal,
        };
        let mut update_color = false;
        for (col, row, cell) in content {
            // eprintln!("{:?}", cell);
            if row != last_row || col != last_col + 1 {
                self.curses.move_rc(row as i32, col as i32);
            }
            last_col = col;
            last_row = row;
            if cell.style.modifier != style.modifier {
                if curses_style.attribute != pancurses::Attribute::Normal {
                    self.curses.win.attroff(curses_style.attribute);
                }
                let attribute: pancurses::Attribute = cell.style.modifier.into();
                self.curses.win.attron(attribute);
                curses_style.attribute = attribute;
                style.modifier = cell.style.modifier;
            };
            if cell.style.fg != style.fg {
                update_color = true;
                if let Some(ccolor) = cell.style.fg.into() {
                    style.fg = cell.style.fg;
                    curses_style.fg = ccolor;
                } else {
                    style.fg = Color::White;
                    curses_style.fg = easycurses::Color::White;
                }
            };
            if cell.style.bg != style.bg {
                update_color = true;
                if let Some(ccolor) = cell.style.bg.into() {
                    style.bg = cell.style.bg;
                    curses_style.bg = ccolor;
                } else {
                    style.bg = Color::Black;
                    curses_style.bg = easycurses::Color::Black;
                }
            };
            if update_color {
                self.curses
                    .set_color_pair(easycurses::ColorPair::new(curses_style.fg, curses_style.bg));
            };
            update_color = false;
            draw(&mut self.curses, cell.symbol.as_str());
        }
        self.curses.win.attrset(pancurses::Attribute::Normal);
        self.curses.set_color_pair(easycurses::ColorPair::new(
            easycurses::Color::White,
            easycurses::Color::Black,
        ));
        Ok(())
    }
    fn hide_cursor(&mut self) -> io::Result<()> {
        self.curses
            .set_cursor_visibility(easycurses::CursorVisibility::Invisible);
        Ok(())
    }
    fn show_cursor(&mut self) -> io::Result<()> {
        self.curses
            .set_cursor_visibility(easycurses::CursorVisibility::Visible);
        Ok(())
    }
    fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
        let (x, y) = self.curses.get_cursor_rc();
        Ok((x as u16, y as u16))
    }
    fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
        self.curses.move_rc(x as i32, y as i32);
        Ok(())
    }
    fn clear(&mut self) -> io::Result<()> {
        self.curses.clear();
        // self.curses.refresh();
        Ok(())
    }
    fn size(&self) -> Result<Rect, io::Error> {
        let (nrows, ncols) = self.curses.get_row_col_count();
        Ok(Rect::new(0, 0, ncols as u16, nrows as u16))
    }
    fn flush(&mut self) -> io::Result<()> {
        self.curses.refresh();
        Ok(())
    }
}

struct CursesStyle {
    fg: easycurses::Color,
    bg: easycurses::Color,
    attribute: pancurses::Attribute,
}

#[cfg(unix)]
/// Deals with lack of unicode support for ncurses on unix
fn draw(curses: &mut easycurses::EasyCurses, symbol: &str) {
    for grapheme in symbol.graphemes(true) {
        let ch = match grapheme {
            line::TOP_RIGHT => pancurses::ACS_URCORNER(),
            line::VERTICAL => pancurses::ACS_VLINE(),
            line::HORIZONTAL => pancurses::ACS_HLINE(),
            line::TOP_LEFT => pancurses::ACS_ULCORNER(),
            line::BOTTOM_RIGHT => pancurses::ACS_LRCORNER(),
            line::BOTTOM_LEFT => pancurses::ACS_LLCORNER(),
            line::VERTICAL_LEFT => pancurses::ACS_RTEE(),
            line::VERTICAL_RIGHT => pancurses::ACS_LTEE(),
            line::HORIZONTAL_DOWN => pancurses::ACS_TTEE(),
            line::HORIZONTAL_UP => pancurses::ACS_BTEE(),
            block::FULL => pancurses::ACS_BLOCK(),
            block::SEVEN_EIGHTHS => pancurses::ACS_BLOCK(),
            block::THREE_QUATERS => pancurses::ACS_BLOCK(),
            block::FIVE_EIGHTHS => pancurses::ACS_BLOCK(),
            block::HALF => pancurses::ACS_BLOCK(),
            block::THREE_EIGHTHS => ' ' as chtype,
            block::ONE_QUATER => ' ' as chtype,
            block::ONE_EIGHTH => ' ' as chtype,
            bar::SEVEN_EIGHTHS => pancurses::ACS_BLOCK(),
            bar::THREE_QUATERS => pancurses::ACS_BLOCK(),
            bar::FIVE_EIGHTHS => pancurses::ACS_BLOCK(),
            bar::HALF => pancurses::ACS_BLOCK(),
            bar::THREE_EIGHTHS => pancurses::ACS_S9(),
            bar::ONE_QUATER => pancurses::ACS_S9(),
            bar::ONE_EIGHTH => pancurses::ACS_S9(),
            DOT => pancurses::ACS_BULLET(),
            unicode_char => {
                if unicode_char.is_ascii() {
                    let mut chars = unicode_char.chars();
                    if let Some(ch) = chars.next() {
                        ch.to_chtype()
                    } else {
                        pancurses::ACS_BLOCK()
                    }
                } else {
                    pancurses::ACS_BLOCK()
                }
            }
        };
        curses.win.addch(ch);
    }
}

#[cfg(windows)]
fn draw(curses: &mut easycurses::EasyCurses, symbol: &str) {
    for grapheme in symbol.graphemes(true) {
        let ch = match grapheme {
            block::SEVEN_EIGHTHS => block::FULL,
            block::THREE_QUATERS => block::FULL,
            block::FIVE_EIGHTHS => block::HALF,
            block::THREE_EIGHTHS => block::HALF,
            block::ONE_QUATER => block::HALF,
            block::ONE_EIGHTH => " ",
            bar::SEVEN_EIGHTHS => bar::FULL,
            bar::THREE_QUATERS => bar::FULL,
            bar::FIVE_EIGHTHS => bar::HALF,
            bar::THREE_EIGHTHS => bar::HALF,
            bar::ONE_QUATER => bar::HALF,
            bar::ONE_EIGHTH => " ",
            ch => ch,
        };
        // curses.win.addch(ch);
        curses.print(ch);
    }
}

impl From<Color> for Option<easycurses::Color> {
    fn from(color: Color) -> Option<easycurses::Color> {
        match color {
            Color::Reset => None,
            Color::Black => Some(easycurses::Color::Black),
            Color::Red | Color::LightRed => Some(easycurses::Color::Red),
            Color::Green | Color::LightGreen => Some(easycurses::Color::Green),
            Color::Yellow | Color::LightYellow => Some(easycurses::Color::Yellow),
            Color::Magenta | Color::LightMagenta => Some(easycurses::Color::Magenta),
            Color::Cyan | Color::LightCyan => Some(easycurses::Color::Cyan),
            Color::White | Color::Gray | Color::DarkGray => Some(easycurses::Color::White),
            Color::Blue | Color::LightBlue => Some(easycurses::Color::Blue),
            Color::Rgb(_, _, _) => None,
        }
    }
}

impl From<Modifier> for pancurses::Attribute {
    fn from(modifier: Modifier) -> pancurses::Attribute {
        match modifier {
            Modifier::Blink => pancurses::Attribute::Blink,
            Modifier::Bold => pancurses::Attribute::Bold,
            Modifier::CrossedOut => pancurses::Attribute::Strikeout,
            Modifier::Faint => pancurses::Attribute::Dim,
            Modifier::Invert => pancurses::Attribute::Reverse,
            Modifier::Italic => pancurses::Attribute::Italic,
            Modifier::Underline => pancurses::Attribute::Underline,
            _ => pancurses::Attribute::Normal,
        }
    }
}
<|endoftext|>


<commit_before>#![warn(rust_2018_idioms)] // while we're getting used to 2018
#![allow(clippy::too_many_arguments)] // large project
#![allow(clippy::redundant_closure)] // there's a false positive
#![warn(clippy::needless_borrow)]
#![warn(clippy::redundant_clone)]

use std::collections::{BTreeMap, BTreeSet};
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

use cargo::core::shell::Shell;
use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config};
use cargo::util::{CliError, ProcessError};

mod cli;
mod commands;

use crate::command_prelude::*;

fn main() {
    #[cfg(feature = "pretty-env-logger")]
    pretty_env_logger::init_custom_env("CARGO_LOG");
    #[cfg(not(feature = "pretty-env-logger"))]
    env_logger::init_from_env("CARGO_LOG");
    cargo::core::maybe_allow_nightly_features();

    let mut config = match Config::default() {
        Ok(cfg) => cfg,
        Err(e) => {
            let mut shell = Shell::new();
            cargo::exit_with_error(e.into(), &mut shell)
        }
    };

    let result = match cargo::ops::fix_maybe_exec_rustc() {
        Ok(true) => Ok(()),
        Ok(false) => {
            init_git_transports(&config);
            let _token = cargo::util::job::setup();
            cli::main(&mut config)
        }
        Err(e) => Err(CliError::from(e)),
    };

    match result {
        Err(e) => cargo::exit_with_error(e, &mut *config.shell()),
        Ok(()) => {}
    }
}

fn aliased_command(config: &Config, command: &str) -> CargoResult<Option<Vec<String>>> {
    let alias_name = format!("alias.{}", command);
    let user_alias = match config.get_string(&alias_name) {
        Ok(Some(record)) => Some(
            record
                .val
                .split_whitespace()
                .map(|s| s.to_string())
                .collect(),
        ),
        Ok(None) => None,
        Err(_) => config.get::<Option<Vec<String>>>(&alias_name)?,
    };
    let result = user_alias.or_else(|| match command {
        "b" => Some(vec!["build".to_string()]),
        "c" => Some(vec!["check".to_string()]),
        "r" => Some(vec!["run".to_string()]),
        "t" => Some(vec!["test".to_string()]),
        _ => None,
    });
    Ok(result)
}

/// List all runnable commands
fn list_commands(config: &Config) -> BTreeSet<CommandInfo> {
    let prefix = "cargo-";
    let suffix = env::consts::EXE_SUFFIX;
    let mut commands = BTreeSet::new();
    for dir in search_directories(config) {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue,
        };
        for entry in entries.filter_map(|e| e.ok()) {
            let path = entry.path();
            let filename = match path.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue,
            };
            if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
                continue;
            }
            if is_executable(entry.path()) {
                let end = filename.len() - suffix.len();
                commands.insert(CommandInfo::External {
                    name: filename[prefix.len()..end].to_string(),
                    path: path.clone(),
                });
            }
        }
    }

    for cmd in commands::builtin() {
        commands.insert(CommandInfo::BuiltIn {
            name: cmd.get_name().to_string(),
            about: cmd.p.meta.about.map(|s| s.to_string()),
        });
    }

    commands
}

/// List all runnable aliases
fn list_aliases(config: &Config) -> Vec<String> {
    match config.get::<BTreeMap<String, String>>("alias") {
        Ok(aliases) => aliases.keys().map(|a| a.to_string()).collect(),
        Err(_) => Vec::new(),
    }
}

fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> CliResult {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = search_directories(config)
        .iter()
        .map(|dir| dir.join(&command_exe))
        .find(|file| is_executable(file));
    let command = match path {
        Some(command) => command,
        None => {
            let commands: Vec<String> = list_commands(config)
                .iter()
                .map(|c| c.name().to_string())
                .collect();
            let aliases = list_aliases(config);
            let suggestions = commands.iter().chain(aliases.iter());
            let did_you_mean = closest_msg(cmd, suggestions, |c| c);
            let err = failure::format_err!("no such subcommand: `{}`{}", cmd, did_you_mean);
            return Err(CliError::new(err, 101));
        }
    };

    let cargo_exe = config.cargo_exe()?;
    let err = match util::process(&command)
        .env(cargo::CARGO_ENV, cargo_exe)
        .args(args)
        .exec_replace()
    {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if let Some(perr) = err.downcast_ref::<ProcessError>() {
        if let Some(code) = perr.exit.as_ref().and_then(|c| c.code()) {
            return Err(CliError::code(code));
        }
    }
    Err(CliError::new(err, 101))
}

#[cfg(unix)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path)
        .map(|metadata| metadata.is_file() && metadata.permissions().mode() & 0o111 != 0)
        .unwrap_or(false)
}
#[cfg(windows)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path)
        .map(|metadata| metadata.is_file())
        .unwrap_or(false)
}

fn search_directories(config: &Config) -> Vec<PathBuf> {
    let mut dirs = vec![config.home().clone().into_path_unlocked().join("bin")];
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if any HTTP options are specified,
    // such as proxies or custom certificate authorities. The custom
    // transport, however, is not as well battle-tested.

    match cargo::ops::needs_custom_http_transport(config) {
        Ok(true) => {}
        _ => return,
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>remove suppression of clippy lint `too_many_arguments`<commit_after>#![warn(rust_2018_idioms)] // while we're getting used to 2018
#![allow(clippy::redundant_closure)] // there's a false positive
#![warn(clippy::needless_borrow)]
#![warn(clippy::redundant_clone)]

use std::collections::{BTreeMap, BTreeSet};
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

use cargo::core::shell::Shell;
use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config};
use cargo::util::{CliError, ProcessError};

mod cli;
mod commands;

use crate::command_prelude::*;

fn main() {
    #[cfg(feature = "pretty-env-logger")]
    pretty_env_logger::init_custom_env("CARGO_LOG");
    #[cfg(not(feature = "pretty-env-logger"))]
    env_logger::init_from_env("CARGO_LOG");
    cargo::core::maybe_allow_nightly_features();

    let mut config = match Config::default() {
        Ok(cfg) => cfg,
        Err(e) => {
            let mut shell = Shell::new();
            cargo::exit_with_error(e.into(), &mut shell)
        }
    };

    let result = match cargo::ops::fix_maybe_exec_rustc() {
        Ok(true) => Ok(()),
        Ok(false) => {
            init_git_transports(&config);
            let _token = cargo::util::job::setup();
            cli::main(&mut config)
        }
        Err(e) => Err(CliError::from(e)),
    };

    match result {
        Err(e) => cargo::exit_with_error(e, &mut *config.shell()),
        Ok(()) => {}
    }
}

fn aliased_command(config: &Config, command: &str) -> CargoResult<Option<Vec<String>>> {
    let alias_name = format!("alias.{}", command);
    let user_alias = match config.get_string(&alias_name) {
        Ok(Some(record)) => Some(
            record
                .val
                .split_whitespace()
                .map(|s| s.to_string())
                .collect(),
        ),
        Ok(None) => None,
        Err(_) => config.get::<Option<Vec<String>>>(&alias_name)?,
    };
    let result = user_alias.or_else(|| match command {
        "b" => Some(vec!["build".to_string()]),
        "c" => Some(vec!["check".to_string()]),
        "r" => Some(vec!["run".to_string()]),
        "t" => Some(vec!["test".to_string()]),
        _ => None,
    });
    Ok(result)
}

/// List all runnable commands
fn list_commands(config: &Config) -> BTreeSet<CommandInfo> {
    let prefix = "cargo-";
    let suffix = env::consts::EXE_SUFFIX;
    let mut commands = BTreeSet::new();
    for dir in search_directories(config) {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue,
        };
        for entry in entries.filter_map(|e| e.ok()) {
            let path = entry.path();
            let filename = match path.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue,
            };
            if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
                continue;
            }
            if is_executable(entry.path()) {
                let end = filename.len() - suffix.len();
                commands.insert(CommandInfo::External {
                    name: filename[prefix.len()..end].to_string(),
                    path: path.clone(),
                });
            }
        }
    }

    for cmd in commands::builtin() {
        commands.insert(CommandInfo::BuiltIn {
            name: cmd.get_name().to_string(),
            about: cmd.p.meta.about.map(|s| s.to_string()),
        });
    }

    commands
}

/// List all runnable aliases
fn list_aliases(config: &Config) -> Vec<String> {
    match config.get::<BTreeMap<String, String>>("alias") {
        Ok(aliases) => aliases.keys().map(|a| a.to_string()).collect(),
        Err(_) => Vec::new(),
    }
}

fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> CliResult {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = search_directories(config)
        .iter()
        .map(|dir| dir.join(&command_exe))
        .find(|file| is_executable(file));
    let command = match path {
        Some(command) => command,
        None => {
            let commands: Vec<String> = list_commands(config)
                .iter()
                .map(|c| c.name().to_string())
                .collect();
            let aliases = list_aliases(config);
            let suggestions = commands.iter().chain(aliases.iter());
            let did_you_mean = closest_msg(cmd, suggestions, |c| c);
            let err = failure::format_err!("no such subcommand: `{}`{}", cmd, did_you_mean);
            return Err(CliError::new(err, 101));
        }
    };

    let cargo_exe = config.cargo_exe()?;
    let err = match util::process(&command)
        .env(cargo::CARGO_ENV, cargo_exe)
        .args(args)
        .exec_replace()
    {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if let Some(perr) = err.downcast_ref::<ProcessError>() {
        if let Some(code) = perr.exit.as_ref().and_then(|c| c.code()) {
            return Err(CliError::code(code));
        }
    }
    Err(CliError::new(err, 101))
}

#[cfg(unix)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path)
        .map(|metadata| metadata.is_file() && metadata.permissions().mode() & 0o111 != 0)
        .unwrap_or(false)
}
#[cfg(windows)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path)
        .map(|metadata| metadata.is_file())
        .unwrap_or(false)
}

fn search_directories(config: &Config) -> Vec<PathBuf> {
    let mut dirs = vec![config.home().clone().into_path_unlocked().join("bin")];
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if any HTTP options are specified,
    // such as proxies or custom certificate authorities. The custom
    // transport, however, is not as well battle-tested.

    match cargo::ops::needs_custom_http_transport(config) {
        Ok(true) => {}
        _ => return,
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<|endoftext|>


<commit_before>use std::hash;
use std::iter::FromIterator;
use std::collections::HashMap;
use num::{BigUint, FromPrimitive, One};
use nock::{self, Shape, Noun, FromNoun};

pub struct Jet {
    pub name: String,
    pub jet: Option<fn(&Noun) -> Noun>,
    pub battery: Noun,
    // TODO: What do we do with these?
    pub axis: u32,
    pub hooks: HashMap<String, Noun>,
    pub calls: u64,
}

impl Jet {
    pub fn new(name: String, battery: Noun, axis: u32, hooks: Vec<(String, Noun)>) -> Jet {
        let jet = match &name[..] {
            "dec" => Some(dec as fn(&Noun) -> Noun),
            "bex" => Some(bex as fn(&Noun) -> Noun),
            "add" => Some(add as fn(&Noun) -> Noun),
            "mul" => Some(mul as fn(&Noun) -> Noun),
            "sub" => Some(sub as fn(&Noun) -> Noun),
            "div" => Some(div as fn(&Noun) -> Noun),
            "lth" => Some(lth as fn(&Noun) -> Noun),
            "rsh" => Some(rsh as fn(&Noun) -> Noun),
            "lsh" => Some(lsh as fn(&Noun) -> Noun),
            "mod" => Some(mod_ as fn(&Noun) -> Noun),
            "end" => Some(end as fn(&Noun) -> Noun),
            "mix" => Some(mix as fn(&Noun) -> Noun),
            "met" => Some(met as fn(&Noun) -> Noun),
            "cut" => Some(cut as fn(&Noun) -> Noun),
            "mug" => Some(mug as fn(&Noun) -> Noun),
            _ => None,
        };

        Jet {
            name: name,
            jet: jet,
            battery: battery,
            axis: axis,
            hooks: HashMap::from_iter(hooks.into_iter()),
            calls: 0,
        }
    }
}

impl hash::Hash for Jet {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.battery.hash(state);
    }
}

// FIXME: Needing to do the get_axis on subject.
// TODO: Error handling that isn't panicing.

pub fn dec(subject: &Noun) -> Noun {
    // XXX: How do we know the axis here?
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let n = BigUint::from_noun(&arg).unwrap();
    Noun::from(n - BigUint::one())
}

pub fn bex(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    // XXX: Will fail if arg is above machine word size.
    let n: usize = FromNoun::from_noun(&arg).unwrap();
    Noun::from(BigUint::one() << n)
}

pub fn add(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (x, y): (BigUint, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(x + y)
}

pub fn mul(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (x, y): (BigUint, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(x * y)
}

pub fn sub(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (x, y): (BigUint, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(x - y)
}

pub fn div(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (x, y): (BigUint, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(x / y)
}

pub fn lth(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (x, y): (BigUint, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(x < y)
}

pub fn rsh(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (a, b, c): (usize, usize, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(c >> ((1 << a) * b))
}

pub fn lsh(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (a, b, c): (usize, usize, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(c << ((1 << a) * b))
}

pub fn mod_(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (x, y): (BigUint, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(x % y)
}

pub fn end(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (a, b, c): (usize, usize, BigUint) = FromNoun::from_noun(&arg).unwrap();

    Noun::from(c % BigUint::from_usize(1 << ((1 << a) * b)).unwrap())
}

pub fn mix(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (a, b): (BigUint, BigUint) = FromNoun::from_noun(&arg).unwrap();

    Noun::from(a ^ b)
}

pub fn met(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    if let Shape::Cell(ref bloq, ref b) = arg.get() {
        let bloq: usize = FromNoun::from_noun(bloq).unwrap();

        let mut bits;
        if let Shape::Atom(ref atom) = b.get() {
            bits = atom.len() * 8;
            if bits > 0 {
                let last = atom[atom.len() - 1];
                for i in (1..8).rev() {
                    if last & (1 << i) == 0 {
                        bits -= 1;
                    } else {
                        break;
                    }
                }
            }
        } else {
            panic!("Bad atom");
        }

        bits += (1 << bloq) - 1;

        Noun::from(bits / (1 << bloq))
    } else {
        panic!("Bad argument");
    }
}

pub fn cut(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (a, (mut b, mut c), mut d): (usize, (usize, usize), BigUint) = FromNoun::from_noun(&arg).unwrap();
    b = b << a;
    c = c << (1 << a);
    d = d >> b;
    d = d % BigUint::from_usize(c).unwrap();

    Noun::from(d)
}

pub fn mug(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();
    Noun::from(arg.mug())
}
<commit_msg>Use msb fn for met jet<commit_after>use std::hash;
use std::iter::FromIterator;
use std::collections::HashMap;
use num::{BigUint, FromPrimitive, One};
use nock::{self, Shape, Noun, FromNoun};

pub struct Jet {
    pub name: String,
    pub jet: Option<fn(&Noun) -> Noun>,
    pub battery: Noun,
    // TODO: What do we do with these?
    pub axis: u32,
    pub hooks: HashMap<String, Noun>,
    pub calls: u64,
}

impl Jet {
    pub fn new(name: String, battery: Noun, axis: u32, hooks: Vec<(String, Noun)>) -> Jet {
        let jet = match &name[..] {
            "dec" => Some(dec as fn(&Noun) -> Noun),
            "bex" => Some(bex as fn(&Noun) -> Noun),
            "add" => Some(add as fn(&Noun) -> Noun),
            "mul" => Some(mul as fn(&Noun) -> Noun),
            "sub" => Some(sub as fn(&Noun) -> Noun),
            "div" => Some(div as fn(&Noun) -> Noun),
            "lth" => Some(lth as fn(&Noun) -> Noun),
            "rsh" => Some(rsh as fn(&Noun) -> Noun),
            "lsh" => Some(lsh as fn(&Noun) -> Noun),
            "mod" => Some(mod_ as fn(&Noun) -> Noun),
            "end" => Some(end as fn(&Noun) -> Noun),
            "mix" => Some(mix as fn(&Noun) -> Noun),
            "met" => Some(met as fn(&Noun) -> Noun),
            "cut" => Some(cut as fn(&Noun) -> Noun),
            "mug" => Some(mug as fn(&Noun) -> Noun),
            _ => None,
        };

        Jet {
            name: name,
            jet: jet,
            battery: battery,
            axis: axis,
            hooks: HashMap::from_iter(hooks.into_iter()),
            calls: 0,
        }
    }
}

impl hash::Hash for Jet {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.battery.hash(state);
    }
}

// FIXME: Needing to do the get_axis on subject.
// TODO: Error handling that isn't panicing.

pub fn dec(subject: &Noun) -> Noun {
    // XXX: How do we know the axis here?
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let n = BigUint::from_noun(&arg).unwrap();
    Noun::from(n - BigUint::one())
}

pub fn bex(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    // XXX: Will fail if arg is above machine word size.
    let n: usize = FromNoun::from_noun(&arg).unwrap();
    Noun::from(BigUint::one() << n)
}

pub fn add(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (x, y): (BigUint, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(x + y)
}

pub fn mul(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (x, y): (BigUint, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(x * y)
}

pub fn sub(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (x, y): (BigUint, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(x - y)
}

pub fn div(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (x, y): (BigUint, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(x / y)
}

pub fn lth(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (x, y): (BigUint, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(x < y)
}

pub fn rsh(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (a, b, c): (usize, usize, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(c >> ((1 << a) * b))
}

pub fn lsh(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (a, b, c): (usize, usize, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(c << ((1 << a) * b))
}

pub fn mod_(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (x, y): (BigUint, BigUint) = FromNoun::from_noun(&arg).unwrap();
    Noun::from(x % y)
}

pub fn end(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (a, b, c): (usize, usize, BigUint) = FromNoun::from_noun(&arg).unwrap();

    Noun::from(c % BigUint::from_usize(1 << ((1 << a) * b)).unwrap())
}

pub fn mix(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (a, b): (BigUint, BigUint) = FromNoun::from_noun(&arg).unwrap();

    Noun::from(a ^ b)
}

pub fn met(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    if let Shape::Cell(ref bloq, ref b) = arg.get() {
        let bloq: usize = FromNoun::from_noun(bloq).unwrap();

        let bits = if let Shape::Atom(ref atom) = b.get() {
            nock::msb(atom)
        } else {
            panic!("Bad atom");
        } + (1 << bloq) - 1;

        Noun::from(bits / (1 << bloq))
    } else {
        panic!("Bad argument");
    }
}

pub fn cut(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();

    let (a, (mut b, mut c), mut d): (usize, (usize, usize), BigUint) = FromNoun::from_noun(&arg).unwrap();
    b = b << a;
    c = c << (1 << a);
    d = d >> b;
    d = d % BigUint::from_usize(c).unwrap();

    Noun::from(d)
}

pub fn mug(subject: &Noun) -> Noun {
    let arg = nock::get_axis(&Noun::from(6u32), subject).unwrap();
    Noun::from(arg.mug())
}
<|endoftext|>


<commit_before>
mod curses;

use std::ffi::CString;

use curses::*;

enum DrawMe {
    //Circle { radius : i32, x : i32, y : i32 },
    Rec { width : i32, height : i32, x : i32, y : i32 },
    /*VHall { length : i32, x : i32, y : i32 },
    HHall { length : i32, x : i32, y : i32 },*/
    // TODO add color
    // TODO add background color
    // TODO add point case
    // TODO add overlap
    // TODO can probably have a struct represent common items (x,y, color, etc)
}

unsafe fn render_shape( s : &DrawMe ) {
    match s {
        &DrawMe::Rec { width, height, x, y } => render_rec( width, height, x, y ),
        _ => (),
    }
}

unsafe fn render_rec( w : i32, h : i32, x : i32, y : i32 ) {
    let c = CString::new( "." ).unwrap();

    let mut h2 = h;
    while h2 > 0 {
        let mut w2 = w;
        while w2 > 0 {
            mvprintw( y + h2, x + w2, c.as_ptr() );
            w2 -= 1;
        }
        h2 -= 1;
    }
}

fn main() {
    let mut x = 0;
    let mut y = 0;
    unsafe {
        initscr();
        cbreak();
        noecho();

        let mut c = getch();

        while c as u8 as char != 'q' {
            let c2 = c as u8 as char;

            match c2 {
                'j' => {
                    y+=1;
                    cursor_move( y, x );
                },
                'k' => {
                    y-=1;
                    cursor_move( y, x );
                },
                'l' => {
                    x+=1;
                    cursor_move( y, x );
                },
                'h' => {
                    x-=1;
                    cursor_move( y, x );
                },
                _ => (),
            }
            refresh();
            c = getch();
        }

        endwin();
    }
}

<commit_msg>added render method usage; moved cursor_move to centeral location<commit_after>
mod curses;

use std::ffi::CString;

use curses::*;

enum DrawMe {
    //Circle { radius : i32, x : i32, y : i32 },
    Rec { width : i32, height : i32, x : i32, y : i32 },
    /*VHall { length : i32, x : i32, y : i32 },
    HHall { length : i32, x : i32, y : i32 },*/
    // TODO add color
    // TODO add background color
    // TODO add point case
    // TODO add overlap
    // TODO can probably have a struct represent common items (x,y, color, etc)
}

unsafe fn render_shape( s : &DrawMe ) {
    match s {
        &DrawMe::Rec { width, height, x, y } => render_rec( width, height, x, y ),
        _ => (),
    }
}

unsafe fn render_rec( w : i32, h : i32, x : i32, y : i32 ) {
    let c = CString::new( "." ).unwrap();

    let mut h2 = h;
    while h2 > 0 {
        let mut w2 = w;
        while w2 > 0 {
            mvprintw( y + h2, x + w2, c.as_ptr() );
            w2 -= 1;
        }
        h2 -= 1;
    }
}

fn main() {
    let mut x = 0;
    let mut y = 0;
    unsafe {
        initscr();
        cbreak();
        noecho();

        let mut c = getch();
        let mut shapes : Vec<DrawMe> = vec! [];

        while c as u8 as char != 'q' {
            let c2 = c as u8 as char;

            match c2 {
                /*'c' => {
                    shapes.push( DrawMe::Circle { radius: 5, x: x, y: y } );
                },*/
                'r' => {
                    shapes.push( DrawMe::Rec { width: 2, height: 2, x: x, y: y } );
                },
                'j' => {
                    y+=1;
                },
                'k' => {
                    y-=1;
                },
                'l' => {
                    x+=1;
                },
                'h' => {
                    x-=1;
                },
                _ => (),
            }

            for s in &shapes {
                render_shape( s );
            }

            cursor_move( y, x );
      //      clear();
            refresh();

            c = getch();
        }

        endwin();
    }
}

<|endoftext|>


<commit_before>extern crate atom_syndication;
extern crate byteorder;
extern crate chrono;
extern crate clap;
extern crate escapade;
extern crate futures;
extern crate lettre;
extern crate reqwest;
extern crate rmp_serde;
extern crate rss;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[cfg(test)]
extern crate tempdir;
extern crate toml;

mod config;
mod error;
mod log;
mod model;

pub use error::Error;

use std::io::Write;
use std::sync::Arc;

const CONFIG_PATH: &str = "rss2email.conf";
const DB_PATH: &str = "rss2email.db";

struct FakeDebug<T>(T);

impl<T> std::fmt::Debug for FakeDebug<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        "(no debug info available)".fmt(f)
    }
}

impl<T> std::ops::Deref for FakeDebug<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T> std::ops::DerefMut for FakeDebug<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

fn main_impl() -> Result<(), Error> {

    use clap::{App, Arg, SubCommand};
    use model::Database;

    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .subcommand(
            SubCommand::with_name("add")
                .about("Add feed to the database")
                .arg(
                    Arg::with_name("FEED_URL")
                        .help("URL of the feed to add")
                        .required(true),
                ),
        )
        .subcommand(SubCommand::with_name("create").about("Create database"))
        .subcommand(
            SubCommand::with_name("fetch")
                .about("Fetch feeds and send emails for new items")
                .arg(
                    Arg::with_name("VERBOSE")
                        .short("v")
                        .long("verbose")
                        .multiple(true)
                        .help("Print more information"),
                )
                .arg(Arg::with_name("NO_SEND").long("no-send").help(
                    "Run as normal but do not send emails",
                ))
                .arg(Arg::with_name("FEED_URL").multiple(true).help(
                    "URL of the feed(s) to fetch",
                )),
        )
        .subcommand(SubCommand::with_name("list").about("Print all feed URLs"))
        .subcommand(
            SubCommand::with_name("remove")
                .about("Remove a feed from the database")
                .arg(
                    Arg::with_name("FEED_URL")
                        .help("URL of the feed to remove")
                        .required(true),
                ),
        )
        .get_matches();

    if let Some(matches) = matches.subcommand_matches("add") {
        let feed_url = matches.value_of("FEED_URL").unwrap();
        let mut db = Database::open(DB_PATH)?;
        db.add_feed(feed_url)?;
        db.commit()?;
    } else if let Some(_matches) = matches.subcommand_matches("create") {
        let db = Database::create(DB_PATH)?;
        db.commit()?;
    } else if let Some(matches) = matches.subcommand_matches("fetch") {
        let config = config::Config::load(CONFIG_PATH)?;
        let mut db = Database::open(DB_PATH)?;
        let log_level = match matches.occurrences_of("VERBOSE") {
            0 => log::LogLevel::Normal,
            _ => log::LogLevel::Verbose,
        };
        let logger = Arc::new(log::Logger::new(log_level));
        let fetcher = model::NetFetcher::new()?;
        let sender = model::EmailSender::new(&config)?;
        let mut options = model::FetchAndSendOptions::new();
        options.with_no_send(matches.is_present("NO_SEND"));
        if let Some(feed_urls) = matches.values_of("FEED_URL") {
            options.with_feed_urls(feed_urls);
        }
        db.fetch_and_send_feeds(logger, fetcher, &sender, &options)?;
        db.commit()?;
    } else if let Some(_matches) = matches.subcommand_matches("list") {
        let db = Database::open(DB_PATH)?;
        let stdout = std::io::stdout();
        let mut w = stdout.lock();
        for feed_url in db.feed_urls() {
            writeln!(w, "{}", feed_url).unwrap();
        }
    } else if let Some(matches) = matches.subcommand_matches("remove") {
        let feed_url = matches.value_of("FEED_URL").unwrap();
        let mut db = Database::open(DB_PATH)?;
        db.remove_feed(feed_url)?;
        db.commit()?;
    } else {
        unreachable!();
    }

    Ok(())
}

fn main() {
    match main_impl() {
        Ok(..) => {}
        Err(e) => {
            let stderr = std::io::stderr();
            const UNKNOWN_EXE: &str = "???";
            let name = std::env::current_exe()
                .map(|x| {
                    x.file_name()
                        .map(|x| x.to_string_lossy().into_owned())
                        .unwrap_or(String::from(UNKNOWN_EXE))
                })
                .unwrap_or(String::from(UNKNOWN_EXE));
            writeln!(stderr.lock(), "{}: *** {}", name, e).unwrap();
            std::process::exit(1);
        }
    }
}
<commit_msg>Don't crash if run without arguments<commit_after>extern crate atom_syndication;
extern crate byteorder;
extern crate chrono;
extern crate clap;
extern crate escapade;
extern crate futures;
extern crate lettre;
extern crate reqwest;
extern crate rmp_serde;
extern crate rss;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[cfg(test)]
extern crate tempdir;
extern crate toml;

mod config;
mod error;
mod log;
mod model;

pub use error::Error;

use std::io::Write;
use std::sync::Arc;

const CONFIG_PATH: &str = "rss2email.conf";
const DB_PATH: &str = "rss2email.db";

struct FakeDebug<T>(T);

impl<T> std::fmt::Debug for FakeDebug<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        "(no debug info available)".fmt(f)
    }
}

impl<T> std::ops::Deref for FakeDebug<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T> std::ops::DerefMut for FakeDebug<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

fn main_impl() -> Result<(), Error> {

    use clap::{App, Arg, SubCommand};
    use model::Database;

    let mut app = App::new(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .subcommand(
            SubCommand::with_name("add")
                .about("Add feed to the database")
                .arg(
                    Arg::with_name("FEED_URL")
                        .help("URL of the feed to add")
                        .required(true),
                ),
        )
        .subcommand(SubCommand::with_name("create").about("Create database"))
        .subcommand(
            SubCommand::with_name("fetch")
                .about("Fetch feeds and send emails for new items")
                .arg(
                    Arg::with_name("VERBOSE")
                        .short("v")
                        .long("verbose")
                        .multiple(true)
                        .help("Print more information"),
                )
                .arg(Arg::with_name("NO_SEND").long("no-send").help(
                    "Run as normal but do not send emails",
                ))
                .arg(Arg::with_name("FEED_URL").multiple(true).help(
                    "URL of the feed(s) to fetch",
                )),
        )
        .subcommand(SubCommand::with_name("list").about("Print all feed URLs"))
        .subcommand(
            SubCommand::with_name("remove")
                .about("Remove a feed from the database")
                .arg(
                    Arg::with_name("FEED_URL")
                        .help("URL of the feed to remove")
                        .required(true),
                ),
        );

    let matches = app.clone().get_matches();

    if let Some(matches) = matches.subcommand_matches("add") {
        let feed_url = matches.value_of("FEED_URL").unwrap();
        let mut db = Database::open(DB_PATH)?;
        db.add_feed(feed_url)?;
        db.commit()?;
    } else if let Some(_matches) = matches.subcommand_matches("create") {
        let db = Database::create(DB_PATH)?;
        db.commit()?;
    } else if let Some(matches) = matches.subcommand_matches("fetch") {
        let config = config::Config::load(CONFIG_PATH)?;
        let mut db = Database::open(DB_PATH)?;
        let log_level = match matches.occurrences_of("VERBOSE") {
            0 => log::LogLevel::Normal,
            _ => log::LogLevel::Verbose,
        };
        let logger = Arc::new(log::Logger::new(log_level));
        let fetcher = model::NetFetcher::new()?;
        let sender = model::EmailSender::new(&config)?;
        let mut options = model::FetchAndSendOptions::new();
        options.with_no_send(matches.is_present("NO_SEND"));
        if let Some(feed_urls) = matches.values_of("FEED_URL") {
            options.with_feed_urls(feed_urls);
        }
        db.fetch_and_send_feeds(logger, fetcher, &sender, &options)?;
        db.commit()?;
    } else if let Some(_matches) = matches.subcommand_matches("list") {
        let db = Database::open(DB_PATH)?;
        let stdout = std::io::stdout();
        let mut w = stdout.lock();
        for feed_url in db.feed_urls() {
            writeln!(w, "{}", feed_url).unwrap();
        }
    } else if let Some(matches) = matches.subcommand_matches("remove") {
        let feed_url = matches.value_of("FEED_URL").unwrap();
        let mut db = Database::open(DB_PATH)?;
        db.remove_feed(feed_url)?;
        db.commit()?;
    } else {
        app.print_help().unwrap();
        println!(); // print_help omits final newline
    }

    Ok(())
}

fn main() {
    match main_impl() {
        Ok(..) => {}
        Err(e) => {
            let stderr = std::io::stderr();
            const UNKNOWN_EXE: &str = "???";
            let name = std::env::current_exe()
                .map(|x| {
                    x.file_name()
                        .map(|x| x.to_string_lossy().into_owned())
                        .unwrap_or(String::from(UNKNOWN_EXE))
                })
                .unwrap_or(String::from(UNKNOWN_EXE));
            writeln!(stderr.lock(), "{}: *** {}", name, e).unwrap();
            std::process::exit(1);
        }
    }
}
<|endoftext|>