<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use super::watchman_query_builder::{get_all_roots, get_watchman_expr};
use super::FileSourceResult;
use super::FileSourceSubscriptionNextChange;
use super::WatchmanFile;
use crate::errors::{Error, Result};
use crate::{compiler_state::CompilerState, config::Config, saved_state::SavedStateLoader};
use common::{PerfLogEvent, PerfLogger};
use log::{debug, info, warn};
use serde_bser::value::Value;
use std::process::Command;
pub use watchman_client::prelude::Clock;
use watchman_client::prelude::*;
use watchman_client::{Subscription as WatchmanSubscription, SubscriptionData};

pub struct WatchmanFileSource<'config> {
    client: Client,
    config: &'config Config,
    resolved_root: ResolvedRoot,
}

#[derive(Debug)]
pub struct WatchmanFileSourceResult {
    pub files: Vec<WatchmanFile>,
    pub resolved_root: ResolvedRoot,
    pub clock: Clock,
    pub saved_state_info: Option<Value>,
}

impl<'config> WatchmanFileSource<'config> {
    pub async fn connect(
        config: &'config Config,
        perf_logger_event: &impl PerfLogEvent,
    ) -> Result<WatchmanFileSource<'config>> {
        let connect_timer = perf_logger_event.start("file_source_connect_time");
        let client = Connector::new().connect().await?;
        let canonical_root = CanonicalPath::canonicalize(&config.root_dir).map_err(|err| {
            Error::CanonicalizeRoot {
                root: config.root_dir.clone(),
                source: err,
            }
        })?;
        let resolved_root = client.resolve_root(canonical_root).await?;
        perf_logger_event.stop(connect_timer);

        Ok(Self {
            client,
            config,
            resolved_root,
        })
    }

    /// Executes a point query (as opposed to a subscription) to find all files
    /// to compile and returns the result.
    pub async fn query(
        &self,
        perf_logger_event: &impl PerfLogEvent,
        perf_logger: &impl PerfLogger,
    ) -> Result<CompilerState> {
        info!("querying files to compile...");
        let query_time = perf_logger_event.start("file_source_query_time");
        // If the saved state flag is passed, load from it or fail.
        if let Some(saved_state_path) = &self.config.load_saved_state_file {
            let mut compiler_state = perf_logger_event.time("deserialize_saved_state", || {
                CompilerState::deserialize_from_file(&saved_state_path)
            })?;
            let file_source_result = self
                .query_file_result(Some(compiler_state.clock.clone()), perf_logger_event)
                .await?;
            compiler_state
                .pending_file_source_changes
                .write()
                .unwrap()
                .push(file_source_result);
            compiler_state.merge_file_source_changes(
                &self.config,
                perf_logger_event,
                perf_logger,
                true,
            )?;
            perf_logger_event.stop(query_time);
            return Ok(compiler_state);
        }

        // If saved state is configured, try using saved state unless the config
        // forces a full build.
        if let Config {
            compile_everything: false,
            saved_state_config: Some(saved_state_config),
            saved_state_loader: Some(saved_state_loader),
            saved_state_version,
            ..
        } = self.config
        {
            match self
                .try_saved_state(
                    perf_logger,
                    perf_logger_event,
                    saved_state_config.clone(),
                    saved_state_loader.as_ref(),
                    saved_state_version,
                )
                .await
            {
                Ok(load_result) => {
                    perf_logger_event.stop(query_time);
                    return load_result;
                }
                Err(saved_state_failure) => {
                    warn!(
                        "Unable to load saved state, falling back to full build: {}",
                        saved_state_failure
                    );
                }
            }
        }

        // Finally, do a simple full query.
        let file_source_result = self.query_file_result(None, perf_logger_event).await?;
        let compiler_state = perf_logger_event.time("from_file_source_changes", || {
            CompilerState::from_file_source_changes(
                &self.config,
                &file_source_result,
                perf_logger_event,
                perf_logger,
            )
        })?;
        perf_logger_event.stop(query_time);
        Ok(compiler_state)
    }

    /// Starts a subscription sending updates since the given clock.
    pub async fn subscribe(
        self,
        perf_logger_event: &impl PerfLogEvent,
        perf_logger: &impl PerfLogger,
    ) -> Result<(CompilerState, WatchmanFileSourceSubscription)> {
        let timer = perf_logger_event.start("file_source_subscribe_time");
        let compiler_state = self.query(perf_logger_event, perf_logger).await?;

        let expression = get_watchman_expr(&self.config);

        let file_source_result = self
            .query_file_result(Some(compiler_state.clock.clone()), perf_logger_event)
            .await?;

        let (subscription, _initial) = self
            .client
            .subscribe::<WatchmanFile>(
                &self.resolved_root,
                SubscribeRequest {
                    expression: Some(expression),
                    since: Some(file_source_result.clock()),
                    defer: vec!["hg.update"],
                    ..Default::default()
                },
            )
            .await?;

        perf_logger_event.stop(timer);

        Ok((
            compiler_state,
            WatchmanFileSourceSubscription::new(self.resolved_root.clone(), subscription),
        ))
    }

    /// Internal method to issue a watchman query, returning a raw
    /// WatchmanFileSourceResult.
    async fn query_file_result(
        &self,
        since_clock: Option<Clock>,
        perf_logger_event: &impl PerfLogEvent,
    ) -> Result<FileSourceResult> {
        let expression = get_watchman_expr(&self.config);

        let query_timer = perf_logger_event.start("watchman_query_time");
        // If `since` is available, we should not pass the `path` parameter.
        // Watchman ignores `since` parameter if both `path` and `since` are
        // passed as the request params
        let request = if since_clock.is_some() {
            QueryRequestCommon {
                expression: Some(expression),
                since: since_clock,
                ..Default::default()
            }
        } else {
            let query_roots = get_all_roots(&self.config)
                .into_iter()
                .map(PathGeneratorElement::RecursivePath)
                .collect();
            QueryRequestCommon {
                expression: Some(expression),
                path: Some(query_roots),
                ..Default::default()
            }
        };
        let query_result = self
            .client
            .query::<WatchmanFile>(&self.resolved_root, request)
            .await?;
        perf_logger_event.stop(query_timer);

        let files = query_result.files.ok_or(Error::EmptyQueryResult)?;
        Ok(FileSourceResult::Watchman(WatchmanFileSourceResult {
            files,
            resolved_root: self.resolved_root.clone(),
            clock: query_result.clock,
            saved_state_info: query_result.saved_state_info,
        }))
    }

    /// Tries to load saved state with a watchman query.
    /// The return value is a nested Result:
    /// The outer Result indicates the result of a possible saved state infrastructure failure.
    /// The inner Result is a potential parse error.
    async fn try_saved_state(
        &self,
        perf_logger: &impl PerfLogger,
        perf_logger_event: &impl PerfLogEvent,
        saved_state_config: ScmAwareClockData,
        saved_state_loader: &'_ (dyn SavedStateLoader + Send + Sync),
        saved_state_version: &str,
    ) -> std::result::Result<Result<CompilerState>, &'static str> {
        let scm_since = Clock::ScmAware(FatClockData {
            clock: ClockSpec::null(),
            scm: Some(saved_state_config),
        });
        let file_source_result = self
            .query_file_result(Some(scm_since), perf_logger_event)
            .await
            .map_err(|_| "query failed")?;
        let saved_state_info = file_source_result
            .saved_state_info()
            .as_ref()
            .ok_or("no saved state in watchman response")?;
        let saved_state_path = perf_logger_event.time("saved_state_loading_time", || {
            saved_state_loader
                .load(&saved_state_info, self.config)
                .ok_or("unable to load")
        })?;
        let mut compiler_state = perf_logger_event
            .time("deserialize_saved_state", || {
                CompilerState::deserialize_from_file(&saved_state_path)
            })
            .map_err(|err| {
                let error_event = perf_logger.create_event("saved_state_loader_error");
                error_event.string("error", format!("Failed to deserialize: {}", err));
                perf_logger.complete_event(error_event);
                perf_logger.flush();
                "failed to deserialize"
            })?;
        // For cases, where we want to debug saved state integration, that doesn't include
        // saved_state format changes we may need to disable this by adding this env variable
        if std::env::var("RELAY_COMPILER_IGNORE_SAVED_STATE_VERSION").is_err()
            && compiler_state.saved_state_version != saved_state_version
        {
            return Err("Saved state version doesn't match.");
        }
        compiler_state
            .pending_file_source_changes
            .write()
            .unwrap()
            .push(file_source_result);
        if let Err(parse_error) = perf_logger_event.time("merge_file_source_changes", || {
            compiler_state.merge_file_source_changes(
                &self.config,
                perf_logger_event,
                perf_logger,
                true,
            )
        }) {
            Ok(Err(parse_error))
        } else {
            Ok(Ok(compiler_state))
        }
    }
}

pub struct WatchmanFileSourceSubscription {
    resolved_root: ResolvedRoot,
    subscription: WatchmanSubscription<WatchmanFile>,
    base_revision: String,
}

impl WatchmanFileSourceSubscription {
    fn new(resolved_root: ResolvedRoot, subscription: WatchmanSubscription<WatchmanFile>) -> Self {
        Self {
            resolved_root,
            subscription,
            base_revision: get_base_revision(None),
        }
    }

    /// Awaits changes from Watchman and provides the next set of changes
    /// if there were any changes to files
    pub async fn next_change(&mut self) -> Result<FileSourceSubscriptionNextChange> {
        match self.subscription.next().await? {
            SubscriptionData::FilesChanged(changes) => {
                if let Some(files) = changes.files {
                    debug!("number of files in this update: {}", files.len());
                    return Ok(FileSourceSubscriptionNextChange::Result(
                        FileSourceResult::Watchman(WatchmanFileSourceResult {
                            files,
                            resolved_root: self.resolved_root.clone(),
                            clock: changes.clock,
                            saved_state_info: None,
                        }),
                    ));
                }
            }
            SubscriptionData::StateEnter { state_name, .. } => {
                if state_name == "hg.update" {
                    return Ok(FileSourceSubscriptionNextChange::SourceControlUpdateEnter);
                }
            }
            SubscriptionData::StateLeave {
                state_name,
                metadata,
            } => {
                if state_name == "hg.update" {
                    let current_commit = if let Some(Value::ByteString(value)) = metadata {
                        Some(value.to_string())
                    } else {
                        None
                    };
                    let current_base_revision = get_base_revision(current_commit);
                    if current_base_revision != self.base_revision {
                        self.base_revision = current_base_revision;
                        return Ok(FileSourceSubscriptionNextChange::SourceControlUpdate);
                    } else {
                        return Ok(FileSourceSubscriptionNextChange::SourceControlUpdateLeave);
                    }
                }
            }
            SubscriptionData::Canceled => {
                return Err(Error::WatchmanSubscriptionCanceled);
            }
        }
        Ok(FileSourceSubscriptionNextChange::None)
    }
}

