<commit_before>//! Advertizes the capabilities of the LSP Server.
use std::env;

use lsp_types::{
    CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions,
    CodeActionProviderCapability, CodeLensOptions, CompletionOptions,
    DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, HoverProviderCapability,
    ImplementationProviderCapability, RenameOptions, RenameProviderCapability, SaveOptions,
    SelectionRangeProviderCapability, SemanticTokensDocumentProvider, SemanticTokensLegend,
    SemanticTokensOptions, SemanticTokensServerCapabilities, ServerCapabilities,
    SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind,
    TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions,
};
use serde_json::{json, Value};

use crate::semantic_tokens;

pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabilities {
    let code_action_provider = code_action_capabilities(client_caps);
    let semantic_tokens_provider = semantic_tokens_capabilities(client_caps);
    let experimental = experimental_capabilities(client_caps);

    ServerCapabilities {
        text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions {
            open_close: Some(true),
            change: Some(if env::var("RA_NO_INCREMENTAL_SYNC").is_ok() {
                TextDocumentSyncKind::Full
            } else {
                TextDocumentSyncKind::Incremental
            }),
            will_save: None,
            will_save_wait_until: None,
            save: Some(SaveOptions::default().into()),
        })),
        hover_provider: Some(HoverProviderCapability::Simple(true)),
        completion_provider: Some(CompletionOptions {
            resolve_provider: None,
            trigger_characters: Some(vec![":".to_string(), ".".to_string()]),
            work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
        }),
        signature_help_provider: Some(SignatureHelpOptions {
            trigger_characters: Some(vec!["(".to_string(), ",".to_string()]),
            retrigger_characters: None,
            work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
        }),
        declaration_provider: None,
        definition_provider: Some(true),
        type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
        implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
        references_provider: Some(true),
        document_highlight_provider: Some(true),
        document_symbol_provider: Some(true),
        workspace_symbol_provider: Some(true),
        code_action_provider: Some(code_action_provider),
        code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }),
        document_formatting_provider: Some(true),
        document_range_formatting_provider: None,
        document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions {
            first_trigger_character: "=".to_string(),
            more_trigger_character: Some(vec![".".to_string(), ">".to_string()]),
        }),
        selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)),
        semantic_highlighting: None,
        folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
        rename_provider: Some(RenameProviderCapability::Options(RenameOptions {
            prepare_provider: Some(true),
            work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
        })),
        document_link_provider: None,
        color_provider: None,
        execute_command_provider: None,
        workspace: None,
        call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)),
        semantic_tokens_provider,
        experimental,
    }
}

fn experimental_capabilities(client_caps: &ClientCapabilities) -> Option<Value> {
    client_caps.experimental.as_ref().and_then(|it| {
        it.as_object().map(|map| {
            let mut obj = json!({});
            let result = obj.as_object_mut().unwrap();

            if map.contains_key("joinLines") {
                result.insert("joinLines".into(), true.into());
            }

            if map.contains_key("ssr") {
                result.insert("ssr".into(), true.into());
            }

            if map.contains_key("onEnter") {
                result.insert("onEnter".into(), true.into());
            }

            if map.contains_key("parentModule") {
                result.insert("parentModule".into(), true.into());
            }

            if map.contains_key("runnables") {
                result.insert("runnables".into(), json!({ "kinds": [ "cargo" ] }));
            }

            obj
        })
    })
}

fn semantic_tokens_capabilities(
    client_caps: &ClientCapabilities,
) -> Option<SemanticTokensServerCapabilities> {
    client_caps.text_document.as_ref().and_then(|it| it.semantic_tokens.as_ref()).map(|_|
            // client supports semanticTokens
            SemanticTokensOptions {
            legend: SemanticTokensLegend {
                token_types: semantic_tokens::SUPPORTED_TYPES.to_vec(),
                token_modifiers: semantic_tokens::SUPPORTED_MODIFIERS.to_vec(),
            },

            document_provider: Some(SemanticTokensDocumentProvider::Bool(true)),
            range_provider: Some(true),
            work_done_progress_options: Default::default(),
        }
        .into())
}

fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProviderCapability {
    client_caps
        .text_document
        .as_ref()
        .and_then(|it| it.code_action.as_ref())
        .and_then(|it| it.code_action_literal_support.as_ref())
        .map_or(CodeActionProviderCapability::Simple(true), |caps| {
            let mut action_kinds = vec![
                CodeActionKind::EMPTY,
                CodeActionKind::QUICKFIX,
                CodeActionKind::REFACTOR,
                CodeActionKind::REFACTOR_EXTRACT,
                CodeActionKind::REFACTOR_INLINE,
                CodeActionKind::REFACTOR_REWRITE,
            ];

            // Not all clients can fall back gracefully for unknown values.
            // Microsoft.VisualStudio.LanguageServer.Protocol.CodeActionKind does not support CodeActionKind::EMPTY
            // So have to filter out.
            action_kinds
                .retain(|it| caps.code_action_kind.value_set.contains(&it.as_str().to_owned()));

            CodeActionProviderCapability::Options(CodeActionOptions {
                code_action_kinds: Some(action_kinds),
                work_done_progress_options: Default::default(),
            })
        })
}
<commit_msg>Always send experimental & semantic server caps.<commit_after>//! Advertizes the capabilities of the LSP Server.
use std::env;

use lsp_types::{
    CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions,
    CodeActionProviderCapability, CodeLensOptions, CompletionOptions,
    DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, HoverProviderCapability,
    ImplementationProviderCapability, RenameOptions, RenameProviderCapability, SaveOptions,
    SelectionRangeProviderCapability, SemanticTokensDocumentProvider, SemanticTokensLegend,
    SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability,
    TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability,
    WorkDoneProgressOptions,
};
use serde_json::json;

use crate::semantic_tokens;

pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabilities {
    let code_action_provider = code_action_capabilities(client_caps);

    ServerCapabilities {
        text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions {
            open_close: Some(true),
            change: Some(if env::var("RA_NO_INCREMENTAL_SYNC").is_ok() {
                TextDocumentSyncKind::Full
            } else {
                TextDocumentSyncKind::Incremental
            }),
            will_save: None,
            will_save_wait_until: None,
            save: Some(SaveOptions::default().into()),
        })),
        hover_provider: Some(HoverProviderCapability::Simple(true)),
        completion_provider: Some(CompletionOptions {
            resolve_provider: None,
            trigger_characters: Some(vec![":".to_string(), ".".to_string()]),
            work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
        }),
        signature_help_provider: Some(SignatureHelpOptions {
            trigger_characters: Some(vec!["(".to_string(), ",".to_string()]),
            retrigger_characters: None,
            work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
        }),
        declaration_provider: None,
        definition_provider: Some(true),
        type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
        implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
        references_provider: Some(true),
        document_highlight_provider: Some(true),
        document_symbol_provider: Some(true),
        workspace_symbol_provider: Some(true),
        code_action_provider: Some(code_action_provider),
        code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }),
        document_formatting_provider: Some(true),
        document_range_formatting_provider: None,
        document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions {
            first_trigger_character: "=".to_string(),
            more_trigger_character: Some(vec![".".to_string(), ">".to_string()]),
        }),
        selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)),
        semantic_highlighting: None,
        folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
        rename_provider: Some(RenameProviderCapability::Options(RenameOptions {
            prepare_provider: Some(true),
            work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
        })),
        document_link_provider: None,
        color_provider: None,
        execute_command_provider: None,
        workspace: None,
        call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)),
        semantic_tokens_provider: Some(
            SemanticTokensOptions {
                legend: SemanticTokensLegend {
                    token_types: semantic_tokens::SUPPORTED_TYPES.to_vec(),
                    token_modifiers: semantic_tokens::SUPPORTED_MODIFIERS.to_vec(),
                },

                document_provider: Some(SemanticTokensDocumentProvider::Bool(true)),
                range_provider: Some(true),
                work_done_progress_options: Default::default(),
            }
            .into(),
        ),
        experimental: Some(json!({
            "joinLines": true,
            "ssr": true,
            "onEnter": true,
            "parentModule": true,
            "runnables": {
                "kinds": [ "cargo" ],
            },
        })),
    }
}

fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProviderCapability {
    client_caps
        .text_document
        .as_ref()
        .and_then(|it| it.code_action.as_ref())
        .and_then(|it| it.code_action_literal_support.as_ref())
        .map_or(CodeActionProviderCapability::Simple(true), |_| {
            CodeActionProviderCapability::Options(CodeActionOptions {
                // Advertise support for all built-in CodeActionKinds.
                // Ideally we would base this off of the client capabilities
                // but the client is supposed to fall back gracefully for unknown values.
                code_action_kinds: Some(vec![
                    CodeActionKind::EMPTY,
                    CodeActionKind::QUICKFIX,
                    CodeActionKind::REFACTOR,
                    CodeActionKind::REFACTOR_EXTRACT,
                    CodeActionKind::REFACTOR_INLINE,
                    CodeActionKind::REFACTOR_REWRITE,
                ]),
                work_done_progress_options: Default::default(),
            })
        })
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::result::Result as RResult;

use toml::{Parser, Value};

/**
 * Errors which are related to configuration-file loading
 */
pub mod error {
    use std::error::Error;
    use std::fmt::{Debug, Display, Formatter};
    use std::fmt::Error as FmtError;

    /**
     * The kind of an error
     */
    #[derive(Clone, Debug, PartialEq)]
    pub enum ConfigErrorKind {
        ConfigParsingFailed,
        NoConfigFileFound,
    }

    /**
     * Configuration error type
     */
    #[derive(Debug)]
    pub struct ConfigError {
        kind: ConfigErrorKind,
        cause: Option<Box<Error>>,
    }

    impl ConfigError {

        /**
         * Instantiate a new ConfigError, optionally with cause
         */
        pub fn new(kind: ConfigErrorKind, cause: Option<Box<Error>>) -> ConfigError {
            ConfigError {
                kind: kind,
                cause: cause,
            }
        }

        /**
         * get the Kind of the Error
         */
        pub fn kind(&self) -> ConfigErrorKind {
            self.kind.clone()
        }

        /**
         * Get the string, the ConfigError can be described with
         */
        pub fn as_str(e: &ConfigError) -> &'static str {
            match e.kind() {
                ConfigErrorKind::ConfigParsingFailed => "Config parsing failed",
                ConfigErrorKind::NoConfigFileFound   => "No config file found",
            }
        }

    }

    impl Display for ConfigError {

        fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
            try!(write!(fmt, "{}", ConfigError::as_str(self)));
            Ok(())
        }

    }

    impl Error for ConfigError {

        fn description(&self) -> &str {
            ConfigError::as_str(self)
        }

        fn cause(&self) -> Option<&Error> {
            self.cause.as_ref().map(|e| &**e)
        }

    }

}

