<commit_before>//! This module implements the root command of the CLI tool.

use std::env;
use std::fmt;
use std::process;

use clap::{App, AppSettings, Arg, ArgMatches};
use failure::{bail, Error};
use log::{debug, info};

use crate::api::Api;
use crate::config::{prepare_environment, Auth, Config};
use crate::constants::{ARCH, PLATFORM, VERSION};
use crate::utils::system::{print_error, QuietExit};
use crate::utils::update::run_sentrycli_update_nagger;

const ABOUT: &str = "
Command line utility for Sentry.

This tool helps you manage remote resources on a Sentry server like
sourcemaps, debug symbols or releases.  Use `--help` on the subcommands
to learn more about them.";

macro_rules! each_subcommand {
    ($mac:ident) => {
        $mac!(upload_dif);
        $mac!(upload_dsym);
        $mac!(upload_proguard);
        $mac!(releases);
        $mac!(issues);
        $mac!(repos);
        $mac!(projects);
        $mac!(monitors);
        #[cfg(not(feature = "managed"))]
        $mac!(update);
        #[cfg(not(feature = "managed"))]
        $mac!(uninstall);
        $mac!(info);
        $mac!(login);
        $mac!(send_event);
        $mac!(react_native);
        $mac!(difutil);
        $mac!(bash_hook);

        // these here exist for legacy reasons only.  They were moved
        // to subcommands of the react-native command.  Note that
        // codepush was never available on that level.
        #[cfg(target_os = "macos")]
        $mac!(react_native_xcode);
        $mac!(react_native_gradle);
    };
}

// commands we want to run the update nagger on
const UPDATE_NAGGER_CMDS: &[&str] = &[
    "releases", "issues", "repos", "projects", "monitors", "info", "login", "difutil",
];

// it would be great if this could be a macro expansion as well
// but rust bug #37663 breaks location information then.
pub mod bash_hook;
pub mod info;
pub mod issues;
pub mod login;
pub mod monitors;
pub mod projects;
pub mod releases;
pub mod repos;
pub mod send_event;
pub mod uninstall;
pub mod update;
pub mod upload_dif;
pub mod upload_dsym;
pub mod upload_proguard;

pub mod react_native;
pub mod react_native_appcenter;
pub mod react_native_codepush;
pub mod react_native_gradle;
#[cfg(target_os = "macos")]
pub mod react_native_xcode;

pub mod difutil;
pub mod difutil_bundle_sources;
pub mod difutil_check;
pub mod difutil_find;
pub mod difutil_id;

fn preexecute_hooks() -> Result<bool, Error> {
    return sentry_react_native_xcode_wrap();

    #[cfg(target_os = "macos")]
    fn sentry_react_native_xcode_wrap() -> Result<bool, Error> {
        if let Ok(val) = env::var("__SENTRY_RN_WRAP_XCODE_CALL") {
            env::remove_var("__SENTRY_RN_WRAP_XCODE_CALL");
            if &val == "1" {
                react_native_xcode::wrap_call()?;
                return Ok(true);
            }
        }
        Ok(false)
    }

    #[cfg(not(target_os = "macos"))]
    fn sentry_react_native_xcode_wrap() -> Result<bool, Error> {
        Ok(false)
    }
}

fn configure_args(config: &mut Config, matches: &ArgMatches<'_>) -> Result<(), Error> {
    if let Some(url) = matches.value_of("url") {
        config.set_base_url(url);
    }

    if let Some(api_key) = matches.value_of("api_key") {
        config.set_auth(Auth::Key(api_key.to_owned()));
    }

    if let Some(auth_token) = matches.value_of("auth_token") {
        config.set_auth(Auth::Token(auth_token.to_owned()));
    }

    if let Some(level_str) = matches.value_of("log_level") {
        match level_str.parse() {
            Ok(level) => {
                config.set_log_level(level);
            }
            Err(_) => {
                bail!("Unknown log level: {}", level_str);
            }
        }
    }

    Ok(())
}

fn add_commands<'a, 'b>(mut app: App<'a, 'b>) -> App<'a, 'b> {
    macro_rules! add_subcommand {
        ($name:ident) => {{
            let mut cmd = $name::make_app(App::new(stringify!($name).replace("_", "-").as_str()));

            // for legacy reasons
            if stringify!($name).starts_with("react_native_") {
                cmd = cmd.setting(AppSettings::Hidden);
            }

            app = app.subcommand(cmd);
        }};
    }

    each_subcommand!(add_subcommand);
    app
}

#[allow(clippy::cognitive_complexity)]
fn run_command(matches: &ArgMatches<'_>) -> Result<(), Error> {
    macro_rules! execute_subcommand {
        ($name:ident) => {{
            let cmd = stringify!($name).replace("_", "-");
            if let Some(sub_matches) = matches.subcommand_matches(&cmd) {
                let rv = $name::execute(&sub_matches)?;
                if UPDATE_NAGGER_CMDS.iter().any(|x| x == &cmd) {
                    run_sentrycli_update_nagger();
                }
                return Ok(rv);
            }
        }};
    }

    each_subcommand!(execute_subcommand);
    unreachable!();
}

struct DebugArgs<'a>(Vec<&'a str>);

impl<'a> fmt::Display for DebugArgs<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for (idx, arg) in self.0.iter().enumerate() {
            if idx > 0 {
                write!(f, " ")?;
            }
            write!(f, "{:?}", arg)?;
        }
        Ok(())
    }
}

/// Given an argument vector and a `Config` this executes the
/// command line and returns the result.
pub fn execute(args: &[String]) -> Result<(), Error> {
    let mut config = Config::from_cli_config()?;

    // special case for the xcode integration for react native.  For more
    // information see commands/react_native_xcode.rs
    if preexecute_hooks()? {
        return Ok(());
    }

    let mut app = App::new("sentry-cli")
        .help_message("Print this help message.")
        .version(VERSION)
        .version_message("Print version information.")
        .about(ABOUT)
        .max_term_width(100)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .global_setting(AppSettings::UnifiedHelpMessage)
        .arg(Arg::with_name("url").value_name("URL").long("url").help(
            "Fully qualified URL to the Sentry server.{n}\
             [defaults to https://sentry.io/]",
        ))
        .arg(
            Arg::with_name("auth_token")
                .value_name("AUTH_TOKEN")
                .long("auth-token")
                .help("Use the given Sentry auth token."),
        )
        .arg(
            Arg::with_name("api_key")
                .value_name("API_KEY")
                .long("api-key")
                .help("The given Sentry API key."),
        )
        .arg(
            Arg::with_name("log_level")
                .value_name("LOG_LEVEL")
                .long("log-level")
                .global(true)
                .help(
                    "Set the log output verbosity.{n}\
                     [valid levels: TRACE, DEBUG, INFO, WARN, ERROR]",
                ),
        );

    app = add_commands(app);
    let matches = app.get_matches_from_safe(&args[..])?;
    configure_args(&mut config, &matches)?;

    // bind the config to the process and fetch an immutable reference to it
    config.bind_to_process();
    info!(
        "Loaded config from {}",
        Config::current().get_filename().display()
    );

    debug!(
        "sentry-cli version: {}, platform: \"{}\", architecture: \"{}\"",
        VERSION, PLATFORM, ARCH
    );

    info!(
        "sentry-cli was invoked with the following command line: {}",
        DebugArgs(args.iter().map(String::as_str).collect())
    );

    run_command(&matches)
}

fn run() -> Result<(), Error> {
    prepare_environment();
    match execute(&env::args().collect::<Vec<String>>()) {
        Ok(()) => Ok(()),
        Err(err) => {
            // if the user hit an error, it might be time to run the update
            // nagger because maybe they tried to do something only newer
            // versions support.
            debug!("error: running update nagger");
            run_sentrycli_update_nagger();
            Err(err)
        }
    }
}

fn setup() {
    use crate::utils::logging::Logger;

    crate::utils::system::init_backtrace();
    crate::utils::system::load_dotenv();

    // we use debug internally but our log handler then rejects to a lower limit.
    // This is okay for our uses but not as efficient.
    log::set_max_level(log::LevelFilter::Debug);

    // if we work with crash reporting we initialize the sentry system.  This
    // also configures the logger.
    #[cfg(feature = "with_crash_reporting")]
    {
        crate::utils::crashreporting::setup(Box::new(Logger));
    }
    #[cfg(not(feature = "with_crash_reporting"))]
    {
        static LOGGER: Logger = Logger;
        log::set_logger(&Logger);
    }
}

