<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

//! Abstract time service

use enum_dispatch::enum_dispatch;
#[cfg(any(test, feature = "async"))]
use pin_project::pin_project;
use std::{
    fmt::Debug,
    time::{Duration, Instant},
};
#[cfg(any(test, feature = "async"))]
use std::{
    future::Future,
    pin::Pin,
    task::{Context, Poll},
};

#[cfg(any(test, feature = "async"))]
pub mod interval;
#[cfg(any(test, feature = "testing"))]
pub mod mock;
pub mod real;
#[cfg(any(test, feature = "async"))]
pub mod timeout;

#[cfg(any(test, feature = "testing"))]
pub use crate::mock::{MockSleep, MockTimeService};
pub use crate::real::RealTimeService;
#[cfg(any(test, feature = "async"))]
pub use crate::{interval::Interval, real::RealSleep, timeout::Timeout};

// TODO(philiphayes): use Duration constants when those stabilize.
#[cfg(any(test, feature = "async"))]
const ZERO_DURATION: Duration = Duration::from_nanos(0);

/// `TimeService` abstracts all time-related operations in one place that can be
/// easily mocked-out and controlled in tests or delegated to the actual
/// underlying runtime (usually tokio). It's provided as an enum so we don't have
/// to infect everything with a generic tag.
///
/// `TimeService` is async-focused: the `sleep`, `interval`, and `timeout` methods
/// all return `Future`s and `Stream`s. That said, `TimeService` supports non-async
/// clients as well; simply use the `sleep_blocking` method instead of `sleep`.
/// Note that the blocking call will actually block the current thread until the
/// sleep time has elapsed.
///
/// `TimeService` tries to mirror the API provided by [`tokio::time`] to an
/// extent. The primary difference is that all time is expressed in relative
/// [`Duration`]s. In other words, "sleep for 5s" vs "sleep until unix time
/// 1607734460". Absolute time is provided by [`TimeService::now`] which returns
/// the current unix time.
///
/// Note: you must also include the [`TimeServiceTrait`] to use the actual
/// time-related functionality.
///
/// Note: we have to provide our own [`Timeout`] and [`Interval`] types that
/// use the [`Sleep`] future, since tokio's implementations are coupled to its
/// internal Sleep future.
///
/// Note: `TimeService`'s should be free (or very cheap) to clone and send around
/// between threads. In production (without test features), this enum is a
/// zero-sized type.
#[enum_dispatch(TimeServiceTrait)]
#[derive(Clone, Debug)]
pub enum TimeService {
    RealTimeService(RealTimeService),

    #[cfg(any(test, feature = "testing"))]
    MockTimeService(MockTimeService),
}

impl TimeService {
    /// Create a new real, production time service that actually uses the systemtime.
    ///
    /// See [`RealTimeService`].
    pub fn real() -> Self {
        RealTimeService::new().into()
    }

    /// Create a mock, simulated time service that does not query the system time
    /// and allows fine-grained control over advancing time and waking sleeping
    /// tasks.
    ///
    /// See [`MockTimeService`].
    #[cfg(any(test, feature = "testing"))]
    pub fn mock() -> Self {
        MockTimeService::new().into()
    }

    #[cfg(any(test, feature = "testing"))]
    pub fn into_mock(self) -> MockTimeService {
        match self {
            TimeService::MockTimeService(inner) => inner,
            ts => panic!("Unexpected TimeService, expected MockTimeService: {:?}", ts),
        }
    }
}

impl Default for TimeService {
    fn default() -> Self {
        Self::real()
    }
}

#[enum_dispatch]
pub trait TimeServiceTrait: Send + Sync + Clone + Debug {
    /// Query a monotonically nondecreasing clock. Returns an opaque type that
    /// can only be compared to other [`Instant`]s, i.e., this is a monotonic
    /// relative time whereas [`now_unix_time`](#method.now_unix_time) is a
    /// non-monotonic absolute time.
    ///
    /// On Linux, this is equivalent to
    /// [`clock_gettime(CLOCK_MONOTONIC, _)`](https://linux.die.net/man/3/clock_gettime)
    ///
    /// See [`Instant`] for more details.
    fn now(&self) -> Instant;

    /// Query the current unix timestamp as a [`Duration`].
    ///
    /// When used on a `TimeService::real()`, this is equivalent to
    /// `SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)`.
    ///
    /// Note: the [`Duration`] returned from this function is _NOT_ guaranteed to
    /// be monotonic. Use [`now`](#method.now) if you need monotonicity.
    ///
    /// From the [`SystemTime`] docs:
    ///
    /// > Distinct from the [`Instant`] type, this time measurement is
    /// > not monotonic. This means that you can save a file to the file system,
    /// > then save another file to the file system, and the second file has a
    /// > [`SystemTime`] measurement earlier than the first. In other words, an
    /// > operation that happens after another operation in real time may have
    /// > an earlier SystemTime!
    ///
    /// For example, the system administrator could [`clock_settime`] into the
    /// past, breaking clock time monotonicity.
    ///
    /// On Linux, this is equivalent to
    /// [`clock_gettime(CLOCK_REALTIME, _)`](https://linux.die.net/man/3/clock_gettime).
    ///
    /// [`Duration`]: std::time::Duration
    /// [`Instant`]: std::time::Instant
    /// [`SystemTime`]: std::time::SystemTime
    /// [`clock_settime`]: https://linux.die.net/man/3/clock_settime
    fn now_unix_time(&self) -> Duration;

    /// Query the current unix timestamp in seconds.
    ///
    /// Equivalent to `self.now_unix_time().as_secs()`.
    /// See [`now_unix_time`](#method.now_unix_time).
    fn now_secs(&self) -> u64 {
        self.now_unix_time().as_secs()
    }

    /// Return a [`Future`] that waits until `duration` has passed.
    ///
    /// No work is performed while awaiting on the sleep future to complete. `Sleep`
    /// operates at millisecond granularity and should not be used for tasks that
    /// require high-resolution timers.
    ///
    /// # Cancelation
    ///
    /// Canceling a sleep instance is done by dropping the returned future. No
    /// additional cleanup work is required.
    #[cfg(any(test, feature = "async"))]
    fn sleep(&self, duration: Duration) -> Sleep;

    /// Return a [`Future`] that waits until the `deadline`.
    ///
    /// If the deadline is in the past, the Sleep will trigger as soons as it's
    /// polled.
    ///
    /// See [`sleep`](#method.sleep) for more details.
    #[cfg(any(test, feature = "async"))]
    fn sleep_until(&self, deadline: Instant) -> Sleep {
        let duration = deadline.saturating_duration_since(self.now());
        self.sleep(duration)
    }

    /// Blocks the current thread until `duration` time has passed.
    fn sleep_blocking(&self, duration: Duration);

    /// Creates a new [`Interval`] that yields with interval of `period`. The
    /// first tick completes immediately. An interval will tick indefinitely.
    ///
    /// # Cancelation
    ///
    /// At any time, the [`Interval`] value can be dropped. This cancels the interval.
    ///
    /// # Panics
    ///
    /// This function panics if `period` is zero.
    #[cfg(any(test, feature = "async"))]
    fn interval(&self, period: Duration) -> Interval {
        let delay = self.sleep(ZERO_DURATION);
        Interval::new(delay, period)
    }

    /// Creates a new [`Interval`] that yields with interval of `period`. The
    /// first tick completes after the `start` deadline. An interval will tick
    /// indefinitely.
    ///
    /// See [`interval`](#method.interval) for more details.
    #[cfg(any(test, feature = "async"))]
    fn interval_at(&self, start: Instant, period: Duration) -> Interval {
        let delay = self.sleep_until(start);
        Interval::new(delay, period)
    }

    /// Require a [`Future`] to complete before the specified duration has elapsed.
    ///
    /// If the future completes before the duration has elapsed, then the completed
    /// value is returned. Otherwise, `Err(Elapsed)` is returned and the future is
    /// canceled.
    ///
    /// # Cancelation
    ///
    /// Cancelling a timeout is done by dropping the future. No additional cleanup
    /// or other work is required.
    ///
    /// The original future may be obtained by calling [`Timeout::into_inner`]. This
    /// consumes the [`Timeout`].
    #[cfg(any(test, feature = "async"))]
    fn timeout<F: Future>(&self, duration: Duration, future: F) -> Timeout<F> {
        let delay = self.sleep(duration);
        Timeout::new(future, delay)
    }

    /// Require a [`Future`] to complete before the `deadline`.
    ///
    /// If the future completes before the duration has elapsed, then the completed
    /// value is returned. Otherwise, `Err(Elapsed)` is returned and the future is
    /// canceled.
    ///
    /// See [`timeout`](#method.timeout) for more details.
    #[cfg(any(test, feature = "async"))]
    fn timeout_at<F: Future>(&self, deadline: Instant, future: F) -> Timeout<F> {
        let delay = self.sleep_until(deadline);
        Timeout::new(future, delay)
    }
}

/// A [`Future`] that resolves after some time has elapsed (either real or
/// simulated, depending on the parent [`TimeService`]).
///
/// `Sleep` is modeled after [`tokio::time::Sleep`].
#[pin_project(project = SleepProject)]
#[derive(Debug)]
#[cfg(any(test, feature = "async"))]
pub enum Sleep {
    RealSleep(#[pin] RealSleep),

    #[cfg(any(test, feature = "testing"))]
    MockSleep(MockSleep),
}

#[cfg(any(test, feature = "async"))]
impl From<RealSleep> for Sleep {
    fn from(sleep: RealSleep) -> Self {
        Sleep::RealSleep(sleep)
    }
}

#[cfg(any(test, feature = "fuzzing", feature = "testing"))]
impl From<MockSleep> for Sleep {
    fn from(sleep: MockSleep) -> Self {
        Sleep::MockSleep(sleep)
    }
}

#[cfg(any(test, feature = "async"))]
impl Future for Sleep {
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        match self.project() {
            SleepProject::RealSleep(inner) => inner.poll(cx),
            #[cfg(any(test, feature = "testing"))]
            SleepProject::MockSleep(inner) => Pin::new(inner).poll(cx),
        }
    }
}

#[cfg(any(test, feature = "async"))]
pub trait SleepTrait: Future<Output = ()> + Send + Sync + Debug {
    /// Returns `true` if this `Sleep`'s requested wait duration has elapsed.
    fn is_elapsed(&self) -> bool;

    /// Resets this `Sleep` to wait again for `duration`.
    fn reset(self: Pin<&mut Self>, duration: Duration);

    /// Reset this `Sleep` to wait again until the `deadline`.
    fn reset_until(self: Pin<&mut Self>, deadline: Instant);
}

#[cfg(any(test, feature = "async"))]
impl SleepTrait for Sleep {
    fn is_elapsed(&self) -> bool {
        match self {
            Sleep::RealSleep(inner) => SleepTrait::is_elapsed(inner),
            #[cfg(any(test, feature = "fuzzing", feature = "testing"))]
            Sleep::MockSleep(inner) => SleepTrait::is_elapsed(inner),
        }
    }

