<commit_before>use std::collections::{hash_set, HashSet};
use std::fmt;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use itertools::Itertools;
use rustfmt_config_proc_macro::config_type;
use serde::de::{SeqAccess, Visitor};
use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

use crate::config::lists::*;
use crate::config::Config;

#[config_type]
pub enum NewlineStyle {
    /// Auto-detect based on the raw source input.
    Auto,
    /// Force CRLF (`\r\n`).
    Windows,
    /// Force CR (`\n).
    Unix,
    /// `\r\n` in Windows, `\n`` on other platforms.
    Native,
}

#[config_type]
/// Where to put the opening brace of items (`fn`, `impl`, etc.).
pub enum BraceStyle {
    /// Put the opening brace on the next line.
    AlwaysNextLine,
    /// Put the opening brace on the same line, if possible.
    PreferSameLine,
    /// Prefer the same line except where there is a where-clause, in which
    /// case force the brace to be put on the next line.
    SameLineWhere,
}

#[config_type]
/// Where to put the opening brace of conditional expressions (`if`, `match`, etc.).
pub enum ControlBraceStyle {
    /// K&R style, Rust community default
    AlwaysSameLine,
    /// Stroustrup style
    ClosingNextLine,
    /// Allman style
    AlwaysNextLine,
}

#[config_type]
/// How to indent.
pub enum IndentStyle {
    /// First line on the same line as the opening brace, all lines aligned with
    /// the first line.
    Visual,
    /// First line is on a new line and all lines align with **block** indent.
    Block,
}

#[config_type]
/// How to place a list-like items.
/// FIXME: Issue-3581: this should be renamed to ItemsLayout when publishing 2.0
pub enum Density {
    /// Fit as much on one line as possible.
    Compressed,
    /// Items are placed horizontally if sufficient space, vertically otherwise.
    Tall,
    /// Place every item on a separate line.
    Vertical,
}

#[config_type]
/// Spacing around type combinators.
pub enum TypeDensity {
    /// No spaces around "=" and "+"
    Compressed,
    /// Spaces around " = " and " + "
    Wide,
}

#[config_type]
/// Heuristic settings that can be used to simply
/// the configuration of the granular width configurations
/// like `struct_lit_width`, `array_width`, etc.
pub enum Heuristics {
    /// Turn off any heuristics
    Off,
    /// Turn on max heuristics
    Max,
    /// Use scaled values based on the value of `max_width`
    Default,
}

impl Density {
    pub fn to_list_tactic(self, len: usize) -> ListTactic {
        match self {
            Density::Compressed => ListTactic::Mixed,
            Density::Tall => ListTactic::HorizontalVertical,
            Density::Vertical if len == 1 => ListTactic::Horizontal,
            Density::Vertical => ListTactic::Vertical,
        }
    }
}

#[config_type]
/// Configuration for import groups, i.e. sets of imports separated by newlines.
pub enum GroupImportsTactic {
    /// Keep groups as they are.
    Preserve,
    /// Discard existing groups, and create new groups for
    ///  1. `std` / `core` / `alloc` imports
    ///  2. other imports
    ///  3. `self` / `crate` / `super` imports
    StdExternalCrate,
    /// Discard existing groups, and create a single group for everything
    One,
}

#[config_type]
/// How to merge imports.
pub enum ImportGranularity {
    /// Do not merge imports.
    Preserve,
    /// Use one `use` statement per crate.
    Crate,
    /// Use one `use` statement per module.
    Module,
    /// Use one `use` statement per imported item.
    Item,
    /// Use one `use` statement including all items.
    One,
}

/// Controls how rustfmt should handle case in hexadecimal literals.
#[config_type]
pub enum HexLiteralCase {
    /// Leave the literal as-is
    Preserve,
    /// Ensure all literals use uppercase lettering
    Upper,
    /// Ensure all literals use lowercase lettering
    Lower,
}

#[config_type]
pub enum ReportTactic {
    Always,
    Unnumbered,
    Never,
}

/// What Rustfmt should emit. Mostly corresponds to the `--emit` command line
/// option.
#[config_type]
pub enum EmitMode {
    /// Emits to files.
    Files,
    /// Writes the output to stdout.
    Stdout,
    /// Displays how much of the input file was processed
    Coverage,
    /// Unfancy stdout
    Checkstyle,
    /// Writes the resulting diffs in a JSON format. Returns an empty array
    /// `[]` if there were no diffs.
    Json,
    /// Output the changed lines (for internal value only)
    ModifiedLines,
    /// Checks if a diff can be generated. If so, rustfmt outputs a diff and
    /// quits with exit code 1.
    /// This option is designed to be run in CI where a non-zero exit signifies
    /// non-standard code formatting. Used for `--check`.
    Diff,
}

/// Client-preference for coloured output.
#[config_type]
pub enum Color {
    /// Always use color, whether it is a piped or terminal output
    Always,
    /// Never use color
    Never,
    /// Automatically use color, if supported by terminal
    Auto,
}

#[config_type]
/// rustfmt format style version.
pub enum Version {
    /// 1.x.y. When specified, rustfmt will format in the same style as 1.0.0.
    One,
    /// 2.x.y. When specified, rustfmt will format in the the latest style.
    Two,
}

impl Color {
    /// Whether we should use a coloured terminal.
    pub fn use_colored_tty(self) -> bool {
        match self {
            Color::Always | Color::Auto => true,
            Color::Never => false,
        }
    }
}

/// How chatty should Rustfmt be?
#[config_type]
pub enum Verbosity {
    /// Emit more.
    Verbose,
    /// Default.
    Normal,
    /// Emit as little as possible.
    Quiet,
}

#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
pub struct WidthHeuristics {
    // Maximum width of the args of a function call before falling back
    // to vertical formatting.
    pub fn_call_width: usize,
    // Maximum width of the args of a function-like attributes before falling
    // back to vertical formatting.
    pub attr_fn_like_width: usize,
    // Maximum width in the body of a struct lit before falling back to
    // vertical formatting.
    pub struct_lit_width: usize,
    // Maximum width in the body of a struct variant before falling back
    // to vertical formatting.
    pub struct_variant_width: usize,
    // Maximum width of an array literal before falling back to vertical
    // formatting.
    pub array_width: usize,
    // Maximum length of a chain to fit on a single line.
    pub chain_width: usize,
    // Maximum line length for single line if-else expressions. A value
    // of zero means always break if-else expressions.
    pub single_line_if_else_max_width: usize,
}

impl fmt::Display for WidthHeuristics {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl WidthHeuristics {
    // Using this WidthHeuristics means we ignore heuristics.
    pub fn null() -> WidthHeuristics {
        WidthHeuristics {
            fn_call_width: usize::max_value(),
            attr_fn_like_width: usize::max_value(),
            struct_lit_width: 0,
            struct_variant_width: 0,
            array_width: usize::max_value(),
            chain_width: usize::max_value(),
            single_line_if_else_max_width: 0,
        }
    }

    pub fn set(max_width: usize) -> WidthHeuristics {
        WidthHeuristics {
            fn_call_width: max_width,
            attr_fn_like_width: max_width,
            struct_lit_width: max_width,
            struct_variant_width: max_width,
            array_width: max_width,
            chain_width: max_width,
            single_line_if_else_max_width: max_width,
        }
    }

    // scale the default WidthHeuristics according to max_width
    pub fn scaled(max_width: usize) -> WidthHeuristics {
        const DEFAULT_MAX_WIDTH: usize = 100;
        let max_width_ratio = if max_width > DEFAULT_MAX_WIDTH {
            let ratio = max_width as f32 / DEFAULT_MAX_WIDTH as f32;
            // round to the closest 0.1
            (ratio * 10.0).round() / 10.0
        } else {
            1.0
        };
        WidthHeuristics {
            fn_call_width: (60.0 * max_width_ratio).round() as usize,
            attr_fn_like_width: (70.0 * max_width_ratio).round() as usize,
            struct_lit_width: (18.0 * max_width_ratio).round() as usize,
            struct_variant_width: (35.0 * max_width_ratio).round() as usize,
            array_width: (60.0 * max_width_ratio).round() as usize,
            chain_width: (60.0 * max_width_ratio).round() as usize,
            single_line_if_else_max_width: (50.0 * max_width_ratio).round() as usize,
        }
    }
}

impl ::std::str::FromStr for WidthHeuristics {
    type Err = &'static str;

    fn from_str(_: &str) -> Result<Self, Self::Err> {
        Err("WidthHeuristics is not parsable")
    }
}

impl Default for EmitMode {
    fn default() -> EmitMode {
        EmitMode::Files
    }
}

/// A set of directories, files and modules that rustfmt should ignore.
#[derive(Default, Clone, Debug, PartialEq)]
pub struct IgnoreList {
    /// A set of path specified in rustfmt.toml.
    path_set: HashSet<PathBuf>,
    /// A path to rustfmt.toml.
    rustfmt_toml_path: PathBuf,
}

impl fmt::Display for IgnoreList {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "[{}]",
            self.path_set
                .iter()
                .format_with(", ", |path, f| f(&format_args!(
                    "{}",
                    path.to_string_lossy()
                )))
        )
    }
}

impl Serialize for IgnoreList {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut seq = serializer.serialize_seq(Some(self.path_set.len()))?;
        for e in &self.path_set {
            seq.serialize_element(e)?;
        }
        seq.end()
    }
}

impl<'de> Deserialize<'de> for IgnoreList {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct HashSetVisitor;
        impl<'v> Visitor<'v> for HashSetVisitor {
            type Value = HashSet<PathBuf>;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                formatter.write_str("a sequence of path")
            }

            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
            where
                A: SeqAccess<'v>,
            {
                let mut path_set = HashSet::new();
                while let Some(elem) = seq.next_element()? {
                    path_set.insert(elem);
                }
                Ok(path_set)
            }
        }
        Ok(IgnoreList {
            path_set: deserializer.deserialize_seq(HashSetVisitor)?,
            rustfmt_toml_path: PathBuf::new(),
        })
    }
}

impl<'a> IntoIterator for &'a IgnoreList {
    type Item = &'a PathBuf;
    type IntoIter = hash_set::Iter<'a, PathBuf>;

    fn into_iter(self) -> Self::IntoIter {
        self.path_set.iter()
    }
}

impl IgnoreList {
    pub fn add_prefix(&mut self, dir: &Path) {
        self.rustfmt_toml_path = dir.to_path_buf();
    }

    pub fn rustfmt_toml_path(&self) -> &Path {
        &self.rustfmt_toml_path
    }
}

impl FromStr for IgnoreList {
    type Err = &'static str;

    fn from_str(_: &str) -> Result<Self, Self::Err> {
        Err("IgnoreList is not parsable")
    }
}