/// Executes the command line application and exits the process.
pub fn main() {
    setup();
    let result = run();

    let status_code = match result {
        Ok(()) => 0,
        Err(err) => {
            if let Some(&QuietExit(code)) = err.downcast_ref() {
                code
            } else {
                print_error(&err);
                #[cfg(feature = "with_crash_reporting")]
                {
                    crate::utils::crashreporting::try_report_to_sentry(&err);
                }
                1
            }
        }
    };

    // before we shut down we unbind the api to give the connection pool
    // a chance to collect.  Not doing so has shown to cause hung threads
    // on windows.
    Api::dispose_pool();
    process::exit(status_code);
}
<commit_msg>fix: Log config path only when its actually loaded (#677)<commit_after>//! This module implements the root command of the CLI tool.

use std::env;
use std::fmt;
use std::process;

use clap::{App, AppSettings, Arg, ArgMatches};
use failure::{bail, Error};
use log::{debug, info};

use crate::api::Api;
use crate::config::{prepare_environment, Auth, Config};
use crate::constants::{ARCH, PLATFORM, VERSION};
use crate::utils::system::{print_error, QuietExit};
use crate::utils::update::run_sentrycli_update_nagger;

const ABOUT: &str = "
Command line utility for Sentry.

This tool helps you manage remote resources on a Sentry server like
sourcemaps, debug symbols or releases.  Use `--help` on the subcommands
to learn more about them.";

macro_rules! each_subcommand {
    ($mac:ident) => {
        $mac!(upload_dif);
        $mac!(upload_dsym);
        $mac!(upload_proguard);
        $mac!(releases);
        $mac!(issues);
        $mac!(repos);
        $mac!(projects);
        $mac!(monitors);
        #[cfg(not(feature = "managed"))]
        $mac!(update);
        #[cfg(not(feature = "managed"))]
        $mac!(uninstall);
        $mac!(info);
        $mac!(login);
        $mac!(send_event);
        $mac!(react_native);
        $mac!(difutil);
        $mac!(bash_hook);

        // these here exist for legacy reasons only.  They were moved
        // to subcommands of the react-native command.  Note that
        // codepush was never available on that level.
        #[cfg(target_os = "macos")]
        $mac!(react_native_xcode);
        $mac!(react_native_gradle);
    };
}

// commands we want to run the update nagger on
const UPDATE_NAGGER_CMDS: &[&str] = &[
    "releases", "issues", "repos", "projects", "monitors", "info", "login", "difutil",
];

// it would be great if this could be a macro expansion as well
// but rust bug #37663 breaks location information then.
pub mod bash_hook;
pub mod info;
pub mod issues;
pub mod login;
pub mod monitors;
pub mod projects;
pub mod releases;
pub mod repos;
pub mod send_event;
pub mod uninstall;
pub mod update;
pub mod upload_dif;
pub mod upload_dsym;
pub mod upload_proguard;

pub mod react_native;
pub mod react_native_appcenter;
pub mod react_native_codepush;
pub mod react_native_gradle;
#[cfg(target_os = "macos")]
pub mod react_native_xcode;

pub mod difutil;
pub mod difutil_bundle_sources;
pub mod difutil_check;
pub mod difutil_find;
pub mod difutil_id;

fn preexecute_hooks() -> Result<bool, Error> {
    return sentry_react_native_xcode_wrap();

    #[cfg(target_os = "macos")]
    fn sentry_react_native_xcode_wrap() -> Result<bool, Error> {
        if let Ok(val) = env::var("__SENTRY_RN_WRAP_XCODE_CALL") {
            env::remove_var("__SENTRY_RN_WRAP_XCODE_CALL");
            if &val == "1" {
                react_native_xcode::wrap_call()?;
                return Ok(true);
            }
        }
        Ok(false)
    }

    #[cfg(not(target_os = "macos"))]
    fn sentry_react_native_xcode_wrap() -> Result<bool, Error> {
        Ok(false)
    }
}

fn configure_args(config: &mut Config, matches: &ArgMatches<'_>) -> Result<(), Error> {
    if let Some(url) = matches.value_of("url") {
        config.set_base_url(url);
    }

    if let Some(api_key) = matches.value_of("api_key") {
        config.set_auth(Auth::Key(api_key.to_owned()));
    }

    if let Some(auth_token) = matches.value_of("auth_token") {
        config.set_auth(Auth::Token(auth_token.to_owned()));
    }

    if let Some(level_str) = matches.value_of("log_level") {
        match level_str.parse() {
            Ok(level) => {
                config.set_log_level(level);
            }
            Err(_) => {
                bail!("Unknown log level: {}", level_str);
            }
        }
    }

    Ok(())
}

fn add_commands<'a, 'b>(mut app: App<'a, 'b>) -> App<'a, 'b> {
    macro_rules! add_subcommand {
        ($name:ident) => {{
            let mut cmd = $name::make_app(App::new(stringify!($name).replace("_", "-").as_str()));

            // for legacy reasons
            if stringify!($name).starts_with("react_native_") {
                cmd = cmd.setting(AppSettings::Hidden);
            }

            app = app.subcommand(cmd);
        }};
    }

    each_subcommand!(add_subcommand);
    app
}

#[allow(clippy::cognitive_complexity)]
fn run_command(matches: &ArgMatches<'_>) -> Result<(), Error> {
    macro_rules! execute_subcommand {
        ($name:ident) => {{
            let cmd = stringify!($name).replace("_", "-");
            if let Some(sub_matches) = matches.subcommand_matches(&cmd) {
                let rv = $name::execute(&sub_matches)?;
                if UPDATE_NAGGER_CMDS.iter().any(|x| x == &cmd) {
                    run_sentrycli_update_nagger();
                }
                return Ok(rv);
            }
        }};
    }

    each_subcommand!(execute_subcommand);
    unreachable!();
}

struct DebugArgs<'a>(Vec<&'a str>);

impl<'a> fmt::Display for DebugArgs<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for (idx, arg) in self.0.iter().enumerate() {
            if idx > 0 {
                write!(f, " ")?;
            }
            write!(f, "{:?}", arg)?;
        }
        Ok(())
    }
}

/// Given an argument vector and a `Config` this executes the
/// command line and returns the result.
pub fn execute(args: &[String]) -> Result<(), Error> {
    let mut config = Config::from_cli_config()?;

    // special case for the xcode integration for react native.  For more
    // information see commands/react_native_xcode.rs
    if preexecute_hooks()? {
        return Ok(());
    }

    let mut app = App::new("sentry-cli")
        .help_message("Print this help message.")
        .version(VERSION)
        .version_message("Print version information.")
        .about(ABOUT)
        .max_term_width(100)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .global_setting(AppSettings::UnifiedHelpMessage)
        .arg(Arg::with_name("url").value_name("URL").long("url").help(
            "Fully qualified URL to the Sentry server.{n}\
             [defaults to https://sentry.io/]",
        ))
        .arg(
            Arg::with_name("auth_token")
                .value_name("AUTH_TOKEN")
                .long("auth-token")
                .help("Use the given Sentry auth token."),
        )
        .arg(
            Arg::with_name("api_key")
                .value_name("API_KEY")
                .long("api-key")
                .help("The given Sentry API key."),
        )
        .arg(
            Arg::with_name("log_level")
                .value_name("LOG_LEVEL")
                .long("log-level")
                .global(true)
                .help(
                    "Set the log output verbosity.{n}\
                     [valid levels: TRACE, DEBUG, INFO, WARN, ERROR]",
                ),
        );

    app = add_commands(app);
    let matches = app.get_matches_from_safe(&args[..])?;
    configure_args(&mut config, &matches)?;

    // bind the config to the process and fetch an immutable reference to it
    config.bind_to_process();
    if Config::current().get_filename().exists() {
        info!(
            "Loaded config from {}",
            Config::current().get_filename().display()
        );
    }

    debug!(
        "sentry-cli version: {}, platform: \"{}\", architecture: \"{}\"",
        VERSION, PLATFORM, ARCH
    );

    info!(
        "sentry-cli was invoked with the following command line: {}",
        DebugArgs(args.iter().map(String::as_str).collect())
    );

    run_command(&matches)
}

fn run() -> Result<(), Error> {
    prepare_environment();
    match execute(&env::args().collect::<Vec<String>>()) {
        Ok(()) => Ok(()),
        Err(err) => {
            // if the user hit an error, it might be time to run the update
            // nagger because maybe they tried to do something only newer
            // versions support.
            debug!("error: running update nagger");
            run_sentrycli_update_nagger();
            Err(err)
        }
    }
}

fn setup() {
    use crate::utils::logging::Logger;

    crate::utils::system::init_backtrace();
    crate::utils::system::load_dotenv();

    // we use debug internally but our log handler then rejects to a lower limit.
    // This is okay for our uses but not as efficient.
    log::set_max_level(log::LevelFilter::Debug);

    // if we work with crash reporting we initialize the sentry system.  This
    // also configures the logger.
    #[cfg(feature = "with_crash_reporting")]
    {
        crate::utils::crashreporting::setup(Box::new(Logger));
    }
    #[cfg(not(feature = "with_crash_reporting"))]
    {
        static LOGGER: Logger = Logger;
        log::set_logger(&Logger);
    }
}

/// Executes the command line application and exits the process.
pub fn main() {
    setup();
    let result = run();

    let status_code = match result {
        Ok(()) => 0,
        Err(err) => {
            if let Some(&QuietExit(code)) = err.downcast_ref() {
                code
            } else {
                print_error(&err);
                #[cfg(feature = "with_crash_reporting")]
                {
                    crate::utils::crashreporting::try_report_to_sentry(&err);
                }
                1
            }
        }
    };

    // before we shut down we unbind the api to give the connection pool
    // a chance to collect.  Not doing so has shown to cause hung threads
    // on windows.
    Api::dispose_pool();
    process::exit(status_code);
}
<|endoftext|>


<commit_before>use std;
use base::*;
use super::{LoudsTrie, NodeID, LoudsPos, LinkID, INVALID_LINK_ID};

struct State<'a> {
    trie_: &'a LoudsTrie,
    node_id_: NodeID,
    louds_pos_: LoudsPos,
    link_id_: LinkID,
    key_pos_: u32,
    //key_id_: u32,
}

impl<'a> std::fmt::Debug for State<'a> {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("State")
            .field("node_id_", &self.node_id_)
            .field("louds_pos_", &self.louds_pos_)
            .field("link_id_", &self.link_id_)
            .field("key_pos_", &self.key_pos_)
            .finish()
    }
}

impl<'a> State<'a> {
    fn new(trie: &'a LoudsTrie, node_id: NodeID, louds_pos: LoudsPos,
           link_id: LinkID, key_pos: u32) -> State<'a> {
        State { trie_: trie, node_id_: node_id, louds_pos_: louds_pos,
                link_id_: link_id, key_pos_: key_pos }
    }
}

#[derive(Debug)]
pub struct Nav<'a> {
    history_: Vec<State<'a> >,
    key_buf_: Vec<u8>,
}

// For lookups, marisa does caching based on the input character.
// We can't do that here. May want to remove or rethink the cache
// implementation in light of this.

impl<'a> Nav<'a> {
    fn new(trie: &'a LoudsTrie) -> Nav<'a> {
        let mut out = Nav { history_: Vec::new(), key_buf_: Vec::new() };
        out.history_.push(State::new(trie, NodeID(0), LoudsPos(0),
                          INVALID_LINK_ID, 0));
        out
    }

    fn get_link_id(&self) -> LinkID {
        self.history_.last().unwrap().link_id_
    }

    fn push_str<'b>(&mut self, key: &'b[u8], trie: &'a LoudsTrie, node_id: NodeID,
                    louds_pos: LoudsPos, link_id: LinkID) {

        debug!("push_str(key: {:?})", key);

//        debug!("push_str(key: {:#?}, node_id: {:#?}, louds_pos: {:#?}, \
//                link_id: {:#?}", key, node_id, louds_pos, link_id);

        let old_len = self.key_buf_.len();
        self.key_buf_.extend(key);
        assert!(old_len <= std::u32::MAX as usize);
        self.history_.push(State::new(trie, node_id, louds_pos, link_id,
                                      old_len as u32));
    }

