<commit_before>//! Support for ANSI terminal colors via the colored crate.
//!
//! To enable support for colors, add the `"colored"` feature in your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! fern = { version = "0.5", features = ["colored"] }
//! ```
//!
//! ---
//!
//! Colors are currently supported mainly for the log-level. Meaning you can configure the "INFO" / "WARN"
//! / "ERROR" text itself to be a different color depending on which of those it is.
//!
//! To do this, the [`ColoredLevelConfig`] structure allows configuration of per-level colors.
//!
//! ```
//! use fern::colors::{Color, ColoredLevelConfig};
//!
//!
//! let mut colors = ColoredLevelConfig::new()
//!     // use builder methods
//!     .info(Color::Green);
//! // or access raw fields
//! colors.warn = Color::Magenta;
//! ```
//!
//! It can then be used within any regular fern formatting closure:
//!
//! ```
//! fern::Dispatch::new()
//!     // ...
//!     .format(move |out, message, record| {
//!         out.finish(format_args!(
//!             "[{}] {}",
//!             // just use 'colors.color(..)' instead of the level
//!             // itself to insert ANSI colors.
//!             colors.color(record.level()),
//!         ))
//!     })
//! ```
//!
//! [`ColoredLevelConfig`]: struct.ColoredLevelConfig.html
use std::fmt;
pub use colored::Color;
use log::Level;

/// Extension crate allowing the use of `.colored` on Levels.
trait ColoredLogLevel {
    /// Colors this log level with the given color.
    fn colored(&self, color: Color) -> WithFgColor<Level>;
}

/// Opaque structure which represents some text data and a color to display it with.
///
/// This implements [`fmt::Display`] to displaying the inner text (usually a log level) with ANSI color markers before
/// to set the color and after to reset the color.
///
/// WithFgColor instances can be created and displayed without any allocation.
// this is necessary in order to avoid using colored::ColorString, which has a Display
// implementation involving many allocations, and would involve two more string allocations
// even to create it.
//
// [`fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
pub struct WithFgColor<T>
where
    T: fmt::Display,
{
    text: T,
    color: Color,
}

impl<T> fmt::Display for WithFgColor<T>
where
    T: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "\x1B[{}m{}\x1B[0m", self.color.to_fg_str(), self.text)
    }
}

/// Configuration specifying colors a log level can be colored as.
///
/// Example usage setting custom 'info' and 'debug' colors:
///
/// ```
/// use fern::colors::{Color, ColoredLevelConfig};
///
/// let colors = ColoredLevelConfig::new()
///     .info(Color::Green)
///     .debug(Color::Magenta);
///
/// fern::Dispatch::new()
///     .format(move |out, message, record| {
///         out.finish(format_args!(
///             "[{}] {}",
///             colors.color(record.level()),
///             message
///         ))
///     })
///     .chain(std::io::stdout())
/// # /*
///     .apply()?;
/// # */
/// #   .into_log();
/// ```
#[derive(Copy, Clone)]
#[must_use = "builder methods take config by value and thus must be reassigned to variable"]
pub struct ColoredLevelConfig {
    /// The color to color logs with the [`Error`] level.
    ///
    /// [`Error`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Error
    pub error: Color,
    /// The color to color logs with the [`Warn`] level.
    ///
    /// [`Warn`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Warn
    pub warn: Color,
    /// The color to color logs with the [`Info`] level.
    ///
    /// [`Info`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Info
    pub info: Color,
    /// The color to color logs with the [`Debug`] level.
    ///
    /// [`Debug`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Debug
    pub debug: Color,
    /// The color to color logs with the [`Trace`] level.
    ///
    /// [`Trace`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Trace
    pub trace: Color,
}

impl ColoredLevelConfig {
    /// Creates a new ColoredLevelConfig with the default colors.
    ///
    /// This matches the behavior of [`ColoredLevelConfig::default`].
    ///
    /// [`ColoredLevelConfig::default`]: #method.default
    #[inline]
    pub fn new() -> Self {
        Self::default()
    }

    /// Overrides the [`Error`] level color with the given color.
    ///
    /// The default color is [`Color::Red`].
    ///
    /// [`Error`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Error
    /// [`Color::Red`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Red
    pub fn error(mut self, error: Color) -> Self {
        self.error = error;
        self
    }

    /// Overrides the [`Warn`] level color with the given color.
    ///
    /// The default color is [`Color::Yellow`].
    ///
    /// [`Warn`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Warn
    /// [`Color::Yellow`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Yellow
    pub fn warn(mut self, warn: Color) -> Self {
        self.warn = warn;
        self
    }

    /// Overrides the [`Info`] level color with the given color.
    ///
    /// The default color is [`Color::White`].
    ///
    /// [`Info`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Info
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    pub fn info(mut self, info: Color) -> Self {
        self.info = info;
        self
    }

    /// Overrides the [`Debug`] level color with the given color.
    ///
    /// The default color is [`Color::White`].
    ///
    /// [`Debug`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Debug
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    pub fn debug(mut self, debug: Color) -> Self {
        self.debug = debug;
        self
    }

    /// Overrides the [`Trace`] level color with the given color.
    ///
    /// The default color is [`Color::White`].
    ///
    /// [`Trace`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Trace
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    pub fn trace(mut self, trace: Color) -> Self {
        self.trace = trace;
        self
    }

    /// Retrieves the default configuration. This has:
    ///
    /// - [`Error`] as [`Color::Red`]
    /// - [`Warn`] as [`Color::Yellow`]
    /// - [`Info`] as [`Color::White`]
    /// - [`Debug`] as [`Color::White`]
    /// - [`Trace`] as [`Color::White`]
    ///
    /// [`Error`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Error
    /// [`Warn`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Warn
    /// [`Info`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Info
    /// [`Debug`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Debug
    /// [`Trace`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Trace
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    /// [`Color::Yellow`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Yellow
    /// [`Color::Red`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Red
    pub fn default() -> Self {
        ColoredLevelConfig {
            error: Color::Red,
            warn: Color::Yellow,
            debug: Color::White,
            info: Color::White,
            trace: Color::White,
        }
    }

    /// Colors the given log level with the color in this configuration corresponding to it's
    /// level.
    ///
    /// The structure returned is opaque, but will print the Level surrounded by ANSI color
    /// codes when displayed. This will work correctly for UNIX terminals, but due to a lack
    /// of support from the [`colored`] crate, this will not function in Windows.
    ///
    /// [`colored`]: https://github.com/mackwic/colored
    pub fn color(&self, level: Level) -> WithFgColor<Level> {
        level.colored(self.get_color(&level))
    }

    /// Retrieves the color that a log level should be colored as.
    pub fn get_color(&self, level: &Level) -> Color {
        match *level {
            Level::Error => self.error,
            Level::Warn => self.warn,
            Level::Info => self.info,
            Level::Debug => self.debug,
            Level::Trace => self.trace,
        }
    }
}

impl ColoredLogLevel for Level {
    fn colored(&self, color: Color) -> WithFgColor<Level> {
        WithFgColor {
            text: *self,
            color: color,
        }
    }
}

#[cfg(test)]
mod test {
    use super::WithFgColor;
    use colored::Colorize;
    use colored::Color::*;

    #[test]
    fn fg_color_matches_colored_behavior() {
        for &color in &[
            Black,
            Red,
            Green,
            Yellow,
            Blue,
            Magenta,
            Cyan,
            White,
            BrightBlack,
            BrightRed,
            BrightGreen,
            BrightYellow,
            BrightBlue,
            BrightMagenta,
            BrightCyan,
            BrightWhite,
        ] {
            assert_eq!(
                format!("{}", "test".color(color)),
                format!(
                    "{}",
                    WithFgColor {
                        text: "test",
                        color: color,
                    }
                )
            );
        }
    }
}
<commit_msg>Move ColoredLogConfig::default into an implementation of Default.<commit_after>//! Support for ANSI terminal colors via the colored crate.
//!
//! To enable support for colors, add the `"colored"` feature in your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! fern = { version = "0.5", features = ["colored"] }
//! ```
//!
//! ---
//!
//! Colors are currently supported mainly for the log-level. Meaning you can configure the "INFO" / "WARN"
//! / "ERROR" text itself to be a different color depending on which of those it is.
//!
//! To do this, the [`ColoredLevelConfig`] structure allows configuration of per-level colors.
//!
//! ```
//! use fern::colors::{Color, ColoredLevelConfig};
//!
//!
//! let mut colors = ColoredLevelConfig::new()
//!     // use builder methods
//!     .info(Color::Green);
//! // or access raw fields
//! colors.warn = Color::Magenta;
//! ```
//!
//! It can then be used within any regular fern formatting closure:
//!
//! ```
//! fern::Dispatch::new()
//!     // ...
//!     .format(move |out, message, record| {
//!         out.finish(format_args!(
//!             "[{}] {}",
//!             // just use 'colors.color(..)' instead of the level
//!             // itself to insert ANSI colors.
//!             colors.color(record.level()),
//!         ))
//!     })
//! ```
//!
//! [`ColoredLevelConfig`]: struct.ColoredLevelConfig.html
use std::fmt;
pub use colored::Color;
use log::Level;

/// Extension crate allowing the use of `.colored` on Levels.
trait ColoredLogLevel {
    /// Colors this log level with the given color.
    fn colored(&self, color: Color) -> WithFgColor<Level>;
}

/// Opaque structure which represents some text data and a color to display it with.
///
/// This implements [`fmt::Display`] to displaying the inner text (usually a log level) with ANSI color markers before
/// to set the color and after to reset the color.
///
/// WithFgColor instances can be created and displayed without any allocation.
// this is necessary in order to avoid using colored::ColorString, which has a Display
// implementation involving many allocations, and would involve two more string allocations
// even to create it.
//
// [`fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
pub struct WithFgColor<T>
where
    T: fmt::Display,
{
    text: T,
    color: Color,
}

impl<T> fmt::Display for WithFgColor<T>
where
    T: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "\x1B[{}m{}\x1B[0m", self.color.to_fg_str(), self.text)
    }
}