    fn reset(self: Pin<&mut Self>, duration: Duration) {
        match self.project() {
            SleepProject::RealSleep(inner) => SleepTrait::reset(inner, duration),
            #[cfg(any(test, feature = "fuzzing", feature = "testing"))]
            SleepProject::MockSleep(inner) => SleepTrait::reset(Pin::new(inner), duration),
        }
    }

    fn reset_until(self: Pin<&mut Self>, deadline: Instant) {
        match self.project() {
            SleepProject::RealSleep(inner) => SleepTrait::reset_until(inner, deadline),
            #[cfg(any(test, feature = "fuzzing", feature = "testing"))]
            SleepProject::MockSleep(inner) => SleepTrait::reset_until(Pin::new(inner), deadline),
        }
    }
}
<commit_msg>[time-service] Ensure sleep outputs are being used<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

//! Abstract time service

use enum_dispatch::enum_dispatch;
#[cfg(any(test, feature = "async"))]
use pin_project::pin_project;
use std::{
    fmt::Debug,
    time::{Duration, Instant},
};
#[cfg(any(test, feature = "async"))]
use std::{
    future::Future,
    pin::Pin,
    task::{Context, Poll},
};

#[cfg(any(test, feature = "async"))]
pub mod interval;
#[cfg(any(test, feature = "testing"))]
pub mod mock;
pub mod real;
#[cfg(any(test, feature = "async"))]
pub mod timeout;

#[cfg(any(test, feature = "testing"))]
pub use crate::mock::{MockSleep, MockTimeService};
pub use crate::real::RealTimeService;
#[cfg(any(test, feature = "async"))]
pub use crate::{interval::Interval, real::RealSleep, timeout::Timeout};

// TODO(philiphayes): use Duration constants when those stabilize.
#[cfg(any(test, feature = "async"))]
const ZERO_DURATION: Duration = Duration::from_nanos(0);

/// `TimeService` abstracts all time-related operations in one place that can be
/// easily mocked-out and controlled in tests or delegated to the actual
/// underlying runtime (usually tokio). It's provided as an enum so we don't have
/// to infect everything with a generic tag.
///
/// `TimeService` is async-focused: the `sleep`, `interval`, and `timeout` methods
/// all return `Future`s and `Stream`s. That said, `TimeService` supports non-async
/// clients as well; simply use the `sleep_blocking` method instead of `sleep`.
/// Note that the blocking call will actually block the current thread until the
/// sleep time has elapsed.
///
/// `TimeService` tries to mirror the API provided by [`tokio::time`] to an
/// extent. The primary difference is that all time is expressed in relative
/// [`Duration`]s. In other words, "sleep for 5s" vs "sleep until unix time
/// 1607734460". Absolute time is provided by [`TimeService::now`] which returns
/// the current unix time.
///
/// Note: you must also include the [`TimeServiceTrait`] to use the actual
/// time-related functionality.
///
/// Note: we have to provide our own [`Timeout`] and [`Interval`] types that
/// use the [`Sleep`] future, since tokio's implementations are coupled to its
/// internal Sleep future.
///
/// Note: `TimeService`'s should be free (or very cheap) to clone and send around
/// between threads. In production (without test features), this enum is a
/// zero-sized type.
#[enum_dispatch(TimeServiceTrait)]
#[derive(Clone, Debug)]
pub enum TimeService {
    RealTimeService(RealTimeService),

    #[cfg(any(test, feature = "testing"))]
    MockTimeService(MockTimeService),
}

impl TimeService {
    /// Create a new real, production time service that actually uses the systemtime.
    ///
    /// See [`RealTimeService`].
    pub fn real() -> Self {
        RealTimeService::new().into()
    }

    /// Create a mock, simulated time service that does not query the system time
    /// and allows fine-grained control over advancing time and waking sleeping
    /// tasks.
    ///
    /// See [`MockTimeService`].
    #[cfg(any(test, feature = "testing"))]
    pub fn mock() -> Self {
        MockTimeService::new().into()
    }

    #[cfg(any(test, feature = "testing"))]
    pub fn into_mock(self) -> MockTimeService {
        match self {
            TimeService::MockTimeService(inner) => inner,
            ts => panic!("Unexpected TimeService, expected MockTimeService: {:?}", ts),
        }
    }
}

impl Default for TimeService {
    fn default() -> Self {
        Self::real()
    }
}

#[enum_dispatch]
pub trait TimeServiceTrait: Send + Sync + Clone + Debug {
    /// Query a monotonically nondecreasing clock. Returns an opaque type that
    /// can only be compared to other [`Instant`]s, i.e., this is a monotonic
    /// relative time whereas [`now_unix_time`](#method.now_unix_time) is a
    /// non-monotonic absolute time.
    ///
    /// On Linux, this is equivalent to
    /// [`clock_gettime(CLOCK_MONOTONIC, _)`](https://linux.die.net/man/3/clock_gettime)
    ///
    /// See [`Instant`] for more details.
    fn now(&self) -> Instant;

    /// Query the current unix timestamp as a [`Duration`].
    ///
    /// When used on a `TimeService::real()`, this is equivalent to
    /// `SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)`.
    ///
    /// Note: the [`Duration`] returned from this function is _NOT_ guaranteed to
    /// be monotonic. Use [`now`](#method.now) if you need monotonicity.
    ///
    /// From the [`SystemTime`] docs:
    ///
    /// > Distinct from the [`Instant`] type, this time measurement is
    /// > not monotonic. This means that you can save a file to the file system,
    /// > then save another file to the file system, and the second file has a
    /// > [`SystemTime`] measurement earlier than the first. In other words, an
    /// > operation that happens after another operation in real time may have
    /// > an earlier SystemTime!
    ///
    /// For example, the system administrator could [`clock_settime`] into the
    /// past, breaking clock time monotonicity.
    ///
    /// On Linux, this is equivalent to
    /// [`clock_gettime(CLOCK_REALTIME, _)`](https://linux.die.net/man/3/clock_gettime).
    ///
    /// [`Duration`]: std::time::Duration
    /// [`Instant`]: std::time::Instant
    /// [`SystemTime`]: std::time::SystemTime
    /// [`clock_settime`]: https://linux.die.net/man/3/clock_settime
    fn now_unix_time(&self) -> Duration;

    /// Query the current unix timestamp in seconds.
    ///
    /// Equivalent to `self.now_unix_time().as_secs()`.
    /// See [`now_unix_time`](#method.now_unix_time).
    fn now_secs(&self) -> u64 {
        self.now_unix_time().as_secs()
    }

    /// Return a [`Future`] that waits until `duration` has passed.
    ///
    /// No work is performed while awaiting on the sleep future to complete. `Sleep`
    /// operates at millisecond granularity and should not be used for tasks that
    /// require high-resolution timers.
    ///
    /// # Cancelation
    ///
    /// Canceling a sleep instance is done by dropping the returned future. No
    /// additional cleanup work is required.
    #[cfg(any(test, feature = "async"))]
    fn sleep(&self, duration: Duration) -> Sleep;

    /// Return a [`Future`] that waits until the `deadline`.
    ///
    /// If the deadline is in the past, the Sleep will trigger as soons as it's
    /// polled.
    ///
    /// See [`sleep`](#method.sleep) for more details.
    #[cfg(any(test, feature = "async"))]
    fn sleep_until(&self, deadline: Instant) -> Sleep {
        let duration = deadline.saturating_duration_since(self.now());
        self.sleep(duration)
    }

    /// Blocks the current thread until `duration` time has passed.
    fn sleep_blocking(&self, duration: Duration);

    /// Creates a new [`Interval`] that yields with interval of `period`. The
    /// first tick completes immediately. An interval will tick indefinitely.
    ///
    /// # Cancelation
    ///
    /// At any time, the [`Interval`] value can be dropped. This cancels the interval.
    ///
    /// # Panics
    ///
    /// This function panics if `period` is zero.
    #[cfg(any(test, feature = "async"))]
    fn interval(&self, period: Duration) -> Interval {
        let delay = self.sleep(ZERO_DURATION);
        Interval::new(delay, period)
    }

    /// Creates a new [`Interval`] that yields with interval of `period`. The
    /// first tick completes after the `start` deadline. An interval will tick
    /// indefinitely.
    ///
    /// See [`interval`](#method.interval) for more details.
    #[cfg(any(test, feature = "async"))]
    fn interval_at(&self, start: Instant, period: Duration) -> Interval {
        let delay = self.sleep_until(start);
        Interval::new(delay, period)
    }

    /// Require a [`Future`] to complete before the specified duration has elapsed.
    ///
    /// If the future completes before the duration has elapsed, then the completed
    /// value is returned. Otherwise, `Err(Elapsed)` is returned and the future is
    /// canceled.
    ///
    /// # Cancelation
    ///
    /// Cancelling a timeout is done by dropping the future. No additional cleanup
    /// or other work is required.
    ///
    /// The original future may be obtained by calling [`Timeout::into_inner`]. This
    /// consumes the [`Timeout`].
    #[cfg(any(test, feature = "async"))]
    fn timeout<F: Future>(&self, duration: Duration, future: F) -> Timeout<F> {
        let delay = self.sleep(duration);
        Timeout::new(future, delay)
    }

    /// Require a [`Future`] to complete before the `deadline`.
    ///
    /// If the future completes before the duration has elapsed, then the completed
    /// value is returned. Otherwise, `Err(Elapsed)` is returned and the future is
    /// canceled.
    ///
    /// See [`timeout`](#method.timeout) for more details.
    #[cfg(any(test, feature = "async"))]
    fn timeout_at<F: Future>(&self, deadline: Instant, future: F) -> Timeout<F> {
        let delay = self.sleep_until(deadline);
        Timeout::new(future, delay)
    }
}

/// A [`Future`] that resolves after some time has elapsed (either real or
/// simulated, depending on the parent [`TimeService`]).
///
/// `Sleep` is modeled after [`tokio::time::Sleep`].
#[pin_project(project = SleepProject)]
#[derive(Debug)]
#[cfg(any(test, feature = "async"))]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub enum Sleep {
    RealSleep(#[pin] RealSleep),

    #[cfg(any(test, feature = "testing"))]
    MockSleep(MockSleep),
}

#[cfg(any(test, feature = "async"))]
impl From<RealSleep> for Sleep {
    fn from(sleep: RealSleep) -> Self {
        Sleep::RealSleep(sleep)
    }
}

#[cfg(any(test, feature = "fuzzing", feature = "testing"))]
impl From<MockSleep> for Sleep {
    fn from(sleep: MockSleep) -> Self {
        Sleep::MockSleep(sleep)
    }
}

#[cfg(any(test, feature = "async"))]
impl Future for Sleep {
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        match self.project() {
            SleepProject::RealSleep(inner) => inner.poll(cx),
            #[cfg(any(test, feature = "testing"))]
            SleepProject::MockSleep(inner) => Pin::new(inner).poll(cx),
        }
    }
}

