<commit_before>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! # **glib**, **gobject** and **gio** bindings for Rust
//!
//! This library contains
//!
//! - bindings to some essential GLib, GObject, GIO types and APIs,
//!
//! - common building blocks used in both handmade and machine generated
//! bindings to GTK+ and other GLib-based libraries.
//!
//! It is the foundation for higher level libraries with uniform Rusty (safe and
//! strongly typed) APIs. It avoids exposing GLib-specific data types where
//! possible and is not meant to provide comprehensive GLib bindings, which
//! would often amount to duplicating the Rust Standard Library or other utility
//! crates.
//!
//! The library is a work in progress: expect missing functionality and breaking
//! changes.
//!
//! # Dynamic typing
//!
//! Most types in the GLib family have type identifiers
//! ([`Type`](types/enum.Type.html)). Their corresponding Rust types implement
//! the [`StaticType`](types/trait.StaticType.html) trait.
//!
//! Dynamically typed [`Value`](value/index.html) can carry values of any `T:
//! StaticType`.
//!
//! [`Variant`](variant/index.html) can carry values of `T: StaticVariantType`.
//!
//! # Errors
//!
//! Errors are represented by [`Error`](error/struct.Error.html), which can
//! carry values from various [error
//! domains](error/trait.ErrorDomain.html#implementors) (such as
//! [`FileError`](enum.FileError.html)).
//!
//! # Objects
//!
//! Each class and interface has a corresponding smart pointer struct
//! representing an instance of that type (e.g. `Object` for `GObject`,
//! `gtk::Widget` for `GtkWidget`). They are reference counted and feature
//! interior mutability similarly to Rust's `Rc<RefCell<T>>` idiom.
//! Consequently, cloning objects is cheap and their methods never require
//! mutable borrows. Two smart pointers are equal iff they point to the same
//! object.
//!
//! The root of the object hierarchy is [`Object`](object/struct.Object.html).
//! Inheritance and subtyping is denoted with the [`IsA`](object/trait.IsA.html)
//! marker trait. The [`Cast`](object/trait.Cast.html) trait enables upcasting
//! and downcasting.
//!
//! Interfaces and non-leaf classes also have corresponding traits (e.g.
//! `ObjectExt` and `gtk::WidgetExt`), which are blanketly implemented for all
//! their subtypes.
//!
//! # Under the hood
//!
//! GLib-based libraries largely operate on pointers to various boxed or
//! reference counted structures so the bindings have to implement corresponding
//! smart pointers (wrappers), which encapsulate resource management and safety
//! checks. Such wrappers are defined via the
//! [`glib_wrapper!`](macro.glib_wrapper!.html) macro, which uses abstractions
//! defined in the [`wrapper`](wrapper/index.html), [`boxed`](boxed/index.html),
//! [`shared`](shared/index.html) and [`object`](object/index.html) modules.
//!
//! The [`translate`](translate/index.html) module defines and partly implements
//! conversions between high level Rust types (including the aforementioned
//! wrappers) and their FFI counterparts.

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate glib_sys as ffi;
extern crate gobject_sys as gobject_ffi;

use std::ffi::CStr;
pub use bytes::Bytes;
pub use closure::Closure;
pub use error::{Error, BoolError};
pub use file_error::FileError;
pub use object::{
    Cast,
    IsA,
    Object,
    ObjectExt,
};
pub use signal::{
    signal_handler_block,
    signal_handler_unblock,
    signal_stop_emission,
    signal_stop_emission_by_name
};
pub use source::{
    CallbackGuard,
    Continue,
    idle_add,
    timeout_add,
    timeout_add_seconds,
    child_watch_add,
    source_remove,
    Id as SourceId,
};

#[cfg(unix)]
pub use source::{
    unix_signal_add,
};

pub use types::{
    StaticType,
    Type,
};
pub use value::{
    ToValue,
    TypedValue,
    Value,
};
pub use variant::{
    StaticVariantType,
    ToVariant,
    Variant,
};
pub use variant_type::{
    VariantTy,
    VariantType,
};
pub use time_val::{
    TimeVal,
    get_current_time,
};
pub use enums::{
    UserDirectory,
};

lazy_static! {
  pub static ref KEY_FILE_DESKTOP_GROUP: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_GROUP).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_ACTIONS: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_ACTIONS).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_CATEGORIES: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_CATEGORIES).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_COMMENT: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_COMMENT).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_EXEC: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_EXEC).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_FULLNAME: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_FULLNAME).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_GENERIC_NAME: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_HIDDEN: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_HIDDEN).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_ICON: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_ICON).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_KEYWORDS: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_KEYWORDS).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_MIME_TYPE: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_MIME_TYPE).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_NAME: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_NAME).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_NO_DISPLAY: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_PATH: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_PATH).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_TERMINAL: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_TERMINAL).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_TRY_EXEC: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_TRY_EXEC).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_TYPE: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_TYPE).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_URL: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_URL).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_VERSION: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_VERSION).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_TYPE_APPLICATION: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_TYPE_APPLICATION).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_TYPE_DIRECTORY: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_TYPE_DIRECTORY).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_TYPE_LINK: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_TYPE_LINK).to_str().unwrap()};
}

#[macro_use]
pub mod wrapper;
#[macro_use]
pub mod boxed;
#[macro_use]
pub mod shared;
#[macro_use]
pub mod object;

pub use auto::*;
pub use auto::functions::*;
mod auto;

mod bytes;
pub mod closure;
pub mod error;
mod enums;
mod file_error;
mod key_file;
pub mod prelude;
pub mod signal;
pub mod source;
mod time_val;
pub mod translate;
pub mod types;
mod utils;
pub use utils::*;
pub mod value;
pub mod variant;
mod variant_type;
mod main_context;
<commit_msg>Export everything from source::* at the crate level<commit_after>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! # **glib**, **gobject** and **gio** bindings for Rust
//!
//! This library contains
//!
//! - bindings to some essential GLib, GObject, GIO types and APIs,
//!
//! - common building blocks used in both handmade and machine generated
//! bindings to GTK+ and other GLib-based libraries.
//!
//! It is the foundation for higher level libraries with uniform Rusty (safe and
//! strongly typed) APIs. It avoids exposing GLib-specific data types where
//! possible and is not meant to provide comprehensive GLib bindings, which
//! would often amount to duplicating the Rust Standard Library or other utility
//! crates.
//!
//! The library is a work in progress: expect missing functionality and breaking
//! changes.
//!
//! # Dynamic typing
//!
//! Most types in the GLib family have type identifiers
//! ([`Type`](types/enum.Type.html)). Their corresponding Rust types implement
//! the [`StaticType`](types/trait.StaticType.html) trait.
//!
//! Dynamically typed [`Value`](value/index.html) can carry values of any `T:
//! StaticType`.
//!
//! [`Variant`](variant/index.html) can carry values of `T: StaticVariantType`.
//!
//! # Errors
//!
//! Errors are represented by [`Error`](error/struct.Error.html), which can
//! carry values from various [error
//! domains](error/trait.ErrorDomain.html#implementors) (such as
//! [`FileError`](enum.FileError.html)).
//!
//! # Objects
//!
//! Each class and interface has a corresponding smart pointer struct
//! representing an instance of that type (e.g. `Object` for `GObject`,
//! `gtk::Widget` for `GtkWidget`). They are reference counted and feature
//! interior mutability similarly to Rust's `Rc<RefCell<T>>` idiom.
//! Consequently, cloning objects is cheap and their methods never require
//! mutable borrows. Two smart pointers are equal iff they point to the same
//! object.
//!
//! The root of the object hierarchy is [`Object`](object/struct.Object.html).
//! Inheritance and subtyping is denoted with the [`IsA`](object/trait.IsA.html)
//! marker trait. The [`Cast`](object/trait.Cast.html) trait enables upcasting
//! and downcasting.
//!
//! Interfaces and non-leaf classes also have corresponding traits (e.g.
//! `ObjectExt` and `gtk::WidgetExt`), which are blanketly implemented for all
//! their subtypes.
//!
//! # Under the hood
//!
//! GLib-based libraries largely operate on pointers to various boxed or
//! reference counted structures so the bindings have to implement corresponding
//! smart pointers (wrappers), which encapsulate resource management and safety
//! checks. Such wrappers are defined via the
//! [`glib_wrapper!`](macro.glib_wrapper!.html) macro, which uses abstractions
//! defined in the [`wrapper`](wrapper/index.html), [`boxed`](boxed/index.html),
//! [`shared`](shared/index.html) and [`object`](object/index.html) modules.
//!
//! The [`translate`](translate/index.html) module defines and partly implements
//! conversions between high level Rust types (including the aforementioned
//! wrappers) and their FFI counterparts.

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate glib_sys as ffi;
extern crate gobject_sys as gobject_ffi;

use std::ffi::CStr;
pub use bytes::Bytes;
pub use closure::Closure;
pub use error::{Error, BoolError};
pub use file_error::FileError;
pub use object::{
    Cast,
    IsA,
    Object,
    ObjectExt,
};
pub use signal::{
    signal_handler_block,
    signal_handler_unblock,
    signal_stop_emission,
    signal_stop_emission_by_name
};

pub use types::{
    StaticType,
    Type,
};
pub use value::{
    ToValue,
    TypedValue,
    Value,
};
pub use variant::{
    StaticVariantType,
    ToVariant,
    Variant,
};
pub use variant_type::{
    VariantTy,
    VariantType,
};
pub use time_val::{
    TimeVal,
    get_current_time,
};
pub use enums::{
    UserDirectory,
};

lazy_static! {
  pub static ref KEY_FILE_DESKTOP_GROUP: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_GROUP).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_ACTIONS: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_ACTIONS).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_CATEGORIES: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_CATEGORIES).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_COMMENT: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_COMMENT).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_EXEC: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_EXEC).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_FULLNAME: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_FULLNAME).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_GENERIC_NAME: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_HIDDEN: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_HIDDEN).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_ICON: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_ICON).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_KEYWORDS: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_KEYWORDS).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_MIME_TYPE: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_MIME_TYPE).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_NAME: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_NAME).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_NO_DISPLAY: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_PATH: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_PATH).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_TERMINAL: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_TERMINAL).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_TRY_EXEC: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_TRY_EXEC).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_TYPE: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_TYPE).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_URL: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_URL).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_KEY_VERSION: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_VERSION).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_TYPE_APPLICATION: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_TYPE_APPLICATION).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_TYPE_DIRECTORY: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_TYPE_DIRECTORY).to_str().unwrap()};
  pub static ref KEY_FILE_DESKTOP_TYPE_LINK: &'static str = unsafe{CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_TYPE_LINK).to_str().unwrap()};
}

#[macro_use]
pub mod wrapper;
#[macro_use]
pub mod boxed;
#[macro_use]
pub mod shared;
#[macro_use]
pub mod object;

pub use auto::*;
pub use auto::functions::*;
mod auto;

mod bytes;
pub mod closure;
pub mod error;
mod enums;
mod file_error;
mod key_file;
pub mod prelude;
pub mod signal;
pub mod source;
pub use source::*;
mod time_val;
pub mod translate;
pub mod types;
mod utils;
pub use utils::*;
pub mod value;
pub mod variant;
mod variant_type;
mod main_context;
<|endoftext|>


<commit_before>extern crate rand;

use rand::{Rand, Rng};
use rand::Closed01 as RandClosed01;

