<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![cfg_attr(target_os = "nacl", allow(dead_code))]

use env;
use io::prelude::*;
use io;
use libc;
use str;
use sync::atomic::{self, Ordering};

pub use sys::backtrace::write;

#[cfg(target_pointer_width = "64")]
pub const HEX_WIDTH: usize = 18;

#[cfg(target_pointer_width = "32")]
pub const HEX_WIDTH: usize = 10;

// For now logging is turned off by default, and this function checks to see
// whether the magical environment variable is present to see if it's turned on.
pub fn log_enabled() -> bool {
    static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
    match ENABLED.load(Ordering::SeqCst) {
        1 => return false,
        2 => return true,
        _ => {}
    }

    let val = match env::var_os("RUST_BACKTRACE") {
        Some(x) => if &x == "0" { 1 } else { 2 },
        None => 1,
    };
    ENABLED.store(val, Ordering::SeqCst);
    val == 2
}

// These output functions should now be used everywhere to ensure consistency.
pub fn output(w: &mut Write, idx: isize, addr: *mut libc::c_void,
              s: Option<&[u8]>) -> io::Result<()> {
    write!(w, "  {:2}: {:2$?} - ", idx, addr, HEX_WIDTH)?;
    match s.and_then(|s| str::from_utf8(s).ok()) {
        Some(string) => demangle(w, string)?,
        None => write!(w, "<unknown>")?,
    }
    w.write_all(&['\n' as u8])
}

#[allow(dead_code)]
pub fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int,
                       more: bool) -> io::Result<()> {
    let file = str::from_utf8(file).unwrap_or("<unknown>");
    // prior line: "  ##: {:2$} - func"
    write!(w, "      {:3$}at {}:{}", "", file, line, HEX_WIDTH)?;
    if more {
        write!(w, " <... and possibly more>")?;
    }
    w.write_all(&['\n' as u8])
}

// All rust symbols are in theory lists of "::"-separated identifiers. Some
// assemblers, however, can't handle these characters in symbol names. To get
// around this, we use C++-style mangling. The mangling method is:
//
// 1. Prefix the symbol with "_ZN"
// 2. For each element of the path, emit the length plus the element
// 3. End the path with "E"
//
// For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar".
//
// We're the ones printing our backtraces, so we can't rely on anything else to
// demangle our symbols. It's *much* nicer to look at demangled symbols, so
// this function is implemented to give us nice pretty output.
//
// Note that this demangler isn't quite as fancy as it could be. We have lots
// of other information in our symbols like hashes, version, type information,
// etc. Additionally, this doesn't handle glue symbols at all.
pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> {
    // First validate the symbol. If it doesn't look like anything we're
    // expecting, we just print it literally. Note that we must handle non-rust
    // symbols because we could have any function in the backtrace.
    let mut valid = true;
    let mut inner = s;
    if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") {
        inner = &s[3 .. s.len() - 1];
    // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" form too.
    } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with("E") {
        inner = &s[2 .. s.len() - 1];
    } else {
        valid = false;
    }

    if valid {
        let mut chars = inner.chars();
        while valid {
            let mut i = 0;
            for c in chars.by_ref() {
                if c.is_numeric() {
                    i = i * 10 + c as usize - '0' as usize;
                } else {
                    break
                }
            }
            if i == 0 {
                valid = chars.next().is_none();
                break
            } else if chars.by_ref().take(i - 1).count() != i - 1 {
                valid = false;
            }
        }
    }

    // Alright, let's do this.
    if !valid {
        writer.write_all(s.as_bytes())?;
    } else {
        let mut first = true;
        while !inner.is_empty() {
            if !first {
                writer.write_all(b"::")?;
            } else {
                first = false;
            }
            let mut rest = inner;
            while rest.chars().next().unwrap().is_numeric() {
                rest = &rest[1..];
            }
            let i: usize = inner[.. (inner.len() - rest.len())].parse().unwrap();
            inner = &rest[i..];
            rest = &rest[..i];
            while !rest.is_empty() {
                if rest.starts_with("$") {
                    macro_rules! demangle {
                        ($($pat:expr, => $demangled:expr),*) => ({
                            $(if rest.starts_with($pat) {
                                try!(writer.write_all($demangled));
                                rest = &rest[$pat.len()..];
                              } else)*
                            {
                                try!(writer.write_all(rest.as_bytes()));
                                break;
                            }

                        })
                    }

                    // see src/librustc/back/link.rs for these mappings
                    demangle! (
                        "$SP$", => b"@",
                        "$BP$", => b"*",
                        "$RF$", => b"&",
                        "$LT$", => b"<",
                        "$GT$", => b">",
                        "$LP$", => b"(",
                        "$RP$", => b")",
                        "$C$", => b",",

                        // in theory we can demangle any Unicode code point, but
                        // for simplicity we just catch the common ones.
                        "$u7e$", => b"~",
                        "$u20$", => b" ",
                        "$u27$", => b"'",
                        "$u5b$", => b"[",
                        "$u5d$", => b"]"
                    )
                } else {
                    let idx = match rest.find('$') {
                        None => rest.len(),
                        Some(i) => i,
                    };
                    writer.write_all(rest[..idx].as_bytes())?;
                    rest = &rest[idx..];
                }
            }
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use prelude::v1::*;
    use sys_common;
    macro_rules! t { ($a:expr, $b:expr) => ({
        let mut m = Vec::new();
        sys_common::backtrace::demangle(&mut m, $a).unwrap();
        assert_eq!(String::from_utf8(m).unwrap(), $b);
    }) }

    #[test]
    fn demangle() {
        t!("test", "test");
        t!("_ZN4testE", "test");
        t!("_ZN4test", "_ZN4test");
        t!("_ZN4test1a2bcE", "test::a::bc");
    }

    #[test]
    fn demangle_dollars() {
        t!("_ZN4$RP$E", ")");
        t!("_ZN8$RF$testE", "&test");
        t!("_ZN8$BP$test4foobE", "*test::foob");
        t!("_ZN9$u20$test4foobE", " test::foob");
    }

    #[test]
    fn demangle_many_dollars() {
        t!("_ZN13test$u20$test4foobE", "test test::foob");
        t!("_ZN12test$BP$test4foobE", "test*test::foob");
    }

    #[test]
    fn demangle_windows() {
        t!("ZN4testE", "test");
        t!("ZN13test$u20$test4foobE", "test test::foob");
        t!("ZN12test$RF$test4foobE", "test&test::foob");
    }
}
<commit_msg>Demangle curly braces<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![cfg_attr(target_os = "nacl", allow(dead_code))]

use env;
use io::prelude::*;
use io;
use libc;
use str;
use sync::atomic::{self, Ordering};

pub use sys::backtrace::write;

#[cfg(target_pointer_width = "64")]
pub const HEX_WIDTH: usize = 18;

#[cfg(target_pointer_width = "32")]
pub const HEX_WIDTH: usize = 10;

// For now logging is turned off by default, and this function checks to see
// whether the magical environment variable is present to see if it's turned on.
pub fn log_enabled() -> bool {
    static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
    match ENABLED.load(Ordering::SeqCst) {
        1 => return false,
        2 => return true,
        _ => {}
    }

    let val = match env::var_os("RUST_BACKTRACE") {
        Some(x) => if &x == "0" { 1 } else { 2 },
        None => 1,
    };
    ENABLED.store(val, Ordering::SeqCst);
    val == 2
}

// These output functions should now be used everywhere to ensure consistency.
pub fn output(w: &mut Write, idx: isize, addr: *mut libc::c_void,
              s: Option<&[u8]>) -> io::Result<()> {
    write!(w, "  {:2}: {:2$?} - ", idx, addr, HEX_WIDTH)?;
    match s.and_then(|s| str::from_utf8(s).ok()) {
        Some(string) => demangle(w, string)?,
        None => write!(w, "<unknown>")?,
    }
    w.write_all(&['\n' as u8])
}

#[allow(dead_code)]
pub fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int,
                       more: bool) -> io::Result<()> {
    let file = str::from_utf8(file).unwrap_or("<unknown>");
    // prior line: "  ##: {:2$} - func"
    write!(w, "      {:3$}at {}:{}", "", file, line, HEX_WIDTH)?;
    if more {
        write!(w, " <... and possibly more>")?;
    }
    w.write_all(&['\n' as u8])
}