use self::error::{ConfigError, ConfigErrorKind};

/**
 * Result type of this module. Either T or ConfigError
 */
pub type Result<T> = RResult<T, ConfigError>;

/**
 * Configuration object
 *
 * Holds all config variables which are globally available plus the configuration object from the
 * config parser, which can be accessed.
 */
#[derive(Debug)]
pub struct Configuration {

    /**
     * The plain configuration object for direct access if necessary
     */
    config: Value,

    /**
     * The verbosity the program should run with
     */
    verbosity: bool,

    /**
     * The editor which should be used
     */
    editor: Option<String>,

    /**
     * The options the editor should get when opening some file
     */
    editor_opts: String,
}

impl Configuration {

    /**
     * Get a new configuration object.
     *
     * The passed runtimepath is used for searching the configuration file, whereas several file
     * names are tested. If that does not work, the home directory and the XDG basedir are tested
     * with all variants.
     *
     * If that doesn't work either, an error is returned.
     */
    pub fn new(rtp: &PathBuf) -> Result<Configuration> {
        fetch_config(&rtp).map(|cfg| {
            let verbosity   = get_verbosity(&cfg);
            let editor      = get_editor(&cfg);
            let editor_opts = get_editor_opts(&cfg);

            debug!("Building configuration");
            debug!("  - verbosity  : {:?}", verbosity);
            debug!("  - editor     : {:?}", editor);
            debug!("  - editor-opts: {}", editor_opts);

            Configuration {
                config: cfg,
                verbosity: verbosity,
                editor: editor,
                editor_opts: editor_opts,
            }
        })
    }

    pub fn editor(&self) -> Option<&String> {
        self.editor.as_ref()
    }

    pub fn config(&self) -> &Value {
        &self.config
    }

    pub fn store_config(&self) -> Option<&Value> {
        match &self.config {
            &Value::Table(ref tabl) => tabl.get("store"),
            _ => None,
        }
    }

}

fn get_verbosity(v: &Value) -> bool {
    match v {
        &Value::Table(ref t) => t.get("verbose")
                .map(|v| match v { &Value::Boolean(b) => b, _ => false, })
                .unwrap_or(false),
        _ => false,
    }
}

fn get_editor(v: &Value) -> Option<String> {
    match v {
        &Value::Table(ref t) => t.get("editor")
                .and_then(|v| match v { &Value::String(ref s) => Some(s.clone()), _ => None, }),
        _ => None,
    }
}

fn get_editor_opts(v: &Value) -> String {
    match v {
        &Value::Table(ref t) => t.get("editor-opts")
                .and_then(|v| match v { &Value::String(ref s) => Some(s.clone()), _ => None, })
                .unwrap_or(String::new()),
        _ => String::new(),
    }
}

/**
 * Helper to fetch the config file
 *
 * Tests several variants for the config file path and uses the first one which works.
 */
fn fetch_config(rtp: &PathBuf) -> Result<Value> {
    use std::env;
    use std::fs::File;
    use std::io::Read;

    use xdg_basedir;
    use itertools::Itertools;

    use libimagutil::variants::generate_variants as gen_vars;

    let variants = vec!["config", "config.toml", "imagrc", "imagrc.toml"];
    let modifier = |base: &PathBuf, v: &'static str| {
        let mut base = base.clone();
        base.push(format!("/{}", v));
        base
    };

    vec![
        gen_vars(rtp.clone(), variants.clone(), &modifier),

        env::var("HOME").map(|home| gen_vars(PathBuf::from(home), variants.clone(), &modifier))
                        .unwrap_or(vec![]),

        xdg_basedir::get_data_home().map(|data_dir| gen_vars(data_dir, variants.clone(), &modifier))
                                    .unwrap_or(vec![]),
    ].iter()
        .flatten()
        .filter(|path| path.exists())
        .map(|path| {
            let content = {
                let mut s = String::new();
                let mut f = File::open(path);
                if f.is_err() {
                }
                let mut f = f.unwrap();
                f.read_to_string(&mut s);
                s
            };
            Parser::new(&content[..]).parse()
        })
        .filter(|loaded| loaded.is_some())
        .nth(0)
        .map(|inner| Value::Table(inner.unwrap()))
        .ok_or(ConfigError::new(ConfigErrorKind::NoConfigFileFound, None))
}

<commit_msg>Remove unused import<commit_after>use std::path::PathBuf;
use std::result::Result as RResult;

use toml::{Parser, Value};

/**
 * Errors which are related to configuration-file loading
 */
pub mod error {
    use std::error::Error;
    use std::fmt::{Display, Formatter};
    use std::fmt::Error as FmtError;

    /**
     * The kind of an error
     */
    #[derive(Clone, Debug, PartialEq)]
    pub enum ConfigErrorKind {
        ConfigParsingFailed,
        NoConfigFileFound,
    }

    /**
     * Configuration error type
     */
    #[derive(Debug)]
    pub struct ConfigError {
        kind: ConfigErrorKind,
        cause: Option<Box<Error>>,
    }

    impl ConfigError {

        /**
         * Instantiate a new ConfigError, optionally with cause
         */
        pub fn new(kind: ConfigErrorKind, cause: Option<Box<Error>>) -> ConfigError {
            ConfigError {
                kind: kind,
                cause: cause,
            }
        }

        /**
         * get the Kind of the Error
         */
        pub fn kind(&self) -> ConfigErrorKind {
            self.kind.clone()
        }

        /**
         * Get the string, the ConfigError can be described with
         */
        pub fn as_str(e: &ConfigError) -> &'static str {
            match e.kind() {
                ConfigErrorKind::ConfigParsingFailed => "Config parsing failed",
                ConfigErrorKind::NoConfigFileFound   => "No config file found",
            }
        }

    }

    impl Display for ConfigError {

        fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
            try!(write!(fmt, "{}", ConfigError::as_str(self)));
            Ok(())
        }

    }

    impl Error for ConfigError {

        fn description(&self) -> &str {
            ConfigError::as_str(self)
        }

        fn cause(&self) -> Option<&Error> {
            self.cause.as_ref().map(|e| &**e)
        }

    }

}

use self::error::{ConfigError, ConfigErrorKind};

/**
 * Result type of this module. Either T or ConfigError
 */
pub type Result<T> = RResult<T, ConfigError>;

/**
 * Configuration object
 *
 * Holds all config variables which are globally available plus the configuration object from the
 * config parser, which can be accessed.
 */
#[derive(Debug)]
pub struct Configuration {

    /**
     * The plain configuration object for direct access if necessary
     */
    config: Value,

    /**
     * The verbosity the program should run with
     */
    verbosity: bool,

    /**
     * The editor which should be used
     */
    editor: Option<String>,

    /**
     * The options the editor should get when opening some file
     */
    editor_opts: String,
}

impl Configuration {

    /**
     * Get a new configuration object.
     *
     * The passed runtimepath is used for searching the configuration file, whereas several file
     * names are tested. If that does not work, the home directory and the XDG basedir are tested
     * with all variants.
     *
     * If that doesn't work either, an error is returned.
     */
    pub fn new(rtp: &PathBuf) -> Result<Configuration> {
        fetch_config(&rtp).map(|cfg| {
            let verbosity   = get_verbosity(&cfg);
            let editor      = get_editor(&cfg);
            let editor_opts = get_editor_opts(&cfg);

            debug!("Building configuration");
            debug!("  - verbosity  : {:?}", verbosity);
            debug!("  - editor     : {:?}", editor);
            debug!("  - editor-opts: {}", editor_opts);

            Configuration {
                config: cfg,
                verbosity: verbosity,
                editor: editor,
                editor_opts: editor_opts,
            }
        })
    }

    pub fn editor(&self) -> Option<&String> {
        self.editor.as_ref()
    }

    pub fn config(&self) -> &Value {
        &self.config
    }

    pub fn store_config(&self) -> Option<&Value> {
        match &self.config {
            &Value::Table(ref tabl) => tabl.get("store"),
            _ => None,
        }
    }

}

fn get_verbosity(v: &Value) -> bool {
    match v {
        &Value::Table(ref t) => t.get("verbose")
                .map(|v| match v { &Value::Boolean(b) => b, _ => false, })
                .unwrap_or(false),
        _ => false,
    }
}

fn get_editor(v: &Value) -> Option<String> {
    match v {
        &Value::Table(ref t) => t.get("editor")
                .and_then(|v| match v { &Value::String(ref s) => Some(s.clone()), _ => None, }),
        _ => None,
    }
}

fn get_editor_opts(v: &Value) -> String {
    match v {
        &Value::Table(ref t) => t.get("editor-opts")
                .and_then(|v| match v { &Value::String(ref s) => Some(s.clone()), _ => None, })
                .unwrap_or(String::new()),
        _ => String::new(),
    }
}

/**
 * Helper to fetch the config file
 *
 * Tests several variants for the config file path and uses the first one which works.
 */