    fn push(&mut self, mut node_id: NodeID, louds_pos: LoudsPos) {
//        debug!("push");
        let mut trie = self.history_.last().unwrap().trie_;
        loop {
            if trie.link_flags_.at(node_id.0 as usize) {
                debug!("Link flags TRUE");
                let (linked_node_id, link_id) = trie.get_linked_ids(node_id.0
                                                                    as usize);
                // Proceed either to next trie or tail
                match &trie.next_trie_ {
                    &Some(ref next_trie) => {
                        panic!();
                        trie = &**next_trie;
                        node_id = linked_node_id; // not sure about this
                        continue;
                    },
                    &None => {
                        // FIXME: Shouldn't need this temporary vector.
                        //        'restore' should return an iterator, and
                        //        state.push should consume it.
                        let mut v = Vec::new();
                        trie.tail_.restore(linked_node_id.0 as usize, &mut v);

                        // Not sure if these values are correct/useful.
                        // If some stuff is only needed for some nodes...
                        // should reflect that in the types we use
                        self.push_str(&v, trie, node_id, louds_pos, link_id);
                    }
                }
            } else {
                debug!("Link flags FALSE");
                let node_char = [ trie.bases_[node_id.0 as usize] ];
                self.push_str(&node_char, trie, node_id, louds_pos,
                              INVALID_LINK_ID);
            }
            break;
        }
    }
    pub fn has_child(&self) -> bool {
        self.history_.last().map(|s| s.trie_.has_child(s.node_id_))
            .unwrap_or(false)
    }
    pub fn go_to_child(&mut self) -> bool {
        debug!("go_to_child");
        if let Some((node_id, louds_pos)) =
            self.history_.last()
            .and_then(|s| { s.trie_.child_pos(s.node_id_) })
        {
//            debug!("(node_id: {:#?} louds_pos: {:#?})", node_id, louds_pos);
            self.push(node_id, louds_pos);
            true
        }
        else {
            false
        }
    }
    pub fn has_prev_sibling(&self) -> bool {
        // FIXME: Is this all...?
        self.history_.last().map(|h| {
            h.trie_.louds_.at(h.louds_pos_.0 as usize - 1)
        }).unwrap_or(false)
    }
    pub fn go_to_prev_sibling(&mut self) -> bool {
        // pop history and string
        // decrease louds_pos and node_id by 1 if we have a sibling
        // get string (factor this out?)
        // push new history & string

        panic!("not implemented")
    }
    pub fn has_sibling(&self) -> bool {
        self.history_.last().map(|h| {
            h.trie_.louds_.at(h.louds_pos_.0 as usize + 1)
        }).unwrap_or(false)
    }
    pub fn go_to_sibling(&mut self) -> bool {
        debug!("go_to_sibling");
        //if self.history_.len() < 2 {
        //    return false;
        //}
        if let Some(s) = self.history_.pop() {
            let cur_len = self.key_buf_.len();
            debug!("s.key_pos_: {:?}, cur_len: {:?}", s.key_pos_, cur_len);
            assert!((s.key_pos_ as usize) <= cur_len);
            self.key_buf_.truncate(s.key_pos_ as usize);
            if s.trie_.louds_.at(s.louds_pos_.0 as usize + 1) {
                // FIXME: What about LinkID?
                self.push(NodeID(s.node_id_.0 + 1),
                          LoudsPos(s.louds_pos_.0 + 1));
                true
            } else {
                false
            }
        } else {
            false
        }
    }
    pub fn has_parent(&self) -> bool {
        panic!("not implemented")
    }
    pub fn go_to_parent(&mut self) -> bool {
        debug!("go_to_parent");
        // Could use LOUDS-trie select1(rank0(m)) to navigate upward (within a
        // single trie), but it's probably more efficient just to keep a stack
        // and pop to go up

        //if self.history_.len() == 1 {
        //    self.history_.pop();
        //    return false;
        //}

        if let Some(s) = self.history_.pop() {
            let cur_len = self.key_buf_.len();
            assert!((s.key_pos_ as usize) <= cur_len);
            self.key_buf_.truncate(s.key_pos_ as usize);
            true
        } else {
            false
        }
    }
    pub fn is_leaf(&self) -> bool {
        //debug!("is_leaf");
        self.history_.last().map(|s|
            s.trie_.terminal_flags_.at(s.node_id_.0 as usize)
        ).unwrap_or(false)
    }
    //pub fn get_string(&self) -> &str {
    //    panic!("not implemented")
    //}
    pub fn get_u8(&self) -> &[u8] {
        &self.key_buf_[..]
    }
    pub fn is_end(&self) -> bool {
        panic!("not implemented")
    }
}

#[derive(Copy, Clone, Debug)]
enum DFT {
    ToChild,
    ToSibling,
    ToParentSibling,
    End
}