/// Base revision in this case is a common ancestor of two revisions:
/// `master` and current commit hash or `.`
fn get_base_revision(commit_hash: Option<String>) -> String {
    let output = Command::new("hg")
        .arg("log".to_string())
        .arg("-r".to_string())
        .arg(format!(
            "ancestor(master, {})",
            commit_hash.unwrap_or_else(|| ".".to_string())
        ))
        .arg("-T={node}")
        .output()
        .expect("Expect `hg` command getting base revision.");

    if output.stdout.is_empty() {
        panic!(
            "Failed to get base revision hash:\n {:?}",
            String::from_utf8_lossy(&output.stderr)
        );
    }

    String::from_utf8_lossy(&output.stdout).to_string()
}
<commit_msg>Add watchman debug logs: query, saved state, results<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use super::watchman_query_builder::{get_all_roots, get_watchman_expr};
use super::FileSourceResult;
use super::FileSourceSubscriptionNextChange;
use super::WatchmanFile;
use crate::errors::{Error, Result};
use crate::{compiler_state::CompilerState, config::Config, saved_state::SavedStateLoader};
use common::{PerfLogEvent, PerfLogger};
use log::{debug, info, warn};
use serde_bser::value::Value;
use std::process::Command;
pub use watchman_client::prelude::Clock;
use watchman_client::prelude::*;
use watchman_client::{Subscription as WatchmanSubscription, SubscriptionData};

pub struct WatchmanFileSource<'config> {
    client: Client,
    config: &'config Config,
    resolved_root: ResolvedRoot,
}

#[derive(Debug)]
pub struct WatchmanFileSourceResult {
    pub files: Vec<WatchmanFile>,
    pub resolved_root: ResolvedRoot,
    pub clock: Clock,
    pub saved_state_info: Option<Value>,
}

impl<'config> WatchmanFileSource<'config> {
    pub async fn connect(
        config: &'config Config,
        perf_logger_event: &impl PerfLogEvent,
    ) -> Result<WatchmanFileSource<'config>> {
        let connect_timer = perf_logger_event.start("file_source_connect_time");
        let client = Connector::new().connect().await?;
        let canonical_root = CanonicalPath::canonicalize(&config.root_dir).map_err(|err| {
            Error::CanonicalizeRoot {
                root: config.root_dir.clone(),
                source: err,
            }
        })?;
        let resolved_root = client.resolve_root(canonical_root).await?;
        perf_logger_event.stop(connect_timer);
        debug!(
            "WatchmanFileSource::connect(...) resolved_root = {:?}",
            resolved_root
        );
        Ok(Self {
            client,
            config,
            resolved_root,
        })
    }

    /// Executes a point query (as opposed to a subscription) to find all files
    /// to compile and returns the result.
    pub async fn query(
        &self,
        perf_logger_event: &impl PerfLogEvent,
        perf_logger: &impl PerfLogger,
    ) -> Result<CompilerState> {
        info!("querying files to compile...");
        let query_time = perf_logger_event.start("file_source_query_time");
        // If the saved state flag is passed, load from it or fail.
        if let Some(saved_state_path) = &self.config.load_saved_state_file {
            let mut compiler_state = perf_logger_event.time("deserialize_saved_state", || {
                CompilerState::deserialize_from_file(&saved_state_path)
            })?;
            let file_source_result = self
                .query_file_result(Some(compiler_state.clock.clone()), perf_logger_event)
                .await?;
            compiler_state
                .pending_file_source_changes
                .write()
                .unwrap()
                .push(file_source_result);
            compiler_state.merge_file_source_changes(
                &self.config,
                perf_logger_event,
                perf_logger,
                true,
            )?;
            perf_logger_event.stop(query_time);
            return Ok(compiler_state);
        }

        // If saved state is configured, try using saved state unless the config
        // forces a full build.
        if let Config {
            compile_everything: false,
            saved_state_config: Some(saved_state_config),
            saved_state_loader: Some(saved_state_loader),
            saved_state_version,
            ..
        } = self.config
        {
            match self
                .try_saved_state(
                    perf_logger,
                    perf_logger_event,
                    saved_state_config.clone(),
                    saved_state_loader.as_ref(),
                    saved_state_version,
                )
                .await
            {
                Ok(load_result) => {
                    perf_logger_event.stop(query_time);
                    return load_result;
                }
                Err(saved_state_failure) => {
                    warn!(
                        "Unable to load saved state, falling back to full build: {}",
                        saved_state_failure
                    );
                }
            }
        }

        // Finally, do a simple full query.
        let file_source_result = self.query_file_result(None, perf_logger_event).await?;
        let compiler_state = perf_logger_event.time("from_file_source_changes", || {
            CompilerState::from_file_source_changes(
                &self.config,
                &file_source_result,
                perf_logger_event,
                perf_logger,
            )
        })?;
        perf_logger_event.stop(query_time);
        Ok(compiler_state)
    }

    /// Starts a subscription sending updates since the given clock.
    pub async fn subscribe(
        self,
        perf_logger_event: &impl PerfLogEvent,
        perf_logger: &impl PerfLogger,
    ) -> Result<(CompilerState, WatchmanFileSourceSubscription)> {
        let timer = perf_logger_event.start("file_source_subscribe_time");
        let compiler_state = self.query(perf_logger_event, perf_logger).await?;

        let expression = get_watchman_expr(&self.config);

        let file_source_result = self
            .query_file_result(Some(compiler_state.clock.clone()), perf_logger_event)
            .await?;

        let (subscription, _initial) = self
            .client
            .subscribe::<WatchmanFile>(
                &self.resolved_root,
                SubscribeRequest {
                    expression: Some(expression),
                    since: Some(file_source_result.clock()),
                    defer: vec!["hg.update"],
                    ..Default::default()
                },
            )
            .await?;

        perf_logger_event.stop(timer);

        Ok((
            compiler_state,
            WatchmanFileSourceSubscription::new(self.resolved_root.clone(), subscription),
        ))
    }

    /// Internal method to issue a watchman query, returning a raw
    /// WatchmanFileSourceResult.
    async fn query_file_result(
        &self,
        since_clock: Option<Clock>,
        perf_logger_event: &impl PerfLogEvent,
    ) -> Result<FileSourceResult> {
        let expression = get_watchman_expr(&self.config);
        debug!(
            "WatchmanFileSource::query_file_result(...) get_watchman_expr = {:?}",
            &expression
        );

        let query_timer = perf_logger_event.start("watchman_query_time");
        // If `since` is available, we should not pass the `path` parameter.
        // Watchman ignores `since` parameter if both `path` and `since` are
        // passed as the request params
        let request = if since_clock.is_some() {
            QueryRequestCommon {
                expression: Some(expression),
                since: since_clock,
                ..Default::default()
            }
        } else {
            let query_roots = get_all_roots(&self.config)
                .into_iter()
                .map(PathGeneratorElement::RecursivePath)
                .collect();
            QueryRequestCommon {
                expression: Some(expression),
                path: Some(query_roots),
                ..Default::default()
            }
        };
        debug!(
            "WatchmanFileSource::query_file_result(...) request = {:?}",
            &request
        );
        let query_result = self
            .client
            .query::<WatchmanFile>(&self.resolved_root, request)
            .await?;
        perf_logger_event.stop(query_timer);

        // print debug information for this result
        // (file list will include only files with specified extension)
        debug_query_results(&query_result, "graphql");

        let files = query_result.files.ok_or(Error::EmptyQueryResult)?;
        Ok(FileSourceResult::Watchman(WatchmanFileSourceResult {
            files,
            resolved_root: self.resolved_root.clone(),
            clock: query_result.clock,
            saved_state_info: query_result.saved_state_info,
        }))
    }

    /// Tries to load saved state with a watchman query.
    /// The return value is a nested Result:
    /// The outer Result indicates the result of a possible saved state infrastructure failure.
    /// The inner Result is a potential parse error.
    async fn try_saved_state(
        &self,
        perf_logger: &impl PerfLogger,
        perf_logger_event: &impl PerfLogEvent,
        saved_state_config: ScmAwareClockData,
        saved_state_loader: &'_ (dyn SavedStateLoader + Send + Sync),
        saved_state_version: &str,
    ) -> std::result::Result<Result<CompilerState>, &'static str> {
        let scm_since = Clock::ScmAware(FatClockData {
            clock: ClockSpec::null(),
            scm: Some(saved_state_config),
        });
        debug!(
            "WatchmanFileSource::try_saved_state(...) scm_since = {:?}",
            &scm_since
        );
        let file_source_result = self
            .query_file_result(Some(scm_since), perf_logger_event)
            .await
            .map_err(|_| "query failed")?;
        debug!(
            "WatchmanFileSource::try_saved_state(...) file_source_result = {:?}",
            &file_source_result
        );
        let saved_state_info = file_source_result
            .saved_state_info()
            .as_ref()
            .ok_or("no saved state in watchman response")?;
        debug!(
            "WatchmanFileSource::saved_state_info(...) file_source_result = {:?}",
            &saved_state_info
        );
        let saved_state_path = perf_logger_event.time("saved_state_loading_time", || {
            saved_state_loader
                .load(&saved_state_info, self.config)
                .ok_or("unable to load")
        })?;
        let mut compiler_state = perf_logger_event
            .time("deserialize_saved_state", || {
                CompilerState::deserialize_from_file(&saved_state_path)
            })
            .map_err(|err| {
                let error_event = perf_logger.create_event("saved_state_loader_error");
                error_event.string("error", format!("Failed to deserialize: {}", err));
                perf_logger.complete_event(error_event);
                perf_logger.flush();
                "failed to deserialize"
            })?;
        // For cases, where we want to debug saved state integration, that doesn't include
        // saved_state format changes we may need to disable this by adding this env variable
        if std::env::var("RELAY_COMPILER_IGNORE_SAVED_STATE_VERSION").is_err()
            && compiler_state.saved_state_version != saved_state_version
        {
            return Err("Saved state version doesn't match.");
        }
        compiler_state
            .pending_file_source_changes
            .write()
            .unwrap()
            .push(file_source_result);
        if let Err(parse_error) = perf_logger_event.time("merge_file_source_changes", || {
            compiler_state.merge_file_source_changes(
                &self.config,
                perf_logger_event,
                perf_logger,
                true,
            )
        }) {
            Ok(Err(parse_error))
        } else {
            Ok(Ok(compiler_state))
        }
    }
}

pub struct WatchmanFileSourceSubscription {
    resolved_root: ResolvedRoot,
    subscription: WatchmanSubscription<WatchmanFile>,
    base_revision: String,
}

impl WatchmanFileSourceSubscription {
    fn new(resolved_root: ResolvedRoot, subscription: WatchmanSubscription<WatchmanFile>) -> Self {
        Self {
            resolved_root,
            subscription,
            base_revision: get_base_revision(None),
        }
    }

    /// Awaits changes from Watchman and provides the next set of changes
    /// if there were any changes to files
    pub async fn next_change(&mut self) -> Result<FileSourceSubscriptionNextChange> {
        match self.subscription.next().await? {
            SubscriptionData::FilesChanged(changes) => {
                if let Some(files) = changes.files {
                    debug!("number of files in this update: {}", files.len());
                    return Ok(FileSourceSubscriptionNextChange::Result(
                        FileSourceResult::Watchman(WatchmanFileSourceResult {
                            files,
                            resolved_root: self.resolved_root.clone(),
                            clock: changes.clock,
                            saved_state_info: None,
                        }),
                    ));
                }
            }
            SubscriptionData::StateEnter { state_name, .. } => {
                if state_name == "hg.update" {
                    return Ok(FileSourceSubscriptionNextChange::SourceControlUpdateEnter);
                }
            }
            SubscriptionData::StateLeave {
                state_name,
                metadata,
            } => {
                if state_name == "hg.update" {
                    let current_commit = if let Some(Value::ByteString(value)) = metadata {
                        Some(value.to_string())
                    } else {
                        None
                    };
                    let current_base_revision = get_base_revision(current_commit);
                    if current_base_revision != self.base_revision {
                        self.base_revision = current_base_revision;
                        return Ok(FileSourceSubscriptionNextChange::SourceControlUpdate);
                    } else {
                        return Ok(FileSourceSubscriptionNextChange::SourceControlUpdateLeave);
                    }
                }
            }
            SubscriptionData::Canceled => {
                return Err(Error::WatchmanSubscriptionCanceled);
            }
        }
        Ok(FileSourceSubscriptionNextChange::None)
    }
}

