<commit_before>// Copyright (c) 2016, 2018 vergen developers
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! # Generate Build Time Information
//! `vergen`, when used in conjunction with cargo [build scripts], will
//! generate environment variables to use with the `env!` macro.  Below
//! is a list of the supported variables.
//!
//! Key                       | Sample Value
//! --------------------------|----------------------------------------
//! VERGEN_BUILD_TIMESTAMP    |2018-08-09T15:15:57.282334589+00:000
//! VERGEN_BUILD_DATE         |2018-08-09
//! VERGEN_SHA                |75b390dc6c05a6a4aa2791cc7b3934591803bc22
//! VERGEN_SHA_SHORT          |75b390d
//! VERGEN_COMMIT_DATE        |2018-08-08
//! VERGEN_TARGET_TRIPLE      |x86_64-unknown-linux-gnu
//! VERGEN_SEMVER             |v0.1.0
//! VERGEN_SEMVER_LIGHTWEIGHT |v0.1.0
//!
//! The variable generation can be toggled on or off at an individual level
//! via [ConstantsFlags](crate::constants::ConstantsFlags)
//!
//! ### Note on SEMVER
//! `VERGEN_SEMVER` can be generated via `git describe` or by
//! `env::var("CARGO_PKG_VERSION")`.
//!
//! By default, `SEMVER` uses `git describe` if possible, and falls back to `CARGO_PKG_VERSION`.
//!
//! If you wish to force `CARGO_PKG_VERSION`, toggle off `SEMVER` and toggle
//! on `SEMVER_FROM_CARGO_PKG`.
//!
//! # Re-build On Changed HEAD
//! `vergen` can also be configured to re-run `build.rs` when either `.git/HEAD` or
//! the file that `.git/HEAD` points at changes.
//!
//! This can behavior can be toggled on or of with the [REBUILD_ON_HEAD_CHANGE] flag.
//!
//! [REBUILD_ON_HEAD_CHANGE]: crate::constants::ConstantsFlags::REBUILD_ON_HEAD_CHANGE
//! [build scripts]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
//!
//! ## 'cargo:' Key Build Script Output
//! ```toml
//! [package]
//! #..
//! build = "build.rs"
//!
//! [dependencies]
//! #..
//!
//! [build-dependencies]
//! vergen = "3"
//! ```
//!
//! ### Example 'build.rs'
//! ```
//! use vergen::{ConstantsFlags, generate_cargo_keys};
//!
//! // Setup the flags, toggling off the 'SEMVER_FROM_CARGO_PKG' flag
//! let mut flags = ConstantsFlags::all();
//! flags.toggle(ConstantsFlags::SEMVER_FROM_CARGO_PKG);
//!
//! // Generate the 'cargo:' key output
//! generate_cargo_keys(flags).expect("Unable to generate the cargo keys!");
//! ```
//!
//! ### Use the constants in your code
//! ```
//! fn my_fn() {
//!     println!("Build Timestamp: {}", env!("VERGEN_BUILD_TIMESTAMP"));
//! }
//! ```
//!
//! ## **DEPRECATED** - `version.rs` File Build Script Output
//! Generate a `version.rs` file in `OUT_DIR` (defined by cargo) with up to 8 build time
//! constants.  This file can then be used with the `include!` macro to pull the
//! constants into your source for use.
//!
//! See the [generate_version_rs](crate::output::codegen::generate_version_rs) documentation
//! if you wish to use this method.
#![deny(
  missing_docs,
  missing_debug_implementations,
  missing_copy_implementations,
  trivial_casts,
  trivial_numeric_casts,
  unsafe_code,
  unused_import_braces,
  unused_qualifications
)]
#[macro_use]
extern crate bitflags;
#[cfg(test)]
#[macro_use]
extern crate lazy_static;

mod constants;
mod output;

pub use crate::constants::ConstantsFlags;
pub use crate::output::envvar::generate_cargo_keys;
use std::error::Error;
use std::fmt::{self, Display, Formatter};

#[derive(Clone, Debug)]
/// An error generated by Vergen
pub struct VergenError {
  description: String,
}

impl VergenError {
  /// Create an error struct
  pub fn new<T: Into<String>>(description: T) -> Self {
    VergenError { description: description.into() }
  }
}

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

impl Error for VergenError {}
<commit_msg>crates: vergen: Remove unused import<commit_after>// Copyright (c) 2016, 2018 vergen developers
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! # Generate Build Time Information
//! `vergen`, when used in conjunction with cargo [build scripts], will
//! generate environment variables to use with the `env!` macro.  Below
//! is a list of the supported variables.
//!
//! Key                       | Sample Value
//! --------------------------|----------------------------------------
//! VERGEN_BUILD_TIMESTAMP    |2018-08-09T15:15:57.282334589+00:000
//! VERGEN_BUILD_DATE         |2018-08-09
//! VERGEN_SHA                |75b390dc6c05a6a4aa2791cc7b3934591803bc22
//! VERGEN_SHA_SHORT          |75b390d
//! VERGEN_COMMIT_DATE        |2018-08-08
//! VERGEN_TARGET_TRIPLE      |x86_64-unknown-linux-gnu
//! VERGEN_SEMVER             |v0.1.0
//! VERGEN_SEMVER_LIGHTWEIGHT |v0.1.0
//!
//! The variable generation can be toggled on or off at an individual level
//! via [ConstantsFlags](crate::constants::ConstantsFlags)
//!
//! ### Note on SEMVER
//! `VERGEN_SEMVER` can be generated via `git describe` or by
//! `env::var("CARGO_PKG_VERSION")`.
//!
//! By default, `SEMVER` uses `git describe` if possible, and falls back to `CARGO_PKG_VERSION`.
//!
//! If you wish to force `CARGO_PKG_VERSION`, toggle off `SEMVER` and toggle
//! on `SEMVER_FROM_CARGO_PKG`.
//!
//! # Re-build On Changed HEAD
//! `vergen` can also be configured to re-run `build.rs` when either `.git/HEAD` or
//! the file that `.git/HEAD` points at changes.
//!
//! This can behavior can be toggled on or of with the [REBUILD_ON_HEAD_CHANGE] flag.
//!
//! [REBUILD_ON_HEAD_CHANGE]: crate::constants::ConstantsFlags::REBUILD_ON_HEAD_CHANGE
//! [build scripts]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
//!
//! ## 'cargo:' Key Build Script Output
//! ```toml
//! [package]
//! #..
//! build = "build.rs"
//!
//! [dependencies]
//! #..
//!
//! [build-dependencies]
//! vergen = "3"
//! ```
//!
//! ### Example 'build.rs'
//! ```
//! use vergen::{ConstantsFlags, generate_cargo_keys};
//!
//! // Setup the flags, toggling off the 'SEMVER_FROM_CARGO_PKG' flag
//! let mut flags = ConstantsFlags::all();
//! flags.toggle(ConstantsFlags::SEMVER_FROM_CARGO_PKG);
//!
//! // Generate the 'cargo:' key output
//! generate_cargo_keys(flags).expect("Unable to generate the cargo keys!");
//! ```
//!
//! ### Use the constants in your code
//! ```
//! fn my_fn() {
//!     println!("Build Timestamp: {}", env!("VERGEN_BUILD_TIMESTAMP"));
//! }
//! ```
//!
//! ## **DEPRECATED** - `version.rs` File Build Script Output
//! Generate a `version.rs` file in `OUT_DIR` (defined by cargo) with up to 8 build time
//! constants.  This file can then be used with the `include!` macro to pull the
//! constants into your source for use.
//!
//! See the [generate_version_rs](crate::output::codegen::generate_version_rs) documentation
//! if you wish to use this method.
#![deny(
  missing_docs,
  missing_debug_implementations,
  missing_copy_implementations,
  trivial_casts,
  trivial_numeric_casts,
  unsafe_code,
  unused_import_braces,
  unused_qualifications
)]
#[macro_use]
extern crate bitflags;
#[cfg(test)]
extern crate lazy_static;

mod constants;
mod output;

pub use crate::constants::ConstantsFlags;
pub use crate::output::envvar::generate_cargo_keys;
use std::error::Error;
use std::fmt::{self, Display, Formatter};

#[derive(Clone, Debug)]
/// An error generated by Vergen
pub struct VergenError {
  description: String,
}

impl VergenError {
  /// Create an error struct
  pub fn new<T: Into<String>>(description: T) -> Self {
    VergenError { description: description.into() }
  }
}

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

impl Error for VergenError {}
<|endoftext|>