impl DFT {
    fn new() -> DFT {
        DFT::ToChild
    }
    fn depth_first_traversal_step<'a>(&mut self, nav: &mut Nav<'a>) -> bool {

        match *self {
            DFT::ToChild => {
                if nav.go_to_child() {
//                    debug!("{:#?}, {:#?}", *self, *nav);
                    //if nav.history_.len() == 3 { panic!() }

                    return true;
                } else {
                    *self = DFT::ToSibling;
                    return false;
                }
            },
            DFT::ToSibling => {
                if nav.go_to_sibling() {
                    *self = DFT::ToChild;
                    return true;
                } else {
                    *self = DFT::ToParentSibling;
                    return false;
                }
            },
            DFT::ToParentSibling => {
                if !nav.go_to_parent() {
                    *self = DFT::End;
                    return false;
                }
                if nav.go_to_sibling() {
                    *self = DFT::ToChild;
                    return true;
                }
                return false;
            },
            DFT::End => {
                return false;
            }
        }
    }
    fn next_terminal<'a, 'b>(&mut self, nav: &'b mut Nav<'a>)
      -> Option<&'b[u8]> {
        loop {
            match *self {
                DFT::End => { return None; },
                _ => (),
            }
            if self.depth_first_traversal_step(nav) && nav.is_leaf() {
                return Some(nav.get_u8());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use env_logger;
    use std::cmp::Ordering;
    use quickcheck as qc;
    use config::{Config, NumTries};
    use key::Key;
    use super::{DFT, Nav};
    use super::super::LoudsTrie;

    fn nav_restore_prop(v: Vec<String>, num_tries: NumTries)
      -> qc::TestResult {
        debug!("in: {:?}", v);
        let mut vu: Vec<Vec<u8>> = Vec::new();
        for s in v.iter() {
            vu.push(From::from(s.as_bytes()));
        }
        debug!("u8: {:?}", vu);

        if v.iter().any(|x| x.is_empty()) {
            debug!("");
            return qc::TestResult::discard();
        }
        let mut keys: Vec<Key> = v.iter().map(|s| Key::new(s.as_bytes()))
                                 .collect();
        let config = Config::new().with_num_tries(num_tries);
        let trie = LoudsTrie::build(&mut keys, &config);

        let mut nav = Nav::new(&trie);
        let mut dft = DFT::new();

        let mut vv1: Vec<Vec<u8>> = v.iter().map(|s| From::from(s.as_bytes()))
                                    .collect();

        let mut vv2: Vec<Vec<u8>> = Vec::new();
        while let Some(s) = dft.next_terminal(&mut nav) {
            vv2.push(From::from(s));
        }

        vv1.sort();
        vv2.sort();
        debug!("vv1: {:?}", vv1);
        debug!("vv2: {:?}", vv2);

        let b = vv1.cmp(&vv2) == Ordering::Equal;
        debug!("equal: {:?}", b);
        debug!("");
        qc::TestResult::from_bool(b)
    }

    fn nav_restore_prop_1(v: Vec<String>) -> qc::TestResult {
        nav_restore_prop(v, NumTries::new(1))
    }

    #[test]
    fn nav_restore_qc() {
        let _ = env_logger::init();
        qc::quickcheck(nav_restore_prop as fn(Vec<String>, NumTries)
                       -> qc::TestResult);
    }

    #[test]
    fn nav_restore_qc_1() {
        let _ = env_logger::init();
        qc::quickcheck(nav_restore_prop_1 as fn(Vec<String>)
                       -> qc::TestResult);
    }

    fn assert_passed(tr: qc::TestResult) {
        assert!(!tr.is_failure());
    }

    #[test]
    fn nav_restore_manual() {
        let _ = env_logger::init();
        //assert_passed(nav_restore_prop_1(vec!["a".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["ab".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["\u{194}\u{128}".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["Testing".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["\u{80}".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["\u{7f}".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["~".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["\u{0}".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["Testing".to_owned(),
        //                                      "T".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["Testing".to_owned(),
        //                                      "Test".to_owned()]));
        assert_passed(nav_restore_prop_1(vec![
                                              "Threep".to_owned(),
                                              "Test".to_owned()]));
        assert_passed(nav_restore_prop_1(vec!["trouble".to_owned(),
                                              "Threep".to_owned(),
                                              "Test".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["Testing".to_owned(),
        //                                      "trouble".to_owned(),
        //                                      "Trouble".to_owned(),
        //                                      "Threep".to_owned(),
        //                                      "Test".to_owned()]));
    }
}

<commit_msg>fix current manual test case<commit_after>use std;
use base::*;
use super::{LoudsTrie, NodeID, LoudsPos, LinkID, INVALID_LINK_ID};

#[derive(Copy, Clone)]
struct State<'a> {
    trie_: &'a LoudsTrie,
    node_id_: NodeID,
    louds_pos_: LoudsPos,
    link_id_: LinkID,
    key_pos_: u32,
    //key_id_: u32,
}

impl<'a> std::fmt::Debug for State<'a> {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("State")
            .field("node_id_", &self.node_id_)
            .field("louds_pos_", &self.louds_pos_)
            .field("link_id_", &self.link_id_)
            .field("key_pos_", &self.key_pos_)
            .finish()
    }
}

impl<'a> State<'a> {
    fn new(trie: &'a LoudsTrie, node_id: NodeID, louds_pos: LoudsPos,
           link_id: LinkID, key_pos: u32) -> State<'a> {
        State { trie_: trie, node_id_: node_id, louds_pos_: louds_pos,
                link_id_: link_id, key_pos_: key_pos }
    }
}

#[derive(Debug)]
pub struct Nav<'a> {
    history_: Vec<State<'a> >,
    key_buf_: Vec<u8>,
}

// For lookups, marisa does caching based on the input character.
// We can't do that here. May want to remove or rethink the cache
// implementation in light of this.

impl<'a> Nav<'a> {
    fn new(trie: &'a LoudsTrie) -> Nav<'a> {
        let mut out = Nav { history_: Vec::new(), key_buf_: Vec::new() };
        out.history_.push(State::new(trie, NodeID(0), LoudsPos(0),
                          INVALID_LINK_ID, 0));
        out
    }

    fn get_link_id(&self) -> LinkID {
        self.history_.last().unwrap().link_id_
    }

    fn push_str<'b>(&mut self, key: &'b[u8], trie: &'a LoudsTrie, node_id: NodeID,
                    louds_pos: LoudsPos, link_id: LinkID) {

        debug!("push_str(key: {:?})", key);

//        debug!("push_str(key: {:#?}, node_id: {:#?}, louds_pos: {:#?}, \
//                link_id: {:#?}", key, node_id, louds_pos, link_id);

        let old_len = self.key_buf_.len();
        self.key_buf_.extend(key);
        assert!(old_len <= std::u32::MAX as usize);
        self.history_.push(State::new(trie, node_id, louds_pos, link_id,
                                      old_len as u32));
    }

    fn push(&mut self, mut node_id: NodeID, louds_pos: LoudsPos) {
//        debug!("push");
        let mut trie = self.history_.last().unwrap().trie_;
        loop {
            if trie.link_flags_.at(node_id.0 as usize) {
                debug!("Link flags TRUE");
                let (linked_node_id, link_id) = trie.get_linked_ids(node_id.0
                                                                    as usize);
                // Proceed either to next trie or tail
                match &trie.next_trie_ {
                    &Some(ref next_trie) => {
                        panic!();
                        trie = &**next_trie;
                        node_id = linked_node_id; // not sure about this
                        continue;
                    },
                    &None => {
                        // FIXME: Shouldn't need this temporary vector.
                        //        'restore' should return an iterator, and
                        //        state.push should consume it.
                        let mut v = Vec::new();
                        trie.tail_.restore(linked_node_id.0 as usize, &mut v);

                        // Not sure if these values are correct/useful.
                        // If some stuff is only needed for some nodes...
                        // should reflect that in the types we use
                        self.push_str(&v, trie, node_id, louds_pos, link_id);
                    }
                }
            } else {
                debug!("Link flags FALSE");
                let node_char = [ trie.bases_[node_id.0 as usize] ];
                self.push_str(&node_char, trie, node_id, louds_pos,
                              INVALID_LINK_ID);
            }
            break;
        }
    }
    pub fn has_child(&self) -> bool {
        self.history_.last().map(|s| s.trie_.has_child(s.node_id_))
            .unwrap_or(false)
    }
    pub fn go_to_child(&mut self) -> bool {
        debug!("go_to_child");
        if let Some((node_id, louds_pos)) =
            self.history_.last()
            .and_then(|s| { s.trie_.child_pos(s.node_id_) })
        {
            debug!("  (node_id: {:?} louds_pos: {:?})", node_id.0, louds_pos.0);
            self.push(node_id, louds_pos);
            true
        }
        else {
            debug!("  no child");
            false
        }
    }
    pub fn has_prev_sibling(&self) -> bool {
        // FIXME: Is this all...?
        self.history_.last().map(|h| {
            h.trie_.louds_.at(h.louds_pos_.0 as usize - 1)
        }).unwrap_or(false)
    }
    pub fn go_to_prev_sibling(&mut self) -> bool {
        // pop history and string
        // decrease louds_pos and node_id by 1 if we have a sibling
        // get string (factor this out?)
        // push new history & string

        panic!("not implemented")
    }
    pub fn has_sibling(&self) -> bool {
        self.history_.last().map(|h| {
            h.trie_.louds_.at(h.louds_pos_.0 as usize + 1)
        }).unwrap_or(false)
    }
    pub fn go_to_sibling(&mut self) -> bool {
        debug!("go_to_sibling");
        //if self.history_.len() < 2 {
        //    return false;
        //}
        if let Some(&s) = self.history_.last() {
            //debug!("louds_pos: {:?}", s.louds_pos_.0);
            //debug!("louds_pos + 1: {:?}", s.louds_pos_.0 + 1);

            let cur_len = self.key_buf_.len();
            debug!("s.key_pos_: {:?}, cur_len: {:?}", s.key_pos_, cur_len);
            assert!((s.key_pos_ as usize) <= cur_len);
            self.key_buf_.truncate(s.key_pos_ as usize);
            if s.trie_.louds_.at(s.louds_pos_.0 as usize + 1) {
                debug!("  (node_id: {:?} louds_pos: {:?})",
                       s.node_id_.0 + 1, s.louds_pos_.0 + 1);
                self.history_.pop();
                // FIXME: What about LinkID?
                self.push(NodeID(s.node_id_.0 + 1),
                          LoudsPos(s.louds_pos_.0 + 1));
                true
            } else {
                debug!("  no sibling");
                false
            }
        } else {
            false
        }
    }
    pub fn has_parent(&self) -> bool {
        panic!("not implemented")
    }
    pub fn go_to_parent(&mut self) -> bool {
        debug!("go_to_parent");
        // Could use LOUDS-trie select1(rank0(m)) to navigate upward (within a
        // single trie), but it's probably more efficient just to keep a stack
        // and pop to go up

        //if self.history_.len() == 1 {
        //    self.history_.pop();
        //    return false;
        //}

        if let Some(s) = self.history_.pop() {
            let cur_len = self.key_buf_.len();
            assert!((s.key_pos_ as usize) <= cur_len);
            self.key_buf_.truncate(s.key_pos_ as usize);
            if let Some(s) = self.history_.last() {
                let node_id = s.node_id_;
                let louds_pos = s.louds_pos_;
                debug!("  (node_id: {:?} louds_pos: {:?})", node_id, louds_pos);
            }
            true
        } else {
            false
        }
    }
    pub fn is_leaf(&self) -> bool {
        //debug!("is_leaf");
        self.history_.last().map(|s|
            s.trie_.terminal_flags_.at(s.node_id_.0 as usize)
        ).unwrap_or(false)
    }
    //pub fn get_string(&self) -> &str {
    //    panic!("not implemented")
    //}
    pub fn get_u8(&self) -> &[u8] {
        &self.key_buf_[..]
    }
    pub fn is_end(&self) -> bool {
        panic!("not implemented")
    }
}

#[derive(Copy, Clone, Debug)]
enum DFT {
    ToChild,
    ToSibling,
    ToParentSibling,
    End
}

impl DFT {
    fn new() -> DFT {
        DFT::ToChild
    }
    fn depth_first_traversal_step<'a>(&mut self, nav: &mut Nav<'a>) -> bool {

        match *self {
            DFT::ToChild => {
                if nav.go_to_child() {
//                    debug!("{:#?}, {:#?}", *self, *nav);
                    //if nav.history_.len() == 3 { panic!() }

                    return true;
                } else {
                    *self = DFT::ToSibling;
                    return false;
                }
            },
            DFT::ToSibling => {
                if nav.go_to_sibling() {
                    *self = DFT::ToChild;
                    return true;
                } else {
                    *self = DFT::ToParentSibling;
                    return false;
                }
            },
            DFT::ToParentSibling => {
                if !nav.go_to_parent() {
                    *self = DFT::End;
                    return false;
                }
                if nav.go_to_sibling() {
                    *self = DFT::ToChild;
                    return true;
                }
                return false;
            },
            DFT::End => {
                return false;
            }
        }
    }
    fn next_terminal<'a, 'b>(&mut self, nav: &'b mut Nav<'a>)
      -> Option<&'b[u8]> {
        loop {
            match *self {
                DFT::End => { return None; },
                _ => (),
            }
            if self.depth_first_traversal_step(nav) && nav.is_leaf() {
                return Some(nav.get_u8());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use env_logger;
    use std::cmp::Ordering;
    use quickcheck as qc;
    use config::{Config, NumTries};
    use key::Key;
    use super::{DFT, Nav};
    use super::super::LoudsTrie;

    fn nav_restore_prop(v: Vec<String>, num_tries: NumTries)
      -> qc::TestResult {
        debug!("in: {:?}", v);
        let mut vu: Vec<Vec<u8>> = Vec::new();
        for s in v.iter() {
            vu.push(From::from(s.as_bytes()));
        }
        debug!("u8: {:?}", vu);

        if v.iter().any(|x| x.is_empty()) {
            debug!("");
            return qc::TestResult::discard();
        }
        let mut keys: Vec<Key> = v.iter().map(|s| Key::new(s.as_bytes()))
                                 .collect();
        let config = Config::new().with_num_tries(num_tries);
        let trie = LoudsTrie::build(&mut keys, &config);
        //debug!("trie: {:#?}", trie);

        let mut nav = Nav::new(&trie);
        let mut dft = DFT::new();

        let mut vv1: Vec<Vec<u8>> = v.iter().map(|s| From::from(s.as_bytes()))
                                    .collect();

        let mut vv2: Vec<Vec<u8>> = Vec::new();
        while let Some(s) = dft.next_terminal(&mut nav) {
            vv2.push(From::from(s));
        }

        vv1.sort();
        vv2.sort();
        debug!("vv1: {:?}", vv1);
        debug!("vv2: {:?}", vv2);

        let b = vv1.cmp(&vv2) == Ordering::Equal;
        debug!("equal: {:?}", b);
        debug!("");
        qc::TestResult::from_bool(b)
    }

    fn nav_restore_prop_1(v: Vec<String>) -> qc::TestResult {
        nav_restore_prop(v, NumTries::new(1))
    }

    #[test]
    fn nav_restore_qc() {
        let _ = env_logger::init();
        qc::quickcheck(nav_restore_prop as fn(Vec<String>, NumTries)
                       -> qc::TestResult);
    }

    #[test]
    fn nav_restore_qc_1() {
        let _ = env_logger::init();
        qc::quickcheck(nav_restore_prop_1 as fn(Vec<String>)
                       -> qc::TestResult);
    }

    fn assert_passed(tr: qc::TestResult) {
        assert!(!tr.is_failure());
    }

    #[test]
    fn nav_restore_manual() {
        let _ = env_logger::init();
        //assert_passed(nav_restore_prop_1(vec!["a".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["ab".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["\u{194}\u{128}".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["Testing".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["\u{80}".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["\u{7f}".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["~".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["\u{0}".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["Testing".to_owned(),
        //                                      "T".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["Testing".to_owned(),
        //                                      "Test".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["trouble".to_owned(),
        //                                      "Threep".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["Threep".to_owned(),
        //                                      "Test".to_owned()]));
        assert_passed(nav_restore_prop_1(vec!["trouble".to_owned(),
                                              "Threep".to_owned(),
                                              "Test".to_owned()]));
        //assert_passed(nav_restore_prop_1(vec!["Testing".to_owned(),
        //                                      "trouble".to_owned(),
        //                                      "Trouble".to_owned(),
        //                                      "Threep".to_owned(),
        //                                      "Test".to_owned()]));
    }
}

<|endoftext|>


<commit_before>/// Overrides for https://docs.rs/log/#macros
///
/// Source shared by `derive_builder_core` and `derive_builder` via symlink.

macro_rules! log_enabled {
    ($( $x:tt )*) => { false }
}

// delegate to format_args and throw away the result to avoid `unused variable`
// lints.
// The compiler should be able to optimize this away.
macro_rules! debug {
    ($( $x:tt )*) => { format_args!($( $x )*); }
}

macro_rules! error {
    ($( $x:tt )*) => { format_args!($( $x )*); }
}

macro_rules! info {
    ($( $x:tt )*) => { format_args!($( $x )*); }
}

macro_rules! log {
    ($( $x:tt )*) => { format_args!($( $x )*); }
}

macro_rules! trace {
    ($( $x:tt )*) => { format_args!($( $x )*); }
}

macro_rules! warn {
    ($( $x:tt )*) => { format_args!($( $x )*); }
}
<commit_msg>fix unused macro test regression<commit_after>/// Overrides for https://docs.rs/log/#macros
///
/// Source shared by `derive_builder_core` and `derive_builder` via symlink.

#[allow(unknown_lints, unused_macros)]
macro_rules! log_enabled {
    ($( $x:tt )*) => { false }
}

// delegate to format_args and throw away the result to avoid `unused variable`
// lints.
// The compiler should be able to optimize this away.
#[allow(unknown_lints, unused_macros)]
macro_rules! debug {
    ($( $x:tt )*) => { format_args!($( $x )*); }
}

#[allow(unknown_lints, unused_macros)]
macro_rules! error {
    ($( $x:tt )*) => { format_args!($( $x )*); }
}

#[allow(unknown_lints, unused_macros)]
macro_rules! info {
    ($( $x:tt )*) => { format_args!($( $x )*); }
}

#[allow(unknown_lints, unused_macros)]
macro_rules! log {
    ($( $x:tt )*) => { format_args!($( $x )*); }
}

#[allow(unknown_lints, unused_macros)]
macro_rules! trace {
    ($( $x:tt )*) => { format_args!($( $x )*); }
}

#[allow(unknown_lints, unused_macros)]
macro_rules! warn {
    ($( $x:tt )*) => { format_args!($( $x )*); }
}
<|endoftext|>


<commit_before>use super::Matcher;
use regex::Regex;

pub struct MatchesRegex<'a>(pub &'a str);

impl<'a> Matcher<&'a str> for MatchesRegex<'a> {
    fn matches(&self, lhs: &&'a str) -> bool {
        match Regex::new(self.0) {
            Ok(re) => re.is_match(lhs),
            Err(_) => false
        }
    }

    fn fail_msg(&self, lhs: &&'a str) -> String {
        format!("expected {:?} to match {:?}", lhs, self.0)
    }

    fn negated_fail_msg(&self, lhs: &&'a str) -> String {
        format!("expected {:?} not to match {:?}", lhs, self.0)
    }
}

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

    #[test]
    fn test_match_regex_matches() {
        expect("Hello").to(match_regex(r"..ll."))
    }

    #[test]
    #[should_panic(expected="expected \"Hello\" to match \".\\\\o/.\"")]
    fn test_match_regex_fails_with_message() {
        expect("Hello").to(match_regex(".\\o/."))
    }

    #[test]
    #[should_panic(expected="expected \"-\\\\o/-\" not to match \".....\"")]
    fn test_negated_match_regex_fails_with_message() {
        expect("-\\o/-").to_not(match_regex("....."))
    }
}
<commit_msg>Add regex matcher for String<commit_after>use super::Matcher;
use regex::Regex;