/// Configuration specifying colors a log level can be colored as.
///
/// Example usage setting custom 'info' and 'debug' colors:
///
/// ```
/// use fern::colors::{Color, ColoredLevelConfig};
///
/// let colors = ColoredLevelConfig::new()
///     .info(Color::Green)
///     .debug(Color::Magenta);
///
/// fern::Dispatch::new()
///     .format(move |out, message, record| {
///         out.finish(format_args!(
///             "[{}] {}",
///             colors.color(record.level()),
///             message
///         ))
///     })
///     .chain(std::io::stdout())
/// # /*
///     .apply()?;
/// # */
/// #   .into_log();
/// ```
#[derive(Copy, Clone)]
#[must_use = "builder methods take config by value and thus must be reassigned to variable"]
pub struct ColoredLevelConfig {
    /// The color to color logs with the [`Error`] level.
    ///
    /// [`Error`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Error
    pub error: Color,
    /// The color to color logs with the [`Warn`] level.
    ///
    /// [`Warn`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Warn
    pub warn: Color,
    /// The color to color logs with the [`Info`] level.
    ///
    /// [`Info`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Info
    pub info: Color,
    /// The color to color logs with the [`Debug`] level.
    ///
    /// [`Debug`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Debug
    pub debug: Color,
    /// The color to color logs with the [`Trace`] level.
    ///
    /// [`Trace`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Trace
    pub trace: Color,
}

impl ColoredLevelConfig {
    /// Creates a new ColoredLevelConfig with the default colors.
    ///
    /// This matches the behavior of [`ColoredLevelConfig::default`].
    ///
    /// [`ColoredLevelConfig::default`]: #method.default
    #[inline]
    pub fn new() -> Self {
        Self::default()
    }

    /// Overrides the [`Error`] level color with the given color.
    ///
    /// The default color is [`Color::Red`].
    ///
    /// [`Error`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Error
    /// [`Color::Red`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Red
    pub fn error(mut self, error: Color) -> Self {
        self.error = error;
        self
    }

    /// Overrides the [`Warn`] level color with the given color.
    ///
    /// The default color is [`Color::Yellow`].
    ///
    /// [`Warn`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Warn
    /// [`Color::Yellow`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Yellow
    pub fn warn(mut self, warn: Color) -> Self {
        self.warn = warn;
        self
    }

    /// Overrides the [`Info`] level color with the given color.
    ///
    /// The default color is [`Color::White`].
    ///
    /// [`Info`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Info
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    pub fn info(mut self, info: Color) -> Self {
        self.info = info;
        self
    }

    /// Overrides the [`Debug`] level color with the given color.
    ///
    /// The default color is [`Color::White`].
    ///
    /// [`Debug`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Debug
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    pub fn debug(mut self, debug: Color) -> Self {
        self.debug = debug;
        self
    }

    /// Overrides the [`Trace`] level color with the given color.
    ///
    /// The default color is [`Color::White`].
    ///
    /// [`Trace`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Trace
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    pub fn trace(mut self, trace: Color) -> Self {
        self.trace = trace;
        self
    }

    /// Colors the given log level with the color in this configuration corresponding to it's
    /// level.
    ///
    /// The structure returned is opaque, but will print the Level surrounded by ANSI color
    /// codes when displayed. This will work correctly for UNIX terminals, but due to a lack
    /// of support from the [`colored`] crate, this will not function in Windows.
    ///
    /// [`colored`]: https://github.com/mackwic/colored
    pub fn color(&self, level: Level) -> WithFgColor<Level> {
        level.colored(self.get_color(&level))
    }

    /// Retrieves the color that a log level should be colored as.
    pub fn get_color(&self, level: &Level) -> Color {
        match *level {
            Level::Error => self.error,
            Level::Warn => self.warn,
            Level::Info => self.info,
            Level::Debug => self.debug,
            Level::Trace => self.trace,
        }
    }
}

impl Default for ColoredLevelConfig {
    /// Retrieves the default configuration. This has:
    ///
    /// - [`Error`] as [`Color::Red`]
    /// - [`Warn`] as [`Color::Yellow`]
    /// - [`Info`] as [`Color::White`]
    /// - [`Debug`] as [`Color::White`]
    /// - [`Trace`] as [`Color::White`]
    ///
    /// [`Error`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Error
    /// [`Warn`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Warn
    /// [`Info`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Info
    /// [`Debug`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Debug
    /// [`Trace`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Trace
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    /// [`Color::Yellow`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Yellow
    /// [`Color::Red`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Red
    fn default() -> Self {
        ColoredLevelConfig {
            error: Color::Red,
            warn: Color::Yellow,
            debug: Color::White,
            info: Color::White,
            trace: Color::White,
        }
    }
}

impl ColoredLogLevel for Level {
    fn colored(&self, color: Color) -> WithFgColor<Level> {
        WithFgColor {
            text: *self,
            color: color,
        }
    }
}

#[cfg(test)]
mod test {
    use super::WithFgColor;
    use colored::Colorize;
    use colored::Color::*;

    #[test]
    fn fg_color_matches_colored_behavior() {
        for &color in &[
            Black,
            Red,
            Green,
            Yellow,
            Blue,
            Magenta,
            Cyan,
            White,
            BrightBlack,
            BrightRed,
            BrightGreen,
            BrightYellow,
            BrightBlue,
            BrightMagenta,
            BrightCyan,
            BrightWhite,
        ] {
            assert_eq!(
                format!("{}", "test".color(color)),
                format!(
                    "{}",
                    WithFgColor {
                        text: "test",
                        color: color,
                    }
                )
            );
        }
    }
}
<|endoftext|>


<commit_before>//! Contains common types for reader and writer.

/// Format of FBX data
#[derive(Debug, Clone, Copy)]
pub enum FbxFormatType {
    /// Binary FBX, with version (for example, `7400` for FBX 7.4).
    Binary(u32),
    /// ASCII FBX.
    Ascii,
}

/// A property type of the FBX node.
#[derive(Debug, Clone, PartialEq)]
pub enum OwnedProperty {
    /// Boolean.
    Bool(bool),
    /// 2 byte signed integer.
    I16(i16),
    /// 4 byte signed integer.
    I32(i32),
    /// 8 byte signed integer.
    I64(i64),
    /// 4 byte single-precision IEEE 754 floating-point number.
    F32(f32),
    /// 8 byte double-precision IEEE 754 floating-point number.
    F64(f64),
    /// Array of boolean.
    VecBool(Vec<bool>),
    /// Array of 4 byte signed integer.
    VecI32(Vec<i32>),
    /// Array of 8 byte signed integer.
    VecI64(Vec<i64>),
    /// Array of 4 byte single-precision IEEE 754 number.
    VecF32(Vec<f32>),
    /// Array of 8 byte double-precision IEEE 754 number.
    VecF64(Vec<f64>),
    /// String.
    ///
    /// Note that the string can contain special character like `\u{0}`.
    String(String),
    /// Raw binary data.
    Binary(Vec<u8>),
}

impl OwnedProperty {
    pub fn borrow(&self) -> Property {
        match *self {
            OwnedProperty::Bool(v) => Property::Bool(v),
            OwnedProperty::I16(v) => Property::I16(v),
            OwnedProperty::I32(v) => Property::I32(v),
            OwnedProperty::I64(v) => Property::I64(v),
            OwnedProperty::F32(v) => Property::F32(v),
            OwnedProperty::F64(v) => Property::F64(v),
            OwnedProperty::VecBool(ref v) => Property::VecBool(&v),
            OwnedProperty::VecI32(ref v) => Property::VecI32(&v),
            OwnedProperty::VecI64(ref v) => Property::VecI64(&v),
            OwnedProperty::VecF32(ref v) => Property::VecF32(&v),
            OwnedProperty::VecF64(ref v) => Property::VecF64(&v),
            OwnedProperty::String(ref v) => Property::String(&v),
            OwnedProperty::Binary(ref v) => Property::Binary(&v),
        }
    }
}