<commit_before>use bounding_volume::AABB;
use math::Isometry;
use na::{Point2, Real, Vector3};
use partitioning::{BestFirstBVVisitStatus, BestFirstDataVisitStatus, BestFirstVisitor};
use query::{closest_points_internal, Ray, RayCast, RayIntersection};
use shape::{CompositeShape, HeightField, FeatureId};

#[cfg(feature = "dim2")]
impl<N: Real> RayCast<N> for HeightField<N> {
    #[inline]
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        _: bool,
    ) -> Option<RayIntersection<N>>
    {
        let aabb = self.aabb();
        let ls_ray = ray.inverse_transform_by(m);
        let (min_t, max_t) = aabb.clip_ray_parameters(&ls_ray)?;
        let (clip_ray_a, clip_ray_b) = (ls_ray.point_at(min_t), ls_ray.point_at(max_t));
        let mut curr = match self.cell_at_point(&clip_ray_a) {
            Some(cell) => cell,
            // None may happen due to slight numerical errors.
            None => if ls_ray.origin.x > N::zero() { self.num_cells() - 1 } else {
                0
            }
        };

        /*
         * Test the segment under the ray.
         */
        if let Some(seg) = self.segment_at(curr) {
            let (s, t) = closest_points_internal::line_against_line_parameters(&ray.origin, &ray.dir, seg.a(), &seg.scaled_direction());
            if s >= N::zero() && t >= N::zero() && t <= N::one() {
                // Cast succeeded on the first element!
                // FIXME: return the correct feature and normal.
                return Some(RayIntersection::new(s, m * seg.normal().unwrap().unwrap(), FeatureId::Face(curr)))
            }
        }

        /*
         * Test other segments in the path of the ray.
         */
        if ls_ray.dir.x == N::zero() {
            return None;
        }

        let right = ls_ray.dir.x > N::zero();
        let cell_width = self.cell_width();
        let start_x = self.start_x();

        while (right && curr < self.num_cells()) || (!right && curr > 0) {
            let curr_param;

            if right {
                curr += 1;
                curr_param = (cell_width * na::convert(curr as f64) + start_x - ls_ray.origin.x) / ls_ray.dir.x;
            } else {
                curr_param = (ls_ray.origin.x - cell_width * na::convert(curr as f64) - start_x) / ls_ray.dir.x;
                curr -= 1;
            }

            if curr_param >= max_t {
                // The part of the ray after max_t is outside of the heightfield AABB.
                return None;
            }

            if let Some(seg) = self.segment_at(curr) {
                // TODO: test the y-coordinates (equivalent to an AABB test) before actually computing the intersection.
                let (s, t) = closest_points_internal::line_against_line_parameters(&ray.origin, &ray.dir, seg.a(), &seg.scaled_direction());
                if t >= N::zero() && t <= N::one() {
                    // FIXME: return the correct feature and normal.
                    return Some(RayIntersection::new(s, m * seg.normal().unwrap().unwrap(), FeatureId::Face(curr)))
                }
            }
        }

        None
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> RayCast<N> for HeightField<N> {
    #[inline]
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let aabb = self.aabb();
        let ls_ray = ray.inverse_transform_by(m);
        let (min_t, max_t) = aabb.clip_ray_parameters(&ls_ray)?;
        let (clip_ray_a, clip_ray_b) = (ls_ray.point_at(min_t), ls_ray.point_at(max_t));
        let mut cell = match self.cell_at_point(&clip_ray_a) {
            Some(cell) => cell,
            // None may happen due to slight numerical errors.
            None => (0, 0) /* XXX: if ls_ray.origin.x > N::zero() { self.num_cells() - 1 } else {
                0
            }*/
        };

        loop {
            let tris = self.triangles_at(cell.0, cell.1);
            let inter1 = tris.0.and_then(|tri| tri.toi_and_normal_with_ray(m, ray, solid));
            let inter2 = tris.1.and_then(|tri| tri.toi_and_normal_with_ray(m, ray, solid));

            match (inter1, inter2) {
                (Some(inter1), Some(inter2)) => {
                    // XXX: adjust the feature ID.
                    if inter1.toi < inter2.toi {
                        return Some(inter1);
                    } else {
                        return Some(inter2);
                    }
                }
                (Some(inter), None) => {
                    // XXX: adjust the feature ID.
                    return Some(inter);
                }
                (None, Some(inter)) => {
                    // XXX: adjust the feature ID.
                    return Some(inter);
                }
                (None, None) => {}
            }

            /*
             * Find the next cell to cast the ray on.
             */
            let (toi_x, right) = if ls_ray.dir.x > N::zero() {
                let x = self.x_at(cell.1 + 1);
                ((x - ls_ray.origin.x) / ls_ray.dir.x, true)
            } else if ls_ray.dir.x < N::zero() {
                let x = self.x_at(cell.1 + 0);
                ((x - ls_ray.origin.x) / ls_ray.dir.x, false)
            } else {
                (N::max_value(), false)
            };

            let (toi_z, down) = if ls_ray.dir.z > N::zero() {
                let z = self.z_at(cell.0 + 1);
                ((z - ls_ray.origin.z) / ls_ray.dir.z, true)
            } else if ls_ray.dir.z < N::zero() {
                let z = self.z_at(cell.0 + 0);
                ((z - ls_ray.origin.z) / ls_ray.dir.z, false)
            } else {
                (N::max_value(), false)
            };

            if toi_x == N::max_value() && toi_z == N::max_value() {
                break;
            }

            if toi_x >= N::zero() && toi_x < toi_z {
                if right {
                    cell.1 += 1
                } else if cell.1 > 0 {
                    cell.1 -= 1
                } else {
                    break;
                }
            } else if toi_z >= N::zero() {
                if down {
                    cell.0 += 1
                } else if cell.0 > 0 {
                    cell.0 -= 1
                } else {
                    break
                }
            } else {
                break;
            }

            if cell.0 >= self.nrows() || cell.1 >= self.ncols() {
                break;
            }
        }

        None
    }
}
<commit_msg>Fix ray-cast on 3D heightfield initialization.<commit_after>use bounding_volume::AABB;
use math::Isometry;
use na::{Point2, Real, Vector3};
use partitioning::{BestFirstBVVisitStatus, BestFirstDataVisitStatus, BestFirstVisitor};
use query::{closest_points_internal, Ray, RayCast, RayIntersection};
use shape::{CompositeShape, HeightField, FeatureId};