/// Maps client-supplied options to Rustfmt's internals, mostly overriding
/// values in a config with values from the command line.
pub trait CliOptions {
    fn apply_to(self, config: &mut Config);
    fn config_path(&self) -> Option<&Path>;
}

/// The edition of the syntax and semntics of code (RFC 2052).
#[config_type]
pub enum Edition {
    #[value = "2015"]
    #[doc_hint = "2015"]
    /// Edition 2015.
    Edition2015,
    #[value = "2018"]
    #[doc_hint = "2018"]
    /// Edition 2018.
    Edition2018,
    #[value = "2021"]
    #[doc_hint = "2021"]
    /// Edition 2021.
    Edition2021,
}

impl Default for Edition {
    fn default() -> Edition {
        Edition::Edition2015
    }
}

impl From<Edition> for rustc_span::edition::Edition {
    fn from(edition: Edition) -> Self {
        match edition {
            Edition::Edition2015 => Self::Edition2015,
            Edition::Edition2018 => Self::Edition2018,
            Edition::Edition2021 => Self::Edition2021,
        }
    }
}

impl PartialOrd for Edition {
    fn partial_cmp(&self, other: &Edition) -> Option<std::cmp::Ordering> {
        rustc_span::edition::Edition::partial_cmp(&(*self).into(), &(*other).into())
    }
}

/// Controls how rustfmt should handle leading pipes on match arms.
#[config_type]
pub enum MatchArmLeadingPipe {
    /// Place leading pipes on all match arms
    Always,
    /// Never emit leading pipes on match arms
    Never,
    /// Preserve any existing leading pipes
    Preserve,
}
<commit_msg> Remove grave accent that shouldn't be there<commit_after>use std::collections::{hash_set, HashSet};
use std::fmt;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use itertools::Itertools;
use rustfmt_config_proc_macro::config_type;
use serde::de::{SeqAccess, Visitor};
use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

use crate::config::lists::*;
use crate::config::Config;

#[config_type]
pub enum NewlineStyle {
    /// Auto-detect based on the raw source input.
    Auto,
    /// Force CRLF (`\r\n`).
    Windows,
    /// Force CR (`\n).
    Unix,
    /// `\r\n` in Windows, `\n` on other platforms.
    Native,
}

#[config_type]
/// Where to put the opening brace of items (`fn`, `impl`, etc.).
pub enum BraceStyle {
    /// Put the opening brace on the next line.
    AlwaysNextLine,
    /// Put the opening brace on the same line, if possible.
    PreferSameLine,
    /// Prefer the same line except where there is a where-clause, in which
    /// case force the brace to be put on the next line.
    SameLineWhere,
}

#[config_type]
/// Where to put the opening brace of conditional expressions (`if`, `match`, etc.).
pub enum ControlBraceStyle {
    /// K&R style, Rust community default
    AlwaysSameLine,
    /// Stroustrup style
    ClosingNextLine,
    /// Allman style
    AlwaysNextLine,
}

#[config_type]
/// How to indent.
pub enum IndentStyle {
    /// First line on the same line as the opening brace, all lines aligned with
    /// the first line.
    Visual,
    /// First line is on a new line and all lines align with **block** indent.
    Block,
}

#[config_type]
/// How to place a list-like items.
/// FIXME: Issue-3581: this should be renamed to ItemsLayout when publishing 2.0
pub enum Density {
    /// Fit as much on one line as possible.
    Compressed,
    /// Items are placed horizontally if sufficient space, vertically otherwise.
    Tall,
    /// Place every item on a separate line.
    Vertical,
}

#[config_type]
/// Spacing around type combinators.
pub enum TypeDensity {
    /// No spaces around "=" and "+"
    Compressed,
    /// Spaces around " = " and " + "
    Wide,
}

#[config_type]
/// Heuristic settings that can be used to simply
/// the configuration of the granular width configurations
/// like `struct_lit_width`, `array_width`, etc.
pub enum Heuristics {
    /// Turn off any heuristics
    Off,
    /// Turn on max heuristics
    Max,
    /// Use scaled values based on the value of `max_width`
    Default,
}

impl Density {
    pub fn to_list_tactic(self, len: usize) -> ListTactic {
        match self {
            Density::Compressed => ListTactic::Mixed,
            Density::Tall => ListTactic::HorizontalVertical,
            Density::Vertical if len == 1 => ListTactic::Horizontal,
            Density::Vertical => ListTactic::Vertical,
        }
    }
}

#[config_type]
/// Configuration for import groups, i.e. sets of imports separated by newlines.
pub enum GroupImportsTactic {
    /// Keep groups as they are.
    Preserve,
    /// Discard existing groups, and create new groups for
    ///  1. `std` / `core` / `alloc` imports
    ///  2. other imports
    ///  3. `self` / `crate` / `super` imports
    StdExternalCrate,
    /// Discard existing groups, and create a single group for everything
    One,
}

#[config_type]
/// How to merge imports.
pub enum ImportGranularity {
    /// Do not merge imports.
    Preserve,
    /// Use one `use` statement per crate.
    Crate,
    /// Use one `use` statement per module.
    Module,
    /// Use one `use` statement per imported item.
    Item,
    /// Use one `use` statement including all items.
    One,
}

/// Controls how rustfmt should handle case in hexadecimal literals.
#[config_type]
pub enum HexLiteralCase {
    /// Leave the literal as-is
    Preserve,
    /// Ensure all literals use uppercase lettering
    Upper,
    /// Ensure all literals use lowercase lettering
    Lower,
}

#[config_type]
pub enum ReportTactic {
    Always,
    Unnumbered,
    Never,
}

/// What Rustfmt should emit. Mostly corresponds to the `--emit` command line
/// option.
#[config_type]
pub enum EmitMode {
    /// Emits to files.
    Files,
    /// Writes the output to stdout.
    Stdout,
    /// Displays how much of the input file was processed
    Coverage,
    /// Unfancy stdout
    Checkstyle,
    /// Writes the resulting diffs in a JSON format. Returns an empty array
    /// `[]` if there were no diffs.
    Json,
    /// Output the changed lines (for internal value only)
    ModifiedLines,
    /// Checks if a diff can be generated. If so, rustfmt outputs a diff and
    /// quits with exit code 1.
    /// This option is designed to be run in CI where a non-zero exit signifies
    /// non-standard code formatting. Used for `--check`.
    Diff,
}

/// Client-preference for coloured output.
#[config_type]
pub enum Color {
    /// Always use color, whether it is a piped or terminal output
    Always,
    /// Never use color
    Never,
    /// Automatically use color, if supported by terminal
    Auto,
}

#[config_type]
/// rustfmt format style version.
pub enum Version {
    /// 1.x.y. When specified, rustfmt will format in the same style as 1.0.0.
    One,
    /// 2.x.y. When specified, rustfmt will format in the the latest style.
    Two,
}

impl Color {
    /// Whether we should use a coloured terminal.
    pub fn use_colored_tty(self) -> bool {
        match self {
            Color::Always | Color::Auto => true,
            Color::Never => false,
        }
    }
}

/// How chatty should Rustfmt be?
#[config_type]
pub enum Verbosity {
    /// Emit more.
    Verbose,
    /// Default.
    Normal,
    /// Emit as little as possible.
    Quiet,
}

#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
pub struct WidthHeuristics {
    // Maximum width of the args of a function call before falling back
    // to vertical formatting.
    pub fn_call_width: usize,
    // Maximum width of the args of a function-like attributes before falling
    // back to vertical formatting.
    pub attr_fn_like_width: usize,
    // Maximum width in the body of a struct lit before falling back to
    // vertical formatting.
    pub struct_lit_width: usize,
    // Maximum width in the body of a struct variant before falling back
    // to vertical formatting.
    pub struct_variant_width: usize,
    // Maximum width of an array literal before falling back to vertical
    // formatting.
    pub array_width: usize,
    // Maximum length of a chain to fit on a single line.
    pub chain_width: usize,
    // Maximum line length for single line if-else expressions. A value
    // of zero means always break if-else expressions.
    pub single_line_if_else_max_width: usize,
}

impl fmt::Display for WidthHeuristics {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl WidthHeuristics {
    // Using this WidthHeuristics means we ignore heuristics.
    pub fn null() -> WidthHeuristics {
        WidthHeuristics {
            fn_call_width: usize::max_value(),
            attr_fn_like_width: usize::max_value(),
            struct_lit_width: 0,
            struct_variant_width: 0,
            array_width: usize::max_value(),
            chain_width: usize::max_value(),
            single_line_if_else_max_width: 0,
        }
    }

    pub fn set(max_width: usize) -> WidthHeuristics {
        WidthHeuristics {
            fn_call_width: max_width,
            attr_fn_like_width: max_width,
            struct_lit_width: max_width,
            struct_variant_width: max_width,
            array_width: max_width,
            chain_width: max_width,
            single_line_if_else_max_width: max_width,
        }
    }

    // scale the default WidthHeuristics according to max_width
    pub fn scaled(max_width: usize) -> WidthHeuristics {
        const DEFAULT_MAX_WIDTH: usize = 100;
        let max_width_ratio = if max_width > DEFAULT_MAX_WIDTH {
            let ratio = max_width as f32 / DEFAULT_MAX_WIDTH as f32;
            // round to the closest 0.1
            (ratio * 10.0).round() / 10.0
        } else {
            1.0
        };
        WidthHeuristics {
            fn_call_width: (60.0 * max_width_ratio).round() as usize,
            attr_fn_like_width: (70.0 * max_width_ratio).round() as usize,
            struct_lit_width: (18.0 * max_width_ratio).round() as usize,
            struct_variant_width: (35.0 * max_width_ratio).round() as usize,
            array_width: (60.0 * max_width_ratio).round() as usize,
            chain_width: (60.0 * max_width_ratio).round() as usize,
            single_line_if_else_max_width: (50.0 * max_width_ratio).round() as usize,
        }
    }
}

impl ::std::str::FromStr for WidthHeuristics {
    type Err = &'static str;

    fn from_str(_: &str) -> Result<Self, Self::Err> {
        Err("WidthHeuristics is not parsable")
    }
}

impl Default for EmitMode {
    fn default() -> EmitMode {
        EmitMode::Files
    }
}

/// A set of directories, files and modules that rustfmt should ignore.
#[derive(Default, Clone, Debug, PartialEq)]
pub struct IgnoreList {
    /// A set of path specified in rustfmt.toml.
    path_set: HashSet<PathBuf>,
    /// A path to rustfmt.toml.
    rustfmt_toml_path: PathBuf,
}

impl fmt::Display for IgnoreList {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "[{}]",
            self.path_set
                .iter()
                .format_with(", ", |path, f| f(&format_args!(
                    "{}",
                    path.to_string_lossy()
                )))
        )
    }
}

impl Serialize for IgnoreList {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut seq = serializer.serialize_seq(Some(self.path_set.len()))?;
        for e in &self.path_set {
            seq.serialize_element(e)?;
        }
        seq.end()
    }
}