pub struct MatchesRegex<'a>(pub &'a str);

impl<'a> Matcher<&'a str> for MatchesRegex<'a> {
    fn matches(&self, lhs: &&'a str) -> bool {
        match Regex::new(self.0) {
            Ok(re) => re.is_match(lhs),
            Err(_) => false
        }
    }

    fn fail_msg(&self, lhs: &&'a str) -> String {
        format!("expected {:?} to match {:?}", lhs, self.0)
    }

    fn negated_fail_msg(&self, lhs: &&'a str) -> String {
        format!("expected {:?} not to match {:?}", lhs, self.0)
    }
}

impl<'a> Matcher<String> for MatchesRegex<'a> {
    fn matches(&self, lhs: &String) -> bool {
        match Regex::new(self.0) {
            Ok(re) => re.is_match(&*lhs),
            Err(_) => false
        }
    }

    fn fail_msg(&self, lhs: &String) -> String {
        format!("expected {:?} to match {:?}", lhs, self.0)
    }

    fn negated_fail_msg(&self, lhs: &String) -> String {
        format!("expected {:?} not to match {:?}", lhs, self.0)
    }
}

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

        #[test]
        fn test_match_regex_matches() {
            expect("Hello").to(match_regex(r"..ll."))
        }

        #[test]
        #[should_panic(expected="expected \"Hello\" to match \".\\\\o/.\"")]
        fn test_match_regex_fails_with_message() {
            expect("Hello").to(match_regex(".\\o/."))
        }

        #[test]
        #[should_panic(expected="expected \"-\\\\o/-\" not to match \".....\"")]
        fn test_negated_match_regex_fails_with_message() {
            expect("-\\o/-").to_not(match_regex("....."))
        }
    }

    mod string_match_regex {
        use super::super::super::super::dsl::*;

        #[test]
        fn test_match_regex_matches() {
            expect("Hello".to_string()).to(match_regex(r"..ll."))
        }

        #[test]
        #[should_panic(expected="expected \"Hello\" to match \".\\\\o/.\"")]
        fn test_match_regex_fails_with_message() {
            expect("Hello".to_string()).to(match_regex(".\\o/."))
        }

        #[test]
        #[should_panic(expected="expected \"-\\\\o/-\" not to match \".....\"")]
        fn test_negated_match_regex_fails_with_message() {
            expect("-\\o/-".to_string()).to_not(match_regex("....."))
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// 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.

use core::{fmt, str};
use parser;
use prelude::*;

impl fmt::Debug for Uuid {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::Display for Uuid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::Display for Variant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Variant::NCS => write!(f, "NCS"),
            Variant::RFC4122 => write!(f, "RFC4122"),
            Variant::Microsoft => write!(f, "Microsoft"),
            Variant::Future => write!(f, "Future"),
        }
    }
}

impl fmt::Display for ::BytesError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "invalid bytes length: expected {}, found {}",
            self.expected(),
            self.found()
        )
    }
}

impl fmt::LowerHex for Uuid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(&self.to_hyphenated_ref(), f)
    }
}

impl fmt::UpperHex for Uuid {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::UpperHex::fmt(&self.to_hyphenated_ref(), f)
    }
}

impl str::FromStr for Uuid {
    type Err = parser::ParseError;

    fn from_str(uuid_str: &str) -> Result<Self, Self::Err> {
        Uuid::parse_str(uuid_str)
    }
}

impl Default for Uuid {
    #[inline]
    fn default() -> Self {
        Uuid::nil()
    }
}

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

    use self::std::prelude::v1::*;
    use prelude::*;
    use test_util;

    macro_rules! check {
        ($buf:ident, $format:expr, $target:expr, $len:expr, $cond:expr) => {
            $buf.clear();
            write!($buf, $format, $target).unwrap();
            assert!($buf.len() == $len);
            assert!($buf.chars().all($cond), "{}", $buf);
        };
    }

    #[test]
    fn test_uuid_compare() {
        let uuid1 = test_util::new();
        let uuid2 = test_util::new2();

        assert_eq!(uuid1, uuid1);
        assert_eq!(uuid2, uuid2);

        assert_ne!(uuid1, uuid2);
        assert_ne!(uuid2, uuid1);
    }

    #[test]
    fn test_uuid_default() {
        let default_uuid = Uuid::default();
        let nil_uuid = Uuid::nil();

        assert_eq!(default_uuid, nil_uuid);
    }

    #[test]
    fn test_uuid_display() {
        use super::fmt::Write;

        let uuid = test_util::new();
        let s = uuid.to_string();
        let mut buffer = String::new();

        assert_eq!(s, uuid.to_hyphenated().to_string());

        check!(buffer, "{}", uuid, 36, |c| c.is_lowercase()
            || c.is_digit(10)
            || c == '-');
    }

    #[test]
    fn test_uuid_lowerhex() {
        use super::fmt::Write;

        let mut buffer = String::new();
        let uuid = test_util::new();

        check!(buffer, "{:x}", uuid, 36, |c| c.is_lowercase()
            || c.is_digit(10)
            || c == '-');
    }

    // noinspection RsAssertEqual
    #[test]
    fn test_uuid_operator_eq() {
        let uuid1 = test_util::new();
        let uuid1_dup = uuid1.clone();
        let uuid2 = test_util::new2();

        assert!(uuid1 == uuid1);
        assert!(uuid1 == uuid1_dup);
        assert!(uuid1_dup == uuid1);

        assert!(uuid1 != uuid2);
        assert!(uuid2 != uuid1);
        assert!(uuid1_dup != uuid2);
        assert!(uuid2 != uuid1_dup);
    }

    #[test]
    fn test_uuid_to_string() {
        use super::fmt::Write;

        let uuid = test_util::new();
        let s = uuid.to_string();
        let mut buffer = String::new();

        assert_eq!(s.len(), 36);

        check!(buffer, "{}", s, 36, |c| c.is_lowercase()
            || c.is_digit(10)
            || c == '-');
    }

    #[test]
    fn test_uuid_upperhex() {
        use super::fmt::Write;

        let mut buffer = String::new();
        let uuid = test_util::new();

        check!(buffer, "{:X}", uuid, 36, |c| c.is_uppercase()
            || c.is_digit(10)
            || c == '-');
    }
}
<commit_msg>implement Display for uuid::Error<commit_after>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// 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.

use core::{fmt, str};
use parser;
use prelude::*;

impl fmt::Debug for Uuid {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::Display for super::Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            super::Error::Bytes(err) => fmt::Display::fmt(&err, self.fmt),
            super::Error::Parse(err) => fmt::Display::fmt(&err, self.fmt),
        }
    }
}

impl fmt::Display for Uuid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::Display for Variant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Variant::NCS => write!(f, "NCS"),
            Variant::RFC4122 => write!(f, "RFC4122"),
            Variant::Microsoft => write!(f, "Microsoft"),
            Variant::Future => write!(f, "Future"),
        }
    }
}

impl fmt::Display for ::BytesError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "invalid bytes length: expected {}, found {}",
            self.expected(),
            self.found()
        )
    }
}

impl fmt::LowerHex for Uuid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(&self.to_hyphenated_ref(), f)
    }
}

impl fmt::UpperHex for Uuid {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::UpperHex::fmt(&self.to_hyphenated_ref(), f)
    }
}

impl str::FromStr for Uuid {
    type Err = parser::ParseError;

    fn from_str(uuid_str: &str) -> Result<Self, Self::Err> {
        Uuid::parse_str(uuid_str)
    }
}

impl Default for Uuid {
    #[inline]
    fn default() -> Self {
        Uuid::nil()
    }
}

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

    use self::std::prelude::v1::*;
    use prelude::*;
    use test_util;

    macro_rules! check {
        ($buf:ident, $format:expr, $target:expr, $len:expr, $cond:expr) => {
            $buf.clear();
            write!($buf, $format, $target).unwrap();
            assert!($buf.len() == $len);
            assert!($buf.chars().all($cond), "{}", $buf);
        };
    }

    #[test]
    fn test_uuid_compare() {
        let uuid1 = test_util::new();
        let uuid2 = test_util::new2();

        assert_eq!(uuid1, uuid1);
        assert_eq!(uuid2, uuid2);

        assert_ne!(uuid1, uuid2);
        assert_ne!(uuid2, uuid1);
    }

    #[test]
    fn test_uuid_default() {
        let default_uuid = Uuid::default();
        let nil_uuid = Uuid::nil();

        assert_eq!(default_uuid, nil_uuid);
    }

    #[test]
    fn test_uuid_display() {
        use super::fmt::Write;

        let uuid = test_util::new();
        let s = uuid.to_string();
        let mut buffer = String::new();

        assert_eq!(s, uuid.to_hyphenated().to_string());

        check!(buffer, "{}", uuid, 36, |c| c.is_lowercase()
            || c.is_digit(10)
            || c == '-');
    }

    #[test]
    fn test_uuid_lowerhex() {
        use super::fmt::Write;

        let mut buffer = String::new();
        let uuid = test_util::new();

        check!(buffer, "{:x}", uuid, 36, |c| c.is_lowercase()
            || c.is_digit(10)
            || c == '-');
    }

    // noinspection RsAssertEqual
    #[test]
    fn test_uuid_operator_eq() {
        let uuid1 = test_util::new();
        let uuid1_dup = uuid1.clone();
        let uuid2 = test_util::new2();

        assert!(uuid1 == uuid1);
        assert!(uuid1 == uuid1_dup);
        assert!(uuid1_dup == uuid1);

        assert!(uuid1 != uuid2);
        assert!(uuid2 != uuid1);
        assert!(uuid1_dup != uuid2);
        assert!(uuid2 != uuid1_dup);
    }

    #[test]
    fn test_uuid_to_string() {
        use super::fmt::Write;

        let uuid = test_util::new();
        let s = uuid.to_string();
        let mut buffer = String::new();

        assert_eq!(s.len(), 36);

        check!(buffer, "{}", s, 36, |c| c.is_lowercase()
            || c.is_digit(10)
            || c == '-');
    }

    #[test]
    fn test_uuid_upperhex() {
        use super::fmt::Write;

        let mut buffer = String::new();
        let uuid = test_util::new();

        check!(buffer, "{:X}", uuid, 36, |c| c.is_uppercase()
            || c.is_digit(10)
            || c == '-');
    }
}
<|endoftext|>