/// Encapsulates a floating point number in the range [0, 1] including both endpoints.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Closed01<F>(F);

impl Closed01<f32> {
    #[inline(always)]
    pub fn new(f: f32) -> Closed01<f32> {
        assert!(f >= 0.0 && f <= 1.0);
        Closed01(f)
    }

    #[inline(always)]
    pub fn zero() -> Closed01<f32> {
        Closed01(0.0)
    }

    #[inline(always)]
    pub fn middle() -> Closed01<f32> {
        Closed01(0.5)
    }

    #[inline(always)]
    pub fn one() -> Closed01<f32> {
        Closed01(1.0)
    }

    #[inline(always)]
    /// Returns the smaller of the two.
    pub fn min(self, other: Closed01<f32>) -> Closed01<f32> {
        if self.0 <= other.0 {
            self
        } else {
            other
        }
    }

    #[inline(always)]
    /// Returns the greater of the two.
    pub fn max(self, other: Closed01<f32>) -> Closed01<f32> {
        if self.0 >= other.0 {
            self
        } else {
            other
        }
    }

    #[inline(always)]
    /// Returns the distance between the two numbers.
    pub fn distance(self, other: Closed01<f32>) -> Closed01<f32> {
        let d = (self.0 - other.0).abs();
        debug_assert!(d >= 0.0 && d <= 1.0);
        Closed01(d)
    }

    #[inline(always)]
    pub fn get(self) -> f32 {
        debug_assert!(self.0 >= 0.0 && self.0 <= 1.0);
        self.0
    }

    #[inline(always)]
    /// The average of two values.
    pub fn avg(a: Closed01<f32>, b: Closed01<f32>) -> Closed01<f32> {
        let avg = (a.get() + b.get()) / 2.0;
        debug_assert!(avg >= 0.0 && avg <= 1.0);
        Closed01(avg)
    }

    #[inline(always)]
    /// Saturating add
    pub fn saturating_add(self, other: Closed01<f32>) -> Closed01<f32> {
        let mut sum = self.0 + other.0;
        if sum > 1.0 {
            sum = 1.0;
        }
        debug_assert!(sum >= 0.0 && sum <= 1.0);
        Closed01(sum)
    }

    #[inline(always)]
    /// Saturating add
    pub fn saturating_sub(self, other: Closed01<f32>) -> Closed01<f32> {
        let mut sub = self.0 - other.0;
        if sub < 0.0 {
            sub = 0.0;
        }
        debug_assert!(sub >= 0.0 && sub <= 1.0);
        Closed01(sub)
    }

    #[inline(always)]
    /// Multiplies both numbers.
    pub fn mul(&self, scalar: Closed01<f32>) -> Closed01<f32> {
        let s = self.get() * scalar.get();
        debug_assert!(s >= 0.0 && s <= 1.0);
        Closed01(s)
    }
}

impl Into<f32> for Closed01<f32> {
    fn into(self) -> f32 {
        self.get()
    }
}

impl Rand for Closed01<f32> {
    fn rand<R: Rng>(rng: &mut R) -> Closed01<f32> {
        Closed01::new(RandClosed01::<f32>::rand(rng).0)
    }
}

#[test]
fn test_into() {
    assert_eq!(0.5f32, Closed01::new(0.5).into());
}

#[test]
fn test_minmax() {
    let a = Closed01::new(0.4);
    let b = Closed01::new(0.5);
    assert_eq!(a, a.min(b));
    assert_eq!(a, b.min(a));
    assert_eq!(b, a.max(b));
    assert_eq!(b, b.max(a));
}
<commit_msg>Add tests for saturation<commit_after>extern crate rand;

use rand::{Rand, Rng};
use rand::Closed01 as RandClosed01;

/// Encapsulates a floating point number in the range [0, 1] including both endpoints.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Closed01<F>(F);

impl Closed01<f32> {
    #[inline(always)]
    pub fn new(f: f32) -> Closed01<f32> {
        assert!(f >= 0.0 && f <= 1.0);
        Closed01(f)
    }

    #[inline(always)]
    pub fn zero() -> Closed01<f32> {
        Closed01(0.0)
    }

    #[inline(always)]
    pub fn middle() -> Closed01<f32> {
        Closed01(0.5)
    }

    #[inline(always)]
    pub fn one() -> Closed01<f32> {
        Closed01(1.0)
    }

    #[inline(always)]
    /// Returns the smaller of the two.
    pub fn min(self, other: Closed01<f32>) -> Closed01<f32> {
        if self.0 <= other.0 {
            self
        } else {
            other
        }
    }

    #[inline(always)]
    /// Returns the greater of the two.
    pub fn max(self, other: Closed01<f32>) -> Closed01<f32> {
        if self.0 >= other.0 {
            self
        } else {
            other
        }
    }

    #[inline(always)]
    /// Returns the distance between the two numbers.
    pub fn distance(self, other: Closed01<f32>) -> Closed01<f32> {
        let d = (self.0 - other.0).abs();
        debug_assert!(d >= 0.0 && d <= 1.0);
        Closed01(d)
    }

    #[inline(always)]
    pub fn get(self) -> f32 {
        debug_assert!(self.0 >= 0.0 && self.0 <= 1.0);
        self.0
    }

    #[inline(always)]
    /// The average of two values.
    pub fn avg(a: Closed01<f32>, b: Closed01<f32>) -> Closed01<f32> {
        let avg = (a.get() + b.get()) / 2.0;
        debug_assert!(avg >= 0.0 && avg <= 1.0);
        Closed01(avg)
    }

    #[inline(always)]
    /// Saturating add
    pub fn saturating_add(self, other: Closed01<f32>) -> Closed01<f32> {
        let mut sum = self.0 + other.0;
        if sum > 1.0 {
            sum = 1.0;
        }
        debug_assert!(sum >= 0.0 && sum <= 1.0);
        Closed01(sum)
    }

    #[inline(always)]
    /// Saturating sub
    pub fn saturating_sub(self, other: Closed01<f32>) -> Closed01<f32> {
        let mut sub = self.0 - other.0;
        if sub < 0.0 {
            sub = 0.0;
        }
        debug_assert!(sub >= 0.0 && sub <= 1.0);
        Closed01(sub)
    }

    #[inline(always)]
    /// Multiplies both numbers.
    pub fn mul(&self, scalar: Closed01<f32>) -> Closed01<f32> {
        let s = self.get() * scalar.get();
        debug_assert!(s >= 0.0 && s <= 1.0);
        Closed01(s)
    }
}

impl Into<f32> for Closed01<f32> {
    fn into(self) -> f32 {
        self.get()
    }
}

impl Rand for Closed01<f32> {
    fn rand<R: Rng>(rng: &mut R) -> Closed01<f32> {
        Closed01::new(RandClosed01::<f32>::rand(rng).0)
    }
}

#[test]
fn test_into() {
    assert_eq!(0.5f32, Closed01::new(0.5).into());
}

#[test]
fn test_minmax() {
    let a = Closed01::new(0.4);
    let b = Closed01::new(0.5);
    assert_eq!(a, a.min(b));
    assert_eq!(a, b.min(a));
    assert_eq!(b, a.max(b));
    assert_eq!(b, b.max(a));
}

#[test]
fn test_saturation() {
    let a = Closed01::new(0.4);
    let b = Closed01::new(0.5);
    let c = Closed01::new(0.6);

    assert_eq!(0.9, a.saturating_add(b).get());
    assert_eq!(1.0, a.saturating_add(c).get());
    assert_eq!(1.0, b.saturating_add(c).get());

    assert_eq!(0.0, a.saturating_sub(b).get());
    assert_eq!(0.0, a.saturating_sub(c).get());
    assert_eq!(0.0, b.saturating_sub(c).get());

    assert!((c.saturating_sub(b).get() - 0.1).abs() < 0.001);
    assert!((c.saturating_sub(a).get() - 0.2).abs() < 0.001);
}
<|endoftext|>


<commit_before>#![feature(never_type)]

pub enum CoResult<YieldT, CoroT, ReturnT> {
    Yield(YieldT, CoroT),
    Return(ReturnT)
}

trait Coroutine<Input> : Sized {
    type Yield;
    type Return;

    fn next(self, i: Input) -> CoResult<Self::Yield, Self, Self::Return>;
}