fn fetch_config(rtp: &PathBuf) -> Result<Value> {
    use std::env;
    use std::fs::File;
    use std::io::Read;

    use xdg_basedir;
    use itertools::Itertools;

    use libimagutil::variants::generate_variants as gen_vars;

    let variants = vec!["config", "config.toml", "imagrc", "imagrc.toml"];
    let modifier = |base: &PathBuf, v: &'static str| {
        let mut base = base.clone();
        base.push(format!("/{}", v));
        base
    };

    vec![
        gen_vars(rtp.clone(), variants.clone(), &modifier),

        env::var("HOME").map(|home| gen_vars(PathBuf::from(home), variants.clone(), &modifier))
                        .unwrap_or(vec![]),

        xdg_basedir::get_data_home().map(|data_dir| gen_vars(data_dir, variants.clone(), &modifier))
                                    .unwrap_or(vec![]),
    ].iter()
        .flatten()
        .filter(|path| path.exists())
        .map(|path| {
            let content = {
                let mut s = String::new();
                let mut f = File::open(path);
                if f.is_err() {
                }
                let mut f = f.unwrap();
                f.read_to_string(&mut s);
                s
            };
            Parser::new(&content[..]).parse()
        })
        .filter(|loaded| loaded.is_some())
        .nth(0)
        .map(|inner| Value::Table(inner.unwrap()))
        .ok_or(ConfigError::new(ConfigErrorKind::NoConfigFileFound, None))
}

<|endoftext|>


<commit_before>#[macro_use]
mod common;

use std::os::unix::raw::mode_t;
use std::os::unix::fs::PermissionsExt;
use std::os::unix::fs::OpenOptionsExt;
use common::util::*;

static UTIL_NAME: &'static str = "chmod";
static TEST_FILE: &'static str = "file";

struct TestCase {
    args: Vec<&'static str>,
    before: mode_t,
    after: mode_t
}

fn mkfile(file: &str, mode: mode_t) {
    std::fs::OpenOptions::new().mode(mode).create(true).open(file).unwrap();
    let mut perms = std::fs::metadata(file).unwrap().permissions();
    perms.set_mode(mode);
    std::fs::set_permissions(file, perms).unwrap();
}

fn run_tests(tests: Vec<TestCase>) {
    for test in tests {
        let (at, mut ucmd) = testing(UTIL_NAME);

        mkfile(&at.plus_as_string(TEST_FILE), test.before);
        let perms = at.metadata(TEST_FILE).permissions().mode();
        if perms != test.before{
            panic!(format!("{}: expected: {:o} got: {:o}", "setting permissions failed", test.after, perms));
        }

        for arg in test.args {
            ucmd.arg(arg);
        }
        let r = ucmd.run();
        if !r.success {
            println!("{}", r.stderr);
            panic!(format!("{:?}: failed", ucmd.raw));
        }

        let perms = at.metadata(TEST_FILE).permissions().mode();
        if perms != test.after {
            panic!(format!("{:?}: expected: {:o} got: {:o}", ucmd.raw, test.after, perms));
        }
    }
}

#[test]
fn test_chmod_octal() {
    let tests = vec!{
        TestCase{args: vec!{"0700",  TEST_FILE}, before: 0o000, after: 0o700},
        TestCase{args: vec!{"0070",  TEST_FILE}, before: 0o000, after: 0o070},
        TestCase{args: vec!{"0007",  TEST_FILE}, before: 0o000, after: 0o007},
        // Known failues: #788
        // TestCase{args: vec!{"-0700", TEST_FILE}, before: 0o700, after: 0o000},
        // TestCase{args: vec!{"-0070", TEST_FILE}, before: 0o060, after: 0o000},
        // TestCase{args: vec!{"-0007", TEST_FILE}, before: 0o001, after: 0o000},
        TestCase{args: vec!{"+0100", TEST_FILE}, before: 0o600, after: 0o700},
        TestCase{args: vec!{"+0020", TEST_FILE}, before: 0o050, after: 0o070},
        TestCase{args: vec!{"+0004", TEST_FILE}, before: 0o003, after: 0o007},
    };
    run_tests(tests);
}

#[test]
fn test_chmod_ugoa() {
    let tests = vec!{
        TestCase{args: vec!{"u=rwx", TEST_FILE}, before: 0o000, after: 0o700},
        TestCase{args: vec!{"g=rwx", TEST_FILE}, before: 0o000, after: 0o070},
        TestCase{args: vec!{"o=rwx", TEST_FILE}, before: 0o000, after: 0o007},
        TestCase{args: vec!{"a=rwx", TEST_FILE}, before: 0o000, after: 0o777},
    };
    run_tests(tests);
}

#[test]
fn test_chmod_ugo_copy() {
    let tests = vec!{
        TestCase{args: vec!{"u=g", TEST_FILE}, before: 0o070, after: 0o770},
        TestCase{args: vec!{"g=o", TEST_FILE}, before: 0o005, after: 0o055},
        TestCase{args: vec!{"o=u", TEST_FILE}, before: 0o200, after: 0o202},
        TestCase{args: vec!{"u-g", TEST_FILE}, before: 0o710, after: 0o610},
        TestCase{args: vec!{"u+g", TEST_FILE}, before: 0o250, after: 0o750},
    };
    run_tests(tests);
}
<commit_msg>tests/chmod: fix tests on nightly<commit_after>#[macro_use]
mod common;

use std::os::unix::raw::mode_t;
use std::os::unix::fs::PermissionsExt;
use std::os::unix::fs::OpenOptionsExt;
use common::util::*;

static UTIL_NAME: &'static str = "chmod";
static TEST_FILE: &'static str = "file";

struct TestCase {
    args: Vec<&'static str>,
    before: mode_t,
    after: mode_t
}

fn mkfile(file: &str, mode: mode_t) {
    std::fs::OpenOptions::new().mode(mode).create(true).write(true).open(file).unwrap();
    let mut perms = std::fs::metadata(file).unwrap().permissions();
    perms.set_mode(mode);
    std::fs::set_permissions(file, perms).unwrap();
}

fn run_tests(tests: Vec<TestCase>) {
    for test in tests {
        let (at, mut ucmd) = testing(UTIL_NAME);

        mkfile(&at.plus_as_string(TEST_FILE), test.before);
        let perms = at.metadata(TEST_FILE).permissions().mode();
        if perms != test.before{
            panic!(format!("{}: expected: {:o} got: {:o}", "setting permissions failed", test.after, perms));
        }

        for arg in test.args {
            ucmd.arg(arg);
        }
        let r = ucmd.run();
        if !r.success {
            println!("{}", r.stderr);
            panic!(format!("{:?}: failed", ucmd.raw));
        }

        let perms = at.metadata(TEST_FILE).permissions().mode();
        if perms != test.after {
            panic!(format!("{:?}: expected: {:o} got: {:o}", ucmd.raw, test.after, perms));
        }
    }
}

#[test]
fn test_chmod_octal() {
    let tests = vec!{
        TestCase{args: vec!{"0700",  TEST_FILE}, before: 0o000, after: 0o700},
        TestCase{args: vec!{"0070",  TEST_FILE}, before: 0o000, after: 0o070},
        TestCase{args: vec!{"0007",  TEST_FILE}, before: 0o000, after: 0o007},
        // Known failues: #788
        // TestCase{args: vec!{"-0700", TEST_FILE}, before: 0o700, after: 0o000},
        // TestCase{args: vec!{"-0070", TEST_FILE}, before: 0o060, after: 0o000},
        // TestCase{args: vec!{"-0007", TEST_FILE}, before: 0o001, after: 0o000},
        TestCase{args: vec!{"+0100", TEST_FILE}, before: 0o600, after: 0o700},
        TestCase{args: vec!{"+0020", TEST_FILE}, before: 0o050, after: 0o070},
        TestCase{args: vec!{"+0004", TEST_FILE}, before: 0o003, after: 0o007},
    };
    run_tests(tests);
}

#[test]
fn test_chmod_ugoa() {
    let tests = vec!{
        TestCase{args: vec!{"u=rwx", TEST_FILE}, before: 0o000, after: 0o700},
        TestCase{args: vec!{"g=rwx", TEST_FILE}, before: 0o000, after: 0o070},
        TestCase{args: vec!{"o=rwx", TEST_FILE}, before: 0o000, after: 0o007},
        TestCase{args: vec!{"a=rwx", TEST_FILE}, before: 0o000, after: 0o777},
    };
    run_tests(tests);
}

#[test]
fn test_chmod_ugo_copy() {
    let tests = vec!{
        TestCase{args: vec!{"u=g", TEST_FILE}, before: 0o070, after: 0o770},
        TestCase{args: vec!{"g=o", TEST_FILE}, before: 0o005, after: 0o055},
        TestCase{args: vec!{"o=u", TEST_FILE}, before: 0o200, after: 0o202},
        TestCase{args: vec!{"u-g", TEST_FILE}, before: 0o710, after: 0o610},
        TestCase{args: vec!{"u+g", TEST_FILE}, before: 0o250, after: 0o750},
    };
    run_tests(tests);
}
<|endoftext|>


<commit_before>use indoc::indoc;
use serde_json::{json, Number, Value};

#[test]
fn number() {
    assert_eq!(format!("{:?}", Number::from(1)), "Number(1)");
    assert_eq!(format!("{:?}", Number::from(-1)), "Number(-1)");
    assert_eq!(
        format!("{:?}", Number::from_f64(1.0).unwrap()),
        "Number(1.0)"
    );
}

#[test]
fn value_null() {
    assert_eq!(format!("{:?}", json!(null)), "Null");
}

#[test]
fn value_bool() {
    assert_eq!(format!("{:?}", json!(true)), "Bool(true)");
    assert_eq!(format!("{:?}", json!(false)), "Bool(false)");
}