impl<'de> Deserialize<'de> for IgnoreList {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct HashSetVisitor;
        impl<'v> Visitor<'v> for HashSetVisitor {
            type Value = HashSet<PathBuf>;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                formatter.write_str("a sequence of path")
            }

            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
            where
                A: SeqAccess<'v>,
            {
                let mut path_set = HashSet::new();
                while let Some(elem) = seq.next_element()? {
                    path_set.insert(elem);
                }
                Ok(path_set)
            }
        }
        Ok(IgnoreList {
            path_set: deserializer.deserialize_seq(HashSetVisitor)?,
            rustfmt_toml_path: PathBuf::new(),
        })
    }
}

impl<'a> IntoIterator for &'a IgnoreList {
    type Item = &'a PathBuf;
    type IntoIter = hash_set::Iter<'a, PathBuf>;

    fn into_iter(self) -> Self::IntoIter {
        self.path_set.iter()
    }
}

impl IgnoreList {
    pub fn add_prefix(&mut self, dir: &Path) {
        self.rustfmt_toml_path = dir.to_path_buf();
    }

    pub fn rustfmt_toml_path(&self) -> &Path {
        &self.rustfmt_toml_path
    }
}

impl FromStr for IgnoreList {
    type Err = &'static str;

    fn from_str(_: &str) -> Result<Self, Self::Err> {
        Err("IgnoreList is not parsable")
    }
}

/// Maps client-supplied options to Rustfmt's internals, mostly overriding
/// values in a config with values from the command line.
pub trait CliOptions {
    fn apply_to(self, config: &mut Config);
    fn config_path(&self) -> Option<&Path>;
}

/// The edition of the syntax and semntics of code (RFC 2052).
#[config_type]
pub enum Edition {
    #[value = "2015"]
    #[doc_hint = "2015"]
    /// Edition 2015.
    Edition2015,
    #[value = "2018"]
    #[doc_hint = "2018"]
    /// Edition 2018.
    Edition2018,
    #[value = "2021"]
    #[doc_hint = "2021"]
    /// Edition 2021.
    Edition2021,
}

impl Default for Edition {
    fn default() -> Edition {
        Edition::Edition2015
    }
}

impl From<Edition> for rustc_span::edition::Edition {
    fn from(edition: Edition) -> Self {
        match edition {
            Edition::Edition2015 => Self::Edition2015,
            Edition::Edition2018 => Self::Edition2018,
            Edition::Edition2021 => Self::Edition2021,
        }
    }
}

impl PartialOrd for Edition {
    fn partial_cmp(&self, other: &Edition) -> Option<std::cmp::Ordering> {
        rustc_span::edition::Edition::partial_cmp(&(*self).into(), &(*other).into())
    }
}

/// Controls how rustfmt should handle leading pipes on match arms.
#[config_type]
pub enum MatchArmLeadingPipe {
    /// Place leading pipes on all match arms
    Always,
    /// Never emit leading pipes on match arms
    Never,
    /// Preserve any existing leading pipes
    Preserve,
}
<|endoftext|>


<commit_before>use super::super::api;

pub struct Tree {
    root: Box<Node>
}

struct Node {
    left: Option<Box<Node>>,
    right: Option<Box<Node>>,
    criterion: Option<usize>,
    target: Option<api::Target>
}

pub fn id3<T>(data: &api::DataSet<T>, solver: &api::Solver<T>, criterions: &Vec<Box<api::Criterion<T>>>) -> Tree {
    Tree {
        root: create_node(data, &api::all_view(data), solver, criterions)
    }
}

fn create_node<T>(data: &api::DataSet<T>, view: &api::DataSetView, solver: &api::Solver<T>, criterions: &Vec<Box<api::Criterion<T>>>) -> Box<Node> {
    let mut max = 0f64;
    let mut index = 0usize;
    for (i, criterion) in criterions.iter().enumerate() {
        let current = solver(data, view, &**criterion);
        if max < current {
            max = current;
            index = i;
        }
    }
    let criterion = &criterions[index];
    let mut left_records = Vec::new();
    let mut right_records = Vec::new();
    for i in view.iter() {
        let record = &data.records[*i];
        if criterion(&record.0) {
            right_records.push(*i)
        } else {
            left_records.push(*i)
        }
    }
    if right_records.is_empty() || left_records.is_empty() {
        let target = if right_records.len() < left_records.len() {
            calculate_target(data, &left_records)
        } else {
            calculate_target(data, &right_records)
        };
        Box::new(Node{left: None, right: None, criterion: None, target: Some(target)})
    } else {
        Box::new(Node{
            left: Some(create_node(data, &left_records, solver, criterions)),
            right: Some(create_node(data, &right_records, solver, criterions)),
            criterion: Some(index),
            target: None
        })
    }
}

fn calculate_target<T>(data: &api::DataSet<T>, view: &api::DataSetView) -> api::Target {
    let mut classes = vec![0; data.target_count];
    for index in view.iter() {
        let record = &data.records[*index];
        classes[record.1 as usize] += 1;
    }
    let mut max_class = 0;
    let mut target = 0;
    for (i, class) in classes.iter().enumerate() {
        if max_class < *class {
            max_class = *class;
            target = i;
        }
    }
    target as u32
}

fn apply_node<T>(node: &Box<Node>, record: &T, criterions: &Vec<Box<api::Criterion<T>>>) -> api::Target {
    match node.target {
        Some(target) => target,
        None => {
            let criterion = node.criterion.unwrap();
            if criterions[criterion](record) {
                match node.right {
                    Some(ref nnode) => apply_node(nnode, record, criterions),
                    None => panic!("assimetric tree")
                }
            } else {
                match node.left {
                    Some(ref nnode) => apply_node(nnode, record, criterions),
                    None => panic!("assimetric tree")
                }
            }
        }
    }
}

impl Tree {

    pub fn apply<T>(&self, record: &T, criterions: &Vec<Box<api::Criterion<T>>>) -> api::Target {
        apply_node(&self.root, record, criterions)
    }
}
<commit_msg>#1 Use 'enum pattern' for tree<commit_after>use super::super::api;

pub struct Tree {
    root: Box<Node>
}

enum Node {
    Fork(Box<Node>, Box<Node>, usize),
    Target(api::Target)
 }

pub fn id3<T>(data: &api::DataSet<T>, solver: &api::Solver<T>, criterions: &Vec<Box<api::Criterion<T>>>) -> Tree {
    Tree {
        root: create_node(data, &api::all_view(data), solver, criterions)
    }
}

fn create_node<T>(data: &api::DataSet<T>, view: &api::DataSetView, solver: &api::Solver<T>, criterions: &Vec<Box<api::Criterion<T>>>) -> Box<Node> {
    let mut max = 0f64;
    let mut index = 0usize;
    for (i, criterion) in criterions.iter().enumerate() {
        let current = solver(data, view, &**criterion);
        if max < current {
            max = current;
            index = i;
        }
    }
    let criterion = &criterions[index];
    let mut left_records = Vec::new();
    let mut right_records = Vec::new();
    for i in view.iter() {
        let record = &data.records[*i];
        if criterion(&record.0) {
            right_records.push(*i)
        } else {
            left_records.push(*i)
        }
    }
    if right_records.is_empty() || left_records.is_empty() {
        let target = if right_records.len() < left_records.len() {
            calculate_target(data, &left_records)
        } else {
            calculate_target(data, &right_records)
        };
        Box::new(Node::Target(target))
    } else {
        Box::new(Node::Fork(create_node(data, &left_records, solver, criterions), create_node(data, &right_records, solver, criterions), index))
    }
}

fn calculate_target<T>(data: &api::DataSet<T>, view: &api::DataSetView) -> api::Target {
    let mut classes = vec![0; data.target_count];
    for index in view.iter() {
        let record = &data.records[*index];
        classes[record.1 as usize] += 1;
    }
    let mut max_class = 0;
    let mut target = 0;
    for (i, class) in classes.iter().enumerate() {
        if max_class < *class {
            max_class = *class;
            target = i;
        }
    }
    target as u32
}

fn apply_node<T>(node: &Box<Node>, record: &T, criterions: &Vec<Box<api::Criterion<T>>>) -> api::Target {
    match **node {
        Node::Target(target) => target,
        Node::Fork(ref left, ref right, criterion) => {
            if criterions[criterion](record) {
                apply_node(right, record, criterions)
            } else {
                apply_node(left, record, criterions)
            }
        }
    }
}

impl Tree {