#[cfg(any(test, feature = "async"))]
pub trait SleepTrait: Future<Output = ()> + Send + Sync + Debug {
    /// Returns `true` if this `Sleep`'s requested wait duration has elapsed.
    fn is_elapsed(&self) -> bool;

    /// Resets this `Sleep` to wait again for `duration`.
    fn reset(self: Pin<&mut Self>, duration: Duration);

    /// Reset this `Sleep` to wait again until the `deadline`.
    fn reset_until(self: Pin<&mut Self>, deadline: Instant);
}

#[cfg(any(test, feature = "async"))]
impl SleepTrait for Sleep {
    fn is_elapsed(&self) -> bool {
        match self {
            Sleep::RealSleep(inner) => SleepTrait::is_elapsed(inner),
            #[cfg(any(test, feature = "fuzzing", feature = "testing"))]
            Sleep::MockSleep(inner) => SleepTrait::is_elapsed(inner),
        }
    }

    fn reset(self: Pin<&mut Self>, duration: Duration) {
        match self.project() {
            SleepProject::RealSleep(inner) => SleepTrait::reset(inner, duration),
            #[cfg(any(test, feature = "fuzzing", feature = "testing"))]
            SleepProject::MockSleep(inner) => SleepTrait::reset(Pin::new(inner), duration),
        }
    }

    fn reset_until(self: Pin<&mut Self>, deadline: Instant) {
        match self.project() {
            SleepProject::RealSleep(inner) => SleepTrait::reset_until(inner, deadline),
            #[cfg(any(test, feature = "fuzzing", feature = "testing"))]
            SleepProject::MockSleep(inner) => SleepTrait::reset_until(Pin::new(inner), deadline),
        }
    }
}
<|endoftext|>


<commit_before>use std::path::MAIN_SEPARATOR;
use std::process::Command;

use clap::{App, Arg};

#[derive(Debug)]
pub struct Args {
    pub cmd: String,
    pub paths: Vec<String>,
    pub filters: Vec<String>,
    pub ignores: Vec<String>,
    pub clear_screen: bool,
    pub signal: String,
    pub restart: bool,
    pub debug: bool,
    pub run_initially: bool,
    pub no_vcs_ignore: bool,
    pub once: bool,
    pub poll: bool,
    pub poll_interval: u32,
}

#[cfg(target_family = "windows")]
pub fn clear_screen() {
    let _ = Command::new("cls").status();
}

#[cfg(target_family = "unix")]
pub fn clear_screen() {
    let _ = Command::new("clear").status();
}

#[allow(unknown_lints)]
#[allow(or_fun_call)]
pub fn get_args() -> Args {
    let args = App::new("watchexec")
        .version(crate_version!())
        .about("Execute commands when watched files change")
        .arg(Arg::with_name("command")
            .help("Command to execute")
            .multiple(true)
            .required(true))
        .arg(Arg::with_name("extensions")
            .help("Comma-separated list of file extensions to watch (js,css,html)")
            .short("e")
            .long("exts")
            .takes_value(true))
        .arg(Arg::with_name("path")
            .help("Watch a specific directory")
            .short("w")
            .long("watch")
            .number_of_values(1)
            .multiple(true)
            .takes_value(true))
        .arg(Arg::with_name("clear")
            .help("Clear screen before executing command")
            .short("c")
            .long("clear"))
        .arg(Arg::with_name("restart")
            .help("Restart the process if it's still running")
            .short("r")
            .long("restart"))
        .arg(Arg::with_name("signal") // TODO: --signal only makes sense when used with --restart
            .help("Signal to send when --restart is used, defaults to SIGTERM")
            .short("s")
            .long("signal")
            .takes_value(true)
            .number_of_values(1)
            .value_name("signal"))
        .arg(Arg::with_name("debug")
            .help("Print debugging messages to stderr")
            .short("d")
            .long("debug"))
        .arg(Arg::with_name("filter")
            .help("Ignore all modifications except those matching the pattern")
            .short("f")
            .long("filter")
            .number_of_values(1)
            .multiple(true)
            .takes_value(true)
            .value_name("pattern"))
        .arg(Arg::with_name("ignore")
            .help("Ignore modifications to paths matching the pattern")
            .short("i")
            .long("ignore")
            .number_of_values(1)
            .multiple(true)
            .takes_value(true)
            .value_name("pattern"))
        .arg(Arg::with_name("no-vcs-ignore")
            .help("Skip auto-loading of .gitignore files for filtering")
            .long("no-vcs-ignore"))
        .arg(Arg::with_name("postpone")
            .help("Wait until first change to execute command")
            .short("p")
            .long("postpone"))
        .arg(Arg::with_name("poll")
            .help("Forces polling mode")
            .long("force-poll")
            .value_name("interval"))
        .arg(Arg::with_name("once")
            .short("1")
            .hidden(true))
        .get_matches();

    let cmd = values_t!(args.values_of("command"), String).unwrap().join(" ");
    let paths = values_t!(args.values_of("path"), String).unwrap_or(vec![String::from(".")]);

    // TODO: I suppose there must be a better way of getting a string and a default value in clap
    let signal = values_t!(args.values_of("signal"), String)
        .unwrap_or(vec![String::from("SIGTERM")]) // TODO: Use SIGHUP as default?
        .join(" ");

    let mut filters = values_t!(args.values_of("filter"), String).unwrap_or(vec![]);

    if let Some(extensions) = args.values_of("extensions") {
        for exts in extensions {
            filters.extend(exts.split(',')
                .filter(|ext| !ext.is_empty())
                .map(|ext| format!("*.{}", ext.replace(".", ""))));

        }
    }

    let mut ignores = vec![];
    let default_ignores = vec![format!("*{}.*{}*", MAIN_SEPARATOR, MAIN_SEPARATOR),
                               format!("*{}.DS_Store", MAIN_SEPARATOR),
                               String::from("*.pyc"),
                               String::from("*.swp")];

    ignores.extend(default_ignores);
    ignores.extend(values_t!(args.values_of("ignore"), String).unwrap_or(vec![]));

    let poll_interval = if args.occurrences_of("poll") > 0 {
        value_t!(args.value_of("poll"), u32).unwrap_or_else(|e| e.exit())
    } else {
        1000
    };

    Args {
        cmd: cmd,
        paths: paths,
        filters: filters,
        ignores: ignores,
        signal: signal,
        clear_screen: args.is_present("clear"),
        restart: args.is_present("restart"),
        debug: args.is_present("debug"),
        run_initially: !args.is_present("postpone"),
        no_vcs_ignore: args.is_present("no-vcs-ignore"),
        once: args.is_present("once"),
        poll: args.occurrences_of("poll") > 0,
        poll_interval: poll_interval,
    }
}
<commit_msg>Use a more idiomatic way to set --signal<commit_after>use std::path::MAIN_SEPARATOR;
use std::process::Command;

use clap::{App, Arg};

#[derive(Debug)]
pub struct Args {
    pub cmd: String,
    pub paths: Vec<String>,
    pub filters: Vec<String>,
    pub ignores: Vec<String>,
    pub clear_screen: bool,
    pub signal: String,
    pub restart: bool,
    pub debug: bool,
    pub run_initially: bool,
    pub no_vcs_ignore: bool,
    pub once: bool,
    pub poll: bool,
    pub poll_interval: u32,
}

#[cfg(target_family = "windows")]
pub fn clear_screen() {
    let _ = Command::new("cls").status();
}

#[cfg(target_family = "unix")]
pub fn clear_screen() {
    let _ = Command::new("clear").status();
}

#[allow(unknown_lints)]
#[allow(or_fun_call)]
pub fn get_args() -> Args {
    let args = App::new("watchexec")
        .version(crate_version!())
        .about("Execute commands when watched files change")
        .arg(Arg::with_name("command")
            .help("Command to execute")
            .multiple(true)
            .required(true))
        .arg(Arg::with_name("extensions")
            .help("Comma-separated list of file extensions to watch (js,css,html)")
            .short("e")
            .long("exts")
            .takes_value(true))
        .arg(Arg::with_name("path")
            .help("Watch a specific directory")
            .short("w")
            .long("watch")
            .number_of_values(1)
            .multiple(true)
            .takes_value(true))
        .arg(Arg::with_name("clear")
            .help("Clear screen before executing command")
            .short("c")
            .long("clear"))
        .arg(Arg::with_name("restart")
            .help("Restart the process if it's still running")
            .short("r")
            .long("restart"))
        .arg(Arg::with_name("signal") // TODO: --signal only makes sense when used with --restart
            .help("Signal to send when --restart is used, defaults to SIGTERM")
            .short("s")
            .long("signal")
            .takes_value(true)
            .number_of_values(1)
            .value_name("signal"))
        .arg(Arg::with_name("debug")
            .help("Print debugging messages to stderr")
            .short("d")
            .long("debug"))
        .arg(Arg::with_name("filter")
            .help("Ignore all modifications except those matching the pattern")
            .short("f")
            .long("filter")
            .number_of_values(1)
            .multiple(true)
            .takes_value(true)
            .value_name("pattern"))
        .arg(Arg::with_name("ignore")
            .help("Ignore modifications to paths matching the pattern")
            .short("i")
            .long("ignore")
            .number_of_values(1)
            .multiple(true)
            .takes_value(true)
            .value_name("pattern"))
        .arg(Arg::with_name("no-vcs-ignore")
            .help("Skip auto-loading of .gitignore files for filtering")
            .long("no-vcs-ignore"))
        .arg(Arg::with_name("postpone")
            .help("Wait until first change to execute command")
            .short("p")
            .long("postpone"))
        .arg(Arg::with_name("poll")
            .help("Forces polling mode")
            .long("force-poll")
            .value_name("interval"))
        .arg(Arg::with_name("once")
            .short("1")
            .hidden(true))
        .get_matches();

    let cmd = values_t!(args.values_of("command"), String).unwrap().join(" ");
    let paths = values_t!(args.values_of("path"), String).unwrap_or(vec![String::from(".")]);
    let signal = args.value_of("signal").unwrap_or("SIGTERM").to_owned();

    let mut filters = values_t!(args.values_of("filter"), String).unwrap_or(vec![]);

    if let Some(extensions) = args.values_of("extensions") {
        for exts in extensions {
            filters.extend(exts.split(',')
                .filter(|ext| !ext.is_empty())
                .map(|ext| format!("*.{}", ext.replace(".", ""))));

        }
    }

    let mut ignores = vec![];
    let default_ignores = vec![format!("*{}.*{}*", MAIN_SEPARATOR, MAIN_SEPARATOR),
                               format!("*{}.DS_Store", MAIN_SEPARATOR),
                               String::from("*.pyc"),
                               String::from("*.swp")];

    ignores.extend(default_ignores);
    ignores.extend(values_t!(args.values_of("ignore"), String).unwrap_or(vec![]));

    let poll_interval = if args.occurrences_of("poll") > 0 {
        value_t!(args.value_of("poll"), u32).unwrap_or_else(|e| e.exit())
    } else {
        1000
    };

    Args {
        cmd: cmd,
        paths: paths,
        filters: filters,
        ignores: ignores,
        signal: signal,
        clear_screen: args.is_present("clear"),
        restart: args.is_present("restart"),
        debug: args.is_present("debug"),
        run_initially: !args.is_present("postpone"),
        no_vcs_ignore: args.is_present("no-vcs-ignore"),
        once: args.is_present("once"),
        poll: args.occurrences_of("poll") > 0,
        poll_interval: poll_interval,
    }
}
<|endoftext|>