/// Base revision in this case is a common ancestor of two revisions:
/// `master` and current commit hash or `.`
fn get_base_revision(commit_hash: Option<String>) -> String {
    let output = Command::new("hg")
        .arg("log".to_string())
        .arg("-r".to_string())
        .arg(format!(
            "ancestor(master, {})",
            commit_hash.unwrap_or_else(|| ".".to_string())
        ))
        .arg("-T={node}")
        .output()
        .expect("Expect `hg` command getting base revision.");

    if output.stdout.is_empty() {
        panic!(
            "Failed to get base revision hash:\n {:?}",
            String::from_utf8_lossy(&output.stderr)
        );
    }

    String::from_utf8_lossy(&output.stdout).to_string()
}

fn debug_query_results(query_result: &QueryResult<WatchmanFile>, extension_filter: &str) {
    if let Ok(rust_log) = std::env::var("RUST_LOG") {
        if rust_log == *"debug" {
            debug!(
                "WatchmanFileSource::query_file_result(...) query_result.version = {:?}",
                query_result.version
            );
            debug!(
                "WatchmanFileSource::query_file_result(...) query_result.clock = {:?}",
                query_result.clock
            );
            debug!(
                "WatchmanFileSource::query_file_result(...) query_result.is_fresh_instance = {:?}",
                query_result.is_fresh_instance
            );
            debug!(
                "WatchmanFileSource::query_file_result(...) query_result.saved_state_info = {:?}",
                query_result.saved_state_info
            );
            debug!(
                "WatchmanFileSource::query_file_result(...) query_result.state_metadata = {:?}",
                query_result.state_metadata
            );
            if let Some(files) = &query_result.files {
                debug!(
                    "WatchmanFileSource::query_file_result(...) query_result.files(only=*.{}) = \n{}",
                    extension_filter,
                    files
                        .iter()
                        .filter_map(|file| {
                            if file.name.extension().is_some()
                                && file.name.extension().unwrap() == extension_filter
                            {
                                Some(format!(
                                    "name: {:?}, hash: {:?}, exists: {}",
                                    *file.name, *file.hash, *file.exists
                                ))
                            } else {
                                None
                            }
                        })
                        .collect::<Vec<String>>()
                        .join("\n")
                );
            } else {
                debug!("WatchmanFileSource::query_file_result(...): no files found");
            }
        }
    }
}
<|endoftext|>


<commit_before>use time::macros::offset;
use time::{OffsetDateTime, Result, UtcOffset};

#[test]
fn utc_is_zero() {
    assert_eq!(offset!(UTC), offset!(+0));
}

#[test]
fn from_hms() -> Result<()> {
    assert_eq!(UtcOffset::from_hms(0, 0, 0), Ok(offset!(UTC)));
    assert_eq!(UtcOffset::from_hms(0, 0, 1), Ok(offset!(+0:00:01)));
    assert_eq!(UtcOffset::from_hms(0, 0, -1), Ok(offset!(-0:00:01)));
    assert_eq!(UtcOffset::from_hms(1, 0, 0), Ok(offset!(+1)));
    assert_eq!(UtcOffset::from_hms(-1, 0, 0), Ok(offset!(-1)));
    assert_eq!(UtcOffset::from_hms(23, 59, 0), Ok(offset!(+23:59)));
    assert_eq!(UtcOffset::from_hms(-23, -59, 0), Ok(offset!(-23:59)));
    assert_eq!(UtcOffset::from_hms(23, 59, 59), Ok(offset!(+23:59:59)));
    assert_eq!(UtcOffset::from_hms(-23, -59, -59), Ok(offset!(-23:59:59)));
    assert_eq!(UtcOffset::from_hms(1, 2, 3)?.as_hms(), (1, 2, 3));
    assert_eq!(UtcOffset::from_hms(1, -2, -3)?.as_hms(), (1, 2, 3));
    assert_eq!(UtcOffset::from_hms(0, 2, -3)?.as_hms(), (0, 2, 3));
    Ok(())
}

#[test]
fn from_whole_seconds() {
    assert_eq!(UtcOffset::from_whole_seconds(0), Ok(offset!(UTC)));
    assert_eq!(UtcOffset::from_whole_seconds(1), Ok(offset!(+0:00:01)));
    assert_eq!(UtcOffset::from_whole_seconds(-1), Ok(offset!(-0:00:01)));
    assert_eq!(UtcOffset::from_whole_seconds(3_600), Ok(offset!(+1)));
    assert_eq!(UtcOffset::from_whole_seconds(-3_600), Ok(offset!(-1)));
    assert_eq!(UtcOffset::from_whole_seconds(86_340), Ok(offset!(+23:59)));
    assert_eq!(UtcOffset::from_whole_seconds(-86_340), Ok(offset!(-23:59)));
    assert_eq!(
        UtcOffset::from_whole_seconds(86_399),
        Ok(offset!(+23:59:59))
    );
    assert_eq!(
        UtcOffset::from_whole_seconds(-86_399),
        Ok(offset!(-23:59:59))
    );
}

#[test]
fn as_hms() {
    assert_eq!(offset!(UTC).as_hms(), (0, 0, 0));
    assert_eq!(offset!(+0:00:01).as_hms(), (0, 0, 1));
    assert_eq!(offset!(-0:00:01).as_hms(), (0, 0, -1));
    assert_eq!(offset!(+1).as_hms(), (1, 0, 0));
    assert_eq!(offset!(-1).as_hms(), (-1, 0, 0));
    assert_eq!(offset!(+23:59).as_hms(), (23, 59, 0));
    assert_eq!(offset!(-23:59).as_hms(), (-23, -59, 0));
    assert_eq!(offset!(+23:59:59).as_hms(), (23, 59, 59));
    assert_eq!(offset!(-23:59:59).as_hms(), (-23, -59, -59));
}

#[test]
fn whole_hours() {
    assert_eq!(offset!(+1:02:03).whole_hours(), 1);
    assert_eq!(offset!(-1:02:03).whole_hours(), -1);
}

#[test]
fn whole_minutes() {
    assert_eq!(offset!(+1:02:03).whole_minutes(), 62);
    assert_eq!(offset!(-1:02:03).whole_minutes(), -62);
}

#[test]
fn minutes_past_hour() {
    assert_eq!(offset!(+1:02:03).minutes_past_hour(), 2);
    assert_eq!(offset!(-1:02:03).minutes_past_hour(), -2);
}

#[test]
fn whole_seconds() {
    assert_eq!(offset!(UTC).whole_seconds(), 0);
    assert_eq!(offset!(+0:00:01).whole_seconds(), 1);
    assert_eq!(offset!(-0:00:01).whole_seconds(), -1);
    assert_eq!(offset!(+1).whole_seconds(), 3_600);
    assert_eq!(offset!(-1).whole_seconds(), -3_600);
    assert_eq!(offset!(+23:59).whole_seconds(), 86_340);
    assert_eq!(offset!(-23:59).whole_seconds(), -86_340);
    assert_eq!(offset!(+23:59:59).whole_seconds(), 86_399);
    assert_eq!(offset!(-23:59:59).whole_seconds(), -86_399);
}

#[test]
fn seconds_past_minute() {
    assert_eq!(offset!(+1:02:03).seconds_past_minute(), 3);
    assert_eq!(offset!(-1:02:03).seconds_past_minute(), -3);
}

#[test]
fn is_utc() {
    assert!(offset!(UTC).is_utc());
    assert!(!offset!(+0:00:01).is_utc());
    assert!(!offset!(-0:00:01).is_utc());
    assert!(!offset!(+1).is_utc());
    assert!(!offset!(-1).is_utc());
    assert!(!offset!(+23:59).is_utc());
    assert!(!offset!(-23:59).is_utc());
    assert!(!offset!(+23:59:59).is_utc());
    assert!(!offset!(-23:59:59).is_utc());
}

#[test]
fn is_positive() {
    assert!(!offset!(UTC).is_positive());
    assert!(offset!(+0:00:01).is_positive());
    assert!(!offset!(-0:00:01).is_positive());
    assert!(offset!(+1).is_positive());
    assert!(!offset!(-1).is_positive());
    assert!(offset!(+23:59).is_positive());
    assert!(!offset!(-23:59).is_positive());
    assert!(offset!(+23:59:59).is_positive());
    assert!(!offset!(-23:59:59).is_positive());
}

#[test]
fn is_negative() {
    assert!(!offset!(UTC).is_negative());
    assert!(!offset!(+0:00:01).is_negative());
    assert!(offset!(-0:00:01).is_negative());
    assert!(!offset!(+1).is_negative());
    assert!(offset!(-1).is_negative());
    assert!(!offset!(+23:59).is_negative());
    assert!(offset!(-23:59).is_negative());
    assert!(!offset!(+23:59:59).is_negative());
    assert!(offset!(-23:59:59).is_negative());
}

#[test]
fn neg() {
    assert_eq!(-offset!(UTC), offset!(UTC));
    assert_eq!(-offset!(+0:00:01), offset!(-0:00:01));
    assert_eq!(-offset!(-0:00:01), offset!(+0:00:01));
    assert_eq!(-offset!(+1), offset!(-1));
    assert_eq!(-offset!(-1), offset!(+1));
    assert_eq!(-offset!(+23:59), offset!(-23:59));
    assert_eq!(-offset!(-23:59), offset!(+23:59));
    assert_eq!(-offset!(+23:59:59), offset!(-23:59:59));
    assert_eq!(-offset!(-23:59:59), offset!(+23:59:59));
}

#[test]
fn local_offset_at() {
    #[cfg(not(target_family = "unix"))]
    assert!(UtcOffset::local_offset_at(OffsetDateTime::UNIX_EPOCH).is_ok());

    #[cfg(target_family = "unix")]
    let _ = UtcOffset::local_offset_at(OffsetDateTime::UNIX_EPOCH);
}

#[test]
fn current_local_offset() {
    #[cfg(not(target_family = "unix"))]
    assert!(UtcOffset::current_local_offset().is_ok());

    #[cfg(target_family = "unix")]
    let _ = UtcOffset::current_local_offset();
}
<commit_msg>Add test for multithreaded Unix systems<commit_after>use time::macros::offset;
use time::{OffsetDateTime, Result, UtcOffset};

#[test]
fn utc_is_zero() {
    assert_eq!(offset!(UTC), offset!(+0));
}