<commit_before>//! De-/serialization helpers for other ruma crates

use serde::de::{Deserialize, IntoDeserializer};

pub mod duration;
pub mod empty;
pub mod json_string;
pub mod test;
pub mod time;
pub mod urlencoded;

pub use empty::vec_as_map_of_empty;

/// Check whether a value is equal to its default value.
pub fn is_default<T: Default + PartialEq>(val: &T) -> bool {
    val == &T::default()
}

/// Simply returns `true`.
///
/// Useful for `#[serde(default = ...)]`.
pub fn default_true() -> bool {
    true
}

/// Simplfy dereferences the given bool.
///
/// Useful for `#[serde(skip_serializing_if = ...)]`
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn is_true(b: &bool) -> bool {
    *b
}

/// Serde deserialization decorator to map empty Strings to None,
/// and forward non-empty Strings to the Deserialize implementation for T.
/// Useful for the typical
/// "A room with an X event with an absent, null, or empty Y field
/// should be treated the same as a room with no such event."
/// formulation in the spec.
///
/// To be used like this:
/// `#[serde(deserialize_with = "empty_string_as_none"]`
/// Relevant serde issue: https://github.com/serde-rs/serde/issues/1425
pub fn empty_string_as_none<'de, D, T>(de: D) -> Result<Option<T>, D::Error>
where
    D: serde::Deserializer<'de>,
    T: serde::Deserialize<'de>,
{
    let opt = Option::<String>::deserialize(de)?;
    // TODO: Switch to and remove this attribute `opt.as_deref()` once MSRV is >= 1.40
    #[allow(clippy::option_as_ref_deref, clippy::unknown_clippy_lints)]
    let opt = opt.as_ref().map(String::as_str);
    match opt {
        None | Some("") => Ok(None),
        // If T = String, like in m.room.name, the second deserialize is actually superfluous.
        // TODO: optimize that somehow?
        Some(s) => T::deserialize(s.into_deserializer()).map(Some),
    }
}
<commit_msg>serde: Repair minor docs typo<commit_after>//! De-/serialization helpers for other ruma crates

use serde::de::{Deserialize, IntoDeserializer};

pub mod duration;
pub mod empty;
pub mod json_string;
pub mod test;
pub mod time;
pub mod urlencoded;

pub use empty::vec_as_map_of_empty;

/// Check whether a value is equal to its default value.
pub fn is_default<T: Default + PartialEq>(val: &T) -> bool {
    val == &T::default()
}

/// Simply returns `true`.
///
/// Useful for `#[serde(default = ...)]`.
pub fn default_true() -> bool {
    true
}

/// Simplfy dereferences the given bool.
///
/// Useful for `#[serde(skip_serializing_if = ...)]`
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn is_true(b: &bool) -> bool {
    *b
}

/// Serde deserialization decorator to map empty Strings to None,
/// and forward non-empty Strings to the Deserialize implementation for T.
/// Useful for the typical
/// "A room with an X event with an absent, null, or empty Y field
/// should be treated the same as a room with no such event."
/// formulation in the spec.
///
/// To be used like this:
/// `#[serde(deserialize_with = "empty_string_as_none")]`
/// Relevant serde issue: https://github.com/serde-rs/serde/issues/1425
pub fn empty_string_as_none<'de, D, T>(de: D) -> Result<Option<T>, D::Error>
where
    D: serde::Deserializer<'de>,
    T: serde::Deserialize<'de>,
{
    let opt = Option::<String>::deserialize(de)?;
    // TODO: Switch to and remove this attribute `opt.as_deref()` once MSRV is >= 1.40
    #[allow(clippy::option_as_ref_deref, clippy::unknown_clippy_lints)]
    let opt = opt.as_ref().map(String::as_str);
    match opt {
        None | Some("") => Ok(None),
        // If T = String, like in m.room.name, the second deserialize is actually superfluous.
        // TODO: optimize that somehow?
        Some(s) => T::deserialize(s.into_deserializer()).map(Some),
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::ptr;

// We should use {u32,u64}::BYTES when they are stable;
const U32_BYTES: usize = 4;
const U64_BYTES: usize = 8;

macro_rules! number_stream(
    ($name:ident, $number_type:ty, $bytes_in_type:expr) => (
#[derive(Debug,Copy,Clone)]
struct $name<'a> {
    start: *const $number_type,
    end: *const $number_type,
    marker: PhantomData<&'a ()>
}

impl<'a> $name<'a> {
    fn new(bytes: &'a [u8]) -> ($name<'a>, &'a [u8]) {
        $name::with_stride(bytes, 1)
    }

    // Stride is a grouping of sequential numbers
    //
    // 0 1 2 3 4 5 6 7
    // -------------      We have 7 bytes
    // --- --- --- X      Each number takes 2 bytes
    // --- --- XXX X      With a stride of 2
    //
    // Only four bytes will be consumed, the rest returned
    fn with_stride(bytes: &'a [u8], stride: usize) -> ($name<'a>, &'a [u8]) {
        let n_numbers_in_bytes = bytes.len() / $bytes_in_type;
        let n_strides_in_numbers = n_numbers_in_bytes / stride;
        let total_numbers = n_strides_in_numbers * stride;

        let (mine, theirs) = bytes.split_at(total_numbers * $bytes_in_type);

        let start = mine.as_ptr() as *const $number_type;
        let end = unsafe { start.offset(total_numbers as isize) };

        let me = $name {
            start: start,
            end: end,
            marker: PhantomData,
        };

        (me, theirs)
    }
}

impl<'a> Iterator for $name<'a> {
    type Item = $number_type;

    fn next(&mut self) -> Option<$number_type> {
        if self.start >= self.end { return None }

        let v: $number_type = unsafe { ptr::read(self.start) };

        self.start = unsafe { self.start.offset(1) };
        Some(v)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let cnt = self.count();
        (cnt, Some(cnt))
    }

    fn count(self) -> usize() {
        let total_bytes = self.end as usize - self.start as usize;
        total_bytes / $bytes_in_type
    }
}
));

number_stream!(U32FromBytes, u32, U32_BYTES);
number_stream!(U64FromBytes, u64, U64_BYTES);

/// Converts a slice of bytes into an iterator of numbers.
///
/// The data is always treated as little endian. Only complete ranges
/// of bytes are parsed as the number, any left-over bytes are returned.
// FIXME: Probably doesn't work on big endian machines.
pub trait NumberStreams {
    /// Reads u32s from the bytes
    fn u32_stream(&self) -> (U32FromBytes, &[u8]);
    /// Reads u32s from the bytes, there will always be a multiple of `stride` numbers
    fn u32_stream_with_stride(&self, stride: usize) -> (U32FromBytes, &[u8]);
    /// Reads u64s from the bytes
    fn u64_stream(&self) -> (U64FromBytes, &[u8]);
    /// Reads u64s from the bytes, there will always be a multiple of `stride` numbers
    fn u64_stream_with_stride(&self, stride: usize) -> (U64FromBytes, &[u8]);
}

impl<'a> NumberStreams for [u8] {
    fn u32_stream(&self) -> (U32FromBytes, &[u8]) {
        U32FromBytes::new(self)
    }
    fn u32_stream_with_stride(&self, stride: usize) -> (U32FromBytes, &[u8]) {
        U32FromBytes::with_stride(self, stride)
    }
    fn u64_stream(&self) -> (U64FromBytes, &[u8]) {
        U64FromBytes::new(self)
    }
    fn u64_stream_with_stride(&self, stride: usize) -> (U64FromBytes, &[u8]) {
        U64FromBytes::with_stride(self, stride)
    }
}

#[cfg(test)]
mod test {
    use ::std::slice;
    use super::{U32_BYTES,U64_BYTES};
    use super::NumberStreams;

    fn u32_slice_as_u8(values: &[u32]) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                values.as_ptr() as *const u8,
                values.len() * U32_BYTES,
            )
        }
    }

    #[test]
    fn can_read_u32_from_bytes() {
        let orig_values: &[u32] = &[0,1];
        let as_u8 = u32_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u32_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert!(rest.is_empty());
    }

    #[test]
    fn can_read_u32_from_bytes_with_leftovers() {
        let orig_values: &[u32] = &[0,1];
        let mut as_u8: Vec<_> = u32_slice_as_u8(orig_values).into();
        as_u8.push(42);

        let (iter, rest) = as_u8.u32_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert_eq!(rest, [42]);
    }

    #[test]
    fn can_read_u32_from_bytes_with_a_stride() {
        let orig_values: &[u32] = &[0,1,2];
        let as_u8 = u32_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u32_stream_with_stride(2);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..2]);

        let (iter, rest) = rest.u32_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[2..]);
        assert!(rest.is_empty());
    }

    fn u64_slice_as_u8(values: &[u64]) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                values.as_ptr() as *const u8,
                values.len() * U64_BYTES,
            )
        }
    }

    #[test]
    fn can_read_u64_from_bytes() {
        let orig_values: &[u64] = &[0,1];
        let as_u8 = u64_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u64_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert!(rest.is_empty());
    }

    #[test]
    fn can_read_u64_from_bytes_with_leftovers() {
        let orig_values: &[u64] = &[0,1];
        let mut as_u8: Vec<_> = u64_slice_as_u8(orig_values).into();
        as_u8.push(42);

        let (iter, rest) = as_u8.u64_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert_eq!(rest, [42]);
    }

    #[test]
    fn can_read_u64_from_bytes_with_a_stride() {
        let orig_values: &[u64] = &[0,1,2];
        let as_u8 = u64_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u64_stream_with_stride(2);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..2]);

        let (iter, rest) = rest.u64_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[2..]);
        assert!(rest.is_empty());
    }
}
<commit_msg>address compiler warnings concerning private type in public interface<commit_after>use std::marker::PhantomData;
use std::ptr;