macro_rules! each {
    ($iter:expr => $elem:ident $loop_body:block then with $then:ident $then_body:block else $else_body:block) => {{
        let mut iter_ = $iter;
        let fin;
        'outer: loop {
            loop {
                #[allow(unused_assignments)]
                match iter_.next(()) {
                    CoResult::Yield($elem, tail) => {
                        iter_ = tail;
                        $loop_body;
                    },
                    CoResult::Return($then) => {
                        fin = $then_body;
                        break 'outer;
                    }
                };
            }
            fin = $else_body;
            break;
        }
        fin
    }};

    ($iter:expr => $elem:ident $loop_body:block then $then_body:block else $else_body:block) => {{
        let mut iter_ = $iter;
        let fin;
        'outer: loop {
            loop {
                #[allow(unused_assignments)]
                match iter_.next(()) {
                    CoResult::Yield($elem, tail) => {
                        iter_ = tail;
                        $loop_body;
                    },
                    CoResult::Return(_) => {
                        fin = $then_body;
                        break 'outer;
                    }
                };
            }
            fin = $else_body;
            break;
        }
        fin
    }};

    ($iter:expr => $elem:ident $loop_body:block then with $then:ident $then_body:block) => {{
        let mut iter_ = $iter;
        let fin;
        'outer: loop {
            #[allow(unused_assignments)]
            match iter_.next(()) {
                CoResult::Yield($elem, tail) => {
                    iter_ = tail;
                    $loop_body;
                },
                CoResult::Return($then) => {
                    fin = $then_body;
                    break 'outer;
                }
            };
        }
        fin
    }};

    ($iter:expr => $elem:ident $loop_body:block then $then_body:block) => {{
        let mut iter_ = $iter;
        let fin;
        'outer: loop {
            #[allow(unused_assignments)]
            match iter_.next(()) {
                CoResult::Yield($elem, tail) => {
                    iter_ = tail;
                    $loop_body;
                },
                CoResult::Return(_) => {
                    fin = $then_body;
                    break 'outer;
                }
            };
        }
        fin
    }};

    ($iter:expr => $elem:ident $loop_body:block else $else_body:block) => {{
        let mut iter_ = $iter;
        let fin;
        'outer: loop {
            loop {
                #[allow(unused_assignments, unreachable_patterns, unreachable_code)]
                match iter_.next(()) {
                    CoResult::Yield($elem, tail) => {
                        iter_ = tail;
                        $loop_body;
                    },
                    CoResult::Return(ret) => {
                        fin = ret;
                        break 'outer;
                    }
                };
            }
            fin = $else_body;
            break;
        }
        fin
    }};

    ($iter:expr => $elem:ident $loop_body:block) => {{
        let mut iter_ = $iter;
        let fin;
        loop {
            #[allow(unused_assignments)]
            match iter_.next(()) {
                CoResult::Yield($elem, tail) => {
                    iter_ = tail;
                    $loop_body;
                },
                CoResult::Return(ret) => {
                    fin = ret;
                    break;
                }
            };
        }
        fin
    }};
}

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

    struct Counter<T>{
        i: T,
        lim: T
    }

    impl Coroutine<()> for Counter<i64> {
        type Yield = i64;
        type Return = &'static str;

        fn next(self, _: ()) -> CoResult<Self::Yield, Self, Self::Return> {
            if self.i < self.lim {
                CoResult::Yield(self.i, Counter{i: self.i + 1, lim: self.lim})
            } else {
                CoResult::Return("I'm done!")
            }
        }
    }

    struct InfiniteCounter<T>{
        i: T
    }

    impl Coroutine<()> for InfiniteCounter<i64> {
        type Yield = i64;
        type Return = !;

        fn next(self, _: ()) -> CoResult<Self::Yield, Self, Self::Return> {
            CoResult::Yield(self.i, InfiniteCounter{i: self.i + 1})
        }
    }

    #[test]
    fn full_each() {
        let bart = Counter::<i64>{i: 3, lim: 10};
        let mut cnt = 3;
        let large_num = 1000;
        let message = each!(bart => i {
            assert_eq!(i, cnt);
            cnt += 1;
            if large_num < 5 { break; }
        } then with msg {
            String::from(msg) + " Yayy!"
        } else {
            String::from("I got broken!")
        });
        assert_eq!(cnt, 10);
        assert_eq!(message, String::from("I'm done! Yayy!"));
    }

    #[test]
    fn full_each_with_break() {
        let bart = Counter::<i64>{i: 3, lim: 10};
        let mut cnt = 3;
        let message = each!(bart => i {
            assert_eq!(i, cnt);
            cnt += 1;
            break;
        } then with msg {
            msg
        } else {
            "I got broken!"
        });
        assert_eq!(cnt, 4);
        assert_eq!(message, "I got broken!");
    }

    #[test]
    fn each_ignore_return() {
        let bart = Counter::<i64>{i: 3, lim: 10};
        let mut cnt = 3;
        let large_number = 1000;
        let message = each!(bart => i {
            assert_eq!(i, cnt);
            cnt += 1;
            if large_number < 5 { break; }
        } then {
            "At last!"
        } else {
            "I got broken!"
        });
        assert_eq!(cnt, 10);
        assert_eq!(message, "At last!");
    }

    #[test]
    fn each_break_no_then() {
        let bart = InfiniteCounter::<i64>{i: 3};
        let mut cnt = 3;
        let message = each!(bart => i {
            assert_eq!(i, cnt);
            cnt += 1;
            if cnt >= 20 { break; }
        } else {
            "I got broken!"
        });
        assert_eq!(cnt, 20);
        assert_eq!(message, "I got broken!");
    }

    #[test]
    fn each_no_else() {
        let bart = Counter::<i64>{i: 3, lim: 10};
        let mut cnt = 3;
        let message = each!(bart => i {
            assert_eq!(i, cnt);
            cnt += 1;
        } then {
            "At last!"
        });
        assert_eq!(cnt, 10);
        assert_eq!(message, "At last!");
    }

    #[test]
    fn each_no_then_else() {
        let bart = Counter::<i64>{i: 3, lim: 10};
        let mut cnt = 3;
        let message = each!(bart => i {
            assert_eq!(i, cnt);
            cnt += 1;
        });
        assert_eq!(cnt, 10);
        assert_eq!(message, "I'm done!");
    }

    #[test]
    fn each_no_then() {
        let bart = Counter::<i64>{i: 3, lim: 10};
        let mut cnt = 3;
        #[allow(unreachable_code)]
        let message = each!(bart => i {
            assert_eq!(i, cnt);
            cnt += 1;
        } else {
            "bogus"
        });
        assert_eq!(cnt, 10);
        assert_eq!(message, "I'm done!");
    }
}
<commit_msg>Allow for capturing patterns in each!<commit_after>#![feature(never_type)]

pub enum CoResult<YieldT, CoroT, ReturnT> {
    Yield(YieldT, CoroT),
    Return(ReturnT)
}

trait Coroutine<Input> : Sized {
    type Yield;
    type Return;

    fn next(self, i: Input) -> CoResult<Self::Yield, Self, Self::Return>;
}

macro_rules! each {
    ($iter:expr => $elem:pat in $loop_body:block then with $then:pat in $then_body:block otherwise $else_body:block) => {{
        let mut iter_ = $iter;
        let fin;
        'outer: loop {
            loop {
                #[allow(unused_assignments)]
                match iter_.next(()) {
                    CoResult::Yield($elem, tail) => {
                        iter_ = tail;
                        $loop_body;
                    },
                    CoResult::Return($then) => {
                        fin = $then_body;
                        break 'outer;
                    }
                };
            }
            fin = $else_body;
            break;
        }
        fin
    }};

    ($iter:expr => $elem:pat in $loop_body:block then $then_body:block otherwise $else_body:block) => {{
        let mut iter_ = $iter;
        let fin;
        'outer: loop {
            loop {
                #[allow(unused_assignments)]
                match iter_.next(()) {
                    CoResult::Yield($elem, tail) => {
                        iter_ = tail;
                        $loop_body;
                    },
                    CoResult::Return(_) => {
                        fin = $then_body;
                        break 'outer;
                    }
                };
            }
            fin = $else_body;
            break;
        }
        fin
    }};

    ($iter:expr => $elem:pat in $loop_body:block then with $then:pat in $then_body:block) => {{
        let mut iter_ = $iter;
        let fin;
        'outer: loop {
            #[allow(unused_assignments)]
            match iter_.next(()) {
                CoResult::Yield($elem, tail) => {
                    iter_ = tail;
                    $loop_body;
                },
                CoResult::Return($then) => {
                    fin = $then_body;
                    break 'outer;
                }
            };
        }
        fin
    }};

    ($iter:expr => $elem:pat in $loop_body:block then $then_body:block) => {{
        let mut iter_ = $iter;
        let fin;
        'outer: loop {
            #[allow(unused_assignments)]
            match iter_.next(()) {
                CoResult::Yield($elem, tail) => {
                    iter_ = tail;
                    $loop_body;
                },
                CoResult::Return(_) => {
                    fin = $then_body;
                    break 'outer;
                }
            };
        }
        fin
    }};

    ($iter:expr => $elem:pat in $loop_body:block otherwise $else_body:block) => {{
        let mut iter_ = $iter;
        let fin;
        'outer: loop {
            loop {
                #[allow(unused_assignments, unreachable_patterns, unreachable_code)]
                match iter_.next(()) {
                    CoResult::Yield($elem, tail) => {
                        iter_ = tail;
                        $loop_body;
                    },
                    CoResult::Return(ret) => {
                        fin = ret;
                        break 'outer;
                    }
                };
            }
            fin = $else_body;
            break;
        }
        fin
    }};

    ($iter:expr => $elem:pat in $loop_body:block) => {{
        let mut iter_ = $iter;
        let fin;
        loop {
            #[allow(unused_assignments)]
            match iter_.next(()) {
                CoResult::Yield($elem, tail) => {
                    iter_ = tail;
                    $loop_body;
                },
                CoResult::Return(ret) => {
                    fin = ret;
                    break;
                }
            };
        }
        fin
    }};
}

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

    struct Counter<T>{
        i: T,
        lim: T
    }

    impl Coroutine<()> for Counter<i64> {
        type Yield = i64;
        type Return = &'static str;

        fn next(self, _: ()) -> CoResult<Self::Yield, Self, Self::Return> {
            if self.i < self.lim {
                CoResult::Yield(self.i, Counter{i: self.i + 1, lim: self.lim})
            } else {
                CoResult::Return("I'm done!")
            }
        }
    }

    struct InfiniteCounter<T>{
        i: T
    }

    impl Coroutine<()> for InfiniteCounter<i64> {
        type Yield = i64;
        type Return = !;

        fn next(self, _: ()) -> CoResult<Self::Yield, Self, Self::Return> {
            CoResult::Yield(self.i, InfiniteCounter{i: self.i + 1})
        }
    }

    #[test]
    fn full_each() {
        let bart = Counter::<i64>{i: 3, lim: 10};
        let mut cnt = 3;
        let large_num = 1000;
        let message = each!(bart => i in {
            assert_eq!(i, cnt);
            cnt += 1;
            if large_num < 5 { break; }
        } then with msg in {
            String::from(msg) + " Yayy!"
        } otherwise {
            String::from("I got broken!")
        });
        assert_eq!(cnt, 10);
        assert_eq!(message, String::from("I'm done! Yayy!"));
    }

    #[test]
    fn full_each_with_break() {
        let bart = Counter::<i64>{i: 3, lim: 10};
        let mut cnt = 3;
        let message = each!(bart => i in {
            assert_eq!(i, cnt);
            cnt += 1;
            break;
        } then with msg in {
            msg
        } otherwise {
            "I got broken!"
        });
        assert_eq!(cnt, 4);
        assert_eq!(message, "I got broken!");
    }

    #[test]
    fn each_ignore_return() {
        let bart = Counter::<i64>{i: 3, lim: 10};
        let mut cnt = 3;
        let large_number = 1000;
        let message = each!(bart => i in {
            assert_eq!(i, cnt);
            cnt += 1;
            if large_number < 5 { break; }
        } then {
            "At last!"
        } otherwise {
            "I got broken!"
        });
        assert_eq!(cnt, 10);
        assert_eq!(message, "At last!");
    }

    #[test]
    fn each_break_no_then() {
        let bart = InfiniteCounter::<i64>{i: 3};
        let mut cnt = 3;
        let message = each!(bart => i in {
            assert_eq!(i, cnt);
            cnt += 1;
            if cnt >= 20 { break; }
        } otherwise {
            "I got broken!"
        });
        assert_eq!(cnt, 20);
        assert_eq!(message, "I got broken!");
    }

    #[test]
    fn each_no_else() {
        let bart = Counter::<i64>{i: 3, lim: 10};
        let mut cnt = 3;
        let message = each!(bart => i in {
            assert_eq!(i, cnt);
            cnt += 1;
        } then {
            "At last!"
        });
        assert_eq!(cnt, 10);
        assert_eq!(message, "At last!");
    }

    #[test]
    fn each_no_then_else() {
        let bart = Counter::<i64>{i: 3, lim: 10};
        let mut cnt = 3;
        let message = each!(bart => i in {
            assert_eq!(i, cnt);
            cnt += 1;
        });
        assert_eq!(cnt, 10);
        assert_eq!(message, "I'm done!");
    }

    #[test]
    fn each_no_then() {
        let bart = Counter::<i64>{i: 3, lim: 10};
        let mut cnt = 3;
        #[allow(unreachable_code)]
        let message = each!(bart => i in {
            assert_eq!(i, cnt);
            cnt += 1;
        } otherwise {
            "bogus"
        });
        assert_eq!(cnt, 10);
        assert_eq!(message, "I'm done!");
    }

    #[test]
    fn each_capture_patterns() {

        struct Blabber<T>{
            i: T,
            lim: T
        }

        impl Coroutine<()> for Blabber<i64> {
            type Yield = (i64, i64);
            type Return = (&'static str, i64);

            fn next(self, _: ()) -> CoResult<Self::Yield, Self, Self::Return> {
                if self.i < self.lim {
                    CoResult::Yield((self.i, self.lim), Blabber{i: self.i + 1, lim: self.lim})
                } else {
                    CoResult::Return(("I'm done!", self.lim))
                }
            }
        }

        let bart = Blabber::<i64>{i: 3, lim: 10};
        let mut cnt = 3;
        let large_num = 1000;
        let (message, lim) = each!(bart => (i, lim) in {
            assert_eq!(i, cnt);
            assert_eq!(lim, 10);
            cnt += 1;
            if large_num < 5 { break; }
        } then with (msg, lim) in {
            (String::from(msg) + " Yayy!", lim)
        } otherwise {
            (String::from("I got broken!"), -1)
        });
        assert_eq!(cnt, 10);
        assert_eq!(message, String::from("I'm done! Yayy!"));
        assert_eq!(lim, 10);
    }
}
<|endoftext|>