#[test]
fn value_number() {
    assert_eq!(format!("{:?}", json!(1)), "Number(1)");
    assert_eq!(format!("{:?}", json!(-1)), "Number(-1)");
    assert_eq!(format!("{:?}", json!(1.0)), "Number(1.0)");
}

#[test]
fn value_string() {
    assert_eq!(format!("{:?}", json!("s")), "String(\"s\")");
}

#[test]
fn value_array() {
    assert_eq!(format!("{:?}", json!([])), "Array []");
}

#[test]
fn value_object() {
    assert_eq!(format!("{:?}", json!({})), "Object {}");
}

#[test]
fn error() {
    let err = serde_json::from_str::<Value>("{0}").unwrap_err();
    let expected = "Error(\"key must be a string\", line: 1, column: 2)";
    assert_eq!(format!("{:?}", err), expected);
}

#[test]
fn indented() {
    let j = json!({
        "Array": [true],
        "Bool": true,
        "EmptyArray": [],
        "EmptyObject": {},
        "Null": null,
        "Number": 1,
        "String": "...",
    });
    let expected = indoc! {r#"
        Object {
            "Array": Array [
                Bool(true),
            ],
            "Bool": Bool(true),
            "EmptyArray": Array [],
            "EmptyObject": Object {},
            "Null": Null,
            "Number": Number(1),
            "String": String("..."),
        }"#
    };
    assert_eq!(format!("{:#?}", j), expected);
}
<commit_msg>Add test of Display for Number containing float<commit_after>use indoc::indoc;
use serde_json::{json, Number, Value};

#[test]
fn number() {
    assert_eq!(format!("{:?}", Number::from(1)), "Number(1)");
    assert_eq!(format!("{:?}", Number::from(-1)), "Number(-1)");
    assert_eq!(
        format!("{:?}", Number::from_f64(1.0).unwrap()),
        "Number(1.0)"
    );
}

#[test]
fn value_null() {
    assert_eq!(format!("{:?}", json!(null)), "Null");
}

#[test]
fn value_bool() {
    assert_eq!(format!("{:?}", json!(true)), "Bool(true)");
    assert_eq!(format!("{:?}", json!(false)), "Bool(false)");
}

#[test]
fn value_number() {
    assert_eq!(format!("{:?}", json!(1)), "Number(1)");
    assert_eq!(format!("{:?}", json!(-1)), "Number(-1)");
    assert_eq!(format!("{:?}", json!(1.0)), "Number(1.0)");
    assert_eq!(Number::from_f64(1.0).unwrap().to_string(), "1");
}

#[test]
fn value_string() {
    assert_eq!(format!("{:?}", json!("s")), "String(\"s\")");
}

#[test]
fn value_array() {
    assert_eq!(format!("{:?}", json!([])), "Array []");
}

#[test]
fn value_object() {
    assert_eq!(format!("{:?}", json!({})), "Object {}");
}

#[test]
fn error() {
    let err = serde_json::from_str::<Value>("{0}").unwrap_err();
    let expected = "Error(\"key must be a string\", line: 1, column: 2)";
    assert_eq!(format!("{:?}", err), expected);
}

#[test]
fn indented() {
    let j = json!({
        "Array": [true],
        "Bool": true,
        "EmptyArray": [],
        "EmptyObject": {},
        "Null": null,
        "Number": 1,
        "String": "...",
    });
    let expected = indoc! {r#"
        Object {
            "Array": Array [
                Bool(true),
            ],
            "Bool": Bool(true),
            "EmptyArray": Array [],
            "EmptyObject": Object {},
            "Null": Null,
            "Number": Number(1),
            "String": String("..."),
        }"#
    };
    assert_eq!(format!("{:#?}", j), expected);
}
<|endoftext|>


<commit_before>#![feature(phase)]

#[phase(plugin)]
extern crate quickcheck_macros;
extern crate quickcheck;

use quickcheck::TestResult;

#[quickcheck]
fn min(x: int, y: int) -> TestResult {
    if x < y {
        return TestResult::discard()
    } else {
        return TestResult::from_bool(::std::cmp::min(x, y) == y)
    }
}

#[quickcheck]
#[should_fail]
fn fail_fn() -> bool { false }

#[quickcheck]
static static_bool: bool = true;

#[quickcheck]
#[should_fail]
static fail_static_bool: bool = false;

// If static_bool wasn't turned into a test function, then this should
// result in a compiler error.
#[test]
fn static_bool_test_is_function() {
    static_bool()
}
<commit_msg>Fix some tests.<commit_after>#![allow(non_uppercase_statics)]
#![feature(phase)]

#[phase(plugin)]
extern crate quickcheck_macros;
extern crate quickcheck;

use quickcheck::TestResult;

#[quickcheck]
fn min(x: int, y: int) -> TestResult {
    if x < y {
        return TestResult::discard()
    } else {
        return TestResult::from_bool(::std::cmp::min(x, y) == y)
    }
}

// #[quickcheck]
// #[should_fail]
// fn fail_fn() -> bool { false }

#[quickcheck]
static static_bool: bool = true;

#[quickcheck]
#[should_fail]
static fail_static_bool: bool = false;