/// A property type of the FBX node.
#[derive(Debug, Clone, PartialEq)]
pub enum Property<'a> {
    /// Boolean.
    Bool(bool),
    /// 2 byte signed integer.
    I16(i16),
    /// 4 byte signed integer.
    I32(i32),
    /// 8 byte signed integer.
    I64(i64),
    /// 4 byte single-precision IEEE 754 floating-point number.
    F32(f32),
    /// 8 byte double-precision IEEE 754 floating-point number.
    F64(f64),
    /// Array of boolean.
    VecBool(&'a [bool]),
    /// Array of 4 byte signed integer.
    VecI32(&'a [i32]),
    /// Array of 8 byte signed integer.
    VecI64(&'a [i64]),
    /// Array of 4 byte single-precision IEEE 754 number.
    VecF32(&'a [f32]),
    /// Array of 8 byte double-precision IEEE 754 number.
    VecF64(&'a [f64]),
    /// String.
    ///
    /// Note that the string can contain special character like `\u{0}`.
    String(&'a str),
    /// Raw binary data.
    Binary(&'a [u8]),
}
<commit_msg>Add method to get property value as specific type<commit_after>//! Contains common types for reader and writer.

use std::borrow::Cow;

/// Format of FBX data
#[derive(Debug, Clone, Copy)]
pub enum FbxFormatType {
    /// Binary FBX, with version (for example, `7400` for FBX 7.4).
    Binary(u32),
    /// ASCII FBX.
    Ascii,
}

/// A property type of the FBX node.
#[derive(Debug, Clone, PartialEq)]
pub enum OwnedProperty {
    /// Boolean.
    Bool(bool),
    /// 2 byte signed integer.
    I16(i16),
    /// 4 byte signed integer.
    I32(i32),
    /// 8 byte signed integer.
    I64(i64),
    /// 4 byte single-precision IEEE 754 floating-point number.
    F32(f32),
    /// 8 byte double-precision IEEE 754 floating-point number.
    F64(f64),
    /// Array of boolean.
    VecBool(Vec<bool>),
    /// Array of 4 byte signed integer.
    VecI32(Vec<i32>),
    /// Array of 8 byte signed integer.
    VecI64(Vec<i64>),
    /// Array of 4 byte single-precision IEEE 754 number.
    VecF32(Vec<f32>),
    /// Array of 8 byte double-precision IEEE 754 number.
    VecF64(Vec<f64>),
    /// String.
    ///
    /// Note that the string can contain special character like `\u{0}`.
    String(String),
    /// Raw binary data.
    Binary(Vec<u8>),
}

impl OwnedProperty {
    pub fn borrow(&self) -> Property {
        match *self {
            OwnedProperty::Bool(v) => Property::Bool(v),
            OwnedProperty::I16(v) => Property::I16(v),
            OwnedProperty::I32(v) => Property::I32(v),
            OwnedProperty::I64(v) => Property::I64(v),
            OwnedProperty::F32(v) => Property::F32(v),
            OwnedProperty::F64(v) => Property::F64(v),
            OwnedProperty::VecBool(ref v) => Property::VecBool(&v),
            OwnedProperty::VecI32(ref v) => Property::VecI32(&v),
            OwnedProperty::VecI64(ref v) => Property::VecI64(&v),
            OwnedProperty::VecF32(ref v) => Property::VecF32(&v),
            OwnedProperty::VecF64(ref v) => Property::VecF64(&v),
            OwnedProperty::String(ref v) => Property::String(&v),
            OwnedProperty::Binary(ref v) => Property::Binary(&v),
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_bool(&self) -> Option<bool> {
        match *self {
            OwnedProperty::Bool(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_i16(&self) -> Option<i16> {
        match *self {
            OwnedProperty::Bool(v) => Some(if v { 1 } else { 0 }),
            OwnedProperty::I16(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_i32(&self) -> Option<i32> {
        match *self {
            OwnedProperty::Bool(v) => Some(if v { 1 } else { 0 }),
            OwnedProperty::I16(v) => Some(v as i32),
            OwnedProperty::I32(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_i64(&self) -> Option<i64> {
        match *self {
            OwnedProperty::Bool(v) => Some(if v { 1 } else { 0 }),
            OwnedProperty::I16(v) => Some(v as i64),
            OwnedProperty::I32(v) => Some(v as i64),
            OwnedProperty::I64(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_f32(&self) -> Option<f32> {
        match *self {
            OwnedProperty::F32(v) => Some(v),
            OwnedProperty::F64(v) => Some(v as f32),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_f64(&self) -> Option<f64> {
        match *self {
            OwnedProperty::F32(v) => Some(v as f64),
            OwnedProperty::F64(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_vec_bool(&self) -> Option<&[bool]> {
        match *self {
            OwnedProperty::VecBool(ref v) => Some(&v[..]),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_vec_i32(&self) -> Option<Cow<[i32]>> {
        match *self {
            OwnedProperty::VecBool(ref v) => Some(Cow::Owned(v.iter().map(|&v| if v { 1 } else { 0 }).collect())),
            OwnedProperty::VecI32(ref v) => Some(Cow::Borrowed(&v)),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_vec_i64(&self) -> Option<Cow<[i64]>> {
        match *self {
            OwnedProperty::VecBool(ref v) => Some(Cow::Owned(v.iter().map(|&v| if v { 1 } else { 0 }).collect())),
            OwnedProperty::VecI32(ref v) => Some(Cow::Owned(v.iter().map(|&v| v as i64).collect())),
            OwnedProperty::VecI64(ref v) => Some(Cow::Borrowed(&v)),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_vec_f32(&self) -> Option<Cow<[f32]>> {
        match *self {
            OwnedProperty::VecF32(ref v) => Some(Cow::Borrowed(&v)),
            OwnedProperty::VecF64(ref v) => Some(Cow::Owned(v.iter().map(|&v| v as f32).collect())),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_vec_f64(&self) -> Option<Cow<[f64]>> {
        match *self {
            OwnedProperty::VecF32(ref v) => Some(Cow::Owned(v.iter().map(|&v| v as f64).collect())),
            OwnedProperty::VecF64(ref v) => Some(Cow::Borrowed(&v)),
            _ => None,
        }
    }

    /// Get string value if possible.
    pub fn get_string(&self) -> Option<&String> {
        match *self {
            OwnedProperty::String(ref v) => Some(&v),
            _ => None,
        }
    }

    /// Get binary value if possible.
    pub fn get_binary(&self) -> Option<&[u8]> {
        match *self {
            OwnedProperty::Binary(ref v) => Some(&v[..]),
            _ => None,
        }
    }
}

/// A property type of the FBX node.
#[derive(Debug, Clone, PartialEq)]
pub enum Property<'a> {
    /// Boolean.
    Bool(bool),
    /// 2 byte signed integer.
    I16(i16),
    /// 4 byte signed integer.
    I32(i32),
    /// 8 byte signed integer.
    I64(i64),
    /// 4 byte single-precision IEEE 754 floating-point number.
    F32(f32),
    /// 8 byte double-precision IEEE 754 floating-point number.
    F64(f64),
    /// Array of boolean.
    VecBool(&'a [bool]),
    /// Array of 4 byte signed integer.
    VecI32(&'a [i32]),
    /// Array of 8 byte signed integer.
    VecI64(&'a [i64]),
    /// Array of 4 byte single-precision IEEE 754 number.
    VecF32(&'a [f32]),
    /// Array of 8 byte double-precision IEEE 754 number.
    VecF64(&'a [f64]),
    /// String.
    ///
    /// Note that the string can contain special character like `\u{0}`.
    String(&'a str),
    /// Raw binary data.
    Binary(&'a [u8]),
}

impl<'a> Property<'a> {
    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_bool(&self) -> Option<bool> {
        match *self {
            Property::Bool(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_i16(&self) -> Option<i16> {
        match *self {
            Property::Bool(v) => Some(if v { 1 } else { 0 }),
            Property::I16(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_i32(&self) -> Option<i32> {
        match *self {
            Property::Bool(v) => Some(if v { 1 } else { 0 }),
            Property::I16(v) => Some(v as i32),
            Property::I32(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_i64(&self) -> Option<i64> {
        match *self {
            Property::Bool(v) => Some(if v { 1 } else { 0 }),
            Property::I16(v) => Some(v as i64),
            Property::I32(v) => Some(v as i64),
            Property::I64(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_f32(&self) -> Option<f32> {
        match *self {
            Property::F32(v) => Some(v),
            Property::F64(v) => Some(v as f32),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_f64(&self) -> Option<f64> {
        match *self {
            Property::F32(v) => Some(v as f64),
            Property::F64(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_vec_bool(&self) -> Option<&[bool]> {
        match *self {
            Property::VecBool(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_vec_i32(&self) -> Option<Cow<[i32]>> {
        match *self {
            Property::VecBool(v) => Some(Cow::Owned(v.iter().map(|&v| if v { 1 } else { 0 }).collect())),
            Property::VecI32(v) => Some(Cow::Borrowed(v)),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_vec_i64(&self) -> Option<Cow<[i64]>> {
        match *self {
            Property::VecBool(v) => Some(Cow::Owned(v.iter().map(|&v| if v { 1 } else { 0 }).collect())),
            Property::VecI32(v) => Some(Cow::Owned(v.iter().map(|&v| v as i64).collect())),
            Property::VecI64(v) => Some(Cow::Borrowed(v)),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_vec_f32(&self) -> Option<Cow<[f32]>> {
        match *self {
            Property::VecF32(v) => Some(Cow::Borrowed(v)),
            Property::VecF64(v) => Some(Cow::Owned(v.iter().map(|&v| v as f32).collect())),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn get_vec_f64(&self) -> Option<Cow<[f64]>> {
        match *self {
            Property::VecF32(v) => Some(Cow::Owned(v.iter().map(|&v| v as f64).collect())),
            Property::VecF64(v) => Some(Cow::Borrowed(v)),
            _ => None,
        }
    }

    /// Get string value if possible.
    pub fn get_string(&self) -> Option<&str> {
        match *self {
            Property::String(v) => Some(v),
            _ => None,
        }
    }

    /// Get binary value if possible.
    pub fn get_binary(&self) -> Option<&[u8]> {
        match *self {
            Property::Binary(v) => Some(v),
            _ => None,
        }
    }
}

#[cfg(test)]
mod property_tests {
    use super::{OwnedProperty};

    #[test]
    fn owned_vec_i32_to_vec_i64() {
        let vec_i32: Vec<i32> = vec![1, -1, 2, -3, 5, -8, 13, -21, 34];
        let vec_i64 = vec_i32.iter().map(|&v| v as i64).collect::<Vec<_>>();
        let src = OwnedProperty::VecI32(vec_i32.clone());
        let dst = src.get_vec_i64().unwrap().into_owned();
        assert_eq!(vec_i64, dst);
    }

    #[test]
    fn borrowed_vec_i32_to_vec_i64() {
        let vec_i32: Vec<i32> = vec![1, -1, 2, -3, 5, -8, 13, -21, 34];
        let vec_i64 = vec_i32.iter().map(|&v| v as i64).collect::<Vec<_>>();
        let src_owned = OwnedProperty::VecI32(vec_i32.clone());
        let src = src_owned.borrow();
        let dst = src.get_vec_i64().unwrap().into_owned();
        assert_eq!(vec_i64, dst);
    }
}
<|endoftext|>


<commit_before>// compile-flags: -Z chalk

trait Foo: Sized { }

trait Bar {
    type Item: Foo;
}

impl Foo for i32 { }

impl Foo for str { }
//~^ ERROR the size for values of type `str` cannot be known at compilation time

// Implicit `T: Sized` bound.
impl<T> Foo for Option<T> { }

impl Bar for () {
    type Item = i32;
}

impl<T> Bar for Option<T> {
    type Item = Option<T>;
}

impl Bar for f32 {
//~^ ERROR the trait bound `f32: Foo` is not satisfied
    type Item = f32;
}

trait Baz<U: ?Sized> where U: Foo { }

impl Baz<i32> for i32 { }

impl Baz<f32> for f32 { }
//~^ ERROR the trait bound `f32: Foo` is not satisfied

fn main() {
}
<commit_msg>fix compile-fail test<commit_after>// compile-flags: -Z chalk

trait Foo: Sized { }

trait Bar {
    type Item: Foo;
}

impl Foo for i32 { }

impl Foo for str { }
//~^ ERROR the size for values of type `str` cannot be known at compilation time

// Implicit `T: Sized` bound.
impl<T> Foo for Option<T> { }

impl Bar for () {
    type Item = i32;
}

impl<T> Bar for Option<T> {
    type Item = Option<T>;
}

impl Bar for f32 {
//~^ ERROR the trait bound `f32: Foo` is not satisfied
    type Item = f32;
    //~^ ERROR the trait bound `f32: Foo` is not satisfied
}

trait Baz<U: ?Sized> where U: Foo { }

impl Baz<i32> for i32 { }

impl Baz<f32> for f32 { }
//~^ ERROR the trait bound `f32: Foo` is not satisfied

fn main() {
}
<|endoftext|>


<commit_before>use editor::Editor;
use redraw::RedrawTask;
use buffer::Buffer;
use cursor::Cursor;

impl Editor {
    /// Delete a character
    #[inline]
    pub fn delete(&mut self) {
        let &Cursor{ x, y, ..} = self.cursor();
        if x == self.buffer[y].len() {
            if y < self.buffer.len() - 1 {
                let s = self.buffer.remove_line(y + 1);
                self.buffer[y].push_str(&s);
                self.redraw_task = RedrawTask::Lines(y..y+1);
            }
        } else if x < self.buffer[y].len() {
            self.buffer[y].remove(x);
            self.redraw_task = RedrawTask::LinesAfter(y);
        }

        self.hint();
    }

    #[inline]
    pub fn backspace(&mut self) {
        let previous = self.previous(1);
        if let Some(p) = previous {
            self.goto(p);
            self.delete();
        }
        else {
            self.status_bar.msg = format!("Can't delete file start");
        }
    }
}
<commit_msg>Various nitpicks<commit_after>use editor::Editor;
use redraw::RedrawTask;
use buffer::Buffer;
use cursor::Cursor;

impl Editor {
    /// Delete a character
    #[inline]
    pub fn delete(&mut self) {
        let &Cursor{ x, y, ..} = self.cursor();
        if x == self.buffer[y].len() {
            if y + 1 < self.buffer.len() {
                let s = self.buffer.remove_line(y + 1);
                self.buffer[y].push_str(&s);
                self.redraw_task = RedrawTask::Lines(y..y + 1);
            }
        } else if x < self.buffer[y].len() {
            self.buffer[y].remove(x);
            self.redraw_task = RedrawTask::LinesAfter(y);
        }

        self.hint();
    }

    #[inline]
    pub fn backspace(&mut self) {
        let previous = self.previous(1);
        if let Some(p) = previous {
            self.goto(p);
            self.delete();
        } else {
            self.status_bar.msg = "Can't delete file start".to_owned();
        }
    }
}
<|endoftext|>


<commit_before>//! Common filesystem errors.
//!
//! This module provides convenience functions for generating [`io::Error`]s from OS error codes.
//! Notably, these errors are the only errors returned in the [`mem`] module if using implemented
//! behavior (unimplemented behavior returns `Error::new::ErrorKind::Other`).
//!
//! [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
//! [`mem`]: ../mem/index.html

use std::io::Error;

/// Used when a file or directory does not exist.
#[allow(non_snake_case)]
pub fn ENOENT() -> Error {
    Error::from_raw_os_error(2)
}

/// Used when performing an operation with a file that was not opened in a way to allow that
/// operation (read on a write only open, etc).
#[allow(non_snake_case)]
pub fn EBADF() -> Error {
    Error::from_raw_os_error(9)
}

/// Used when a user does not have requisite permissions.
#[allow(non_snake_case)]
pub fn EACCES() -> Error {
    Error::from_raw_os_error(13)
}

/// Used when trying to modify something that is actively performing an operation.
#[allow(non_snake_case)]
pub fn EBUSY() -> Error {
    Error::from_raw_os_error(16)
}

/// Used when a file or directory does not exist.
#[allow(non_snake_case)]
pub fn EEXIST() -> Error {
    Error::from_raw_os_error(17)
}

/// Used when attempting to perform a directory operation on a file.
#[allow(non_snake_case)]
pub fn ENOTDIR() -> Error {
    Error::from_raw_os_error(20)
}

/// Used when attempting to perform a file operation on a directory.
#[allow(non_snake_case)]
pub fn EISDIR() -> Error {
    Error::from_raw_os_error(21)
}

/// Used when performing an invalid operation (aka, a bad `OpenOptions` combination).
#[allow(non_snake_case)]
pub fn EINVAL() -> Error {
    Error::from_raw_os_error(22)
}

/// Used when an operation needs an empty directory and is performed on a non-empty directory.
#[allow(non_snake_case)]
pub fn ENOTEMPTY() -> Error {
    // TODO Windows is 41, other Unix / BSD distros differ from 39.
    Error::from_raw_os_error(39)
}

/// Used when traversing too many symlinks.
#[allow(non_snake_case)]
pub fn ELOOP() -> Error {
    Error::from_raw_os_error(40)
}
<commit_msg>errors: add EPERM<commit_after>//! Common filesystem errors.
//!
//! This module provides convenience functions for generating [`io::Error`]s from OS error codes.
//! Notably, these errors are the only errors returned in the [`mem`] module if using implemented
//! behavior (unimplemented behavior returns `Error::new::ErrorKind::Other`).
//!
//! [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
//! [`mem`]: ../mem/index.html

use std::io::Error;

/// Used when an operation is not permitted.
#[allow(non_snake_case)]
pub fn EPERM() -> Error {
    Error::from_raw_os_error(1)
}

/// Used when a file or directory does not exist.
#[allow(non_snake_case)]
pub fn ENOENT() -> Error {
    Error::from_raw_os_error(2)
}

/// Used when performing an operation with a file that was not opened in a way to allow that
/// operation (read on a write only open, etc).
#[allow(non_snake_case)]
pub fn EBADF() -> Error {
    Error::from_raw_os_error(9)
}

/// Used when a user does not have requisite permissions.
#[allow(non_snake_case)]
pub fn EACCES() -> Error {
    Error::from_raw_os_error(13)
}

/// Used when trying to modify something that is actively performing an operation.
#[allow(non_snake_case)]
pub fn EBUSY() -> Error {
    Error::from_raw_os_error(16)
}

/// Used when a file or directory does not exist.
#[allow(non_snake_case)]
pub fn EEXIST() -> Error {
    Error::from_raw_os_error(17)
}

/// Used when attempting to perform a directory operation on a file.
#[allow(non_snake_case)]
pub fn ENOTDIR() -> Error {
    Error::from_raw_os_error(20)
}

/// Used when attempting to perform a file operation on a directory.
#[allow(non_snake_case)]
pub fn EISDIR() -> Error {
    Error::from_raw_os_error(21)
}

/// Used when performing an invalid operation (aka, a bad `OpenOptions` combination).
#[allow(non_snake_case)]
pub fn EINVAL() -> Error {
    Error::from_raw_os_error(22)
}

/// Used when an operation needs an empty directory and is performed on a non-empty directory.
#[allow(non_snake_case)]
pub fn ENOTEMPTY() -> Error {
    // TODO Windows is 41, other Unix / BSD distros differ from 39.
    Error::from_raw_os_error(39)
}

/// Used when traversing too many symlinks.
#[allow(non_snake_case)]
pub fn ELOOP() -> Error {
    Error::from_raw_os_error(40)
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate ndarray;
// p-stable hash function
use self::rand::distributions::{Normal, IndependentSample};
use self::rand::Rng;
use self::ndarray::prelude::*;
fn get_random_normal_vector(length: usize) -> Vec<f32> {
    let normal = Normal::new(0.0,1.0);
    let output_vector: Vec<f32> = vec![normal.ind_sample(&mut rand::thread_rng()) as f32; length];
    output_vector
}

pub fn get_hash_closure(length: usize, w: f32) -> Box<Fn(&Vec<f32>) -> f32> {
    let a = get_random_normal_vector(length);
    let b = rand::thread_rng().gen_range(0.0, w);
    let clos = move |v: &Vec<f32>| -> f32 {
        /*let mut total = b;
        for i in 1..v.len() {
            total += v[i] * a[i];
        }
        (total) / w*/
        aview1(v).dot(&aview1(&a)) + b
    };
    Box::new(clos)
}

#[cfg(test)]
mod tests {
    use super::get_random_normal_vector;
    #[test]
    fn test_get_normal() {
        get_random_normal_vector(10);
    }
}
<commit_msg>remove dead code<commit_after>extern crate rand;
extern crate ndarray;
// p-stable hash function
use self::rand::distributions::{Normal, IndependentSample};
use self::rand::Rng;
use self::ndarray::prelude::*;
fn get_random_normal_vector(length: usize) -> Vec<f32> {
    let normal = Normal::new(0.0,1.0);
    let output_vector: Vec<f32> = vec![normal.ind_sample(&mut rand::thread_rng()) as f32; length];
    output_vector
}

pub fn get_hash_closure(length: usize, w: f32) -> Box<Fn(&Vec<f32>) -> f32> {
    let a = get_random_normal_vector(length);
    let b = rand::thread_rng().gen_range(0.0, w);
    let clos = move |v: &Vec<f32>| -> f32 {
        aview1(v).dot(&aview1(&a)) + b
    };
    Box::new(clos)
}

#[cfg(test)]
mod tests {
    use super::get_random_normal_vector;
    #[test]
    fn test_get_normal() {
        get_random_normal_vector(10);
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::str;

use cargo;
use cargotest::cargo_process;
use cargotest::support::paths::{self, CargoPathExt};
use cargotest::support::{execs, project, Project, basic_bin_manifest};
use hamcrest::{assert_that, existing_file};

#[cfg_attr(windows,allow(dead_code))]
enum FakeKind<'a> {
    Executable,
    Symlink{target:&'a Path},
}

/// Add an empty file with executable flags (and platform-dependent suffix).
/// TODO: move this to `Project` if other cases using this emerge.
fn fake_file(proj: Project, dir: &Path, name: &str, kind: &FakeKind) -> Project {
    let path = proj.root().join(dir).join(&format!("{}{}", name,
                                                   env::consts::EXE_SUFFIX));
    path.parent().unwrap().mkdir_p();
    match *kind {
        FakeKind::Executable => {
            File::create(&path).unwrap();
            make_executable(&path);
        },
        FakeKind::Symlink{target} => {
            make_symlink(&path,target);
        }
    }
    return proj;

    #[cfg(unix)]
    fn make_executable(p: &Path) {
        use std::os::unix::prelude::*;

        let mut perms = fs::metadata(p).unwrap().permissions();
        let mode = perms.mode();
        perms.set_mode(mode | 0o111);
        fs::set_permissions(p, perms).unwrap();
    }
    #[cfg(windows)]
    fn make_executable(_: &Path) {}
    #[cfg(unix)]
    fn make_symlink(p: &Path, t: &Path) {
        ::std::os::unix::fs::symlink(t,p).expect("Failed to create symlink");
    }
    #[cfg(windows)]
    fn make_symlink(_: &Path, _: &Path) {
        panic!("Not supported")
    }
}

fn path() -> Vec<PathBuf> {
    env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect()
}

#[test]
#[ignore]
fn list_command_looks_at_path() {
    let proj = project("list-non-overlapping").build();
    let proj = fake_file(proj, Path::new("path-test"), "cargo-1", &FakeKind::Executable);
    let mut pr = cargo_process();

    let mut path = path();
    path.push(proj.root().join("path-test"));
    let path = env::join_paths(path.iter()).unwrap();
    let output = pr.arg("-v").arg("--list")
                   .env("PATH", &path);
    let output = output.exec_with_output().unwrap();
    let output = str::from_utf8(&output.stdout).unwrap();
    assert!(output.contains("\n    1                   "), "missing 1: {}", output);
}

// windows and symlinks don't currently agree that well
#[cfg(unix)]
#[test]
#[ignore]
fn list_command_resolves_symlinks() {
    use cargotest::support::cargo_exe;

    let proj = project("list-non-overlapping").build();
    let proj = fake_file(proj, Path::new("path-test"), "cargo-2",
                         &FakeKind::Symlink{target:&cargo_exe()});
    let mut pr = cargo_process();

    let mut path = path();
    path.push(proj.root().join("path-test"));
    let path = env::join_paths(path.iter()).unwrap();
    let output = pr.arg("-v").arg("--list")
                   .env("PATH", &path);
    let output = output.exec_with_output().unwrap();
    let output = str::from_utf8(&output.stdout).unwrap();
    assert!(output.contains("\n    2                   "), "missing 2: {}", output);
}

#[test]
#[ignore]
fn find_closest_biuld_to_build() {
    let mut pr = cargo_process();
    pr.arg("biuld");

    assert_that(pr,
                execs().with_status(101)
                       .with_stderr("[ERROR] no such subcommand: `biuld`

<tab>Did you mean `build`?

"));
}

// if a subcommand is more than 3 edit distance away, we don't make a suggestion
#[test]
#[ignore]
fn find_closest_dont_correct_nonsense() {
    let mut pr = cargo_process();
    pr.arg("there-is-no-way-that-there-is-a-command-close-to-this")
      .cwd(&paths::root());

    assert_that(pr,
                execs().with_status(101)
                       .with_stderr("[ERROR] no such subcommand: \
                        `there-is-no-way-that-there-is-a-command-close-to-this`
"));
}

#[test]
#[ignore]
fn displays_subcommand_on_error() {
    let mut pr = cargo_process();
    pr.arg("invalid-command");

    assert_that(pr,
                execs().with_status(101)
                       .with_stderr("[ERROR] no such subcommand: `invalid-command`
"));
}

#[test]
fn override_cargo_home() {
    let root = paths::root();
    let my_home = root.join("my_home");
    fs::create_dir(&my_home).unwrap();
    File::create(&my_home.join("config")).unwrap().write_all(br#"
        [cargo-new]
        name = "foo"
        email = "bar"
        git = false
    "#).unwrap();

    assert_that(cargo_process()
                    .arg("new").arg("foo")
                    .env("USER", "foo")
                    .env("CARGO_HOME", &my_home),
                execs().with_status(0));

    let toml = paths::root().join("foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"authors = ["foo <bar>"]"#));
}

#[test]
fn cargo_subcommand_env() {
    use cargotest::support::cargo_exe;

    let src = format!(r#"
        use std::env;

        fn main() {{
            println!("{{}}", env::var("{}").unwrap());
        }}
        "#, cargo::CARGO_ENV);

    let p = project("cargo-envtest")
        .file("Cargo.toml", &basic_bin_manifest("cargo-envtest"))
        .file("src/main.rs", &src)
        .build();

    let target_dir = p.target_debug_dir();

    assert_that(p.cargo("build"), execs().with_status(0));
    assert_that(&p.bin("cargo-envtest"), existing_file());

    let mut pr = cargo_process();
    let cargo = cargo_exe().canonicalize().unwrap();
    let mut path = path();
    path.push(target_dir);
    let path = env::join_paths(path.iter()).unwrap();

    assert_that(pr.arg("envtest").env("PATH", &path),
                execs().with_status(0).with_stdout(cargo.to_str().unwrap()));
}

#[test]
#[ignore]
fn cargo_help() {
    assert_that(cargo_process(),
                execs().with_status(0));
    assert_that(cargo_process().arg("help"),
                execs().with_status(0));
    assert_that(cargo_process().arg("-h"),
                execs().with_status(0));
    assert_that(cargo_process().arg("help").arg("build"),
                execs().with_status(0));
    assert_that(cargo_process().arg("build").arg("-h"),
                execs().with_status(0));
    assert_that(cargo_process().arg("help").arg("-h"),
                execs().with_status(0));
    assert_that(cargo_process().arg("help").arg("help"),
                execs().with_status(0));
}

#[test]
fn explain() {
    assert_that(cargo_process().arg("--explain").arg("E0001"),
                execs().with_status(0));
}
<commit_msg>Disable `cargo help -h`<commit_after>use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::str;

use cargo;
use cargotest::cargo_process;
use cargotest::support::paths::{self, CargoPathExt};
use cargotest::support::{execs, project, Project, basic_bin_manifest};
use hamcrest::{assert_that, existing_file};

#[cfg_attr(windows,allow(dead_code))]
enum FakeKind<'a> {
    Executable,
    Symlink{target:&'a Path},
}

/// Add an empty file with executable flags (and platform-dependent suffix).
/// TODO: move this to `Project` if other cases using this emerge.
fn fake_file(proj: Project, dir: &Path, name: &str, kind: &FakeKind) -> Project {
    let path = proj.root().join(dir).join(&format!("{}{}", name,
                                                   env::consts::EXE_SUFFIX));
    path.parent().unwrap().mkdir_p();
    match *kind {
        FakeKind::Executable => {
            File::create(&path).unwrap();
            make_executable(&path);
        },
        FakeKind::Symlink{target} => {
            make_symlink(&path,target);
        }
    }
    return proj;

    #[cfg(unix)]
    fn make_executable(p: &Path) {
        use std::os::unix::prelude::*;

        let mut perms = fs::metadata(p).unwrap().permissions();
        let mode = perms.mode();
        perms.set_mode(mode | 0o111);
        fs::set_permissions(p, perms).unwrap();
    }
    #[cfg(windows)]
    fn make_executable(_: &Path) {}
    #[cfg(unix)]
    fn make_symlink(p: &Path, t: &Path) {
        ::std::os::unix::fs::symlink(t,p).expect("Failed to create symlink");
    }
    #[cfg(windows)]
    fn make_symlink(_: &Path, _: &Path) {
        panic!("Not supported")
    }
}

fn path() -> Vec<PathBuf> {
    env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect()
}

#[test]
#[ignore]
fn list_command_looks_at_path() {
    let proj = project("list-non-overlapping").build();
    let proj = fake_file(proj, Path::new("path-test"), "cargo-1", &FakeKind::Executable);
    let mut pr = cargo_process();

    let mut path = path();
    path.push(proj.root().join("path-test"));
    let path = env::join_paths(path.iter()).unwrap();
    let output = pr.arg("-v").arg("--list")
                   .env("PATH", &path);
    let output = output.exec_with_output().unwrap();
    let output = str::from_utf8(&output.stdout).unwrap();
    assert!(output.contains("\n    1                   "), "missing 1: {}", output);
}

// windows and symlinks don't currently agree that well
#[cfg(unix)]
#[test]
#[ignore]
fn list_command_resolves_symlinks() {
    use cargotest::support::cargo_exe;

    let proj = project("list-non-overlapping").build();
    let proj = fake_file(proj, Path::new("path-test"), "cargo-2",
                         &FakeKind::Symlink{target:&cargo_exe()});
    let mut pr = cargo_process();

    let mut path = path();
    path.push(proj.root().join("path-test"));
    let path = env::join_paths(path.iter()).unwrap();
    let output = pr.arg("-v").arg("--list")
                   .env("PATH", &path);
    let output = output.exec_with_output().unwrap();
    let output = str::from_utf8(&output.stdout).unwrap();
    assert!(output.contains("\n    2                   "), "missing 2: {}", output);
}

#[test]
#[ignore]
fn find_closest_biuld_to_build() {
    let mut pr = cargo_process();
    pr.arg("biuld");

    assert_that(pr,
                execs().with_status(101)
                       .with_stderr("[ERROR] no such subcommand: `biuld`

<tab>Did you mean `build`?

"));
}

// if a subcommand is more than 3 edit distance away, we don't make a suggestion
#[test]
#[ignore]
fn find_closest_dont_correct_nonsense() {
    let mut pr = cargo_process();
    pr.arg("there-is-no-way-that-there-is-a-command-close-to-this")
      .cwd(&paths::root());

    assert_that(pr,
                execs().with_status(101)
                       .with_stderr("[ERROR] no such subcommand: \
                        `there-is-no-way-that-there-is-a-command-close-to-this`
"));
}

#[test]
#[ignore]
fn displays_subcommand_on_error() {
    let mut pr = cargo_process();
    pr.arg("invalid-command");

    assert_that(pr,
                execs().with_status(101)
                       .with_stderr("[ERROR] no such subcommand: `invalid-command`
"));
}

#[test]
fn override_cargo_home() {
    let root = paths::root();
    let my_home = root.join("my_home");
    fs::create_dir(&my_home).unwrap();
    File::create(&my_home.join("config")).unwrap().write_all(br#"
        [cargo-new]
        name = "foo"
        email = "bar"
        git = false
    "#).unwrap();

    assert_that(cargo_process()
                    .arg("new").arg("foo")
                    .env("USER", "foo")
                    .env("CARGO_HOME", &my_home),
                execs().with_status(0));

    let toml = paths::root().join("foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"authors = ["foo <bar>"]"#));
}

#[test]
fn cargo_subcommand_env() {
    use cargotest::support::cargo_exe;

    let src = format!(r#"
        use std::env;

        fn main() {{
            println!("{{}}", env::var("{}").unwrap());
        }}
        "#, cargo::CARGO_ENV);

    let p = project("cargo-envtest")
        .file("Cargo.toml", &basic_bin_manifest("cargo-envtest"))
        .file("src/main.rs", &src)
        .build();

    let target_dir = p.target_debug_dir();

    assert_that(p.cargo("build"), execs().with_status(0));
    assert_that(&p.bin("cargo-envtest"), existing_file());

    let mut pr = cargo_process();
    let cargo = cargo_exe().canonicalize().unwrap();
    let mut path = path();
    path.push(target_dir);
    let path = env::join_paths(path.iter()).unwrap();

    assert_that(pr.arg("envtest").env("PATH", &path),
                execs().with_status(0).with_stdout(cargo.to_str().unwrap()));
}

#[test]
fn cargo_help() {
    assert_that(cargo_process(),
                execs().with_status(0));
    assert_that(cargo_process().arg("help"),
                execs().with_status(0));
    assert_that(cargo_process().arg("-h"),
                execs().with_status(0));
    assert_that(cargo_process().arg("help").arg("build"),
                execs().with_status(0));
    assert_that(cargo_process().arg("build").arg("-h"),
                execs().with_status(0));
    assert_that(cargo_process().arg("help").arg("help"),
                execs().with_status(0));
}

#[test]
fn explain() {
    assert_that(cargo_process().arg("--explain").arg("E0001"),
                execs().with_status(0));
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Result;
use std::io::BufReader;
use std::io::BufRead;
use std::iter::Iterator;

use io::OPEN_BUS;
use io::IO;
use memory::MemSegment;
use util::ShiftRegister8;

pub struct FM2IO {
    iter: Box<Iterator<Item=String>>,
    controller1: ShiftRegister8,
    controller2: ShiftRegister8,
}

impl FM2IO {
    pub fn read(file: String) -> Result<FM2IO> {
        let file = try!(File::open(file));
        let reader = BufReader::new(file);
        let iter = reader.lines()
            .map(|result| result.unwrap())
            .skip_while(|line| !line.contains("|"))
            .skip(1);
        return Ok( FM2IO {
                iter: Box::new(iter),
                controller1: ShiftRegister8::new(0),
                controller2: ShiftRegister8::new(0),
            } );
    }
}

fn parse(string: &str) -> u8 {
    let mut accumulator: u8 = 0;
    for (idx, _) in string.char_indices()
        .filter(|&(_, c)| c != '.') {
        accumulator |= 1 << (7 - idx);
    }
    accumulator
}

impl MemSegment for FM2IO {
        fn read(&mut self, idx: u16) -> u8 {
        match idx {
            0x4016 => OPEN_BUS | self.controller1.shift(),
            0x4017 => OPEN_BUS | self.controller2.shift(),
            x => invalid_address!(x),
        }
    }

    fn write(&mut self, idx: u16, val: u8) {
        match idx {
            0x4016 => {
                if val & 0x01 != 0 {
                    if let Some(line) = self.iter.next() {
                        let mut split = line.split("|").skip(1)
                            .skip(1); //Ignore the commands for now.
                        self.controller1.load(parse(split.next().unwrap()));
                        self.controller2.load(parse(split.next().unwrap()));
                    }
                }
            },
            0x4017 => (),
            x => invalid_address!(x),
        }
    }
}

impl IO for FM2IO {
    fn poll(&mut self) {
        //TODO
    }
}<commit_msg>Minor refactoring in FM2 code.<commit_after>use std::fs::File;
use std::io::Result;
use std::io::BufReader;
use std::io::BufRead;
use std::iter::Iterator;

use io::OPEN_BUS;
use io::IO;
use memory::MemSegment;
use util::ShiftRegister8;

pub struct FM2IO {
    iter: Box<Iterator<Item=String>>,
    controller1: ShiftRegister8,
    controller2: ShiftRegister8,
}

impl FM2IO {
    pub fn read(file: String) -> Result<FM2IO> {
        let file = try!(File::open(file));
        let reader = BufReader::new(file);
        let iter = reader.lines()
            .map(|result| result.unwrap())
            .skip_while(|line| !line.contains("|"))
            .skip(1);
        return Ok( FM2IO {
                iter: Box::new(iter),
                controller1: ShiftRegister8::new(0),
                controller2: ShiftRegister8::new(0),
            } );
    }
}

fn parse(string: &str) -> u8 {
    string.char_indices()
        .filter(|&(_, c)| c != '.')
        .fold(0u8, |acc, (idx, _)| acc | 1u8 << (7 - idx) )
}

impl MemSegment for FM2IO {
        fn read(&mut self, idx: u16) -> u8 {
        match idx {
            0x4016 => OPEN_BUS | self.controller1.shift(),
            0x4017 => OPEN_BUS | self.controller2.shift(),
            x => invalid_address!(x),
        }
    }

    fn write(&mut self, idx: u16, val: u8) {
        match idx {
            0x4016 => {
                if val & 0x01 != 0 {
                    if let Some(line) = self.iter.next() {
                        let mut split = line.split("|").skip(1)
                            .skip(1); //Ignore the commands for now.
                        self.controller1.load(parse(split.next().unwrap()));
                        self.controller2.load(parse(split.next().unwrap()));
                    }
                }
            },
            0x4017 => (),
            x => invalid_address!(x),
        }
    }
}

impl IO for FM2IO {
    fn poll(&mut self) {
        //TODO
    }
}<|endoftext|>


<commit_before>//! Issues interface
use std::collections::HashMap;
use std::fmt;

use url::form_urlencoded;
use serde::{Deserialize, Serialize};

use crate::comments::Comments;
use crate::labels::Label;
use crate::users::User;
use crate::{Future, Github, SortDirection, Stream};

/// enum representation of github pull and issue state
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum State {
    /// Only open issues
    Open,
    /// Only closed issues
    Closed,
    /// All issues, open or closed
    All,
}

impl fmt::Display for State {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            State::Open => "open",
            State::Closed => "closed",
            State::All => "all",
        }
        .fmt(f)
    }
}

impl Default for State {
    fn default() -> State {
        State::Open
    }
}

/// Sort options available for github issues
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Sort {
    /// sort by creation time of issue
    Created,
    /// sort by the last time issue was updated
    Updated,
    /// sort by number of comments
    Comments,
}

impl fmt::Display for Sort {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Sort::Created => "created",
            Sort::Updated => "updated",
            Sort::Comments => "comments",
        }
        .fmt(f)
    }
}

impl Default for Sort {
    fn default() -> Sort {
        Sort::Created
    }
}

/// Provides access to assignee operations available for an individual issue
pub struct IssueAssignees {
    github: Github,
    owner: String,
    repo: String,
    number: u64,
}

impl IssueAssignees {
    #[doc(hidden)]
    pub fn new<O, R>(github: Github, owner: O, repo: R, number: u64) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        IssueAssignees {
            github,
            owner: owner.into(),
            repo: repo.into(),
            number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!(
            "/repos/{}/{}/issues/{}/assignees{}",
            self.owner, self.repo, self.number, more
        )
    }

    /// add a set of assignees
    pub fn add(&self, assignees: Vec<&str>) -> Future<Issue> {
        self.github.post(&self.path(""), json_lit!({ "assignees": assignees }))
    }
}

/// Provides access to label operations available for an individual issue
pub struct IssueLabels {
    github: Github,
    owner: String,
    repo: String,
    number: u64,
}

impl IssueLabels {
    #[doc(hidden)]
    pub fn new<O, R>(github: Github, owner: O, repo: R, number: u64) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        IssueLabels {
            github,
            owner: owner.into(),
            repo: repo.into(),
            number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!(
            "/repos/{}/{}/issues/{}/labels{}",
            self.owner, self.repo, self.number, more
        )
    }

    /// add a set of labels to this issue ref
    #[allow(clippy::needless_pass_by_value)] // shipped public API
    pub fn add(&self, labels: Vec<&str>) -> Future<Vec<Label>> {
        self.github.post(&self.path(""), json!(labels))
    }

    /// remove a label from this issue
    pub fn remove(&self, label: &str) -> Future<()> {
        self.github.delete(&self.path(&format!("/{}", label)))
    }

    /// replace all labels associated with this issue with a new set.
    /// providing an empty set of labels is the same as clearing the
    /// current labels
    #[allow(clippy::needless_pass_by_value)] // shipped public API
    pub fn set(&self, labels: Vec<&str>) -> Future<Vec<Label>> {
        self.github.put(&self.path(""), json!(labels))
    }

    /// remove all labels from an issue
    pub fn clear(&self) -> Future<()> {
        self.github.delete(&self.path(""))
    }
}

/// Provides access to operations available for a single issue
/// Typically accessed from `github.repo(.., ..).issues().get(number)`
pub struct IssueRef {
    github: Github,
    owner: String,
    repo: String,
    number: u64,
}

impl IssueRef {
    #[doc(hidden)]
    pub fn new<O, R>(github: Github, owner: O, repo: R, number: u64) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        IssueRef {
            github,
            owner: owner.into(),
            repo: repo.into(),
            number,
        }
    }

    /// Request an issue's information
    pub fn get(&self) -> Future<Issue> {
        self.github.get(&self.path(""))
    }

    fn path(&self, more: &str) -> String {
        format!(
            "/repos/{}/{}/issues/{}{}",
            self.owner, self.repo, self.number, more
        )
    }

    /// Return a reference to labels operations available for this issue
    pub fn labels(&self) -> IssueLabels {
        IssueLabels::new(
            self.github.clone(),
            self.owner.as_str(),
            self.repo.as_str(),
            self.number,
        )
    }

    /// Return a reference to assignee operations available for this issue
    pub fn assignees(&self) -> IssueAssignees {
        IssueAssignees::new(
            self.github.clone(),
            self.owner.as_str(),
            self.repo.as_str(),
            self.number,
        )
    }

    /// Edit the issues options
    pub fn edit(&self, is: &IssueOptions) -> Future<Issue> {
        self.github.patch(&self.path(""), json!(is))
    }

    /// Return a reference to comment operations available for this issue
    pub fn comments(&self) -> Comments {
        Comments::new(
            self.github.clone(),
            self.owner.clone(),
            self.repo.clone(),
            self.number,
        )
    }
}

/// Provides access to operations available for a repository issues
/// Typically accessed via `github.repo(..., ...).issues()`
pub struct Issues {
    github: Github,
    owner: String,
    repo: String,
}

impl Issues {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: Github, owner: O, repo: R) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        Issues {
            github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
    }

    pub fn get(&self, number: u64) -> IssueRef {
        IssueRef::new(
            self.github.clone(),
            self.owner.as_str(),
            self.repo.as_str(),
            number,
        )
    }

    pub fn create(&self, is: &IssueOptions) -> Future<Issue> {
        self.github.post(&self.path(""), json!(is))
    }

    /// Return the first page of issues for this repisotiry
    /// See the [github docs](https://developer.github.com/v3/issues/#list-issues-for-a-repository)
    /// for more information
    pub fn list(&self, options: &IssueListOptions) -> Future<Vec<Issue>> {
        let mut uri = vec![self.path("")];
        if let Some(query) = options.serialize() {
            uri.push(query);
        }
        self.github.get(&uri.join("?"))
    }

    /// Return a stream of all issues for this repository
    ///
    /// See the [github docs](https://developer.github.com/v3/issues/#list-issues-for-a-repository)
    /// for more information
    ///
    /// Note: You'll typically want to use a `IssueListOptions` with a `per_page`
    /// of 100 for maximum api credential rate limit efficency
    pub fn iter(&self, options: &IssueListOptions) -> Stream<Issue> {
        let mut uri = vec![self.path("")];
        if let Some(query) = options.serialize() {
            uri.push(query);
        }
        self.github.get_stream(&uri.join("?"))
    }
}

// representations

/// Options used to filter repository issue listings
///
/// See the [github docs](https://developer.github.com/v3/issues/#list-issues-for-a-repository)
/// for more information
///
/// By default this returns up to `30` items. You can
/// request up to `100` using the [per_page](https://developer.github.com/v3/#pagination)
/// parameter
#[derive(Default)]
pub struct IssueListOptions {
    params: HashMap<&'static str, String>,
}

impl IssueListOptions {
    pub fn builder() -> IssueListOptionsBuilder {
        IssueListOptionsBuilder::default()
    }

    pub fn serialize(&self) -> Option<String> {
        if self.params.is_empty() {
            None
        } else {
            let encoded: String = form_urlencoded::Serializer::new(String::new())
                .extend_pairs(&self.params)
                .finish();
            Some(encoded)
        }
    }
}

/// a mutable issue list builder
#[derive(Default)]
pub struct IssueListOptionsBuilder(IssueListOptions);

impl IssueListOptionsBuilder {
    pub fn state(&mut self, state: State) -> &mut Self {
        self.0.params.insert("state", state.to_string());
        self
    }

    pub fn sort(&mut self, sort: Sort) -> &mut Self {
        self.0.params.insert("sort", sort.to_string());
        self
    }

    pub fn asc(&mut self) -> &mut Self {
        self.direction(SortDirection::Asc)
    }

    pub fn desc(&mut self) -> &mut Self {
        self.direction(SortDirection::Desc)
    }

    pub fn direction(&mut self, direction: SortDirection) -> &mut Self {
        self.0.params.insert("direction", direction.to_string());
        self
    }

    pub fn assignee<A>(&mut self, assignee: A) -> &mut Self
    where
        A: Into<String>,
    {
        self.0.params.insert("assignee", assignee.into());
        self
    }

    pub fn creator<C>(&mut self, creator: C) -> &mut Self
    where
        C: Into<String>,
    {
        self.0.params.insert("creator", creator.into());
        self
    }

    pub fn mentioned<M>(&mut self, mentioned: M) -> &mut Self
    where
        M: Into<String>,
    {
        self.0.params.insert("mentioned", mentioned.into());
        self
    }

    pub fn labels<L>(&mut self, labels: Vec<L>) -> &mut Self
    where
        L: Into<String>,
    {
        self.0.params.insert(
            "labels",
            labels
                .into_iter()
                .map(|l| l.into())
                .collect::<Vec<_>>()
                .join(","),
        );
        self
    }

    pub fn since<S>(&mut self, since: S) -> &mut Self
    where
        S: Into<String>,
    {
        self.0.params.insert("since", since.into());
        self
    }

    pub fn per_page(&mut self, n: u32) -> &mut Self {
        self.0.params.insert("per_page", n.to_string());
        self
    }

    pub fn build(&self) -> IssueListOptions {
        IssueListOptions {
            params: self.0.params.clone(),
        }
    }
}

#[derive(Debug, Serialize)]
pub struct IssueOptions {
    pub title: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub body: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub assignee: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub milestone: Option<u64>,
    pub labels: Vec<String>,
}

impl IssueOptions {
    pub fn new<T, B, A, L>(
        title: T,
        body: Option<B>,
        assignee: Option<A>,
        milestone: Option<u64>,
        labels: Vec<L>,
    ) -> IssueOptions
    where
        T: Into<String>,
        B: Into<String>,
        A: Into<String>,
        L: Into<String>,
    {
        IssueOptions {
            title: title.into(),
            body: body.map(|b| b.into()),
            assignee: assignee.map(|a| a.into()),
            milestone,
            labels: labels
                .into_iter()
                .map(|l| l.into())
                .collect::<Vec<String>>(),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Issue {
    pub id: u64,
    pub url: String,
    pub labels_url: String,
    pub comments_url: String,
    pub events_url: String,
    pub html_url: String,
    pub number: u64,
    pub state: String,
    pub title: String,
    pub body: Option<String>,
    pub user: User,
    pub labels: Vec<Label>,
    pub assignee: Option<User>,
    pub locked: bool,
    pub comments: u64,
    pub pull_request: Option<PullRef>,
    pub closed_at: Option<String>,
    pub created_at: String,
    pub updated_at: String,
    pub assignees: Vec<User>,
}

/// A reference to a pull request.
#[derive(Debug, Deserialize)]
pub struct PullRef {
    pub url: String,
    pub html_url: String,
    pub diff_url: String,
    pub patch_url: String,
}

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

    #[test]
    fn default_state() {
        let default: State = Default::default();
        assert_eq!(default, State::Open)
    }

    #[test]
    fn issue_list_reqs() {
        fn test_serialize(tests: Vec<(IssueListOptions, Option<String>)>) {
            for test in tests {
                match test {
                    (k, v) => assert_eq!(k.serialize(), v),
                }
            }
        }
        let tests = vec![
            (IssueListOptions::builder().build(), None),
            (
                IssueListOptions::builder().state(State::Closed).build(),
                Some("state=closed".to_owned()),
            ),
            (
                IssueListOptions::builder()
                    .labels(vec!["foo", "bar"])
                    .build(),
                Some("labels=foo%2Cbar".to_owned()),
            ),
        ];
        test_serialize(tests)
    }

    #[test]
    fn sort_default() {
        let default: Sort = Default::default();
        assert_eq!(default, Sort::Created)
    }

    #[test]
    fn sort_display() {
        for (k, v) in &[
            (Sort::Created, "created"),
            (Sort::Updated, "updated"),
            (Sort::Comments, "comments"),
        ] {
            assert_eq!(k.to_string(), *v)
        }
    }
}
<commit_msg>Percent-encode label in IssueLabels::remove().<commit_after>//! Issues interface
use std::collections::HashMap;
use std::fmt;

use url::form_urlencoded;
use percent_encoding::{percent_encode, PATH_SEGMENT_ENCODE_SET};
use serde::{Deserialize, Serialize};

use crate::comments::Comments;
use crate::labels::Label;
use crate::users::User;
use crate::{Future, Github, SortDirection, Stream};

/// enum representation of github pull and issue state
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum State {
    /// Only open issues
    Open,
    /// Only closed issues
    Closed,
    /// All issues, open or closed
    All,
}

impl fmt::Display for State {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            State::Open => "open",
            State::Closed => "closed",
            State::All => "all",
        }
        .fmt(f)
    }
}

impl Default for State {
    fn default() -> State {
        State::Open
    }
}

/// Sort options available for github issues
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Sort {
    /// sort by creation time of issue
    Created,
    /// sort by the last time issue was updated
    Updated,
    /// sort by number of comments
    Comments,
}

impl fmt::Display for Sort {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Sort::Created => "created",
            Sort::Updated => "updated",
            Sort::Comments => "comments",
        }
        .fmt(f)
    }
}

impl Default for Sort {
    fn default() -> Sort {
        Sort::Created
    }
}

/// Provides access to assignee operations available for an individual issue
pub struct IssueAssignees {
    github: Github,
    owner: String,
    repo: String,
    number: u64,
}

impl IssueAssignees {
    #[doc(hidden)]
    pub fn new<O, R>(github: Github, owner: O, repo: R, number: u64) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        IssueAssignees {
            github,
            owner: owner.into(),
            repo: repo.into(),
            number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!(
            "/repos/{}/{}/issues/{}/assignees{}",
            self.owner, self.repo, self.number, more
        )
    }

    /// add a set of assignees
    pub fn add(&self, assignees: Vec<&str>) -> Future<Issue> {
        self.github.post(&self.path(""), json_lit!({ "assignees": assignees }))
    }
}

/// Provides access to label operations available for an individual issue
pub struct IssueLabels {
    github: Github,
    owner: String,
    repo: String,
    number: u64,
}

impl IssueLabels {
    #[doc(hidden)]
    pub fn new<O, R>(github: Github, owner: O, repo: R, number: u64) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        IssueLabels {
            github,
            owner: owner.into(),
            repo: repo.into(),
            number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!(
            "/repos/{}/{}/issues/{}/labels{}",
            self.owner, self.repo, self.number, more
        )
    }

    /// add a set of labels to this issue ref
    #[allow(clippy::needless_pass_by_value)] // shipped public API
    pub fn add(&self, labels: Vec<&str>) -> Future<Vec<Label>> {
        self.github.post(&self.path(""), json!(labels))
    }

    /// remove a label from this issue
    pub fn remove(&self, label: &str) -> Future<()> {
        let label = percent_encode(label.as_ref(), PATH_SEGMENT_ENCODE_SET);
        self.github.delete(&self.path(&format!("/{}", label)))
    }

    /// replace all labels associated with this issue with a new set.
    /// providing an empty set of labels is the same as clearing the
    /// current labels
    #[allow(clippy::needless_pass_by_value)] // shipped public API
    pub fn set(&self, labels: Vec<&str>) -> Future<Vec<Label>> {
        self.github.put(&self.path(""), json!(labels))
    }

    /// remove all labels from an issue
    pub fn clear(&self) -> Future<()> {
        self.github.delete(&self.path(""))
    }
}

/// Provides access to operations available for a single issue
/// Typically accessed from `github.repo(.., ..).issues().get(number)`
pub struct IssueRef {
    github: Github,
    owner: String,
    repo: String,
    number: u64,
}

impl IssueRef {
    #[doc(hidden)]
    pub fn new<O, R>(github: Github, owner: O, repo: R, number: u64) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        IssueRef {
            github,
            owner: owner.into(),
            repo: repo.into(),
            number,
        }
    }

    /// Request an issue's information
    pub fn get(&self) -> Future<Issue> {
        self.github.get(&self.path(""))
    }

    fn path(&self, more: &str) -> String {
        format!(
            "/repos/{}/{}/issues/{}{}",
            self.owner, self.repo, self.number, more
        )
    }

    /// Return a reference to labels operations available for this issue
    pub fn labels(&self) -> IssueLabels {
        IssueLabels::new(
            self.github.clone(),
            self.owner.as_str(),
            self.repo.as_str(),
            self.number,
        )
    }

    /// Return a reference to assignee operations available for this issue
    pub fn assignees(&self) -> IssueAssignees {
        IssueAssignees::new(
            self.github.clone(),
            self.owner.as_str(),
            self.repo.as_str(),
            self.number,
        )
    }

    /// Edit the issues options
    pub fn edit(&self, is: &IssueOptions) -> Future<Issue> {
        self.github.patch(&self.path(""), json!(is))
    }

    /// Return a reference to comment operations available for this issue
    pub fn comments(&self) -> Comments {
        Comments::new(
            self.github.clone(),
            self.owner.clone(),
            self.repo.clone(),
            self.number,
        )
    }
}

/// Provides access to operations available for a repository issues
/// Typically accessed via `github.repo(..., ...).issues()`
pub struct Issues {
    github: Github,
    owner: String,
    repo: String,
}

impl Issues {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: Github, owner: O, repo: R) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        Issues {
            github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
    }

    pub fn get(&self, number: u64) -> IssueRef {
        IssueRef::new(
            self.github.clone(),
            self.owner.as_str(),
            self.repo.as_str(),
            number,
        )
    }

    pub fn create(&self, is: &IssueOptions) -> Future<Issue> {
        self.github.post(&self.path(""), json!(is))
    }

    /// Return the first page of issues for this repisotiry
    /// See the [github docs](https://developer.github.com/v3/issues/#list-issues-for-a-repository)
    /// for more information
    pub fn list(&self, options: &IssueListOptions) -> Future<Vec<Issue>> {
        let mut uri = vec![self.path("")];
        if let Some(query) = options.serialize() {
            uri.push(query);
        }
        self.github.get(&uri.join("?"))
    }

    /// Return a stream of all issues for this repository
    ///
    /// See the [github docs](https://developer.github.com/v3/issues/#list-issues-for-a-repository)
    /// for more information
    ///
    /// Note: You'll typically want to use a `IssueListOptions` with a `per_page`
    /// of 100 for maximum api credential rate limit efficency
    pub fn iter(&self, options: &IssueListOptions) -> Stream<Issue> {
        let mut uri = vec![self.path("")];
        if let Some(query) = options.serialize() {
            uri.push(query);
        }
        self.github.get_stream(&uri.join("?"))
    }
}

// representations

/// Options used to filter repository issue listings
///
/// See the [github docs](https://developer.github.com/v3/issues/#list-issues-for-a-repository)
/// for more information
///
/// By default this returns up to `30` items. You can
/// request up to `100` using the [per_page](https://developer.github.com/v3/#pagination)
/// parameter
#[derive(Default)]
pub struct IssueListOptions {
    params: HashMap<&'static str, String>,
}

impl IssueListOptions {
    pub fn builder() -> IssueListOptionsBuilder {
        IssueListOptionsBuilder::default()
    }

    pub fn serialize(&self) -> Option<String> {
        if self.params.is_empty() {
            None
        } else {
            let encoded: String = form_urlencoded::Serializer::new(String::new())
                .extend_pairs(&self.params)
                .finish();
            Some(encoded)
        }
    }
}

/// a mutable issue list builder
#[derive(Default)]
pub struct IssueListOptionsBuilder(IssueListOptions);

impl IssueListOptionsBuilder {
    pub fn state(&mut self, state: State) -> &mut Self {
        self.0.params.insert("state", state.to_string());
        self
    }

    pub fn sort(&mut self, sort: Sort) -> &mut Self {
        self.0.params.insert("sort", sort.to_string());
        self
    }

    pub fn asc(&mut self) -> &mut Self {
        self.direction(SortDirection::Asc)
    }

    pub fn desc(&mut self) -> &mut Self {
        self.direction(SortDirection::Desc)
    }

    pub fn direction(&mut self, direction: SortDirection) -> &mut Self {
        self.0.params.insert("direction", direction.to_string());
        self
    }

    pub fn assignee<A>(&mut self, assignee: A) -> &mut Self
    where
        A: Into<String>,
    {
        self.0.params.insert("assignee", assignee.into());
        self
    }

    pub fn creator<C>(&mut self, creator: C) -> &mut Self
    where
        C: Into<String>,
    {
        self.0.params.insert("creator", creator.into());
        self
    }

    pub fn mentioned<M>(&mut self, mentioned: M) -> &mut Self
    where
        M: Into<String>,
    {
        self.0.params.insert("mentioned", mentioned.into());
        self
    }

    pub fn labels<L>(&mut self, labels: Vec<L>) -> &mut Self
    where
        L: Into<String>,
    {
        self.0.params.insert(
            "labels",
            labels
                .into_iter()
                .map(|l| l.into())
                .collect::<Vec<_>>()
                .join(","),
        );
        self
    }

    pub fn since<S>(&mut self, since: S) -> &mut Self
    where
        S: Into<String>,
    {
        self.0.params.insert("since", since.into());
        self
    }

    pub fn per_page(&mut self, n: u32) -> &mut Self {
        self.0.params.insert("per_page", n.to_string());
        self
    }

    pub fn build(&self) -> IssueListOptions {
        IssueListOptions {
            params: self.0.params.clone(),
        }
    }
}

#[derive(Debug, Serialize)]
pub struct IssueOptions {
    pub title: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub body: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub assignee: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub milestone: Option<u64>,
    pub labels: Vec<String>,
}

impl IssueOptions {
    pub fn new<T, B, A, L>(
        title: T,
        body: Option<B>,
        assignee: Option<A>,
        milestone: Option<u64>,
        labels: Vec<L>,
    ) -> IssueOptions
    where
        T: Into<String>,
        B: Into<String>,
        A: Into<String>,
        L: Into<String>,
    {
        IssueOptions {
            title: title.into(),
            body: body.map(|b| b.into()),
            assignee: assignee.map(|a| a.into()),
            milestone,
            labels: labels
                .into_iter()
                .map(|l| l.into())
                .collect::<Vec<String>>(),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Issue {
    pub id: u64,
    pub url: String,
    pub labels_url: String,
    pub comments_url: String,
    pub events_url: String,
    pub html_url: String,
    pub number: u64,
    pub state: String,
    pub title: String,
    pub body: Option<String>,
    pub user: User,
    pub labels: Vec<Label>,
    pub assignee: Option<User>,
    pub locked: bool,
    pub comments: u64,
    pub pull_request: Option<PullRef>,
    pub closed_at: Option<String>,
    pub created_at: String,
    pub updated_at: String,
    pub assignees: Vec<User>,
}

/// A reference to a pull request.
#[derive(Debug, Deserialize)]
pub struct PullRef {
    pub url: String,
    pub html_url: String,
    pub diff_url: String,
    pub patch_url: String,
}

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

    #[test]
    fn default_state() {
        let default: State = Default::default();
        assert_eq!(default, State::Open)
    }

    #[test]
    fn issue_list_reqs() {
        fn test_serialize(tests: Vec<(IssueListOptions, Option<String>)>) {
            for test in tests {
                match test {
                    (k, v) => assert_eq!(k.serialize(), v),
                }
            }
        }
        let tests = vec![
            (IssueListOptions::builder().build(), None),
            (
                IssueListOptions::builder().state(State::Closed).build(),
                Some("state=closed".to_owned()),
            ),
            (
                IssueListOptions::builder()
                    .labels(vec!["foo", "bar"])
                    .build(),
                Some("labels=foo%2Cbar".to_owned()),
            ),
        ];
        test_serialize(tests)
    }

    #[test]
    fn sort_default() {
        let default: Sort = Default::default();
        assert_eq!(default, Sort::Created)
    }

    #[test]
    fn sort_display() {
        for (k, v) in &[
            (Sort::Created, "created"),
            (Sort::Updated, "updated"),
            (Sort::Comments, "comments"),
        ] {
            assert_eq!(k.to_string(), *v)
        }
    }
}
<|endoftext|>