// All rust symbols are in theory lists of "::"-separated identifiers. Some
// assemblers, however, can't handle these characters in symbol names. To get
// around this, we use C++-style mangling. The mangling method is:
//
// 1. Prefix the symbol with "_ZN"
// 2. For each element of the path, emit the length plus the element
// 3. End the path with "E"
//
// For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar".
//
// We're the ones printing our backtraces, so we can't rely on anything else to
// demangle our symbols. It's *much* nicer to look at demangled symbols, so
// this function is implemented to give us nice pretty output.
//
// Note that this demangler isn't quite as fancy as it could be. We have lots
// of other information in our symbols like hashes, version, type information,
// etc. Additionally, this doesn't handle glue symbols at all.
pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> {
    // First validate the symbol. If it doesn't look like anything we're
    // expecting, we just print it literally. Note that we must handle non-rust
    // symbols because we could have any function in the backtrace.
    let mut valid = true;
    let mut inner = s;
    if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") {
        inner = &s[3 .. s.len() - 1];
    // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" form too.
    } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with("E") {
        inner = &s[2 .. s.len() - 1];
    } else {
        valid = false;
    }

    if valid {
        let mut chars = inner.chars();
        while valid {
            let mut i = 0;
            for c in chars.by_ref() {
                if c.is_numeric() {
                    i = i * 10 + c as usize - '0' as usize;
                } else {
                    break
                }
            }
            if i == 0 {
                valid = chars.next().is_none();
                break
            } else if chars.by_ref().take(i - 1).count() != i - 1 {
                valid = false;
            }
        }
    }

    // Alright, let's do this.
    if !valid {
        writer.write_all(s.as_bytes())?;
    } else {
        let mut first = true;
        while !inner.is_empty() {
            if !first {
                writer.write_all(b"::")?;
            } else {
                first = false;
            }
            let mut rest = inner;
            while rest.chars().next().unwrap().is_numeric() {
                rest = &rest[1..];
            }
            let i: usize = inner[.. (inner.len() - rest.len())].parse().unwrap();
            inner = &rest[i..];
            rest = &rest[..i];
            while !rest.is_empty() {
                if rest.starts_with("$") {
                    macro_rules! demangle {
                        ($($pat:expr, => $demangled:expr),*) => ({
                            $(if rest.starts_with($pat) {
                                try!(writer.write_all($demangled));
                                rest = &rest[$pat.len()..];
                              } else)*
                            {
                                try!(writer.write_all(rest.as_bytes()));
                                break;
                            }

                        })
                    }

                    // see src/librustc/back/link.rs for these mappings
                    demangle! (
                        "$SP$", => b"@",
                        "$BP$", => b"*",
                        "$RF$", => b"&",
                        "$LT$", => b"<",
                        "$GT$", => b">",
                        "$LP$", => b"(",
                        "$RP$", => b")",
                        "$C$", => b",",

                        // in theory we can demangle any Unicode code point, but
                        // for simplicity we just catch the common ones.
                        "$u7e$", => b"~",
                        "$u20$", => b" ",
                        "$u27$", => b"'",
                        "$u5b$", => b"[",
                        "$u5d$", => b"]",
                        "$u7b$", => b"{",
                        "$u7d$", => b"}"
                    )
                } else {
                    let idx = match rest.find('$') {
                        None => rest.len(),
                        Some(i) => i,
                    };
                    writer.write_all(rest[..idx].as_bytes())?;
                    rest = &rest[idx..];
                }
            }
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use prelude::v1::*;
    use sys_common;
    macro_rules! t { ($a:expr, $b:expr) => ({
        let mut m = Vec::new();
        sys_common::backtrace::demangle(&mut m, $a).unwrap();
        assert_eq!(String::from_utf8(m).unwrap(), $b);
    }) }

    #[test]
    fn demangle() {
        t!("test", "test");
        t!("_ZN4testE", "test");
        t!("_ZN4test", "_ZN4test");
        t!("_ZN4test1a2bcE", "test::a::bc");
    }

    #[test]
    fn demangle_dollars() {
        t!("_ZN4$RP$E", ")");
        t!("_ZN8$RF$testE", "&test");
        t!("_ZN8$BP$test4foobE", "*test::foob");
        t!("_ZN9$u20$test4foobE", " test::foob");
    }

    #[test]
    fn demangle_many_dollars() {
        t!("_ZN13test$u20$test4foobE", "test test::foob");
        t!("_ZN12test$BP$test4foobE", "test*test::foob");
    }

    #[test]
    fn demangle_windows() {
        t!("ZN4testE", "test");
        t!("ZN13test$u20$test4foobE", "test test::foob");
        t!("ZN12test$RF$test4foobE", "test&test::foob");
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_use]
extern crate log;
extern crate chrono;
extern crate fern;

extern crate dirs;

extern crate xi_core_lib;
extern crate xi_rpc;

use std::collections::HashMap;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

use xi_core_lib::XiCore;
use xi_rpc::RpcLoop;

const XI_LOG_DIR: &str = "xi-core";
const XI_LOG_FILE: &str = "xi-core.log";

fn get_logging_directory_path<P: AsRef<Path>>(directory: P) -> Result<PathBuf, io::Error> {
    match dirs::data_local_dir() {
        Some(mut log_dir) => {
            log_dir.push(directory);
            Ok(log_dir)
        }
        None => Err(io::Error::new(
            io::ErrorKind::NotFound,
            "No standard logging directory known for this platform",
        )),
    }
}

/// This function tries to create the parent directories for a file
///
/// It wraps around the `parent()` function of `Path` which returns an `Option<&Path>` and
/// `fs::create_dir_all` which returns an `io::Result<()`.
///
/// This allows you to use `?`/`try!()` to create the dir and you recive the additional custom error for when `parent()`
/// returns nothing.
///
/// # Errors
/// This can return an `io::Error` if `fs::create_dir_all` fails or if `parent()` returns `None`.
/// See `Path`'s `parent()` function for more details.
/// # Examples
/// ```
/// use std::path::PathBuf;
/// let path_with_file = PathBuf::from("/some/directory/then/file");
/// assert_eq!(Some(OsStr::new("file")), path_with_file.file_name());
/// assert_eq!(create_parent_directory(path_with_file).is_ok(), true);
///
/// let path_with_other_file = PathBuf::from("/other_file");
/// assert_eq!(Some(OsStr::new("other_file")), path_with_other_file.file_name());
/// assert_eq!(create_parent_directory(path_with_file).is_ok(), true);
///
/// // Path that is just the root or prefix:
/// let path_without_file = PathBuf::from("/");
/// assert_eq!(None, path_with_file.file_name());
/// assert_eq!(create_parent_directory(path_with_file).is_ok(), false);
/// ```
pub fn create_parent_directory(path_with_file: &PathBuf) -> Result<(), io::Error> {
    let parent_path = path_with_file.parent().ok_or(io::Error::new(
        io::ErrorKind::InvalidInput,
        format!(
            "Unable to get the parent of the following Path: {}",
            path_with_file.display(),
        ),
    ))?;
    // Try to create the directory.
    fs::create_dir_all(parent_path)?;
    Ok(())
}

fn setup_logging(logging_path_result: Option<PathBuf>) -> Result<(), fern::InitError> {
    let level_filter = match std::env::var("XI_LOG") {
        Ok(level) => match level.to_lowercase().as_ref() {
            "trace" => log::LevelFilter::Trace,
            "debug" => log::LevelFilter::Debug,
            _ => log::LevelFilter::Info,
        },
        // Default to info
        Err(_) => log::LevelFilter::Info,
    };

    let mut fern_dispatch = fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!(
                "{}[{}][{}] {}",
                chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
                record.target(),
                record.level(),
                message,
            ))
        }).level(level_filter)
        .chain(io::stderr());

    if let Some(logging_file_path) = &logging_path_result {
        // Try to create the parent directories for the logging file in the logging file path
        create_parent_directory(&logging_file_path)?;

        // Attach it to fern
        fern_dispatch = fern_dispatch.chain(fern::log_file(logging_file_path)?);
    };

    // Start fern
    fern_dispatch.apply()?;
    info!("Logging with fern is setup");

    // Log details of the logging_file_path result using fern/log
    // Either logging the path fern is outputting to or the error from obtaining the path
    match &logging_path_result {
        Some(logging_file_path) => info!(
            "Logging to the following file: {}",
            logging_file_path.display()
        ),
        None => warn!("There was no path supplied for the log file, falling back to stderr."),
    }
    Ok(())
}

fn generate_logging_path(logfile_config: LogfileConfig) -> Result<PathBuf, io::Error> {
    // Use the file name set in logfile_config or fallback to the default
    let logfile_file_name = match logfile_config.file {
        Some(file_name) => file_name,
        None => PathBuf::from(XI_LOG_FILE),
    };
    if logfile_file_name.eq(Path::new("")) {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "A blank file name was supplied",
        ));
    };
    // Use the directory name set in logfile_config or fallback to the default
    let logfile_directory_name = match logfile_config.directory {
        Some(dir) => dir,
        None => PathBuf::from(XI_LOG_DIR),
    };

    let mut logging_directory_path = get_logging_directory_path(logfile_directory_name)?;

    // Add the file name & return the full path
    logging_directory_path.push(logfile_file_name);
    Ok(logging_directory_path)
}

fn get_flags() -> HashMap<String, Option<String>> {
    let mut flags: HashMap<String, Option<String>> = HashMap::new();

    let flag_prefix = "-";
    let mut args_iterator = std::env::args().peekable();
    while let Some(arg) = args_iterator.next() {
        if arg.starts_with(flag_prefix) {
            let key = arg.trim_left_matches(flag_prefix).to_string();

            // Check the next argument doesn't start with the flag prefix
            // map_or accounts for peek returning an Option
            let next_arg_not_a_flag: bool = args_iterator
                .peek()
                .map_or(false, |val| !val.starts_with(flag_prefix));
            if next_arg_not_a_flag {
                flags.insert(key, args_iterator.next());
            }
        }
    }
    flags
}

struct EnvFlagConfig {
    env_name: &'static str,
    flag_name: &'static str,
}

/// Extracts a value from the flags and the env.
///
/// In this order: `String` from the flags, then `String` from the env, then `None`
fn extract_env_or_flag(
    flags: &HashMap<String, Option<String>>,
    conf: EnvFlagConfig,
) -> Option<String> {
    flags
        .get(conf.flag_name)
        .cloned()
        .unwrap_or(std::env::var(conf.env_name).ok())
}

struct LogfileConfig {
    directory: Option<PathBuf>,
    file: Option<PathBuf>,
}

fn generate_logfile_config(flags: &HashMap<String, Option<String>>) -> LogfileConfig {
    // If the key is set, get the Option within
    let log_dir_env_flag = EnvFlagConfig {
        env_name: "XI_LOG_DIR",
        flag_name: "log-dir",
    };
    let log_file_env_flag = EnvFlagConfig {
        env_name: "XI_LOG_FILE",
        flag_name: "log-file",
    };
    let log_dir_flag_option = extract_env_or_flag(&flags, log_dir_env_flag).map(PathBuf::from);

    let log_file_flag_option = extract_env_or_flag(&flags, log_file_env_flag).map(PathBuf::from);

    LogfileConfig {
        directory: log_dir_flag_option,
        file: log_file_flag_option,
    }
}

fn main() {
    let mut state = XiCore::new();
    let stdin = io::stdin();
    let stdout = io::stdout();
    let mut rpc_looper = RpcLoop::new(stdout);

    let flags: HashMap<String, Option<String>> = get_flags();

    let logfile_config = generate_logfile_config(&flags);

    let logging_path_result: Result<PathBuf, io::Error> = generate_logging_path(logfile_config);

    let mut logging_path: Option<PathBuf> = None;
    let mut logging_error: Option<io::Error> = None;
    match logging_path_result {
        Ok(val) => logging_path = Some(val),
        Err(e) => logging_error = Some(e),
    };
    if let Err(e) = setup_logging(logging_path) {
        eprintln!(
            "[ERROR] setup_logging returned error, logging not enabled: {:?}",
            e
        );
    }
    if let Some(e) = logging_error {
        warn!("Unable to successfully generate the logging path: {}", e)
    }

    match rpc_looper.mainloop(|| stdin.lock(), &mut state) {
        Ok(_) => (),
        Err(err) => error!("xi-core exited with error:\n{:?}", err),
    }
}
<commit_msg>Renamed and removed pub.<commit_after>// Copyright 2016 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_use]
extern crate log;
extern crate chrono;
extern crate fern;

extern crate dirs;

extern crate xi_core_lib;
extern crate xi_rpc;

use std::collections::HashMap;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

use xi_core_lib::XiCore;
use xi_rpc::RpcLoop;

const XI_LOG_DIR: &str = "xi-core";
const XI_LOG_FILE: &str = "xi-core.log";

fn get_logging_directory_path<P: AsRef<Path>>(directory: P) -> Result<PathBuf, io::Error> {
    match dirs::data_local_dir() {
        Some(mut log_dir) => {
            log_dir.push(directory);
            Ok(log_dir)
        }
        None => Err(io::Error::new(
            io::ErrorKind::NotFound,
            "No standard logging directory known for this platform",
        )),
    }
}

/// This function tries to create the parent directories for a file
///
/// It wraps around the `parent()` function of `Path` which returns an `Option<&Path>` and
/// `fs::create_dir_all` which returns an `io::Result<()`.
///
/// This allows you to use `?`/`try!()` to create the dir and you recive the additional custom error for when `parent()`
/// returns nothing.
///
/// # Errors
/// This can return an `io::Error` if `fs::create_dir_all` fails or if `parent()` returns `None`.
/// See `Path`'s `parent()` function for more details.
/// # Examples
/// ```
/// use std::path::PathBuf;
/// let path_with_file = PathBuf::from("/some/directory/then/file");
/// assert_eq!(Some(OsStr::new("file")), path_with_file.file_name());
/// assert_eq!(create_log_directory(path_with_file).is_ok(), true);
///
/// let path_with_other_file = PathBuf::from("/other_file");
/// assert_eq!(Some(OsStr::new("other_file")), path_with_other_file.file_name());
/// assert_eq!(create_log_directory(path_with_file).is_ok(), true);
///
/// // Path that is just the root or prefix:
/// let path_without_file = PathBuf::from("/");
/// assert_eq!(None, path_with_file.file_name());
/// assert_eq!(create_log_directory(path_with_file).is_ok(), false);
/// ```
fn create_log_directory(path_with_file: &PathBuf) -> Result<(), io::Error> {
    let log_dir = path_with_file.parent().ok_or(io::Error::new(
        io::ErrorKind::InvalidInput,
        format!(
            "Unable to get the parent of the following Path: {}",
            path_with_file.display(),
        ),
    ))?;
    // Try to create the directory.
    fs::create_dir_all(log_dir)?;
    Ok(())
}