#[test]
fn from_hms() -> Result<()> {
    assert_eq!(UtcOffset::from_hms(0, 0, 0), Ok(offset!(UTC)));
    assert_eq!(UtcOffset::from_hms(0, 0, 1), Ok(offset!(+0:00:01)));
    assert_eq!(UtcOffset::from_hms(0, 0, -1), Ok(offset!(-0:00:01)));
    assert_eq!(UtcOffset::from_hms(1, 0, 0), Ok(offset!(+1)));
    assert_eq!(UtcOffset::from_hms(-1, 0, 0), Ok(offset!(-1)));
    assert_eq!(UtcOffset::from_hms(23, 59, 0), Ok(offset!(+23:59)));
    assert_eq!(UtcOffset::from_hms(-23, -59, 0), Ok(offset!(-23:59)));
    assert_eq!(UtcOffset::from_hms(23, 59, 59), Ok(offset!(+23:59:59)));
    assert_eq!(UtcOffset::from_hms(-23, -59, -59), Ok(offset!(-23:59:59)));
    assert_eq!(UtcOffset::from_hms(1, 2, 3)?.as_hms(), (1, 2, 3));
    assert_eq!(UtcOffset::from_hms(1, -2, -3)?.as_hms(), (1, 2, 3));
    assert_eq!(UtcOffset::from_hms(0, 2, -3)?.as_hms(), (0, 2, 3));
    Ok(())
}

#[test]
fn from_whole_seconds() {
    assert_eq!(UtcOffset::from_whole_seconds(0), Ok(offset!(UTC)));
    assert_eq!(UtcOffset::from_whole_seconds(1), Ok(offset!(+0:00:01)));
    assert_eq!(UtcOffset::from_whole_seconds(-1), Ok(offset!(-0:00:01)));
    assert_eq!(UtcOffset::from_whole_seconds(3_600), Ok(offset!(+1)));
    assert_eq!(UtcOffset::from_whole_seconds(-3_600), Ok(offset!(-1)));
    assert_eq!(UtcOffset::from_whole_seconds(86_340), Ok(offset!(+23:59)));
    assert_eq!(UtcOffset::from_whole_seconds(-86_340), Ok(offset!(-23:59)));
    assert_eq!(
        UtcOffset::from_whole_seconds(86_399),
        Ok(offset!(+23:59:59))
    );
    assert_eq!(
        UtcOffset::from_whole_seconds(-86_399),
        Ok(offset!(-23:59:59))
    );
}

#[test]
fn as_hms() {
    assert_eq!(offset!(UTC).as_hms(), (0, 0, 0));
    assert_eq!(offset!(+0:00:01).as_hms(), (0, 0, 1));
    assert_eq!(offset!(-0:00:01).as_hms(), (0, 0, -1));
    assert_eq!(offset!(+1).as_hms(), (1, 0, 0));
    assert_eq!(offset!(-1).as_hms(), (-1, 0, 0));
    assert_eq!(offset!(+23:59).as_hms(), (23, 59, 0));
    assert_eq!(offset!(-23:59).as_hms(), (-23, -59, 0));
    assert_eq!(offset!(+23:59:59).as_hms(), (23, 59, 59));
    assert_eq!(offset!(-23:59:59).as_hms(), (-23, -59, -59));
}

#[test]
fn whole_hours() {
    assert_eq!(offset!(+1:02:03).whole_hours(), 1);
    assert_eq!(offset!(-1:02:03).whole_hours(), -1);
}

#[test]
fn whole_minutes() {
    assert_eq!(offset!(+1:02:03).whole_minutes(), 62);
    assert_eq!(offset!(-1:02:03).whole_minutes(), -62);
}

#[test]
fn minutes_past_hour() {
    assert_eq!(offset!(+1:02:03).minutes_past_hour(), 2);
    assert_eq!(offset!(-1:02:03).minutes_past_hour(), -2);
}

#[test]
fn whole_seconds() {
    assert_eq!(offset!(UTC).whole_seconds(), 0);
    assert_eq!(offset!(+0:00:01).whole_seconds(), 1);
    assert_eq!(offset!(-0:00:01).whole_seconds(), -1);
    assert_eq!(offset!(+1).whole_seconds(), 3_600);
    assert_eq!(offset!(-1).whole_seconds(), -3_600);
    assert_eq!(offset!(+23:59).whole_seconds(), 86_340);
    assert_eq!(offset!(-23:59).whole_seconds(), -86_340);
    assert_eq!(offset!(+23:59:59).whole_seconds(), 86_399);
    assert_eq!(offset!(-23:59:59).whole_seconds(), -86_399);
}

#[test]
fn seconds_past_minute() {
    assert_eq!(offset!(+1:02:03).seconds_past_minute(), 3);
    assert_eq!(offset!(-1:02:03).seconds_past_minute(), -3);
}

#[test]
fn is_utc() {
    assert!(offset!(UTC).is_utc());
    assert!(!offset!(+0:00:01).is_utc());
    assert!(!offset!(-0:00:01).is_utc());
    assert!(!offset!(+1).is_utc());
    assert!(!offset!(-1).is_utc());
    assert!(!offset!(+23:59).is_utc());
    assert!(!offset!(-23:59).is_utc());
    assert!(!offset!(+23:59:59).is_utc());
    assert!(!offset!(-23:59:59).is_utc());
}

#[test]
fn is_positive() {
    assert!(!offset!(UTC).is_positive());
    assert!(offset!(+0:00:01).is_positive());
    assert!(!offset!(-0:00:01).is_positive());
    assert!(offset!(+1).is_positive());
    assert!(!offset!(-1).is_positive());
    assert!(offset!(+23:59).is_positive());
    assert!(!offset!(-23:59).is_positive());
    assert!(offset!(+23:59:59).is_positive());
    assert!(!offset!(-23:59:59).is_positive());
}

#[test]
fn is_negative() {
    assert!(!offset!(UTC).is_negative());
    assert!(!offset!(+0:00:01).is_negative());
    assert!(offset!(-0:00:01).is_negative());
    assert!(!offset!(+1).is_negative());
    assert!(offset!(-1).is_negative());
    assert!(!offset!(+23:59).is_negative());
    assert!(offset!(-23:59).is_negative());
    assert!(!offset!(+23:59:59).is_negative());
    assert!(offset!(-23:59:59).is_negative());
}

#[test]
fn neg() {
    assert_eq!(-offset!(UTC), offset!(UTC));
    assert_eq!(-offset!(+0:00:01), offset!(-0:00:01));
    assert_eq!(-offset!(-0:00:01), offset!(+0:00:01));
    assert_eq!(-offset!(+1), offset!(-1));
    assert_eq!(-offset!(-1), offset!(+1));
    assert_eq!(-offset!(+23:59), offset!(-23:59));
    assert_eq!(-offset!(-23:59), offset!(+23:59));
    assert_eq!(-offset!(+23:59:59), offset!(-23:59:59));
    assert_eq!(-offset!(-23:59:59), offset!(+23:59:59));
}

#[test]
fn local_offset_at() {
    #[cfg(not(target_family = "unix"))]
    assert!(UtcOffset::local_offset_at(OffsetDateTime::UNIX_EPOCH).is_ok());

    #[cfg(target_family = "unix")]
    let _ = UtcOffset::local_offset_at(OffsetDateTime::UNIX_EPOCH);
}

#[test]
fn current_local_offset() {
    #[cfg(not(target_family = "unix"))]
    assert!(UtcOffset::current_local_offset().is_ok());

    #[cfg(target_family = "unix")]
    let _ = UtcOffset::current_local_offset();
}

#[test]
#[cfg(target_family = "unix")]
fn local_offset_error_when_multithreaded() {
    std::thread::spawn(|| {
        assert!(UtcOffset::current_local_offset().is_err());
    })
    .join()
    .expect("failed to join thread");
}
<|endoftext|>


<commit_before>use {channel, Handler, Evented, Poll, NotifyError, Token};
use event::{Event, EventSet, PollOpt};
use timer::{self, Timer, Timeout};
use std::{io, fmt, usize};
use std::sync::mpsc;
use std::default::Default;
use std::time::Duration;

#[derive(Debug, Default, Clone)]
pub struct EventLoopBuilder {
    config: Config,
}

/// `EventLoop` configuration details
#[derive(Clone, Debug)]
struct Config {
    // == Notifications ==
    notify_capacity: usize,
    messages_per_tick: usize,

    // == Timer ==
    timer_tick: Duration,
    timer_wheel_size: usize,
    timer_capacity: usize,
}

impl Default for Config {
    fn default() -> Config {
        // Default EventLoop configuration values
        Config {
            notify_capacity: 4_096,
            messages_per_tick: 256,
            timer_tick: Duration::from_millis(100),
            timer_wheel_size: 1_024,
            timer_capacity: 65_536,
        }
    }
}

impl EventLoopBuilder {
    /// Construct a new `EventLoopBuilder` with the default configuration
    /// values.
    pub fn new() -> EventLoopBuilder {
        EventLoopBuilder::default()
    }

    /// Sets the maximum number of messages that can be buffered on the event
    /// loop's notification channel before a send will fail.
    ///
    /// The default value for this is 4096.
    pub fn notify_capacity(&mut self, capacity: usize) -> &mut Self {
        self.config.notify_capacity = capacity;
        self
    }

    /// Sets the maximum number of messages that can be processed on any tick of
    /// the event loop.
    ///
    /// The default value for this is 256.
    pub fn messages_per_tick(&mut self, messages: usize) -> &mut Self {
        self.config.messages_per_tick = messages;
        self
    }

    pub fn timer_tick(&mut self, val: Duration) -> &mut Self {
        self.config.timer_tick = val;
        self
    }

    pub fn timer_wheel_size(&mut self, size: usize) -> &mut Self {
        self.config.timer_wheel_size = size;
        self
    }

    pub fn timer_capacity(&mut self, cap: usize) -> &mut Self {
        self.config.timer_capacity = cap;
        self
    }

    /// Constructs a new `EventLoop` using the configured values. The
    /// `EventLoop` will not be running.
    pub fn build<H: Handler>(self) -> io::Result<EventLoop<H>> {
        EventLoop::configured(self.config)
    }
}

/// Single threaded IO event loop.
pub struct EventLoop<H: Handler> {
    run: bool,
    poll: Poll,
    timer: Timer<H::Timeout>,
    notify_tx: channel::Sender<H::Message>,
    notify_rx: channel::Receiver<H::Message>,
    config: Config,
}

// Token used to represent notifications
const NOTIFY: Token = Token(usize::MAX - 1);
const TIMER: Token = Token(usize::MAX - 2);

impl<H: Handler> EventLoop<H> {

    /// Constructs a new `EventLoop` using the default configuration values.
    /// The `EventLoop` will not be running.
    pub fn new() -> io::Result<EventLoop<H>> {
        EventLoop::configured(Config::default())
    }

    fn configured(config: Config) -> io::Result<EventLoop<H>> {
        // Create the IO poller
        let poll = try!(Poll::new());

        let timer = timer::Builder::default()
            .tick_duration(config.timer_tick)
            .num_slots(config.timer_wheel_size)
            .capacity(config.timer_capacity)
            .build();

        // Create cross thread notification queue
        let (tx, rx) = channel::from_std_sync_channel(mpsc::sync_channel(config.notify_capacity));

        // Register the notification wakeup FD with the IO poller
        try!(poll.register(&rx, NOTIFY, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()));
        try!(poll.register(&timer, TIMER, EventSet::readable(), PollOpt::edge()));

        Ok(EventLoop {
            run: true,
            poll: poll,
            timer: timer,
            notify_tx: tx,
            notify_rx: rx,
            config: config,
        })
    }