#[cfg(feature = "dim2")]
impl<N: Real> RayCast<N> for HeightField<N> {
    #[inline]
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        _: bool,
    ) -> Option<RayIntersection<N>>
    {
        let aabb = self.aabb();
        let ls_ray = ray.inverse_transform_by(m);
        let (min_t, max_t) = aabb.clip_ray_parameters(&ls_ray)?;
        let (clip_ray_a, clip_ray_b) = (ls_ray.point_at(min_t), ls_ray.point_at(max_t));
        let mut curr = match self.cell_at_point(&clip_ray_a) {
            Some(cell) => cell,
            // None may happen due to slight numerical errors.
            None => if ls_ray.origin.x > N::zero() { self.num_cells() - 1 } else {
                0
            }
        };

        /*
         * Test the segment under the ray.
         */
        if let Some(seg) = self.segment_at(curr) {
            let (s, t) = closest_points_internal::line_against_line_parameters(&ray.origin, &ray.dir, seg.a(), &seg.scaled_direction());
            if s >= N::zero() && t >= N::zero() && t <= N::one() {
                // Cast succeeded on the first element!
                // FIXME: return the correct feature and normal.
                return Some(RayIntersection::new(s, m * seg.normal().unwrap().unwrap(), FeatureId::Face(curr)))
            }
        }

        /*
         * Test other segments in the path of the ray.
         */
        if ls_ray.dir.x == N::zero() {
            return None;
        }

        let right = ls_ray.dir.x > N::zero();
        let cell_width = self.cell_width();
        let start_x = self.start_x();

        while (right && curr < self.num_cells()) || (!right && curr > 0) {
            let curr_param;

            if right {
                curr += 1;
                curr_param = (cell_width * na::convert(curr as f64) + start_x - ls_ray.origin.x) / ls_ray.dir.x;
            } else {
                curr_param = (ls_ray.origin.x - cell_width * na::convert(curr as f64) - start_x) / ls_ray.dir.x;
                curr -= 1;
            }

            if curr_param >= max_t {
                // The part of the ray after max_t is outside of the heightfield AABB.
                return None;
            }

            if let Some(seg) = self.segment_at(curr) {
                // TODO: test the y-coordinates (equivalent to an AABB test) before actually computing the intersection.
                let (s, t) = closest_points_internal::line_against_line_parameters(&ray.origin, &ray.dir, seg.a(), &seg.scaled_direction());
                if t >= N::zero() && t <= N::one() {
                    // FIXME: return the correct feature and normal.
                    return Some(RayIntersection::new(s, m * seg.normal().unwrap().unwrap(), FeatureId::Face(curr)))
                }
            }
        }

        None
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> RayCast<N> for HeightField<N> {
    #[inline]
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let aabb = self.aabb();
        let ls_ray = ray.inverse_transform_by(m);
        let (min_t, max_t) = aabb.clip_ray_parameters(&ls_ray)?;
        let (clip_ray_a, clip_ray_b) = (ls_ray.point_at(min_t), ls_ray.point_at(max_t));
        let mut cell = match self.cell_at_point(&clip_ray_a) {
            Some(cell) => cell,
            // None may happen due to slight numerical errors.
            None => {
                let i = if ls_ray.origin.z > N::zero() {
                    self.nrows()
                } else {
                    0
                };

                let j = if ls_ray.origin.x > N::zero() {
                    self.ncols()
                } else {
                    0
                };

                (i, j)
            }
        };

        loop {
            let tris = self.triangles_at(cell.0, cell.1);
            let inter1 = tris.0.and_then(|tri| tri.toi_and_normal_with_ray(m, ray, solid));
            let inter2 = tris.1.and_then(|tri| tri.toi_and_normal_with_ray(m, ray, solid));

            match (inter1, inter2) {
                (Some(inter1), Some(inter2)) => {
                    // XXX: adjust the feature ID.
                    if inter1.toi < inter2.toi {
                        return Some(inter1);
                    } else {
                        return Some(inter2);
                    }
                }
                (Some(inter), None) => {
                    // XXX: adjust the feature ID.
                    return Some(inter);
                }
                (None, Some(inter)) => {
                    // XXX: adjust the feature ID.
                    return Some(inter);
                }
                (None, None) => {}
            }

            /*
             * Find the next cell to cast the ray on.
             */
            let (toi_x, right) = if ls_ray.dir.x > N::zero() {
                let x = self.x_at(cell.1 + 1);
                ((x - ls_ray.origin.x) / ls_ray.dir.x, true)
            } else if ls_ray.dir.x < N::zero() {
                let x = self.x_at(cell.1 + 0);
                ((x - ls_ray.origin.x) / ls_ray.dir.x, false)
            } else {
                (N::max_value(), false)
            };

            let (toi_z, down) = if ls_ray.dir.z > N::zero() {
                let z = self.z_at(cell.0 + 1);
                ((z - ls_ray.origin.z) / ls_ray.dir.z, true)
            } else if ls_ray.dir.z < N::zero() {
                let z = self.z_at(cell.0 + 0);
                ((z - ls_ray.origin.z) / ls_ray.dir.z, false)
            } else {
                (N::max_value(), false)
            };

            if toi_x == N::max_value() && toi_z == N::max_value() {
                break;
            }

            if toi_x >= N::zero() && toi_x < toi_z {
                if right {
                    cell.1 += 1
                } else if cell.1 > 0 {
                    cell.1 -= 1
                } else {
                    break;
                }
            } else if toi_z >= N::zero() {
                if down {
                    cell.0 += 1
                } else if cell.0 > 0 {
                    cell.0 -= 1
                } else {
                    break
                }
            } else {
                break;
            }

            if cell.0 >= self.nrows() || cell.1 >= self.ncols() {
                break;
            }
        }

        None
    }
}
<|endoftext|>


<commit_before>use std::boxed::FnBox;
use std::collections::{HashMap, HashSet};
use std::sync::{RwLock, Arc};
use std::sync::atomic::{AtomicU64, Ordering};
use futures::Future;
use futures_cpupool::CpuPool;
use bifrost_hasher::{hash_str, hash_bytes};
use raft::RaftService;
use rpc;
use serde;
use super::super::{StateMachineCtl, OpType};
use super::super::super::RaftMsg;
use super::*;

lazy_static! {
    pub static ref SUBSCRIPTIONS: RwLock<HashMap<u64, Subscriptions>> = RwLock::new(HashMap::new());
    pub static ref THREAD_POOL:CpuPool = CpuPool::new_num_cpus();
}

pub struct Subscriber {
    pub session_id: u64,
    pub client: Arc<SyncServiceClient>
}

pub struct Subscriptions {
    next_id: u64,
    subscribers: HashMap<u64, Subscriber>,
    suber_subs: HashMap<u64, HashSet<u64>>, //suber_id -> sub_id
    subscriptions: HashMap<SubKey, HashSet<u64>>, // key -> sub_id
    sub_suber: HashMap<u64, u64>,
    sub_to_key: HashMap<u64, SubKey>, //sub_id -> sub_key
}

impl Subscriptions {

    pub fn new() -> Subscriptions {
        Subscriptions {
            next_id: 0,
            subscribers: HashMap::new(),
            suber_subs: HashMap::new(),
            subscriptions: HashMap::new(),
            sub_suber: HashMap::new(),
            sub_to_key: HashMap::new(),
        }
    }

    pub fn subscribe(&mut self, key: SubKey, address: String, session_id: u64) -> Result<u64, ()> {
        let sub_service_id = DEFAULT_SERVICE_ID;
        let suber_id = hash_str(address.clone());
        let suber_exists = self.subscribers.contains_key(&suber_id);
        let sub_id = self.next_id;
        let require_reload_suber = if suber_exists {
            let session_match = self.subscribers.get(&suber_id).unwrap().session_id == session_id;
            if !session_match {
                self.remove_subscriber(suber_id);
                true
            } else {false}
        } else {true};
        if !self.subscribers.contains_key(&suber_id) {
            self.subscribers.insert(suber_id, Subscriber {
                session_id: session_id,
                client: {
                    if let Ok(client) = rpc::DEFAULT_CLIENT_POOL.get(&address) {
                        SyncServiceClient::new(sub_service_id, client)
                    } else {
                        return Err(());
                    }
                }
            });
        }
        self.suber_subs.entry(suber_id).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.subscriptions.entry(key).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.sub_to_key.insert(sub_id, key);
        self.sub_suber.insert(sub_id, suber_id);

        self.next_id += 1;
        Ok(sub_id)
    }

    pub fn remove_subscriber(&mut self, suber_id: u64) {
        let suber_subs = if let Some(sub_ids) = self.suber_subs.get(&suber_id) {
            sub_ids.iter().cloned().collect()
        } else {Vec::<u64>::new()};
        for subs_id in suber_subs {
            self.remove_subscription(subs_id)
        }
        self.subscribers.remove(&suber_id);
        self.suber_subs.remove(&suber_id);
    }

    pub fn remove_subscription(&mut self, id: u64) {
        let sub_key = self.sub_to_key.remove(&id);
        if let Some(sub_key) = sub_key {
            if let Some(ref mut sub_subers) = self.subscriptions.get_mut(&sub_key) {
                sub_subers.remove(&id);
                self.sub_suber.remove(&id);
            }
        }
    }
}

pub struct SMCallback {
    pub raft_service: Arc<RaftService>,
    pub sm_id: u64,
}

impl SMCallback {
    pub fn new(state_machine_id: u64, raft_service: Arc<RaftService>) -> SMCallback {
        SMCallback {
            raft_service: raft_service,
            sm_id: state_machine_id,
        }
    }
    pub fn notify<R>(&self, func: &RaftMsg<R>, data: R)
    where R: serde::Serialize + Clone + Send + Sync {
        let (fn_id, op_type, pattern_data) = func.encode();
        match op_type {
            OpType::SUBSCRIBE => {
                let pattern_id = hash_bytes(&pattern_data.as_slice());
                let raft_sid = self.raft_service.options.service_id;
                let sm_id = self.sm_id;
                let key = (raft_sid, sm_id, fn_id, pattern_id);
                let subscriptions_map = SUBSCRIPTIONS.read().unwrap();
                if let Some(subscriptions) = subscriptions_map.get(&raft_sid) {
                    if let Some(sub_ids) = subscriptions.subscriptions.get(&key) {
                        let data = serialize!(&data);
                        for sub_id in sub_ids {
                            if let Some(subscriber_id) = subscriptions.sub_suber.get(&sub_id) {
                                if let Some(subscriber) = subscriptions.subscribers.get(&subscriber_id) {
                                    let data = data.clone();
                                    let client = subscriber.client.clone();
                                    println!("=============");
                                    THREAD_POOL.spawn_fn(move || -> Result<(), ()>{
                                        println!("------------");
                                        println!("NOTIFY: {:?}", client.notify(
                                            key, data
                                        ));
                                        Ok(())
                                    });
                                }
                            }
                        }
                    }
                }
            },
            _ => {}
        }
    }
}
<commit_msg>use normal threadpool than futures because futures delay<commit_after>use std::boxed::FnBox;
use std::collections::{HashMap, HashSet};
use std::sync::{RwLock, Mutex, Arc};
use std::sync::atomic::{AtomicU64, Ordering};
use threadpool::ThreadPool;
use num_cpus;
use bifrost_hasher::{hash_str, hash_bytes};
use raft::RaftService;
use rpc;
use serde;
use super::super::{StateMachineCtl, OpType};
use super::super::super::RaftMsg;
use super::*;