fn setup_logging(logging_path_result: Option<PathBuf>) -> Result<(), fern::InitError> {
    let level_filter = match std::env::var("XI_LOG") {
        Ok(level) => match level.to_lowercase().as_ref() {
            "trace" => log::LevelFilter::Trace,
            "debug" => log::LevelFilter::Debug,
            _ => log::LevelFilter::Info,
        },
        // Default to info
        Err(_) => log::LevelFilter::Info,
    };

    let mut fern_dispatch = fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!(
                "{}[{}][{}] {}",
                chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
                record.target(),
                record.level(),
                message,
            ))
        }).level(level_filter)
        .chain(io::stderr());

    if let Some(logging_file_path) = &logging_path_result {
        // Try to create the parent directories for the logging file in the logging file path
        create_log_directory(&logging_file_path)?;

        // Attach it to fern
        fern_dispatch = fern_dispatch.chain(fern::log_file(logging_file_path)?);
    };

    // Start fern
    fern_dispatch.apply()?;
    info!("Logging with fern is setup");

    // Log details of the logging_file_path result using fern/log
    // Either logging the path fern is outputting to or the error from obtaining the path
    match &logging_path_result {
        Some(logging_file_path) => info!(
            "Logging to the following file: {}",
            logging_file_path.display()
        ),
        None => warn!("There was no path supplied for the log file, falling back to stderr."),
    }
    Ok(())
}

fn generate_logging_path(logfile_config: LogfileConfig) -> Result<PathBuf, io::Error> {
    // Use the file name set in logfile_config or fallback to the default
    let logfile_file_name = match logfile_config.file {
        Some(file_name) => file_name,
        None => PathBuf::from(XI_LOG_FILE),
    };
    if logfile_file_name.eq(Path::new("")) {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "A blank file name was supplied",
        ));
    };
    // Use the directory name set in logfile_config or fallback to the default
    let logfile_directory_name = match logfile_config.directory {
        Some(dir) => dir,
        None => PathBuf::from(XI_LOG_DIR),
    };

    let mut logging_directory_path = get_logging_directory_path(logfile_directory_name)?;

    // Add the file name & return the full path
    logging_directory_path.push(logfile_file_name);
    Ok(logging_directory_path)
}

fn get_flags() -> HashMap<String, Option<String>> {
    let mut flags: HashMap<String, Option<String>> = HashMap::new();

    let flag_prefix = "-";
    let mut args_iterator = std::env::args().peekable();
    while let Some(arg) = args_iterator.next() {
        if arg.starts_with(flag_prefix) {
            let key = arg.trim_left_matches(flag_prefix).to_string();

            // Check the next argument doesn't start with the flag prefix
            // map_or accounts for peek returning an Option
            let next_arg_not_a_flag: bool = args_iterator
                .peek()
                .map_or(false, |val| !val.starts_with(flag_prefix));
            if next_arg_not_a_flag {
                flags.insert(key, args_iterator.next());
            }
        }
    }
    flags
}

struct EnvFlagConfig {
    env_name: &'static str,
    flag_name: &'static str,
}

/// Extracts a value from the flags and the env.
///
/// In this order: `String` from the flags, then `String` from the env, then `None`
fn extract_env_or_flag(
    flags: &HashMap<String, Option<String>>,
    conf: EnvFlagConfig,
) -> Option<String> {
    flags
        .get(conf.flag_name)
        .cloned()
        .unwrap_or(std::env::var(conf.env_name).ok())
}

struct LogfileConfig {
    directory: Option<PathBuf>,
    file: Option<PathBuf>,
}

fn generate_logfile_config(flags: &HashMap<String, Option<String>>) -> LogfileConfig {
    // If the key is set, get the Option within
    let log_dir_env_flag = EnvFlagConfig {
        env_name: "XI_LOG_DIR",
        flag_name: "log-dir",
    };
    let log_file_env_flag = EnvFlagConfig {
        env_name: "XI_LOG_FILE",
        flag_name: "log-file",
    };
    let log_dir_flag_option = extract_env_or_flag(&flags, log_dir_env_flag).map(PathBuf::from);

    let log_file_flag_option = extract_env_or_flag(&flags, log_file_env_flag).map(PathBuf::from);

    LogfileConfig {
        directory: log_dir_flag_option,
        file: log_file_flag_option,
    }
}

fn main() {
    let mut state = XiCore::new();
    let stdin = io::stdin();
    let stdout = io::stdout();
    let mut rpc_looper = RpcLoop::new(stdout);

    let flags: HashMap<String, Option<String>> = get_flags();

    let logfile_config = generate_logfile_config(&flags);

    let logging_path_result: Result<PathBuf, io::Error> = generate_logging_path(logfile_config);

    let mut logging_path: Option<PathBuf> = None;
    let mut logging_error: Option<io::Error> = None;
    match logging_path_result {
        Ok(val) => logging_path = Some(val),
        Err(e) => logging_error = Some(e),
    };
    if let Err(e) = setup_logging(logging_path) {
        eprintln!(
            "[ERROR] setup_logging returned error, logging not enabled: {:?}",
            e
        );
    }
    if let Some(e) = logging_error {
        warn!("Unable to successfully generate the logging path: {}", e)
    }

    match rpc_looper.mainloop(|| stdin.lock(), &mut state) {
        Ok(_) => (),
        Err(err) => error!("xi-core exited with error:\n{:?}", err),
    }
}
<|endoftext|>


<commit_before>pub mod char_data;
pub mod scanner;
pub mod token;

use public::*;
use parser::scanner::Scanner;
use std::mem;

/// Shared parsing state
#[derive(Debug)]
struct Parser<'s, 'c: 's> {
    pub scanner: Scanner<'s, 'c>,
    pub need_next: NeedNext,
    pub tokens: Vec<Token>,
    pub token_starts: Vec<ByteIndex>,
}

#[derive(Debug, PartialEq)]
enum NeedNext {
    InitialTerm,
    Operator,
    Operand,
    Either((ByteIndex, String)),
}

pub fn parse<'s>(compiler: &'s Compiler, source: SourceIndex) {
    let (char_data, tokens, token_starts) = compiler.with_source(source, |s| {
        s.source_spec().with_buffer(compiler, source, |raw_buffer| {
            let scanner = Scanner::new(compiler, source, raw_buffer);
            let parser = Parser::new(scanner, NeedNext::InitialTerm);
            parser.parse()
        })
    });
    compiler.with_source_mut(source, |s| {
        s.parse_complete(char_data, tokens, token_starts);
    });
}

impl<'s, 'c: 's> Parser<'s, 'c> {
    pub fn new(scanner: Scanner<'s, 'c>, need_next: NeedNext) -> Self {
        let tokens = vec![];
        let token_starts = vec![];
        Parser { scanner, need_next, tokens, token_starts }
    }

    pub fn parse(mut self) -> (CharData, Vec<Token>, Vec<ByteIndex>) {
        while self.step() {}
        self.close();
        (self.scanner.char_data, self.tokens, self.token_starts)
    }

    fn step(&mut self) -> bool {
        if self.scanner.eof() {
            return false;
        }

        if self.scan_token() {
            true
        } else if self.report_unsupported_characters() {
            true
        } else {
            self.report_invalid_utf8();
            true
        }
    }

    fn scan_token(&mut self) -> bool {
        if let Some(end) = self.scanner.match_all(digit) { self.term(IntegerLiteral, end) }
        else if let Some(end) = self.scanner.match_all(operator) { self.operator(end) }
        else { return false }
        true
    }

    fn term(&mut self, term_type: TermType, end: ByteIndex) {
        let string = self.scanner.take_string(end);
        self.transition(|p, need_next| {
            match need_next {
                NeedNext::InitialTerm|NeedNext::Operand => p.push_token(term_type, string),
                NeedNext::Operator => unreachable!(),
                NeedNext::Either(prev_operator) => {
                    p.push_token(Infix, prev_operator);
                    p.push_token(term_type, string);
                }
            }
            NeedNext::Operator
        })
    }

    fn operator(&mut self, end: ByteIndex) {
        let string = self.scanner.take_string(end);
        self.transition(|p, need_next| {
            match need_next {
                NeedNext::InitialTerm|NeedNext::Operand => {
                    p.push_token(Prefix, string);
                    NeedNext::Operand
                },
                NeedNext::Operator => NeedNext::Either(string),
                NeedNext::Either(_) => unreachable!(),
            }
        })
    }

    fn close(&mut self) {
        self.transition(|p, need_next| {
            match need_next {
                // NOTE: we do not report MissingRightOperand here because it will be reported by the typechecker.
                NeedNext::InitialTerm|NeedNext::Operator|NeedNext::Operand => {},
                NeedNext::Either(prev_string) => p.push_token(Postfix, prev_string),
            }
            NeedNext::Operator
        })
    }

    fn transition<F: FnOnce(&mut Self, NeedNext) -> NeedNext>(&mut self, transition: F) {
        let need_next = mem::replace(&mut self.need_next, NeedNext::InitialTerm);
        self.need_next = transition(self, need_next);
    }

    fn push_token<T: Into<TokenType>>(&mut self, token_type: T, (start, string): (ByteIndex, String)) {
        self.tokens.push(Token::new(token_type.into(), string));
        self.token_starts.push(start);
    }

    fn report_unsupported_characters(&mut self) -> bool {
        let start = self.scanner.index;
        let mut string = String::new();
        if !self.scanner.take_valid_char(&mut string) {
            return false;
        }

        // If there are valid UTF-8 chars, they are just unsupported. Report
        while !self.scanner.eof() && !self.scan_token() && self.scanner.take_valid_char(&mut string) {}
        self.scanner.compiler.report_at(UnsupportedCharacters, self.scanner.source, start, &string);
        true
    }

    fn report_invalid_utf8(&mut self) {
        // Invalid UTF-8. Read invalid characters until you find something valid.
        let start = self.scanner.index;
        let mut bytes: Vec<u8> = vec![];
        while !self.scanner.eof() && !self.scanner.is_valid_char() {
            self.scanner.take_byte(&mut bytes);
        }
        self.scanner.compiler.report_invalid_bytes(InvalidUtf8, self.scanner.source, start, &bytes)
    }
}

fn digit(byte: u8) -> bool { (b'0'..=b'9').contains(byte) }
fn operator(byte: u8) -> bool { match byte { b'+'|b'-'|b'*'|b'/' => true, _ => false } }
<commit_msg>Make parser lifetime 'p instead of 's<commit_after>pub mod char_data;
pub mod scanner;
pub mod token;

use public::*;
use parser::scanner::Scanner;
use std::mem;

/// Shared parsing state
#[derive(Debug)]
struct Parser<'p, 'c: 'p> {
    pub scanner: Scanner<'p, 'c>,
    pub need_next: NeedNext,
    pub tokens: Vec<Token>,
    pub token_starts: Vec<ByteIndex>,
}