<commit_before>extern crate crossbeam;

use std::borrow::Borrow;
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::Path;
use std::process::{Command, Output, ExitStatus};
use std::thread::JoinHandle;

mod pipe;

pub fn cmd<T: AsRef<OsStr>>(argv: &[T]) -> Expression<'static> {
    let argv_vec = argv.iter().map(|arg| arg.as_ref().to_owned()).collect();
    Expression {
        inner: ExpressionInner::ArgvCommand(argv_vec),
        ioargs: IoArgs::new(),
    }
}

pub fn sh<T: AsRef<OsStr>>(command: T) -> Expression<'static> {
    Expression {
        inner: ExpressionInner::ShCommand(command.as_ref().to_owned()),
        ioargs: IoArgs::new(),
    }
}

pub fn pipe<'a>(left: Expression<'a>, right: Expression<'a>) -> Expression<'a> {
    Expression {
        inner: ExpressionInner::Pipe(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

pub fn then<'a>(left: Expression<'a>, right: Expression<'a>) -> Expression<'a> {
    Expression {
        inner: ExpressionInner::Then(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

pub struct Expression<'a> {
    inner: ExpressionInner<'a>,
    ioargs: IoArgs<'a>,
}

enum ExpressionInner<'a> {
    ArgvCommand(Vec<OsString>),
    ShCommand(OsString),
    Pipe(Box<Expression<'a>>, Box<Expression<'a>>),
    Then(Box<Expression<'a>>, Box<Expression<'a>>),
}

impl<'a> Expression<'a> {
    pub fn run(&self) -> Result<Output, Error> {
        unreachable!();
    }

    pub fn read(&self) -> Result<String, Error> {
        let (handle, reader) = pipe_with_reader_thread();
        let mut context = IoContext::new();
        context.stdout = handle;
        let status = try!(self.exec(context));
        let stdout_vec = try!(reader.join().unwrap());
        if !status.success() {
            return Err(Error::Status(Output {
                status: status,
                stdout: stdout_vec,
                stderr: Vec::new(),
            }));
        }
        let stdout_string = try!(std::str::from_utf8(&stdout_vec))
                                .trim_right_matches('\n')
                                .to_owned();
        Ok(stdout_string)
    }

    fn exec(&self, parent_context: IoContext) -> io::Result<ExitStatus> {
        self.ioargs.with_child_context(parent_context, |context| {
            match self.inner {
                ExpressionInner::ArgvCommand(ref argv) => exec_argv(argv, context),
                ExpressionInner::ShCommand(ref command) => exec_sh(command, context),
                ExpressionInner::Pipe(ref left, ref right) => exec_pipe(left, right, context),
                ExpressionInner::Then(ref left, ref right) => exec_then(left, right, context),
            }
        })
    }

    pub fn stdin(&mut self, arg: InputArg<'a>) -> &mut Self {
        self.ioargs.stdin = arg;
        self
    }

    pub fn stdout(&mut self, arg: OutputArg<'a>) -> &mut Self {
        self.ioargs.stdout = arg;
        self
    }

    pub fn stderr(&mut self, arg: OutputArg<'a>) -> &mut Self {
        self.ioargs.stderr = arg;
        self
    }
}

fn exec_argv(argv: &Vec<OsString>, context: IoContext) -> io::Result<ExitStatus> {
    let mut command = Command::new(&argv[0]);
    command.args(&argv[1..]);
    command.stdin(context.stdin.to_stdio());
    command.stdout(context.stdout.to_stdio());
    command.stderr(context.stderr.to_stdio());
    command.status()
}

fn exec_sh(command: &OsStr, context: IoContext) -> io::Result<ExitStatus> {
    // TODO: What shell should we be using here, really?
    // TODO: Figure out how cmd.exe works on Windows.
    let mut argv = Vec::new();
    argv.push("bash".into());
    argv.push("-c".into());
    argv.push(command.to_owned());
    exec_argv(&argv, context)
}

fn exec_pipe(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let left_context = IoContext {
        stdin: context.stdin,
        stdout: write_pipe,
        stderr: context.stderr.clone(),
    };
    let right_context = IoContext {
        stdin: read_pipe,
        stdout: context.stdout,
        stderr: context.stderr,
    };

    let (left_result, right_result) = crossbeam::scope(|scope| {
        let left_joiner = scope.spawn(|| left.exec(left_context));
        let right_result = right.exec(right_context);
        let left_result = left_joiner.join();
        (left_result, right_result)
    });

    let right_status = try!(right_result);
    let left_status = try!(left_result);
    if !right_status.success() {
        Ok(right_status)
    } else {
        Ok(left_status)
    }
}

fn exec_then(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let status = try!(left.exec(context.clone()));
    if !status.success() {
        Ok(status)
    } else {
        right.exec(context)
    }
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Utf8(std::str::Utf8Error),
    Status(Output),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<std::str::Utf8Error> for Error {
    fn from(err: std::str::Utf8Error) -> Error {
        Error::Utf8(err)
    }
}

// IoArgs store the redirections and other settings associated with an expression. At execution
// time, IoArgs are used to modify an IoContext, which contains the actual pipes that child process
struct IoArgs<'a> {
    stdin: InputArg<'a>,
    stdout: OutputArg<'a>,
    stderr: OutputArg<'a>,
}

impl<'a> IoArgs<'a> {
    fn new() -> IoArgs<'static> {
        IoArgs {
            stdin: InputArg::Inherit,
            stdout: OutputArg::Inherit,
            stderr: OutputArg::Inherit,
        }
    }

    fn with_child_context<F, T>(&self, parent_context: IoContext, inner: F) -> io::Result<T>
        where F: FnOnce(IoContext) -> io::Result<T>
    {
        crossbeam::scope(|scope| {
            let parent_context = parent_context;  // move it into the closure
            let (stdin, maybe_stdin_thread) = try!(self.stdin
                                                       .update_handle(parent_context.stdin, scope));
            let stdout = try!(self.stdout.update_handle(parent_context.stdout));
            let stderr = try!(self.stderr.update_handle(parent_context.stderr));
            let (stdout, stderr) = apply_swaps(stdout, stderr, &self.stdout, &self.stderr);

            let child_context = IoContext {
                stdin: stdin,
                stdout: stdout,
                stderr: stderr,
            };

            let ret = try!(inner(child_context));

            if let Some(thread) = maybe_stdin_thread {
                try!(thread.join());
            }

            Ok(ret)
        })
    }
}

// returns (new_stdout, new_stderr)
fn apply_swaps(stdout_handle: pipe::Handle,
               stderr_handle: pipe::Handle,
               stdout_arg: &OutputArg,
               stderr_arg: &OutputArg)
               -> (pipe::Handle, pipe::Handle) {
    // TODO: These clones are a little excessive.
    let new_stdout = if let &OutputArg::Stderr = stdout_arg {
        stderr_handle.clone()
    } else {
        stdout_handle.clone()
    };
    let new_stderr = if let &OutputArg::Stdout = stderr_arg {
        stdout_handle.clone()
    } else {
        stderr_handle.clone()
    };
    (new_stdout, new_stderr)
}

pub enum InputArg<'a> {
    Inherit,
    Null,
    Path(Box<Borrow<Path> + Sync + 'a>),
    File(Box<Borrow<File> + Sync + 'a>),
    Bytes(Box<Borrow<[u8]> + Sync + 'a>),
}

impl<'a> InputArg<'a> {
    fn update_handle(&'a self,
                     parent_handle: pipe::Handle,
                     scope: &crossbeam::Scope<'a>)
                     -> io::Result<(pipe::Handle, Option<WriterThreadJoiner>)> {
        let mut maybe_thread = None;
        let handle = match self {
            &InputArg::Inherit => parent_handle,
            &InputArg::Null => pipe::Handle::from_file(try!(File::open("/dev/null"))),  // TODO: Windows
            &InputArg::Path(ref p) => pipe::Handle::from_file(try!(File::open((&**p).borrow()))),
            &InputArg::File(ref f) => pipe::Handle::dup_file((&**f).borrow()),
            &InputArg::Bytes(ref v) => {
                let (handle, thread) = pipe_with_writer_thread((&**v).borrow(), scope);
                maybe_thread = Some(thread);
                handle
            }
        };
        Ok((handle, maybe_thread))
    }
}

pub enum OutputArg<'a> {
    Inherit,
    Null,
    Stdout,
    Stderr,
    Path(Box<Borrow<Path> + Sync + 'a>),
    File(Box<Borrow<File> + Sync + 'a>),
}

impl<'a> OutputArg<'a> {
    fn update_handle(&self, parent_handle: pipe::Handle) -> io::Result<pipe::Handle> {
        let handle = match self {
            // Stdout and Stderr are no-ops here, but with_child_context interprets them. This is
            // because they refer to the *child's* stdout/stderr, with other redirections already
            // applied, rather than to the parent's.
            &OutputArg::Inherit | &OutputArg::Stdout | &OutputArg::Stderr => parent_handle,
            &OutputArg::Null => pipe::Handle::from_file(try!(File::create("/dev/null"))),  // TODO: Windows
            &OutputArg::Path(ref p) => pipe::Handle::from_file(try!(File::create((&**p).borrow()))),
            &OutputArg::File(ref f) => pipe::Handle::dup_file((&**f).borrow()),
        };
        Ok(handle)
    }
}

// An IoContext represents the file descriptors child processes are talking to at execution time.
// It's initialized in run(), with dups of the stdin/stdout/stderr pipes, and then passed down to
// sub-expressions. Compound expressions will clone() it, and pipes/redirections will modify it
// according to their IoArgs.
#[derive(Clone, Debug)]
pub struct IoContext {
    stdin: pipe::Handle,
    stdout: pipe::Handle,
    stderr: pipe::Handle,
}

impl IoContext {
    fn new() -> IoContext {
        IoContext {
            stdin: pipe::Handle::stdin(),
            stdout: pipe::Handle::stdout(),
            stderr: pipe::Handle::stderr(),
        }
    }
}

fn pipe_with_reader_thread() -> (pipe::Handle, JoinHandle<io::Result<Vec<u8>>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut read_file = read_pipe.to_file();
        let mut output = Vec::new();
        try!(read_file.read_to_end(&mut output));
        Ok(output)
    });
    (write_pipe, thread)
}

type WriterThreadJoiner = crossbeam::ScopedJoinHandle<io::Result<()>>;

fn pipe_with_writer_thread<'a>(input: &'a [u8],
                               scope: &crossbeam::Scope<'a>)
                               -> (pipe::Handle, WriterThreadJoiner) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = scope.spawn(move || {
        let mut write_file = write_pipe.to_file();
        try!(write_file.write_all(&input));
        Ok(())
    });
    (read_pipe, thread)
}

#[cfg(test)]
mod test {
    extern crate tempfile;

    use super::*;
    use std::io::prelude::*;
    use std::io::SeekFrom;

    #[test]
    fn test_cmd() {
        let output = cmd(&["echo", "hi"]).read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_sh() {
        let output = sh("echo hi").read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_pipe() {
        let output = pipe(sh("echo hi"), sh("sed s/i/o/")).read().unwrap();
        assert_eq!("ho", output);
    }

    #[test]
    fn test_then() {
        let output = then(sh("echo -n hi"), sh("echo lo")).read().unwrap();
        assert_eq!("hilo", output);
    }

    #[test]
    fn test_input() {
        let mut expr = sh("sed s/f/g/");
        expr.stdin(InputArg::Bytes(Box::new(b"foo".as_ref())));
        let output = expr.read().unwrap();
        assert_eq!("goo", output);
    }

    #[test]
    fn test_null() {
        let mut expr = cmd(&["cat"]);
        expr.stdin(InputArg::Null);
        expr.stdout(OutputArg::Null);
        let output = expr.read().unwrap();
        assert_eq!("", output);
    }

    #[test]
    fn test_path() {
        let mut input_file = tempfile::NamedTempFile::new().unwrap();
        let mut output_file = tempfile::NamedTempFile::new().unwrap();
        println!("Here are the paths: {:?} {:?}",
                 input_file.path(),
                 output_file.path());
        input_file.write_all(b"foo").unwrap();
        let mut expr = sh("sed s/o/a/g");
        expr.stdin(InputArg::Path(Box::new(input_file.path().to_owned())));
        expr.stdout(OutputArg::Path(Box::new(output_file.path().to_owned())));
        let output = expr.read().unwrap();
        assert_eq!("", output);
        let mut file_output = String::new();
        output_file.read_to_string(&mut file_output).unwrap();
        assert_eq!("faa", file_output);
    }

    #[test]
    fn test_owned_input() {
        fn set_input(expr: &mut Expression) {
            let mystr = format!("I own this: {}", "foo");
            // This would be a lifetime error if we tried to use &mystr.
            expr.stdin(InputArg::Bytes(Box::new(mystr.into_bytes())));
        }

        let mut c = cmd(&["cat"]);
        set_input(&mut c);
        let output = c.read().unwrap();
        assert_eq!("I own this: foo", output);
    }

    #[test]
    fn test_stderr_to_stdout() {
        let mut command = sh("echo hi >&2");
        command.stderr(OutputArg::Stdout);
        let output = command.read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_file() {
        let mut temp = tempfile::NamedTempFile::new().unwrap();
        temp.write_all(b"example").unwrap();
        temp.seek(SeekFrom::Start(0)).unwrap();
        let mut expr = cmd(&["cat"]);
        expr.stdin(InputArg::File(Box::new(&*temp)));
        let output = expr.read().unwrap();
        assert_eq!(output, "example");
    }
}
<commit_msg>use AsRef instead of Borrow where possible (not for File)<commit_after>extern crate crossbeam;

use std::borrow::Borrow;
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::Path;
use std::process::{Command, Output, ExitStatus};
use std::thread::JoinHandle;

mod pipe;

pub fn cmd<T: AsRef<OsStr>>(argv: &[T]) -> Expression<'static> {
    let argv_vec = argv.iter().map(|arg| arg.as_ref().to_owned()).collect();
    Expression {
        inner: ExpressionInner::ArgvCommand(argv_vec),
        ioargs: IoArgs::new(),
    }
}

pub fn sh<T: AsRef<OsStr>>(command: T) -> Expression<'static> {
    Expression {
        inner: ExpressionInner::ShCommand(command.as_ref().to_owned()),
        ioargs: IoArgs::new(),
    }
}

pub fn pipe<'a>(left: Expression<'a>, right: Expression<'a>) -> Expression<'a> {
    Expression {
        inner: ExpressionInner::Pipe(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

pub fn then<'a>(left: Expression<'a>, right: Expression<'a>) -> Expression<'a> {
    Expression {
        inner: ExpressionInner::Then(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

pub struct Expression<'a> {
    inner: ExpressionInner<'a>,
    ioargs: IoArgs<'a>,
}

enum ExpressionInner<'a> {
    ArgvCommand(Vec<OsString>),
    ShCommand(OsString),
    Pipe(Box<Expression<'a>>, Box<Expression<'a>>),
    Then(Box<Expression<'a>>, Box<Expression<'a>>),
}

impl<'a> Expression<'a> {
    pub fn run(&self) -> Result<Output, Error> {
        unreachable!();
    }

    pub fn read(&self) -> Result<String, Error> {
        let (handle, reader) = pipe_with_reader_thread();
        let mut context = IoContext::new();
        context.stdout = handle;
        let status = try!(self.exec(context));
        let stdout_vec = try!(reader.join().unwrap());
        if !status.success() {
            return Err(Error::Status(Output {
                status: status,
                stdout: stdout_vec,
                stderr: Vec::new(),
            }));
        }
        let stdout_string = try!(std::str::from_utf8(&stdout_vec))
                                .trim_right_matches('\n')
                                .to_owned();
        Ok(stdout_string)
    }

    fn exec(&self, parent_context: IoContext) -> io::Result<ExitStatus> {
        self.ioargs.with_child_context(parent_context, |context| {
            match self.inner {
                ExpressionInner::ArgvCommand(ref argv) => exec_argv(argv, context),
                ExpressionInner::ShCommand(ref command) => exec_sh(command, context),
                ExpressionInner::Pipe(ref left, ref right) => exec_pipe(left, right, context),
                ExpressionInner::Then(ref left, ref right) => exec_then(left, right, context),
            }
        })
    }

    pub fn stdin(&mut self, arg: InputArg<'a>) -> &mut Self {
        self.ioargs.stdin = arg;
        self
    }

    pub fn stdout(&mut self, arg: OutputArg<'a>) -> &mut Self {
        self.ioargs.stdout = arg;
        self
    }

    pub fn stderr(&mut self, arg: OutputArg<'a>) -> &mut Self {
        self.ioargs.stderr = arg;
        self
    }
}

fn exec_argv(argv: &Vec<OsString>, context: IoContext) -> io::Result<ExitStatus> {
    let mut command = Command::new(&argv[0]);
    command.args(&argv[1..]);
    command.stdin(context.stdin.to_stdio());
    command.stdout(context.stdout.to_stdio());
    command.stderr(context.stderr.to_stdio());
    command.status()
}

fn exec_sh(command: &OsStr, context: IoContext) -> io::Result<ExitStatus> {
    // TODO: What shell should we be using here, really?
    // TODO: Figure out how cmd.exe works on Windows.
    let mut argv = Vec::new();
    argv.push("bash".into());
    argv.push("-c".into());
    argv.push(command.to_owned());
    exec_argv(&argv, context)
}

fn exec_pipe(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let left_context = IoContext {
        stdin: context.stdin,
        stdout: write_pipe,
        stderr: context.stderr.clone(),
    };
    let right_context = IoContext {
        stdin: read_pipe,
        stdout: context.stdout,
        stderr: context.stderr,
    };

    let (left_result, right_result) = crossbeam::scope(|scope| {
        let left_joiner = scope.spawn(|| left.exec(left_context));
        let right_result = right.exec(right_context);
        let left_result = left_joiner.join();
        (left_result, right_result)
    });

    let right_status = try!(right_result);
    let left_status = try!(left_result);
    if !right_status.success() {
        Ok(right_status)
    } else {
        Ok(left_status)
    }
}

fn exec_then(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let status = try!(left.exec(context.clone()));
    if !status.success() {
        Ok(status)
    } else {
        right.exec(context)
    }
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Utf8(std::str::Utf8Error),
    Status(Output),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<std::str::Utf8Error> for Error {
    fn from(err: std::str::Utf8Error) -> Error {
        Error::Utf8(err)
    }
}

// IoArgs store the redirections and other settings associated with an expression. At execution
// time, IoArgs are used to modify an IoContext, which contains the actual pipes that child process
struct IoArgs<'a> {
    stdin: InputArg<'a>,
    stdout: OutputArg<'a>,
    stderr: OutputArg<'a>,
}

impl<'a> IoArgs<'a> {
    fn new() -> IoArgs<'static> {
        IoArgs {
            stdin: InputArg::Inherit,
            stdout: OutputArg::Inherit,
            stderr: OutputArg::Inherit,
        }
    }

    fn with_child_context<F, T>(&self, parent_context: IoContext, inner: F) -> io::Result<T>
        where F: FnOnce(IoContext) -> io::Result<T>
    {
        crossbeam::scope(|scope| {
            let parent_context = parent_context;  // move it into the closure
            let (stdin, maybe_stdin_thread) = try!(self.stdin
                                                       .update_handle(parent_context.stdin, scope));
            let stdout = try!(self.stdout.update_handle(parent_context.stdout));
            let stderr = try!(self.stderr.update_handle(parent_context.stderr));
            let (stdout, stderr) = apply_swaps(stdout, stderr, &self.stdout, &self.stderr);

            let child_context = IoContext {
                stdin: stdin,
                stdout: stdout,
                stderr: stderr,
            };

            let ret = try!(inner(child_context));

            if let Some(thread) = maybe_stdin_thread {
                try!(thread.join());
            }

            Ok(ret)
        })
    }
}

// returns (new_stdout, new_stderr)
fn apply_swaps(stdout_handle: pipe::Handle,
               stderr_handle: pipe::Handle,
               stdout_arg: &OutputArg,
               stderr_arg: &OutputArg)
               -> (pipe::Handle, pipe::Handle) {
    // TODO: These clones are a little excessive.
    let new_stdout = if let &OutputArg::Stderr = stdout_arg {
        stderr_handle.clone()
    } else {
        stdout_handle.clone()
    };
    let new_stderr = if let &OutputArg::Stdout = stderr_arg {
        stdout_handle.clone()
    } else {
        stderr_handle.clone()
    };
    (new_stdout, new_stderr)
}

pub enum InputArg<'a> {
    Inherit,
    Null,
    Path(Box<AsRef<Path> + Sync + 'a>),
    File(Box<Borrow<File> + Sync + 'a>),
    Bytes(Box<AsRef<[u8]> + Sync + 'a>),
}

impl<'a> InputArg<'a> {
    fn update_handle(&'a self,
                     parent_handle: pipe::Handle,
                     scope: &crossbeam::Scope<'a>)
                     -> io::Result<(pipe::Handle, Option<WriterThreadJoiner>)> {
        let mut maybe_thread = None;
        let handle = match self {
            &InputArg::Inherit => parent_handle,
            &InputArg::Null => pipe::Handle::from_file(try!(File::open("/dev/null"))),  // TODO: Windows
            &InputArg::Path(ref p) => pipe::Handle::from_file(try!(File::open(p.as_ref()))),
            &InputArg::File(ref f) => pipe::Handle::dup_file((&**f).borrow()),
            &InputArg::Bytes(ref v) => {
                let (handle, thread) = pipe_with_writer_thread((**v).as_ref(), scope);
                maybe_thread = Some(thread);
                handle
            }
        };
        Ok((handle, maybe_thread))
    }
}

pub enum OutputArg<'a> {
    Inherit,
    Null,
    Stdout,
    Stderr,
    Path(Box<AsRef<Path> + Sync + 'a>),
    File(Box<Borrow<File> + Sync + 'a>),
}

impl<'a> OutputArg<'a> {
    fn update_handle(&self, parent_handle: pipe::Handle) -> io::Result<pipe::Handle> {
        let handle = match self {
            // Stdout and Stderr are no-ops here, but with_child_context interprets them. This is
            // because they refer to the *child's* stdout/stderr, with other redirections already
            // applied, rather than to the parent's.
            &OutputArg::Inherit | &OutputArg::Stdout | &OutputArg::Stderr => parent_handle,
            &OutputArg::Null => pipe::Handle::from_file(try!(File::create("/dev/null"))),  // TODO: Windows
            &OutputArg::Path(ref p) => pipe::Handle::from_file(try!(File::create(p.as_ref()))),
            &OutputArg::File(ref f) => pipe::Handle::dup_file((&**f).borrow()),
        };
        Ok(handle)
    }
}

// An IoContext represents the file descriptors child processes are talking to at execution time.
// It's initialized in run(), with dups of the stdin/stdout/stderr pipes, and then passed down to
// sub-expressions. Compound expressions will clone() it, and pipes/redirections will modify it
// according to their IoArgs.
#[derive(Clone, Debug)]
pub struct IoContext {
    stdin: pipe::Handle,
    stdout: pipe::Handle,
    stderr: pipe::Handle,
}

impl IoContext {
    fn new() -> IoContext {
        IoContext {
            stdin: pipe::Handle::stdin(),
            stdout: pipe::Handle::stdout(),
            stderr: pipe::Handle::stderr(),
        }
    }
}

fn pipe_with_reader_thread() -> (pipe::Handle, JoinHandle<io::Result<Vec<u8>>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut read_file = read_pipe.to_file();
        let mut output = Vec::new();
        try!(read_file.read_to_end(&mut output));
        Ok(output)
    });
    (write_pipe, thread)
}

type WriterThreadJoiner = crossbeam::ScopedJoinHandle<io::Result<()>>;

fn pipe_with_writer_thread<'a>(input: &'a [u8],
                               scope: &crossbeam::Scope<'a>)
                               -> (pipe::Handle, WriterThreadJoiner) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = scope.spawn(move || {
        let mut write_file = write_pipe.to_file();
        try!(write_file.write_all(&input));
        Ok(())
    });
    (read_pipe, thread)
}

#[cfg(test)]
mod test {
    extern crate tempfile;

    use super::*;
    use std::io::prelude::*;
    use std::io::SeekFrom;

    #[test]
    fn test_cmd() {
        let output = cmd(&["echo", "hi"]).read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_sh() {
        let output = sh("echo hi").read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_pipe() {
        let output = pipe(sh("echo hi"), sh("sed s/i/o/")).read().unwrap();
        assert_eq!("ho", output);
    }

    #[test]
    fn test_then() {
        let output = then(sh("echo -n hi"), sh("echo lo")).read().unwrap();
        assert_eq!("hilo", output);
    }

    #[test]
    fn test_input() {
        let mut expr = sh("sed s/f/g/");
        expr.stdin(InputArg::Bytes(Box::new(b"foo".as_ref())));
        let output = expr.read().unwrap();
        assert_eq!("goo", output);
    }

    #[test]
    fn test_null() {
        let mut expr = cmd(&["cat"]);
        expr.stdin(InputArg::Null);
        expr.stdout(OutputArg::Null);
        let output = expr.read().unwrap();
        assert_eq!("", output);
    }

    #[test]
    fn test_path() {
        let mut input_file = tempfile::NamedTempFile::new().unwrap();
        let mut output_file = tempfile::NamedTempFile::new().unwrap();
        println!("Here are the paths: {:?} {:?}",
                 input_file.path(),
                 output_file.path());
        input_file.write_all(b"foo").unwrap();
        let mut expr = sh("sed s/o/a/g");
        expr.stdin(InputArg::Path(Box::new(input_file.path().to_owned())));
        expr.stdout(OutputArg::Path(Box::new(output_file.path().to_owned())));
        let output = expr.read().unwrap();
        assert_eq!("", output);
        let mut file_output = String::new();
        output_file.read_to_string(&mut file_output).unwrap();
        assert_eq!("faa", file_output);
    }

    #[test]
    fn test_owned_input() {
        fn set_input(expr: &mut Expression) {
            let mystr = format!("I own this: {}", "foo");
            // This would be a lifetime error if we tried to use &mystr.
            expr.stdin(InputArg::Bytes(Box::new(mystr.into_bytes())));
        }

        let mut c = cmd(&["cat"]);
        set_input(&mut c);
        let output = c.read().unwrap();
        assert_eq!("I own this: foo", output);
    }

    #[test]
    fn test_stderr_to_stdout() {
        let mut command = sh("echo hi >&2");
        command.stderr(OutputArg::Stdout);
        let output = command.read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_file() {
        let mut temp = tempfile::NamedTempFile::new().unwrap();
        temp.write_all(b"example").unwrap();
        temp.seek(SeekFrom::Start(0)).unwrap();
        let mut expr = cmd(&["cat"]);
        expr.stdin(InputArg::File(Box::new(&*temp)));
        let output = expr.read().unwrap();
        assert_eq!(output, "example");
    }
}
<|endoftext|>


<commit_before>extern crate time;

use std::iter::Iterator;

use time::{now_utc, Tm, Duration};

pub struct ProgressRecord {

    /// How many elements before this
    num: usize,
    iterating_for: Duration,
    size_hint: (usize, Option<usize>),

}

impl ProgressRecord {
    /// Returns a basic log message of where we are now. You can construct this yourself, but this
    /// is a helpful convience method.
    pub fn message(&self) -> String {
        format!("{} - Seen {} Rate {}/sec", self.duration_since_start().num_seconds(), self.num_done(), self.rate())
    }

    /// Duration since iteration started
    pub fn duration_since_start(&self) -> Duration {
        self.iterating_for
    }

    /// Number of items we've generated so far
    pub fn num_done(&self) -> usize {
        self.num
    }

    /// Prints a basic message
    pub fn print_message(&self) {
        println!("{}", self.message());
    }

    /// Number of items per second
    pub fn rate(&self) -> f32 {
        // number of items per second
        (self.num_done() as f32) / (self.duration_since_start().num_seconds() as f32)
    }

    /// None if we don't know how much we've done (as a fraction), otherwise a value form 0 to 1
    /// for what fraction along we are.
    pub fn fraction(&self) -> Option<f32> {
        if self.is_size_known() {
            let remaining = self.size_hint.0;
            let done = self.num_done();
            Some(( done as f32 ) / ( (remaining+done) as f32 ))
        } else {
            None
        }
    }

    /// None if we don't know how much we've done, otherwise value for 0 to 100 representing how
    /// far along as a percentage we are.
    pub fn percent(&self) -> Option<f32> {
        match self.fraction() {
            None => { None }
            Some(f) => { Some(f * 100.0) }
        }
    }

    /// If we want to print every `n` items, should we print now?
    pub fn should_print_every_items(&self, n: usize) -> bool {
        (self.num_done() - 1) % n == 0
    }

    /// Print out `msg`, but only if there has been `n` items.
    /// Often you want to print out a debug message every 1,000 items or so. This function does
    /// that.
    pub fn print_every<T: std::fmt::Display>(&self, n: usize, msg: T) {
        if self.should_print_every_items(n) {
            print!("{}", msg);
        }
    }

    /// Does the size_hint tell us exactly how many items are left? False iff there is some
    /// ambiguity/unknown
    fn is_size_known(&self) -> bool {
        match self.size_hint.1 {
            None => { false },
            Some(x) => { self.size_hint.0 == x },
        }
    }

}

/// Wraps an iterator and keeps track of state used for `ProgressRecord`'s
pub struct ProgressRecorderIter<I> {

    /// The iterator that we are iteating on
    iter: I,

    /// How many items have been seen
    count: usize,

    /// When did we start iterating
    started_iterating: Tm,
}

impl<I: Iterator> ProgressRecorderIter<I> {
    /// Create a new `ProgressRecorderIter` from another iterator.
    pub fn new(iter: I) -> ProgressRecorderIter<I> {
        ProgressRecorderIter{ iter: iter, count: 0, started_iterating: now_utc() }
    }

    /// Calculate the current `ProgressRecord` for where we are now.
    fn generate_record(&mut self) -> ProgressRecord {
        self.count += 1;
        ProgressRecord{ num: self.count, iterating_for: now_utc() - self.started_iterating, size_hint: self.iter.size_hint() }
    }

}

/// An iterator that records it's progress as it goes along
pub trait ProgressableIter<I> {
    fn progress(self) -> ProgressRecorderIter<I>;
}

impl<I> ProgressableIter<I> for I where I: Iterator {
    /// Convert an iterator into a `ProgressRecorderIter`.
    fn progress(self) -> ProgressRecorderIter<I> {
        ProgressRecorderIter::new(self)
    }
}

impl<I> Iterator for ProgressRecorderIter<I> where I: Iterator {
    type Item = (ProgressRecord, <I as Iterator>::Item);

    #[inline]
    fn next(&mut self) -> Option<(ProgressRecord, <I as Iterator>::Item)> {
        self.iter.next().map(|a| {
            (self.generate_record(), a)
        })
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }

    #[inline]
    fn count(self) -> usize {
        self.iter.count()
    }
}

mod test {
    #[test]
    fn test_simple() {
        use super::ProgressableIter;
        use std::thread::sleep_ms;
        use time::Duration;

        let vec: Vec<u8> = vec![0, 1, 2, 3, 4];
        let mut progressor = vec.iter().progress();

        sleep_ms(500);
        let (state, _) = progressor.next().unwrap();
        assert_eq!(state.message(), "0 - Seen 1 Rate inf/sec");
        // It'll always print on the first one
        assert_eq!(state.should_print_every_items(2), true);
        assert_eq!(state.should_print_every_items(3), true);
        assert_eq!(state.should_print_every_items(5), true);
        assert_eq!(state.rate(), ::std::f32::INFINITY);

        sleep_ms(500);
        let (state, _) = progressor.next().unwrap();
        assert_eq!(state.message(), "1 - Seen 2 Rate 2/sec");
        assert_eq!(state.should_print_every_items(2), false);
        assert_eq!(state.should_print_every_items(3), false);
        assert_eq!(state.should_print_every_items(5), false);
        assert_eq!(state.rate(), 2.);

        sleep_ms(500);
        let (state, _) = progressor.next().unwrap();
        assert_eq!(state.message(), "1 - Seen 3 Rate 3/sec");
        assert_eq!(state.should_print_every_items(2), true);
        assert_eq!(state.should_print_every_items(3), false);
        assert_eq!(state.should_print_every_items(5), false);
        assert_eq!(state.rate(), 3.);

        sleep_ms(500);
        let (state, _) = progressor.next().unwrap();
        assert_eq!(state.message(), "2 - Seen 4 Rate 2/sec");
        assert_eq!(state.should_print_every_items(2), false);
        assert_eq!(state.should_print_every_items(3), true);
        assert_eq!(state.should_print_every_items(5), false);
        assert_eq!(state.rate(), 2.);
    }

    #[test]
    fn test_size_hint() {
        use super::ProgressableIter;
        use time::Duration;

        let vec: Vec<u8> = vec![0, 1, 2, 3, 4];
        let mut progressor = vec.iter().progress();

        let (state, _) = progressor.next().unwrap();
        assert_eq!(state.fraction(), Some(0.2));
        assert_eq!(state.percent(), Some(20.));

        let (state, _) = progressor.next().unwrap();
        assert_eq!(state.fraction(), Some(0.4));
        assert_eq!(state.percent(), Some(40.));

        let mut progressor = (0..).progress();

        let (state, val) = progressor.next().unwrap();
        assert_eq!(val, 0);
        assert_eq!(state.fraction(), None);
        let (state, val) = progressor.next().unwrap();
        assert_eq!(val, 1);
        assert_eq!(state.fraction(), None);

    }
}

<commit_msg>feat: Keep track of recent rate, rather than global rate<commit_after>extern crate time;

use std::iter::Iterator;

use time::{now_utc, Tm, Duration};

pub struct ProgressRecord {

    /// How many elements before this
    num: usize,

    iterating_for: Duration,
    size_hint: (usize, Option<usize>),

    recent_rate: f32,

}

impl ProgressRecord {
    /// Returns a basic log message of where we are now. You can construct this yourself, but this
    /// is a helpful convience method.
    pub fn message(&self) -> String {
        format!("{} - Seen {} Rate {}/sec", self.duration_since_start().num_seconds(), self.num_done(), self.recent_rate())
    }

    /// Duration since iteration started
    pub fn duration_since_start(&self) -> Duration {
        self.iterating_for
    }

    /// Number of items we've generated so far
    pub fn num_done(&self) -> usize {
        self.num
    }

    /// Prints a basic message
    pub fn print_message(&self) {
        println!("{}", self.message());
    }

    /// Number of items per second
    pub fn rate(&self) -> f32 {
        // number of items per second
        (self.num_done() as f32) / (self.duration_since_start().num_seconds() as f32)
    }

    /// None if we don't know how much we've done (as a fraction), otherwise a value form 0 to 1
    /// for what fraction along we are.
    pub fn fraction(&self) -> Option<f32> {
        if self.is_size_known() {
            let remaining = self.size_hint.0;
            let done = self.num_done();
            Some(( done as f32 ) / ( (remaining+done) as f32 ))
        } else {
            None
        }
    }

    /// None if we don't know how much we've done, otherwise value for 0 to 100 representing how
    /// far along as a percentage we are.
    pub fn percent(&self) -> Option<f32> {
        match self.fraction() {
            None => { None }
            Some(f) => { Some(f * 100.0) }
        }
    }

    /// If we want to print every `n` items, should we print now?
    pub fn should_print_every_items(&self, n: usize) -> bool {
        (self.num_done() - 1) % n == 0
    }

    /// Print out `msg`, but only if there has been `n` items.
    /// Often you want to print out a debug message every 1,000 items or so. This function does
    /// that.
    pub fn print_every<T: std::fmt::Display>(&self, n: usize, msg: T) {
        if self.should_print_every_items(n) {
            print!("{}", msg);
        }
    }

    /// Does the size_hint tell us exactly how many items are left? False iff there is some
    /// ambiguity/unknown
    fn is_size_known(&self) -> bool {
        match self.size_hint.1 {
            None => { false },
            Some(x) => { self.size_hint.0 == x },
        }
    }

    /// The rate of the last few items.
    pub fn recent_rate(&self) -> f32 {
        self.recent_rate
    }

}

/// Wraps an iterator and keeps track of state used for `ProgressRecord`'s
pub struct ProgressRecorderIter<I> {

    /// The iterator that we are iteating on
    iter: I,

    /// How many items have been seen
    count: usize,

    /// When did we start iterating
    started_iterating: Tm,

    /// Keeps track of recent times
    recent_times: Vec<Tm>
}

impl<I: Iterator> ProgressRecorderIter<I> {
    /// Create a new `ProgressRecorderIter` from another iterator.
    pub fn new(iter: I) -> ProgressRecorderIter<I> {
        ProgressRecorderIter{ iter: iter, count: 0, started_iterating: now_utc(), recent_times: Vec::with_capacity(5) }
    }

    /// Calculate the current `ProgressRecord` for where we are now.
    fn generate_record(&mut self) -> ProgressRecord {
        let now = now_utc();
        self.recent_times.push(now);
        while self.recent_times.len() > 100 {
            self.recent_times.remove(0);
        }

        //println!("\n");
        //println!("Recents {:?} now {:?}", self.recent_times.iter().map(|&d| { (now - d).num_seconds() }).collect::<Vec<_>>(), now);
        let recent_rate = match self.recent_times.get(0) { None => { ::std::f32::INFINITY }, Some(&first) => {
            //println!("{} {}", self.recent_times.len() as f32, (now - first).num_seconds() as f32);
            (self.recent_times.len() as f32 ) / ((now - first).num_seconds() as f32)
        }, };

        self.count += 1;
        ProgressRecord{ num: self.count, iterating_for: now - self.started_iterating, size_hint: self.iter.size_hint(), recent_rate: recent_rate }
    }

}

/// An iterator that records it's progress as it goes along
pub trait ProgressableIter<I> {
    fn progress(self) -> ProgressRecorderIter<I>;
}

impl<I> ProgressableIter<I> for I where I: Iterator {
    /// Convert an iterator into a `ProgressRecorderIter`.
    fn progress(self) -> ProgressRecorderIter<I> {
        ProgressRecorderIter::new(self)
    }
}

impl<I> Iterator for ProgressRecorderIter<I> where I: Iterator {
    type Item = (ProgressRecord, <I as Iterator>::Item);

    #[inline]
    fn next(&mut self) -> Option<(ProgressRecord, <I as Iterator>::Item)> {
        self.iter.next().map(|a| {
            (self.generate_record(), a)
        })
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }

    #[inline]
    fn count(self) -> usize {
        self.iter.count()
    }
}

mod test {
    #[test]
    fn test_simple() {
        use super::ProgressableIter;
        use std::thread::sleep_ms;
        use time::Duration;

        let vec: Vec<u8> = vec![0, 1, 2, 3, 4];
        let mut progressor = vec.iter().progress();

        sleep_ms(500);
        let (state, _) = progressor.next().unwrap();
        assert_eq!(state.message(), "0 - Seen 1 Rate inf/sec");
        // It'll always print on the first one
        assert_eq!(state.should_print_every_items(2), true);
        assert_eq!(state.should_print_every_items(3), true);
        assert_eq!(state.should_print_every_items(5), true);
        assert_eq!(state.rate(), ::std::f32::INFINITY);
        assert_eq!(state.recent_rate(), ::std::f32::INFINITY);

        sleep_ms(500);
        let (state, _) = progressor.next().unwrap();
        assert_eq!(state.message(), "1 - Seen 2 Rate 2/sec");
        assert_eq!(state.should_print_every_items(2), false);
        assert_eq!(state.should_print_every_items(3), false);
        assert_eq!(state.should_print_every_items(5), false);
        assert_eq!(state.rate(), 2.);
        //assert_eq!(state.recent_rate(), 2.);

        sleep_ms(500);
        let (state, _) = progressor.next().unwrap();
        assert_eq!(state.message(), "1 - Seen 3 Rate 3/sec");
        assert_eq!(state.should_print_every_items(2), true);
        assert_eq!(state.should_print_every_items(3), false);
        assert_eq!(state.should_print_every_items(5), false);
        assert_eq!(state.rate(), 3.);
        assert_eq!(state.recent_rate(), 3.);

        sleep_ms(500);
        let (state, _) = progressor.next().unwrap();
        assert_eq!(state.message(), "2 - Seen 4 Rate 2/sec");
        assert_eq!(state.should_print_every_items(2), false);
        assert_eq!(state.should_print_every_items(3), true);
        assert_eq!(state.should_print_every_items(5), false);
        assert_eq!(state.rate(), 2.);
        assert_eq!(state.recent_rate(), 2.);
    }

    #[test]
    fn test_size_hint() {
        use super::ProgressableIter;
        use time::Duration;

        let vec: Vec<u8> = vec![0, 1, 2, 3, 4];
        let mut progressor = vec.iter().progress();

        let (state, _) = progressor.next().unwrap();
        assert_eq!(state.fraction(), Some(0.2));
        assert_eq!(state.percent(), Some(20.));

        let (state, _) = progressor.next().unwrap();
        assert_eq!(state.fraction(), Some(0.4));
        assert_eq!(state.percent(), Some(40.));

        let mut progressor = (0..).progress();

        let (state, val) = progressor.next().unwrap();
        assert_eq!(val, 0);
        assert_eq!(state.fraction(), None);
        let (state, val) = progressor.next().unwrap();
        assert_eq!(val, 1);
        assert_eq!(state.fraction(), None);

    }
}

<|endoftext|>


<commit_before>use ipnetwork::IpNetwork;
use pnet_datalink;
use sysinfo::{CpuExt, DiskExt, ProcessExt, System, SystemExt};

pub struct Device {
    systeminfo: SystemInfo,
    cpus: Vec<Cpu>,
    disks: Vec<Disk>,
    interfaces: Vec<Interface>,
    sys: System,
}

#[derive(Debug, Clone)]
struct SystemInfo {
    os_version: String,
    kernel_version: String,
    hostname: String,
    cores_nb: usize,
    total_ram: u64,
    free_ram: u64,
    used_ram: u64,
    total_swap: u64,
    free_swap: u64,
    used_swap: u64,
}

#[derive(Debug, Clone)]
pub struct Cpu {
    name: String,
    usage: f32,
    vendor_id: String,
    brand: String,
}

#[derive(Debug, Clone)]
pub struct Disk {
    name: String,
    mount_point: String,
    total_space: u64,
    available_space: u64,
}

#[derive(Clone, Debug)]
pub struct Interface {
    name: String,
    mac: String,
    ip: String,
    prefix: u8,
    version: u8,
}

/// Implementation for the struct Device.
/// This one is used to get system and network info
/// about the device.
impl Device {
    pub fn new() -> Self {
        // get all sys info of device
        let mut sys = System::new_all();

        // update info of sys struct
        sys.refresh_all();

        let os_version = format!("{} {}", sys.name().unwrap(), sys.os_version().unwrap());

        let systeminfo = SystemInfo {
            hostname: sys.host_name().unwrap().clone(),
            os_version: os_version,
            kernel_version: sys.kernel_version().unwrap(),
            cores_nb: sys.cpus().len(),
            total_ram: sys.total_memory(),
            free_ram: sys.free_memory(),
            used_ram: sys.used_memory(),
            total_swap: sys.total_swap(),
            free_swap: sys.free_swap(),
            used_swap: sys.used_swap(),
        };

        // Get all disks and put them in a Vec of Disk structs
        let mut disks: Vec<Disk> = Vec::new();
        for disk in sys.disks() {
            let disk_struct = Disk {
                name: disk.name().to_str().unwrap().to_string(),
                mount_point: disk.mount_point().to_str().unwrap().to_string(),
                total_space: disk.total_space(),
                available_space: disk.available_space(),
            };

            disks.push(disk_struct);
        }

        // Get cpu info an put it in a Vec of Cpu struct
        let mut cpus: Vec<Cpu> = Vec::new();
        for cpu in sys.cpus() {
            let cpu_struct = Cpu {
                name: cpu.name().to_string(),
                usage: cpu.cpu_usage(),
                vendor_id: cpu.vendor_id().to_string(),
                brand: cpu.brand().to_string(),
            };

            cpus.push(cpu_struct);
        }

        // Get all network interfaces
        let mut interfaces: Vec<Interface> = Vec::new();
        for iface in pnet_datalink::interfaces() {
            let mut interface_struct: Interface;

            for ip in iface.ips {
                match ip {
                    IpNetwork::V4(ipv4) => {
                        interface_struct = Interface {
                            name: iface.name.clone(),
                            mac: iface.mac.unwrap().to_string().clone(),
                            ip: ipv4.ip().to_string(),
                            prefix: ipv4.prefix(),
                            version: 4,
                        };
                    }
                    IpNetwork::V6(ipv6) => {
                        interface_struct = Interface {
                            name: iface.name.clone(),
                            mac: iface.mac.unwrap().to_string().clone(),
                            ip: ipv6.ip().to_string(),
                            prefix: ipv6.prefix(),
                            version: 6,
                        };
                    }
                }
                interfaces.push(interface_struct);
            }
        }

        Self {
            systeminfo,
            cpus: cpus,
            disks: disks,
            interfaces: interfaces,
            sys,
        }
    }

    /// Refresh all from system
    pub fn refresh_all(&mut self) {
        self.sys.refresh_all();
    }

    /// Get CPUs
    pub fn get_cpus(&mut self) -> Vec<Cpu> {
        self.cpus.clone()
    }

    /// Get disks
    pub fn get_disks(&mut self) -> Vec<Disk> {
        self.disks.clone()
    }

    /// Get network interfaces
    pub fn get_interfaces(&mut self) -> Vec<Interface> {
        self.interfaces.clone()
    }

    /// Print system information
    pub fn print_system_info(&mut self, do_tab: bool) {
        let tab: String;
        if do_tab {
            tab = format!("   ");
        } else {
            tab = format!("");
        }
        println!("{tab}Hosname: {}", self.systeminfo.hostname);
        println!("{tab}OS : {}", self.systeminfo.os_version);
        println!("{tab}kernel : {}", self.systeminfo.kernel_version);
        println!("{tab}Cores : {}", self.systeminfo.cores_nb);
        println!("{tab}RAM");
        println!("   {tab}Total RAM: {}MB", self.systeminfo.total_ram / 1000);
        println!("   {tab}Free  RAM: {}MB", self.systeminfo.free_ram / 1000);
        println!("   {tab}Used  RAM: {}MB", self.systeminfo.used_ram / 1000);
        println!("{tab}Swap");
        println!(
            "   {tab}Total Swap: {}MB",
            self.systeminfo.total_swap / 1000
        );
        println!("   {tab}Free  Swap: {}MB", self.systeminfo.free_swap / 1000);
        println!("   {tab}Used  Swap: {}MB", self.systeminfo.used_swap / 1000);
    }

    /// Print network info
    pub fn print_network_info(&mut self) {
        for iface in self.get_interfaces() {
            if iface.version != 6 {
                println!("{}", iface.name);
            } else {
                println!("");
            }
            println!("   {}/{}", iface.ip, iface.prefix);
            println!("   {}", iface.mac);
        }
    }

    /// Print CPUs info
    pub fn print_cpus_info(&mut self) {
        for cpu in self.get_cpus() {
            println!("{}", cpu.name);
            println!("   Usage: {}%", f32::trunc(cpu.usage * 100.0) / 100.0);
            println!("   Vendor: {}", cpu.vendor_id);
            println!("   Core: {}", cpu.brand);
        }
    }

    /// Print disks info
    pub fn print_disks_info(&mut self) {
        for disk in self.get_disks() {
            println!("{}", disk.name);
            println!("   Mount point : {}", disk.mount_point);
            println!(
                "   Available space : {}MB",
                (disk.available_space / (1024 * 1024))
            );
            println!("   Total space : {}MB", (disk.total_space / (1024 * 1024)));
        }
    }

    /// Print all process info I need, not in a struct yet, because la flemme
    /// TODO : order by pid
    pub fn print_processes(&mut self) {
        for (pid, process) in self.sys.processes() {
            println!("{} - {}", pid, process.name());
            println!("   CPU usage: {}%", process.cpu_usage());
            println!("   Mem usage: {}MB", process.virtual_memory() / 1000);
            println!("   Status: {}\n", process.status());
        }
    }

    /// Print all info about a device
    pub fn print_all_info(&mut self) {
        println!("System:");
        self.print_system_info(true);

        println!("\nNetwork interfaces:");
        self.print_network_info();

        println!("\nCPUs:");
        self.print_cpus_info();

        println!("\ndisks:");
        self.print_disks_info();
    }
}
<commit_msg>cargo clippy<commit_after>use ipnetwork::IpNetwork;
use sysinfo::{CpuExt, DiskExt, ProcessExt, System, SystemExt};

pub struct Device {
    systeminfo: SystemInfo,
    cpus: Vec<Cpu>,
    disks: Vec<Disk>,
    interfaces: Vec<Interface>,
    sys: System,
}

#[derive(Debug, Clone)]
struct SystemInfo {
    os_version: String,
    kernel_version: String,
    hostname: String,
    cores_nb: usize,
    total_ram: u64,
    free_ram: u64,
    used_ram: u64,
    total_swap: u64,
    free_swap: u64,
    used_swap: u64,
}

#[derive(Debug, Clone)]
pub struct Cpu {
    name: String,
    usage: f32,
    vendor_id: String,
    brand: String,
}

#[derive(Debug, Clone)]
pub struct Disk {
    name: String,
    mount_point: String,
    total_space: u64,
    available_space: u64,
}

#[derive(Clone, Debug)]
pub struct Interface {
    name: String,
    mac: String,
    ip: String,
    prefix: u8,
    version: u8,
}

impl Default for Device {
    fn default() -> Self {
        Self::new()
    }
}

/// Implementation for the struct Device.
/// This one is used to get system and network info
/// about the device.
impl Device {
    pub fn new() -> Self {
        // get all sys info of device
        let mut sys = System::new_all();

        // update info of sys struct
        sys.refresh_all();

        let os_version = format!("{} {}", sys.name().unwrap(), sys.os_version().unwrap());

        let systeminfo = SystemInfo {
            hostname: sys.host_name().unwrap(),
            os_version,
            kernel_version: sys.kernel_version().unwrap(),
            cores_nb: sys.cpus().len(),
            total_ram: sys.total_memory(),
            free_ram: sys.free_memory(),
            used_ram: sys.used_memory(),
            total_swap: sys.total_swap(),
            free_swap: sys.free_swap(),
            used_swap: sys.used_swap(),
        };

        // Get all disks and put them in a Vec of Disk structs
        let mut disks: Vec<Disk> = Vec::new();
        for disk in sys.disks() {
            let disk_struct = Disk {
                name: disk.name().to_str().unwrap().to_string(),
                mount_point: disk.mount_point().to_str().unwrap().to_string(),
                total_space: disk.total_space(),
                available_space: disk.available_space(),
            };

            disks.push(disk_struct);
        }

        // Get cpu info an put it in a Vec of Cpu struct
        let mut cpus: Vec<Cpu> = Vec::new();
        for cpu in sys.cpus() {
            let cpu_struct = Cpu {
                name: cpu.name().to_string(),
                usage: cpu.cpu_usage(),
                vendor_id: cpu.vendor_id().to_string(),
                brand: cpu.brand().to_string(),
            };

            cpus.push(cpu_struct);
        }

        // Get all network interfaces
        let mut interfaces: Vec<Interface> = Vec::new();
        for iface in pnet_datalink::interfaces() {
            let mut interface_struct: Interface;

            for ip in iface.ips {
                match ip {
                    IpNetwork::V4(ipv4) => {
                        interface_struct = Interface {
                            name: iface.name.clone(),
                            mac: iface.mac.unwrap().to_string().clone(),
                            ip: ipv4.ip().to_string(),
                            prefix: ipv4.prefix(),
                            version: 4,
                        };
                    }
                    IpNetwork::V6(ipv6) => {
                        interface_struct = Interface {
                            name: iface.name.clone(),
                            mac: iface.mac.unwrap().to_string().clone(),
                            ip: ipv6.ip().to_string(),
                            prefix: ipv6.prefix(),
                            version: 6,
                        };
                    }
                }
                interfaces.push(interface_struct);
            }
        }

        Self {
            systeminfo,
            cpus,
            disks,
            interfaces,
            sys,
        }
    }

    /// Refresh all from system
    pub fn refresh_all(&mut self) {
        self.sys.refresh_all();
    }

    /// Get CPUs
    pub fn get_cpus(&mut self) -> Vec<Cpu> {
        self.cpus.clone()
    }

    /// Get disks
    pub fn get_disks(&mut self) -> Vec<Disk> {
        self.disks.clone()
    }

    /// Get network interfaces
    pub fn get_interfaces(&mut self) -> Vec<Interface> {
        self.interfaces.clone()
    }

    /// Print system information
    pub fn print_system_info(&mut self, do_tab: bool) {
        let tab: String = if do_tab {
            "   ".to_string()
        } else {
            "".to_string()
        };

        println!("{tab}Hosname: {}", self.systeminfo.hostname);
        println!("{tab}OS : {}", self.systeminfo.os_version);
        println!("{tab}kernel : {}", self.systeminfo.kernel_version);
        println!("{tab}Cores : {}", self.systeminfo.cores_nb);
        println!("{tab}RAM");
        println!("   {tab}Total RAM: {}MB", self.systeminfo.total_ram / 1000);
        println!("   {tab}Free  RAM: {}MB", self.systeminfo.free_ram / 1000);
        println!("   {tab}Used  RAM: {}MB", self.systeminfo.used_ram / 1000);
        println!("{tab}Swap");
        println!(
            "   {tab}Total Swap: {}MB",
            self.systeminfo.total_swap / 1000
        );
        println!("   {tab}Free  Swap: {}MB", self.systeminfo.free_swap / 1000);
        println!("   {tab}Used  Swap: {}MB", self.systeminfo.used_swap / 1000);
    }

    /// Print network info
    pub fn print_network_info(&mut self) {
        for iface in self.get_interfaces() {
            if iface.version != 6 {
                println!("{}", iface.name);
            } else {
                println!();
            }
            println!("   {}/{}", iface.ip, iface.prefix);
            println!("   {}", iface.mac);
        }
    }

    /// Print CPUs info
    pub fn print_cpus_info(&mut self) {
        for cpu in self.get_cpus() {
            println!("{}", cpu.name);
            println!("   Usage: {}%", f32::trunc(cpu.usage * 100.0) / 100.0);
            println!("   Vendor: {}", cpu.vendor_id);
            println!("   Core: {}", cpu.brand);
        }
    }

    /// Print disks info
    pub fn print_disks_info(&mut self) {
        for disk in self.get_disks() {
            println!("{}", disk.name);
            println!("   Mount point : {}", disk.mount_point);
            println!(
                "   Available space : {}MB",
                (disk.available_space / (1024 * 1024))
            );
            println!("   Total space : {}MB", (disk.total_space / (1024 * 1024)));
        }
    }

    /// Print all process info I need, not in a struct yet, because la flemme
    /// TODO : order by pid
    pub fn print_processes(&mut self) {
        for (pid, process) in self.sys.processes() {
            println!("{} - {}", pid, process.name());
            println!("   CPU usage: {}%", process.cpu_usage());
            println!("   Mem usage: {}MB", process.virtual_memory() / 1000);
            println!("   Status: {}\n", process.status());
        }
    }

    /// Print all info about a device
    pub fn print_all_info(&mut self) {
        println!("System:");
        self.print_system_info(true);

        println!("\nNetwork interfaces:");
        self.print_network_info();

        println!("\nCPUs:");
        self.print_cpus_info();

        println!("\ndisks:");
        self.print_disks_info();
    }
}
<|endoftext|>