    /// Returns a sender that allows sending messages to the event loop in a
    /// thread-safe way, waking up the event loop if needed.
    ///
    /// # Example
    /// ```
    /// use std::thread;
    /// use mio::{EventLoop, Handler};
    ///
    /// struct MyHandler;
    ///
    /// impl Handler for MyHandler {
    ///     type Timeout = ();
    ///     type Message = u32;
    ///
    ///     fn notify(&mut self, event_loop: &mut EventLoop<MyHandler>, msg: u32) {
    ///         assert_eq!(msg, 123);
    ///         event_loop.shutdown();
    ///     }
    /// }
    ///
    /// let mut event_loop = EventLoop::new().unwrap();
    /// let sender = event_loop.channel();
    ///
    /// // Send the notification from another thread
    /// thread::spawn(move || {
    ///     let _ = sender.send(123);
    /// });
    ///
    /// let _ = event_loop.run(&mut MyHandler);
    /// ```
    ///
    /// # Implementation Details
    ///
    /// Each [EventLoop](#) contains a lock-free queue with a pre-allocated
    /// buffer size. The size can be changed by modifying
    /// [EventLoopConfig.notify_capacity](struct.EventLoopConfig.html#method.notify_capacity).
    /// When a message is sent to the EventLoop, it is first pushed on to the
    /// queue. Then, if the EventLoop is currently running, an atomic flag is
    /// set to indicate that the next loop iteration should be started without
    /// waiting.
    ///
    /// If the loop is blocked waiting for IO events, then it is woken up. The
    /// strategy for waking up the event loop is platform dependent. For
    /// example, on a modern Linux OS, eventfd is used. On older OSes, a pipe
    /// is used.
    ///
    /// The strategy of setting an atomic flag if the event loop is not already
    /// sleeping allows avoiding an expensive wakeup operation if at all possible.
    pub fn channel(&self) -> Sender<H::Message> {
        Sender::new(self.notify_tx.clone())
    }

    /// Schedules a timeout after the requested time interval. When the
    /// duration has been reached,
    /// [Handler::timeout](trait.Handler.html#method.timeout) will be invoked
    /// passing in the supplied token.
    ///
    /// Returns a handle to the timeout that can be used to cancel the timeout
    /// using [#clear_timeout](#method.clear_timeout).
    ///
    /// # Example
    /// ```
    /// use mio::{EventLoop, Handler};
    /// use std::time::Duration;
    ///
    /// struct MyHandler;
    ///
    /// impl Handler for MyHandler {
    ///     type Timeout = u32;
    ///     type Message = ();
    ///
    ///     fn timeout(&mut self, event_loop: &mut EventLoop<MyHandler>, timeout: u32) {
    ///         assert_eq!(timeout, 123);
    ///         event_loop.shutdown();
    ///     }
    /// }
    ///
    ///
    /// let mut event_loop = EventLoop::new().unwrap();
    /// let timeout = event_loop.timeout(123, Duration::from_millis(300)).unwrap();
    /// let _ = event_loop.run(&mut MyHandler);
    /// ```
    pub fn timeout(&mut self, token: H::Timeout, delay: Duration) -> timer::Result<Timeout> {
        self.timer.set_timeout(delay, token)
    }

    /// If the supplied timeout has not been triggered, cancel it such that it
    /// will not be triggered in the future.
    pub fn clear_timeout(&mut self, timeout: &Timeout) -> bool {
        self.timer.cancel_timeout(&timeout).is_some()
    }

    /// Tells the event loop to exit after it is done handling all events in the
    /// current iteration.
    pub fn shutdown(&mut self) {
        self.run = false;
    }

    /// Indicates whether the event loop is currently running. If it's not it has either
    /// stopped or is scheduled to stop on the next tick.
    pub fn is_running(&self) -> bool {
        self.run
    }

    /// Registers an IO handle with the event loop.
    pub fn register<E: ?Sized>(&mut self, io: &E, token: Token, interest: EventSet, opt: PollOpt) -> io::Result<()>
        where E: Evented
    {
        self.poll.register(io, token, interest, opt)
    }

    /// Re-Registers an IO handle with the event loop.
    pub fn reregister<E: ?Sized>(&mut self, io: &E, token: Token, interest: EventSet, opt: PollOpt) -> io::Result<()>
        where E: Evented
    {
        self.poll.reregister(io, token, interest, opt)
    }

    /// Keep spinning the event loop indefinitely, and notify the handler whenever
    /// any of the registered handles are ready.
    pub fn run(&mut self, handler: &mut H) -> io::Result<()> {
        self.run = true;

        while self.run {
            // Execute ticks as long as the event loop is running
            try!(self.run_once(handler, None));
        }

        Ok(())
    }

    /// Deregisters an IO handle with the event loop.
    pub fn deregister<E: ?Sized>(&mut self, io: &E) -> io::Result<()> where E: Evented {
        self.poll.deregister(io)
    }

    /// Spin the event loop once, with a timeout of one second, and notify the
    /// handler if any of the registered handles become ready during that
    /// time.
    pub fn run_once(&mut self, handler: &mut H, timeout: Option<Duration>) -> io::Result<()> {
        trace!("event loop tick");

        // Check the registered IO handles for any new events. Each poll
        // is for one second, so a shutdown request can last as long as
        // one second before it takes effect.
        let events = match self.io_poll(timeout) {
            Ok(e) => e,
            Err(err) => {
                if err.kind() == io::ErrorKind::Interrupted {
                    handler.interrupted(self);
                    0
                } else {
                    return Err(err);
                }
            }
        };

        self.io_process(handler, events);
        handler.tick(self);
        Ok(())
    }

    #[inline]
    fn io_poll(&mut self, timeout: Option<Duration>) -> io::Result<usize> {
        self.poll.poll(timeout)
    }

    // Process IO events that have been previously polled
    fn io_process(&mut self, handler: &mut H, cnt: usize) {
        let mut i = 0;

        trace!("io_process(..); cnt={}; len={}", cnt, self.poll.events().len());

        // Iterate over the notifications. Each event provides the token
        // it was registered with (which usually represents, at least, the
        // handle that the event is about) as well as information about
        // what kind of event occurred (readable, writable, signal, etc.)
        while i < cnt {
            let evt = self.poll.events().get(i).unwrap();

            trace!("event={:?}; idx={:?}", evt, i);

            match evt.token() {
                NOTIFY => self.notify(handler),
                TIMER => self.timer_process(handler),
                _ => self.io_event(handler, evt)
            }

            i += 1;
        }
    }

    fn io_event(&mut self, handler: &mut H, evt: Event) {
        handler.ready(self, evt.token(), evt.kind());
    }

    fn notify(&mut self, handler: &mut H) {
        for _ in 0..self.config.messages_per_tick {
            match self.notify_rx.try_recv() {
                Ok(msg) => handler.notify(self, msg),
                _ => break,
            }
        }

        // Re-register
        let _ = self.poll.reregister(&self.notify_rx, NOTIFY, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot());
    }

    fn timer_process(&mut self, handler: &mut H) {
        while let Some(t) = self.timer.poll() {
            handler.timeout(self, t);
        }
    }
}

impl<H: Handler> fmt::Debug for EventLoop<H> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("EventLoop")
            .field("run", &self.run)
            .field("poll", &self.poll)
            .field("config", &self.config)
            .finish()
    }
}

/// Sends messages to the EventLoop from other threads.
pub struct Sender<M> {
    tx: channel::Sender<M>
}

impl<M> fmt::Debug for Sender<M> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "Sender<?> {{ ... }}")
    }
}

impl<M> Sender<M> {
    fn new(tx: channel::Sender<M>) -> Sender<M> {
        Sender { tx: tx }
    }

    pub fn send(&self, msg: M) -> Result<(), NotifyError<M>> {
        try!(self.tx.try_send(msg));
        Ok(())
    }
}

#[cfg(test)]
#[cfg(unix)]
mod tests {
    use {unix, EventLoop, Handler, Token, TryRead, TryWrite, EventSet, PollOpt};
    use bytes::{Buf, SliceBuf, ByteBuf};
    use std::str;
    use std::sync::Arc;
    use std::sync::atomic::AtomicIsize;
    use std::sync::atomic::Ordering::SeqCst;
    use std::time::Duration;

    struct Funtimes {
        rcount: Arc<AtomicIsize>,
        wcount: Arc<AtomicIsize>
    }

    impl Funtimes {
        fn new(rcount: Arc<AtomicIsize>, wcount: Arc<AtomicIsize>) -> Funtimes {
            Funtimes {
                rcount: rcount,
                wcount: wcount
            }
        }
    }

    impl Handler for Funtimes {
        type Timeout = usize;
        type Message = ();

        fn ready(&mut self, _event_loop: &mut EventLoop<Funtimes>, token: Token, events: EventSet) {
            if events.is_readable() {
                (*self.rcount).fetch_add(1, SeqCst);
                assert_eq!(token, Token(10));
            }

            if events.is_writable() {
                (*self.wcount).fetch_add(1, SeqCst);
                assert_eq!(token, Token(10));
            }
        }
    }

    #[test]
    pub fn test_readable() {
        let mut event_loop = EventLoop::new().ok().expect("Couldn't make event loop");

        let (mut reader, mut writer) = unix::pipe().unwrap();

        let rcount = Arc::new(AtomicIsize::new(0));
        let wcount = Arc::new(AtomicIsize::new(0));
        let mut handler = Funtimes::new(rcount.clone(), wcount.clone());

        writer.try_write_buf(&mut SliceBuf::wrap(b"hello")).unwrap();
        event_loop.register(&reader, Token(10), EventSet::readable(),
                            PollOpt::edge()).unwrap();

        let _ = event_loop.run_once(&mut handler, None);
        let mut b = ByteBuf::mut_with_capacity(16);

        assert_eq!((*rcount).load(SeqCst), 1);

        reader.try_read_buf(&mut b).unwrap();

        assert_eq!(str::from_utf8(b.flip().bytes()).unwrap(), "hello");
    }

    pub struct BrokenPipeHandler;

    impl Handler for BrokenPipeHandler {
        type Timeout = ();
        type Message = ();
        fn ready(&mut self, _: &mut EventLoop<Self>, token: Token, _: EventSet) {
            if token == Token(1) {
                panic!("Received ready() on a closed pipe.");
            }
        }
    }

    #[test]
    pub fn broken_pipe() {
        let mut event_loop: EventLoop<BrokenPipeHandler> = EventLoop::new().unwrap();
        let (reader, _) = unix::pipe().unwrap();

        // On Darwin this returns a "broken pipe" error.
        let _ = event_loop.register(&reader, Token(1), EventSet::all(), PollOpt::edge());

        let mut handler = BrokenPipeHandler;
        drop(reader);
        event_loop.run_once(&mut handler, Some(Duration::from_millis(1000))).unwrap();
    }
}
<commit_msg>Document deregister behavior<commit_after>use {channel, Handler, Evented, Poll, NotifyError, Token};
use event::{Event, EventSet, PollOpt};
use timer::{self, Timer, Timeout};
use std::{io, fmt, usize};
use std::sync::mpsc;
use std::default::Default;
use std::time::Duration;

#[derive(Debug, Default, Clone)]
pub struct EventLoopBuilder {
    config: Config,
}

/// `EventLoop` configuration details
#[derive(Clone, Debug)]
struct Config {
    // == Notifications ==
    notify_capacity: usize,
    messages_per_tick: usize,