#[derive(Debug, PartialEq)]
enum NeedNext {
    InitialTerm,
    Operator,
    Operand,
    Either((ByteIndex, String)),
}

pub fn parse<'p>(compiler: &'p Compiler, source: SourceIndex) {
    let (char_data, tokens, token_starts) = compiler.with_source(source, |s| {
        s.source_spec().with_buffer(compiler, source, |raw_buffer| {
            let scanner = Scanner::new(compiler, source, raw_buffer);
            let parser = Parser::new(scanner, NeedNext::InitialTerm);
            parser.parse()
        })
    });
    compiler.with_source_mut(source, |s| {
        s.parse_complete(char_data, tokens, token_starts);
    });
}

impl<'p, 'c: 'p> Parser<'p, 'c> {
    pub fn new(scanner: Scanner<'p, 'c>, need_next: NeedNext) -> Self {
        let tokens = vec![];
        let token_starts = vec![];
        Parser { scanner, need_next, tokens, token_starts }
    }

    pub fn parse(mut self) -> (CharData, Vec<Token>, Vec<ByteIndex>) {
        while self.step() {}
        self.close();
        (self.scanner.char_data, self.tokens, self.token_starts)
    }

    fn step(&mut self) -> bool {
        if self.scanner.eof() {
            return false;
        }

        if self.scan_token() {
            true
        } else if self.report_unsupported_characters() {
            true
        } else {
            self.report_invalid_utf8();
            true
        }
    }

    fn scan_token(&mut self) -> bool {
        if let Some(end) = self.scanner.match_all(digit) { self.term(IntegerLiteral, end) }
        else if let Some(end) = self.scanner.match_all(operator) { self.operator(end) }
        else { return false }
        true
    }

    fn term(&mut self, term_type: TermType, end: ByteIndex) {
        let string = self.scanner.take_string(end);
        self.transition(|p, need_next| {
            match need_next {
                NeedNext::InitialTerm|NeedNext::Operand => p.push_token(term_type, string),
                NeedNext::Operator => unreachable!(),
                NeedNext::Either(prev_operator) => {
                    p.push_token(Infix, prev_operator);
                    p.push_token(term_type, string);
                }
            }
            NeedNext::Operator
        })
    }

    fn operator(&mut self, end: ByteIndex) {
        let string = self.scanner.take_string(end);
        self.transition(|p, need_next| {
            match need_next {
                NeedNext::InitialTerm|NeedNext::Operand => {
                    p.push_token(Prefix, string);
                    NeedNext::Operand
                },
                NeedNext::Operator => NeedNext::Either(string),
                NeedNext::Either(_) => unreachable!(),
            }
        })
    }

    fn close(&mut self) {
        self.transition(|p, need_next| {
            match need_next {
                // NOTE: we do not report MissingRightOperand here because it will be reported by the typechecker.
                NeedNext::InitialTerm|NeedNext::Operator|NeedNext::Operand => {},
                NeedNext::Either(prev_string) => p.push_token(Postfix, prev_string),
            }
            NeedNext::Operator
        })
    }

    fn transition<F: FnOnce(&mut Self, NeedNext) -> NeedNext>(&mut self, transition: F) {
        let need_next = mem::replace(&mut self.need_next, NeedNext::InitialTerm);
        self.need_next = transition(self, need_next);
    }

    fn push_token<T: Into<TokenType>>(&mut self, token_type: T, (start, string): (ByteIndex, String)) {
        self.tokens.push(Token::new(token_type.into(), string));
        self.token_starts.push(start);
    }

    fn report_unsupported_characters(&mut self) -> bool {
        let start = self.scanner.index;
        let mut string = String::new();
        if !self.scanner.take_valid_char(&mut string) {
            return false;
        }

        // If there are valid UTF-8 chars, they are just unsupported. Report
        while !self.scanner.eof() && !self.scan_token() && self.scanner.take_valid_char(&mut string) {}
        self.scanner.compiler.report_at(UnsupportedCharacters, self.scanner.source, start, &string);
        true
    }

    fn report_invalid_utf8(&mut self) {
        // Invalid UTF-8. Read invalid characters until you find something valid.
        let start = self.scanner.index;
        let mut bytes: Vec<u8> = vec![];
        while !self.scanner.eof() && !self.scanner.is_valid_char() {
            self.scanner.take_byte(&mut bytes);
        }
        self.scanner.compiler.report_invalid_bytes(InvalidUtf8, self.scanner.source, start, &bytes)
    }
}

fn digit(byte: u8) -> bool { (b'0'..=b'9').contains(byte) }
fn operator(byte: u8) -> bool { match byte { b'+'|b'-'|b'*'|b'/' => true, _ => false } }
<|endoftext|>


<commit_before>// xfail-stage0

use std;
import std::run;

// Regression test for memory leaks
// FIXME (714) Why does this fail on win32?

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
fn test_leaks() {
  run::run_program("echo", []);
  run::start_program("echo", []);
  run::program_output("echo", []);
}

#[cfg(target_os = "win32")]
fn test_leaks() {}

fn main() {
  test_leaks();
}<commit_msg>Enable run-pass/lib-run on win32. Closes #714<commit_after>// xfail-stage0

use std;
import std::run;

// Regression test for memory leaks
fn test_leaks() {
  run::run_program("echo", []);
  run::start_program("echo", []);
  run::program_output("echo", []);
}

fn main() {
  test_leaks();
}<|endoftext|>


<commit_before>//! Backend using the pure-rust crossplatform crossterm library.
//!
//! Requires the `crossterm-backend` feature.

#![cfg(feature = "crossterm")]

use std::{
    cell::{Cell, RefCell, RefMut},
    fs::File,
    io::{self, BufWriter, Stdout, Write},
    time::Duration,
};

use crossterm::{
    cursor::{Hide, MoveTo, Show},
    event::{
        poll, read, DisableMouseCapture, EnableMouseCapture, Event as CEvent,
        KeyCode, KeyEvent as CKeyEvent, KeyModifiers,
        MouseButton as CMouseButton, MouseEvent as CMouseEvent,
    },
    execute, queue,
    style::{
        Attribute, Color, Print, SetAttribute, SetBackgroundColor,
        SetForegroundColor,
    },
    terminal::{
        self, disable_raw_mode, enable_raw_mode, Clear, ClearType,
        EnterAlternateScreen, LeaveAlternateScreen,
    },
};

use crate::{
    backend,
    event::{Event, Key, MouseButton, MouseEvent},
    theme,
    vec::Vec2,
};

/// Backend using crossterm
pub struct Backend {
    current_style: Cell<theme::ColorPair>,
    last_button: Option<MouseButton>,

    #[cfg(windows)]
    stdout: RefCell<BufWriter<Stdout>>,
    #[cfg(unix)]
    stdout: RefCell<BufWriter<File>>,
}

impl From<CMouseButton> for MouseButton {
    fn from(button: CMouseButton) -> Self {
        match button {
            CMouseButton::Left => MouseButton::Left,
            CMouseButton::Right => MouseButton::Right,
            CMouseButton::Middle => MouseButton::Middle,
        }
    }
}

impl From<KeyCode> for Key {
    fn from(code: KeyCode) -> Self {
        match code {
            KeyCode::Esc => Key::Esc,
            KeyCode::Backspace => Key::Backspace,
            KeyCode::Left => Key::Left,
            KeyCode::Right => Key::Right,
            KeyCode::Up => Key::Up,
            KeyCode::Down => Key::Down,
            KeyCode::Home => Key::Home,
            KeyCode::End => Key::End,
            KeyCode::PageUp => Key::PageUp,
            KeyCode::PageDown => Key::PageDown,
            KeyCode::Delete => Key::Del,
            KeyCode::Insert => Key::Ins,
            KeyCode::Enter => Key::Enter,
            KeyCode::Tab => Key::Tab,
            KeyCode::F(n) => Key::from_f(n),
            KeyCode::BackTab => Key::Tab, /* not supported */
            KeyCode::Char(_) => Key::Tab, /* is handled at `Event` level, use tab as default */
            KeyCode::Null => Key::Tab, /* is handled at `Event` level, use tab as default */
        }
    }
}

impl From<CKeyEvent> for Event {
    fn from(event: CKeyEvent) -> Self {
        const CTRL_ALT: KeyModifiers = KeyModifiers::from_bits_truncate(
            KeyModifiers::CONTROL.bits() | KeyModifiers::ALT.bits(),
        );
        const CTRL_SHIFT: KeyModifiers = KeyModifiers::from_bits_truncate(
            KeyModifiers::CONTROL.bits() | KeyModifiers::SHIFT.bits(),
        );
        const ALT_SHIFT: KeyModifiers = KeyModifiers::from_bits_truncate(
            KeyModifiers::ALT.bits() | KeyModifiers::SHIFT.bits(),
        );

        match event {
            // Handle Char + modifier.
            CKeyEvent {
                modifiers: KeyModifiers::CONTROL,
                code: KeyCode::Char('c'),
            } => Event::Exit,
            CKeyEvent {
                modifiers: KeyModifiers::CONTROL,
                code: KeyCode::Char(c),
            } => Event::CtrlChar(c),
            CKeyEvent {
                modifiers: KeyModifiers::ALT,
                code: KeyCode::Char(c),
            } => Event::AltChar(c),
            CKeyEvent {
                modifiers: KeyModifiers::SHIFT,
                code: KeyCode::Char(c),
            } => Event::Char(c),

            // Handle key + multiple modifiers
            CKeyEvent {
                modifiers: CTRL_ALT,
                code,
            } => Event::CtrlAlt(Key::from(code)),
            CKeyEvent {
                modifiers: CTRL_SHIFT,
                code,
            } => Event::CtrlShift(Key::from(code)),
            CKeyEvent {
                modifiers: ALT_SHIFT,
                code,
            } => Event::AltShift(Key::from(code)),

            // Handle key + single modifier
            CKeyEvent {
                modifiers: KeyModifiers::CONTROL,
                code,
            } => Event::Ctrl(Key::from(code)),
            CKeyEvent {
                modifiers: KeyModifiers::ALT,
                code,
            } => Event::Alt(Key::from(code)),
            CKeyEvent {
                modifiers: KeyModifiers::SHIFT,
                code,
            } => Event::Shift(Key::from(code)),

            CKeyEvent {
                code: KeyCode::Char(c),
                ..
            } => Event::Char(c),

            // Explicitly handle 'backtab' since crossterm does not sent SHIFT alongside the back tab key.
            CKeyEvent {
                code: KeyCode::BackTab,
                ..
            } => Event::Shift(Key::Tab),

            // All other keys.
            CKeyEvent { code, .. } => Event::Key(Key::from(code)),
        }
    }
}