// We should use {u32,u64}::BYTES when they are stable;
const U32_BYTES: usize = 4;
const U64_BYTES: usize = 8;

macro_rules! number_stream(
    ($name:ident, $number_type:ty, $bytes_in_type:expr) => (
#[derive(Debug,Copy,Clone)]
pub struct $name<'a> {
    start: *const $number_type,
    end: *const $number_type,
    marker: PhantomData<&'a ()>
}

impl<'a> $name<'a> {
    fn new(bytes: &'a [u8]) -> ($name<'a>, &'a [u8]) {
        $name::with_stride(bytes, 1)
    }

    // Stride is a grouping of sequential numbers
    //
    // 0 1 2 3 4 5 6 7
    // -------------      We have 7 bytes
    // --- --- --- X      Each number takes 2 bytes
    // --- --- XXX X      With a stride of 2
    //
    // Only four bytes will be consumed, the rest returned
    fn with_stride(bytes: &'a [u8], stride: usize) -> ($name<'a>, &'a [u8]) {
        let n_numbers_in_bytes = bytes.len() / $bytes_in_type;
        let n_strides_in_numbers = n_numbers_in_bytes / stride;
        let total_numbers = n_strides_in_numbers * stride;

        let (mine, theirs) = bytes.split_at(total_numbers * $bytes_in_type);

        let start = mine.as_ptr() as *const $number_type;
        let end = unsafe { start.offset(total_numbers as isize) };

        let me = $name {
            start: start,
            end: end,
            marker: PhantomData,
        };

        (me, theirs)
    }
}

impl<'a> Iterator for $name<'a> {
    type Item = $number_type;

    fn next(&mut self) -> Option<$number_type> {
        if self.start >= self.end { return None }

        let v: $number_type = unsafe { ptr::read(self.start) };

        self.start = unsafe { self.start.offset(1) };
        Some(v)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let cnt = self.count();
        (cnt, Some(cnt))
    }

    fn count(self) -> usize() {
        let total_bytes = self.end as usize - self.start as usize;
        total_bytes / $bytes_in_type
    }
}
));

number_stream!(U32FromBytes, u32, U32_BYTES);
number_stream!(U64FromBytes, u64, U64_BYTES);

/// Converts a slice of bytes into an iterator of numbers.
///
/// The data is always treated as little endian. Only complete ranges
/// of bytes are parsed as the number, any left-over bytes are returned.
// FIXME: Probably doesn't work on big endian machines.
pub trait NumberStreams {
    /// Reads u32s from the bytes
    fn u32_stream(&self) -> (U32FromBytes, &[u8]);
    /// Reads u32s from the bytes, there will always be a multiple of `stride` numbers
    fn u32_stream_with_stride(&self, stride: usize) -> (U32FromBytes, &[u8]);
    /// Reads u64s from the bytes
    fn u64_stream(&self) -> (U64FromBytes, &[u8]);
    /// Reads u64s from the bytes, there will always be a multiple of `stride` numbers
    fn u64_stream_with_stride(&self, stride: usize) -> (U64FromBytes, &[u8]);
}

impl<'a> NumberStreams for [u8] {
    fn u32_stream(&self) -> (U32FromBytes, &[u8]) {
        U32FromBytes::new(self)
    }
    fn u32_stream_with_stride(&self, stride: usize) -> (U32FromBytes, &[u8]) {
        U32FromBytes::with_stride(self, stride)
    }
    fn u64_stream(&self) -> (U64FromBytes, &[u8]) {
        U64FromBytes::new(self)
    }
    fn u64_stream_with_stride(&self, stride: usize) -> (U64FromBytes, &[u8]) {
        U64FromBytes::with_stride(self, stride)
    }
}

#[cfg(test)]
mod test {
    use ::std::slice;
    use super::{U32_BYTES,U64_BYTES};
    use super::NumberStreams;

    fn u32_slice_as_u8(values: &[u32]) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                values.as_ptr() as *const u8,
                values.len() * U32_BYTES,
            )
        }
    }

    #[test]
    fn can_read_u32_from_bytes() {
        let orig_values: &[u32] = &[0,1];
        let as_u8 = u32_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u32_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert!(rest.is_empty());
    }

    #[test]
    fn can_read_u32_from_bytes_with_leftovers() {
        let orig_values: &[u32] = &[0,1];
        let mut as_u8: Vec<_> = u32_slice_as_u8(orig_values).into();
        as_u8.push(42);

        let (iter, rest) = as_u8.u32_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert_eq!(rest, [42]);
    }

    #[test]
    fn can_read_u32_from_bytes_with_a_stride() {
        let orig_values: &[u32] = &[0,1,2];
        let as_u8 = u32_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u32_stream_with_stride(2);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..2]);

        let (iter, rest) = rest.u32_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[2..]);
        assert!(rest.is_empty());
    }

    fn u64_slice_as_u8(values: &[u64]) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                values.as_ptr() as *const u8,
                values.len() * U64_BYTES,
            )
        }
    }

    #[test]
    fn can_read_u64_from_bytes() {
        let orig_values: &[u64] = &[0,1];
        let as_u8 = u64_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u64_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert!(rest.is_empty());
    }

    #[test]
    fn can_read_u64_from_bytes_with_leftovers() {
        let orig_values: &[u64] = &[0,1];
        let mut as_u8: Vec<_> = u64_slice_as_u8(orig_values).into();
        as_u8.push(42);

        let (iter, rest) = as_u8.u64_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert_eq!(rest, [42]);
    }

    #[test]
    fn can_read_u64_from_bytes_with_a_stride() {
        let orig_values: &[u64] = &[0,1,2];
        let as_u8 = u64_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u64_stream_with_stride(2);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..2]);

        let (iter, rest) = rest.u64_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[2..]);
        assert!(rest.is_empty());
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::fs::File;
use std::io::*;
use std::mem;
use std::slice;
use std::thread;

use super::system::graphics::fast_set;

use super::super::FONT;
use super::super::Event;
use super::super::Color;

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: i32,
    /// The y coordinate of the window
    y: i32,
    /// The width of the window
    w: u32,
    /// The height of the window
    h: u32,
    /// The title of the window
    t: String,
    /// True if the window should not wait for events
    async: bool,
    /// The input scheme
    file: File,
    /// Window data
    data: Box<[Color]>,
}

impl Window {
    /// Create a new window
    pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Self> {
        Window::new_flags(x, y, w, h, title, false)
    }

    /// Create a new window with flags
    pub fn new_flags(x: i32, y: i32, w: u32, h: u32, title: &str, async: bool) -> Option<Self> {
        match File::open(&format!("orbital:{}/{}/{}/{}/{}/{}", if async { "a" } else { "" }, x, y, w, h, title)) {
            Ok(file) => {
                Some(Window {
                    x: x,
                    y: y,
                    w: w,
                    h: h,
                    t: title.to_string(),
                    async: async,
                    file: file,
                    data: vec![Color::rgb(0, 0, 0); (w * h * 4) as usize].into_boxed_slice(),
                })
            }
            Err(_) => None,
        }
    }

    // TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        if let Ok(path) = self.file.path() {
            // orbital:/x/y/w/h/t
            if let Some(path_str) = path.to_str() {
                let mut parts = path_str.split('/').skip(1);
                if let Some(x) = parts.next() {
                    self.x = x.parse::<i32>().unwrap_or(0);
                }
                if let Some(y) = parts.next() {
                    self.y = y.parse::<i32>().unwrap_or(0);
                }
                if let Some(w) = parts.next() {
                    self.w = w.parse::<u32>().unwrap_or(0);
                }
                if let Some(h) = parts.next() {
                    self.h = h.parse::<u32>().unwrap_or(0);
                }
            }
        }
    }

    /// Get x
    // TODO: Sync with window movements
    pub fn x(&self) -> i32 {
        self.x
    }

    /// Get y
    // TODO: Sync with window movements
    pub fn y(&self) -> i32 {
        self.y
    }

    /// Get width
    pub fn width(&self) -> u32 {
        self.w
    }

    /// Get height
    pub fn height(&self) -> u32 {
        self.h
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set title
    pub fn set_title(&mut self, _: &str) {
        // TODO
    }

    pub fn data(&self) -> &[Color] {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut [Color] {
        &mut self.data
    }

    /// Draw a pixel
    pub fn pixel(&mut self, x: i32, y: i32, color: Color) {
        if x >= 0 && y >= 0 && x < self.w as i32 && y < self.h as i32 {
            let new = color.data;

            let alpha = (new >> 24) & 0xFF;
            if alpha > 0 {
                let old = &mut self.data[y as usize * self.w as usize + x as usize].data;
                if alpha >= 255 {
                    *old = new;
                } else {
                    let n_r = (((new >> 16) & 0xFF) * alpha) >> 8;
                    let n_g = (((new >> 8) & 0xFF) * alpha) >> 8;
                    let n_b = ((new & 0xFF) * alpha) >> 8;

                    let n_alpha = 255 - alpha;
                    let o_a = (((*old >> 24) & 0xFF) * n_alpha) >> 8;
                    let o_r = (((*old >> 16) & 0xFF) * n_alpha) >> 8;
                    let o_g = (((*old >> 8) & 0xFF) * n_alpha) >> 8;
                    let o_b = ((*old & 0xFF) * n_alpha) >> 8;

                    *old = ((o_a << 24) | (o_r << 16) | (o_g << 8) | o_b) + ((alpha << 24) | (n_r << 16) | (n_g << 8) | n_b);
                }
            }
        }
    }

    /// Draw a line
    pub fn line(&mut self, argx1: i32, argy1: i32, argx2: i32, argy2: i32, color: Color) {
        let mut x1 = argx1;
        let mut y1 = argy1;
        let mut x2 = argx2;
        let mut y2 = argy2;

        if x2 < x1 {
            x1 = argx2;
            y1 = argy2;
            x2 = argx1;
            y2 = argy1;
        }

        let dx = x2 - x1;
        let dy = y2 - y1;

        //let ratio = dy as f32 / dx as f32;
        for x in x1..x2 {
            let y = y1 + ((dy * (x - x1)) as f32 / dx as f32) as i32;
            self.pixel(x, y, color);
        }
    }

    pub fn lines(&mut self, points: &[[i32; 2]], color: Color) {
        if points.len() == 0 {
            // when no points given, do nothing
        } else if points.len() == 1 {
            self.pixel(points[0][0], points[0][1], color);
        } else {
            for i in 0..points.len() - 1 {
                self.line(points[i][0], points[i][1], points[i+1][0], points[i+1][1], color);
            }
        }
    }

    /// Draw a character, using the loaded font
    pub fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
        let mut offset = (c as usize) * 16;
        for row in 0..16 {
            let row_data;
            if offset < FONT.len() {
                row_data = FONT[offset];
            } else {
                row_data = 0;
            }

            for col in 0..8 {
                let pixel = (row_data >> (7 - col)) & 1;
                if pixel > 0 {
                    self.pixel(x + col as i32, y + row as i32, color);
                }
            }
            offset += 1;
        }
    }

    // TODO move, resize, set_title

    /// Set entire window to a color
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn set(&mut self, color: Color) {
        unsafe {
            fast_set(self.data.as_mut_ptr() as *mut u32, color.data, self.data.len());
        }
    }

    /// Sets the whole window to black
    pub fn clear(&mut self) {
        self.set(Color::rgb(0,0,0));
    }

    /// Draw rectangle
    #[allow(unused_variables)]
    pub fn rect(&mut self, x: i32, y: i32, w: u32, h: u32, color: Color) {
        let data = color.data;

        let start_y = cmp::max(0, cmp::min(self.h as i32 - 1, y));
        let end_y = cmp::max(start_y, cmp::min(self.h as i32 - 1, y + h as i32));

        let start_x = cmp::max(0, cmp::min(self.w as i32 - 1, x));
        let len = cmp::max(start_x, cmp::min(self.w as i32 - 1, x + w as i32)) - start_x;

        for y in start_y..end_y {
            unsafe {
                fast_set(self.data.as_mut_ptr().offset((y * self.w as i32 + start_x) as isize) as *mut u32, data, len as usize);
            }
        }
    }

    /// Display an image
    // TODO: Improve speed
    pub fn image(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color]) {
        let mut i = 0;
        for y in start_y..start_y + h as i32 {
            for x in start_x..start_x + w as i32 {
                if i < data.len() {
                    self.pixel(x, y, data[i])
                }
                i += 1;
            }
        }
    }

    /// Blocking iterator over events
    pub fn events(&mut self) -> EventIter {
        let mut iter = EventIter {
            events: [Event::new(); 128],
            i: 0,
            count: 0,
        };

        'blocking: loop {
            //Should it be cleared? iter.events = [Event::new(); 128];
            match self.file.read(unsafe {
                slice::from_raw_parts_mut(iter.events.as_mut_ptr() as *mut u8, iter.events.len() * mem::size_of::<Event>())
            }){
                Ok(0) => if ! self.async {
                    thread::yield_now();
                } else {
                    break 'blocking;
                },
                Ok(count) => {
                    iter.count = count/mem::size_of::<Event>();
                    break 'blocking;
                },
                Err(_) => break 'blocking,
            }
        }

        iter
    }

    /// Flip the window buffer
    pub fn sync(&mut self) -> bool {
        self.file.write(unsafe {
            slice::from_raw_parts(self.data.as_ptr() as *const u8, self.data.len() * mem::size_of::<Color>())
        }).is_ok()
    }
}