// If static_bool wasn't turned into a test function, then this should
// result in a compiler error.
#[test]
fn static_bool_test_is_function() {
    static_bool()
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Alan Andrade <alan.andradec@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.
//  *
//  * Synced with: https://raw.github.com/avsm/src/master/usr.bin/head/head.c

#[macro_use]
extern crate uucore;

use std::collections::VecDeque;
use std::fs::File;
use std::io::{stdin, BufRead, BufReader, Read};
use std::path::Path;
use std::str::from_utf8;

static SYNTAX: &str = "";
static SUMMARY: &str = "";
static LONG_HELP: &str = "";

enum FilterMode {
    Bytes(usize),
    Lines(usize),
    NLines(usize),
}

struct Settings {
    mode: FilterMode,
    verbose: bool,
    zero_terminated: bool,
}

impl Default for Settings {
    fn default() -> Settings {
        Settings {
            mode: FilterMode::Lines(10),
            verbose: false,
            zero_terminated: false,
        }
    }
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args.collect_str();

    let mut settings: Settings = Default::default();

    // handle obsolete -number syntax
    let new_args = match obsolete(&args[0..]) {
        (args, Some(n)) => {
            settings.mode = FilterMode::Lines(n);
            args
        }
        (args, None) => args,
    };

    let matches = app!(SYNTAX, SUMMARY, LONG_HELP)
        .optopt(
            "c",
            "bytes",
            "Print the first K bytes.  With the leading '-', print all but the last K bytes",
            "[-]K",
        )
        .optopt(
            "n",
            "lines",
            "Print the first K lines.  With the leading '-', print all but the last K lines",
            "[-]K",
        )
        .optflag("q", "quiet", "never print headers giving file names")
        .optflag("v", "verbose", "always print headers giving file names")
        .optflag("z", "zero-terminated", "line delimiter is NUL, not newline")
        .optflag("h", "help", "display this help and exit")
        .optflag("V", "version", "output version information and exit")
        .parse(new_args);

    let use_bytes = matches.opt_present("c");
    // TODO: suffixes (e.g. b, kB, etc.)
    match matches.opt_str("n") {
        Some(n) => {
            if use_bytes {
                show_error!("cannot specify both --bytes and --lines.");
                return 1;
            }

            match n.parse::<isize>() {
                Ok(m) => {
                    settings.mode = if m < 0 {
                        let m: usize = m.abs() as usize;
                        FilterMode::NLines(m)
                    } else {
                        let m: usize = m.abs() as usize;
                        FilterMode::Lines(m)
                    }
                }
                Err(e) => {
                    show_error!("invalid line count '{}': {}", n, e);
                    return 1;
                }
            }
        }
        None => {
            if let Some(count) = matches.opt_str("c") {
                match count.parse::<usize>() {
                    Ok(m) => settings.mode = FilterMode::Bytes(m),
                    Err(e) => {
                        show_error!("invalid byte count '{}': {}", count, e);
                        return 1;
                    }
                }
            }
        }
    };

    let quiet = matches.opt_present("q");
    let verbose = matches.opt_present("v");
    settings.zero_terminated = matches.opt_present("z");
    let files = matches.free;

    // GNU implementation allows multiple declarations of "-q" and "-v" with the
    // last flag winning. This can't be simulated with the getopts cargo unless
    // we manually parse the arguments. Given the declaration of both flags,
    // verbose mode always wins. This is a potential future improvement.
    if files.len() > 1 && !quiet && !verbose {
        settings.verbose = true;
    }
    if quiet {
        settings.verbose = false;
    }
    if verbose {
        settings.verbose = true;
    }

    if files.is_empty() {
        let mut buffer = BufReader::new(stdin());
        head(&mut buffer, &settings);
    } else {
        let mut first_time = true;

        for file in &files {
            if settings.verbose {
                if !first_time {
                    println!();
                }
                println!("==> {} <==", file);
            }
            first_time = false;

            let path = Path::new(file);
            let reader = File::open(&path).unwrap();
            let mut buffer = BufReader::new(reader);
            if !head(&mut buffer, &settings) {
                break;
            }
        }
    }

    0
}

// It searches for an option in the form of -123123
//
// In case is found, the options vector will get rid of that object so that
// getopts works correctly.
fn obsolete(options: &[String]) -> (Vec<String>, Option<usize>) {
    let mut options: Vec<String> = options.to_vec();
    let mut a = 1;
    let b = options.len();

    while a < b {
        let previous = options[a - 1].clone();
        let current = options[a].clone();
        let current = current.as_bytes();

        if previous != "-n" && current.len() > 1 && current[0] == b'-' {
            let len = current.len();
            for pos in 1..len {
                // Ensure that the argument is only made out of digits
                if !(current[pos] as char).is_numeric() {
                    break;
                }

                // If this is the last number
                if pos == len - 1 {
                    options.remove(a);
                    let number: Option<usize> =
                        from_utf8(&current[1..len]).unwrap().parse::<usize>().ok();
                    return (options, Some(number.unwrap()));
                }
            }
        }

        a += 1;
    }

    (options, None)
}

// TODO: handle errors on read
fn head<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> bool {
    match settings.mode {
        FilterMode::Bytes(count) => {
            for byte in reader.bytes().take(count) {
                print!("{}", byte.unwrap() as char);
            }
        }
        FilterMode::Lines(count) => {
            if settings.zero_terminated {
                for line in reader.split(0).take(count) {
                    print!("{}\0", String::from_utf8(line.unwrap()).unwrap())
                }
            } else {
                for line in reader.lines().take(count) {
                    println!("{}", line.unwrap());
                }
            }
        }
        FilterMode::NLines(count) => {
            let mut vector: VecDeque<String> = VecDeque::new();

            for line in reader.lines() {
                vector.push_back(line.unwrap());
                if vector.len() <= count {
                    continue;
                }
                println!("{}", vector.pop_front().unwrap());
            }
        }
    }
    true
}
<commit_msg>Format head.rs<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Alan Andrade <alan.andradec@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.
//  *
//  * Synced with: https://raw.github.com/avsm/src/master/usr.bin/head/head.c

#[macro_use]
extern crate uucore;

use std::collections::VecDeque;
use std::fs::File;
use std::io::{stdin, BufRead, BufReader, Read};
use std::path::Path;
use std::str::from_utf8;

static SYNTAX: &str = "";
static SUMMARY: &str = "";
static LONG_HELP: &str = "";

enum FilterMode {
    Bytes(usize),
    Lines(usize),
    NLines(usize),
}

struct Settings {
    mode: FilterMode,
    verbose: bool,
    zero_terminated: bool,
}

impl Default for Settings {
    fn default() -> Settings {
        Settings {
            mode: FilterMode::Lines(10),
            verbose: false,
            zero_terminated: false,
        }
    }
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args.collect_str();

    let mut settings: Settings = Default::default();

    // handle obsolete -number syntax
    let new_args = match obsolete(&args[0..]) {
        (args, Some(n)) => {
            settings.mode = FilterMode::Lines(n);
            args
        }
        (args, None) => args,
    };

    let matches = app!(SYNTAX, SUMMARY, LONG_HELP)
        .optopt(
            "c",
            "bytes",
            "Print the first K bytes.  With the leading '-', print all but the last K bytes",
            "[-]K",
        )
        .optopt(
            "n",
            "lines",
            "Print the first K lines.  With the leading '-', print all but the last K lines",
            "[-]K",
        )
        .optflag("q", "quiet", "never print headers giving file names")
        .optflag("v", "verbose", "always print headers giving file names")
        .optflag("z", "zero-terminated", "line delimiter is NUL, not newline")
        .optflag("h", "help", "display this help and exit")
        .optflag("V", "version", "output version information and exit")
        .parse(new_args);

    let use_bytes = matches.opt_present("c");
    // TODO: suffixes (e.g. b, kB, etc.)
    match matches.opt_str("n") {
        Some(n) => {
            if use_bytes {
                show_error!("cannot specify both --bytes and --lines.");
                return 1;
            }

            match n.parse::<isize>() {
                Ok(m) => {
                    settings.mode = if m < 0 {
                        let m: usize = m.abs() as usize;
                        FilterMode::NLines(m)
                    } else {
                        let m: usize = m.abs() as usize;
                        FilterMode::Lines(m)
                    }
                }
                Err(e) => {
                    show_error!("invalid line count '{}': {}", n, e);
                    return 1;
                }
            }
        }
        None => {
            if let Some(count) = matches.opt_str("c") {
                match count.parse::<usize>() {
                    Ok(m) => settings.mode = FilterMode::Bytes(m),
                    Err(e) => {
                        show_error!("invalid byte count '{}': {}", count, e);
                        return 1;
                    }
                }
            }
        }
    };

    let quiet = matches.opt_present("q");
    let verbose = matches.opt_present("v");
    settings.zero_terminated = matches.opt_present("z");
    let files = matches.free;

    // GNU implementation allows multiple declarations of "-q" and "-v" with the
    // last flag winning. This can't be simulated with the getopts cargo unless
    // we manually parse the arguments. Given the declaration of both flags,
    // verbose mode always wins. This is a potential future improvement.
    if files.len() > 1 && !quiet && !verbose {
        settings.verbose = true;
    }
    if quiet {
        settings.verbose = false;
    }
    if verbose {
        settings.verbose = true;
    }

    if files.is_empty() {
        let mut buffer = BufReader::new(stdin());
        head(&mut buffer, &settings);
    } else {
        let mut first_time = true;

        for file in &files {
            if settings.verbose {
                if !first_time {
                    println!();
                }
                println!("==> {} <==", file);
            }
            first_time = false;

            let path = Path::new(file);
            let reader = File::open(&path).unwrap();
            let mut buffer = BufReader::new(reader);
            if !head(&mut buffer, &settings) {
                break;
            }
        }
    }

    0
}

// It searches for an option in the form of -123123
//
// In case is found, the options vector will get rid of that object so that
// getopts works correctly.
fn obsolete(options: &[String]) -> (Vec<String>, Option<usize>) {
    let mut options: Vec<String> = options.to_vec();
    let mut a = 1;
    let b = options.len();

    while a < b {
        let previous = options[a - 1].clone();
        let current = options[a].clone();
        let current = current.as_bytes();

        if previous != "-n" && current.len() > 1 && current[0] == b'-' {
            let len = current.len();
            for pos in 1..len {
                // Ensure that the argument is only made out of digits
                if !(current[pos] as char).is_numeric() {
                    break;
                }

                // If this is the last number
                if pos == len - 1 {
                    options.remove(a);
                    let number: Option<usize> =
                        from_utf8(&current[1..len]).unwrap().parse::<usize>().ok();
                    return (options, Some(number.unwrap()));
                }
            }
        }

        a += 1;
    }

    (options, None)
}

// TODO: handle errors on read
fn head<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> bool {
    match settings.mode {
        FilterMode::Bytes(count) => {
            for byte in reader.bytes().take(count) {
                print!("{}", byte.unwrap() as char);
            }
        }
        FilterMode::Lines(count) => {
            if settings.zero_terminated {
                for line in reader.split(0).take(count) {
                    print!("{}\0", String::from_utf8(line.unwrap()).unwrap())
                }
            } else {
                for line in reader.lines().take(count) {
                    println!("{}", line.unwrap());
                }
            }
        }
        FilterMode::NLines(count) => {
            let mut vector: VecDeque<String> = VecDeque::new();

            for line in reader.lines() {
                vector.push_back(line.unwrap());
                if vector.len() <= count {
                    continue;
                }
                println!("{}", vector.pop_front().unwrap());
            }
        }
    }
    true
}
<|endoftext|>


<commit_before>extern crate filetime;
extern crate libc;
extern crate rand;
extern crate regex;
extern crate tempdir;
extern crate time;
extern crate uu_tail;

#[cfg(windows)] extern crate kernel32;
#[cfg(windows)] extern crate winapi;

#[macro_use]
mod common;

#[path="../src/factor/sieve.rs"]
mod sieve;

#[cfg(unix)] mod test_chmod;
#[cfg(unix)] mod test_mv;
#[cfg(unix)] mod test_stdbuf;
#[cfg(unix)] mod test_touch;
#[cfg(unix)] mod test_unlink;

mod test_base64;
mod test_basename;
mod test_cat;
mod test_cksum;
mod test_comm;
mod test_cp;
mod test_cut;
mod test_dircolors;
mod test_dirname;
mod test_echo;
mod test_env;
mod test_expr;
mod test_factor;
mod test_false;
mod test_fold;
mod test_hashsum;
mod test_head;
mod test_link;
mod test_ln;
mod test_ls;
mod test_mkdir;
mod test_mktemp;
mod test_nl;
mod test_od;
mod test_paste;
mod test_pathchk;
mod test_printf;
mod test_ptx;
mod test_pwd;
mod test_readlink;
mod test_realpath;
mod test_rm;
mod test_rmdir;
mod test_seq;
mod test_sort;
mod test_split;
mod test_sum;
mod test_tac;
mod test_tail;
mod test_test;
mod test_tr;
mod test_true;
mod test_truncate;
mod test_tsort;
mod test_unexpand;
mod test_uniq;
mod test_wc;
<commit_msg>pathchk: make Unix only<commit_after>extern crate filetime;
extern crate libc;
extern crate rand;
extern crate regex;
extern crate tempdir;
extern crate time;
extern crate uu_tail;

#[cfg(windows)] extern crate kernel32;
#[cfg(windows)] extern crate winapi;

#[macro_use]
mod common;

#[path="../src/factor/sieve.rs"]
mod sieve;

#[cfg(unix)] mod test_chmod;
#[cfg(unix)] mod test_mv;
#[cfg(unix)] mod test_pathchk;
#[cfg(unix)] mod test_stdbuf;
#[cfg(unix)] mod test_touch;
#[cfg(unix)] mod test_unlink;

mod test_base64;
mod test_basename;
mod test_cat;
mod test_cksum;
mod test_comm;
mod test_cp;
mod test_cut;
mod test_dircolors;
mod test_dirname;
mod test_echo;
mod test_env;
mod test_expr;
mod test_factor;
mod test_false;
mod test_fold;
mod test_hashsum;
mod test_head;
mod test_link;
mod test_ln;
mod test_ls;
mod test_mkdir;
mod test_mktemp;
mod test_nl;
mod test_od;
mod test_paste;
mod test_printf;
mod test_ptx;
mod test_pwd;
mod test_readlink;
mod test_realpath;
mod test_rm;
mod test_rmdir;
mod test_seq;
mod test_sort;
mod test_split;
mod test_sum;
mod test_tac;
mod test_tail;
mod test_test;
mod test_tr;
mod test_true;
mod test_truncate;
mod test_tsort;
mod test_unexpand;
mod test_uniq;
mod test_wc;
<|endoftext|>


<commit_before>use crate::consts::{constant_context, Constant};
use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg, walk_ptrs_ty};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `.repeat(1)` and suggest the following method for each types.
    /// - `.to_string()` for `str`
    /// - `.clone()` for `String`
    /// - `.to_vec()` for `slice`
    ///
    /// **Why is this bad?** For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning the string is the intention behind this, `clone()` should be used.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// fn main() {
    ///     let x = String::from("hello world").repeat(1);
    /// }
    /// ```
    /// Use instead:
    /// ```rust
    /// fn main() {
    ///     let x = String::from("hello world").clone();
    /// }
    /// ```
    pub REPEAT_ONCE,
    complexity,
    "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
}