impl From<theme::Color> for Color {
    fn from(base_color: theme::Color) -> Self {
        match base_color {
            theme::Color::Dark(theme::BaseColor::Black) => Color::Black,
            theme::Color::Dark(theme::BaseColor::Red) => Color::DarkRed,
            theme::Color::Dark(theme::BaseColor::Green) => Color::DarkGreen,
            theme::Color::Dark(theme::BaseColor::Yellow) => Color::DarkYellow,
            theme::Color::Dark(theme::BaseColor::Blue) => Color::DarkBlue,
            theme::Color::Dark(theme::BaseColor::Magenta) => {
                Color::DarkMagenta
            }
            theme::Color::Dark(theme::BaseColor::Cyan) => Color::DarkCyan,
            theme::Color::Dark(theme::BaseColor::White) => Color::Grey,
            theme::Color::Light(theme::BaseColor::Black) => Color::DarkGrey,
            theme::Color::Light(theme::BaseColor::Red) => Color::Red,
            theme::Color::Light(theme::BaseColor::Green) => Color::Green,
            theme::Color::Light(theme::BaseColor::Yellow) => Color::Yellow,
            theme::Color::Light(theme::BaseColor::Blue) => Color::Blue,
            theme::Color::Light(theme::BaseColor::Magenta) => Color::Magenta,
            theme::Color::Light(theme::BaseColor::Cyan) => Color::Cyan,
            theme::Color::Light(theme::BaseColor::White) => Color::White,
            theme::Color::Rgb(r, g, b) => Color::Rgb { r, g, b },
            theme::Color::RgbLowRes(r, g, b) => {
                debug_assert!(r <= 5,
                              "Red color fragment (r = {}) is out of bound. Make sure r ≤ 5.",
                              r);
                debug_assert!(g <= 5,
                              "Green color fragment (g = {}) is out of bound. Make sure g ≤ 5.",
                              g);
                debug_assert!(b <= 5,
                              "Blue color fragment (b = {}) is out of bound. Make sure b ≤ 5.",
                              b);

                Color::AnsiValue(16 + 36 * r + 6 * g + b)
            }
            theme::Color::TerminalDefault => Color::Reset,
        }
    }
}

impl Backend {
    /// Creates a new crossterm backend.
    pub fn init() -> Result<Box<dyn backend::Backend>, crossterm::ErrorKind>
    where
        Self: Sized,
    {
        enable_raw_mode()?;

        execute!(
            io::stdout(),
            EnterAlternateScreen,
            EnableMouseCapture,
            Hide
        )?;

        #[cfg(unix)]
        let stdout = RefCell::new(BufWriter::new(File::create("/dev/tty")?));
        #[cfg(windows)]
        let stdout = RefCell::new(BufWriter::new(io::stdout()));

        Ok(Box::new(Backend {
            current_style: Cell::new(theme::ColorPair::from_256colors(0, 0)),
            last_button: None,
            stdout,
        }))
    }

    fn apply_colors(&self, colors: theme::ColorPair) {
        queue!(
            self.stdout_mut(),
            SetForegroundColor(Color::from(colors.front)),
            SetBackgroundColor(Color::from(colors.back))
        )
        .unwrap();
    }

    #[cfg(unix)]
    fn stdout_mut(&self) -> RefMut<BufWriter<File>> {
        self.stdout.borrow_mut()
    }

    #[cfg(windows)]
    fn stdout_mut(&self) -> RefMut<BufWriter<Stdout>> {
        self.stdout.borrow_mut()
    }

    fn set_attr(&self, attr: Attribute) {
        queue!(self.stdout_mut(), SetAttribute(attr)).unwrap();
    }

    fn map_key(&mut self, event: CEvent) -> Event {
        match event {
            CEvent::Key(key_event) => Event::from(key_event),
            CEvent::Mouse(mouse_event) => {
                let position;
                let event;

                match mouse_event {
                    CMouseEvent::Down(button, x, y, _) => {
                        let button = MouseButton::from(button);
                        self.last_button = Some(button);
                        event = MouseEvent::Press(button);
                        position = (x, y).into();
                    }
                    CMouseEvent::Up(_, x, y, _) => {
                        event = MouseEvent::Release(self.last_button.unwrap());
                        position = (x, y).into();
                    }
                    CMouseEvent::Drag(_, x, y, _) => {
                        event = MouseEvent::Hold(self.last_button.unwrap());
                        position = (x, y).into();
                    }
                    CMouseEvent::ScrollDown(x, y, _) => {
                        event = MouseEvent::WheelDown;
                        position = (x, y).into();
                    }
                    CMouseEvent::ScrollUp(x, y, _) => {
                        event = MouseEvent::WheelDown;
                        position = (x, y).into();
                    }
                };

                Event::Mouse {
                    event,
                    position,
                    offset: Vec2::zero(),
                }
            }
            CEvent::Resize(_, _) => Event::WindowResize,
        }
    }
}

impl backend::Backend for Backend {
    fn poll_event(&mut self) -> Option<Event> {
        match poll(Duration::from_millis(1)) {
            Ok(true) => match read() {
                Ok(event) => Some(self.map_key(event)),
                Err(e) => panic!("{:?}", e),
            },
            _ => None,
        }
    }

    fn finish(&mut self) {
        // We have to execute the show cursor command at the `stdout`.
        execute!(
            io::stdout(),
            LeaveAlternateScreen,
            DisableMouseCapture,
            Show
        )
        .expect("Can not disable mouse capture or show cursor.");

        disable_raw_mode().unwrap();
    }

    fn refresh(&mut self) {
        self.stdout_mut().flush().unwrap();
    }

    fn has_colors(&self) -> bool {
        // TODO: color support detection?
        true
    }

    fn screen_size(&self) -> Vec2 {
        let size = terminal::size().unwrap_or((1, 1));
        Vec2::from(size)
    }

    fn print_at(&self, pos: Vec2, text: &str) {
        queue!(
            self.stdout_mut(),
            MoveTo(pos.x as u16, pos.y as u16),
            Print(text)
        )
        .unwrap();
    }

    fn print_at_rep(&self, pos: Vec2, repetitions: usize, text: &str) {
        if repetitions > 0 {
            let mut out = self.stdout_mut();

            queue!(out, MoveTo(pos.x as u16, pos.y as u16)).unwrap();

            out.write_all(text.as_bytes()).unwrap();

            let mut dupes_left = repetitions - 1;
            while dupes_left > 0 {
                out.write_all(text.as_bytes()).unwrap();
                dupes_left -= 1;
            }
        }
    }

    fn clear(&self, color: theme::Color) {
        self.apply_colors(theme::ColorPair {
            front: color,
            back: color,
        });

        queue!(self.stdout_mut(), Clear(ClearType::All)).unwrap();
    }

    fn set_color(&self, color: theme::ColorPair) -> theme::ColorPair {
        let current_style = self.current_style.get();

        if current_style != color {
            self.apply_colors(color);
            self.current_style.set(color);
        }

        current_style
    }

    fn set_effect(&self, effect: theme::Effect) {
        match effect {
            theme::Effect::Simple => (),
            theme::Effect::Reverse => self.set_attr(Attribute::Reverse),
            theme::Effect::Bold => self.set_attr(Attribute::Bold),
            theme::Effect::Italic => self.set_attr(Attribute::Italic),
            theme::Effect::Strikethrough => {
                self.set_attr(Attribute::CrossedOut)
            }
            theme::Effect::Underline => self.set_attr(Attribute::Underlined),
        }
    }

    fn unset_effect(&self, effect: theme::Effect) {
        match effect {
            theme::Effect::Simple => (),
            theme::Effect::Reverse => self.set_attr(Attribute::NoReverse),
            theme::Effect::Bold => self.set_attr(Attribute::NormalIntensity),
            theme::Effect::Italic => self.set_attr(Attribute::NoItalic),
            theme::Effect::Strikethrough => {
                self.set_attr(Attribute::NotCrossedOut)
            }
            theme::Effect::Underline => self.set_attr(Attribute::NoUnderline),
        }
    }