    // == Timer ==
    timer_tick: Duration,
    timer_wheel_size: usize,
    timer_capacity: usize,
}

impl Default for Config {
    fn default() -> Config {
        // Default EventLoop configuration values
        Config {
            notify_capacity: 4_096,
            messages_per_tick: 256,
            timer_tick: Duration::from_millis(100),
            timer_wheel_size: 1_024,
            timer_capacity: 65_536,
        }
    }
}

impl EventLoopBuilder {
    /// Construct a new `EventLoopBuilder` with the default configuration
    /// values.
    pub fn new() -> EventLoopBuilder {
        EventLoopBuilder::default()
    }

    /// Sets the maximum number of messages that can be buffered on the event
    /// loop's notification channel before a send will fail.
    ///
    /// The default value for this is 4096.
    pub fn notify_capacity(&mut self, capacity: usize) -> &mut Self {
        self.config.notify_capacity = capacity;
        self
    }

    /// Sets the maximum number of messages that can be processed on any tick of
    /// the event loop.
    ///
    /// The default value for this is 256.
    pub fn messages_per_tick(&mut self, messages: usize) -> &mut Self {
        self.config.messages_per_tick = messages;
        self
    }

    pub fn timer_tick(&mut self, val: Duration) -> &mut Self {
        self.config.timer_tick = val;
        self
    }

    pub fn timer_wheel_size(&mut self, size: usize) -> &mut Self {
        self.config.timer_wheel_size = size;
        self
    }

    pub fn timer_capacity(&mut self, cap: usize) -> &mut Self {
        self.config.timer_capacity = cap;
        self
    }

    /// Constructs a new `EventLoop` using the configured values. The
    /// `EventLoop` will not be running.
    pub fn build<H: Handler>(self) -> io::Result<EventLoop<H>> {
        EventLoop::configured(self.config)
    }
}

/// Single threaded IO event loop.
pub struct EventLoop<H: Handler> {
    run: bool,
    poll: Poll,
    timer: Timer<H::Timeout>,
    notify_tx: channel::Sender<H::Message>,
    notify_rx: channel::Receiver<H::Message>,
    config: Config,
}

// Token used to represent notifications
const NOTIFY: Token = Token(usize::MAX - 1);
const TIMER: Token = Token(usize::MAX - 2);

impl<H: Handler> EventLoop<H> {

    /// Constructs a new `EventLoop` using the default configuration values.
    /// The `EventLoop` will not be running.
    pub fn new() -> io::Result<EventLoop<H>> {
        EventLoop::configured(Config::default())
    }

    fn configured(config: Config) -> io::Result<EventLoop<H>> {
        // Create the IO poller
        let poll = try!(Poll::new());

        let timer = timer::Builder::default()
            .tick_duration(config.timer_tick)
            .num_slots(config.timer_wheel_size)
            .capacity(config.timer_capacity)
            .build();

        // Create cross thread notification queue
        let (tx, rx) = channel::from_std_sync_channel(mpsc::sync_channel(config.notify_capacity));

        // Register the notification wakeup FD with the IO poller
        try!(poll.register(&rx, NOTIFY, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()));
        try!(poll.register(&timer, TIMER, EventSet::readable(), PollOpt::edge()));

        Ok(EventLoop {
            run: true,
            poll: poll,
            timer: timer,
            notify_tx: tx,
            notify_rx: rx,
            config: config,
        })
    }

    /// Returns a sender that allows sending messages to the event loop in a
    /// thread-safe way, waking up the event loop if needed.
    ///
    /// # Example
    /// ```
    /// use std::thread;
    /// use mio::{EventLoop, Handler};
    ///
    /// struct MyHandler;
    ///
    /// impl Handler for MyHandler {
    ///     type Timeout = ();
    ///     type Message = u32;
    ///
    ///     fn notify(&mut self, event_loop: &mut EventLoop<MyHandler>, msg: u32) {
    ///         assert_eq!(msg, 123);
    ///         event_loop.shutdown();
    ///     }
    /// }
    ///
    /// let mut event_loop = EventLoop::new().unwrap();
    /// let sender = event_loop.channel();
    ///
    /// // Send the notification from another thread
    /// thread::spawn(move || {
    ///     let _ = sender.send(123);
    /// });
    ///
    /// let _ = event_loop.run(&mut MyHandler);
    /// ```
    ///
    /// # Implementation Details
    ///
    /// Each [EventLoop](#) contains a lock-free queue with a pre-allocated
    /// buffer size. The size can be changed by modifying
    /// [EventLoopConfig.notify_capacity](struct.EventLoopConfig.html#method.notify_capacity).
    /// When a message is sent to the EventLoop, it is first pushed on to the
    /// queue. Then, if the EventLoop is currently running, an atomic flag is
    /// set to indicate that the next loop iteration should be started without
    /// waiting.
    ///
    /// If the loop is blocked waiting for IO events, then it is woken up. The
    /// strategy for waking up the event loop is platform dependent. For
    /// example, on a modern Linux OS, eventfd is used. On older OSes, a pipe
    /// is used.
    ///
    /// The strategy of setting an atomic flag if the event loop is not already
    /// sleeping allows avoiding an expensive wakeup operation if at all possible.
    pub fn channel(&self) -> Sender<H::Message> {
        Sender::new(self.notify_tx.clone())
    }

    /// Schedules a timeout after the requested time interval. When the
    /// duration has been reached,
    /// [Handler::timeout](trait.Handler.html#method.timeout) will be invoked
    /// passing in the supplied token.
    ///
    /// Returns a handle to the timeout that can be used to cancel the timeout
    /// using [#clear_timeout](#method.clear_timeout).
    ///
    /// # Example
    /// ```
    /// use mio::{EventLoop, Handler};
    /// use std::time::Duration;
    ///
    /// struct MyHandler;
    ///
    /// impl Handler for MyHandler {
    ///     type Timeout = u32;
    ///     type Message = ();
    ///
    ///     fn timeout(&mut self, event_loop: &mut EventLoop<MyHandler>, timeout: u32) {
    ///         assert_eq!(timeout, 123);
    ///         event_loop.shutdown();
    ///     }
    /// }
    ///
    ///
    /// let mut event_loop = EventLoop::new().unwrap();
    /// let timeout = event_loop.timeout(123, Duration::from_millis(300)).unwrap();
    /// let _ = event_loop.run(&mut MyHandler);
    /// ```
    pub fn timeout(&mut self, token: H::Timeout, delay: Duration) -> timer::Result<Timeout> {
        self.timer.set_timeout(delay, token)
    }

    /// If the supplied timeout has not been triggered, cancel it such that it
    /// will not be triggered in the future.
    pub fn clear_timeout(&mut self, timeout: &Timeout) -> bool {
        self.timer.cancel_timeout(&timeout).is_some()
    }

    /// Tells the event loop to exit after it is done handling all events in the
    /// current iteration.
    pub fn shutdown(&mut self) {
        self.run = false;
    }

    /// Indicates whether the event loop is currently running. If it's not it has either
    /// stopped or is scheduled to stop on the next tick.
    pub fn is_running(&self) -> bool {
        self.run
    }

    /// Registers an IO handle with the event loop.
    pub fn register<E: ?Sized>(&mut self, io: &E, token: Token, interest: EventSet, opt: PollOpt) -> io::Result<()>
        where E: Evented
    {
        self.poll.register(io, token, interest, opt)
    }

    /// Re-Registers an IO handle with the event loop.
    pub fn reregister<E: ?Sized>(&mut self, io: &E, token: Token, interest: EventSet, opt: PollOpt) -> io::Result<()>
        where E: Evented
    {
        self.poll.reregister(io, token, interest, opt)
    }

    /// Keep spinning the event loop indefinitely, and notify the handler whenever
    /// any of the registered handles are ready.
    pub fn run(&mut self, handler: &mut H) -> io::Result<()> {
        self.run = true;

        while self.run {
            // Execute ticks as long as the event loop is running
            try!(self.run_once(handler, None));
        }

        Ok(())
    }

    /// Deregisters an IO handle with the event loop.
    ///
    /// Both kqueue and epoll will automatically clear any pending events when closing a
    /// file descriptor (socket). In that case, this method does not need to be called
    /// prior to dropping a connection from the slab.
    ///
    /// Warning: kqueue effectively builds in deregister when using edge-triggered mode with
    /// oneshot. Calling `deregister()` on the socket will cause a TcpStream error.
    pub fn deregister<E: ?Sized>(&mut self, io: &E) -> io::Result<()> where E: Evented {
        self.poll.deregister(io)
    }

    /// Spin the event loop once, with a timeout of one second, and notify the
    /// handler if any of the registered handles become ready during that
    /// time.
    pub fn run_once(&mut self, handler: &mut H, timeout: Option<Duration>) -> io::Result<()> {
        trace!("event loop tick");

        // Check the registered IO handles for any new events. Each poll
        // is for one second, so a shutdown request can last as long as
        // one second before it takes effect.
        let events = match self.io_poll(timeout) {
            Ok(e) => e,
            Err(err) => {
                if err.kind() == io::ErrorKind::Interrupted {
                    handler.interrupted(self);
                    0
                } else {
                    return Err(err);
                }
            }
        };

        self.io_process(handler, events);
        handler.tick(self);
        Ok(())
    }

    #[inline]
    fn io_poll(&mut self, timeout: Option<Duration>) -> io::Result<usize> {
        self.poll.poll(timeout)
    }

    // Process IO events that have been previously polled
    fn io_process(&mut self, handler: &mut H, cnt: usize) {
        let mut i = 0;

        trace!("io_process(..); cnt={}; len={}", cnt, self.poll.events().len());

        // Iterate over the notifications. Each event provides the token
        // it was registered with (which usually represents, at least, the
        // handle that the event is about) as well as information about
        // what kind of event occurred (readable, writable, signal, etc.)
        while i < cnt {
            let evt = self.poll.events().get(i).unwrap();

            trace!("event={:?}; idx={:?}", evt, i);

            match evt.token() {
                NOTIFY => self.notify(handler),
                TIMER => self.timer_process(handler),
                _ => self.io_event(handler, evt)
            }

            i += 1;
        }
    }

    fn io_event(&mut self, handler: &mut H, evt: Event) {
        handler.ready(self, evt.token(), evt.kind());
    }

    fn notify(&mut self, handler: &mut H) {
        for _ in 0..self.config.messages_per_tick {
            match self.notify_rx.try_recv() {
                Ok(msg) => handler.notify(self, msg),
                _ => break,
            }
        }

        // Re-register
        let _ = self.poll.reregister(&self.notify_rx, NOTIFY, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot());
    }

    fn timer_process(&mut self, handler: &mut H) {
        while let Some(t) = self.timer.poll() {
            handler.timeout(self, t);
        }
    }
}

impl<H: Handler> fmt::Debug for EventLoop<H> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("EventLoop")
            .field("run", &self.run)
            .field("poll", &self.poll)
            .field("config", &self.config)
            .finish()
    }
}

/// Sends messages to the EventLoop from other threads.
pub struct Sender<M> {
    tx: channel::Sender<M>
}

impl<M> fmt::Debug for Sender<M> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "Sender<?> {{ ... }}")
    }
}

impl<M> Sender<M> {
    fn new(tx: channel::Sender<M>) -> Sender<M> {
        Sender { tx: tx }
    }