declare_lint_pass!(RepeatOnce => [REPEAT_ONCE]);

impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
        if_chain! {
            if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
            if path.ident.name == sym!(repeat);
            if let Some(Constant::Int(1)) = constant_context(cx, cx.tables()).expr(&args[1]);
            if !in_macro(args[0].span);
            then {
                let ty = walk_ptrs_ty(cx.tables().expr_ty(&args[0]));
                if ty.is_str() {
                    span_lint_and_sugg(
                        cx,
                        REPEAT_ONCE,
                        expr.span,
                        "calling `repeat(1)` on str",
                        "consider using `.to_string()` instead",
                        format!("{}.to_string()", snippet(cx, args[0].span, r#""...""#)),
                        Applicability::MachineApplicable,
                    );
                } else if let Some(_) = ty.builtin_index() {
                    span_lint_and_sugg(
                        cx,
                        REPEAT_ONCE,
                        expr.span,
                        "calling `repeat(1)` on slice",
                        "consider using `.to_vec()` instead",
                        format!("{}.to_vec()", snippet(cx, args[0].span, r#""...""#)),
                        Applicability::MachineApplicable,
                    );
                } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) {
                    span_lint_and_sugg(
                        cx,
                        REPEAT_ONCE,
                        expr.span,
                        "calling `repeat(1)` on a string literal",
                        "consider using `.clone()` instead",
                        format!("{}.clone()", snippet(cx, args[0].span, r#""...""#)),
                        Applicability::MachineApplicable,
                    );
                }
            }
        }
    }
}
<commit_msg>Use `.is_some()` not `Some(_)`<commit_after>use crate::consts::{constant_context, Constant};
use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg, walk_ptrs_ty};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `.repeat(1)` and suggest the following method for each types.
    /// - `.to_string()` for `str`
    /// - `.clone()` for `String`
    /// - `.to_vec()` for `slice`
    ///
    /// **Why is this bad?** For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning the string is the intention behind this, `clone()` should be used.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// fn main() {
    ///     let x = String::from("hello world").repeat(1);
    /// }
    /// ```
    /// Use instead:
    /// ```rust
    /// fn main() {
    ///     let x = String::from("hello world").clone();
    /// }
    /// ```
    pub REPEAT_ONCE,
    complexity,
    "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
}

declare_lint_pass!(RepeatOnce => [REPEAT_ONCE]);

impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
        if_chain! {
            if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
            if path.ident.name == sym!(repeat);
            if let Some(Constant::Int(1)) = constant_context(cx, cx.tables()).expr(&args[1]);
            if !in_macro(args[0].span);
            then {
                let ty = walk_ptrs_ty(cx.tables().expr_ty(&args[0]));
                if ty.is_str() {
                    span_lint_and_sugg(
                        cx,
                        REPEAT_ONCE,
                        expr.span,
                        "calling `repeat(1)` on str",
                        "consider using `.to_string()` instead",
                        format!("{}.to_string()", snippet(cx, args[0].span, r#""...""#)),
                        Applicability::MachineApplicable,
                    );
                } else if ty.builtin_index().is_some() {
                    span_lint_and_sugg(
                        cx,
                        REPEAT_ONCE,
                        expr.span,
                        "calling `repeat(1)` on slice",
                        "consider using `.to_vec()` instead",
                        format!("{}.to_vec()", snippet(cx, args[0].span, r#""...""#)),
                        Applicability::MachineApplicable,
                    );
                } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) {
                    span_lint_and_sugg(
                        cx,
                        REPEAT_ONCE,
                        expr.span,
                        "calling `repeat(1)` on a string literal",
                        "consider using `.clone()` instead",
                        format!("{}.clone()", snippet(cx, args[0].span, r#""...""#)),
                        Applicability::MachineApplicable,
                    );
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/* Copyright 2018-2022 Torbjørn Birch Moltu
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://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.
 */

// Run with -- --nocapture to show error messages if setup fails.
// (or use ./do.sh)

#![cfg(feature="std")]
#![feature(test)]
extern crate test;
use test::{Bencher, black_box};

use std::fs;
use std::path::Path;
use std::io::ErrorKind;
use std::thread::sleep;
use std::time::Duration;
use std::collections::HashMap;
extern crate minreq;
#[macro_use] extern crate lazy_static;
extern crate encode_unicode;
use encode_unicode::{CharExt, Utf8Char, U8UtfExt, Utf16Char, U16UtfExt};

// Setup; need longish strings to make benchmarks representative and
// reduce overhead (might get cache misses now though)
// Therefore we download a few wikipedia articles in different languages.
// Downloading a fixed revision of the articles doesn't prevent the HTML from
// changing due to changes in templates or rendering.

fn load_wikipedia(language: &str,  article: &str,  english: &str,  revision: usize) -> String {
    let cache_path = Path::new("benches").join("texts");
    let cache_path = cache_path.to_str().unwrap();
    let name = format!("{}_{}.html", language, english);
    let path = Path::new(cache_path).join(&name);
    let path = path.to_str().unwrap();
    match fs::read_to_string(path) {
        Ok(content) => return content,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {},//continue
        Err(ref e) if e.kind() == ErrorKind::InvalidData => {
            panic!("{} exists but is not UTF-8", &name);
        },
        Err(e) => panic!("{} exists but cannot be read ({})", path, e),
    }
    let url = format!("https://{}.m.wikipedia.org/w/index.php?title={}&oldid={}",
        language, article, revision
    );
    println!("Downloading {} and saving to {}", &url, path);
    let response = minreq::get(&url).send().unwrap_or_else(|e| {
        panic!("Cannot get {}: {}", url, e);
    });
    if response.status_code != 200 {
        panic!("Bad URL {}: {} {}", url, response.status_code, response.reason_phrase);
    }
    let content = String::from_utf8(response.into_bytes()).unwrap_or_else(|_| {
        panic!("Response from {} is not UTF-8", url);
    });
    if let Err(e) = fs::create_dir_all(cache_path) {
        eprintln!("Warning: failed to create directory {}: {}", cache_path, e);
    } else if let Err(e) = fs::write(&path, &content) {
        eprintln!("Warning: failed to save {}: {}", path, e);
    }
    sleep(Duration::from_secs(1));
    content
}
const ARTICLES: &[(&str, &str, &str, usize)] = &[
    ("en", "United_Kingdom", "United_Kingdom", 855522252),// 99,7% ASCII
    ("es", "España", "Spain", 109861222),// 1,75% 2-byte characters
    ("ru", "Россия", "Russia", 94607243),// 36% 2-byte characters
    // Only UCS / bmp characters are allowed unescaped in URLs:
    ("zh", "%E4%B8%AD%E5%9C%8B", "China", 50868604),// 30% 3-byte characters
];
lazy_static!{
    static ref STRINGS: HashMap<&'static str, String> = {
        let mut content = HashMap::new();
        for &(language, article, english, revision) in ARTICLES {
            content.insert(language, load_wikipedia(language, article, english, revision));
        }
        // make one string with only ASCII
        let only_ascii = content.values()
            .map(|v| (v, v.bytes().filter(|b| b.is_ascii() ).count()) )
            .max_by_key(|&(_,len)| len )
            .map(|(v,_)| v.bytes().filter(|b| b.is_ascii() ).map(|b| b as char ).collect() )
            .unwrap();
        content.insert("ascii", only_ascii);
        content
    };
    static ref EQUAL_CHARS: HashMap<&'static str, &'static str> = {
        let (least, chars) = STRINGS.iter()
            .map(|(l,s)| (l, s.chars().count()) )
            .min_by_key(|&(_,chars)| chars )
            .unwrap();
        println!("chars: {} (limited by {})", chars, least);
        STRINGS.iter().map(|(&language, string)| {
            let cut = string.char_indices()
                .nth(chars)
                .map_or(string.len(), |(i,_)| i );
            let string = &string[..cut];
            assert_eq!(string.chars().count(), chars);
            (language, string)
        }).collect()
    };
    static ref EQUAL_BYTES: HashMap<&'static str, String> = {
        let (least, bytes) = STRINGS.iter()
            .map(|(l,s)| (l, s.len()) )
            .min_by_key(|&(_,bytes)| bytes )
            .unwrap();
        println!("bytes: {} (limited by {})", bytes, least);
        STRINGS.iter().map(|(&language, string)| {
            let mut remaining = bytes;
            // take just so many characters that their length is exactly $bytes
            // slicing won't if !string.is_char_boundary(bytes),
            let string = string.chars().filter(|c| {
                match remaining.checked_sub(c.len_utf8()) {
                    Some(after) => {remaining = after; true},
                    None => false
                }
            }).collect::<String>();
            assert_eq!(string.len(), bytes);
            (language, string)
        }).collect()
    };
    static ref EQUAL_UNITS: HashMap<&'static str, String> = {
        let (least, units) = STRINGS.iter()
            .map(|(l,s)| (l, s.chars().map(|c| c.len_utf16() ).sum::<usize>()) )
            .min_by_key(|&(_,units)| units )
            .unwrap();
        println!("units: {} (limited by {})", units, least);
        STRINGS.iter().map(|(&language, string)| {
            let mut remaining = units;
            let string = string.chars().filter(|c| {
                match remaining.checked_sub(c.len_utf16()) {
                    Some(after) => {remaining = after; true},
                    None => false
                }
            }).collect::<String>();
            assert_eq!(string.chars().map(|c| c.len_utf16() ).sum::<usize>(), units);
            (language, string)
        }).collect()
    };
}

  ///////////////////////////
 // benchmarks begin here //
///////////////////////////

fn utf8char_len(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_BYTES[language];
    let chars: Vec<Utf8Char> = string.chars().map(|c| c.to_utf8() ).collect();
    let bytes = string.len();
    b.iter(|| {
        let sum: usize = black_box(&chars).iter().map(|u8c| u8c.len() ).sum();
        assert_eq!(sum, bytes);
    });
}
#[bench] fn utf8char_len_ascii(b: &mut Bencher) {utf8char_len("ascii", b)}
#[bench] fn utf8char_len_en(b: &mut Bencher) {utf8char_len("en", b)}
#[bench] fn utf8char_len_es(b: &mut Bencher) {utf8char_len("es", b)}
#[bench] fn utf8char_len_ru(b: &mut Bencher) {utf8char_len("ru", b)}
#[bench] fn utf8char_len_zh(b: &mut Bencher) {utf8char_len("zh", b)}

fn utf8_extra_bytes_unchecked(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_CHARS[language];
    let chars = string.chars().count();
    let string = string.as_bytes();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        while i < string.len() {
            i += string[i].extra_utf8_bytes_unchecked();
            i += 1;
            loops += 1;
        }
        assert_eq!(loops, chars);
    });
}
#[bench] fn utf8_extra_bytes_unchecked_ascii(b: &mut Bencher) {utf8_extra_bytes_unchecked("ascii", b)}
#[bench] fn utf8_extra_bytes_unchecked_en(b: &mut Bencher) {utf8_extra_bytes_unchecked("en", b)}
#[bench] fn utf8_extra_bytes_unchecked_es(b: &mut Bencher) {utf8_extra_bytes_unchecked("es", b)}
#[bench] fn utf8_extra_bytes_unchecked_ru(b: &mut Bencher) {utf8_extra_bytes_unchecked("ru", b)}
#[bench] fn utf8_extra_bytes_unchecked_zh(b: &mut Bencher) {utf8_extra_bytes_unchecked("zh", b)}

fn utf8_extra_bytes(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_CHARS[language];
    let chars = string.chars().count();
    let string = string.as_bytes();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        let mut errors = 0;
        while i < string.len() {
            match string[i].extra_utf8_bytes() {
                Ok(n) => i += n,
                Err(_) => errors += 1,
            }
            i += 1;
            loops += 1;
        }
        assert_eq!(loops, chars);
        assert_eq!(errors, 0);
    });
}
#[bench] fn utf8_extra_bytes_ascii(b: &mut Bencher) {utf8_extra_bytes("ascii", b)}
#[bench] fn utf8_extra_bytes_en(b: &mut Bencher) {utf8_extra_bytes("en", b)}
#[bench] fn utf8_extra_bytes_es(b: &mut Bencher) {utf8_extra_bytes("es", b)}
#[bench] fn utf8_extra_bytes_ru(b: &mut Bencher) {utf8_extra_bytes("ru", b)}
#[bench] fn utf8_extra_bytes_zh(b: &mut Bencher) {utf8_extra_bytes("zh", b)}

fn utf16char_len(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_UNITS[language];
    let chars: Vec<Utf16Char> = string.chars().map(|c| c.to_utf16() ).collect();
    let units = string.chars().map(|c| c.len_utf16() ).sum::<usize>();
    b.iter(|| {
        let sum: usize = black_box(&chars).iter().map(|u8c| u8c.len() ).sum();
        assert_eq!(sum, units);
    });
}
#[bench] fn utf16char_len_ascii(b: &mut Bencher) {utf16char_len("ascii", b)}
#[bench] fn utf16char_len_en(b: &mut Bencher) {utf16char_len("en", b)}
#[bench] fn utf16char_len_es(b: &mut Bencher) {utf16char_len("en", b)}
#[bench] fn utf16char_len_ru(b: &mut Bencher) {utf16char_len("ru", b)}
#[bench] fn utf16char_len_zh(b: &mut Bencher) {utf16char_len("zh", b)}

fn utf16_is_leading_surrogate(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_UNITS[language];
    let chars = string.chars().count();
    let string: Vec<u16> = string.chars().map(|c| c.to_utf16() ).collect();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        while i < string.len() {
            i += if string[i].is_utf16_leading_surrogate() {2} else {1};
            loops += 1;
        }
        assert_eq!(loops, chars);
    });
}
#[bench] fn utf16_is_leading_surrogate_ascii(b: &mut Bencher) {utf16_is_leading_surrogate("ascii", b)}
#[bench] fn utf16_is_leading_surrogate_en(b: &mut Bencher) {utf16_is_leading_surrogate("en", b)}
#[bench] fn utf16_is_leading_surrogate_es(b: &mut Bencher) {utf16_is_leading_surrogate("es", b)}
#[bench] fn utf16_is_leading_surrogate_ru(b: &mut Bencher) {utf16_is_leading_surrogate("ru", b)}
#[bench] fn utf16_is_leading_surrogate_zh(b: &mut Bencher) {utf16_is_leading_surrogate("zh", b)}