    fn name(&self) -> &str {
        "crossterm"
    }
}
<commit_msg>crossterm: fix scroll up event conversion (#417)<commit_after>//! Backend using the pure-rust crossplatform crossterm library.
//!
//! Requires the `crossterm-backend` feature.

#![cfg(feature = "crossterm")]

use std::{
    cell::{Cell, RefCell, RefMut},
    fs::File,
    io::{self, BufWriter, Stdout, Write},
    time::Duration,
};

use crossterm::{
    cursor::{Hide, MoveTo, Show},
    event::{
        poll, read, DisableMouseCapture, EnableMouseCapture, Event as CEvent,
        KeyCode, KeyEvent as CKeyEvent, KeyModifiers,
        MouseButton as CMouseButton, MouseEvent as CMouseEvent,
    },
    execute, queue,
    style::{
        Attribute, Color, Print, SetAttribute, SetBackgroundColor,
        SetForegroundColor,
    },
    terminal::{
        self, disable_raw_mode, enable_raw_mode, Clear, ClearType,
        EnterAlternateScreen, LeaveAlternateScreen,
    },
};

use crate::{
    backend,
    event::{Event, Key, MouseButton, MouseEvent},
    theme,
    vec::Vec2,
};

/// Backend using crossterm
pub struct Backend {
    current_style: Cell<theme::ColorPair>,
    last_button: Option<MouseButton>,

    #[cfg(windows)]
    stdout: RefCell<BufWriter<Stdout>>,
    #[cfg(unix)]
    stdout: RefCell<BufWriter<File>>,
}

impl From<CMouseButton> for MouseButton {
    fn from(button: CMouseButton) -> Self {
        match button {
            CMouseButton::Left => MouseButton::Left,
            CMouseButton::Right => MouseButton::Right,
            CMouseButton::Middle => MouseButton::Middle,
        }
    }
}

impl From<KeyCode> for Key {
    fn from(code: KeyCode) -> Self {
        match code {
            KeyCode::Esc => Key::Esc,
            KeyCode::Backspace => Key::Backspace,
            KeyCode::Left => Key::Left,
            KeyCode::Right => Key::Right,
            KeyCode::Up => Key::Up,
            KeyCode::Down => Key::Down,
            KeyCode::Home => Key::Home,
            KeyCode::End => Key::End,
            KeyCode::PageUp => Key::PageUp,
            KeyCode::PageDown => Key::PageDown,
            KeyCode::Delete => Key::Del,
            KeyCode::Insert => Key::Ins,
            KeyCode::Enter => Key::Enter,
            KeyCode::Tab => Key::Tab,
            KeyCode::F(n) => Key::from_f(n),
            KeyCode::BackTab => Key::Tab, /* not supported */
            KeyCode::Char(_) => Key::Tab, /* is handled at `Event` level, use tab as default */
            KeyCode::Null => Key::Tab, /* is handled at `Event` level, use tab as default */
        }
    }
}

impl From<CKeyEvent> for Event {
    fn from(event: CKeyEvent) -> Self {
        const CTRL_ALT: KeyModifiers = KeyModifiers::from_bits_truncate(
            KeyModifiers::CONTROL.bits() | KeyModifiers::ALT.bits(),
        );
        const CTRL_SHIFT: KeyModifiers = KeyModifiers::from_bits_truncate(
            KeyModifiers::CONTROL.bits() | KeyModifiers::SHIFT.bits(),
        );
        const ALT_SHIFT: KeyModifiers = KeyModifiers::from_bits_truncate(
            KeyModifiers::ALT.bits() | KeyModifiers::SHIFT.bits(),
        );

        match event {
            // Handle Char + modifier.
            CKeyEvent {
                modifiers: KeyModifiers::CONTROL,
                code: KeyCode::Char('c'),
            } => Event::Exit,
            CKeyEvent {
                modifiers: KeyModifiers::CONTROL,
                code: KeyCode::Char(c),
            } => Event::CtrlChar(c),
            CKeyEvent {
                modifiers: KeyModifiers::ALT,
                code: KeyCode::Char(c),
            } => Event::AltChar(c),
            CKeyEvent {
                modifiers: KeyModifiers::SHIFT,
                code: KeyCode::Char(c),
            } => Event::Char(c),

            // Handle key + multiple modifiers
            CKeyEvent {
                modifiers: CTRL_ALT,
                code,
            } => Event::CtrlAlt(Key::from(code)),
            CKeyEvent {
                modifiers: CTRL_SHIFT,
                code,
            } => Event::CtrlShift(Key::from(code)),
            CKeyEvent {
                modifiers: ALT_SHIFT,
                code,
            } => Event::AltShift(Key::from(code)),

            // Handle key + single modifier
            CKeyEvent {
                modifiers: KeyModifiers::CONTROL,
                code,
            } => Event::Ctrl(Key::from(code)),
            CKeyEvent {
                modifiers: KeyModifiers::ALT,
                code,
            } => Event::Alt(Key::from(code)),
            CKeyEvent {
                modifiers: KeyModifiers::SHIFT,
                code,
            } => Event::Shift(Key::from(code)),

            CKeyEvent {
                code: KeyCode::Char(c),
                ..
            } => Event::Char(c),

            // Explicitly handle 'backtab' since crossterm does not sent SHIFT alongside the back tab key.
            CKeyEvent {
                code: KeyCode::BackTab,
                ..
            } => Event::Shift(Key::Tab),

            // All other keys.
            CKeyEvent { code, .. } => Event::Key(Key::from(code)),
        }
    }
}

impl From<theme::Color> for Color {
    fn from(base_color: theme::Color) -> Self {
        match base_color {
            theme::Color::Dark(theme::BaseColor::Black) => Color::Black,
            theme::Color::Dark(theme::BaseColor::Red) => Color::DarkRed,
            theme::Color::Dark(theme::BaseColor::Green) => Color::DarkGreen,
            theme::Color::Dark(theme::BaseColor::Yellow) => Color::DarkYellow,
            theme::Color::Dark(theme::BaseColor::Blue) => Color::DarkBlue,
            theme::Color::Dark(theme::BaseColor::Magenta) => {
                Color::DarkMagenta
            }
            theme::Color::Dark(theme::BaseColor::Cyan) => Color::DarkCyan,
            theme::Color::Dark(theme::BaseColor::White) => Color::Grey,
            theme::Color::Light(theme::BaseColor::Black) => Color::DarkGrey,
            theme::Color::Light(theme::BaseColor::Red) => Color::Red,
            theme::Color::Light(theme::BaseColor::Green) => Color::Green,
            theme::Color::Light(theme::BaseColor::Yellow) => Color::Yellow,
            theme::Color::Light(theme::BaseColor::Blue) => Color::Blue,
            theme::Color::Light(theme::BaseColor::Magenta) => Color::Magenta,
            theme::Color::Light(theme::BaseColor::Cyan) => Color::Cyan,
            theme::Color::Light(theme::BaseColor::White) => Color::White,
            theme::Color::Rgb(r, g, b) => Color::Rgb { r, g, b },
            theme::Color::RgbLowRes(r, g, b) => {
                debug_assert!(r <= 5,
                              "Red color fragment (r = {}) is out of bound. Make sure r ≤ 5.",
                              r);
                debug_assert!(g <= 5,
                              "Green color fragment (g = {}) is out of bound. Make sure g ≤ 5.",
                              g);
                debug_assert!(b <= 5,
                              "Blue color fragment (b = {}) is out of bound. Make sure b ≤ 5.",
                              b);

                Color::AnsiValue(16 + 36 * r + 6 * g + b)
            }
            theme::Color::TerminalDefault => Color::Reset,
        }
    }
}

impl Backend {
    /// Creates a new crossterm backend.
    pub fn init() -> Result<Box<dyn backend::Backend>, crossterm::ErrorKind>
    where
        Self: Sized,
    {
        enable_raw_mode()?;

        execute!(
            io::stdout(),
            EnterAlternateScreen,
            EnableMouseCapture,
            Hide
        )?;

        #[cfg(unix)]
        let stdout = RefCell::new(BufWriter::new(File::create("/dev/tty")?));
        #[cfg(windows)]
        let stdout = RefCell::new(BufWriter::new(io::stdout()));

        Ok(Box::new(Backend {
            current_style: Cell::new(theme::ColorPair::from_256colors(0, 0)),
            last_button: None,
            stdout,
        }))
    }

    fn apply_colors(&self, colors: theme::ColorPair) {
        queue!(
            self.stdout_mut(),
            SetForegroundColor(Color::from(colors.front)),
            SetBackgroundColor(Color::from(colors.back))
        )
        .unwrap();
    }

    #[cfg(unix)]
    fn stdout_mut(&self) -> RefMut<BufWriter<File>> {
        self.stdout.borrow_mut()
    }

    #[cfg(windows)]
    fn stdout_mut(&self) -> RefMut<BufWriter<Stdout>> {
        self.stdout.borrow_mut()
    }

    fn set_attr(&self, attr: Attribute) {
        queue!(self.stdout_mut(), SetAttribute(attr)).unwrap();
    }

    fn map_key(&mut self, event: CEvent) -> Event {
        match event {
            CEvent::Key(key_event) => Event::from(key_event),
            CEvent::Mouse(mouse_event) => {
                let position;
                let event;

                match mouse_event {
                    CMouseEvent::Down(button, x, y, _) => {
                        let button = MouseButton::from(button);
                        self.last_button = Some(button);
                        event = MouseEvent::Press(button);
                        position = (x, y).into();
                    }
                    CMouseEvent::Up(_, x, y, _) => {
                        event = MouseEvent::Release(self.last_button.unwrap());
                        position = (x, y).into();
                    }
                    CMouseEvent::Drag(_, x, y, _) => {
                        event = MouseEvent::Hold(self.last_button.unwrap());
                        position = (x, y).into();
                    }
                    CMouseEvent::ScrollDown(x, y, _) => {
                        event = MouseEvent::WheelDown;
                        position = (x, y).into();
                    }
                    CMouseEvent::ScrollUp(x, y, _) => {
                        event = MouseEvent::WheelUp;
                        position = (x, y).into();
                    }
                };

                Event::Mouse {
                    event,
                    position,
                    offset: Vec2::zero(),
                }
            }
            CEvent::Resize(_, _) => Event::WindowResize,
        }
    }
}

impl backend::Backend for Backend {
    fn poll_event(&mut self) -> Option<Event> {
        match poll(Duration::from_millis(1)) {
            Ok(true) => match read() {
                Ok(event) => Some(self.map_key(event)),
                Err(e) => panic!("{:?}", e),
            },
            _ => None,
        }
    }

    fn finish(&mut self) {
        // We have to execute the show cursor command at the `stdout`.
        execute!(
            io::stdout(),
            LeaveAlternateScreen,
            DisableMouseCapture,
            Show
        )
        .expect("Can not disable mouse capture or show cursor.");

        disable_raw_mode().unwrap();
    }

    fn refresh(&mut self) {
        self.stdout_mut().flush().unwrap();
    }

    fn has_colors(&self) -> bool {
        // TODO: color support detection?
        true
    }

    fn screen_size(&self) -> Vec2 {
        let size = terminal::size().unwrap_or((1, 1));
        Vec2::from(size)
    }

    fn print_at(&self, pos: Vec2, text: &str) {
        queue!(
            self.stdout_mut(),
            MoveTo(pos.x as u16, pos.y as u16),
            Print(text)
        )
        .unwrap();
    }

    fn print_at_rep(&self, pos: Vec2, repetitions: usize, text: &str) {
        if repetitions > 0 {
            let mut out = self.stdout_mut();

            queue!(out, MoveTo(pos.x as u16, pos.y as u16)).unwrap();

            out.write_all(text.as_bytes()).unwrap();

            let mut dupes_left = repetitions - 1;
            while dupes_left > 0 {
                out.write_all(text.as_bytes()).unwrap();
                dupes_left -= 1;
            }
        }
    }

    fn clear(&self, color: theme::Color) {
        self.apply_colors(theme::ColorPair {
            front: color,
            back: color,
        });

        queue!(self.stdout_mut(), Clear(ClearType::All)).unwrap();
    }

    fn set_color(&self, color: theme::ColorPair) -> theme::ColorPair {
        let current_style = self.current_style.get();

        if current_style != color {
            self.apply_colors(color);
            self.current_style.set(color);
        }

        current_style
    }

    fn set_effect(&self, effect: theme::Effect) {
        match effect {
            theme::Effect::Simple => (),
            theme::Effect::Reverse => self.set_attr(Attribute::Reverse),
            theme::Effect::Bold => self.set_attr(Attribute::Bold),
            theme::Effect::Italic => self.set_attr(Attribute::Italic),
            theme::Effect::Strikethrough => {
                self.set_attr(Attribute::CrossedOut)
            }
            theme::Effect::Underline => self.set_attr(Attribute::Underlined),
        }
    }

    fn unset_effect(&self, effect: theme::Effect) {
        match effect {
            theme::Effect::Simple => (),
            theme::Effect::Reverse => self.set_attr(Attribute::NoReverse),
            theme::Effect::Bold => self.set_attr(Attribute::NormalIntensity),
            theme::Effect::Italic => self.set_attr(Attribute::NoItalic),
            theme::Effect::Strikethrough => {
                self.set_attr(Attribute::NotCrossedOut)
            }
            theme::Effect::Underline => self.set_attr(Attribute::NoUnderline),
        }
    }

    fn name(&self) -> &str {
        "crossterm"
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The implementations of the `Standard` distribution for other built-in types.

use core::char;
use core::num::Wrapping;

use crate::distributions::{Distribution, Standard, Uniform};
use crate::Rng;

#[cfg(feature = "serde1")]
use serde::{Serialize, Deserialize};

// ----- Sampling distributions -----

/// Sample a `u8`, uniformly distributed over ASCII letters and numbers:
/// a-z, A-Z and 0-9.
///
/// # Example
///
/// ```
/// use std::iter;
/// use rand::{Rng, thread_rng};
/// use rand::distributions::Alphanumeric;
///
/// let mut rng = thread_rng();
/// let chars: String = iter::repeat(())
///         .map(|()| rng.sample(Alphanumeric))
///         .map(char::from)
///         .take(7)
///         .collect();
/// println!("Random chars: {}", chars);
/// ```
///
/// # Passwords
///
/// Users sometimes ask whether it is safe to use a string of random characters
/// as a password. In principle, all RNGs in Rand implementing `CryptoRng` are
/// suitable as a source of randomness for generating passwords (if they are
/// properly seeded), but it is more conservative to only use randomness
/// directly from the operating system via the `getrandom` crate, or the
/// corresponding bindings of a crypto library.
///
/// When generating passwords or keys, it is important to consider the threat
/// model and in some cases the memorability of the password. This is out of
/// scope of the Rand project, and therefore we defer to the following
/// references:
///
/// - [Wikipedia article on Password Strength](https://en.wikipedia.org/wiki/Password_strength)
/// - [Diceware for generating memorable passwords](https://en.wikipedia.org/wiki/Diceware)
#[derive(Debug)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Alphanumeric;

// ----- Implementations of distributions -----

impl Distribution<char> for Standard {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
        // A valid `char` is either in the interval `[0, 0xD800)` or
        // `(0xDFFF, 0x11_0000)`. All `char`s must therefore be in
        // `[0, 0x11_0000)` but not in the "gap" `[0xD800, 0xDFFF]` which is
        // reserved for surrogates. This is the size of that gap.
        const GAP_SIZE: u32 = 0xDFFF - 0xD800 + 1;

        // Uniform::new(0, 0x11_0000 - GAP_SIZE) can also be used but it
        // seemed slower.
        let range = Uniform::new(GAP_SIZE, 0x11_0000);

        let mut n = range.sample(rng);
        if n <= 0xDFFF {
            n -= GAP_SIZE;
        }
        unsafe { char::from_u32_unchecked(n) }
    }
}

impl Distribution<u8> for Alphanumeric {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
        const RANGE: u32 = 26 + 26 + 10;
        const GEN_ASCII_STR_CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                abcdefghijklmnopqrstuvwxyz\
                0123456789";
        // We can pick from 62 characters. This is so close to a power of 2, 64,
        // that we can do better than `Uniform`. Use a simple bitshift and
        // rejection sampling. We do not use a bitmask, because for small RNGs
        // the most significant bits are usually of higher quality.
        loop {
            let var = rng.next_u32() >> (32 - 6);
            if var < RANGE {
                return GEN_ASCII_STR_CHARSET[var as usize];
            }
        }
    }
}

impl Distribution<bool> for Standard {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {
        // We can compare against an arbitrary bit of an u32 to get a bool.
        // Because the least significant bits of a lower quality RNG can have
        // simple patterns, we compare against the most significant bit. This is
        // easiest done using a sign test.
        (rng.next_u32() as i32) < 0
    }
}

macro_rules! tuple_impl {
    // use variables to indicate the arity of the tuple
    ($($tyvar:ident),* ) => {
        // the trailing commas are for the 1 tuple
        impl< $( $tyvar ),* >
            Distribution<( $( $tyvar ),* , )>
            for Standard
            where $( Standard: Distribution<$tyvar> ),*
        {
            #[inline]
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> ( $( $tyvar ),* , ) {
                (
                    // use the $tyvar's to get the appropriate number of
                    // repeats (they're not actually needed)
                    $(
                        _rng.gen::<$tyvar>()
                    ),*
                    ,
                )
            }
        }
    }
}

impl Distribution<()> for Standard {
    #[allow(clippy::unused_unit)]
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () {
        ()
    }
}
tuple_impl! {A}
tuple_impl! {A, B}
tuple_impl! {A, B, C}
tuple_impl! {A, B, C, D}
tuple_impl! {A, B, C, D, E}
tuple_impl! {A, B, C, D, E, F}
tuple_impl! {A, B, C, D, E, F, G}
tuple_impl! {A, B, C, D, E, F, G, H}
tuple_impl! {A, B, C, D, E, F, G, H, I}
tuple_impl! {A, B, C, D, E, F, G, H, I, J}
tuple_impl! {A, B, C, D, E, F, G, H, I, J, K}
tuple_impl! {A, B, C, D, E, F, G, H, I, J, K, L}

#[cfg(feature = "min_const_gen")]
impl<T, const N: usize> Distribution<[T; N]> for Standard
where
    Standard: Distribution<T>,
    T: Default + Copy,
{
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; N] {
        let mut sample = [Default::default(); N];
        for elem in &mut sample {
            *elem = _rng.gen();
        }

        sample
    }
}