lazy_static! {
    pub static ref SUBSCRIPTIONS: RwLock<HashMap<u64, Subscriptions>> = RwLock::new(HashMap::new());
    pub static ref THREAD_POOL: Mutex<ThreadPool> = Mutex::new(ThreadPool::new(
                        num_cpus::get()
                    ));
}

pub struct Subscriber {
    pub session_id: u64,
    pub client: Arc<SyncServiceClient>
}

pub struct Subscriptions {
    next_id: u64,
    subscribers: HashMap<u64, Subscriber>,
    suber_subs: HashMap<u64, HashSet<u64>>, //suber_id -> sub_id
    subscriptions: HashMap<SubKey, HashSet<u64>>, // key -> sub_id
    sub_suber: HashMap<u64, u64>,
    sub_to_key: HashMap<u64, SubKey>, //sub_id -> sub_key
}

impl Subscriptions {

    pub fn new() -> Subscriptions {
        Subscriptions {
            next_id: 0,
            subscribers: HashMap::new(),
            suber_subs: HashMap::new(),
            subscriptions: HashMap::new(),
            sub_suber: HashMap::new(),
            sub_to_key: HashMap::new(),
        }
    }

    pub fn subscribe(&mut self, key: SubKey, address: String, session_id: u64) -> Result<u64, ()> {
        let sub_service_id = DEFAULT_SERVICE_ID;
        let suber_id = hash_str(address.clone());
        let suber_exists = self.subscribers.contains_key(&suber_id);
        let sub_id = self.next_id;
        let require_reload_suber = if suber_exists {
            let session_match = self.subscribers.get(&suber_id).unwrap().session_id == session_id;
            if !session_match {
                self.remove_subscriber(suber_id);
                true
            } else {false}
        } else {true};
        if !self.subscribers.contains_key(&suber_id) {
            self.subscribers.insert(suber_id, Subscriber {
                session_id: session_id,
                client: {
                    if let Ok(client) = rpc::DEFAULT_CLIENT_POOL.get(&address) {
                        SyncServiceClient::new(sub_service_id, client)
                    } else {
                        return Err(());
                    }
                }
            });
        }
        self.suber_subs.entry(suber_id).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.subscriptions.entry(key).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.sub_to_key.insert(sub_id, key);
        self.sub_suber.insert(sub_id, suber_id);

        self.next_id += 1;
        Ok(sub_id)
    }

    pub fn remove_subscriber(&mut self, suber_id: u64) {
        let suber_subs = if let Some(sub_ids) = self.suber_subs.get(&suber_id) {
            sub_ids.iter().cloned().collect()
        } else {Vec::<u64>::new()};
        for subs_id in suber_subs {
            self.remove_subscription(subs_id)
        }
        self.subscribers.remove(&suber_id);
        self.suber_subs.remove(&suber_id);
    }

    pub fn remove_subscription(&mut self, id: u64) {
        let sub_key = self.sub_to_key.remove(&id);
        if let Some(sub_key) = sub_key {
            if let Some(ref mut sub_subers) = self.subscriptions.get_mut(&sub_key) {
                sub_subers.remove(&id);
                self.sub_suber.remove(&id);
            }
        }
    }
}

pub struct SMCallback {
    pub raft_service: Arc<RaftService>,
    pub sm_id: u64,
}

impl SMCallback {
    pub fn new(state_machine_id: u64, raft_service: Arc<RaftService>) -> SMCallback {
        SMCallback {
            raft_service: raft_service,
            sm_id: state_machine_id,
        }
    }
    pub fn notify<R>(&self, func: &RaftMsg<R>, data: R)
    where R: serde::Serialize + Clone + Send + Sync {
        let (fn_id, op_type, pattern_data) = func.encode();
        match op_type {
            OpType::SUBSCRIBE => {
                let pattern_id = hash_bytes(&pattern_data.as_slice());
                let raft_sid = self.raft_service.options.service_id;
                let sm_id = self.sm_id;
                let key = (raft_sid, sm_id, fn_id, pattern_id);
                let subscriptions_map = SUBSCRIPTIONS.read().unwrap();
                if let Some(subscriptions) = subscriptions_map.get(&raft_sid) {
                    if let Some(sub_ids) = subscriptions.subscriptions.get(&key) {
                        let data = serialize!(&data);
                        for sub_id in sub_ids {
                            if let Some(subscriber_id) = subscriptions.sub_suber.get(&sub_id) {
                                if let Some(subscriber) = subscriptions.subscribers.get(&subscriber_id) {
                                    let data = data.clone();
                                    let client = subscriber.client.clone();
                                    THREAD_POOL.lock().unwrap().execute(move || {
                                        client.notify(key, data);
                                    });
                                }
                            }
                        }
                    }
                }
            },
            _ => {}
        }
    }
}
<|endoftext|>


<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::WatchmanFile;
use crate::compiler_state::{ProjectName, SourceSetName};
use crate::config::{Config, SchemaLocation};
use common::Timer;
use std::cmp::Reverse;
use std::collections::HashMap;
use std::ffi::OsStr;
use std::path::{Component, PathBuf};

#[derive(Debug, PartialEq, Eq, Hash)]
pub enum FileGroup {
    Generated,
    Schema { project_name: ProjectName },
    Extension { project_name: ProjectName },
    Source { source_set_name: SourceSetName },
}

/// The watchman query returns a list of files, but for the compiler we
/// need to categorize these files into multiple groups of files like
/// schema files, extensions and sources by their source set name.
///
/// See `FileGroup` for all groups of files.
pub fn categorize_files(
    config: &Config,
    files: &[WatchmanFile],
) -> HashMap<FileGroup, Vec<WatchmanFile>> {
    Timer::time("categorize", || {
        let categorizer = FileCategorizer::from_config(config);
        let mut categorized = HashMap::new();
        for file in files {
            categorized
                .entry(categorizer.categorize(&file.name))
                .or_insert_with(Vec::new)
                .push(file.clone());
        }
        categorized
    })
}

/// The FileCategorizer is created from a Config and categorizes files found by
/// Watchman into what kind of files they are, such as source files of a
/// specific source file group or generated files from some project.
struct FileCategorizer {
    extensions_mapping: PathMapping<ProjectName>,
    generated_str: &'static OsStr,
    source_mapping: PathMapping<SourceSetName>,
    schema_file_mapping: HashMap<PathBuf, ProjectName>,
    schema_dir_mapping: PathMapping<ProjectName>,
}

impl FileCategorizer {
    pub fn from_config(config: &Config) -> Self {
        let mut source_mapping: Vec<(PathBuf, SourceSetName)> =
            config.sources.clone().into_iter().collect();
        source_mapping.sort_by_key(|item| Reverse(item.0.clone()));

        let extensions_mapping = PathMapping(
            config
                .projects
                .iter()
                .flat_map(|(project_name, project_config)| {
                    project_config
                        .extensions
                        .iter()
                        .map(move |extension_dir| (extension_dir.clone(), *project_name))
                })
                .collect(),
        );

        let schema_file_mapping: HashMap<PathBuf, ProjectName> = config
            .projects
            .iter()
            .filter_map(
                |(&project_name, project_config)| match &project_config.schema_location {
                    SchemaLocation::File(schema_file) => Some((schema_file.clone(), project_name)),
                    SchemaLocation::Directory(_) => None,
                },
            )
            .collect();
        let schema_dir_mapping = PathMapping(
            config
                .projects
                .iter()
                .filter_map(|(&project_name, project_config)| {
                    match &project_config.schema_location {
                        SchemaLocation::File(_) => None,
                        SchemaLocation::Directory(schema_dir) => {
                            Some((schema_dir.clone(), project_name))
                        }
                    }
                })
                .collect(),
        );

        let generated_str = OsStr::new("__generated__");
        Self {
            extensions_mapping,
            generated_str,
            schema_file_mapping,
            schema_dir_mapping,
            source_mapping: PathMapping(source_mapping),
        }
    }