fn utf16_needs_extra_unit(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_UNITS[language];
    let chars = string.chars().count();
    let string: Vec<u16> = string.chars().map(|c| c.to_utf16() ).collect();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        let mut errors = 0;
        while i < string.len() {
            i += match string[i].utf16_needs_extra_unit() {
                Ok(true) => 2,
                Ok(false) => 1,
                Err(_) => {errors+=1; 1}
            };
            loops += 1;
        }
        assert_eq!(loops, chars);
        assert_eq!(errors, 0);
    });
}
#[bench] fn utf16_needs_extra_unit_ascii(b: &mut Bencher) {utf16_needs_extra_unit("ascii", b)}
#[bench] fn utf16_needs_extra_unit_en(b: &mut Bencher) {utf16_needs_extra_unit("en", b)}
#[bench] fn utf16_needs_extra_unit_es(b: &mut Bencher) {utf16_needs_extra_unit("es", b)}
#[bench] fn utf16_needs_extra_unit_ru(b: &mut Bencher) {utf16_needs_extra_unit("ru", b)}
#[bench] fn utf16_needs_extra_unit_zh(b: &mut Bencher) {utf16_needs_extra_unit("zh", b)}
<commit_msg>Fix downloading for benchmarks<commit_after>/* Copyright 2018-2022 Torbjørn Birch Moltu
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://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.
 */

// Run with -- --nocapture to show error messages if setup fails.
// (or use ./do.sh)

#![cfg(feature="std")]
#![feature(test)]
extern crate test;
use test::{Bencher, black_box};

use std::fs;
use std::path::Path;
use std::io::ErrorKind;
use std::thread::sleep;
use std::time::Duration;
use std::collections::HashMap;
extern crate minreq;
#[macro_use] extern crate lazy_static;
extern crate encode_unicode;
use encode_unicode::{CharExt, Utf8Char, U8UtfExt, Utf16Char, U16UtfExt};

// Setup; need longish strings to make benchmarks representative and
// reduce overhead (might get cache misses now though)
// Therefore we download a few wikipedia articles in different languages.
// Downloading a fixed revision of the articles doesn't prevent the HTML from
// changing due to changes in templates or rendering.