<commit_before>use std::path::MAIN_SEPARATOR;
use std::process::Command;

use clap::{App, Arg};

#[derive(Debug)]
pub struct Args {
    pub cmd: String,
    pub paths: Vec<String>,
    pub filters: Vec<String>,
    pub ignores: Vec<String>,
    pub clear_screen: bool,
    pub signal: Option<String>,
    pub restart: bool,
    pub debug: bool,
    pub run_initially: bool,
    pub no_vcs_ignore: bool,
    pub once: bool,
    pub poll: bool,
    pub poll_interval: u32,
}

#[cfg(target_family = "windows")]
pub fn clear_screen() {
    let _ = Command::new("cls").status();
}

#[cfg(target_family = "unix")]
pub fn clear_screen() {
    let _ = Command::new("clear").status();
}

#[allow(unknown_lints)]
#[allow(or_fun_call)]
pub fn get_args() -> Args {
    let args =
        App::new("watchexec")
            .version(crate_version!())
            .about("Execute commands when watched files change")
            .arg(Arg::with_name("command")
                     .help("Command to execute")
                     .multiple(true)
                     .required(true))
            .arg(Arg::with_name("extensions")
                     .help("Comma-separated list of file extensions to watch (js,css,html)")
                     .short("e")
                     .long("exts")
                     .takes_value(true))
            .arg(Arg::with_name("path")
                     .help("Watch a specific directory")
                     .short("w")
                     .long("watch")
                     .number_of_values(1)
                     .multiple(true)
                     .takes_value(true))
            .arg(Arg::with_name("clear")
                     .help("Clear screen before executing command")
                     .short("c")
                     .long("clear"))
            .arg(Arg::with_name("restart")
                     .help("Restart the process if it's still running")
                     .short("r")
                     .long("restart"))
            .arg(Arg::with_name("signal")
                     .help("Send signal to process upon changes, e.g. SIGHUP")
                     .short("s")
                     .long("signal")
                     .takes_value(true)
                     .number_of_values(1)
                     .value_name("signal"))
            .arg(Arg::with_name("debug")
                     .help("Print debugging messages to stderr")
                     .short("d")
                     .long("debug"))
            .arg(Arg::with_name("filter")
                     .help("Ignore all modifications except those matching the pattern")
                     .short("f")
                     .long("filter")
                     .number_of_values(1)
                     .multiple(true)
                     .takes_value(true)
                     .value_name("pattern"))
            .arg(Arg::with_name("ignore")
                     .help("Ignore modifications to paths matching the pattern")
                     .short("i")
                     .long("ignore")
                     .number_of_values(1)
                     .multiple(true)
                     .takes_value(true)
                     .value_name("pattern"))
            .arg(Arg::with_name("no-vcs-ignore")
                     .help("Skip auto-loading of .gitignore files for filtering")
                     .long("no-vcs-ignore"))
            .arg(Arg::with_name("postpone")
                     .help("Wait until first change to execute command")
                     .short("p")
                     .long("postpone"))
            .arg(Arg::with_name("poll")
                     .help("Forces polling mode")
                     .long("force-poll")
                     .value_name("interval"))
            .arg(Arg::with_name("once").short("1").hidden(true))
            .get_matches();

    let cmd = values_t!(args.values_of("command"), String).unwrap().join(" ");
    let paths = values_t!(args.values_of("path"), String).unwrap_or(vec![String::from(".")]);
    let signal = args.value_of("signal").map(str::to_string); // Convert Option<&str> to Option<String>

    let mut filters = values_t!(args.values_of("filter"), String).unwrap_or(vec![]);

    if let Some(extensions) = args.values_of("extensions") {
        for exts in extensions {
            filters.extend(exts.split(',')
                .filter(|ext| !ext.is_empty())
                .map(|ext| format!("*.{}", ext.replace(".", ""))));

        }
    }

    let mut ignores = vec![];
    let default_ignores = vec![format!("*{}.*{}*", MAIN_SEPARATOR, MAIN_SEPARATOR),
                               format!("*{}.DS_Store", MAIN_SEPARATOR),
                               String::from("*.pyc"),
                               String::from("*.swp")];

    ignores.extend(default_ignores);
    ignores.extend(values_t!(args.values_of("ignore"), String).unwrap_or(vec![]));

    let poll_interval = if args.occurrences_of("poll") > 0 {
        value_t!(args.value_of("poll"), u32).unwrap_or_else(|e| e.exit())
    } else {
        1000
    };

    Args {
        cmd: cmd,
        paths: paths,
        filters: filters,
        ignores: ignores,
        signal: signal,
        clear_screen: args.is_present("clear"),
        restart: args.is_present("restart"),
        debug: args.is_present("debug"),
        run_initially: !args.is_present("postpone"),
        no_vcs_ignore: args.is_present("no-vcs-ignore"),
        once: args.is_present("once"),
        poll: args.occurrences_of("poll") > 0,
        poll_interval: poll_interval,
    }
}
<commit_msg>Add check for conflicting --signal and --postpone arguments<commit_after>use std::path::MAIN_SEPARATOR;
use std::process::Command;

use clap::{App, Arg, Error};

#[derive(Debug)]
pub struct Args {
    pub cmd: String,
    pub paths: Vec<String>,
    pub filters: Vec<String>,
    pub ignores: Vec<String>,
    pub clear_screen: bool,
    pub signal: Option<String>,
    pub restart: bool,
    pub debug: bool,
    pub run_initially: bool,
    pub no_vcs_ignore: bool,
    pub once: bool,
    pub poll: bool,
    pub poll_interval: u32,
}

#[cfg(target_family = "windows")]
pub fn clear_screen() {
    let _ = Command::new("cls").status();
}

#[cfg(target_family = "unix")]
pub fn clear_screen() {
    let _ = Command::new("clear").status();
}

#[allow(unknown_lints)]
#[allow(or_fun_call)]
pub fn get_args() -> Args {
    let args =
        App::new("watchexec")
            .version(crate_version!())
            .about("Execute commands when watched files change")
            .arg(Arg::with_name("command")
                     .help("Command to execute")
                     .multiple(true)
                     .required(true))
            .arg(Arg::with_name("extensions")
                     .help("Comma-separated list of file extensions to watch (js,css,html)")
                     .short("e")
                     .long("exts")
                     .takes_value(true))
            .arg(Arg::with_name("path")
                     .help("Watch a specific directory")
                     .short("w")
                     .long("watch")
                     .number_of_values(1)
                     .multiple(true)
                     .takes_value(true))
            .arg(Arg::with_name("clear")
                     .help("Clear screen before executing command")
                     .short("c")
                     .long("clear"))
            .arg(Arg::with_name("restart")
                     .help("Restart the process if it's still running")
                     .short("r")
                     .long("restart"))
            .arg(Arg::with_name("signal")
                     .help("Send signal to process upon changes, e.g. SIGHUP")
                     .short("s")
                     .long("signal")
                     .takes_value(true)
                     .number_of_values(1)
                     .value_name("signal"))
            .arg(Arg::with_name("debug")
                     .help("Print debugging messages to stderr")
                     .short("d")
                     .long("debug"))
            .arg(Arg::with_name("filter")
                     .help("Ignore all modifications except those matching the pattern")
                     .short("f")
                     .long("filter")
                     .number_of_values(1)
                     .multiple(true)
                     .takes_value(true)
                     .value_name("pattern"))
            .arg(Arg::with_name("ignore")
                     .help("Ignore modifications to paths matching the pattern")
                     .short("i")
                     .long("ignore")
                     .number_of_values(1)
                     .multiple(true)
                     .takes_value(true)
                     .value_name("pattern"))
            .arg(Arg::with_name("no-vcs-ignore")
                     .help("Skip auto-loading of .gitignore files for filtering")
                     .long("no-vcs-ignore"))
            .arg(Arg::with_name("postpone")
                     .help("Wait until first change to execute command")
                     .short("p")
                     .long("postpone"))
            .arg(Arg::with_name("poll")
                     .help("Forces polling mode")
                     .long("force-poll")
                     .value_name("interval"))
            .arg(Arg::with_name("once").short("1").hidden(true))
            .get_matches();

    let cmd = values_t!(args.values_of("command"), String).unwrap().join(" ");
    let paths = values_t!(args.values_of("path"), String).unwrap_or(vec![String::from(".")]);
    let signal = args.value_of("signal").map(str::to_string); // Convert Option<&str> to Option<String>

    let mut filters = values_t!(args.values_of("filter"), String).unwrap_or(vec![]);

    if let Some(extensions) = args.values_of("extensions") {
        for exts in extensions {
            filters.extend(exts.split(',')
                .filter(|ext| !ext.is_empty())
                .map(|ext| format!("*.{}", ext.replace(".", ""))));

        }
    }

    let mut ignores = vec![];
    let default_ignores = vec![format!("*{}.*{}*", MAIN_SEPARATOR, MAIN_SEPARATOR),
                               format!("*{}.DS_Store", MAIN_SEPARATOR),
                               String::from("*.pyc"),
                               String::from("*.swp")];

    ignores.extend(default_ignores);
    ignores.extend(values_t!(args.values_of("ignore"), String).unwrap_or(vec![]));

    let poll_interval = if args.occurrences_of("poll") > 0 {
        value_t!(args.value_of("poll"), u32).unwrap_or_else(|e| e.exit())
    } else {
        1000
    };

    if signal.is_some() && args.is_present("postpone") {
        // TODO: Error::argument_conflict() might be the better fit, usage was unclear, though
        Error::value_validation_auto(format!("--postpone and --signal are mutually exclusive"))
            .exit();
    }

    Args {
        cmd: cmd,
        paths: paths,
        filters: filters,
        ignores: ignores,
        signal: signal,
        clear_screen: args.is_present("clear"),
        restart: args.is_present("restart"),
        debug: args.is_present("debug"),
        run_initially: !args.is_present("postpone"),
        no_vcs_ignore: args.is_present("no-vcs-ignore"),
        once: args.is_present("once"),
        poll: args.occurrences_of("poll") > 0,
        poll_interval: poll_interval,
    }
}
<|endoftext|>


<commit_before>use super::memory;
use num::FromPrimitive;
use std::fmt;