#[cfg(not(feature = "min_const_gen"))]
macro_rules! array_impl {
    // recursive, given at least one type parameter:
    {$n:expr, $t:ident, $($ts:ident,)*} => {
        array_impl!{($n - 1), $($ts,)*}

        impl<T> Distribution<[T; $n]> for Standard where Standard: Distribution<T> {
            #[inline]
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] {
                [_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*]
            }
        }
    };
    // empty case:
    {$n:expr,} => {
        impl<T> Distribution<[T; $n]> for Standard {
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { [] }
        }
    };
}

#[cfg(not(feature = "min_const_gen"))]
array_impl! {32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,}

impl<T> Distribution<Option<T>> for Standard
where Standard: Distribution<T>
{
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<T> {
        // UFCS is needed here: https://github.com/rust-lang/rust/issues/24066
        if rng.gen::<bool>() {
            Some(rng.gen())
        } else {
            None
        }
    }
}

impl<T> Distribution<Wrapping<T>> for Standard
where Standard: Distribution<T>
{
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Wrapping<T> {
        Wrapping(rng.gen())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::RngCore;
    #[cfg(feature = "alloc")] use alloc::string::String;

    #[test]
    fn test_misc() {
        let rng: &mut dyn RngCore = &mut crate::test::rng(820);

        rng.sample::<char, _>(Standard);
        rng.sample::<bool, _>(Standard);
    }

    #[cfg(feature = "alloc")]
    #[test]
    fn test_chars() {
        use core::iter;
        let mut rng = crate::test::rng(805);

        // Test by generating a relatively large number of chars, so we also
        // take the rejection sampling path.
        let word: String = iter::repeat(())
            .map(|()| rng.gen::<char>())
            .take(1000)
            .collect();
        assert!(word.len() != 0);
    }

    #[test]
    fn test_alphanumeric() {
        let mut rng = crate::test::rng(806);

        // Test by generating a relatively large number of chars, so we also
        // take the rejection sampling path.
        let mut incorrect = false;
        for _ in 0..100 {
            let c: char = rng.sample(Alphanumeric).into();
            incorrect |= !((c >= '0' && c <= '9') ||
                           (c >= 'A' && c <= 'Z') ||
                           (c >= 'a' && c <= 'z') );
        }
        assert!(incorrect == false);
    }

    #[test]
    fn value_stability() {
        fn test_samples<T: Copy + core::fmt::Debug + PartialEq, D: Distribution<T>>(
            distr: &D, zero: T, expected: &[T],
        ) {
            let mut rng = crate::test::rng(807);
            let mut buf = [zero; 5];
            for x in &mut buf {
                *x = rng.sample(&distr);
            }
            assert_eq!(&buf, expected);
        }

        test_samples(&Standard, 'a', &[
            '\u{8cdac}',
            '\u{a346a}',
            '\u{80120}',
            '\u{ed692}',
            '\u{35888}',
        ]);
        test_samples(&Alphanumeric, 0, &[104, 109, 101, 51, 77]);
        test_samples(&Standard, false, &[true, true, false, true, false]);
        test_samples(&Standard, None as Option<bool>, &[
            Some(true),
            None,
            Some(false),
            None,
            Some(false),
        ]);
        test_samples(&Standard, Wrapping(0i32), &[
            Wrapping(-2074640887),
            Wrapping(-1719949321),
            Wrapping(2018088303),
            Wrapping(-547181756),
            Wrapping(838957336),
        ]);

        // We test only sub-sets of tuple and array impls
        test_samples(&Standard, (), &[(), (), (), (), ()]);
        test_samples(&Standard, (false,), &[
            (true,),
            (true,),
            (false,),
            (true,),
            (false,),
        ]);
        test_samples(&Standard, (false, false), &[
            (true, true),
            (false, true),
            (false, false),
            (true, false),
            (false, false),
        ]);

        test_samples(&Standard, [0u8; 0], &[[], [], [], [], []]);
        test_samples(&Standard, [0u8; 3], &[
            [9, 247, 111],
            [68, 24, 13],
            [174, 19, 194],
            [172, 69, 213],
            [149, 207, 29],
        ]);
    }
}
<commit_msg>Use MaybeUninit to initialize a random array, remove Default + Copy trait bounds<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The implementations of the `Standard` distribution for other built-in types.

use core::char;
use core::num::Wrapping;

use crate::distributions::{Distribution, Standard, Uniform};
use crate::Rng;

#[cfg(feature = "serde1")]
use serde::{Serialize, Deserialize};
#[cfg(feature = "min_const_gen")]
use std::mem::{self, MaybeUninit};

// ----- Sampling distributions -----

/// Sample a `u8`, uniformly distributed over ASCII letters and numbers:
/// a-z, A-Z and 0-9.
///
/// # Example
///
/// ```
/// use std::iter;
/// use rand::{Rng, thread_rng};
/// use rand::distributions::Alphanumeric;
///
/// let mut rng = thread_rng();
/// let chars: String = iter::repeat(())
///         .map(|()| rng.sample(Alphanumeric))
///         .map(char::from)
///         .take(7)
///         .collect();
/// println!("Random chars: {}", chars);
/// ```
///
/// # Passwords
///
/// Users sometimes ask whether it is safe to use a string of random characters
/// as a password. In principle, all RNGs in Rand implementing `CryptoRng` are
/// suitable as a source of randomness for generating passwords (if they are
/// properly seeded), but it is more conservative to only use randomness
/// directly from the operating system via the `getrandom` crate, or the
/// corresponding bindings of a crypto library.
///
/// When generating passwords or keys, it is important to consider the threat
/// model and in some cases the memorability of the password. This is out of
/// scope of the Rand project, and therefore we defer to the following
/// references:
///
/// - [Wikipedia article on Password Strength](https://en.wikipedia.org/wiki/Password_strength)
/// - [Diceware for generating memorable passwords](https://en.wikipedia.org/wiki/Diceware)
#[derive(Debug)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Alphanumeric;

// ----- Implementations of distributions -----

impl Distribution<char> for Standard {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
        // A valid `char` is either in the interval `[0, 0xD800)` or
        // `(0xDFFF, 0x11_0000)`. All `char`s must therefore be in
        // `[0, 0x11_0000)` but not in the "gap" `[0xD800, 0xDFFF]` which is
        // reserved for surrogates. This is the size of that gap.
        const GAP_SIZE: u32 = 0xDFFF - 0xD800 + 1;

        // Uniform::new(0, 0x11_0000 - GAP_SIZE) can also be used but it
        // seemed slower.
        let range = Uniform::new(GAP_SIZE, 0x11_0000);

        let mut n = range.sample(rng);
        if n <= 0xDFFF {
            n -= GAP_SIZE;
        }
        unsafe { char::from_u32_unchecked(n) }
    }
}

impl Distribution<u8> for Alphanumeric {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
        const RANGE: u32 = 26 + 26 + 10;
        const GEN_ASCII_STR_CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                abcdefghijklmnopqrstuvwxyz\
                0123456789";
        // We can pick from 62 characters. This is so close to a power of 2, 64,
        // that we can do better than `Uniform`. Use a simple bitshift and
        // rejection sampling. We do not use a bitmask, because for small RNGs
        // the most significant bits are usually of higher quality.
        loop {
            let var = rng.next_u32() >> (32 - 6);
            if var < RANGE {
                return GEN_ASCII_STR_CHARSET[var as usize];
            }
        }
    }
}

impl Distribution<bool> for Standard {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {
        // We can compare against an arbitrary bit of an u32 to get a bool.
        // Because the least significant bits of a lower quality RNG can have
        // simple patterns, we compare against the most significant bit. This is
        // easiest done using a sign test.
        (rng.next_u32() as i32) < 0
    }
}