    pub fn apply<T>(&self, record: &T, criterions: &Vec<Box<api::Criterion<T>>>) -> api::Target {
        apply_node(&self.root, record, criterions)
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod extra;
extern mod rustc;
extern mod rustpkg;

use extra::time;
use rustc::driver::driver::host_triple;
use rustpkg::api;
use std::from_str::{from_str};
use std::io::fs::{mkdir, File};
use std::io::buffered::BufferedReader;
use std::io;
use std::option::{Option};
use std::os;
use std::run;
use std::str;
use std::vec;

struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl ToStr for Version {
    fn to_str(&self) -> ~str {
        format!("{:u}.{:u}", self.major, self.minor)
    }
}

impl Ord for Version {
    fn lt(&self, other: &Version) -> bool {
        self.major < other.major || (self.major == other.major && self.minor < other.minor)
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail!("Package script error: Failed to `cd` into `{}`", path.display());
    }
}

fn do_install(args: ~[~str]) {
    let sysroot_arg = args[1].clone();
    let sysroot_path = from_str(sysroot_arg).unwrap();

    let pcre_libs = match os::getenv("PCRE_LIBS") {
        None            => {
            let pcre_config_output = io::io_error::cond.trap(|e: io::IoError| {
                match e.kind {
                    io::FileNotFound => fail!("Package script error: Could not run `pcre-config` because no such executable is in the executable search PATH. Make sure that you have installed a dev package for libpcre and/or make sure that libpcre's bindir is added to your PATH (currently \"{}\").", os::getenv("PATH").unwrap_or(~"")),
                    _ => fail!("Package script error: Could not run `pcre-config`: {}", e.to_str())
                }
            }).inside(|| -> run::ProcessOutput {
                run::process_output("pcre-config", [~"--libs"])
            });
            if !pcre_config_output.status.success() {
                fail!("Package script error: `pcre-config` failed");
            }
            let output_ptr = vec::raw::to_ptr(pcre_config_output.output);
            let output_len = pcre_config_output.output.len();
            let libs_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            os::setenv("PCRE_LIBS", libs_str);
            libs_str
        },
        Some(pcre_libs) => pcre_libs
    };
    // `pcre-config` adds a newline to the end, which we need to trim away because newlines
    // in link_args cause build issues.
    let trimmed_pcre_libs = pcre_libs.trim();
    debug!("PCRE_LIBS=\"{:s}\"", trimmed_pcre_libs);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.join("build").join(host_triple());
    if !target_build_path.exists() {
        if !io::result(|| mkdir(&target_build_path, 0x1FF)).is_ok() {
            fail!("Package script error: Failed to create target build directory `{}`", target_build_path.display());
        }
    }
    let out_path = target_build_path.join("pcre");
    if !out_path.exists() {
        if !io::result(|| mkdir(&out_path, 0x1FF)).is_ok() {
            fail!("Package script error: Failed to create output directory `{}`", out_path.display());
        }
    }

    let versioncheck_rs_path = out_path.join("versioncheck.rs");
    {
        let mut w = match File::create(&versioncheck_rs_path) {
            None    => fail!("Package script error: Failed to open `{}` for writing", versioncheck_rs_path.display()),
            Some(w) => w
        };
        write!(&mut w as &mut Writer, "\
\\#[feature(globs)];
\\#[feature(link_args)];
use std::c_str::\\{CString\\};
use std::libc::*;
use std::ptr;
use std::vec;

type options = c_int;
struct pcre;
struct pcre_extra;

\\#[link_args = \"{:s}\"]
extern \\{
    static pcre_free: extern \"C\" fn(ptr: *c_void);

    fn pcre_compile(pattern: *c_char, options: options, errptr: *mut *c_char, erroffset: *mut c_int, tableptr: *c_uchar) -> *pcre;
    fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *c_char;
\\}

fn main () \\{
    unsafe \\{
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_owned();

        let pattern = \"^\\\\\\\\d+\\\\\\\\.\\\\\\\\d+\";
        pattern.with_c_str(|pattern_c_str| \\{
            let mut err: *c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if ptr::is_null(code) \\{
                if ptr::is_null(code) \\{
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() \\{
                        None          => fail!(\"pcre_compile() failed at offset \\{\\}\", erroffset as uint),
                        Some(err_str) => fail!(\"pcre_compile() failed at offset \\{\\}: \\{\\}\", erroffset as uint, err_str)
                    \\}
                \\}
            \\}
            assert!(ptr::is_not_null(code));

            let ovecsize = 1 * 3;
            let mut ovector: ~[c_int] = vec::from_elem(ovecsize, 0 as c_int);
            version_str.with_c_str_unchecked(|version_c_str| \\{
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, vec::raw::to_mut_ptr(ovector), ovecsize as c_int);
                if rc < 0 \\{
                    fail!(\"pcre_exec() failed\");
                \\}

                print(version_str.slice_to(ovector[1] as uint));
            \\});

            pcre_free(code as *c_void);
        \\});
    \\}
\\}
", trimmed_pcre_libs);
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rustc_run_output = run::process_output("rustc", [~"versioncheck.rs"]);
    if !rustc_run_output.status.success() {
        println(str::from_utf8(rustc_run_output.output));
        println(str::from_utf8(rustc_run_output.error));
        fail!("Package script error: `rustc versioncheck.rs` failed: {}", rustc_run_output.status);
    }
    let version_check_output = run::process_output("./versioncheck", []);
    if !version_check_output.status.success() {
        println(str::from_utf8(version_check_output.output));
        println(str::from_utf8(version_check_output.error));
        fail!("versioncheck error: {}", version_check_output.status);
    }
    cd(&workspace_path);

    let output_ptr = vec::raw::to_ptr(version_check_output.output);
    let output_len = version_check_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.rsplit('\n');
    let version_str: ~str = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_owned()
    };

    debug!("libpcre version {:s}", version_str);

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str) {
        None               => fail!("Package script error: Failed to parse version string '{}'", version_str),
        Some(pcre_version) => pcre_version
    };

    if pcre_version < min_required_version {
        fail!("Package script error: Found libpcre version {}, but at least version {} is required", version_str, min_required_version.to_str());
    }

    let src_path = workspace_path.join("src");

    // Output `src/pcre/detail/native.rs`
    let detail_src_path = src_path.join("pcre").join("detail");
    if !detail_src_path.exists() {
        fail!("Package script error: Source directory `{}` does not exist.", detail_src_path.display());
    }
    let native_rs_path = detail_src_path.join("native.rs");
    let native_rs_in_path = detail_src_path.join("native.rs.in");
    if !native_rs_in_path.exists() {
        fail!("Package script error: Source file `{}` does not exist.", native_rs_in_path.display());
    }
    {
        let r = match File::open(&native_rs_in_path) {
            None    => fail!("Package script error: Failed to open `{}` for reading", native_rs_in_path.display()),
            Some(r) => r
        };
        let mut w = match File::create(&native_rs_path) {
            None    => fail!("Package script error: Failed to open `{}` for writing", native_rs_path.display()),
            Some(w) => w
        };
        write!(&mut w as &mut Writer, "// -*- buffer-read-only: t -*-\n");
        write!(&mut w as &mut Writer, "// Generated by {:s} on {:s}\n", args[0], time::now().rfc822());

        let mut buffered_reader = BufferedReader::new(r);
        while !buffered_reader.eof() {
            let line = buffered_reader.read_line();
            if line.is_some() {
                let substituted_line = str::replace(line.unwrap(), "@PCRE_LIBS@", trimmed_pcre_libs);
                write!(&mut w as &mut Writer, "{:s}", substituted_line);
            }
        }
    }

    api::build_lib(sysroot_path, workspace_path, ~"pcre", rustpkg::version::ExactRevision(~"0.1"), from_str("mod.rs").unwrap());
}

fn do_configs(args: ~[~str]) {
    drop(args);
}

fn main() {
    let args = os::args();
    let args_len = args.len();

    if args_len < 2 {
        fail!("Package script requires a directory where rustc libraries live as the first argument");
    } else if args_len < 3 {
        fail!("Package script requires a command as the second argument");
    }

    if args[2] == ~"install" {
        do_install(args);
    } else if args[2] == ~"configs" {
        do_configs(args);
    } else {
        fail!("Package script error: Unsupported command `{}`", args[2]);
    }
}
<commit_msg>Updates for std::run API changes<commit_after>// Copyright 2013 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod extra;
extern mod rustc;
extern mod rustpkg;

use extra::time;
use rustc::driver::driver::host_triple;
use rustpkg::api;
use std::from_str::{from_str};
use std::io::fs::{mkdir, File};
use std::io::buffered::BufferedReader;
use std::io;
use std::option::{Option};
use std::os;
use std::run;
use std::str;
use std::vec;

struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl ToStr for Version {
    fn to_str(&self) -> ~str {
        format!("{:u}.{:u}", self.major, self.minor)
    }
}

impl Ord for Version {
    fn lt(&self, other: &Version) -> bool {
        self.major < other.major || (self.major == other.major && self.minor < other.minor)
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail!("Package script error: Failed to `cd` into `{}`", path.display());
    }
}

fn do_install(args: ~[~str]) {
    let sysroot_arg = args[1].clone();
    let sysroot_path = from_str(sysroot_arg).unwrap();

    let pcre_libs = match os::getenv("PCRE_LIBS") {
        None            => {
            let pcre_config_output = io::io_error::cond.trap(|e: io::IoError| {
                match e.kind {
                    io::FileNotFound => fail!("Package script error: Could not run `pcre-config` because no such executable is in the executable search PATH. Make sure that you have installed a dev package for libpcre and/or make sure that libpcre's bindir is added to your PATH (currently \"{}\").", os::getenv("PATH").unwrap_or(~"")),
                    _ => fail!("Package script error: Could not run `pcre-config`: {}", e.to_str())
                }
            }).inside(|| -> run::ProcessOutput {
                run::process_output("pcre-config", [~"--libs"]).expect("failed to exec `pcre-config`")
            });
            if !pcre_config_output.status.success() {
                fail!("Package script error: `pcre-config` failed");
            }
            let output_ptr = vec::raw::to_ptr(pcre_config_output.output);
            let output_len = pcre_config_output.output.len();
            let libs_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            os::setenv("PCRE_LIBS", libs_str);
            libs_str
        },
        Some(pcre_libs) => pcre_libs
    };
    // `pcre-config` adds a newline to the end, which we need to trim away because newlines
    // in link_args cause build issues.
    let trimmed_pcre_libs = pcre_libs.trim();
    debug!("PCRE_LIBS=\"{:s}\"", trimmed_pcre_libs);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.join("build").join(host_triple());
    if !target_build_path.exists() {
        if !io::result(|| mkdir(&target_build_path, 0x1FF)).is_ok() {
            fail!("Package script error: Failed to create target build directory `{}`", target_build_path.display());
        }
    }
    let out_path = target_build_path.join("pcre");
    if !out_path.exists() {
        if !io::result(|| mkdir(&out_path, 0x1FF)).is_ok() {
            fail!("Package script error: Failed to create output directory `{}`", out_path.display());
        }
    }

    let versioncheck_rs_path = out_path.join("versioncheck.rs");
    {
        let mut w = match File::create(&versioncheck_rs_path) {
            None    => fail!("Package script error: Failed to open `{}` for writing", versioncheck_rs_path.display()),
            Some(w) => w
        };
        write!(&mut w as &mut Writer, "\
\\#[feature(globs)];
\\#[feature(link_args)];
use std::c_str::\\{CString\\};
use std::libc::*;
use std::ptr;
use std::vec;

type options = c_int;
struct pcre;
struct pcre_extra;

\\#[link_args = \"{:s}\"]
extern \\{
    static pcre_free: extern \"C\" fn(ptr: *c_void);

    fn pcre_compile(pattern: *c_char, options: options, errptr: *mut *c_char, erroffset: *mut c_int, tableptr: *c_uchar) -> *pcre;
    fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *c_char;
\\}

fn main () \\{
    unsafe \\{
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_owned();

        let pattern = \"^\\\\\\\\d+\\\\\\\\.\\\\\\\\d+\";
        pattern.with_c_str(|pattern_c_str| \\{
            let mut err: *c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if ptr::is_null(code) \\{
                if ptr::is_null(code) \\{
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() \\{
                        None          => fail!(\"pcre_compile() failed at offset \\{\\}\", erroffset as uint),
                        Some(err_str) => fail!(\"pcre_compile() failed at offset \\{\\}: \\{\\}\", erroffset as uint, err_str)
                    \\}
                \\}
            \\}
            assert!(ptr::is_not_null(code));

            let ovecsize = 1 * 3;
            let mut ovector: ~[c_int] = vec::from_elem(ovecsize, 0 as c_int);
            version_str.with_c_str_unchecked(|version_c_str| \\{
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, vec::raw::to_mut_ptr(ovector), ovecsize as c_int);
                if rc < 0 \\{
                    fail!(\"pcre_exec() failed\");
                \\}

                print(version_str.slice_to(ovector[1] as uint));
            \\});

            pcre_free(code as *c_void);
        \\});
    \\}
\\}
", trimmed_pcre_libs);
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rustc_run_output = run::process_output("rustc", [~"versioncheck.rs"]).expect("failed to exec `rustc`");
    if !rustc_run_output.status.success() {
        println(str::from_utf8(rustc_run_output.output));
        println(str::from_utf8(rustc_run_output.error));
        fail!("Package script error: `rustc versioncheck.rs` failed: {}", rustc_run_output.status);
    }
    let version_check_output = run::process_output("./versioncheck", []).expect("failed to exec `./versioncheck`");
    if !version_check_output.status.success() {
        println(str::from_utf8(version_check_output.output));
        println(str::from_utf8(version_check_output.error));
        fail!("versioncheck error: {}", version_check_output.status);
    }
    cd(&workspace_path);

    let output_ptr = vec::raw::to_ptr(version_check_output.output);
    let output_len = version_check_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.rsplit('\n');
    let version_str: ~str = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_owned()
    };

    debug!("libpcre version {:s}", version_str);

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str) {
        None               => fail!("Package script error: Failed to parse version string '{}'", version_str),
        Some(pcre_version) => pcre_version
    };

    if pcre_version < min_required_version {
        fail!("Package script error: Found libpcre version {}, but at least version {} is required", version_str, min_required_version.to_str());
    }

    let src_path = workspace_path.join("src");

    // Output `src/pcre/detail/native.rs`
    let detail_src_path = src_path.join("pcre").join("detail");
    if !detail_src_path.exists() {
        fail!("Package script error: Source directory `{}` does not exist.", detail_src_path.display());
    }
    let native_rs_path = detail_src_path.join("native.rs");
    let native_rs_in_path = detail_src_path.join("native.rs.in");
    if !native_rs_in_path.exists() {
        fail!("Package script error: Source file `{}` does not exist.", native_rs_in_path.display());
    }
    {
        let r = match File::open(&native_rs_in_path) {
            None    => fail!("Package script error: Failed to open `{}` for reading", native_rs_in_path.display()),
            Some(r) => r
        };
        let mut w = match File::create(&native_rs_path) {
            None    => fail!("Package script error: Failed to open `{}` for writing", native_rs_path.display()),
            Some(w) => w
        };
        write!(&mut w as &mut Writer, "// -*- buffer-read-only: t -*-\n");
        write!(&mut w as &mut Writer, "// Generated by {:s} on {:s}\n", args[0], time::now().rfc822());

        let mut buffered_reader = BufferedReader::new(r);
        while !buffered_reader.eof() {
            let line = buffered_reader.read_line();
            if line.is_some() {
                let substituted_line = str::replace(line.unwrap(), "@PCRE_LIBS@", trimmed_pcre_libs);
                write!(&mut w as &mut Writer, "{:s}", substituted_line);
            }
        }
    }

    api::build_lib(sysroot_path, workspace_path, ~"pcre", rustpkg::version::ExactRevision(~"0.1"), from_str("mod.rs").unwrap());
}

fn do_configs(args: ~[~str]) {
    drop(args);
}

fn main() {
    let args = os::args();
    let args_len = args.len();

    if args_len < 2 {
        fail!("Package script requires a directory where rustc libraries live as the first argument");
    } else if args_len < 3 {
        fail!("Package script requires a command as the second argument");
    }

    if args[2] == ~"install" {
        do_install(args);
    } else if args[2] == ~"configs" {
        do_configs(args);
    } else {
        fail!("Package script error: Unsupported command `{}`", args[2]);
    }
}
<|endoftext|>


<commit_before>extern crate procrs;
extern crate argparse;
#[macro_use]
extern crate prettytable;
use prettytable::Table;
use prettytable::format::FormatBuilder;
use std::collections::HashMap;
use procrs::prc::*;
use argparse::{ArgumentParser, StoreTrue, Store};

fn main() {
  let opts = parse_args();
  match opts {
    ProgOpts{ tree: false, query: q, .. } => {
      let mut table = Table::init(
        ProcIter::new_query(q).unwrap()
          .map(|p_r|
            p_r.map(|p|
              row![p.stat.pid, p.stat.ppid, p.stat.comm, p.cmdline.join(" ")]
            )
          ).collect::<Result<Vec<_>, String>>()
          .unwrap()
      );
      let format = FormatBuilder::new()
        .column_separator(' ')
        .build();
      table.set_titles(row!["Pid", "Ppid", "Comm", "Cmd"]);
      table.set_format(format);
      table.printstd();
    },

    ProgOpts{ tree: true, query: q, .. } => {
      let proc_map: HashMap<_, _> =
        ProcIter::new().unwrap()
        .map(|p_r|
          p_r.map(|p|
            (p.stat.pid, p)
          )
        ).collect::<Result<_, String>>()
        .unwrap();

      let mut child_procs = HashMap::new();
      let mut proc_list = Vec::new();

      for (pid, proc_struct) in &proc_map {
        proc_list.push(pid);
        let ppid = proc_struct.stat.ppid;
        child_procs.entry(ppid)
          .or_insert(Vec::new())
          .push(proc_struct);
      }
      proc_list.sort();
      let pid = match q {
        ProcQuery::PidQuery(p) => p,
        _ => 1
      };
      let mut pid_procs = Vec::new();

      let start_procs = match proc_map.get(&pid) {
        Some(proc_struct) => {
          pid_procs.push(proc_struct);
          &pid_procs
        },
        None => child_procs.get(&pid).expect("Invalid pid")
      };

      print_tree(&child_procs, start_procs, "".to_string());
    }
  }
}

fn print_tree(child_procs: &HashMap<TaskId, Vec<&Proc>>,
              level_procs: &Vec<&Proc>, prefix: String) {
  let mut proc_list = level_procs.to_vec();
  proc_list.sort();
  for proc_struct in proc_list {
    let pid = &proc_struct.stat.pid;

    println!("{}{}", prefix, proc_struct.stat.comm);
    let child_list = child_procs.get(pid);
    if let Some(v) = child_list {
      print_tree(child_procs, v, format!("{}{}", "  ", prefix));
    }
  }
}

struct ProgOpts {
  query: ProcQuery,
  tree: bool,
  verbose: bool
}

fn parse_args() -> ProgOpts {
  let mut opts = ProgOpts {
    query: ProcQuery::NoneQuery,
    tree: false,
    verbose: false
  };

  {
    let mut ap = ArgumentParser::new();
    ap.set_description("Query linux processes");
    ap.refer(&mut opts.tree)
      .add_option(&["-t", "--tree"], StoreTrue, "Display process tree");
    ap.refer(&mut opts.verbose)
      .add_option(&["-v", "--verbose"], StoreTrue, "Verbose output");
    ap.refer(&mut opts.query)
      .add_argument("query", Store, "Optional query to search by, pid or string");
    ap.parse_args_or_exit();
  }

  opts
}
<commit_msg>Add more options<commit_after>extern crate procrs;
extern crate argparse;
#[macro_use]
extern crate prettytable;
use prettytable::Table;
use prettytable::format::FormatBuilder;
use std::collections::HashMap;
use procrs::prc::*;
use argparse::{ArgumentParser, StoreTrue, Store};

fn main() {
  let opts = parse_args();
  match opts {
    ProgOpts{ tree: false, query: q,
              perf: perf, long: long, .. } => {
      let mut table = Table::init(
        ProcIter::new_query(q).unwrap()
          .map(|p_r|
            p_r.map(|p|
              row![p.stat.pid, p.stat.ppid, p.stat.comm, p.cmdline.join(" ")]
            )
          ).collect::<Result<Vec<_>, String>>()
          .unwrap()
      );
      let format = FormatBuilder::new()
        .column_separator(' ')
        .build();
      table.set_titles(row!["Pid", "Ppid", "Comm", "Cmd"]);
      table.set_format(format);
      table.printstd();
    },

    ProgOpts{ tree: true, query: q, .. } => {
      let proc_map: HashMap<_, _> =
        ProcIter::new().unwrap()
        .map(|p_r|
          p_r.map(|p|
            (p.stat.pid, p)
          )
        ).collect::<Result<_, String>>()
        .unwrap();

      let mut child_procs = HashMap::new();
      let mut proc_list = Vec::new();

      for (pid, proc_struct) in &proc_map {
        proc_list.push(pid);
        let ppid = proc_struct.stat.ppid;
        child_procs.entry(ppid)
          .or_insert(Vec::new())
          .push(proc_struct);
      }
      proc_list.sort();
      let pid = match q {
        ProcQuery::PidQuery(p) => p,
        _ => 1
      };
      let mut pid_procs = Vec::new();

      let start_procs = match proc_map.get(&pid) {
        Some(proc_struct) => {
          pid_procs.push(proc_struct);
          &pid_procs
        },
        None => child_procs.get(&pid).expect("Invalid pid")
      };

      print_tree(&child_procs, start_procs, "".to_string());
    }
  }
}

fn print_tree(child_procs: &HashMap<TaskId, Vec<&Proc>>,
              level_procs: &Vec<&Proc>, prefix: String) {
  let mut proc_list = level_procs.to_vec();
  proc_list.sort();
  for proc_struct in proc_list {
    let pid = &proc_struct.stat.pid;

    println!("{}{}", prefix, proc_struct.stat.comm);
    let child_list = child_procs.get(pid);
    if let Some(v) = child_list {
      print_tree(child_procs, v, format!("{}{}", "  ", prefix));
    }
  }
}

struct ProgOpts {
  query: ProcQuery,
  tree: bool,
  perf: bool,
  long: bool,
  verbose: bool
}

fn parse_args() -> ProgOpts {
  let mut opts = ProgOpts {
    query: ProcQuery::NoneQuery,
    tree: false,
    perf: false,
    long: false,
    verbose: false
  };

  {
    let mut ap = ArgumentParser::new();
    ap.set_description("Query linux processes");
    ap.refer(&mut opts.tree)
      .add_option(&["-t", "--tree"], StoreTrue, "Display process tree");
    ap.refer(&mut opts.perf)
      .add_option(&["-p", "--perf"], StoreTrue, "Display performance information");
    ap.refer(&mut opts.long)
      .add_option(&["-l", "--long"], StoreTrue, "Display more information");
    ap.refer(&mut opts.verbose)
      .add_option(&["-v", "--verbose"], StoreTrue, "Verbose output");
    ap.refer(&mut opts.query)
      .add_argument("query", Store, "Optional query to search by, pid or string");
    ap.parse_args_or_exit();
  }

  opts
}
<|endoftext|>


<commit_before>use super::{Color, Event, Point, Rect, Renderer, Widget};

use std::path::Path;
use std::sync::Arc;

extern crate sdl2;
extern crate sdl2_ttf;

pub struct SdlRenderer<'a> {
    font: &'a mut sdl2_ttf::Font,
    inner: &'a mut sdl2::render::Renderer<'static>,
}

impl<'a> SdlRenderer<'a> {
    pub fn new(font: &'a mut sdl2_ttf::Font, inner: &'a mut sdl2::render::Renderer<'static>) -> SdlRenderer<'a> {
        SdlRenderer {
            font: font,
            inner: inner
        }
    }
}

impl<'a> Renderer for SdlRenderer<'a> {
    fn clear(&mut self, color: Color) {
        self.inner.set_draw_color(sdl2::pixels::Color::RGBA((color.data >> 16) as u8, (color.data >> 8) as u8, color.data as u8, (color.data >> 24) as u8));
        self.inner.clear();
    }

    fn char(&mut self, pos: Point, c: char, color: Color) {
        let surface = self.font.render(c, sdl2_ttf::blended(sdl2::pixels::Color::RGBA((color.data >> 16) as u8, (color.data >> 8) as u8, color.data as u8, (color.data >> 24) as u8))).unwrap();
        let mut texture = self.inner.create_texture_from_surface(&surface).unwrap();
        let sdl2::render::TextureQuery { width, height, .. } = texture.query();
        if let Some(rect) = sdl2::rect::Rect::new(pos.x as i32, pos.y as i32, width, height).unwrap() {
            self.inner.copy(&mut texture, None, Some(rect));
        }
    }

    fn rect(&mut self, rect: Rect, color: Color) {
        if let Some(sdl_rect) = sdl2::rect::Rect::new(rect.x as i32, rect.y as i32, rect.width as u32, rect.height as u32).unwrap() {
            self.inner.set_draw_color(sdl2::pixels::Color::RGBA((color.data >> 16) as u8, (color.data >> 8) as u8, color.data as u8, (color.data >> 24) as u8));
            self.inner.fill_rect(sdl_rect);
        }
    }
}

impl<'a> Drop for SdlRenderer<'a> {
    fn drop(&mut self) {
        self.inner.present();
    }
}

pub struct Window {
    _ctx: sdl2::Sdl,
    _video_ctx: sdl2::VideoSubsystem,
    _ttf_context: sdl2_ttf::Sdl2TtfContext,
    events: sdl2::EventPump,
    font: sdl2_ttf::Font,
    inner: sdl2::render::Renderer<'static>,
    pub widgets: Vec<Arc<Widget>>,
    pub bg: Color,
}

impl Window {
    pub fn new(rect: Rect, title: &str) -> Box<Self> {
        let ctx = sdl2::init().unwrap();
        let video_ctx = ctx.video().unwrap();
        let ttf_context = sdl2_ttf::init().unwrap();

        let mut window = video_ctx.window(title, rect.width as u32, rect.height as u32).position(rect.x as i32, rect.y as i32).opengl().build().unwrap();
        window.show();

        video_ctx.text_input().start();

        let events = ctx.event_pump().unwrap();

        Box::new(Window {
            _ctx: ctx,
            _video_ctx: video_ctx,
            _ttf_context: ttf_context,
            events: events,
            font: sdl2_ttf::Font::from_file(&Path::new("res/Unifont.ttf"), 16).unwrap(),
            inner: window.renderer().build().unwrap(),
            widgets: Vec::new(),
            bg: Color::rgb(237, 233, 227),
        })
    }

    pub fn draw(&mut self) {
        let mut renderer = SdlRenderer::new(&mut self.font, &mut self.inner);
        renderer.clear(self.bg);
        for widget in self.widgets.iter() {
            widget.draw(&mut renderer);
        }
    }

    pub fn exec(&mut self) {
        //Keep track of mouse state
        let mut left_button = false;
        let mut middle_button = false;
        let mut right_button = false;

        self.draw();
        'event: loop {
            while let Some(sdl_event) = self.events.poll_event() {
                let mut events: Vec<Event> = Vec::new();

                match sdl_event {
                    sdl2::event::Event::MouseMotion { mousestate, x, y, .. } => {
                        left_button = mousestate.left();
                        middle_button = mousestate.middle();
                        right_button = mousestate.right();

                        events.push(Event::Mouse {
                            point: Point::new(x as isize, y as isize),
                            left_button: left_button,
                            middle_button: middle_button,
                            right_button: right_button,
                        });
                    },
                    sdl2::event::Event::MouseButtonDown { mouse_btn, x, y, .. } => {
                        match mouse_btn {
                            sdl2::mouse::Mouse::Left => left_button = true,
                            sdl2::mouse::Mouse::Middle => middle_button = true,
                            sdl2::mouse::Mouse::Right => right_button = true,
                            _ => ()
                        }

                        events.push(Event::Mouse {
                            point: Point::new(x as isize, y as isize),
                            left_button: left_button,
                            middle_button: middle_button,
                            right_button: right_button,
                        });
                    },
                    sdl2::event::Event::MouseButtonUp { mouse_btn, x, y, .. } => {
                        match mouse_btn {
                            sdl2::mouse::Mouse::Left => left_button = false,
                            sdl2::mouse::Mouse::Middle => middle_button = false,
                            sdl2::mouse::Mouse::Right => right_button = false,
                            _ => ()
                        }

                        events.push(Event::Mouse {
                            point: Point::new(x as isize, y as isize),
                            left_button: left_button,
                            middle_button: middle_button,
                            right_button: right_button,
                        });
                    },
                    sdl2::event::Event::KeyDown { keycode, .. } => if let Some(key) = keycode {
                        match key {
                            sdl2::keyboard::Keycode::Backspace => events.push(Event::Backspace),
                            sdl2::keyboard::Keycode::Delete => events.push(Event::Delete),
                            sdl2::keyboard::Keycode::Up => events.push(Event::UpArrow),
                            sdl2::keyboard::Keycode::Down => events.push(Event::DownArrow),
                            sdl2::keyboard::Keycode::Left => events.push(Event::LeftArrow),
                            sdl2::keyboard::Keycode::Right => events.push(Event::RightArrow),
                            _ => ()
                        }
                    },
                    sdl2::event::Event::TextInput { text, .. } => {
                        for c in text.chars() {
                            events.push(Event::Text {
                                c: c
                            });
                        }
                    },
                    sdl2::event::Event::Quit {..} => break 'event,
                    _ => ()
                };

                for event in events.iter() {
                    for widget in self.widgets.iter() {
                        widget.event(*event);
                    }
                }

                self.draw();
            }
        }
    }
}
<commit_msg>Fix cpu usage in SDL<commit_after>use super::{Color, Event, Point, Rect, Renderer, Widget};

use std::path::Path;
use std::sync::Arc;

extern crate sdl2;
extern crate sdl2_ttf;

pub struct SdlRenderer<'a> {
    font: &'a mut sdl2_ttf::Font,
    inner: &'a mut sdl2::render::Renderer<'static>,
}

impl<'a> SdlRenderer<'a> {
    pub fn new(font: &'a mut sdl2_ttf::Font, inner: &'a mut sdl2::render::Renderer<'static>) -> SdlRenderer<'a> {
        SdlRenderer {
            font: font,
            inner: inner
        }
    }
}

impl<'a> Renderer for SdlRenderer<'a> {
    fn clear(&mut self, color: Color) {
        self.inner.set_draw_color(sdl2::pixels::Color::RGBA((color.data >> 16) as u8, (color.data >> 8) as u8, color.data as u8, (color.data >> 24) as u8));
        self.inner.clear();
    }

    fn char(&mut self, pos: Point, c: char, color: Color) {
        let surface = self.font.render(c, sdl2_ttf::blended(sdl2::pixels::Color::RGBA((color.data >> 16) as u8, (color.data >> 8) as u8, color.data as u8, (color.data >> 24) as u8))).unwrap();
        let mut texture = self.inner.create_texture_from_surface(&surface).unwrap();
        let sdl2::render::TextureQuery { width, height, .. } = texture.query();
        if let Some(rect) = sdl2::rect::Rect::new(pos.x as i32, pos.y as i32, width, height).unwrap() {
            self.inner.copy(&mut texture, None, Some(rect));
        }
    }

    fn rect(&mut self, rect: Rect, color: Color) {
        if let Some(sdl_rect) = sdl2::rect::Rect::new(rect.x as i32, rect.y as i32, rect.width as u32, rect.height as u32).unwrap() {
            self.inner.set_draw_color(sdl2::pixels::Color::RGBA((color.data >> 16) as u8, (color.data >> 8) as u8, color.data as u8, (color.data >> 24) as u8));
            self.inner.fill_rect(sdl_rect);
        }
    }
}

impl<'a> Drop for SdlRenderer<'a> {
    fn drop(&mut self) {
        self.inner.present();
    }
}

pub struct Window {
    _ctx: sdl2::Sdl,
    _video_ctx: sdl2::VideoSubsystem,
    _ttf_context: sdl2_ttf::Sdl2TtfContext,
    events: sdl2::EventPump,
    font: sdl2_ttf::Font,
    inner: sdl2::render::Renderer<'static>,
    pub widgets: Vec<Arc<Widget>>,
    pub bg: Color,
}

impl Window {
    pub fn new(rect: Rect, title: &str) -> Box<Self> {
        let ctx = sdl2::init().unwrap();
        let video_ctx = ctx.video().unwrap();
        let ttf_context = sdl2_ttf::init().unwrap();

        let mut window = video_ctx.window(title, rect.width as u32, rect.height as u32).position(rect.x as i32, rect.y as i32).opengl().build().unwrap();
        window.show();

        video_ctx.text_input().start();

        let events = ctx.event_pump().unwrap();

        Box::new(Window {
            _ctx: ctx,
            _video_ctx: video_ctx,
            _ttf_context: ttf_context,
            events: events,
            font: sdl2_ttf::Font::from_file(&Path::new("res/Unifont.ttf"), 16).unwrap(),
            inner: window.renderer().build().unwrap(),
            widgets: Vec::new(),
            bg: Color::rgb(237, 233, 227),
        })
    }

    pub fn draw(&mut self) {
        let mut renderer = SdlRenderer::new(&mut self.font, &mut self.inner);
        renderer.clear(self.bg);
        for widget in self.widgets.iter() {
            widget.draw(&mut renderer);
        }
    }

    pub fn exec(&mut self) {
        //Keep track of mouse state
        let mut left_button = false;
        let mut middle_button = false;
        let mut right_button = false;

        self.draw();
        'event: loop {
            let mut events: Vec<Event> = Vec::new();

            match self.events.wait_event() {
                sdl2::event::Event::MouseMotion { mousestate, x, y, .. } => {
                    left_button = mousestate.left();
                    middle_button = mousestate.middle();
                    right_button = mousestate.right();

                    events.push(Event::Mouse {
                        point: Point::new(x as isize, y as isize),
                        left_button: left_button,
                        middle_button: middle_button,
                        right_button: right_button,
                    });
                },
                sdl2::event::Event::MouseButtonDown { mouse_btn, x, y, .. } => {
                    match mouse_btn {
                        sdl2::mouse::Mouse::Left => left_button = true,
                        sdl2::mouse::Mouse::Middle => middle_button = true,
                        sdl2::mouse::Mouse::Right => right_button = true,
                        _ => ()
                    }

                    events.push(Event::Mouse {
                        point: Point::new(x as isize, y as isize),
                        left_button: left_button,
                        middle_button: middle_button,
                        right_button: right_button,
                    });
                },
                sdl2::event::Event::MouseButtonUp { mouse_btn, x, y, .. } => {
                    match mouse_btn {
                        sdl2::mouse::Mouse::Left => left_button = false,
                        sdl2::mouse::Mouse::Middle => middle_button = false,
                        sdl2::mouse::Mouse::Right => right_button = false,
                        _ => ()
                    }

                    events.push(Event::Mouse {
                        point: Point::new(x as isize, y as isize),
                        left_button: left_button,
                        middle_button: middle_button,
                        right_button: right_button,
                    });
                },
                sdl2::event::Event::KeyDown { keycode, .. } => if let Some(key) = keycode {
                    match key {
                        sdl2::keyboard::Keycode::Backspace => events.push(Event::Backspace),
                        sdl2::keyboard::Keycode::Delete => events.push(Event::Delete),
                        sdl2::keyboard::Keycode::Up => events.push(Event::UpArrow),
                        sdl2::keyboard::Keycode::Down => events.push(Event::DownArrow),
                        sdl2::keyboard::Keycode::Left => events.push(Event::LeftArrow),
                        sdl2::keyboard::Keycode::Right => events.push(Event::RightArrow),
                        _ => ()
                    }
                },
                sdl2::event::Event::TextInput { text, .. } => {
                    for c in text.chars() {
                        events.push(Event::Text {
                            c: c
                        });
                    }
                },
                sdl2::event::Event::Quit {..} => break 'event,
                _ => ()
            };

            for event in events.iter() {
                for widget in self.widgets.iter() {
                    widget.event(*event);
                }
            }

            self.draw();
        }
    }
}
<|endoftext|>


<commit_before>use std::error;
use std::ffi::{CStr, CString, NulError};
use std::fmt;
use std::rc::Rc;
use libc::{c_char, uint32_t};
use std::mem::transmute;

use sys;

#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Error {
    NoMemError = sys::SDL_errorcode::SDL_ENOMEM as i32,
    ReadError = sys::SDL_errorcode::SDL_EFREAD as i32,
    WriteError = sys::SDL_errorcode::SDL_EFWRITE as i32,
    SeekError = sys::SDL_errorcode::SDL_EFSEEK as i32,
    UnsupportedError = sys::SDL_errorcode::SDL_UNSUPPORTED as i32
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            NoMemError => write!(f, "Out of memory"),
            ReadError => write!(f, "Error reading from datastream"),
            WriteError => write!(f, "Error writing to datastream"),
            SeekError => write!(f, "Error seeking in datastream"),
            UnsupportedError => write!(f, "Unknown SDL error")
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;

        match *self {
            NoMemError => "out of memory",
            ReadError => "error reading from datastream",
            WriteError => "error writing to datastream",
            SeekError => "error seeking in datastream",
            UnsupportedError => "unknown SDL error"
        }
    }
}

use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
/// Only one Sdl context can be alive at a time.
/// Set to false by default (not alive).
static IS_SDL_CONTEXT_ALIVE: AtomicBool = ATOMIC_BOOL_INIT;

/// The SDL context type. Initialize with `sdl2::init()`.
///
/// From a thread-safety perspective, `Sdl` represents the main thread.
/// As such, `Sdl` is a useful type for ensuring that SDL types that can only
/// be used on the main thread are initialized that way.
///
/// For instance, `SDL_PumpEvents()` is not thread safe, and may only be
/// called on the main thread.
/// All functionality that calls `SDL_PumpEvents()` is thus put into an
/// `EventPump` type, which can only be obtained through `Sdl`.
/// This guarantees that the only way to call event-pumping functions is on
/// the main thread.
#[derive(Clone)]
pub struct Sdl {
    sdldrop: Rc<SdlDrop>
}

impl Sdl {
    #[inline]
    fn new() -> Result<Sdl, String> {
        unsafe {
            use std::sync::atomic::Ordering;

            // Atomically switch the `IS_SDL_CONTEXT_ALIVE` global to true
            let was_alive = IS_SDL_CONTEXT_ALIVE.swap(true, Ordering::Relaxed);

            if was_alive {
                Err("Cannot initialize `Sdl` more than once at a time.".to_owned())
            } else if sys::SDL_Init(0) == 0 {
                // Initialize SDL without any explicit subsystems (flags = 0).
                Ok(Sdl {
                    sdldrop: Rc::new(SdlDrop)
                })
            } else {
                IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
                Err(get_error())
            }
        }
    }

    /// Initializes the audio subsystem.
    #[inline]
    pub fn audio(&self) -> Result<AudioSubsystem, String> { AudioSubsystem::new(self) }

    /// Initializes the event subsystem.
    #[inline]
    pub fn event(&self) -> Result<EventSubsystem, String> { EventSubsystem::new(self) }

    /// Initializes the joystick subsystem.
    #[inline]
    pub fn joystick(&self) -> Result<JoystickSubsystem, String> { JoystickSubsystem::new(self) }

    /// Initializes the haptic subsystem.
    #[inline]
    pub fn haptic(&self) -> Result<HapticSubsystem, String> { HapticSubsystem::new(self) }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn game_controller(&self) -> Result<GameControllerSubsystem, String> { GameControllerSubsystem::new(self) }

    /// Initializes the timer subsystem.
    #[inline]
    pub fn timer(&self) -> Result<TimerSubsystem, String> { TimerSubsystem::new(self) }

    /// Initializes the video subsystem.
    #[inline]
    pub fn video(&self) -> Result<VideoSubsystem, String> { VideoSubsystem::new(self) }

    /// Obtains the SDL event pump.
    ///
    /// At most one `EventPump` is allowed to be alive during the program's execution.
    /// If this function is called while an `EventPump` instance is alive, the function will return
    /// an error.
    #[inline]
    pub fn event_pump(&self) -> Result<EventPump, String> {
        EventPump::new(self)
    }

    #[inline]
    #[doc(hidden)]
    pub fn sdldrop(&self) -> Rc<SdlDrop> {
        self.sdldrop.clone()
    }
}

/// When SDL is no longer in use (the refcount in an `Rc<SdlDrop>` reaches 0), the library is quit.
#[doc(hidden)]
#[derive(Debug)]
pub struct SdlDrop;

impl Drop for SdlDrop {
    #[inline]
    fn drop(&mut self) {
        use std::sync::atomic::Ordering;

        let was_alive = IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
        assert!(was_alive);

        unsafe { sys::SDL_Quit(); }
    }
}

// No subsystem can implement `Send` because the destructor, `SDL_QuitSubSystem`,
// utilizes non-atomic reference counting and should thus be called on a single thread.
// Some subsystems have functions designed to be thread-safe, such as adding a timer or accessing
// the event queue. These subsystems implement `Sync`.

macro_rules! subsystem {
    ($name:ident, $flag:expr) => (
        impl $name {
            #[inline]
            fn new(sdl: &Sdl) -> Result<$name, String> {
                let result = unsafe { sys::SDL_InitSubSystem($flag) };

                if result == 0 {
                    Ok($name {
                        _subsystem_drop: Rc::new(SubsystemDrop {
                            _sdldrop: sdl.sdldrop.clone(),
                            flag: $flag
                        })
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    );
    ($name:ident, $flag:expr, nosync) => (
        #[derive(Debug, Clone)]
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }

        impl $name {
            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl { sdldrop: self._subsystem_drop._sdldrop.clone() }
            }
        }

        subsystem!($name, $flag);
    );
    ($name:ident, $flag:expr, sync) => (
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }
        unsafe impl Sync for $name {}

        impl $name {
            #[inline]
            pub fn clone(&self) -> $name {
                $name {
                    _subsystem_drop: self._subsystem_drop.clone()
                }
            }

            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl { sdldrop: self._subsystem_drop._sdldrop.clone() }
            }
        }

        subsystem!($name, $flag);
    )
}

/// When a subsystem is no longer in use (the refcount in an `Rc<SubsystemDrop>` reaches 0),
/// the subsystem is quit.
#[derive(Debug, Clone)]
struct SubsystemDrop {
    _sdldrop: Rc<SdlDrop>,
    flag: uint32_t
}

impl Drop for SubsystemDrop {
    #[inline]
    fn drop(&mut self) {
        unsafe { sys::SDL_QuitSubSystem(self.flag); }
    }
}

subsystem!(AudioSubsystem, sys::SDL_INIT_AUDIO, nosync);
subsystem!(GameControllerSubsystem, sys::SDL_INIT_GAMECONTROLLER, nosync);
subsystem!(HapticSubsystem, sys::SDL_INIT_HAPTIC, nosync);
subsystem!(JoystickSubsystem, sys::SDL_INIT_JOYSTICK, nosync);
subsystem!(VideoSubsystem, sys::SDL_INIT_VIDEO, nosync);
// Timers can be added on other threads.
subsystem!(TimerSubsystem, sys::SDL_INIT_TIMER, sync);
// The event queue can be read from other threads.
subsystem!(EventSubsystem, sys::SDL_INIT_EVENTS, sync);

static mut IS_EVENT_PUMP_ALIVE: bool = false;

/// A thread-safe type that encapsulates SDL event-pumping functions.
pub struct EventPump {
    _sdldrop: Rc<SdlDrop>
}

impl EventPump {
    /// Obtains the SDL event pump.
    #[inline]
    fn new(sdl: &Sdl) -> Result<EventPump, String> {
        // Called on the main SDL thread.

        unsafe {
            if IS_EVENT_PUMP_ALIVE {
                Err("an `EventPump` instance is already alive - there can only be one `EventPump` in use at a time.".to_owned())
            } else {
                // Initialize the events subsystem, just in case none of the other subsystems have done it yet.
                let result = sys::SDL_InitSubSystem(sys::SDL_INIT_EVENTS);

                if result == 0 {
                    IS_EVENT_PUMP_ALIVE = true;

                    Ok(EventPump {
                        _sdldrop: sdl.sdldrop.clone()
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    }
}

impl Drop for EventPump {
    #[inline]
    fn drop(&mut self) {
        // Called on the main SDL thread.

        unsafe {
            assert!(IS_EVENT_PUMP_ALIVE);
            sys::SDL_QuitSubSystem(sys::SDL_INIT_EVENTS);
            IS_EVENT_PUMP_ALIVE = false;
        }
    }
}

/// Initializes the SDL library.
/// This must be called before using any other SDL function.
///
/// # Example
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
/// let mut event_pump = sdl_context.event_pump().unwrap();
///
/// for event in event_pump.poll_iter() {
///     // ...
/// }
///
/// // SDL_Quit() is called here as `sdl_context` is dropped.
/// ```
#[inline]
pub fn init() -> Result<Sdl, String> { Sdl::new() }

pub fn get_error() -> String {
    unsafe {
        let err = sys::SDL_GetError();
        CStr::from_ptr(err as *const _).to_str().unwrap().to_owned()
    }
}

pub fn set_error(err: &str) -> Result<(), NulError> {
    let c_string = try!(CString::new(err));
    Ok(unsafe {
        sys::SDL_SetError(c_string.as_ptr() as *const c_char);
    })
}

pub fn set_error_from_code(err: Error) {
    unsafe { sys::SDL_Error(transmute(err)); }
}

pub fn clear_error() {
    unsafe { sys::SDL_ClearError(); }
}
<commit_msg>Implement sdl::get_platform()<commit_after>use std::error;
use std::ffi::{CStr, CString, NulError};
use std::fmt;
use std::rc::Rc;
use libc::{c_char, uint32_t};
use std::mem::transmute;

use sys;

#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Error {
    NoMemError = sys::SDL_errorcode::SDL_ENOMEM as i32,
    ReadError = sys::SDL_errorcode::SDL_EFREAD as i32,
    WriteError = sys::SDL_errorcode::SDL_EFWRITE as i32,
    SeekError = sys::SDL_errorcode::SDL_EFSEEK as i32,
    UnsupportedError = sys::SDL_errorcode::SDL_UNSUPPORTED as i32
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            NoMemError => write!(f, "Out of memory"),
            ReadError => write!(f, "Error reading from datastream"),
            WriteError => write!(f, "Error writing to datastream"),
            SeekError => write!(f, "Error seeking in datastream"),
            UnsupportedError => write!(f, "Unknown SDL error")
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;

        match *self {
            NoMemError => "out of memory",
            ReadError => "error reading from datastream",
            WriteError => "error writing to datastream",
            SeekError => "error seeking in datastream",
            UnsupportedError => "unknown SDL error"
        }
    }
}

use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
/// Only one Sdl context can be alive at a time.
/// Set to false by default (not alive).
static IS_SDL_CONTEXT_ALIVE: AtomicBool = ATOMIC_BOOL_INIT;

/// The SDL context type. Initialize with `sdl2::init()`.
///
/// From a thread-safety perspective, `Sdl` represents the main thread.
/// As such, `Sdl` is a useful type for ensuring that SDL types that can only
/// be used on the main thread are initialized that way.
///
/// For instance, `SDL_PumpEvents()` is not thread safe, and may only be
/// called on the main thread.
/// All functionality that calls `SDL_PumpEvents()` is thus put into an
/// `EventPump` type, which can only be obtained through `Sdl`.
/// This guarantees that the only way to call event-pumping functions is on
/// the main thread.
#[derive(Clone)]
pub struct Sdl {
    sdldrop: Rc<SdlDrop>
}

impl Sdl {
    #[inline]
    fn new() -> Result<Sdl, String> {
        unsafe {
            use std::sync::atomic::Ordering;

            // Atomically switch the `IS_SDL_CONTEXT_ALIVE` global to true
            let was_alive = IS_SDL_CONTEXT_ALIVE.swap(true, Ordering::Relaxed);

            if was_alive {
                Err("Cannot initialize `Sdl` more than once at a time.".to_owned())
            } else if sys::SDL_Init(0) == 0 {
                // Initialize SDL without any explicit subsystems (flags = 0).
                Ok(Sdl {
                    sdldrop: Rc::new(SdlDrop)
                })
            } else {
                IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
                Err(get_error())
            }
        }
    }

    /// Initializes the audio subsystem.
    #[inline]
    pub fn audio(&self) -> Result<AudioSubsystem, String> { AudioSubsystem::new(self) }

    /// Initializes the event subsystem.
    #[inline]
    pub fn event(&self) -> Result<EventSubsystem, String> { EventSubsystem::new(self) }

    /// Initializes the joystick subsystem.
    #[inline]
    pub fn joystick(&self) -> Result<JoystickSubsystem, String> { JoystickSubsystem::new(self) }

    /// Initializes the haptic subsystem.
    #[inline]
    pub fn haptic(&self) -> Result<HapticSubsystem, String> { HapticSubsystem::new(self) }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn game_controller(&self) -> Result<GameControllerSubsystem, String> { GameControllerSubsystem::new(self) }

    /// Initializes the timer subsystem.
    #[inline]
    pub fn timer(&self) -> Result<TimerSubsystem, String> { TimerSubsystem::new(self) }

    /// Initializes the video subsystem.
    #[inline]
    pub fn video(&self) -> Result<VideoSubsystem, String> { VideoSubsystem::new(self) }

    /// Obtains the SDL event pump.
    ///
    /// At most one `EventPump` is allowed to be alive during the program's execution.
    /// If this function is called while an `EventPump` instance is alive, the function will return
    /// an error.
    #[inline]
    pub fn event_pump(&self) -> Result<EventPump, String> {
        EventPump::new(self)
    }

    #[inline]
    #[doc(hidden)]
    pub fn sdldrop(&self) -> Rc<SdlDrop> {
        self.sdldrop.clone()
    }
}

/// When SDL is no longer in use (the refcount in an `Rc<SdlDrop>` reaches 0), the library is quit.
#[doc(hidden)]
#[derive(Debug)]
pub struct SdlDrop;

impl Drop for SdlDrop {
    #[inline]
    fn drop(&mut self) {
        use std::sync::atomic::Ordering;

        let was_alive = IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
        assert!(was_alive);

        unsafe { sys::SDL_Quit(); }
    }
}

// No subsystem can implement `Send` because the destructor, `SDL_QuitSubSystem`,
// utilizes non-atomic reference counting and should thus be called on a single thread.
// Some subsystems have functions designed to be thread-safe, such as adding a timer or accessing
// the event queue. These subsystems implement `Sync`.

macro_rules! subsystem {
    ($name:ident, $flag:expr) => (
        impl $name {
            #[inline]
            fn new(sdl: &Sdl) -> Result<$name, String> {
                let result = unsafe { sys::SDL_InitSubSystem($flag) };

                if result == 0 {
                    Ok($name {
                        _subsystem_drop: Rc::new(SubsystemDrop {
                            _sdldrop: sdl.sdldrop.clone(),
                            flag: $flag
                        })
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    );
    ($name:ident, $flag:expr, nosync) => (
        #[derive(Debug, Clone)]
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }

        impl $name {
            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl { sdldrop: self._subsystem_drop._sdldrop.clone() }
            }
        }

        subsystem!($name, $flag);
    );
    ($name:ident, $flag:expr, sync) => (
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }
        unsafe impl Sync for $name {}

        impl $name {
            #[inline]
            pub fn clone(&self) -> $name {
                $name {
                    _subsystem_drop: self._subsystem_drop.clone()
                }
            }

            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl { sdldrop: self._subsystem_drop._sdldrop.clone() }
            }
        }

        subsystem!($name, $flag);
    )
}

/// When a subsystem is no longer in use (the refcount in an `Rc<SubsystemDrop>` reaches 0),
/// the subsystem is quit.
#[derive(Debug, Clone)]
struct SubsystemDrop {
    _sdldrop: Rc<SdlDrop>,
    flag: uint32_t
}

impl Drop for SubsystemDrop {
    #[inline]
    fn drop(&mut self) {
        unsafe { sys::SDL_QuitSubSystem(self.flag); }
    }
}

subsystem!(AudioSubsystem, sys::SDL_INIT_AUDIO, nosync);
subsystem!(GameControllerSubsystem, sys::SDL_INIT_GAMECONTROLLER, nosync);
subsystem!(HapticSubsystem, sys::SDL_INIT_HAPTIC, nosync);
subsystem!(JoystickSubsystem, sys::SDL_INIT_JOYSTICK, nosync);
subsystem!(VideoSubsystem, sys::SDL_INIT_VIDEO, nosync);
// Timers can be added on other threads.
subsystem!(TimerSubsystem, sys::SDL_INIT_TIMER, sync);
// The event queue can be read from other threads.
subsystem!(EventSubsystem, sys::SDL_INIT_EVENTS, sync);

static mut IS_EVENT_PUMP_ALIVE: bool = false;

/// A thread-safe type that encapsulates SDL event-pumping functions.
pub struct EventPump {
    _sdldrop: Rc<SdlDrop>
}

impl EventPump {
    /// Obtains the SDL event pump.
    #[inline]
    fn new(sdl: &Sdl) -> Result<EventPump, String> {
        // Called on the main SDL thread.

        unsafe {
            if IS_EVENT_PUMP_ALIVE {
                Err("an `EventPump` instance is already alive - there can only be one `EventPump` in use at a time.".to_owned())
            } else {
                // Initialize the events subsystem, just in case none of the other subsystems have done it yet.
                let result = sys::SDL_InitSubSystem(sys::SDL_INIT_EVENTS);

                if result == 0 {
                    IS_EVENT_PUMP_ALIVE = true;

                    Ok(EventPump {
                        _sdldrop: sdl.sdldrop.clone()
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    }
}

impl Drop for EventPump {
    #[inline]
    fn drop(&mut self) {
        // Called on the main SDL thread.

        unsafe {
            assert!(IS_EVENT_PUMP_ALIVE);
            sys::SDL_QuitSubSystem(sys::SDL_INIT_EVENTS);
            IS_EVENT_PUMP_ALIVE = false;
        }
    }
}

/// Get platform name
#[inline]
pub fn get_platform() -> &'static str {
  unsafe {
    CStr::from_ptr(sys::SDL_GetPlatform()).to_str().unwrap()
  }
}

/// Initializes the SDL library.
/// This must be called before using any other SDL function.
///
/// # Example
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
/// let mut event_pump = sdl_context.event_pump().unwrap();
///
/// for event in event_pump.poll_iter() {
///     // ...
/// }
///
/// // SDL_Quit() is called here as `sdl_context` is dropped.
/// ```
#[inline]
pub fn init() -> Result<Sdl, String> { Sdl::new() }

pub fn get_error() -> String {
    unsafe {
        let err = sys::SDL_GetError();
        CStr::from_ptr(err as *const _).to_str().unwrap().to_owned()
    }
}

pub fn set_error(err: &str) -> Result<(), NulError> {
    let c_string = try!(CString::new(err));
    Ok(unsafe {
        sys::SDL_SetError(c_string.as_ptr() as *const c_char);
    })
}

pub fn set_error_from_code(err: Error) {
    unsafe { sys::SDL_Error(transmute(err)); }
}

pub fn clear_error() {
    unsafe { sys::SDL_ClearError(); }
}
<|endoftext|>