enum_from_primitive! {
#[derive(Debug, Clone, Copy)]
enum Reg16 {
    BC = 0b00,
    DE = 0b01,
    HL = 0b10,
    SP = 0b11
}
}

enum_from_primitive! {
#[derive(Debug, Clone, Copy)]
enum Reg8 {
    A = 0b111,
    B = 0b000,
    C = 0b001,
    D = 0b010,
    E = 0b011,
    H = 0b100,
    L = 0b101
}
}

#[derive(Debug)]
pub struct Cpu {
    // main register set
    a: u8, f: u8,
    b: u8, c: u8,
    d: u8, e: u8,
    h: u8, l: u8,

    // alternate register set
    a_alt: u8, f_alt: u8,
    b_alt: u8, c_alt: u8,
    d_alt: u8, e_alt: u8,
    h_alt: u8, l_alt: u8,

    // interrupt vector
    i: u8,

    // memory refresh
    r: u8,

    // index register X
    ix: u16,

    // index register Y
    iy: u16,

    // stack pointer
    sp: u16,

    // program counter
    pc: u16,

    // interrupt flip-flops
    iff1: bool,
    iff2: bool,

    memory: memory::Memory
}

impl Cpu {
    pub fn new(memory: memory::Memory) -> Cpu {
        Cpu {
            a: 0, f: 0,
            b: 0, c: 0,
            d: 0, e: 0,
            h: 0, l: 0,
            a_alt: 0, f_alt: 0,
            b_alt: 0, c_alt: 0,
            d_alt: 0, e_alt: 0,
            h_alt: 0, l_alt: 0,
            i: 0,
            r: 0,
            ix: 0,
            iy: 0,
            sp: 0,
            pc: 0,
            iff1: false,
            iff2: false,

            memory: memory
        }
    }

    pub fn run(&mut self) {
        loop {
            self.run_instruction();
        }
    }

    fn read_reg8(&self, reg: Reg8) -> u8 {
        match reg {
            Reg8::A => self.a,
            Reg8::B => self.b,
            Reg8::C => self.c,
            Reg8::D => self.d,
            Reg8::E => self.e,
            Reg8::H => self.h,
            Reg8::L => self.l
        }
    }

    fn write_reg8(&mut self, reg: Reg8, val: u8) {
        match reg {
            Reg8::A => self.a = val,
            Reg8::B => self.b = val,
            Reg8::C => self.c = val,
            Reg8::D => self.d = val,
            Reg8::E => self.e = val,
            Reg8::H => self.h = val,
            Reg8::L => self.l = val
        }
    }

    fn read_reg16(&self, reg: Reg16) -> u16 {
        let value = match reg {
            Reg16::SP => self.sp,
            _ => {
                let (high, low) = match reg {
                    Reg16::BC => (self.b, self.c),
                    Reg16::DE => (self.d, self.e),
                    Reg16::HL => (self.h, self.l),
                    _ => unreachable!()
                };
                (((high as u16) << 8 ) + low as u16)
            }
        };
        value
    }

    fn write_reg16(&mut self, reg: Reg16, val: u16) {
        let (high, low) = (((val & 0xFF00) >> 8) as u8, (val & 0x00FF) as u8);
        match reg {
            Reg16::BC => { self.b = high; self.c = low; }
            Reg16::DE => { self.d = high; self.e = low; }
            Reg16::HL => { self.h = high; self.l = low; }
            Reg16::SP => { self.sp = val }
        }
    }

    fn run_instruction(&mut self) {
        let instruction = self.read_word(self.pc);

        match instruction {
            instruction if instruction & 0b11000000 == 0b01000000 => {
                // TODO Better Option handling here
                let rt = Reg8::from_u8((instruction >> 3) & 0b111).unwrap();
                let rs = Reg8::from_u8( instruction       & 0b111).unwrap();
                let rsval = self.read_reg8(rs);
                self.write_reg8(rt, rsval);
                println!("{:#x}: LD {:?}, {:?}", self.pc, rt, rs);
                self.pc += 1;
            },

            0b11110011 => {
                self.iff1 = false;
                self.iff2 = false;
                println!("{:#x}: DI", self.pc);
                self.pc += 1;
            },

            0b00000001 | 0b00010001 | 0b00100001 | 0b00110001 => {
                let nn = (self.read_word(self.pc + 1) as u16) +
                        ((self.read_word(self.pc + 2) as u16) << 8);
                let regpair = Reg16::from_u8((instruction & 0b00110000) >> 4).unwrap();
                self.write_reg16(regpair, nn);

                println!("{:#x}: LD {:?}, ${:x}", self.pc, regpair, nn);
                self.pc += 3;
            },
            0b00001011 | 0b00011011 | 0b00101011 | 0b00111011 => {
                let regpair = Reg16::from_u8((instruction & 0b00110000) >> 4).unwrap();
                let oldregval = self.read_reg16(regpair);
                self.write_reg16(regpair, oldregval - 1);

                println!("{:#x}: DEC {:?}", self.pc, regpair);
                self.pc += 1;
            },
            _ => {
                panic!("Unrecognized instruction: {:#x}", instruction);
            }
        }
    }

    fn read_word(&self, addr: u16) -> u8 {
        self.memory.read_word(addr)
    }
}

<commit_msg>Add prettier debug output for Cpu<commit_after>use super::memory;
use num::FromPrimitive;
use std::fmt;

enum_from_primitive! {
#[derive(Debug, Clone, Copy)]
enum Reg16 {
    BC = 0b00,
    DE = 0b01,
    HL = 0b10,
    SP = 0b11
}
}

enum_from_primitive! {
#[derive(Debug, Clone, Copy)]
enum Reg8 {
    A = 0b111,
    B = 0b000,
    C = 0b001,
    D = 0b010,
    E = 0b011,
    H = 0b100,
    L = 0b101
}
}

pub struct Cpu {
    // main register set
    a: u8, f: u8,
    b: u8, c: u8,
    d: u8, e: u8,
    h: u8, l: u8,

    // alternate register set
    a_alt: u8, f_alt: u8,
    b_alt: u8, c_alt: u8,
    d_alt: u8, e_alt: u8,
    h_alt: u8, l_alt: u8,

    // interrupt vector
    i: u8,

    // memory refresh
    r: u8,

    // index register X
    ix: u16,

    // index register Y
    iy: u16,

    // stack pointer
    sp: u16,

    // program counter
    pc: u16,

    // interrupt flip-flops
    iff1: bool,
    iff2: bool,

    memory: memory::Memory

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "
                         -----------
                     af: | {:02X} | {:02X} |
                     bc: | {:02X} | {:02X} |
                     de: | {:02X} | {:02X} |
                     hl: | {:02X} | {:02X} |
                         -----------
                     ir  | {:02X} | {:02X} |
                         -----------
                     ix  |   {:04X}  |
                     iy  |   {:04X}  |
                     sp  |   {:04X}  |
                     pc  |   {:04X}  |
                         -----------",
                      self.a, self.f,
                      self.b, self.c,
                      self.d, self.e,
                      self.h, self.l,
                      self.i, self.r,
                      self.ix,
                      self.iy,
                      self.sp,
                      self.pc)
    }
}

impl Cpu {
    pub fn new(memory: memory::Memory) -> Cpu {
        Cpu {
            a: 0, f: 0,
            b: 0, c: 0,
            d: 0, e: 0,
            h: 0, l: 0,
            a_alt: 0, f_alt: 0,
            b_alt: 0, c_alt: 0,
            d_alt: 0, e_alt: 0,
            h_alt: 0, l_alt: 0,
            i: 0,
            r: 0,
            ix: 0,
            iy: 0,
            sp: 0,
            pc: 0,
            iff1: false,
            iff2: false,

            memory: memory
        }
    }

    pub fn run(&mut self) {
        loop {
            self.run_instruction();
        }
    }

    fn read_reg8(&self, reg: Reg8) -> u8 {
        match reg {
            Reg8::A => self.a,
            Reg8::B => self.b,
            Reg8::C => self.c,
            Reg8::D => self.d,
            Reg8::E => self.e,
            Reg8::H => self.h,
            Reg8::L => self.l
        }
    }

    fn write_reg8(&mut self, reg: Reg8, val: u8) {
        match reg {
            Reg8::A => self.a = val,
            Reg8::B => self.b = val,
            Reg8::C => self.c = val,
            Reg8::D => self.d = val,
            Reg8::E => self.e = val,
            Reg8::H => self.h = val,
            Reg8::L => self.l = val
        }
    }

    fn read_reg16(&self, reg: Reg16) -> u16 {
        let value = match reg {
            Reg16::SP => self.sp,
            _ => {
                let (high, low) = match reg {
                    Reg16::BC => (self.b, self.c),
                    Reg16::DE => (self.d, self.e),
                    Reg16::HL => (self.h, self.l),
                    _ => unreachable!()
                };
                (((high as u16) << 8 ) + low as u16)
            }
        };
        value
    }

    fn write_reg16(&mut self, reg: Reg16, val: u16) {
        let (high, low) = (((val & 0xFF00) >> 8) as u8, (val & 0x00FF) as u8);
        match reg {
            Reg16::BC => { self.b = high; self.c = low; }
            Reg16::DE => { self.d = high; self.e = low; }
            Reg16::HL => { self.h = high; self.l = low; }
            Reg16::SP => { self.sp = val }
        }
    }

    fn run_instruction(&mut self) {
        let instruction = self.read_word(self.pc);

        match instruction {
            instruction if instruction & 0b11000000 == 0b01000000 => {
                // TODO Better Option handling here
                let rt = Reg8::from_u8((instruction >> 3) & 0b111).unwrap();
                let rs = Reg8::from_u8( instruction       & 0b111).unwrap();
                let rsval = self.read_reg8(rs);
                self.write_reg8(rt, rsval);
                println!("{:#x}: LD {:?}, {:?}", self.pc, rt, rs);
                self.pc += 1;
            },

            0b11110011 => {
                self.iff1 = false;
                self.iff2 = false;
                println!("{:#x}: DI", self.pc);
                self.pc += 1;
            },

            0b00000001 | 0b00010001 | 0b00100001 | 0b00110001 => {
                let nn = (self.read_word(self.pc + 1) as u16) +
                        ((self.read_word(self.pc + 2) as u16) << 8);
                let regpair = Reg16::from_u8((instruction & 0b00110000) >> 4).unwrap();
                self.write_reg16(regpair, nn);

                println!("{:#x}: LD {:?}, ${:x}", self.pc, regpair, nn);
                self.pc += 3;
            },
            0b00001011 | 0b00011011 | 0b00101011 | 0b00111011 => {
                let regpair = Reg16::from_u8((instruction & 0b00110000) >> 4).unwrap();
                let oldregval = self.read_reg16(regpair);
                self.write_reg16(regpair, oldregval - 1);

                println!("{:#x}: DEC {:?}", self.pc, regpair);
                self.pc += 1;
            },
            _ => {
                panic!("Unrecognized instruction: {:#x}", instruction);
            }
        }
        println!("{:?}", self);
    }