    pub fn send(&self, msg: M) -> Result<(), NotifyError<M>> {
        try!(self.tx.try_send(msg));
        Ok(())
    }
}

#[cfg(test)]
#[cfg(unix)]
mod tests {
    use {unix, EventLoop, Handler, Token, TryRead, TryWrite, EventSet, PollOpt};
    use bytes::{Buf, SliceBuf, ByteBuf};
    use std::str;
    use std::sync::Arc;
    use std::sync::atomic::AtomicIsize;
    use std::sync::atomic::Ordering::SeqCst;
    use std::time::Duration;

    struct Funtimes {
        rcount: Arc<AtomicIsize>,
        wcount: Arc<AtomicIsize>
    }

    impl Funtimes {
        fn new(rcount: Arc<AtomicIsize>, wcount: Arc<AtomicIsize>) -> Funtimes {
            Funtimes {
                rcount: rcount,
                wcount: wcount
            }
        }
    }

    impl Handler for Funtimes {
        type Timeout = usize;
        type Message = ();

        fn ready(&mut self, _event_loop: &mut EventLoop<Funtimes>, token: Token, events: EventSet) {
            if events.is_readable() {
                (*self.rcount).fetch_add(1, SeqCst);
                assert_eq!(token, Token(10));
            }

            if events.is_writable() {
                (*self.wcount).fetch_add(1, SeqCst);
                assert_eq!(token, Token(10));
            }
        }
    }

    #[test]
    pub fn test_readable() {
        let mut event_loop = EventLoop::new().ok().expect("Couldn't make event loop");

        let (mut reader, mut writer) = unix::pipe().unwrap();

        let rcount = Arc::new(AtomicIsize::new(0));
        let wcount = Arc::new(AtomicIsize::new(0));
        let mut handler = Funtimes::new(rcount.clone(), wcount.clone());

        writer.try_write_buf(&mut SliceBuf::wrap(b"hello")).unwrap();
        event_loop.register(&reader, Token(10), EventSet::readable(),
                            PollOpt::edge()).unwrap();

        let _ = event_loop.run_once(&mut handler, None);
        let mut b = ByteBuf::mut_with_capacity(16);

        assert_eq!((*rcount).load(SeqCst), 1);

        reader.try_read_buf(&mut b).unwrap();

        assert_eq!(str::from_utf8(b.flip().bytes()).unwrap(), "hello");
    }

    pub struct BrokenPipeHandler;

    impl Handler for BrokenPipeHandler {
        type Timeout = ();
        type Message = ();
        fn ready(&mut self, _: &mut EventLoop<Self>, token: Token, _: EventSet) {
            if token == Token(1) {
                panic!("Received ready() on a closed pipe.");
            }
        }
    }

    #[test]
    pub fn broken_pipe() {
        let mut event_loop: EventLoop<BrokenPipeHandler> = EventLoop::new().unwrap();
        let (reader, _) = unix::pipe().unwrap();

        // On Darwin this returns a "broken pipe" error.
        let _ = event_loop.register(&reader, Token(1), EventSet::all(), PollOpt::edge());

        let mut handler = BrokenPipeHandler;
        drop(reader);
        event_loop.run_once(&mut handler, Some(Duration::from_millis(1000))).unwrap();
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("InheritedTable", inherited=True, gecko_name="TableBorder") %>

${helpers.single_keyword(
    "border-collapse",
    "separate collapse",
    gecko_constant_prefix="NS_STYLE_BORDER",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-tables/#propdef-border-collapse",
    servo_restyle_damage = "reflow",
)}

${helpers.single_keyword(
    "empty-cells",
    "show hide",
    gecko_constant_prefix="NS_STYLE_TABLE_EMPTY_CELLS",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-tables/#propdef-empty-cells",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.single_keyword(
    "caption-side",
    "top bottom",
    extra_gecko_values="right left top-outside bottom-outside",
    needs_conversion="True",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-tables/#propdef-caption-side",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.predefined_type(
    "border-spacing",
    "BorderSpacing",
    "computed::BorderSpacing::zero()",
    animation_value_type="BorderSpacing",
    boxed=True,
    spec="https://drafts.csswg.org/css-tables/#propdef-border-spacing",
    servo_restyle_damage = "reflow",
)}
<commit_msg>style: Convert NS_STYLE_BORDER to an enum class in nsStyleConsts.h.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("InheritedTable", inherited=True, gecko_name="TableBorder") %>

${helpers.single_keyword(
    "border-collapse",
    "separate collapse",
    gecko_enum_prefix="StyleBorderCollapse",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-tables/#propdef-border-collapse",
    servo_restyle_damage = "reflow",
)}

${helpers.single_keyword(
    "empty-cells",
    "show hide",
    gecko_constant_prefix="NS_STYLE_TABLE_EMPTY_CELLS",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-tables/#propdef-empty-cells",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.single_keyword(
    "caption-side",
    "top bottom",
    extra_gecko_values="right left top-outside bottom-outside",
    needs_conversion="True",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-tables/#propdef-caption-side",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.predefined_type(
    "border-spacing",
    "BorderSpacing",
    "computed::BorderSpacing::zero()",
    animation_value_type="BorderSpacing",
    boxed=True,
    spec="https://drafts.csswg.org/css-tables/#propdef-border-spacing",
    servo_restyle_damage = "reflow",
)}
<|endoftext|>


<commit_before>use piston_window::*;

use game::config::Config;

#[derive(Copy, Clone)]
pub struct Block {
    pub color: [f32; 4],
}

impl Block {
    pub fn new(color: [f32; 4]) -> Block {
        Block { color: color }
    }

    pub fn render<G>(&self,
                     x: usize,
                     y: usize,
                     config: &Config,
                     context: Context,
                     gfx: &mut G,
                     e: &Event)
        where G: Graphics
    {
        let grid_offset = config.grid_offset;
        let tile_size = config.tile_size;
        let adjusted_y = y - 2;

        let rect = rectangle::Rectangle {
            color: self.color,
            shape: rectangle::Shape::Bevel(1.0),
            border: Some(rectangle::Border {
                color: [0.0, 0.0, 0.0, 1.0],
                radius: 1.0,
            }),
        };

        rect.draw([x as f64 * tile_size + grid_offset,
                   adjusted_y as f64 * tile_size + grid_offset,
                   tile_size as f64,
                   tile_size as f64],
                  &Default::default(),
                  context.transform,
                  gfx);
    }
}
<commit_msg>Stopped the Rectangle allocation per render<commit_after>use piston_window::*;

use game::config::Config;

#[derive(Copy, Clone)]
pub struct Block {
    pub color: [f32; 4],
    rect: rectangle::Rectangle,
}

impl Block {
    pub fn new(color: [f32; 4]) -> Block {
        let rect = rectangle::Rectangle::new(color)
            .shape(rectangle::Shape::Bevel(1.0))
            .border(rectangle::Border {
                color: [0.0, 0.0, 0.0, 1.0],
                radius: 1.0,
            });

        Block {
            color: color,
            rect: rect,
        }
    }

    pub fn render<G>(&self,
                     x: usize,
                     y: usize,
                     config: &Config,
                     context: Context,
                     gfx: &mut G,
                     e: &Event)
        where G: Graphics
    {
        let grid_offset = config.grid_offset;
        let tile_size = config.tile_size;
        let adjusted_y = y - 2;

        self.rect.draw([x as f64 * tile_size + grid_offset,
                        adjusted_y as f64 * tile_size + grid_offset,
                        tile_size as f64,
                        tile_size as f64],
                       &Default::default(),
                       context.transform,
                       gfx);
    }
}
<|endoftext|>


<commit_before>/*!
Methods for hyphenation dictionaries
*/

use std::borrow::Cow;

use hyphenation_commons::dictionary::*;
use hyphenation_commons::dictionary::extended::*;
use case_folding::{realign, refold, Shift};
use score::Score;

/// The indices of soft hyphens (U+00AD) within the string, if any. Existing
/// soft hyphens indicate a preferred hyphenation, which can be used without
/// resorting to best-effort hyphenation.
pub fn soft_hyphen_indices(word : &str) -> Option<Vec<usize>> {
    let shys : Vec<_> = word.match_indices('\u{00ad}').map(|(i, _)| i).collect();
    if shys.len() > 0 {
        Some(shys)
    } else { None }
}

/// A hyphenated word carrying valid breaks.
///
/// The `Word` can be borrowed or moved for iteration with `iter()` and
/// `into_iter()` respectively.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Word<'t, Break> {
    pub text : &'t str,
    pub breaks : Vec<Break>
}

/// A dictionary capable of hyphenating individual words.
///
/// For the purpose of hyphenation, a "word" should not be a compound in
/// hyphenated form (such as "hard-nosed"), but a single run of letters
/// without intervening punctuation or spaces.
///
/// For details, refer to the `patterns/*.chr.txt` file for each language.
pub trait Hyphenator<'h> {
    /// Plain representation of a word break.
    type Opportunity;

    /// An owned opportunity used to specify and store the predetermined hyphenation
    /// of known words.
    type Exact;

    /// Hyphenate a word, computing appropriate word breaks and preparing it for
    /// iteration.
    ///
    /// Soft hyphens take priority over dictionary hyphenation; if the word
    /// contains any, they will be returned as the only breaks available.
    ///
    /// This method is case-insensitive.
    fn hyphenate<'t>(&'h self, word : &'t str) -> Word<'t, Self::Opportunity>;

    /// The hyphenation opportunities that our dictionary can find in the given
    /// word. The word should be lowercase.
    fn opportunities(&'h self, lowercase_word : &str) -> Vec<Self::Opportunity> {
        match self.boundaries(lowercase_word) {
            None => vec![],
            Some(mins) => {
                match self.exception(lowercase_word) {
                    None => self.opportunities_within(lowercase_word, mins),
                    Some(known) => known
                }
            }
        }
    }

    /// The hyphenation opportunities that arise between the specified indices.
    ///
    /// No attempt is made to retrieve a known exact hyphenation.
    fn opportunities_within(&'h self, lowercase_word : &str, bounds : (usize, usize))
        -> Vec<Self::Opportunity>;

    /// If this word is a known exception, retrieve its specified hyphenation.
    fn exception(&'h self, lowercase_word : &str) -> Option<Vec<Self::Opportunity>>;

    /// Specify the hyphenation of the given word with an exact sequence of
    /// opportunities and add it to the exception list. Subsequent calls to
    /// `hyphenate` or `opportunities` will yield this hyphenation instead of
    /// generating one from patterns.
    ///
    /// If the word is already a known exception, the old opportunities are
    /// returned.
    fn add_exception(&mut self, lowercase_word : String, ops : Vec<Self::Exact>)
        -> Option<Vec<Self::Exact>>;

    /// The number of `char`s from the start and end of a word where breaks may
    /// not occur.
    fn unbreakable_chars(&self) -> (usize, usize);

    /// The byte indices delimiting the substring where breaks may occur, unless
    /// the word is too short to be hyphenated.
    fn boundaries(&self, word : &str) -> Option<(usize, usize)> {
        let (l_min, r_min) = self.unbreakable_chars();
        let length_min = l_min + r_min;
        if word.chars().count() >= length_min {
            ( word.char_indices().nth(l_min).unwrap().0
            , word.char_indices().rev().nth(r_min.saturating_sub(1)).unwrap().0 ).into()
        } else { None }
    }
}

#[derive(Debug, Clone)]
struct Prepared<'t> {
    word : Cow<'t, str>,
    shifts : Vec<Shift>
}

fn prepare<'t>(text : &'t str) -> Prepared<'t> {
    let (word, shifts) = refold(text);
    Prepared { word, shifts }
}