fn load_wikipedia(language: &str,  article: &str,  english: &str,  revision: usize) -> String {
    let cache_path = Path::new("benches").join("texts");
    let cache_path = cache_path.to_str().unwrap();
    let name = format!("{}_{}.html", language, english);
    let path = Path::new(cache_path).join(&name);
    let path = path.to_str().unwrap();
    match fs::read_to_string(path) {
        Ok(content) => return content,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {},//continue
        Err(ref e) if e.kind() == ErrorKind::InvalidData => {
            panic!("{} exists but is not UTF-8", &name);
        },
        Err(e) => panic!("{} exists but cannot be read ({})", path, e),
    }
    let mut article_ascii = String::new();
    for c in article.chars() {
        if c.is_ascii() {
            article_ascii.push(c);
        } else {
            let encoded = format!("%{:2X}", c as u32);
            article_ascii.push_str(encoded.as_str());
        }
    }
    let url = format!("https://{}.m.wikipedia.org/w/index.php?title={}&oldid={}",
        language, article_ascii, revision
    );
    println!("Downloading {} and saving to {}", &url, path);
    let response = minreq::get(&url).send().unwrap_or_else(|e| {
        panic!("Cannot get {}: {}", url, e);
    });
    if response.status_code != 200 {
        panic!("Bad URL {}: {} {}", url, response.status_code, response.reason_phrase);
    }
    let content = String::from_utf8(response.into_bytes()).unwrap_or_else(|_| {
        panic!("Response from {} is not UTF-8", url);
    });
    if let Err(e) = fs::create_dir_all(cache_path) {
        eprintln!("Warning: failed to create directory {}: {}", cache_path, e);
    } else if let Err(e) = fs::write(&path, &content) {
        eprintln!("Warning: failed to save {}: {}", path, e);
    }
    sleep(Duration::from_secs(1));
    content
}
const ARTICLES: &[(&str, &str, &str, usize)] = &[
    ("en", "United_Kingdom", "United_Kingdom", 855522252),// 99,7% ASCII
    ("es", "España", "Spain", 109861222),// 1,75% 2-byte characters
    ("ru", "Россия", "Russia", 94607243),// 36% 2-byte characters
    ("zh", "中國", "China", 50868604),// 30% 3-byte characters
];
lazy_static!{
    static ref STRINGS: HashMap<&'static str, String> = {
        let mut content = HashMap::new();
        for &(language, article, english, revision) in ARTICLES {
            content.insert(language, load_wikipedia(language, article, english, revision));
        }
        // make one string with only ASCII
        let only_ascii = content.values()
            .map(|v| (v, v.bytes().filter(|b| b.is_ascii() ).count()) )
            .max_by_key(|&(_,len)| len )
            .map(|(v,_)| v.bytes().filter(|b| b.is_ascii() ).map(|b| b as char ).collect() )
            .unwrap();
        content.insert("ascii", only_ascii);
        content
    };
    static ref EQUAL_CHARS: HashMap<&'static str, &'static str> = {
        let (least, chars) = STRINGS.iter()
            .map(|(l,s)| (l, s.chars().count()) )
            .min_by_key(|&(_,chars)| chars )
            .unwrap();
        println!("chars: {} (limited by {})", chars, least);
        STRINGS.iter().map(|(&language, string)| {
            let cut = string.char_indices()
                .nth(chars)
                .map_or(string.len(), |(i,_)| i );
            let string = &string[..cut];
            assert_eq!(string.chars().count(), chars);
            (language, string)
        }).collect()
    };
    static ref EQUAL_BYTES: HashMap<&'static str, String> = {
        let (least, bytes) = STRINGS.iter()
            .map(|(l,s)| (l, s.len()) )
            .min_by_key(|&(_,bytes)| bytes )
            .unwrap();
        println!("bytes: {} (limited by {})", bytes, least);
        STRINGS.iter().map(|(&language, string)| {
            let mut remaining = bytes;
            // take just so many characters that their length is exactly $bytes
            // slicing won't if !string.is_char_boundary(bytes),
            let string = string.chars().filter(|c| {
                match remaining.checked_sub(c.len_utf8()) {
                    Some(after) => {remaining = after; true},
                    None => false
                }
            }).collect::<String>();
            assert_eq!(string.len(), bytes);
            (language, string)
        }).collect()
    };
    static ref EQUAL_UNITS: HashMap<&'static str, String> = {
        let (least, units) = STRINGS.iter()
            .map(|(l,s)| (l, s.chars().map(|c| c.len_utf16() ).sum::<usize>()) )
            .min_by_key(|&(_,units)| units )
            .unwrap();
        println!("units: {} (limited by {})", units, least);
        STRINGS.iter().map(|(&language, string)| {
            let mut remaining = units;
            let string = string.chars().filter(|c| {
                match remaining.checked_sub(c.len_utf16()) {
                    Some(after) => {remaining = after; true},
                    None => false
                }
            }).collect::<String>();
            assert_eq!(string.chars().map(|c| c.len_utf16() ).sum::<usize>(), units);
            (language, string)
        }).collect()
    };
}

  ///////////////////////////
 // benchmarks begin here //
///////////////////////////

fn utf8char_len(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_BYTES[language];
    let chars: Vec<Utf8Char> = string.chars().map(|c| c.to_utf8() ).collect();
    let bytes = string.len();
    b.iter(|| {
        let sum: usize = black_box(&chars).iter().map(|u8c| u8c.len() ).sum();
        assert_eq!(sum, bytes);
    });
}
#[bench] fn utf8char_len_ascii(b: &mut Bencher) {utf8char_len("ascii", b)}
#[bench] fn utf8char_len_en(b: &mut Bencher) {utf8char_len("en", b)}
#[bench] fn utf8char_len_es(b: &mut Bencher) {utf8char_len("es", b)}
#[bench] fn utf8char_len_ru(b: &mut Bencher) {utf8char_len("ru", b)}
#[bench] fn utf8char_len_zh(b: &mut Bencher) {utf8char_len("zh", b)}

fn utf8_extra_bytes_unchecked(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_CHARS[language];
    let chars = string.chars().count();
    let string = string.as_bytes();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        while i < string.len() {
            i += string[i].extra_utf8_bytes_unchecked();
            i += 1;
            loops += 1;
        }
        assert_eq!(loops, chars);
    });
}
#[bench] fn utf8_extra_bytes_unchecked_ascii(b: &mut Bencher) {utf8_extra_bytes_unchecked("ascii", b)}
#[bench] fn utf8_extra_bytes_unchecked_en(b: &mut Bencher) {utf8_extra_bytes_unchecked("en", b)}
#[bench] fn utf8_extra_bytes_unchecked_es(b: &mut Bencher) {utf8_extra_bytes_unchecked("es", b)}
#[bench] fn utf8_extra_bytes_unchecked_ru(b: &mut Bencher) {utf8_extra_bytes_unchecked("ru", b)}
#[bench] fn utf8_extra_bytes_unchecked_zh(b: &mut Bencher) {utf8_extra_bytes_unchecked("zh", b)}

fn utf8_extra_bytes(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_CHARS[language];
    let chars = string.chars().count();
    let string = string.as_bytes();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        let mut errors = 0;
        while i < string.len() {
            match string[i].extra_utf8_bytes() {
                Ok(n) => i += n,
                Err(_) => errors += 1,
            }
            i += 1;
            loops += 1;
        }
        assert_eq!(loops, chars);
        assert_eq!(errors, 0);
    });
}
#[bench] fn utf8_extra_bytes_ascii(b: &mut Bencher) {utf8_extra_bytes("ascii", b)}
#[bench] fn utf8_extra_bytes_en(b: &mut Bencher) {utf8_extra_bytes("en", b)}
#[bench] fn utf8_extra_bytes_es(b: &mut Bencher) {utf8_extra_bytes("es", b)}
#[bench] fn utf8_extra_bytes_ru(b: &mut Bencher) {utf8_extra_bytes("ru", b)}
#[bench] fn utf8_extra_bytes_zh(b: &mut Bencher) {utf8_extra_bytes("zh", b)}

fn utf16char_len(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_UNITS[language];
    let chars: Vec<Utf16Char> = string.chars().map(|c| c.to_utf16() ).collect();
    let units = string.chars().map(|c| c.len_utf16() ).sum::<usize>();
    b.iter(|| {
        let sum: usize = black_box(&chars).iter().map(|u8c| u8c.len() ).sum();
        assert_eq!(sum, units);
    });
}
#[bench] fn utf16char_len_ascii(b: &mut Bencher) {utf16char_len("ascii", b)}
#[bench] fn utf16char_len_en(b: &mut Bencher) {utf16char_len("en", b)}
#[bench] fn utf16char_len_es(b: &mut Bencher) {utf16char_len("en", b)}
#[bench] fn utf16char_len_ru(b: &mut Bencher) {utf16char_len("ru", b)}
#[bench] fn utf16char_len_zh(b: &mut Bencher) {utf16char_len("zh", b)}

fn utf16_is_leading_surrogate(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_UNITS[language];
    let chars = string.chars().count();
    let string: Vec<u16> = string.chars().map(|c| c.to_utf16() ).collect();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        while i < string.len() {
            i += if string[i].is_utf16_leading_surrogate() {2} else {1};
            loops += 1;
        }
        assert_eq!(loops, chars);
    });
}
#[bench] fn utf16_is_leading_surrogate_ascii(b: &mut Bencher) {utf16_is_leading_surrogate("ascii", b)}
#[bench] fn utf16_is_leading_surrogate_en(b: &mut Bencher) {utf16_is_leading_surrogate("en", b)}
#[bench] fn utf16_is_leading_surrogate_es(b: &mut Bencher) {utf16_is_leading_surrogate("es", b)}
#[bench] fn utf16_is_leading_surrogate_ru(b: &mut Bencher) {utf16_is_leading_surrogate("ru", b)}
#[bench] fn utf16_is_leading_surrogate_zh(b: &mut Bencher) {utf16_is_leading_surrogate("zh", b)}

fn utf16_needs_extra_unit(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_UNITS[language];
    let chars = string.chars().count();
    let string: Vec<u16> = string.chars().map(|c| c.to_utf16() ).collect();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        let mut errors = 0;
        while i < string.len() {
            i += match string[i].utf16_needs_extra_unit() {
                Ok(true) => 2,
                Ok(false) => 1,
                Err(_) => {errors+=1; 1}
            };
            loops += 1;
        }
        assert_eq!(loops, chars);
        assert_eq!(errors, 0);
    });
}
#[bench] fn utf16_needs_extra_unit_ascii(b: &mut Bencher) {utf16_needs_extra_unit("ascii", b)}
#[bench] fn utf16_needs_extra_unit_en(b: &mut Bencher) {utf16_needs_extra_unit("en", b)}
#[bench] fn utf16_needs_extra_unit_es(b: &mut Bencher) {utf16_needs_extra_unit("es", b)}
#[bench] fn utf16_needs_extra_unit_ru(b: &mut Bencher) {utf16_needs_extra_unit("ru", b)}
#[bench] fn utf16_needs_extra_unit_zh(b: &mut Bencher) {utf16_needs_extra_unit("zh", b)}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate extra;

use std::fs;
use std::io;
use extra::io::WriteExt;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{shutdown} */ r#"
NAME
    shutdown - stop the system

SYNOPSIS
    shutdown

DESCRIPTION
    Attempt to shutdown the system using ACPI. Failure will be logged to the terminal
"#; /* @MANEND */

fn main() {
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    fs::File::create("acpi:off").try(&mut stderr);
}
<commit_msg>Fix shutdown compile<commit_after>#![deny(warnings)]

extern crate extra;

use std::fs;
use std::io;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{shutdown} */ r#"
NAME
    shutdown - stop the system

SYNOPSIS
    shutdown

DESCRIPTION
    Attempt to shutdown the system using ACPI. Failure will be logged to the terminal
"#; /* @MANEND */

fn main() {
    let mut stderr = io::stderr();
    fs::File::create("acpi:off").try(&mut stderr);
}
<|endoftext|>