/// Event iterator
pub struct EventIter {
    events: [Event; 128],
    i: usize,
    count: usize,
}

impl Iterator for EventIter {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        if self.i < self.count {
            if let Some(event) = self.events.get(self.i) {
                self.i += 1;
                Some(*event)
            } else {
                None
            }
        } else {
            None
        }
    }
}
<commit_msg>Fix off by one error<commit_after>use std::cmp;
use std::fs::File;
use std::io::*;
use std::mem;
use std::slice;
use std::thread;

use super::system::graphics::fast_set;

use super::super::FONT;
use super::super::Event;
use super::super::Color;

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: i32,
    /// The y coordinate of the window
    y: i32,
    /// The width of the window
    w: u32,
    /// The height of the window
    h: u32,
    /// The title of the window
    t: String,
    /// True if the window should not wait for events
    async: bool,
    /// The input scheme
    file: File,
    /// Window data
    data: Box<[Color]>,
}

impl Window {
    /// Create a new window
    pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Self> {
        Window::new_flags(x, y, w, h, title, false)
    }

    /// Create a new window with flags
    pub fn new_flags(x: i32, y: i32, w: u32, h: u32, title: &str, async: bool) -> Option<Self> {
        match File::open(&format!("orbital:{}/{}/{}/{}/{}/{}", if async { "a" } else { "" }, x, y, w, h, title)) {
            Ok(file) => {
                Some(Window {
                    x: x,
                    y: y,
                    w: w,
                    h: h,
                    t: title.to_string(),
                    async: async,
                    file: file,
                    data: vec![Color::rgb(0, 0, 0); (w * h * 4) as usize].into_boxed_slice(),
                })
            }
            Err(_) => None,
        }
    }

    // TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        if let Ok(path) = self.file.path() {
            // orbital:/x/y/w/h/t
            if let Some(path_str) = path.to_str() {
                let mut parts = path_str.split('/').skip(1);
                if let Some(x) = parts.next() {
                    self.x = x.parse::<i32>().unwrap_or(0);
                }
                if let Some(y) = parts.next() {
                    self.y = y.parse::<i32>().unwrap_or(0);
                }
                if let Some(w) = parts.next() {
                    self.w = w.parse::<u32>().unwrap_or(0);
                }
                if let Some(h) = parts.next() {
                    self.h = h.parse::<u32>().unwrap_or(0);
                }
            }
        }
    }

    /// Get x
    // TODO: Sync with window movements
    pub fn x(&self) -> i32 {
        self.x
    }

    /// Get y
    // TODO: Sync with window movements
    pub fn y(&self) -> i32 {
        self.y
    }

    /// Get width
    pub fn width(&self) -> u32 {
        self.w
    }

    /// Get height
    pub fn height(&self) -> u32 {
        self.h
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set title
    pub fn set_title(&mut self, _: &str) {
        // TODO
    }

    pub fn data(&self) -> &[Color] {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut [Color] {
        &mut self.data
    }

    /// Draw a pixel
    pub fn pixel(&mut self, x: i32, y: i32, color: Color) {
        if x >= 0 && y >= 0 && x < self.w as i32 && y < self.h as i32 {
            let new = color.data;

            let alpha = (new >> 24) & 0xFF;
            if alpha > 0 {
                let old = &mut self.data[y as usize * self.w as usize + x as usize].data;
                if alpha >= 255 {
                    *old = new;
                } else {
                    let n_r = (((new >> 16) & 0xFF) * alpha) >> 8;
                    let n_g = (((new >> 8) & 0xFF) * alpha) >> 8;
                    let n_b = ((new & 0xFF) * alpha) >> 8;

                    let n_alpha = 255 - alpha;
                    let o_a = (((*old >> 24) & 0xFF) * n_alpha) >> 8;
                    let o_r = (((*old >> 16) & 0xFF) * n_alpha) >> 8;
                    let o_g = (((*old >> 8) & 0xFF) * n_alpha) >> 8;
                    let o_b = ((*old & 0xFF) * n_alpha) >> 8;

                    *old = ((o_a << 24) | (o_r << 16) | (o_g << 8) | o_b) + ((alpha << 24) | (n_r << 16) | (n_g << 8) | n_b);
                }
            }
        }
    }

    /// Draw a line
    pub fn line(&mut self, argx1: i32, argy1: i32, argx2: i32, argy2: i32, color: Color) {
        let mut x1 = argx1;
        let mut y1 = argy1;
        let mut x2 = argx2;
        let mut y2 = argy2;

        if x2 < x1 {
            x1 = argx2;
            y1 = argy2;
            x2 = argx1;
            y2 = argy1;
        }

        let dx = x2 - x1;
        let dy = y2 - y1;

        //let ratio = dy as f32 / dx as f32;
        for x in x1..x2 {
            let y = y1 + ((dy * (x - x1)) as f32 / dx as f32) as i32;
            self.pixel(x, y, color);
        }
    }

    pub fn lines(&mut self, points: &[[i32; 2]], color: Color) {
        if points.len() == 0 {
            // when no points given, do nothing
        } else if points.len() == 1 {
            self.pixel(points[0][0], points[0][1], color);
        } else {
            for i in 0..points.len() - 1 {
                self.line(points[i][0], points[i][1], points[i+1][0], points[i+1][1], color);
            }
        }
    }

    /// Draw a character, using the loaded font
    pub fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
        let mut offset = (c as usize) * 16;
        for row in 0..16 {
            let row_data;
            if offset < FONT.len() {
                row_data = FONT[offset];
            } else {
                row_data = 0;
            }

            for col in 0..8 {
                let pixel = (row_data >> (7 - col)) & 1;
                if pixel > 0 {
                    self.pixel(x + col as i32, y + row as i32, color);
                }
            }
            offset += 1;
        }
    }

    // TODO move, resize, set_title

    /// Set entire window to a color
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn set(&mut self, color: Color) {
        unsafe {
            fast_set(self.data.as_mut_ptr() as *mut u32, color.data, self.data.len());
        }
    }

    /// Sets the whole window to black
    pub fn clear(&mut self) {
        self.set(Color::rgb(0,0,0));
    }

    /// Draw rectangle
    #[allow(unused_variables)]
    pub fn rect(&mut self, x: i32, y: i32, w: u32, h: u32, color: Color) {
        let data = color.data;

        let start_y = cmp::max(0, cmp::min(self.h as i32 - 1, y));
        let end_y = cmp::max(start_y, cmp::min(self.h as i32, y + h as i32));

        let start_x = cmp::max(0, cmp::min(self.w as i32 - 1, x));
        let len = cmp::max(start_x, cmp::min(self.w as i32, x + w as i32)) - start_x;

        for y in start_y..end_y {
            unsafe {
                fast_set(self.data.as_mut_ptr().offset((y * self.w as i32 + start_x) as isize) as *mut u32, data, len as usize);
            }
        }
    }

    /// Display an image
    // TODO: Improve speed
    pub fn image(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color]) {
        let mut i = 0;
        for y in start_y..start_y + h as i32 {
            for x in start_x..start_x + w as i32 {
                if i < data.len() {
                    self.pixel(x, y, data[i])
                }
                i += 1;
            }
        }
    }

    /// Blocking iterator over events
    pub fn events(&mut self) -> EventIter {
        let mut iter = EventIter {
            events: [Event::new(); 128],
            i: 0,
            count: 0,
        };

        'blocking: loop {
            //Should it be cleared? iter.events = [Event::new(); 128];
            match self.file.read(unsafe {
                slice::from_raw_parts_mut(iter.events.as_mut_ptr() as *mut u8, iter.events.len() * mem::size_of::<Event>())
            }){
                Ok(0) => if ! self.async {
                    thread::yield_now();
                } else {
                    break 'blocking;
                },
                Ok(count) => {
                    iter.count = count/mem::size_of::<Event>();
                    break 'blocking;
                },
                Err(_) => break 'blocking,
            }
        }

        iter
    }

    /// Flip the window buffer
    pub fn sync(&mut self) -> bool {
        self.file.write(unsafe {
            slice::from_raw_parts(self.data.as_ptr() as *const u8, self.data.len() * mem::size_of::<Color>())
        }).is_ok()
    }
}

/// Event iterator
pub struct EventIter {
    events: [Event; 128],
    i: usize,
    count: usize,
}

impl Iterator for EventIter {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        if self.i < self.count {
            if let Some(event) = self.events.get(self.i) {
                self.i += 1;
                Some(*event)
            } else {
                None
            }
        } else {
            None
        }
    }
}
<|endoftext|>