impl<'h> Hyphenator<'h> for Standard {
    type Opportunity = usize;
    type Exact = usize;

    fn hyphenate<'t>(&'h self, word : &'t str) -> Word<'t, Self::Opportunity> {
        let breaks = match soft_hyphen_indices(word) {
            Some(ops) => ops,
            None => {
                let Prepared { ref word, ref shifts } = prepare(word);
                if shifts.len() > 0 {
                    self.opportunities(word).into_iter()
                        .map(move |o| realign(o, shifts)).collect()
                } else { self.opportunities(word) }
            }
        };

        Word { breaks, text : word }
    }

    fn opportunities_within(&'h self, word : &str, (l, r) : (usize, usize)) -> Vec<usize> {
        (1 .. word.len())
            .zip(self.score(word))
            .filter(|&(i, v)| {
                let valid = Self::denotes_opportunity(v);
                let within_bounds = i >= l && i <= r;
                let legal_index = word.is_char_boundary(i);
                valid && within_bounds && legal_index
            }).map(|(i, _)| i).collect()
    }

    #[inline]
    fn exception(&'h self, w : &str) -> Option<Vec<Self::Opportunity>> {
        self.exceptions.0.get(w).cloned()
    }

    #[inline]
    fn add_exception(&mut self, w : String, ops : Vec<usize>) -> Option<Vec<usize>> {
        self.exceptions.0.insert(w, ops)
    }

    #[inline] fn unbreakable_chars(&self) -> (usize, usize) { self.minima }
}

impl<'h> Hyphenator<'h> for Extended {
    type Opportunity = (usize, Option<&'h Subregion>);
    type Exact = (usize, Option<Subregion>);

    fn hyphenate<'t>(&'h self, word : &'t str) -> Word<'t, Self::Opportunity> {
        let breaks = match soft_hyphen_indices(word) {
            Some(ops) => ops.into_iter().map(|i| (i, None)).collect(),
            None => {
                let Prepared { ref word, ref shifts } = prepare(word);
                if shifts.len() > 0 {
                    self.opportunities(word).into_iter()
                        .map(move |(i, subr)| (realign(i, shifts), subr)).collect()
                } else { self.opportunities(word) }
            }
        };

        Word { breaks, text : word }
    }

    fn opportunities_within(&'h self, word : &str, (l, r) : (usize, usize))
        -> Vec<Self::Opportunity>
    {
        (1 .. word.len())
            .zip(self.score(word))
            .filter(|&(i, v)| {
                let valid = Self::denotes_opportunity(v);
                let within_bounds = i >= l && i <= r;
                let legal_index = word.is_char_boundary(i);
                valid && within_bounds && legal_index
            }).map(|(i, (_, subr))| (i, subr)).collect()
    }

    #[inline]
    fn exception(&'h self, w : &str) -> Option<Vec<Self::Opportunity>> {
        self.exceptions.0.get(w).map(|v| v.iter().map(|&(i, ref sub)| (i, sub.as_ref())).collect())
    }

    fn add_exception(&mut self, w : String, ops : Vec<Self::Exact>)
        -> Option<Vec<Self::Exact>> {
        self.exceptions.0.insert(w, ops)
    }

    #[inline] fn unbreakable_chars(&self) -> (usize, usize) { self.minima }
}
<commit_msg>Add `Hyphenator::remove_exception()`<commit_after>/*!
Methods for hyphenation dictionaries
*/

use std::borrow::Cow;

use hyphenation_commons::dictionary::*;
use hyphenation_commons::dictionary::extended::*;
use case_folding::{realign, refold, Shift};
use score::Score;

/// The indices of soft hyphens (U+00AD) within the string, if any. Existing
/// soft hyphens indicate a preferred hyphenation, which can be used without
/// resorting to best-effort hyphenation.
pub fn soft_hyphen_indices(word : &str) -> Option<Vec<usize>> {
    let shys : Vec<_> = word.match_indices('\u{00ad}').map(|(i, _)| i).collect();
    if shys.len() > 0 {
        Some(shys)
    } else { None }
}

/// A hyphenated word carrying valid breaks.
///
/// The `Word` can be borrowed or moved for iteration with `iter()` and
/// `into_iter()` respectively.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Word<'t, Break> {
    pub text : &'t str,
    pub breaks : Vec<Break>
}

/// A dictionary capable of hyphenating individual words.
///
/// For the purpose of hyphenation, a "word" should not be a compound in
/// hyphenated form (such as "hard-nosed"), but a single run of letters
/// without intervening punctuation or spaces.
///
/// For details, refer to the `patterns/*.chr.txt` file for each language.
pub trait Hyphenator<'h> {
    /// Plain representation of a word break.
    type Opportunity;

    /// An owned opportunity used to specify and store the predetermined hyphenation
    /// of known words.
    type Exact;

    /// Hyphenate a word, computing appropriate word breaks and preparing it for
    /// iteration.
    ///
    /// Soft hyphens take priority over dictionary hyphenation; if the word
    /// contains any, they will be returned as the only breaks available.
    ///
    /// This method is case-insensitive.
    fn hyphenate<'t>(&'h self, word : &'t str) -> Word<'t, Self::Opportunity>;

    /// The hyphenation opportunities that our dictionary can find in the given
    /// word. The word should be lowercase.
    fn opportunities(&'h self, lowercase_word : &str) -> Vec<Self::Opportunity> {
        match self.boundaries(lowercase_word) {
            None => vec![],
            Some(mins) => {
                match self.exception(lowercase_word) {
                    None => self.opportunities_within(lowercase_word, mins),
                    Some(known) => known
                }
            }
        }
    }

    /// The hyphenation opportunities that arise between the specified indices.
    ///
    /// No attempt is made to retrieve a known exact hyphenation.
    fn opportunities_within(&'h self, lowercase_word : &str, bounds : (usize, usize))
        -> Vec<Self::Opportunity>;

    /// If this word is a known exception, retrieve its specified hyphenation.
    fn exception(&'h self, lowercase_word : &str) -> Option<Vec<Self::Opportunity>>;

    /// Specify the hyphenation of the given word with an exact sequence of
    /// opportunities and add it to the exception list. Subsequent calls to
    /// `hyphenate` or `opportunities` will yield this hyphenation instead of
    /// generating one from patterns.
    ///
    /// If the word is already a known exception, the old opportunities are
    /// returned.
    fn add_exception(&mut self, lowercase_word : String, ops : Vec<Self::Exact>)
        -> Option<Vec<Self::Exact>>;

    /// If the word is an exception, remove it and return the previously specified
    /// opportunities; otherwise, return none.
    fn remove_exception(&mut self, word : &str) -> Option<Vec<Self::Exact>>;

    /// The number of `char`s from the start and end of a word where breaks may
    /// not occur.
    fn unbreakable_chars(&self) -> (usize, usize);

    /// The byte indices delimiting the substring where breaks may occur, unless
    /// the word is too short to be hyphenated.
    fn boundaries(&self, word : &str) -> Option<(usize, usize)> {
        let (l_min, r_min) = self.unbreakable_chars();
        let length_min = l_min + r_min;
        if word.chars().count() >= length_min {
            ( word.char_indices().nth(l_min).unwrap().0
            , word.char_indices().rev().nth(r_min.saturating_sub(1)).unwrap().0 ).into()
        } else { None }
    }
}

#[derive(Debug, Clone)]
struct Prepared<'t> {
    word : Cow<'t, str>,
    shifts : Vec<Shift>
}

fn prepare<'t>(text : &'t str) -> Prepared<'t> {
    let (word, shifts) = refold(text);
    Prepared { word, shifts }
}

impl<'h> Hyphenator<'h> for Standard {
    type Opportunity = usize;
    type Exact = usize;

    fn hyphenate<'t>(&'h self, word : &'t str) -> Word<'t, Self::Opportunity> {
        let breaks = match soft_hyphen_indices(word) {
            Some(ops) => ops,
            None => {
                let Prepared { ref word, ref shifts } = prepare(word);
                if shifts.len() > 0 {
                    self.opportunities(word).into_iter()
                        .map(move |o| realign(o, shifts)).collect()
                } else { self.opportunities(word) }
            }
        };

        Word { breaks, text : word }
    }

    fn opportunities_within(&'h self, word : &str, (l, r) : (usize, usize)) -> Vec<usize> {
        (1 .. word.len())
            .zip(self.score(word))
            .filter(|&(i, v)| {
                let valid = Self::denotes_opportunity(v);
                let within_bounds = i >= l && i <= r;
                let legal_index = word.is_char_boundary(i);
                valid && within_bounds && legal_index
            }).map(|(i, _)| i).collect()
    }

    #[inline]
    fn exception(&'h self, w : &str) -> Option<Vec<Self::Opportunity>> {
        self.exceptions.0.get(w).cloned()
    }

    #[inline]
    fn add_exception(&mut self, w : String, ops : Vec<usize>) -> Option<Vec<usize>> {
        self.exceptions.0.insert(w, ops)
    }

    fn remove_exception(&mut self, w : &str) -> Option<Vec<usize>> {
        self.exceptions.0.remove(w)
    }

    #[inline] fn unbreakable_chars(&self) -> (usize, usize) { self.minima }
}

impl<'h> Hyphenator<'h> for Extended {
    type Opportunity = (usize, Option<&'h Subregion>);
    type Exact = (usize, Option<Subregion>);

    fn hyphenate<'t>(&'h self, word : &'t str) -> Word<'t, Self::Opportunity> {
        let breaks = match soft_hyphen_indices(word) {
            Some(ops) => ops.into_iter().map(|i| (i, None)).collect(),
            None => {
                let Prepared { ref word, ref shifts } = prepare(word);
                if shifts.len() > 0 {
                    self.opportunities(word).into_iter()
                        .map(move |(i, subr)| (realign(i, shifts), subr)).collect()
                } else { self.opportunities(word) }
            }
        };

        Word { breaks, text : word }
    }

    fn opportunities_within(&'h self, word : &str, (l, r) : (usize, usize))
        -> Vec<Self::Opportunity>
    {
        (1 .. word.len())
            .zip(self.score(word))
            .filter(|&(i, v)| {
                let valid = Self::denotes_opportunity(v);
                let within_bounds = i >= l && i <= r;
                let legal_index = word.is_char_boundary(i);
                valid && within_bounds && legal_index
            }).map(|(i, (_, subr))| (i, subr)).collect()
    }

    #[inline]
    fn exception(&'h self, w : &str) -> Option<Vec<Self::Opportunity>> {
        self.exceptions.0.get(w).map(|v| v.iter().map(|&(i, ref sub)| (i, sub.as_ref())).collect())
    }

    fn add_exception(&mut self, w : String, ops : Vec<Self::Exact>)
        -> Option<Vec<Self::Exact>> {
        self.exceptions.0.insert(w, ops)
    }

    fn remove_exception(&mut self, w : &str) -> Option<Vec<Self::Exact>> {
        self.exceptions.0.remove(w)
    }

    #[inline] fn unbreakable_chars(&self) -> (usize, usize) { self.minima }
}
<|endoftext|>