    pub fn categorize(&self, path: &PathBuf) -> FileGroup {
        let extension = path
            .extension()
            .unwrap_or_else(|| panic!("Got unexpected path without extension: `{:?}`.", path));
        if extension == "js" {
            if self.in_relative_generated_dir(path) {
                FileGroup::Generated
            } else {
                let source_set_name = self.source_mapping.get(path);
                FileGroup::Source { source_set_name }
            }
        } else if extension == "graphql" {
            if let Some(&project_name) = self.schema_file_mapping.get(path) {
                FileGroup::Schema { project_name }
            } else if let Some(project_name) = self.extensions_mapping.find(path) {
                FileGroup::Extension { project_name }
            } else if let Some(project_name) = self.schema_dir_mapping.find(path) {
                FileGroup::Schema { project_name }
            } else {
                panic!(
                    "Expected *.graphql file `{:?}` to be either a schema or extension.",
                    path
                )
            }
        } else {
            panic!(
                "Received file {:?} from watchman with unexpected extension.",
                path
            )
        }
    }

    fn in_relative_generated_dir(&self, path: &PathBuf) -> bool {
        path.components().any(|comp| match comp {
            Component::Normal(comp) => comp == self.generated_str,
            _ => false,
        })
    }
}

struct PathMapping<T: Copy>(Vec<(PathBuf, T)>);
impl<T: Copy> PathMapping<T> {
    fn get(&self, path: &PathBuf) -> T {
        self.find(path).unwrap_or_else(|| {
            panic!("Path `{:?}` not in of the the expected directories.", path);
        })
    }
    fn find(&self, path: &PathBuf) -> Option<T> {
        self.0.iter().find_map(|(prefix, item)| {
            if path.starts_with(prefix) {
                Some(*item)
            } else {
                None
            }
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use interner::Intern;

    #[test]
    fn test_categorize() {
        let config = Config::from_string_for_test(
            r#"
                {
                    "sources": {
                        "src/js": "public",
                        "src/js/internal": "internal",
                        "src/vendor": "public"
                    },
                    "projects": {
                        "public": {
                            "schema": "graphql/public.graphql"
                        },
                        "internal": {
                            "schema": "graphql/__generated__/internal.graphql"
                        }
                    }
                }
            "#,
        )
        .unwrap();
        let categorizer = FileCategorizer::from_config(&config);

        assert_eq!(
            categorizer.categorize(&"src/js/a.js".into()),
            FileGroup::Source {
                source_set_name: "public".intern(),
            },
        );
        assert_eq!(
            categorizer.categorize(&"src/js/nested/b.js".into()),
            FileGroup::Source {
                source_set_name: "public".intern(),
            },
        );
        assert_eq!(
            categorizer.categorize(&"src/js/internal/nested/c.js".into()),
            FileGroup::Source {
                source_set_name: "internal".intern(),
            },
        );
        assert_eq!(
            categorizer.categorize(&"src/js/internal/nested/__generated__/c.js".into()),
            FileGroup::Generated,
        );
        assert_eq!(
            categorizer.categorize(&"graphql/public.graphql".into()),
            FileGroup::Schema {
                project_name: "public".intern()
            },
        );
        assert_eq!(
            categorizer.categorize(&"graphql/__generated__/internal.graphql".into()),
            FileGroup::Schema {
                project_name: "internal".intern()
            },
        );
    }
}
<commit_msg>Fix categorizing custom generated dirs<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::WatchmanFile;
use crate::compiler_state::{ProjectName, SourceSetName};
use crate::config::{Config, SchemaLocation};
use common::Timer;
use std::cmp::Reverse;
use std::collections::{HashMap, HashSet};
use std::ffi::OsStr;
use std::path::{Component, PathBuf};

#[derive(Debug, PartialEq, Eq, Hash)]
pub enum FileGroup {
    Generated,
    Schema { project_name: ProjectName },
    Extension { project_name: ProjectName },
    Source { source_set_name: SourceSetName },
}

/// The watchman query returns a list of files, but for the compiler we
/// need to categorize these files into multiple groups of files like
/// schema files, extensions and sources by their source set name.
///
/// See `FileGroup` for all groups of files.
pub fn categorize_files(
    config: &Config,
    files: &[WatchmanFile],
) -> HashMap<FileGroup, Vec<WatchmanFile>> {
    Timer::time("categorize", || {
        let categorizer = FileCategorizer::from_config(config);
        let mut categorized = HashMap::new();
        for file in files {
            categorized
                .entry(categorizer.categorize(&file.name))
                .or_insert_with(Vec::new)
                .push(file.clone());
        }
        categorized
    })
}

/// The FileCategorizer is created from a Config and categorizes files found by
/// Watchman into what kind of files they are, such as source files of a
/// specific source file group or generated files from some project.
struct FileCategorizer {
    extensions_mapping: PathMapping<ProjectName>,
    default_generated_dir: &'static OsStr,
    generated_dir_paths: HashSet<PathBuf>,
    source_mapping: PathMapping<SourceSetName>,
    schema_file_mapping: HashMap<PathBuf, ProjectName>,
    schema_dir_mapping: PathMapping<ProjectName>,
}

impl FileCategorizer {
    pub fn from_config(config: &Config) -> Self {
        let mut source_mapping: Vec<(PathBuf, SourceSetName)> =
            config.sources.clone().into_iter().collect();
        source_mapping.sort_by_key(|item| Reverse(item.0.clone()));

        let extensions_mapping = PathMapping(
            config
                .projects
                .iter()
                .flat_map(|(project_name, project_config)| {
                    project_config
                        .extensions
                        .iter()
                        .map(move |extension_dir| (extension_dir.clone(), *project_name))
                })
                .collect(),
        );

        let schema_file_mapping: HashMap<PathBuf, ProjectName> = config
            .projects
            .iter()
            .filter_map(
                |(&project_name, project_config)| match &project_config.schema_location {
                    SchemaLocation::File(schema_file) => Some((schema_file.clone(), project_name)),
                    SchemaLocation::Directory(_) => None,
                },
            )
            .collect();
        let schema_dir_mapping = PathMapping(
            config
                .projects
                .iter()
                .filter_map(|(&project_name, project_config)| {
                    match &project_config.schema_location {
                        SchemaLocation::File(_) => None,
                        SchemaLocation::Directory(schema_dir) => {
                            Some((schema_dir.clone(), project_name))
                        }
                    }
                })
                .collect(),
        );

        let default_generated_dir = OsStr::new("__generated__");
        let generated_dir_paths: HashSet<PathBuf> = config
            .projects
            .iter()
            .filter_map(|(_, project_config)| project_config.output.clone())
            .collect();

        Self {
            extensions_mapping,
            default_generated_dir,
            generated_dir_paths,
            schema_file_mapping,
            schema_dir_mapping,
            source_mapping: PathMapping(source_mapping),
        }
    }

    pub fn categorize(&self, path: &PathBuf) -> FileGroup {
        let extension = path
            .extension()
            .unwrap_or_else(|| panic!("Got unexpected path without extension: `{:?}`.", path));
        if extension == "js" {
            if self.in_generated_dir(path) {
                FileGroup::Generated
            } else {
                let source_set_name = self.source_mapping.get(path);
                FileGroup::Source { source_set_name }
            }
        } else if extension == "graphql" {
            if let Some(&project_name) = self.schema_file_mapping.get(path) {
                FileGroup::Schema { project_name }
            } else if let Some(project_name) = self.extensions_mapping.find(path) {
                FileGroup::Extension { project_name }
            } else if let Some(project_name) = self.schema_dir_mapping.find(path) {
                FileGroup::Schema { project_name }
            } else {
                panic!(
                    "Expected *.graphql file `{:?}` to be either a schema or extension.",
                    path
                )
            }
        } else {
            panic!(
                "Received file {:?} from watchman with unexpected extension.",
                path
            )
        }
    }

    fn in_generated_dir(&self, path: &PathBuf) -> bool {
        self.in_absolute_generated_dir(path) || self.in_relative_generated_dir(path)
    }

    fn in_absolute_generated_dir(&self, path: &PathBuf) -> bool {
        self.generated_dir_paths
            .iter()
            .any(|generated_dir_path| path.starts_with(generated_dir_path))
    }

    fn in_relative_generated_dir(&self, path: &PathBuf) -> bool {
        path.components().any(|comp| match comp {
            Component::Normal(comp) => comp == self.default_generated_dir,
            _ => false,
        })
    }
}

struct PathMapping<T: Copy>(Vec<(PathBuf, T)>);
impl<T: Copy> PathMapping<T> {
    fn get(&self, path: &PathBuf) -> T {
        self.find(path).unwrap_or_else(|| {
            panic!("Path `{:?}` not in of the the expected directories.", path);
        })
    }
    fn find(&self, path: &PathBuf) -> Option<T> {
        self.0.iter().find_map(|(prefix, item)| {
            if path.starts_with(prefix) {
                Some(*item)
            } else {
                None
            }
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use interner::Intern;

    #[test]
    fn test_categorize() {
        let config = Config::from_string_for_test(
            r#"
                {
                    "sources": {
                        "src/js": "public",
                        "src/js/internal": "internal",
                        "src/vendor": "public",
                        "src/custom": "with_custom_generated_dir"
                    },
                    "projects": {
                        "public": {
                            "schema": "graphql/public.graphql"
                        },
                        "internal": {
                            "schema": "graphql/__generated__/internal.graphql"
                        },
                        "with_custom_generated_dir": {
                            "schema": "graphql/__generated__/custom.graphql",
                            "output": "graphql/custom-generated"
                        }
                    }
                }
            "#,
        )
        .unwrap();
        let categorizer = FileCategorizer::from_config(&config);

        assert_eq!(
            categorizer.categorize(&"src/js/a.js".into()),
            FileGroup::Source {
                source_set_name: "public".intern(),
            },
        );
        assert_eq!(
            categorizer.categorize(&"src/js/nested/b.js".into()),
            FileGroup::Source {
                source_set_name: "public".intern(),
            },
        );
        assert_eq!(
            categorizer.categorize(&"src/js/internal/nested/c.js".into()),
            FileGroup::Source {
                source_set_name: "internal".intern(),
            },
        );
        assert_eq!(
            // When custom output dir is provided, path is correctly categorized
            // even if it has same dirname in path as custom output folder.
            // Path is only categorized as generated if it matches the absolute path
            // of the provided custom output.
            categorizer.categorize(&"src/custom/custom-generated/c.js".into()),
            FileGroup::Source {
                source_set_name: "with_custom_generated_dir".intern(),
            },
        );
        assert_eq!(
            categorizer.categorize(&"src/js/internal/nested/__generated__/c.js".into()),
            FileGroup::Generated,
        );
        assert_eq!(
            categorizer.categorize(&"graphql/custom-generated/c.js".into()),
            FileGroup::Generated,
        );
        assert_eq!(
            categorizer.categorize(&"graphql/public.graphql".into()),
            FileGroup::Schema {
                project_name: "public".intern()
            },
        );
        assert_eq!(
            categorizer.categorize(&"graphql/__generated__/internal.graphql".into()),
            FileGroup::Schema {
                project_name: "internal".intern()
            },
        );
    }
}
<|endoftext|>


<commit_before>//! Utilities for rendering escape sequence errors as diagnostics.

use std::iter::once;
use std::ops::Range;

use rustc_errors::{pluralize, Applicability, Handler};
use rustc_lexer::unescape::{EscapeError, Mode};
use rustc_span::{BytePos, Span};

fn printing(ch: char) -> bool {
    unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) != 0 && !ch.is_whitespace()
}

pub(crate) fn emit_unescape_error(
    handler: &Handler,
    // interior part of the literal, without quotes
    lit: &str,
    // full span of the literal, including quotes
    span_with_quotes: Span,
    // interior span of the literal, without quotes
    span: Span,
    mode: Mode,
    // range of the error inside `lit`
    range: Range<usize>,
    error: EscapeError,
) {
    tracing::debug!(
        "emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}",
        lit,
        span_with_quotes,
        mode,
        range,
        error
    );
    let last_char = || {
        let c = lit[range.clone()].chars().rev().next().unwrap();
        let span = span.with_lo(span.hi() - BytePos(c.len_utf8() as u32));
        (c, span)
    };
    match error {
        EscapeError::LoneSurrogateUnicodeEscape => {
            handler
                .struct_span_err(span, "invalid unicode character escape")
                .span_label(span, "invalid escape")
                .help("unicode escape must not be a surrogate")
                .emit();
        }
        EscapeError::OutOfRangeUnicodeEscape => {
            handler
                .struct_span_err(span, "invalid unicode character escape")
                .span_label(span, "invalid escape")
                .help("unicode escape must be at most 10FFFF")
                .emit();
        }
        EscapeError::MoreThanOneChar => {
            use unicode_normalization::{char::is_combining_mark, UnicodeNormalization};

            let mut has_help = false;
            let mut handler = handler.struct_span_err(
                span_with_quotes,
                "character literal may only contain one codepoint",
            );

            if lit.chars().skip(1).all(|c| is_combining_mark(c)) {
                let escaped_marks =
                    lit.chars().skip(1).map(|c| c.escape_default().to_string()).collect::<Vec<_>>();
                handler.span_note(
                    span,
                    &format!(
                        "this `{}` is followed by the combining mark{} `{}`",
                        lit.chars().next().unwrap(),
                        pluralize!(escaped_marks.len()),
                        escaped_marks.join(""),
                    ),
                );
                let normalized = lit.nfc().to_string();
                if normalized.chars().count() == 1 {
                    has_help = true;
                    handler.span_suggestion(
                        span,
                        &format!(
                            "consider using the normalized form `{}` of this character",
                            normalized.chars().next().unwrap().escape_default()
                        ),
                        normalized,
                        Applicability::MachineApplicable,
                    );
                }
            } else {
                let printable: Vec<char> = lit.chars().filter(|x| printing(*x)).collect();

                if let [ch] = printable.as_slice() {
                    has_help = true;

                    handler.span_note(
                        span,
                        &format!(
                            "there are non-printing characters, the full sequence is `{}`",
                            lit.escape_default(),
                        ),
                    );

                    handler.span_suggestion(
                        span,
                        "consider removing the non-printing characters",
                        ch.to_string(),
                        Applicability::MaybeIncorrect,
                    );
                }
            }

            if !has_help {
                let (prefix, msg) = if mode.is_bytes() {
                    ("b", "if you meant to write a byte string literal, use double quotes")
                } else {
                    ("", "if you meant to write a `str` literal, use double quotes")
                };

                handler.span_suggestion(
                    span_with_quotes,
                    msg,
                    format!("{}\"{}\"", prefix, lit),
                    Applicability::MachineApplicable,
                );
            }

            handler.emit();
        }
        EscapeError::EscapeOnlyChar => {
            let (c, char_span) = last_char();

            let msg = if mode.is_bytes() {
                "byte constant must be escaped"
            } else {
                "character constant must be escaped"
            };
            handler
                .struct_span_err(span, &format!("{}: `{}`", msg, escaped_char(c)))
                .span_suggestion(
                    char_span,
                    "escape the character",
                    c.escape_default().to_string(),
                    Applicability::MachineApplicable,
                )
                .emit()
        }
        EscapeError::BareCarriageReturn => {
            let msg = if mode.in_double_quotes() {
                "bare CR not allowed in string, use `\\r` instead"
            } else {
                "character constant must be escaped: `\\r`"
            };
            handler
                .struct_span_err(span, msg)
                .span_suggestion(
                    span,
                    "escape the character",
                    "\\r".to_string(),
                    Applicability::MachineApplicable,
                )
                .emit();
        }
        EscapeError::BareCarriageReturnInRawString => {
            assert!(mode.in_double_quotes());
            let msg = "bare CR not allowed in raw string";
            handler.span_err(span, msg);
        }
        EscapeError::InvalidEscape => {
            let (c, span) = last_char();

            let label =
                if mode.is_bytes() { "unknown byte escape" } else { "unknown character escape" };
            let ec = escaped_char(c);
            let mut diag = handler.struct_span_err(span, &format!("{}: `{}`", label, ec));
            diag.span_label(span, label);
            if c == '{' || c == '}' && !mode.is_bytes() {
                diag.help(
                    "if used in a formatting string, curly braces are escaped with `{{` and `}}`",
                );
            } else if c == '\r' {
                diag.help(
                    "this is an isolated carriage return; consider checking your editor and \
                     version control settings",
                );
            } else {
                diag.help(
                    "for more information, visit \
                     <https://static.rust-lang.org/doc/master/reference.html#literals>",
                );
            }
            diag.emit();
        }
        EscapeError::TooShortHexEscape => {
            handler.span_err(span, "numeric character escape is too short")
        }
        EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => {
            let (c, span) = last_char();

            let msg = if error == EscapeError::InvalidCharInHexEscape {
                "invalid character in numeric character escape"
            } else {
                "invalid character in unicode escape"
            };
            let c = escaped_char(c);

            handler
                .struct_span_err(span, &format!("{}: `{}`", msg, c))
                .span_label(span, msg)
                .emit();
        }
        EscapeError::NonAsciiCharInByte => {
            assert!(mode.is_bytes());
            let (c, span) = last_char();
            let mut err = handler.struct_span_err(span, "non-ASCII character in byte constant");
            let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
                format!(" but is {:?}", c)
            } else {
                String::new()
            };
            err.span_label(span, &format!("byte constant must be ASCII{}", postfix));
            if (c as u32) <= 0xFF {
                err.span_suggestion(
                    span,
                    &format!(
                        "if you meant to use the unicode code point for {:?}, use a \\xHH escape",
                        c
                    ),
                    format!("\\x{:X}", c as u32),
                    Applicability::MaybeIncorrect,
                );
            } else if matches!(mode, Mode::Byte) {
                err.span_label(span, "this multibyte character does not fit into a single byte");
            } else if matches!(mode, Mode::ByteStr) {
                let mut utf8 = String::new();
                utf8.push(c);
                err.span_suggestion(
                    span,
                    &format!(
                        "if you meant to use the UTF-8 encoding of {:?}, use \\xHH escapes",
                        c
                    ),
                    utf8.as_bytes()
                        .iter()
                        .map(|b: &u8| format!("\\x{:X}", *b))
                        .fold("".to_string(), |a, c| a + &c),
                    Applicability::MaybeIncorrect,
                );
            }
            err.emit();
        }
        EscapeError::NonAsciiCharInByteString => {
            assert!(mode.is_bytes());
            let (c, span) = last_char();
            let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
                format!(" but is {:?}", c)
            } else {
                String::new()
            };
            handler
                .struct_span_err(span, "raw byte string must be ASCII")
                .span_label(span, &format!("must be ASCII{}", postfix))
                .emit();
        }
        EscapeError::OutOfRangeHexEscape => {
            handler
                .struct_span_err(span, "out of range hex escape")
                .span_label(span, "must be a character in the range [\\x00-\\x7f]")
                .emit();
        }
        EscapeError::LeadingUnderscoreUnicodeEscape => {
            let (c, span) = last_char();
            let msg = "invalid start of unicode escape";
            handler
                .struct_span_err(span, &format!("{}: `{}`", msg, c))
                .span_label(span, msg)
                .emit();
        }
        EscapeError::OverlongUnicodeEscape => {
            handler
                .struct_span_err(span, "overlong unicode escape")
                .span_label(span, "must have at most 6 hex digits")
                .emit();
        }
        EscapeError::UnclosedUnicodeEscape => handler
            .struct_span_err(span, "unterminated unicode escape")
            .span_label(span, "missing a closing `}`")
            .span_suggestion_verbose(
                span.shrink_to_hi(),
                "terminate the unicode escape",
                "}".to_string(),
                Applicability::MaybeIncorrect,
            )
            .emit(),
        EscapeError::NoBraceInUnicodeEscape => {
            let msg = "incorrect unicode escape sequence";
            let mut diag = handler.struct_span_err(span, msg);

            let mut suggestion = "\\u{".to_owned();
            let mut suggestion_len = 0;
            let (c, char_span) = last_char();
            let chars = once(c).chain(lit[range.end..].chars());
            for c in chars.take(6).take_while(|c| c.is_digit(16)) {
                suggestion.push(c);
                suggestion_len += c.len_utf8();
            }

            if suggestion_len > 0 {
                suggestion.push('}');
                let hi = char_span.lo() + BytePos(suggestion_len as u32);
                diag.span_suggestion(
                    span.with_hi(hi),
                    "format of unicode escape sequences uses braces",
                    suggestion,
                    Applicability::MaybeIncorrect,
                );
            } else {
                diag.span_label(span, msg);
                diag.help("format of unicode escape sequences is `\\u{...}`");
            }

            diag.emit();
        }
        EscapeError::UnicodeEscapeInByte => {
            let msg = "unicode escape in byte string";
            handler
                .struct_span_err(span, msg)
                .span_label(span, msg)
                .help("unicode escape sequences cannot be used as a byte or in a byte string")
                .emit();
        }
        EscapeError::EmptyUnicodeEscape => {
            handler
                .struct_span_err(span, "empty unicode escape")
                .span_label(span, "this escape must have at least 1 hex digit")
                .emit();
        }
        EscapeError::ZeroChars => {
            let msg = "empty character literal";
            handler.struct_span_err(span, msg).span_label(span, msg).emit()
        }
        EscapeError::LoneSlash => {
            let msg = "invalid trailing slash in literal";
            handler.struct_span_err(span, msg).span_label(span, msg).emit();
        }
        EscapeError::UnskippedWhitespaceWarning => {
            let (c, char_span) = last_char();
            let msg =
                format!("non-ASCII whitespace symbol '{}' is not skipped", c.escape_unicode());
            handler.struct_span_warn(span, &msg).span_label(char_span, &msg).emit();
        }
        EscapeError::MultipleSkippedLinesWarning => {
            let msg = "multiple lines skipped by escaped newline";
            let bottom_msg = "skipping everything up to and including this point";
            handler.struct_span_warn(span, msg).span_label(span, bottom_msg).emit();
        }
    }
}

/// Pushes a character to a message string for error reporting
pub(crate) fn escaped_char(c: char) -> String {
    match c {
        '\u{20}'..='\u{7e}' => {
            // Don't escape \, ' or " for user-facing messages
            c.to_string()
        }
        _ => c.escape_default().to_string(),
    }
}
<commit_msg>Inline printable function<commit_after>//! Utilities for rendering escape sequence errors as diagnostics.

use std::iter::once;
use std::ops::Range;

use rustc_errors::{pluralize, Applicability, Handler};
use rustc_lexer::unescape::{EscapeError, Mode};
use rustc_span::{BytePos, Span};

pub(crate) fn emit_unescape_error(
    handler: &Handler,
    // interior part of the literal, without quotes
    lit: &str,
    // full span of the literal, including quotes
    span_with_quotes: Span,
    // interior span of the literal, without quotes
    span: Span,
    mode: Mode,
    // range of the error inside `lit`
    range: Range<usize>,
    error: EscapeError,
) {
    tracing::debug!(
        "emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}",
        lit,
        span_with_quotes,
        mode,
        range,
        error
    );
    let last_char = || {
        let c = lit[range.clone()].chars().rev().next().unwrap();
        let span = span.with_lo(span.hi() - BytePos(c.len_utf8() as u32));
        (c, span)
    };
    match error {
        EscapeError::LoneSurrogateUnicodeEscape => {
            handler
                .struct_span_err(span, "invalid unicode character escape")
                .span_label(span, "invalid escape")
                .help("unicode escape must not be a surrogate")
                .emit();
        }
        EscapeError::OutOfRangeUnicodeEscape => {
            handler
                .struct_span_err(span, "invalid unicode character escape")
                .span_label(span, "invalid escape")
                .help("unicode escape must be at most 10FFFF")
                .emit();
        }
        EscapeError::MoreThanOneChar => {
            use unicode_normalization::{char::is_combining_mark, UnicodeNormalization};

            let mut has_help = false;
            let mut handler = handler.struct_span_err(
                span_with_quotes,
                "character literal may only contain one codepoint",
            );

            if lit.chars().skip(1).all(|c| is_combining_mark(c)) {
                let escaped_marks =
                    lit.chars().skip(1).map(|c| c.escape_default().to_string()).collect::<Vec<_>>();
                handler.span_note(
                    span,
                    &format!(
                        "this `{}` is followed by the combining mark{} `{}`",
                        lit.chars().next().unwrap(),
                        pluralize!(escaped_marks.len()),
                        escaped_marks.join(""),
                    ),
                );
                let normalized = lit.nfc().to_string();
                if normalized.chars().count() == 1 {
                    has_help = true;
                    handler.span_suggestion(
                        span,
                        &format!(
                            "consider using the normalized form `{}` of this character",
                            normalized.chars().next().unwrap().escape_default()
                        ),
                        normalized,
                        Applicability::MachineApplicable,
                    );
                }
            } else {
                let printable: Vec<char> = lit
                    .chars()
                    .filter(|&x| {
                        unicode_width::UnicodeWidthChar::width(x).unwrap_or(0) != 0
                            && !x.is_whitespace()
                    })
                    .collect();

                if let [ch] = printable.as_slice() {
                    has_help = true;

                    handler.span_note(
                        span,
                        &format!(
                            "there are non-printing characters, the full sequence is `{}`",
                            lit.escape_default(),
                        ),
                    );

                    handler.span_suggestion(
                        span,
                        "consider removing the non-printing characters",
                        ch.to_string(),
                        Applicability::MaybeIncorrect,
                    );
                }
            }

            if !has_help {
                let (prefix, msg) = if mode.is_bytes() {
                    ("b", "if you meant to write a byte string literal, use double quotes")
                } else {
                    ("", "if you meant to write a `str` literal, use double quotes")
                };

                handler.span_suggestion(
                    span_with_quotes,
                    msg,
                    format!("{}\"{}\"", prefix, lit),
                    Applicability::MachineApplicable,
                );
            }

            handler.emit();
        }
        EscapeError::EscapeOnlyChar => {
            let (c, char_span) = last_char();

            let msg = if mode.is_bytes() {
                "byte constant must be escaped"
            } else {
                "character constant must be escaped"
            };
            handler
                .struct_span_err(span, &format!("{}: `{}`", msg, escaped_char(c)))
                .span_suggestion(
                    char_span,
                    "escape the character",
                    c.escape_default().to_string(),
                    Applicability::MachineApplicable,
                )
                .emit()
        }
        EscapeError::BareCarriageReturn => {
            let msg = if mode.in_double_quotes() {
                "bare CR not allowed in string, use `\\r` instead"
            } else {
                "character constant must be escaped: `\\r`"
            };
            handler
                .struct_span_err(span, msg)
                .span_suggestion(
                    span,
                    "escape the character",
                    "\\r".to_string(),
                    Applicability::MachineApplicable,
                )
                .emit();
        }
        EscapeError::BareCarriageReturnInRawString => {
            assert!(mode.in_double_quotes());
            let msg = "bare CR not allowed in raw string";
            handler.span_err(span, msg);
        }
        EscapeError::InvalidEscape => {
            let (c, span) = last_char();

            let label =
                if mode.is_bytes() { "unknown byte escape" } else { "unknown character escape" };
            let ec = escaped_char(c);
            let mut diag = handler.struct_span_err(span, &format!("{}: `{}`", label, ec));
            diag.span_label(span, label);
            if c == '{' || c == '}' && !mode.is_bytes() {
                diag.help(
                    "if used in a formatting string, curly braces are escaped with `{{` and `}}`",
                );
            } else if c == '\r' {
                diag.help(
                    "this is an isolated carriage return; consider checking your editor and \
                     version control settings",
                );
            } else {
                diag.help(
                    "for more information, visit \
                     <https://static.rust-lang.org/doc/master/reference.html#literals>",
                );
            }
            diag.emit();
        }
        EscapeError::TooShortHexEscape => {
            handler.span_err(span, "numeric character escape is too short")
        }
        EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => {
            let (c, span) = last_char();

            let msg = if error == EscapeError::InvalidCharInHexEscape {
                "invalid character in numeric character escape"
            } else {
                "invalid character in unicode escape"
            };
            let c = escaped_char(c);

            handler
                .struct_span_err(span, &format!("{}: `{}`", msg, c))
                .span_label(span, msg)
                .emit();
        }
        EscapeError::NonAsciiCharInByte => {
            assert!(mode.is_bytes());
            let (c, span) = last_char();
            let mut err = handler.struct_span_err(span, "non-ASCII character in byte constant");
            let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
                format!(" but is {:?}", c)
            } else {
                String::new()
            };
            err.span_label(span, &format!("byte constant must be ASCII{}", postfix));
            if (c as u32) <= 0xFF {
                err.span_suggestion(
                    span,
                    &format!(
                        "if you meant to use the unicode code point for {:?}, use a \\xHH escape",
                        c
                    ),
                    format!("\\x{:X}", c as u32),
                    Applicability::MaybeIncorrect,
                );
            } else if matches!(mode, Mode::Byte) {
                err.span_label(span, "this multibyte character does not fit into a single byte");
            } else if matches!(mode, Mode::ByteStr) {
                let mut utf8 = String::new();
                utf8.push(c);
                err.span_suggestion(
                    span,
                    &format!(
                        "if you meant to use the UTF-8 encoding of {:?}, use \\xHH escapes",
                        c
                    ),
                    utf8.as_bytes()
                        .iter()
                        .map(|b: &u8| format!("\\x{:X}", *b))
                        .fold("".to_string(), |a, c| a + &c),
                    Applicability::MaybeIncorrect,
                );
            }
            err.emit();
        }
        EscapeError::NonAsciiCharInByteString => {
            assert!(mode.is_bytes());
            let (c, span) = last_char();
            let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
                format!(" but is {:?}", c)
            } else {
                String::new()
            };
            handler
                .struct_span_err(span, "raw byte string must be ASCII")
                .span_label(span, &format!("must be ASCII{}", postfix))
                .emit();
        }
        EscapeError::OutOfRangeHexEscape => {
            handler
                .struct_span_err(span, "out of range hex escape")
                .span_label(span, "must be a character in the range [\\x00-\\x7f]")
                .emit();
        }
        EscapeError::LeadingUnderscoreUnicodeEscape => {
            let (c, span) = last_char();
            let msg = "invalid start of unicode escape";
            handler
                .struct_span_err(span, &format!("{}: `{}`", msg, c))
                .span_label(span, msg)
                .emit();
        }
        EscapeError::OverlongUnicodeEscape => {
            handler
                .struct_span_err(span, "overlong unicode escape")
                .span_label(span, "must have at most 6 hex digits")
                .emit();
        }
        EscapeError::UnclosedUnicodeEscape => handler
            .struct_span_err(span, "unterminated unicode escape")
            .span_label(span, "missing a closing `}`")
            .span_suggestion_verbose(
                span.shrink_to_hi(),
                "terminate the unicode escape",
                "}".to_string(),
                Applicability::MaybeIncorrect,
            )
            .emit(),
        EscapeError::NoBraceInUnicodeEscape => {
            let msg = "incorrect unicode escape sequence";
            let mut diag = handler.struct_span_err(span, msg);

            let mut suggestion = "\\u{".to_owned();
            let mut suggestion_len = 0;
            let (c, char_span) = last_char();
            let chars = once(c).chain(lit[range.end..].chars());
            for c in chars.take(6).take_while(|c| c.is_digit(16)) {
                suggestion.push(c);
                suggestion_len += c.len_utf8();
            }

            if suggestion_len > 0 {
                suggestion.push('}');
                let hi = char_span.lo() + BytePos(suggestion_len as u32);
                diag.span_suggestion(
                    span.with_hi(hi),
                    "format of unicode escape sequences uses braces",
                    suggestion,
                    Applicability::MaybeIncorrect,
                );
            } else {
                diag.span_label(span, msg);
                diag.help("format of unicode escape sequences is `\\u{...}`");
            }

            diag.emit();
        }
        EscapeError::UnicodeEscapeInByte => {
            let msg = "unicode escape in byte string";
            handler
                .struct_span_err(span, msg)
                .span_label(span, msg)
                .help("unicode escape sequences cannot be used as a byte or in a byte string")
                .emit();
        }
        EscapeError::EmptyUnicodeEscape => {
            handler
                .struct_span_err(span, "empty unicode escape")
                .span_label(span, "this escape must have at least 1 hex digit")
                .emit();
        }
        EscapeError::ZeroChars => {
            let msg = "empty character literal";
            handler.struct_span_err(span, msg).span_label(span, msg).emit()
        }
        EscapeError::LoneSlash => {
            let msg = "invalid trailing slash in literal";
            handler.struct_span_err(span, msg).span_label(span, msg).emit();
        }
        EscapeError::UnskippedWhitespaceWarning => {
            let (c, char_span) = last_char();
            let msg =
                format!("non-ASCII whitespace symbol '{}' is not skipped", c.escape_unicode());
            handler.struct_span_warn(span, &msg).span_label(char_span, &msg).emit();
        }
        EscapeError::MultipleSkippedLinesWarning => {
            let msg = "multiple lines skipped by escaped newline";
            let bottom_msg = "skipping everything up to and including this point";
            handler.struct_span_warn(span, msg).span_label(span, bottom_msg).emit();
        }
    }
}

/// Pushes a character to a message string for error reporting
pub(crate) fn escaped_char(c: char) -> String {
    match c {
        '\u{20}'..='\u{7e}' => {
            // Don't escape \, ' or " for user-facing messages
            c.to_string()
        }
        _ => c.escape_default().to_string(),
    }
}
<|endoftext|>