    fn read_word(&self, addr: u16) -> u8 {
        self.memory.read_word(addr)
    }
}

<|endoftext|>


<commit_before>// Copyright 2021 The Kythe Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
extern crate kythe_rust_indexer;
use kythe_rust_indexer::{
    error::KytheError, indexer::KytheIndexer, providers::*, writer::ProxyWriter,
};

use analysis_rust_proto::*;
use anyhow::{anyhow, Context, Result};
use clap::{App, Arg};
use serde_json::Value;
use std::{
    fs::{self, File},
    io::{self, Write},
    path::{Path, PathBuf},
};
use tempdir::TempDir;

fn main() -> Result<()> {
    let matches = App::new("Kythe Rust Extractor")
        .arg(
            Arg::with_name("tmp_directory")
                .long("tmp_directory")
                .required(false)
                .takes_value(true)
                .help("A directory where to write save_analysis files"),
        )
        .get_matches();

    // Get the absolute path of the tmp_directory argument or default to /tmp
    let tmp_path_arg = {
        if let Some(arg) = matches.value_of("tmp_directory") {
            fs::canonicalize(arg).context("Failed to canonicalize tmp_directory path")?
        } else {
            std::env::temp_dir()
        }
    };

    // Check if the tmp_directory exists
    if !tmp_path_arg.exists() {
        eprintln!("tmp_directory path is not a directory or does not exist");
        std::process::exit(1);
    }

    let mut file_provider = ProxyFileProvider::new();
    let mut kythe_writer = ProxyWriter::new();
    let mut indexer = KytheIndexer::new(&mut kythe_writer);

    // Request and process
    loop {
        let unit = request_compilation_unit()?;
        // Retrieve the save_analysis file
        let analysis_temp_dir = TempDir::new_in(tmp_path_arg.clone(), "rust_indexer_tmp")
            .context("Couldn't create temporary directory")?;
        let analysis_temp_path = PathBuf::new().join(analysis_temp_dir.path());
        let write_res = write_analysis_to_directory(&unit, &analysis_temp_path, &mut file_provider);
        if write_res.is_err() {
            send_done(false, write_res.err().unwrap().to_string())?;
            continue;
        }

        // Index the CompilationUnit and let the proxy know we are done
        let index_res = indexer.index_cu(&unit, &analysis_temp_path, &mut file_provider);
        if index_res.is_ok() {
            send_done(true, String::new())?;
        } else {
            send_done(false, index_res.err().unwrap().to_string())?;
        }
    }
}

/// Takes analysis files present in a CompilationUnit, requests the files
/// from the proxy, and writes them to `temp_path`
pub fn write_analysis_to_directory(
    c_unit: &CompilationUnit,
    temp_path: &Path,
    provider: &mut dyn FileProvider,
) -> std::result::Result<(), KytheError> {
    for required_input in c_unit.get_required_input() {
        let input_path = required_input.get_info().get_path();
        let input_path_buf = PathBuf::new().join(input_path);

        // save_analysis files are JSON files
        if let Some(os_str) = input_path_buf.extension() {
            if let Some("json") = os_str.to_str() {
                let digest = required_input.get_info().get_digest();
                let file_contents = provider.contents(input_path, digest).map_err(|err| {
                    KytheError::IndexerError(format!(
                        "Failed to get contents of file \"{}\" with digest \"{}\": {:?}",
                        input_path, digest, err
                    ))
                })?;

                let output_path = temp_path.join(input_path_buf.file_name().unwrap());
                let mut output_file = File::create(&output_path).map_err(|err| {
                    KytheError::IndexerError(format!("Failed to create file: {:?}", err))
                })?;
                output_file.write_all(&file_contents).map_err(|err| {
                    KytheError::IndexerError(format!(
                        "Failed to copy contents of \"{}\" with digest \"{}\" to \"{}\": {:?}",
                        input_path,
                        digest,
                        output_path.display(),
                        err
                    ))
                })?;
            }
        }
    }
    Ok(())
}