macro_rules! tuple_impl {
    // use variables to indicate the arity of the tuple
    ($($tyvar:ident),* ) => {
        // the trailing commas are for the 1 tuple
        impl< $( $tyvar ),* >
            Distribution<( $( $tyvar ),* , )>
            for Standard
            where $( Standard: Distribution<$tyvar> ),*
        {
            #[inline]
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> ( $( $tyvar ),* , ) {
                (
                    // use the $tyvar's to get the appropriate number of
                    // repeats (they're not actually needed)
                    $(
                        _rng.gen::<$tyvar>()
                    ),*
                    ,
                )
            }
        }
    }
}

impl Distribution<()> for Standard {
    #[allow(clippy::unused_unit)]
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () {
        ()
    }
}
tuple_impl! {A}
tuple_impl! {A, B}
tuple_impl! {A, B, C}
tuple_impl! {A, B, C, D}
tuple_impl! {A, B, C, D, E}
tuple_impl! {A, B, C, D, E, F}
tuple_impl! {A, B, C, D, E, F, G}
tuple_impl! {A, B, C, D, E, F, G, H}
tuple_impl! {A, B, C, D, E, F, G, H, I}
tuple_impl! {A, B, C, D, E, F, G, H, I, J}
tuple_impl! {A, B, C, D, E, F, G, H, I, J, K}
tuple_impl! {A, B, C, D, E, F, G, H, I, J, K, L}

#[cfg(feature = "min_const_gen")]
impl<T, const N: usize> Distribution<[T; N]> for Standard
where Standard: Distribution<T>
{
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; N] {
        let mut buff: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };

        for elem in &mut buff {
            *elem = MaybeUninit::new(_rng.gen());
        }

        unsafe { mem::transmute_copy::<_, _>(&buff) }
    }
}

#[cfg(not(feature = "min_const_gen"))]
macro_rules! array_impl {
    // recursive, given at least one type parameter:
    {$n:expr, $t:ident, $($ts:ident,)*} => {
        array_impl!{($n - 1), $($ts,)*}

        impl<T> Distribution<[T; $n]> for Standard where Standard: Distribution<T> {
            #[inline]
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] {
                [_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*]
            }
        }
    };
    // empty case:
    {$n:expr,} => {
        impl<T> Distribution<[T; $n]> for Standard {
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { [] }
        }
    };
}

#[cfg(not(feature = "min_const_gen"))]
array_impl! {32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,}

impl<T> Distribution<Option<T>> for Standard
where Standard: Distribution<T>
{
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<T> {
        // UFCS is needed here: https://github.com/rust-lang/rust/issues/24066
        if rng.gen::<bool>() {
            Some(rng.gen())
        } else {
            None
        }
    }
}

impl<T> Distribution<Wrapping<T>> for Standard
where Standard: Distribution<T>
{
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Wrapping<T> {
        Wrapping(rng.gen())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::RngCore;
    #[cfg(feature = "alloc")] use alloc::string::String;

    #[test]
    fn test_misc() {
        let rng: &mut dyn RngCore = &mut crate::test::rng(820);

        rng.sample::<char, _>(Standard);
        rng.sample::<bool, _>(Standard);
    }

    #[cfg(feature = "alloc")]
    #[test]
    fn test_chars() {
        use core::iter;
        let mut rng = crate::test::rng(805);

        // Test by generating a relatively large number of chars, so we also
        // take the rejection sampling path.
        let word: String = iter::repeat(())
            .map(|()| rng.gen::<char>())
            .take(1000)
            .collect();
        assert!(word.len() != 0);
    }

    #[test]
    fn test_alphanumeric() {
        let mut rng = crate::test::rng(806);

        // Test by generating a relatively large number of chars, so we also
        // take the rejection sampling path.
        let mut incorrect = false;
        for _ in 0..100 {
            let c: char = rng.sample(Alphanumeric).into();
            incorrect |= !((c >= '0' && c <= '9') ||
                           (c >= 'A' && c <= 'Z') ||
                           (c >= 'a' && c <= 'z') );
        }
        assert!(incorrect == false);
    }

    #[test]
    fn value_stability() {
        fn test_samples<T: Copy + core::fmt::Debug + PartialEq, D: Distribution<T>>(
            distr: &D, zero: T, expected: &[T],
        ) {
            let mut rng = crate::test::rng(807);
            let mut buf = [zero; 5];
            for x in &mut buf {
                *x = rng.sample(&distr);
            }
            assert_eq!(&buf, expected);
        }

        test_samples(&Standard, 'a', &[
            '\u{8cdac}',
            '\u{a346a}',
            '\u{80120}',
            '\u{ed692}',
            '\u{35888}',
        ]);
        test_samples(&Alphanumeric, 0, &[104, 109, 101, 51, 77]);
        test_samples(&Standard, false, &[true, true, false, true, false]);
        test_samples(&Standard, None as Option<bool>, &[
            Some(true),
            None,
            Some(false),
            None,
            Some(false),
        ]);
        test_samples(&Standard, Wrapping(0i32), &[
            Wrapping(-2074640887),
            Wrapping(-1719949321),
            Wrapping(2018088303),
            Wrapping(-547181756),
            Wrapping(838957336),
        ]);

        // We test only sub-sets of tuple and array impls
        test_samples(&Standard, (), &[(), (), (), (), ()]);
        test_samples(&Standard, (false,), &[
            (true,),
            (true,),
            (false,),
            (true,),
            (false,),
        ]);
        test_samples(&Standard, (false, false), &[
            (true, true),
            (false, true),
            (false, false),
            (true, false),
            (false, false),
        ]);

        test_samples(&Standard, [0u8; 0], &[[], [], [], [], []]);
        test_samples(&Standard, [0u8; 3], &[
            [9, 247, 111],
            [68, 24, 13],
            [174, 19, 194],
            [172, 69, 213],
            [149, 207, 29],
        ]);
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use header::{Header, Raw, parsing};

/// `Content-Length` header, defined in
/// [RFC7230](http://tools.ietf.org/html/rfc7230#section-3.3.2)
///
/// When a message does not have a `Transfer-Encoding` header field, a
/// Content-Length header field can provide the anticipated size, as a
/// decimal number of octets, for a potential payload body.  For messages
/// that do include a payload body, the Content-Length field-value
/// provides the framing information necessary for determining where the
/// body (and message) ends.  For messages that do not include a payload
/// body, the Content-Length indicates the size of the selected
/// representation.
///
/// # ABNF
/// ```plain
/// Content-Length = 1*DIGIT
/// ```
///
/// # Example values
/// * `3495`
///
/// # Example
/// ```
/// use hyper::header::{Headers, ContentLength};
///
/// let mut headers = Headers::new();
/// headers.set(ContentLength(1024u64));
/// ```
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ContentLength(pub u64);

//static NAME: &'static str = "Content-Length";

impl Header for ContentLength {
    #[inline]
    fn header_name() -> &'static str {
        static NAME: &'static str = "Content-Length";
        NAME
    }

    fn parse_header(raw: &Raw) -> ::Result<ContentLength> {
        // If multiple Content-Length headers were sent, everything can still
        // be alright if they all contain the same value, and all parse
        // correctly. If not, then it's an error.
        raw.iter()
            .map(parsing::from_raw_str)
            .fold(None, |prev, x| {
                match (prev, x) {
                    (None, x) => Some(x),
                    (e @ Some(Err(_)), _ ) => e,
                    (Some(Ok(prev)), Ok(x)) if prev == x => Some(Ok(prev)),
                    _ => Some(Err(::Error::Header)),
                }
            })
            .unwrap_or(Err(::Error::Header))
            .map(ContentLength)
    }

    #[inline]
    fn fmt_header(&self, f: &mut ::header::Formatter) -> fmt::Result {
        f.fmt_line(self)
    }
}

impl fmt::Display for ContentLength {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

__hyper__deref!(ContentLength => u64);

__hyper__tm!(ContentLength, tests {
    // Testcase from RFC
    test_header!(test1, vec![b"3495"], Some(HeaderField(3495)));

    test_header!(test_invalid, vec![b"34v95"], None);

    // Can't use the test_header macro because "5, 5" gets cleaned to "5".
    #[test]
    fn test_duplicates() {
        let parsed = HeaderField::parse_header(&vec![b"5".to_vec(),
                                                 b"5".to_vec()].into()).unwrap();
        assert_eq!(parsed, HeaderField(5));
        assert_eq!(format!("{}", parsed), "5");
    }

    test_header!(test_duplicates_vary, vec![b"5", b"6", b"5"], None);
});

bench_header!(bench, ContentLength, { vec![b"42349984".to_vec()] });
<commit_msg>style(header): clean up extra whitespace in ContentLength file<commit_after>use std::fmt;

use header::{Header, Raw, parsing};

/// `Content-Length` header, defined in
/// [RFC7230](http://tools.ietf.org/html/rfc7230#section-3.3.2)
///
/// When a message does not have a `Transfer-Encoding` header field, a
/// Content-Length header field can provide the anticipated size, as a
/// decimal number of octets, for a potential payload body.  For messages
/// that do include a payload body, the Content-Length field-value
/// provides the framing information necessary for determining where the
/// body (and message) ends.  For messages that do not include a payload
/// body, the Content-Length indicates the size of the selected
/// representation.
///
/// # ABNF
/// ```plain
/// Content-Length = 1*DIGIT
/// ```
///
/// # Example values
/// * `3495`
///
/// # Example
/// ```
/// use hyper::header::{Headers, ContentLength};
///
/// let mut headers = Headers::new();
/// headers.set(ContentLength(1024u64));
/// ```
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ContentLength(pub u64);

impl Header for ContentLength {
    #[inline]
    fn header_name() -> &'static str {
        static NAME: &'static str = "Content-Length";
        NAME
    }

    fn parse_header(raw: &Raw) -> ::Result<ContentLength> {
        // If multiple Content-Length headers were sent, everything can still
        // be alright if they all contain the same value, and all parse
        // correctly. If not, then it's an error.
        raw.iter()
            .map(parsing::from_raw_str)
            .fold(None, |prev, x| {
                match (prev, x) {
                    (None, x) => Some(x),
                    (e @ Some(Err(_)), _ ) => e,
                    (Some(Ok(prev)), Ok(x)) if prev == x => Some(Ok(prev)),
                    _ => Some(Err(::Error::Header)),
                }
            })
            .unwrap_or(Err(::Error::Header))
            .map(ContentLength)
    }

    #[inline]
    fn fmt_header(&self, f: &mut ::header::Formatter) -> fmt::Result {
        f.fmt_line(self)
    }
}

impl fmt::Display for ContentLength {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

__hyper__deref!(ContentLength => u64);

__hyper__tm!(ContentLength, tests {
    // Testcase from RFC
    test_header!(test1, vec![b"3495"], Some(HeaderField(3495)));

    test_header!(test_invalid, vec![b"34v95"], None);

    // Can't use the test_header macro because "5, 5" gets cleaned to "5".
    #[test]
    fn test_duplicates() {
        let parsed = HeaderField::parse_header(&vec![b"5".to_vec(),
                                                 b"5".to_vec()].into()).unwrap();
        assert_eq!(parsed, HeaderField(5));
        assert_eq!(format!("{}", parsed), "5");
    }

    test_header!(test_duplicates_vary, vec![b"5", b"6", b"5"], None);
});

bench_header!(bench, ContentLength, { vec![b"42349984".to_vec()] });
<|endoftext|>