fn request_compilation_unit() -> Result<CompilationUnit> {
    println!(r#"{{"req":"analysis_wire"}}"#);
    io::stdout().flush().context("Failed to flush stdout")?;

    // Read the response from the proxy
    let mut response_string = String::new();
    io::stdin().read_line(&mut response_string).context("Failed to read response from proxy")?;

    // Convert to json and extract information
    let response: Value =
        serde_json::from_str(&response_string).context("Failed to parse response as JSON")?;
    if response["rsp"].as_str().unwrap() == "ok" {
        let args = response["args"].clone();
        let unit_base64 = args["unit"].as_str().unwrap();
        let unit_bytes = base64::decode(unit_base64)
            .context("Failed to decode CompilationUnit sent by proxy")?;
        let unit = protobuf::parse_from_bytes::<CompilationUnit>(&unit_bytes)
            .context("Failed to parse protobuf")?;
        Ok(unit)
    } else {
        Err(anyhow!("Failed to get a CompilationUnit from the proxy"))
    }
}

/// Sends the "done" request to the proxy. The first argument sets the "ok"
/// value, and the second sets the error message if the first argument is false.
fn send_done(ok: bool, msg: String) -> Result<()> {
    if ok {
        println!(r#"{{"req":"done", "args":{{"ok":true,"msg":""}}}}"#);
    } else {
        println!(r#"{{"req":"done", "args":{{"ok":false,"msg":"{}"}}}}"#, msg);
    }
    io::stdout().flush().context("Failed to flush stdout")?;

    // Grab the response, but we don't care what it is so just throw it away
    let mut response_string = String::new();
    io::stdin().read_line(&mut response_string).context("Failed to read response from proxy")?;
    Ok(())
}
<commit_msg>fix(rust_indexer): don't try to canonicalize tmp_directory (#5061)<commit_after>// Copyright 2021 The Kythe Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
extern crate kythe_rust_indexer;
use kythe_rust_indexer::{
    error::KytheError, indexer::KytheIndexer, providers::*, writer::ProxyWriter,
};

use analysis_rust_proto::*;
use anyhow::{anyhow, Context, Result};
use clap::{App, Arg};
use serde_json::Value;
use std::{
    fs::File,
    io::{self, Write},
    path::{Path, PathBuf},
};
use tempdir::TempDir;

fn main() -> Result<()> {
    let matches = App::new("Kythe Rust Extractor")
        .arg(
            Arg::with_name("tmp_directory")
                .long("tmp_directory")
                .required(false)
                .takes_value(true)
                .help("A directory where to write save_analysis files"),
        )
        .get_matches();

    // Get the absolute path of the tmp_directory argument or default to /tmp
    let tmp_path_arg = {
        if let Some(arg) = matches.value_of("tmp_directory") {
            let path = PathBuf::new().join(arg);
            if !path.is_dir() {
                panic!("tmp_directory argument \"{}\" does not exist", arg);
            }
            path
        } else {
            std::env::temp_dir()
        }
    };

    // Check if the tmp_directory exists
    if !tmp_path_arg.exists() {
        eprintln!("tmp_directory path is not a directory or does not exist");
        std::process::exit(1);
    }

    let mut file_provider = ProxyFileProvider::new();
    let mut kythe_writer = ProxyWriter::new();
    let mut indexer = KytheIndexer::new(&mut kythe_writer);

    // Request and process
    loop {
        let unit = request_compilation_unit()?;
        // Retrieve the save_analysis file
        let analysis_temp_dir = TempDir::new_in(tmp_path_arg.clone(), "rust_indexer_tmp")
            .context("Couldn't create temporary directory")?;
        let analysis_temp_path = PathBuf::new().join(analysis_temp_dir.path());
        let write_res = write_analysis_to_directory(&unit, &analysis_temp_path, &mut file_provider);
        if write_res.is_err() {
            send_done(false, write_res.err().unwrap().to_string())?;
            continue;
        }

        // Index the CompilationUnit and let the proxy know we are done
        let index_res = indexer.index_cu(&unit, &analysis_temp_path, &mut file_provider);
        if index_res.is_ok() {
            send_done(true, String::new())?;
        } else {
            send_done(false, index_res.err().unwrap().to_string())?;
        }
    }
}

/// Takes analysis files present in a CompilationUnit, requests the files
/// from the proxy, and writes them to `temp_path`
pub fn write_analysis_to_directory(
    c_unit: &CompilationUnit,
    temp_path: &Path,
    provider: &mut dyn FileProvider,
) -> std::result::Result<(), KytheError> {
    for required_input in c_unit.get_required_input() {
        let input_path = required_input.get_info().get_path();
        let input_path_buf = PathBuf::new().join(input_path);

        // save_analysis files are JSON files
        if let Some(os_str) = input_path_buf.extension() {
            if let Some("json") = os_str.to_str() {
                let digest = required_input.get_info().get_digest();
                let file_contents = provider.contents(input_path, digest).map_err(|err| {
                    KytheError::IndexerError(format!(
                        "Failed to get contents of file \"{}\" with digest \"{}\": {:?}",
                        input_path, digest, err
                    ))
                })?;

                let output_path = temp_path.join(input_path_buf.file_name().unwrap());
                let mut output_file = File::create(&output_path).map_err(|err| {
                    KytheError::IndexerError(format!("Failed to create file: {:?}", err))
                })?;
                output_file.write_all(&file_contents).map_err(|err| {
                    KytheError::IndexerError(format!(
                        "Failed to copy contents of \"{}\" with digest \"{}\" to \"{}\": {:?}",
                        input_path,
                        digest,
                        output_path.display(),
                        err
                    ))
                })?;
            }
        }
    }
    Ok(())
}

fn request_compilation_unit() -> Result<CompilationUnit> {
    println!(r#"{{"req":"analysis_wire"}}"#);
    io::stdout().flush().context("Failed to flush stdout")?;

    // Read the response from the proxy
    let mut response_string = String::new();
    io::stdin().read_line(&mut response_string).context("Failed to read response from proxy")?;

    // Convert to json and extract information
    let response: Value =
        serde_json::from_str(&response_string).context("Failed to parse response as JSON")?;
    if response["rsp"].as_str().unwrap() == "ok" {
        let args = response["args"].clone();
        let unit_base64 = args["unit"].as_str().unwrap();
        let unit_bytes = base64::decode(unit_base64)
            .context("Failed to decode CompilationUnit sent by proxy")?;
        let unit = protobuf::parse_from_bytes::<CompilationUnit>(&unit_bytes)
            .context("Failed to parse protobuf")?;
        Ok(unit)
    } else {
        Err(anyhow!("Failed to get a CompilationUnit from the proxy"))
    }
}

/// Sends the "done" request to the proxy. The first argument sets the "ok"
/// value, and the second sets the error message if the first argument is false.
fn send_done(ok: bool, msg: String) -> Result<()> {
    if ok {
        println!(r#"{{"req":"done", "args":{{"ok":true,"msg":""}}}}"#);
    } else {
        println!(r#"{{"req":"done", "args":{{"ok":false,"msg":"{}"}}}}"#, msg);
    }
    io::stdout().flush().context("Failed to flush stdout")?;

    // Grab the response, but we don't care what it is so just throw it away
    let mut response_string = String::new();
    io::stdin().read_line(&mut response_string).context("Failed to read response from proxy")?;
    Ok(())
}
<|endoftext|>


<commit_before>/// Elf reader module
///

const EI_NIDENT: usize = 4;

// ELF32 types
#[allow(non_camel_case_types)]
type Elf32_Addr = u32;
#[allow(non_camel_case_types)]
type Elf32_Half = u16;
#[allow(non_camel_case_types)]
type Elf32_Lworld = u64;
#[allow(non_camel_case_types)]
type Elf32_Off = u32;
#[allow(non_camel_case_types)]
type Elf32_Sword = i32;
#[allow(non_camel_case_types)]
type Elf32_Word = u32;

/// Elf32 header.
/// Source: http://www.freebsd.org/cgi/man.cgi?elf(5)
#[repr(C)]
pub struct Elf32_Ehdr {
    e_ident: [u8; EI_NIDENT],
    e_type: Elf32_Half,
    e_machine: Elf32_Half,
    e_version: Elf32_Word,
    e_entry: Elf32_Addr,
    e_phoff: Elf32_Off,
    e_shoff: Elf32_Off,
    e_flags: Elf32_Word,
    e_ehsize: Elf32_Half,
    e_phentsize: Elf32_Half,
    e_phnum: Elf32_Half,
    e_shentsize: Elf32_Half,
    e_shnum: Elf32_Half,
    e_shstrndx: Elf32_Half,
}

/// Elf32 Program header
#[repr(C)]
pub struct Elf32_Phdr {
    p_type: Elf32_Word,
    p_offset: Elf32_Off,
    p_vaddr: Elf32_Addr,
    p_paddr: Elf32_Addr,
    p_filesz: Elf32_Word,
    p_memsz: Elf32_Word,
    p_flags: Elf32_Word,
    p_align: Elf32_Word,
}

/// Elf32 section header
#[repr(C)]
pub struct Elf32_Shrdr {
    sh_name: Elf32_Word,
    sh_type: Elf32_Word,
    sh_flags: Elf32_Word,
    sh_addr: Elf32_Addr,
    sh_offset: Elf32_Off,
    sh_size: Elf32_Word,
    sh_link: Elf32_Word,
    sh_info: Elf32_Word,
    sh_addalign: Elf32_Word,
    sh_entsize: Elf32_Word,
}

/// Elf32 symbol table
#[repr(C)]
pub struct Elf32_Sym {
    st_name: Elf32_Word,
    st_value: Elf32_Addr,
    st_size: Elf32_Word,
    st_info: u8,
    st_other: u8,
    st_shndx: Elf32_Half,
}
<commit_msg>Add Elf32 relocation structures<commit_after>/// Elf reader module
///

const EI_NIDENT: usize = 4;

// ELF32 types
#[allow(non_camel_case_types)]
type Elf32_Addr = u32;
#[allow(non_camel_case_types)]
type Elf32_Half = u16;
#[allow(non_camel_case_types)]
type Elf32_Lworld = u64;
#[allow(non_camel_case_types)]
type Elf32_Off = u32;
#[allow(non_camel_case_types)]
type Elf32_Sword = i32;
#[allow(non_camel_case_types)]
type Elf32_Word = u32;

/// Elf32 header.
/// Source: http://www.freebsd.org/cgi/man.cgi?elf(5)
#[repr(C)]
pub struct Elf32_Ehdr {
    e_ident: [u8; EI_NIDENT],
    e_type: Elf32_Half,
    e_machine: Elf32_Half,
    e_version: Elf32_Word,
    e_entry: Elf32_Addr,
    e_phoff: Elf32_Off,
    e_shoff: Elf32_Off,
    e_flags: Elf32_Word,
    e_ehsize: Elf32_Half,
    e_phentsize: Elf32_Half,
    e_phnum: Elf32_Half,
    e_shentsize: Elf32_Half,
    e_shnum: Elf32_Half,
    e_shstrndx: Elf32_Half,
}

/// Elf32 Program header
#[repr(C)]
pub struct Elf32_Phdr {
    p_type: Elf32_Word,
    p_offset: Elf32_Off,
    p_vaddr: Elf32_Addr,
    p_paddr: Elf32_Addr,
    p_filesz: Elf32_Word,
    p_memsz: Elf32_Word,
    p_flags: Elf32_Word,
    p_align: Elf32_Word,
}

/// Elf32 section header
#[repr(C)]
pub struct Elf32_Shrdr {
    sh_name: Elf32_Word,
    sh_type: Elf32_Word,
    sh_flags: Elf32_Word,
    sh_addr: Elf32_Addr,
    sh_offset: Elf32_Off,
    sh_size: Elf32_Word,
    sh_link: Elf32_Word,
    sh_info: Elf32_Word,
    sh_addalign: Elf32_Word,
    sh_entsize: Elf32_Word,
}

/// Elf32 symbol table
#[repr(C)]
pub struct Elf32_Sym {
    st_name: Elf32_Word,
    st_value: Elf32_Addr,
    st_size: Elf32_Word,
    st_info: u8,
    st_other: u8,
    st_shndx: Elf32_Half,
}

/// Elf32 relocation structure that doesn't need an addend
#[repr(C)]
pub struct Elf32_Rel {
    r_offset: Elf32_Addr,
    r_info: Elf32_Word,
}

/// Elf32 relocation structure that needs an addend
#[repr(C)]
pub struct Elf32_Rela {
    r_offset: Elf32_Addr,
    r_info: Elf32_Word,
    r_addent: Elf32_Sword
}
<|endoftext|>


<commit_before>#![warn(trivial_casts, trivial_numeric_casts)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

extern crate ansi_term;
extern crate datetime;
extern crate getopts;
extern crate libc;
extern crate locale;
extern crate natord;
extern crate num_cpus;
extern crate number_prefix;
extern crate scoped_threadpool;
extern crate term_grid;
extern crate unicode_width;
extern crate users;
extern crate zoneinfo_compiled;

#[cfg(feature="git")] extern crate git2;
#[macro_use] extern crate lazy_static;

use std::ffi::OsStr;
use std::io::{stderr, Write, Result as IOResult};
use std::path::{Component, Path};

use fs::{Dir, File};
use options::{Options, View};
pub use options::Misfire;

mod fs;
mod info;
mod options;
mod output;
mod term;

/// The main program wrapper.
pub struct Exa<'w, W: Write + 'w> {

    /// List of command-line options, having been successfully parsed.
    pub options: Options,

    /// The output handle that we write to. When running the program normally,
    /// this will be `std::io::Stdout`, but it can accept any struct that’s
    /// `Write` so we can write into, say, a vector for testing.
    pub writer: &'w mut W,

    /// List of the free command-line arguments that should correspond to file
    /// names (anything that isn’t an option).
    pub args: Vec<String>,
}

impl<'w, W: Write + 'w> Exa<'w, W> {
    pub fn new<S>(args: &[S], writer: &'w mut W) -> Result<Exa<'w, W>, Misfire>
    where S: AsRef<OsStr> {
        Options::getopts(args).map(move |(opts, args)| Exa {
            options: opts,
            writer:  writer,
            args:    args,
        })
    }

    pub fn run(&mut self) -> IOResult<()> {
        let mut files = Vec::new();
        let mut dirs = Vec::new();

        // List the current directory by default, like ls.
        if self.args.is_empty() {
            self.args.push(".".to_owned());
        }

        for file_name in self.args.iter() {
            match File::from_path(Path::new(&file_name), None) {
                Err(e) => {
                    try!(writeln!(stderr(), "{}: {}", file_name, e));
                },
                Ok(f) => {
                    if f.is_directory() && !self.options.dir_action.treat_dirs_as_files() {
                        match f.to_dir(self.options.should_scan_for_git()) {
                            Ok(d) => dirs.push(d),
                            Err(e) => try!(writeln!(stderr(), "{}: {}", file_name, e)),
                        }
                    }
                    else {
                        files.push(f);
                    }
                },
            }
        }

        // We want to print a directory’s name before we list it, *except* in
        // the case where it’s the only directory, *except* if there are any
        // files to print as well. (It’s a double negative)

        let no_files = files.is_empty();
        let is_only_dir = dirs.len() == 1 && no_files;

        try!(self.print_files(None, files));
        self.print_dirs(dirs, no_files, is_only_dir)
    }

    fn print_dirs(&mut self, dir_files: Vec<Dir>, mut first: bool, is_only_dir: bool) -> IOResult<()> {
        for dir in dir_files {

            // Put a gap between directories, or between the list of files and
            // the first directory.
            if first {
                first = false;
            }
            else {
                try!(write!(self.writer, "\n"));
            }

            if !is_only_dir {
                try!(writeln!(self.writer, "{}:", dir.path.display()));
            }

            let mut children = Vec::new();
            for file in dir.files() {
                match file {
                    Ok(file)       => children.push(file),
                    Err((path, e)) => try!(writeln!(stderr(), "[{}: {}]", path.display(), e)),
                }
            };

            self.options.filter.filter_files(&mut children);
            self.options.filter.sort_files(&mut children);

            if let Some(recurse_opts) = self.options.dir_action.recurse_options() {
                let depth = dir.path.components().filter(|&c| c != Component::CurDir).count() + 1;
                if !recurse_opts.tree && !recurse_opts.is_too_deep(depth) {

                    let mut child_dirs = Vec::new();
                    for child_dir in children.iter().filter(|f| f.is_directory()) {
                        match child_dir.to_dir(false) {
                            Ok(d)  => child_dirs.push(d),
                            Err(e) => try!(writeln!(stderr(), "{}: {}", child_dir.path.display(), e)),
                        }
                    }

                    try!(self.print_files(Some(&dir), children));
                    try!(self.print_dirs(child_dirs, false, false));
                    continue;
                }
            }

            try!(self.print_files(Some(&dir), children));
        }

        Ok(())
    }

    /// Prints the list of files using whichever view is selected.
    /// For various annoying logistical reasons, each one handles
    /// printing differently...
    fn print_files(&mut self, dir: Option<&Dir>, files: Vec<File>) -> IOResult<()> {
        if !files.is_empty() {
            match self.options.view {
                View::Grid(g)         => g.view(&files, self.writer),
                View::Details(d)      => d.view(dir, files, self.writer),
                View::GridDetails(gd) => gd.view(dir, files, self.writer),
                View::Lines(l)        => l.view(files, self.writer),
            }
        }
        else {
            Ok(())
        }
    }
}
<commit_msg>This lint flag started to cause all kinds of fuss<commit_after>#![warn(trivial_casts, trivial_numeric_casts)]
#![warn(unused_results)]

extern crate ansi_term;
extern crate datetime;
extern crate getopts;
extern crate libc;
extern crate locale;
extern crate natord;
extern crate num_cpus;
extern crate number_prefix;
extern crate scoped_threadpool;
extern crate term_grid;
extern crate unicode_width;
extern crate users;
extern crate zoneinfo_compiled;

#[cfg(feature="git")] extern crate git2;
#[macro_use] extern crate lazy_static;

use std::ffi::OsStr;
use std::io::{stderr, Write, Result as IOResult};
use std::path::{Component, Path};

use fs::{Dir, File};
use options::{Options, View};
pub use options::Misfire;

mod fs;
mod info;
mod options;
mod output;
mod term;

/// The main program wrapper.
pub struct Exa<'w, W: Write + 'w> {

    /// List of command-line options, having been successfully parsed.
    pub options: Options,

    /// The output handle that we write to. When running the program normally,
    /// this will be `std::io::Stdout`, but it can accept any struct that’s
    /// `Write` so we can write into, say, a vector for testing.
    pub writer: &'w mut W,

    /// List of the free command-line arguments that should correspond to file
    /// names (anything that isn’t an option).
    pub args: Vec<String>,
}

impl<'w, W: Write + 'w> Exa<'w, W> {
    pub fn new<S>(args: &[S], writer: &'w mut W) -> Result<Exa<'w, W>, Misfire>
    where S: AsRef<OsStr> {
        Options::getopts(args).map(move |(opts, args)| Exa {
            options: opts,
            writer:  writer,
            args:    args,
        })
    }

    pub fn run(&mut self) -> IOResult<()> {
        let mut files = Vec::new();
        let mut dirs = Vec::new();

        // List the current directory by default, like ls.
        if self.args.is_empty() {
            self.args.push(".".to_owned());
        }

        for file_name in self.args.iter() {
            match File::from_path(Path::new(&file_name), None) {
                Err(e) => {
                    try!(writeln!(stderr(), "{}: {}", file_name, e));
                },
                Ok(f) => {
                    if f.is_directory() && !self.options.dir_action.treat_dirs_as_files() {
                        match f.to_dir(self.options.should_scan_for_git()) {
                            Ok(d) => dirs.push(d),
                            Err(e) => try!(writeln!(stderr(), "{}: {}", file_name, e)),
                        }
                    }
                    else {
                        files.push(f);
                    }
                },
            }
        }

        // We want to print a directory’s name before we list it, *except* in
        // the case where it’s the only directory, *except* if there are any
        // files to print as well. (It’s a double negative)

        let no_files = files.is_empty();
        let is_only_dir = dirs.len() == 1 && no_files;

        try!(self.print_files(None, files));
        self.print_dirs(dirs, no_files, is_only_dir)
    }

    fn print_dirs(&mut self, dir_files: Vec<Dir>, mut first: bool, is_only_dir: bool) -> IOResult<()> {
        for dir in dir_files {

            // Put a gap between directories, or between the list of files and
            // the first directory.
            if first {
                first = false;
            }
            else {
                try!(write!(self.writer, "\n"));
            }

            if !is_only_dir {
                try!(writeln!(self.writer, "{}:", dir.path.display()));
            }

            let mut children = Vec::new();
            for file in dir.files() {
                match file {
                    Ok(file)       => children.push(file),
                    Err((path, e)) => try!(writeln!(stderr(), "[{}: {}]", path.display(), e)),
                }
            };

            self.options.filter.filter_files(&mut children);
            self.options.filter.sort_files(&mut children);

            if let Some(recurse_opts) = self.options.dir_action.recurse_options() {
                let depth = dir.path.components().filter(|&c| c != Component::CurDir).count() + 1;
                if !recurse_opts.tree && !recurse_opts.is_too_deep(depth) {

                    let mut child_dirs = Vec::new();
                    for child_dir in children.iter().filter(|f| f.is_directory()) {
                        match child_dir.to_dir(false) {
                            Ok(d)  => child_dirs.push(d),
                            Err(e) => try!(writeln!(stderr(), "{}: {}", child_dir.path.display(), e)),
                        }
                    }

                    try!(self.print_files(Some(&dir), children));
                    try!(self.print_dirs(child_dirs, false, false));
                    continue;
                }
            }

            try!(self.print_files(Some(&dir), children));
        }

        Ok(())
    }

    /// Prints the list of files using whichever view is selected.
    /// For various annoying logistical reasons, each one handles
    /// printing differently...
    fn print_files(&mut self, dir: Option<&Dir>, files: Vec<File>) -> IOResult<()> {
        if !files.is_empty() {
            match self.options.view {
                View::Grid(g)         => g.view(&files, self.writer),
                View::Details(d)      => d.view(dir, files, self.writer),
                View::GridDetails(gd) => gd.view(dir, files, self.writer),
                View::Lines(l)        => l.view(files, self.writer),
            }
        }
        else {
            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>#![allow(warnings)]

use libc;

pub static MZ_NO_FLUSH: libc::c_int = 0;
pub static MZ_SYNC_FLUSH: libc::c_int = 2;
pub static MZ_FINISH: libc::c_int = 4;

pub static MZ_OK: libc::c_int = 0;
pub static MZ_STREAM_END: libc::c_int = 1;
pub static MZ_NEED_DICT: libc::c_int = 2;
pub static MZ_ERRNO: libc::c_int = -1;
pub static MZ_STREAM_ERROR: libc::c_int = -2;
pub static MZ_DATA_ERROR: libc::c_int = -3;
pub static MZ_MEM_ERROR: libc::c_int = -4;
pub static MZ_BUF_ERROR: libc::c_int = -5;
pub static MZ_VERSION_ERROR: libc::c_int = -6;
pub static MZ_PARAM_ERROR: libc::c_int = -10000;

pub static MZ_DEFLATED: libc::c_int = 8;
pub static MZ_DEFAULT_WINDOW_BITS: libc::c_int = 15;
pub static MZ_DEFAULT_STRATEGY: libc::c_int = 0;

#[repr(C)]
pub struct mz_stream {
    pub next_in: *const u8,
    pub avail_in: libc::c_uint,
    pub total_in: libc::c_ulong,

    pub next_out: *mut u8,
    pub avail_out: libc::c_uint,
    pub total_out: libc::c_ulong,

    pub msg: *const libc::c_char,
    pub state: *mut mz_internal_state,

    pub zalloc: Option<mz_alloc_func>,
    pub zfree: Option<mz_free_func>,
    pub opaque: *mut libc::c_void,

    pub data_type: libc::c_int,
    pub adler: libc::c_ulong,
    pub reserved: libc::c_ulong,
}

pub enum mz_internal_state {}

pub type mz_alloc_func = extern fn(*mut libc::c_void,
                                   libc::size_t,
                                   libc::size_t) -> *mut libc::c_void;
pub type mz_free_func = extern fn(*mut libc::c_void, *mut libc::c_void);

#[link(name = "miniz", kind = "static")]
extern {
    pub fn mz_deflateInit2(stream: *mut mz_stream,
                           level: libc::c_int,
                           method: libc::c_int,
                           window_bits: libc::c_int,
                           mem_level: libc::c_int,
                           strategy: libc::c_int) -> libc::c_int;
    pub fn mz_deflate(stream: *mut mz_stream, flush: libc::c_int) -> libc::c_int;
    pub fn mz_deflateEnd(stream: *mut mz_stream) -> libc::c_int;

    pub fn mz_inflateInit2(stream: *mut mz_stream,
                           window_bits: libc::c_int) -> libc::c_int;
    pub fn mz_inflate(stream: *mut mz_stream, flush: libc::c_int) -> libc::c_int;
    pub fn mz_inflateEnd(stream: *mut mz_stream) -> libc::c_int;

    pub fn mz_crc32(crc: libc::c_ulong, ptr: *const u8,
                    len: libc::size_t) -> libc::c_ulong;
}
<commit_msg>Prepare for s/static/const<commit_after>#![allow(warnings)]

use libc;

pub const MZ_NO_FLUSH: libc::c_int = 0;
pub const MZ_SYNC_FLUSH: libc::c_int = 2;
pub const MZ_FINISH: libc::c_int = 4;

pub const MZ_OK: libc::c_int = 0;
pub const MZ_STREAM_END: libc::c_int = 1;
pub const MZ_NEED_DICT: libc::c_int = 2;
pub const MZ_ERRNO: libc::c_int = -1;
pub const MZ_STREAM_ERROR: libc::c_int = -2;
pub const MZ_DATA_ERROR: libc::c_int = -3;
pub const MZ_MEM_ERROR: libc::c_int = -4;
pub const MZ_BUF_ERROR: libc::c_int = -5;
pub const MZ_VERSION_ERROR: libc::c_int = -6;
pub const MZ_PARAM_ERROR: libc::c_int = -10000;

pub const MZ_DEFLATED: libc::c_int = 8;
pub const MZ_DEFAULT_WINDOW_BITS: libc::c_int = 15;
pub const MZ_DEFAULT_STRATEGY: libc::c_int = 0;

#[repr(C)]
pub struct mz_stream {
    pub next_in: *const u8,
    pub avail_in: libc::c_uint,
    pub total_in: libc::c_ulong,

    pub next_out: *mut u8,
    pub avail_out: libc::c_uint,
    pub total_out: libc::c_ulong,

    pub msg: *const libc::c_char,
    pub state: *mut mz_internal_state,

    pub zalloc: Option<mz_alloc_func>,
    pub zfree: Option<mz_free_func>,
    pub opaque: *mut libc::c_void,

    pub data_type: libc::c_int,
    pub adler: libc::c_ulong,
    pub reserved: libc::c_ulong,
}

pub enum mz_internal_state {}

pub type mz_alloc_func = extern fn(*mut libc::c_void,
                                   libc::size_t,
                                   libc::size_t) -> *mut libc::c_void;
pub type mz_free_func = extern fn(*mut libc::c_void, *mut libc::c_void);

#[link(name = "miniz", kind = "static")]
extern {
    pub fn mz_deflateInit2(stream: *mut mz_stream,
                           level: libc::c_int,
                           method: libc::c_int,
                           window_bits: libc::c_int,
                           mem_level: libc::c_int,
                           strategy: libc::c_int) -> libc::c_int;
    pub fn mz_deflate(stream: *mut mz_stream, flush: libc::c_int) -> libc::c_int;
    pub fn mz_deflateEnd(stream: *mut mz_stream) -> libc::c_int;

    pub fn mz_inflateInit2(stream: *mut mz_stream,
                           window_bits: libc::c_int) -> libc::c_int;
    pub fn mz_inflate(stream: *mut mz_stream, flush: libc::c_int) -> libc::c_int;
    pub fn mz_inflateEnd(stream: *mut mz_stream) -> libc::c_int;

    pub fn mz_crc32(crc: libc::c_ulong, ptr: *const u8,
                    len: libc::size_t) -> libc::c_ulong;
}
<|endoftext|>