<commit_before>use internal::prelude::*;
use internal::ws_impl::ReceiverExt;
use model::event::{Event, GatewayEvent};
use parking_lot::Mutex as ParkingLotMutex;
use std::sync::mpsc::{self, Receiver, Sender};
use std::sync::Arc;
use super::super::super::{EventHandler, dispatch};
use super::{LockedShard, ShardId, ShardManagerMessage};
use typemap::ShareMap;
use websocket::WebSocketError;

#[cfg(feature = "framework")]
use framework::Framework;
#[cfg(feature = "framework")]
use std::sync::Mutex;

pub struct ShardRunner<H: EventHandler + 'static> {
    data: Arc<ParkingLotMutex<ShareMap>>,
    event_handler: Arc<H>,
    #[cfg(feature = "framework")]
    framework: Arc<Mutex<Option<Box<Framework + Send>>>>,
    manager_tx: Sender<ShardManagerMessage>,
    runner_rx: Receiver<ShardManagerMessage>,
    runner_tx: Sender<ShardManagerMessage>,
    shard: LockedShard,
    shard_info: [u64; 2],
}

impl<H: EventHandler + 'static> ShardRunner<H> {
    #[cfg(feature = "framework")]
    pub fn new(shard: LockedShard,
               manager_tx: Sender<ShardManagerMessage>,
               framework: Arc<Mutex<Option<Box<Framework + Send>>>>,
               data: Arc<ParkingLotMutex<ShareMap>>,
               event_handler: Arc<H>) -> Self {
        let (tx, rx) = mpsc::channel();
        let shard_info = shard.lock().shard_info();

        Self {
            runner_rx: rx,
            runner_tx: tx,
            data,
            event_handler,
            framework,
            manager_tx,
            shard,
            shard_info,
        }
    }

    #[cfg(not(feature = "framework"))]
    pub fn new(shard: LockedShard,
               manager_tx: Sender<ShardManagerMessage>,
               data: Arc<ParkingLotMutex<ShareMap>>,
               event_handler: Arc<H>) -> Self {
        let (tx, rx) = mpsc::channel();
        let shard_info = shard.lock().shard_info();

        Self {
            runner_rx: rx,
            runner_tx: tx,
            data,
            event_handler,
            manager_tx,
            shard,
            shard_info,
        }
    }

    pub fn run(&mut self) -> Result<()> {
        debug!("[ShardRunner {:?}] Running", self.shard_info);

        loop {
            {
                let mut shard = self.shard.lock();
                let incoming = self.runner_rx.try_recv();

                // Check for an incoming message over the runner channel.
                //
                // If the message is to shutdown, first verify the ID so we know
                // for certain this runner is to shutdown.
                if let Ok(ShardManagerMessage::Shutdown(id)) = incoming {
                    if id.0 == self.shard_info[0] {
                        let _ = shard.shutdown_clean();

                        return Ok(());
                    }
                }

                if let Err(why) = shard.check_heartbeat() {
                    error!("Failed to heartbeat and reconnect: {:?}", why);

                    return self.request_restart();
                }

                #[cfg(feature = "voice")]
                {
                    shard.cycle_voice_recv();
                }
            }

            let (event, successful) = self.recv_events();

            if let Some(event) = event {
                dispatch(
                    event,
                    &self.shard,
                    #[cfg(feature = "framework")]
                    &self.framework,
                    &self.data,
                    &self.event_handler,
                );
            }

            if !successful && !self.shard.lock().stage().is_connecting() {
                return self.request_restart();
            }
        }
    }

    pub(super) fn runner_tx(&self) -> Sender<ShardManagerMessage> {
        self.runner_tx.clone()
    }

    /// Returns a received event, as well as whether reading the potentially
    /// present event was successful.
    fn recv_events(&mut self) -> (Option<Event>, bool) {
        let mut shard = self.shard.lock();

        let gw_event = match shard.client.recv_json(GatewayEvent::decode) {
            Err(Error::WebSocket(WebSocketError::IoError(_))) => {
                // Check that an amount of time at least double the
                // heartbeat_interval has passed.
                //
                // If not, continue on trying to receive messages.
                //
                // If it has, attempt to auto-reconnect.
                let last = shard.last_heartbeat_ack();
                let interval = shard.heartbeat_interval();

                if let (Some(last_heartbeat_ack), Some(interval)) = (last, interval) {
                    let seconds_passed = last_heartbeat_ack.elapsed().as_secs();
                    let interval_in_secs = interval / 1000;

                    if seconds_passed <= interval_in_secs * 2 {
                        return (None, true);
                    }
                } else {
                    return (None, true);
                }

                debug!("Attempting to auto-reconnect");

                if let Err(why) = shard.autoreconnect() {
                    error!("Failed to auto-reconnect: {:?}", why);
                }

                return (None, true);
            },
            Err(Error::WebSocket(WebSocketError::NoDataAvailable)) => {
                // This is hit when the websocket client dies this will be
                // hit every iteration.
                return (None, false);
            },
            other => other,
        };

        let event = match gw_event {
            Ok(Some(event)) => Ok(event),
            Ok(None) => return (None, true),
            Err(why) => Err(why),
        };

        let event = match shard.handle_event(event) {
            Ok(Some(event)) => event,
            Ok(None) => return (None, true),
            Err(why) => {
                error!("Shard handler received err: {:?}", why);

                return (None, true);
            },
         };

        (Some(event), true)
    }

    fn request_restart(&self) -> Result<()> {
        debug!("[ShardRunner {:?}] Requesting restart", self.shard_info);
        let msg = ShardManagerMessage::Restart(ShardId(self.shard_info[0]));
        let _ = self.manager_tx.send(msg);

        Ok(())
    }
}
<commit_msg>Rename an internal Shard Runner method<commit_after>use internal::prelude::*;
use internal::ws_impl::ReceiverExt;
use model::event::{Event, GatewayEvent};
use parking_lot::Mutex as ParkingLotMutex;
use std::sync::mpsc::{self, Receiver, Sender};
use std::sync::Arc;
use super::super::super::{EventHandler, dispatch};
use super::{LockedShard, ShardId, ShardManagerMessage};
use typemap::ShareMap;
use websocket::WebSocketError;

#[cfg(feature = "framework")]
use framework::Framework;
#[cfg(feature = "framework")]
use std::sync::Mutex;

pub struct ShardRunner<H: EventHandler + 'static> {
    data: Arc<ParkingLotMutex<ShareMap>>,
    event_handler: Arc<H>,
    #[cfg(feature = "framework")]
    framework: Arc<Mutex<Option<Box<Framework + Send>>>>,
    manager_tx: Sender<ShardManagerMessage>,
    runner_rx: Receiver<ShardManagerMessage>,
    runner_tx: Sender<ShardManagerMessage>,
    shard: LockedShard,
    shard_info: [u64; 2],
}

impl<H: EventHandler + 'static> ShardRunner<H> {
    #[cfg(feature = "framework")]
    pub fn new(shard: LockedShard,
               manager_tx: Sender<ShardManagerMessage>,
               framework: Arc<Mutex<Option<Box<Framework + Send>>>>,
               data: Arc<ParkingLotMutex<ShareMap>>,
               event_handler: Arc<H>) -> Self {
        let (tx, rx) = mpsc::channel();
        let shard_info = shard.lock().shard_info();

        Self {
            runner_rx: rx,
            runner_tx: tx,
            data,
            event_handler,
            framework,
            manager_tx,
            shard,
            shard_info,
        }
    }

    #[cfg(not(feature = "framework"))]
    pub fn new(shard: LockedShard,
               manager_tx: Sender<ShardManagerMessage>,
               data: Arc<ParkingLotMutex<ShareMap>>,
               event_handler: Arc<H>) -> Self {
        let (tx, rx) = mpsc::channel();
        let shard_info = shard.lock().shard_info();

        Self {
            runner_rx: rx,
            runner_tx: tx,
            data,
            event_handler,
            manager_tx,
            shard,
            shard_info,
        }
    }

    pub fn run(&mut self) -> Result<()> {
        debug!("[ShardRunner {:?}] Running", self.shard_info);

        loop {
            {
                let mut shard = self.shard.lock();
                let incoming = self.runner_rx.try_recv();

                // Check for an incoming message over the runner channel.
                //
                // If the message is to shutdown, first verify the ID so we know
                // for certain this runner is to shutdown.
                if let Ok(ShardManagerMessage::Shutdown(id)) = incoming {
                    if id.0 == self.shard_info[0] {
                        let _ = shard.shutdown_clean();

                        return Ok(());
                    }
                }

                if let Err(why) = shard.check_heartbeat() {
                    error!("Failed to heartbeat and reconnect: {:?}", why);

                    return self.request_restart();
                }

                #[cfg(feature = "voice")]
                {
                    shard.cycle_voice_recv();
                }
            }

            let (event, successful) = self.recv_event();

            if let Some(event) = event {
                dispatch(
                    event,
                    &self.shard,
                    #[cfg(feature = "framework")]
                    &self.framework,
                    &self.data,
                    &self.event_handler,
                );
            }

            if !successful && !self.shard.lock().stage().is_connecting() {
                return self.request_restart();
            }
        }
    }

    pub(super) fn runner_tx(&self) -> Sender<ShardManagerMessage> {
        self.runner_tx.clone()
    }

    /// Returns a received event, as well as whether reading the potentially
    /// present event was successful.
    fn recv_event(&mut self) -> (Option<Event>, bool) {
        let mut shard = self.shard.lock();

        let gw_event = match shard.client.recv_json(GatewayEvent::decode) {
            Err(Error::WebSocket(WebSocketError::IoError(_))) => {
                // Check that an amount of time at least double the
                // heartbeat_interval has passed.
                //
                // If not, continue on trying to receive messages.
                //
                // If it has, attempt to auto-reconnect.
                let last = shard.last_heartbeat_ack();
                let interval = shard.heartbeat_interval();

                if let (Some(last_heartbeat_ack), Some(interval)) = (last, interval) {
                    let seconds_passed = last_heartbeat_ack.elapsed().as_secs();
                    let interval_in_secs = interval / 1000;

                    if seconds_passed <= interval_in_secs * 2 {
                        return (None, true);
                    }
                } else {
                    return (None, true);
                }

                debug!("Attempting to auto-reconnect");

                if let Err(why) = shard.autoreconnect() {
                    error!("Failed to auto-reconnect: {:?}", why);
                }

                return (None, true);
            },
            Err(Error::WebSocket(WebSocketError::NoDataAvailable)) => {
                // This is hit when the websocket client dies this will be
                // hit every iteration.
                return (None, false);
            },
            other => other,
        };

        let event = match gw_event {
            Ok(Some(event)) => Ok(event),
            Ok(None) => return (None, true),
            Err(why) => Err(why),
        };

        let event = match shard.handle_event(event) {
            Ok(Some(event)) => event,
            Ok(None) => return (None, true),
            Err(why) => {
                error!("Shard handler received err: {:?}", why);

                return (None, true);
            },
         };

        (Some(event), true)
    }

    fn request_restart(&self) -> Result<()> {
        debug!("[ShardRunner {:?}] Requesting restart", self.shard_info);
        let msg = ShardManagerMessage::Restart(ShardId(self.shard_info[0]));
        let _ = self.manager_tx.send(msg);

        Ok(())
    }
}
<|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 http://mozilla.org/MPL/2.0/.

// Code to handle initial setup steps for a pool.
// Initial setup steps are steps that do not alter the environment.

use std::collections::{HashMap, HashSet};
use std::fs::{OpenOptions, read_dir};
use std::io::ErrorKind;
use std::path::PathBuf;

use nix::errno::Errno;
use serde_json;

use devicemapper::{Device, devnode_to_devno};

use super::super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::super::types::PoolUuid;

use super::super::engine::DevOwnership;
use super::super::serde_structs::{BackstoreSave, PoolSave};

use super::blockdev::StratBlockDev;
use super::device::blkdev_size;
use super::metadata::{BDA, StaticHeader};

/// Determine if devnode is a stratis device, if it is we will add  pool uuid and device
/// information to pool_map and return pool uuid.
pub fn is_stratis_device(devnode: &PathBuf) -> EngineResult<Option<PoolUuid>> {
    match OpenOptions::new().read(true).open(&devnode) {
        Ok(mut f) => {
            if let DevOwnership::Ours(pool_uuid, _) = StaticHeader::determine_ownership(&mut f)? {
                Ok(Some(pool_uuid))
            } else {
                Ok(None)
            }
        }
        Err(err) => {
            // There are some reasons for OpenOptions::open() to return an error
            // which are not reasons for this method to return an error.
            // Try to distinguish. Non-error conditions are:
            //
            // 1. ENXIO: The device does not exist anymore. This means that the device
            // was volatile for some reason; in that case it can not belong to
            // Stratis so it is safe to ignore it.
            //
            // 2. ENOMEDIUM: The device has no medium. An example of this case is an
            // empty optical drive.
            //
            // Note that it is better to be conservative and return with an
            // error in any case where failure to read the device could result
            // in bad data for Stratis. Additional exceptions may be added,
            // but only with a complete justification.
            match err.kind() {
                ErrorKind::NotFound => Ok(None),
                _ => {
                    if let Some(errno) = err.raw_os_error() {
                        match Errno::from_i32(errno) {
                            Errno::ENXIO | Errno::ENOMEDIUM => Ok(None),
                            _ => Err(EngineError::Io(err)),
                        }
                    } else {
                        Err(EngineError::Io(err))
                    }
                }
            }
        }
    }
}

/// Find all Stratis devices.
///
/// Returns a map of pool uuids to a map of devices to devnodes for each pool.
pub fn find_all() -> EngineResult<HashMap<PoolUuid, HashMap<Device, PathBuf>>> {

    let mut pool_map = HashMap::new();
    let mut devno_set = HashSet::new();
    for dir_e in read_dir("/dev")? {
        let dir_e = dir_e?;
        let devnode = dir_e.path();

        match devnode_to_devno(&devnode)? {
            None => continue,
            Some(devno) => {
                if devno_set.insert(devno) {
                    is_stratis_device(&devnode)?
                        .and_then(|pool_uuid| {
                                      pool_map
                                          .entry(pool_uuid)
                                          .or_insert_with(HashMap::new)
                                          .insert(Device::from(devno), devnode)
                                  });
                } else {
                    continue;
                }
            }
        }
    }

    Ok(pool_map)
}

/// Get the most recent metadata from a set of Devices for a given pool UUID.
/// Returns None if no metadata found for this pool.
#[allow(implicit_hasher)]
pub fn get_metadata(pool_uuid: PoolUuid,
                    devnodes: &HashMap<Device, PathBuf>)
                    -> EngineResult<Option<PoolSave>> {

    // Get pairs of device nodes and matching BDAs
    // If no BDA, or BDA UUID does not match pool UUID, skip.
    // If there is an error reading the BDA, error. There could have been
    // vital information on that BDA, for example, it may have contained
    // the newest metadata.
    let mut bdas = Vec::new();
    for devnode in devnodes.values() {
        let bda = BDA::load(&mut OpenOptions::new().read(true).open(devnode)?)?;
        if let Some(bda) = bda {
            if bda.pool_uuid() == pool_uuid {
                bdas.push((devnode, bda));
            }
        }
    }

    // Most recent time should never be None if this was a properly
    // created pool; this allows for the method to be called in other
    // circumstances.
    let most_recent_time = {
        match bdas.iter()
                  .filter_map(|&(_, ref bda)| bda.last_update_time())
                  .max() {
            Some(time) => time,
            None => return Ok(None),
        }
    };

    // Try to read from all available devnodes that could contain most
    // recent metadata. In the event of errors, continue to try until all are
    // exhausted.
    for &(devnode, ref bda) in
        bdas.iter()
            .filter(|&&(_, ref bda)| bda.last_update_time() == Some(most_recent_time)) {

        let poolsave = OpenOptions::new()
            .read(true)
            .open(devnode)
            .ok()
            .and_then(|mut f| bda.load_state(&mut f).ok())
            .and_then(|opt| opt)
            .and_then(|data| serde_json::from_slice(&data).ok());

        if poolsave.is_some() {
            return Ok(poolsave);
        }
    }

    // If no data has yet returned, we have an error. That is, we should have
    // some metadata, because we have a most recent time, but we failed to
    // get any.
    let err_str = "timestamp indicates data was written, but no data successfully read";
    Err(EngineError::Engine(ErrorEnum::NotFound, err_str.into()))
}

/// Get all the blockdevs corresponding to this pool that can be obtained from
/// the given devices. Return them in the order in which they were written
/// in the metadata.
/// Returns an error if the blockdevs obtained do not match the metadata.
#[allow(implicit_hasher)]
pub fn get_blockdevs(pool_uuid: PoolUuid,
                     backstore_save: &BackstoreSave,
                     devnodes: &HashMap<Device, PathBuf>)
                     -> EngineResult<Vec<StratBlockDev>> {
    let segments = &backstore_save.segments;

    let mut segment_table = HashMap::new();
    for seg in segments {
        segment_table
            .entry(seg.0)
            .or_insert_with(Vec::default)
            .push((seg.1, seg.2))
    }

    let mut blockdevs = vec![];
    for (device, devnode) in devnodes {
        let bda = BDA::load(&mut OpenOptions::new().read(true).open(devnode)?)?;
        if let Some(bda) = bda {
            if bda.pool_uuid() == pool_uuid {
                let actual_size = blkdev_size(&OpenOptions::new().read(true).open(devnode)?)?
                    .sectors();

                let bd_save = backstore_save
                    .block_devs
                    .iter()
                    .find(|bds| bds.uuid == bda.dev_uuid())
                    .ok_or_else(|| {
                                    let err_msg = format!("Blockdev {} not found in metadata",
                                                          bda.dev_uuid());
                                    EngineError::Engine(ErrorEnum::NotFound, err_msg)
                                })?;

                // If the size of the device has changed and is less,
                // then it is possible that the segments previously allocated
                // for this blockdev no longer exist. If that is the case,
                // StratBlockDev::new will return an error.
                // NOTE: Currently, all blockdevs have all their space
                // allocated to the DM device in the data tier. As long as
                // that is the case, this block will always return an error
                // if the blockdev size has decreased.
                let segments = segment_table.get(&bda.dev_uuid());
                blockdevs.push(StratBlockDev::new(*device,
                                                  devnode.to_owned(),
                                                  actual_size,
                                                  bda,
                                                  segments.unwrap_or(&vec![]),
                                                  bd_save.user_info.clone(),
                                                  bd_save.hardware_info.clone())?);
            }
        }
    }

    // Verify that blockdevs found match blockdevs recorded.
    let current_uuids: HashSet<_> = blockdevs.iter().map(|b| b.uuid()).collect();
    let recorded_uuids: HashSet<_> = backstore_save
        .block_devs
        .iter()
        .map(|bds| bds.uuid)
        .collect();

    if current_uuids != recorded_uuids {
        let err_msg = "Recorded block dev UUIDs != discovered blockdev UUIDs";
        return Err(EngineError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    if blockdevs.len() != current_uuids.len() {
        let err_msg = "Duplicate block devices found in environment";
        return Err(EngineError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    Ok(blockdevs)
}
<commit_msg>Add an explicit guard to detect decreased blockdev size<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 http://mozilla.org/MPL/2.0/.

// Code to handle initial setup steps for a pool.
// Initial setup steps are steps that do not alter the environment.

use std::collections::{HashMap, HashSet};
use std::fs::{OpenOptions, read_dir};
use std::io::ErrorKind;
use std::path::PathBuf;

use nix::errno::Errno;
use serde_json;

use devicemapper::{Device, devnode_to_devno};

use super::super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::super::types::PoolUuid;

use super::super::engine::DevOwnership;
use super::super::serde_structs::{BackstoreSave, PoolSave};

use super::blockdev::StratBlockDev;
use super::device::blkdev_size;
use super::metadata::{BDA, StaticHeader};

/// Determine if devnode is a stratis device, if it is we will add  pool uuid and device
/// information to pool_map and return pool uuid.
pub fn is_stratis_device(devnode: &PathBuf) -> EngineResult<Option<PoolUuid>> {
    match OpenOptions::new().read(true).open(&devnode) {
        Ok(mut f) => {
            if let DevOwnership::Ours(pool_uuid, _) = StaticHeader::determine_ownership(&mut f)? {
                Ok(Some(pool_uuid))
            } else {
                Ok(None)
            }
        }
        Err(err) => {
            // There are some reasons for OpenOptions::open() to return an error
            // which are not reasons for this method to return an error.
            // Try to distinguish. Non-error conditions are:
            //
            // 1. ENXIO: The device does not exist anymore. This means that the device
            // was volatile for some reason; in that case it can not belong to
            // Stratis so it is safe to ignore it.
            //
            // 2. ENOMEDIUM: The device has no medium. An example of this case is an
            // empty optical drive.
            //
            // Note that it is better to be conservative and return with an
            // error in any case where failure to read the device could result
            // in bad data for Stratis. Additional exceptions may be added,
            // but only with a complete justification.
            match err.kind() {
                ErrorKind::NotFound => Ok(None),
                _ => {
                    if let Some(errno) = err.raw_os_error() {
                        match Errno::from_i32(errno) {
                            Errno::ENXIO | Errno::ENOMEDIUM => Ok(None),
                            _ => Err(EngineError::Io(err)),
                        }
                    } else {
                        Err(EngineError::Io(err))
                    }
                }
            }
        }
    }
}

/// Find all Stratis devices.
///
/// Returns a map of pool uuids to a map of devices to devnodes for each pool.
pub fn find_all() -> EngineResult<HashMap<PoolUuid, HashMap<Device, PathBuf>>> {

    let mut pool_map = HashMap::new();
    let mut devno_set = HashSet::new();
    for dir_e in read_dir("/dev")? {
        let dir_e = dir_e?;
        let devnode = dir_e.path();

        match devnode_to_devno(&devnode)? {
            None => continue,
            Some(devno) => {
                if devno_set.insert(devno) {
                    is_stratis_device(&devnode)?
                        .and_then(|pool_uuid| {
                                      pool_map
                                          .entry(pool_uuid)
                                          .or_insert_with(HashMap::new)
                                          .insert(Device::from(devno), devnode)
                                  });
                } else {
                    continue;
                }
            }
        }
    }

    Ok(pool_map)
}

/// Get the most recent metadata from a set of Devices for a given pool UUID.
/// Returns None if no metadata found for this pool.
#[allow(implicit_hasher)]
pub fn get_metadata(pool_uuid: PoolUuid,
                    devnodes: &HashMap<Device, PathBuf>)
                    -> EngineResult<Option<PoolSave>> {

    // Get pairs of device nodes and matching BDAs
    // If no BDA, or BDA UUID does not match pool UUID, skip.
    // If there is an error reading the BDA, error. There could have been
    // vital information on that BDA, for example, it may have contained
    // the newest metadata.
    let mut bdas = Vec::new();
    for devnode in devnodes.values() {
        let bda = BDA::load(&mut OpenOptions::new().read(true).open(devnode)?)?;
        if let Some(bda) = bda {
            if bda.pool_uuid() == pool_uuid {
                bdas.push((devnode, bda));
            }
        }
    }

    // Most recent time should never be None if this was a properly
    // created pool; this allows for the method to be called in other
    // circumstances.
    let most_recent_time = {
        match bdas.iter()
                  .filter_map(|&(_, ref bda)| bda.last_update_time())
                  .max() {
            Some(time) => time,
            None => return Ok(None),
        }
    };

    // Try to read from all available devnodes that could contain most
    // recent metadata. In the event of errors, continue to try until all are
    // exhausted.
    for &(devnode, ref bda) in
        bdas.iter()
            .filter(|&&(_, ref bda)| bda.last_update_time() == Some(most_recent_time)) {

        let poolsave = OpenOptions::new()
            .read(true)
            .open(devnode)
            .ok()
            .and_then(|mut f| bda.load_state(&mut f).ok())
            .and_then(|opt| opt)
            .and_then(|data| serde_json::from_slice(&data).ok());

        if poolsave.is_some() {
            return Ok(poolsave);
        }
    }

    // If no data has yet returned, we have an error. That is, we should have
    // some metadata, because we have a most recent time, but we failed to
    // get any.
    let err_str = "timestamp indicates data was written, but no data successfully read";
    Err(EngineError::Engine(ErrorEnum::NotFound, err_str.into()))
}

/// Get all the blockdevs corresponding to this pool that can be obtained from
/// the given devices. Return them in the order in which they were written
/// in the metadata.
/// Returns an error if the blockdevs obtained do not match the metadata.
#[allow(implicit_hasher)]
pub fn get_blockdevs(pool_uuid: PoolUuid,
                     backstore_save: &BackstoreSave,
                     devnodes: &HashMap<Device, PathBuf>)
                     -> EngineResult<Vec<StratBlockDev>> {
    let segments = &backstore_save.segments;

    let mut segment_table = HashMap::new();
    for seg in segments {
        segment_table
            .entry(seg.0)
            .or_insert_with(Vec::default)
            .push((seg.1, seg.2))
    }

    let mut blockdevs = vec![];
    for (device, devnode) in devnodes {
        let bda = BDA::load(&mut OpenOptions::new().read(true).open(devnode)?)?;
        if let Some(bda) = bda {
            if bda.pool_uuid() == pool_uuid {
                let actual_size = blkdev_size(&OpenOptions::new().read(true).open(devnode)?)?
                    .sectors();

                if actual_size < bda.dev_size() {
                    let err_msg = format!("actual blockdev size ({}) < recorded size ({})",
                                          actual_size,
                                          bda.dev_size());

                    return Err(EngineError::Engine(ErrorEnum::Error, err_msg));
                }

                let bd_save = backstore_save
                    .block_devs
                    .iter()
                    .find(|bds| bds.uuid == bda.dev_uuid())
                    .ok_or_else(|| {
                                    let err_msg = format!("Blockdev {} not found in metadata",
                                                          bda.dev_uuid());
                                    EngineError::Engine(ErrorEnum::NotFound, err_msg)
                                })?;

                // This should always succeed since the actual size is at
                // least the recorded size, so all segments should be
                // available to be allocated. If this fails, the most likely
                // conclusion is metadata corruption.
                let segments = segment_table.get(&bda.dev_uuid());
                blockdevs.push(StratBlockDev::new(*device,
                                                  devnode.to_owned(),
                                                  actual_size,
                                                  bda,
                                                  segments.unwrap_or(&vec![]),
                                                  bd_save.user_info.clone(),
                                                  bd_save.hardware_info.clone())?);
            }
        }
    }

    // Verify that blockdevs found match blockdevs recorded.
    let current_uuids: HashSet<_> = blockdevs.iter().map(|b| b.uuid()).collect();
    let recorded_uuids: HashSet<_> = backstore_save
        .block_devs
        .iter()
        .map(|bds| bds.uuid)
        .collect();

    if current_uuids != recorded_uuids {
        let err_msg = "Recorded block dev UUIDs != discovered blockdev UUIDs";
        return Err(EngineError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    if blockdevs.len() != current_uuids.len() {
        let err_msg = "Duplicate block devices found in environment";
        return Err(EngineError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    Ok(blockdevs)
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use bit_set::BitSet;
use indexed_vec::Idx;
use std::collections::VecDeque;

/// A work queue is a handy data structure for tracking work left to
/// do. (For example, basic blocks left to process.) It is basically a
/// de-duplicating queue; so attempting to insert X if X is already
/// enqueued has no effect. This implementation assumes that the
/// elements are dense indices, so it can allocate the queue to size
/// and also use a bit set to track occupancy.
pub struct WorkQueue<T: Idx> {
    deque: VecDeque<T>,
    set: BitSet<T>,
}

impl<T: Idx> WorkQueue<T> {
    /// Create a new work queue with all the elements from (0..len).
    #[inline]
    pub fn with_all(len: usize) -> Self {
        WorkQueue {
            deque: (0..len).map(T::new).collect(),
            set: BitSet::new_filled(len),
        }
    }

    /// Create a new work queue that starts empty, where elements range from (0..len).
    #[inline]
    pub fn with_none(len: usize) -> Self {
        WorkQueue {
            deque: VecDeque::with_capacity(len),
            set: BitSet::new_empty(len),
        }
    }

    /// Attempt to enqueue `element` in the work queue. Returns false if it was already present.
    #[inline]
    pub fn insert(&mut self, element: T) -> bool {
        if self.set.insert(element) {
            self.deque.push_back(element);
            true
        } else {
            false
        }
    }

    /// Attempt to enqueue `element` in the work queue. Returns false if it was already present.
    #[inline]
    pub fn pop(&mut self) -> Option<T> {
        if let Some(element) = self.deque.pop_front() {
            self.set.remove(element);
            Some(element)
        } else {
            None
        }
    }

    /// True if nothing is enqueued.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.deque.is_empty()
    }
}
<commit_msg>Rollup merge of #54656 - nieksand:workqueue_doc, r=varkor<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use bit_set::BitSet;
use indexed_vec::Idx;
use std::collections::VecDeque;

/// A work queue is a handy data structure for tracking work left to
/// do. (For example, basic blocks left to process.) It is basically a
/// de-duplicating queue; so attempting to insert X if X is already
/// enqueued has no effect. This implementation assumes that the
/// elements are dense indices, so it can allocate the queue to size
/// and also use a bit set to track occupancy.
pub struct WorkQueue<T: Idx> {
    deque: VecDeque<T>,
    set: BitSet<T>,
}

impl<T: Idx> WorkQueue<T> {
    /// Create a new work queue with all the elements from (0..len).
    #[inline]
    pub fn with_all(len: usize) -> Self {
        WorkQueue {
            deque: (0..len).map(T::new).collect(),
            set: BitSet::new_filled(len),
        }
    }

    /// Create a new work queue that starts empty, where elements range from (0..len).
    #[inline]
    pub fn with_none(len: usize) -> Self {
        WorkQueue {
            deque: VecDeque::with_capacity(len),
            set: BitSet::new_empty(len),
        }
    }

    /// Attempt to enqueue `element` in the work queue. Returns false if it was already present.
    #[inline]
    pub fn insert(&mut self, element: T) -> bool {
        if self.set.insert(element) {
            self.deque.push_back(element);
            true
        } else {
            false
        }
    }

    /// Attempt to pop an element from the work queue.
    #[inline]
    pub fn pop(&mut self) -> Option<T> {
        if let Some(element) = self.deque.pop_front() {
            self.set.remove(element);
            Some(element)
        } else {
            None
        }
    }

    /// True if nothing is enqueued.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.deque.is_empty()
    }
}
<|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 http://mozilla.org/MPL/2.0/.

// Utilities to support Stratis.
use std::collections::HashMap;
use std::path::{Path, PathBuf};

use libudev;

use super::device::is_stratis_device;
use stratis::StratisResult;

/// Takes a libudev device entry and returns the properties as a HashMap.
fn device_as_map(device: &libudev::Device) -> HashMap<String, String> {
    let rc: HashMap<_, _> = device
        .properties()
        .map(|i| {
            (
                String::from(i.name().to_str().expect("Unix is utf-8")),
                String::from(i.value().to_str().expect("Unix is utf-8")),
            )
        })
        .collect();
    rc
}

/// Common function used to retrieve the udev db entry for a block device as a HashMap when found
pub fn get_udev_block_device(
    dev_node_search: &Path,
) -> StratisResult<Option<HashMap<String, String>>> {
    let context = libudev::Context::new()?;
    let mut enumerator = libudev::Enumerator::new(&context)?;
    enumerator.match_subsystem("block")?;

    let result = enumerator
        .scan_devices()?
        .find(|x| x.devnode().map_or(false, |d| dev_node_search == d))
        .and_then(|dev| Some(device_as_map(&dev)));
    Ok(result)
}

/// Lookup the WWN from the udev db using the device node eg. /dev/sda
pub fn hw_lookup(dev_node_search: &Path) -> StratisResult<Option<String>> {
    let dev = get_udev_block_device(dev_node_search)?;
    Ok(dev.and_then(|dev| dev.get("ID_WWN").and_then(|i| Some(i.clone()))))
}

/// Collect paths for all the devices that appear to be empty from a udev db perspective.
fn get_all_empty_devices() -> StratisResult<Vec<PathBuf>> {
    let context = libudev::Context::new()?;
    let mut enumerator = libudev::Enumerator::new(&context)?;
    enumerator.match_subsystem("block")?;

    Ok(enumerator
        .scan_devices()?
        .filter(|dev| {
            !((dev.property_value("ID_PART_TABLE_TYPE").is_some()
                && dev.property_value("ID_PART_ENTRY_DISK").is_none())
                || dev.property_value("ID_FS_USAGE").is_some())
        })
        .map(|i| i.devnode().expect("block devices have devnode").into())
        .collect())
}

/// Retrieve all the block devices on the system that have a Stratis signature.
pub fn get_stratis_block_devices() -> StratisResult<Vec<PathBuf>> {
    let context = libudev::Context::new()?;
    let mut enumerator = libudev::Enumerator::new(&context)?;
    enumerator.match_subsystem("block")?;
    enumerator.match_property("ID_FS_TYPE", "stratis")?;

    let devices: Vec<PathBuf> = enumerator
        .scan_devices()?
        .map(|x| x.devnode().expect("block devices have devnode").into())
        .collect();

    if devices.is_empty() {
        // Either we don't have any stratis devices or we are using a distribution that doesn't
        // have a version of libblkid that supports stratis, lets make sure.
        // TODO: At some point in the future we can remove this and just return the devices.

        Ok(get_all_empty_devices()?
            .into_iter()
            .filter(|x| is_stratis_device(&x).ok().is_some())
            .collect())
    } else {
        Ok(devices)
    }
}
<commit_msg>Filter out missing devnode<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 http://mozilla.org/MPL/2.0/.

// Utilities to support Stratis.
use std::collections::HashMap;
use std::path::{Path, PathBuf};

use libudev;

use super::device::is_stratis_device;
use stratis::StratisResult;

/// Takes a libudev device entry and returns the properties as a HashMap.
fn device_as_map(device: &libudev::Device) -> HashMap<String, String> {
    let rc: HashMap<_, _> = device
        .properties()
        .map(|i| {
            (
                String::from(i.name().to_str().expect("Unix is utf-8")),
                String::from(i.value().to_str().expect("Unix is utf-8")),
            )
        })
        .collect();
    rc
}

/// Common function used to retrieve the udev db entry for a block device as a HashMap when found
pub fn get_udev_block_device(
    dev_node_search: &Path,
) -> StratisResult<Option<HashMap<String, String>>> {
    let context = libudev::Context::new()?;
    let mut enumerator = libudev::Enumerator::new(&context)?;
    enumerator.match_subsystem("block")?;

    let result = enumerator
        .scan_devices()?
        .find(|x| x.devnode().map_or(false, |d| dev_node_search == d))
        .and_then(|dev| Some(device_as_map(&dev)));
    Ok(result)
}

/// Lookup the WWN from the udev db using the device node eg. /dev/sda
pub fn hw_lookup(dev_node_search: &Path) -> StratisResult<Option<String>> {
    let dev = get_udev_block_device(dev_node_search)?;
    Ok(dev.and_then(|dev| dev.get("ID_WWN").and_then(|i| Some(i.clone()))))
}

/// Collect paths for all the devices that appear to be empty from a udev db perspective.
fn get_all_empty_devices() -> StratisResult<Vec<PathBuf>> {
    let context = libudev::Context::new()?;
    let mut enumerator = libudev::Enumerator::new(&context)?;
    enumerator.match_subsystem("block")?;

    Ok(enumerator
        .scan_devices()?
        .filter(|dev| {
            !((dev.property_value("ID_PART_TABLE_TYPE").is_some()
                && dev.property_value("ID_PART_ENTRY_DISK").is_none())
                || dev.property_value("ID_FS_USAGE").is_some())
        })
        .filter_map(|i| i.devnode().map(|d| d.into()))
        .collect())
}

/// Retrieve all the block devices on the system that have a Stratis signature.
pub fn get_stratis_block_devices() -> StratisResult<Vec<PathBuf>> {
    let context = libudev::Context::new()?;
    let mut enumerator = libudev::Enumerator::new(&context)?;
    enumerator.match_subsystem("block")?;
    enumerator.match_property("ID_FS_TYPE", "stratis")?;

    let devices: Vec<PathBuf> = enumerator
        .scan_devices()?
        .filter_map(|i| i.devnode().map(|d| d.into()))
        .collect();

    if devices.is_empty() {
        // Either we don't have any stratis devices or we are using a distribution that doesn't
        // have a version of libblkid that supports stratis, lets make sure.
        // TODO: At some point in the future we can remove this and just return the devices.

        Ok(get_all_empty_devices()?
            .into_iter()
            .filter(|x| is_stratis_device(&x).ok().is_some())
            .collect())
    } else {
        Ok(devices)
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::dep_graph::{DepGraphQuery, DepNode};
use rustc::hir::def_id::DefId;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph::{DepthFirstTraversal, INCOMING, NodeIndex};

use super::hash::*;
use ich::Fingerprint;

/// A data-structure that makes it easy to enumerate the hashable
/// predecessors of any given dep-node.
pub struct Predecessors<'query> {
    // - Keys: dep-nodes that may have work-products, output meta-data
    //   nodes.
    // - Values: transitive predecessors of the key that are hashable
    //   (e.g., HIR nodes, input meta-data nodes)
    pub inputs: FxHashMap<&'query DepNode<DefId>, Vec<&'query DepNode<DefId>>>,

    // - Keys: some hashable node
    // - Values: the hash thereof
    pub hashes: FxHashMap<&'query DepNode<DefId>, Fingerprint>,
}

impl<'q> Predecessors<'q> {
    pub fn new(query: &'q DepGraphQuery<DefId>, hcx: &mut HashContext) -> Self {
        // Find nodes for which we want to know the full set of preds
        let mut dfs = DepthFirstTraversal::new(&query.graph, INCOMING);
        let all_nodes = query.graph.all_nodes();
        let tcx = hcx.tcx;

        let inputs: FxHashMap<_, _> = all_nodes.iter()
            .enumerate()
            .filter(|&(_, node)| match node.data {
                DepNode::WorkProduct(_) => true,
                DepNode::MetaData(ref def_id) => def_id.is_local(),

                // if -Z query-dep-graph is passed, save more extended data
                // to enable better unit testing
                DepNode::TypeckItemBody(_) |
                DepNode::TransCrateItem(_) => tcx.sess.opts.debugging_opts.query_dep_graph,

                _ => false,
            })
            .map(|(node_index, node)| {
                dfs.reset(NodeIndex(node_index));
                let inputs: Vec<_> = dfs.by_ref()
                    .map(|i| &all_nodes[i.node_id()].data)
                    .filter(|d| HashContext::is_hashable(d))
                    .collect();
                (&node.data, inputs)
            })
            .collect();

        let mut hashes = FxHashMap();
        for input in inputs.values().flat_map(|v| v.iter().cloned()) {
            hashes.entry(input)
                  .or_insert_with(|| hcx.hash(input).unwrap());
        }

        Predecessors {
            inputs: inputs,
            hashes: hashes,
        }
    }
}
<commit_msg>incr.comp.: Add some caching to Predecessors construction.<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::dep_graph::{DepGraphQuery, DepNode};
use rustc::hir::def_id::DefId;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::bitvec::BitVector;
use rustc_data_structures::graph::{NodeIndex, Graph};

use super::hash::*;
use ich::Fingerprint;

/// A data-structure that makes it easy to enumerate the hashable
/// predecessors of any given dep-node.
pub struct Predecessors<'query> {
    // - Keys: dep-nodes that may have work-products, output meta-data
    //   nodes.
    // - Values: transitive predecessors of the key that are hashable
    //   (e.g., HIR nodes, input meta-data nodes)
    pub inputs: FxHashMap<&'query DepNode<DefId>, Vec<&'query DepNode<DefId>>>,

    // - Keys: some hashable node
    // - Values: the hash thereof
    pub hashes: FxHashMap<&'query DepNode<DefId>, Fingerprint>,
}

impl<'q> Predecessors<'q> {
    pub fn new(query: &'q DepGraphQuery<DefId>, hcx: &mut HashContext) -> Self {
        // Find nodes for which we want to know the full set of preds
        let tcx = hcx.tcx;
        let node_count = query.graph.len_nodes();

        // Set up some data structures the cache predecessor search needs:
        let mut visit_counts: Vec<u32> = Vec::new();
        let mut node_cache: Vec<Option<Box<[u32]>>> = Vec::new();
        visit_counts.resize(node_count, 0);
        node_cache.resize(node_count, None);
        let mut dfs_workspace1 = DfsWorkspace::new(node_count);
        let mut dfs_workspace2 = DfsWorkspace::new(node_count);

        let inputs: FxHashMap<_, _> = query
            .graph
            .all_nodes()
            .iter()
            .enumerate()
            .filter(|&(_, node)| match node.data {
                DepNode::WorkProduct(_) => true,
                DepNode::MetaData(ref def_id) => def_id.is_local(),

                // if -Z query-dep-graph is passed, save more extended data
                // to enable better unit testing
                DepNode::TypeckItemBody(_) |
                DepNode::TransCrateItem(_) => tcx.sess.opts.debugging_opts.query_dep_graph,

                _ => false,
            })
            .map(|(node_index, node)| {
                find_roots(&query.graph,
                           node_index as u32,
                           &mut visit_counts,
                           &mut node_cache[..],
                           HashContext::is_hashable,
                           &mut dfs_workspace1,
                           Some(&mut dfs_workspace2));

                let inputs: Vec<_> = dfs_workspace1.output.nodes.iter().map(|&i| {
                    query.graph.node_data(NodeIndex(i as usize))
                }).collect();

                (&node.data, inputs)
            })
            .collect();

        let mut hashes = FxHashMap();
        for input in inputs.values().flat_map(|v| v.iter().cloned()) {
            hashes.entry(input)
                  .or_insert_with(|| hcx.hash(input).unwrap());
        }

        Predecessors {
            inputs: inputs,
            hashes: hashes,
        }
    }
}

const CACHING_THRESHOLD: u32 = 60;

// Starting at `start_node`, this function finds this node's "roots", that is,
// anything that is hashable, in the dep-graph. It uses a simple depth-first
// search to achieve that. However, since some sub-graphs are traversed over
// and over again, the function also some caching built into it: Each time it
// visits a node it increases a counter for that node. If a node has been
// visited more often than CACHING_THRESHOLD, the function will allocate a
// cache entry in the `cache` array. This cache entry contains a flat list of
// all roots reachable from the given node. The next time the node is visited,
// the search can just add the contents of this array to the output instead of
// recursing further.
//
// The function takes two `DfsWorkspace` arguments. These contains some data
// structures that would be expensive to re-allocate all the time, so they are
// allocated once up-front. There are two of them because building a cache entry
// requires a recursive invocation of this function. Two are enough though,
// since function never recurses more than once.
fn find_roots<T, F>(graph: &Graph<T, ()>,
                    start_node: u32,
                    visit_counts: &mut [u32],
                    cache: &mut [Option<Box<[u32]>>],
                    is_root: F,
                    workspace: &mut DfsWorkspace,
                    mut sub_workspace: Option<&mut DfsWorkspace>)
    where F: Copy + Fn(&T) -> bool,
          T: ::std::fmt::Debug,
{
    workspace.visited.clear();
    workspace.output.clear();
    workspace.stack.clear();
    workspace.stack.push(start_node);

    loop {
        let node = match workspace.stack.pop() {
            Some(node) => node,
            None => return,
        };

        if !workspace.visited.insert(node as usize) {
            continue
        }

        if is_root(graph.node_data(NodeIndex(node as usize))) {
            // If this is a root, just add it to the output.
            workspace.output.insert(node);
        } else {
            if let Some(ref cached) = cache[node as usize] {
                for &n in &cached[..] {
                    workspace.output.insert(n);
                }
                // No need to recurse further from this node
                continue
            }

            visit_counts[node as usize] += 1;

            // If this node has been visited often enough to be cached ...
            if visit_counts[node as usize] > CACHING_THRESHOLD {
                // ... we are actually allowed to cache something, do so:
                if let Some(ref mut sub_workspace) = sub_workspace {
                    // Note that the following recursive invocation does never
                    // write to the cache (since we pass None as sub_workspace).
                    // This is intentional: The graph we are working with
                    // contains cycles and this prevent us from simply building
                    // our caches recursively on-demand.
                    // However, we can just do a regular, non-caching DFS to
                    // yield the set of roots and cache that.
                    find_roots(graph,
                               node,
                               visit_counts,
                               cache,
                               is_root,
                               sub_workspace,
                               None);

                    for &n in &sub_workspace.output.nodes {
                        workspace.output.insert(n);
                    }

                    cache[node as usize] = Some(sub_workspace.output
                                                             .nodes
                                                             .clone()
                                                             .into_boxed_slice());
                    // No need to recurse further from this node
                    continue
                }
            }

            for pred in graph.predecessor_nodes(NodeIndex(node as usize)) {
                workspace.stack.push(pred.node_id() as u32);
            }
        }
    }
}

struct DfsWorkspace {
    stack: Vec<u32>,
    visited: BitVector,
    output: NodeIndexSet,
}

impl DfsWorkspace {
    fn new(total_node_count: usize) -> DfsWorkspace {
        DfsWorkspace {
            stack: Vec::new(),
            visited: BitVector::new(total_node_count),
            output: NodeIndexSet::new(total_node_count),
        }
    }
}

struct NodeIndexSet {
    bitset: BitVector,
    nodes: Vec<u32>,
}

impl NodeIndexSet {
    fn new(total_node_count: usize) -> NodeIndexSet {
        NodeIndexSet {
            bitset: BitVector::new(total_node_count),
            nodes: Vec::new(),
        }
    }

    #[inline]
    fn clear(&mut self) {
        self.bitset.clear();
        self.nodes.clear();
    }

    #[inline]
    fn insert(&mut self, node: u32) {
        if self.bitset.insert(node as usize) {
            self.nodes.push(node)
        }
    }
}

#[test]
fn test_cached_dfs_acyclic() {

    //     0     1   2
    //     |      \ /
    //     3---+   |
    //     |   |   |
    //     |   |   |
    //     4   5   6
    //      \ / \ / \
    //       |   |   |
    //       7   8   9

    let mut g: Graph<bool, ()> = Graph::new();
    g.add_node(false);
    g.add_node(false);
    g.add_node(false);
    g.add_node(false);
    g.add_node(false);
    g.add_node(false);
    g.add_node(false);
    g.add_node(true);
    g.add_node(true);
    g.add_node(true);

    g.add_edge(NodeIndex(3), NodeIndex(0), ());
    g.add_edge(NodeIndex(4), NodeIndex(3), ());
    g.add_edge(NodeIndex(7), NodeIndex(4), ());
    g.add_edge(NodeIndex(5), NodeIndex(3), ());
    g.add_edge(NodeIndex(7), NodeIndex(5), ());
    g.add_edge(NodeIndex(8), NodeIndex(5), ());
    g.add_edge(NodeIndex(8), NodeIndex(6), ());
    g.add_edge(NodeIndex(9), NodeIndex(6), ());
    g.add_edge(NodeIndex(6), NodeIndex(1), ());
    g.add_edge(NodeIndex(6), NodeIndex(2), ());

    let mut ws1 = DfsWorkspace::new(g.len_nodes());
    let mut ws2 = DfsWorkspace::new(g.len_nodes());
    let mut visit_counts: Vec<_> = g.all_nodes().iter().map(|_| 0u32).collect();
    let mut cache: Vec<Option<Box<[u32]>>> = g.all_nodes().iter().map(|_| None).collect();

    fn is_root(x: &bool) -> bool { *x }

    for _ in 0 .. CACHING_THRESHOLD + 1 {
        find_roots(&g, 5, &mut visit_counts, &mut cache[..], is_root, &mut ws1, Some(&mut ws2));
        ws1.output.nodes.sort();
        assert_eq!(ws1.output.nodes, vec![7, 8]);

        find_roots(&g, 6, &mut visit_counts, &mut cache[..], is_root, &mut ws1, Some(&mut ws2));
        ws1.output.nodes.sort();
        assert_eq!(ws1.output.nodes, vec![8, 9]);

        find_roots(&g, 0, &mut visit_counts, &mut cache[..], is_root, &mut ws1, Some(&mut ws2));
        ws1.output.nodes.sort();
        assert_eq!(ws1.output.nodes, vec![7, 8]);

        find_roots(&g, 1, &mut visit_counts, &mut cache[..], is_root, &mut ws1, Some(&mut ws2));
        ws1.output.nodes.sort();
        assert_eq!(ws1.output.nodes, vec![8, 9]);

        find_roots(&g, 2, &mut visit_counts, &mut cache[..], is_root, &mut ws1, Some(&mut ws2));
        ws1.output.nodes.sort();
        assert_eq!(ws1.output.nodes, vec![8, 9]);

        find_roots(&g, 3, &mut visit_counts, &mut cache[..], is_root, &mut ws1, Some(&mut ws2));
        ws1.output.nodes.sort();
        assert_eq!(ws1.output.nodes, vec![7, 8]);

        find_roots(&g, 4, &mut visit_counts, &mut cache[..], is_root, &mut ws1, Some(&mut ws2));
        ws1.output.nodes.sort();
        assert_eq!(ws1.output.nodes, vec![7]);
    }
}

#[test]
fn test_cached_dfs_cyclic() {

    //    0       1 <---- 2       3
    //    ^       |       ^       ^
    //    |       v       |       |
    //    4 ----> 5 ----> 6 ----> 7
    //    ^       ^       ^       ^
    //    |       |       |       |
    //    8       9      10      11

    let mut g: Graph<bool, ()> = Graph::new();
    g.add_node(false);
    g.add_node(false);
    g.add_node(false);
    g.add_node(false);
    g.add_node(false);
    g.add_node(false);
    g.add_node(false);
    g.add_node(false);
    g.add_node(true);
    g.add_node(true);
    g.add_node(true);
    g.add_node(true);

    g.add_edge(NodeIndex( 4), NodeIndex(0), ());
    g.add_edge(NodeIndex( 8), NodeIndex(4), ());
    g.add_edge(NodeIndex( 4), NodeIndex(5), ());
    g.add_edge(NodeIndex( 1), NodeIndex(5), ());
    g.add_edge(NodeIndex( 9), NodeIndex(5), ());
    g.add_edge(NodeIndex( 5), NodeIndex(6), ());
    g.add_edge(NodeIndex( 6), NodeIndex(2), ());
    g.add_edge(NodeIndex( 2), NodeIndex(1), ());
    g.add_edge(NodeIndex(10), NodeIndex(6), ());
    g.add_edge(NodeIndex( 6), NodeIndex(7), ());
    g.add_edge(NodeIndex(11), NodeIndex(7), ());
    g.add_edge(NodeIndex( 7), NodeIndex(3), ());

    let mut ws1 = DfsWorkspace::new(g.len_nodes());
    let mut ws2 = DfsWorkspace::new(g.len_nodes());
    let mut visit_counts: Vec<_> = g.all_nodes().iter().map(|_| 0u32).collect();
    let mut cache: Vec<Option<Box<[u32]>>> = g.all_nodes().iter().map(|_| None).collect();

    fn is_root(x: &bool) -> bool { *x }

    for _ in 0 .. CACHING_THRESHOLD + 1 {
        find_roots(&g, 2, &mut visit_counts, &mut cache[..], is_root, &mut ws1, Some(&mut ws2));
        ws1.output.nodes.sort();
        assert_eq!(ws1.output.nodes, vec![8, 9, 10]);

        find_roots(&g, 3, &mut visit_counts, &mut cache[..], is_root, &mut ws1, Some(&mut ws2));
        ws1.output.nodes.sort();
        assert_eq!(ws1.output.nodes, vec![8, 9, 10, 11]);
    }
}
<|endoftext|>


<commit_before>use rustc::hir::map::blocks::FnLikeNode;
use rustc::ty::query::Providers;
use rustc::ty::TyCtxt;
use rustc_attr as attr;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_span::symbol::Symbol;
use rustc_target::spec::abi::Abi;

/// Whether the `def_id` counts as const fn in your current crate, considering all active
/// feature gates
pub fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    tcx.is_const_fn_raw(def_id)
        && match is_unstable_const_fn(tcx, def_id) {
            Some(feature_name) => {
                // has a `rustc_const_unstable` attribute, check whether the user enabled the
                // corresponding feature gate.
                tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_name)
            }
            // functions without const stability are either stable user written
            // const fn or the user is using feature gates and we thus don't
            // care what they do
            None => true,
        }
}

/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
    if tcx.is_const_fn_raw(def_id) {
        let const_stab = tcx.lookup_const_stability(def_id)?;
        if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
    } else {
        None
    }
}

/// Returns `true` if this function must conform to `min_const_fn`
pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    // Bail out if the signature doesn't contain `const`
    if !tcx.is_const_fn_raw(def_id) {
        return false;
    }

    if tcx.features().staged_api {
        // In order for a libstd function to be considered min_const_fn
        // it needs to be stable and have no `rustc_const_unstable` attribute.
        match tcx.lookup_const_stability(def_id) {
            // `rustc_const_unstable` functions don't need to conform.
            Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
            None => {
                if let Some(stab) = tcx.lookup_stability(def_id) {
                    if stab.level.is_stable() {
                        tcx.sess.span_err(
                            tcx.def_span(def_id),
                            "stable const functions must have either `rustc_const_stable` or \
                             `rustc_const_unstable` attribute",
                        );
                        // While we errored above, because we don't know if we need to conform, we
                        // err on the "safe" side and require min_const_fn.
                        true
                    } else {
                        // Unstable functions need not conform to min_const_fn.
                        false
                    }
                } else {
                    // Internal functions are forced to conform to min_const_fn.
                    // Annotate the internal function with a const stability attribute if
                    // you need to use unstable features.
                    // Note: this is an arbitrary choice that does not affect stability or const
                    // safety or anything, it just changes whether we need to annotate some
                    // internal functions with `rustc_const_stable` or with `rustc_const_unstable`
                    true
                }
            }
            // Everything else needs to conform, because it would be callable from
            // other `min_const_fn` functions.
            _ => true,
        }
    } else {
        // users enabling the `const_fn` feature gate can do what they want
        !tcx.features().const_fn
    }
}

pub fn provide(providers: &mut Providers<'_>) {
    /// Const evaluability whitelist is here to check evaluability at the
    /// top level beforehand.
    fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
        if tcx.is_closure(def_id) {
            return None;
        }

        match tcx.fn_sig(def_id).abi() {
            Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
                Some(tcx.lookup_const_stability(def_id).is_some())
            }
            _ => None,
        }
    }

    /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
    /// said intrinsic is on the whitelist for being const callable.
    fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        let hir_id = tcx
            .hir()
            .as_local_hir_id(def_id)
            .expect("Non-local call to local provider is_const_fn");

        let node = tcx.hir().get(hir_id);

        if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
            whitelisted
        } else if let Some(fn_like) = FnLikeNode::from_node(node) {
            if fn_like.constness() == hir::Constness::Const {
                return true;
            }

            // If the function itself is not annotated with `const`, it may still be a `const fn`
            // if it resides in a const trait impl.
            let parent_id = tcx.hir().get_parent_did(hir_id);
            if def_id != parent_id && !parent_id.is_top_level_module() {
                is_const_impl_raw(tcx, LocalDefId::from_def_id(parent_id))
            } else {
                false
            }
        } else if let hir::Node::Ctor(_) = node {
            true
        } else {
            false
        }
    }

    /// Checks whether the given item is an `impl` that has a `const` modifier.
    fn is_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
        let node = tcx.hir().get(hir_id);
        matches!(
            node,
            hir::Node::Item(hir::Item {
                kind: hir::ItemKind::Impl { constness: hir::Constness::Const, .. },
                ..
            })
        )
    }

    fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        is_const_fn(tcx, def_id)
            && match tcx.lookup_const_stability(def_id) {
                Some(stab) => {
                    if cfg!(debug_assertions) && stab.promotable {
                        let sig = tcx.fn_sig(def_id);
                        assert_eq!(
                            sig.unsafety(),
                            hir::Unsafety::Normal,
                            "don't mark const unsafe fns as promotable",
                            // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
                        );
                    }
                    stab.promotable
                }
                None => false,
            }
    }

    fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        is_const_fn(tcx, def_id)
            && tcx
                .lookup_const_stability(def_id)
                .map(|stab| stab.allow_const_fn_ptr)
                .unwrap_or(false)
    }

    *providers = Providers {
        is_const_fn_raw,
        is_const_impl_raw: |tcx, def_id| is_const_impl_raw(tcx, LocalDefId::from_def_id(def_id)),
        is_promotable_const_fn,
        const_fn_is_allowed_fn_ptr,
        ..*providers
    };
}
<commit_msg>Make `fn_queries` helpers module-private<commit_after>use rustc::hir::map::blocks::FnLikeNode;
use rustc::ty::query::Providers;
use rustc::ty::TyCtxt;
use rustc_attr as attr;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_span::symbol::Symbol;
use rustc_target::spec::abi::Abi;

/// Whether the `def_id` counts as const fn in your current crate, considering all active
/// feature gates
pub fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    tcx.is_const_fn_raw(def_id)
        && match is_unstable_const_fn(tcx, def_id) {
            Some(feature_name) => {
                // has a `rustc_const_unstable` attribute, check whether the user enabled the
                // corresponding feature gate.
                tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_name)
            }
            // functions without const stability are either stable user written
            // const fn or the user is using feature gates and we thus don't
            // care what they do
            None => true,
        }
}

/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
    if tcx.is_const_fn_raw(def_id) {
        let const_stab = tcx.lookup_const_stability(def_id)?;
        if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
    } else {
        None
    }
}

/// Returns `true` if this function must conform to `min_const_fn`
pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    // Bail out if the signature doesn't contain `const`
    if !tcx.is_const_fn_raw(def_id) {
        return false;
    }

    if tcx.features().staged_api {
        // In order for a libstd function to be considered min_const_fn
        // it needs to be stable and have no `rustc_const_unstable` attribute.
        match tcx.lookup_const_stability(def_id) {
            // `rustc_const_unstable` functions don't need to conform.
            Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
            None => {
                if let Some(stab) = tcx.lookup_stability(def_id) {
                    if stab.level.is_stable() {
                        tcx.sess.span_err(
                            tcx.def_span(def_id),
                            "stable const functions must have either `rustc_const_stable` or \
                             `rustc_const_unstable` attribute",
                        );
                        // While we errored above, because we don't know if we need to conform, we
                        // err on the "safe" side and require min_const_fn.
                        true
                    } else {
                        // Unstable functions need not conform to min_const_fn.
                        false
                    }
                } else {
                    // Internal functions are forced to conform to min_const_fn.
                    // Annotate the internal function with a const stability attribute if
                    // you need to use unstable features.
                    // Note: this is an arbitrary choice that does not affect stability or const
                    // safety or anything, it just changes whether we need to annotate some
                    // internal functions with `rustc_const_stable` or with `rustc_const_unstable`
                    true
                }
            }
            // Everything else needs to conform, because it would be callable from
            // other `min_const_fn` functions.
            _ => true,
        }
    } else {
        // users enabling the `const_fn` feature gate can do what they want
        !tcx.features().const_fn
    }
}

pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
    let parent_id = tcx.hir().get_parent_did(hir_id);
    if !parent_id.is_top_level_module() {
        is_const_impl_raw(tcx, LocalDefId::from_def_id(parent_id))
    } else {
        false
    }
}

/// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
/// said intrinsic is on the whitelist for being const callable.
fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    let hir_id =
        tcx.hir().as_local_hir_id(def_id).expect("Non-local call to local provider is_const_fn");

    let node = tcx.hir().get(hir_id);

    if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
        whitelisted
    } else if let Some(fn_like) = FnLikeNode::from_node(node) {
        if fn_like.constness() == hir::Constness::Const {
            return true;
        }

        // If the function itself is not annotated with `const`, it may still be a `const fn`
        // if it resides in a const trait impl.
        is_parent_const_impl_raw(tcx, hir_id)
    } else if let hir::Node::Ctor(_) = node {
        true
    } else {
        false
    }
}

/// Const evaluability whitelist is here to check evaluability at the
/// top level beforehand.
fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
    if tcx.is_closure(def_id) {
        return None;
    }

    match tcx.fn_sig(def_id).abi() {
        Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
            Some(tcx.lookup_const_stability(def_id).is_some())
        }
        _ => None,
    }
}

/// Checks whether the given item is an `impl` that has a `const` modifier.
fn is_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
    let node = tcx.hir().get(hir_id);
    matches!(
        node,
        hir::Node::Item(hir::Item {
            kind: hir::ItemKind::Impl { constness: hir::Constness::Const, .. },
            ..
        })
    )
}

fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    is_const_fn(tcx, def_id)
        && match tcx.lookup_const_stability(def_id) {
            Some(stab) => {
                if cfg!(debug_assertions) && stab.promotable {
                    let sig = tcx.fn_sig(def_id);
                    assert_eq!(
                        sig.unsafety(),
                        hir::Unsafety::Normal,
                        "don't mark const unsafe fns as promotable",
                        // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
                    );
                }
                stab.promotable
            }
            None => false,
        }
}

fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    is_const_fn(tcx, def_id)
        && tcx.lookup_const_stability(def_id).map(|stab| stab.allow_const_fn_ptr).unwrap_or(false)
}

pub fn provide(providers: &mut Providers<'_>) {
    *providers = Providers {
        is_const_fn_raw,
        is_const_impl_raw: |tcx, def_id| is_const_impl_raw(tcx, LocalDefId::from_def_id(def_id)),
        is_promotable_const_fn,
        const_fn_is_allowed_fn_ptr,
        ..*providers
    };
}
<|endoftext|>


<commit_before>use na::{self, Real};

use query::algorithms::{gjk, CSOPoint, VoronoiSimplex};
use query::{Ray, RayCast, RayIntersection};
use shape::{Capsule, Segment, SupportMap};
#[cfg(feature = "dim2")]
use shape::ConvexPolygon;
#[cfg(feature = "dim3")]
use shape::{Cone, ConvexHull, Cylinder};
use math::Isometry;

/// Cast a ray on a shape using the GJK algorithm.
pub fn implicit_toi_and_normal_with_ray<N, G: ?Sized>(
    m: &Isometry<N>,
    shape: &G,
    simplex: &mut VoronoiSimplex<N>,
    ray: &Ray<N>,
    solid: bool,
) -> Option<RayIntersection<N>>
where
    N: Real,
    G: SupportMap<N>,
{
    let supp = shape.support_point(m, &-ray.dir);
    simplex.reset(CSOPoint::single_point(supp - ray.origin.coords));

    let inter = gjk::cast_ray(m, shape, simplex, ray);

    if !solid {
        match inter {
            None => None,
            Some((toi, normal)) => {
                if toi.is_zero() {
                    // the ray is inside of the shape.
                    let ndir = na::normalize(&ray.dir);
                    let supp = shape.support_point(m, &ndir);
                    let shift = na::dot(&(supp - ray.origin), &ndir) + na::convert(0.001f64);
                    let new_ray = Ray::new(ray.origin + ndir * shift, -ray.dir);

                    // FIXME: replace by? : simplex.translate_by(&(ray.origin - new_ray.origin));
                    simplex.reset(CSOPoint::single_point(supp - new_ray.origin.coords));

                    gjk::cast_ray(m, shape, simplex, &new_ray)
                        .map(|(toi, normal)| RayIntersection::new(shift - toi, normal))
                } else {
                    Some(RayIntersection::new(toi, normal))
                }
            }
        }
    } else {
        inter.map(|(toi, normal)| RayIntersection::new(toi, normal))
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> RayCast<N> for Cylinder<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>> {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        ).map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> RayCast<N> for Cone<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>> {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        ).map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

impl<N: Real> RayCast<N> for Capsule<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>> {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        ).map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> RayCast<N> for ConvexHull<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>> {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        ).map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

#[cfg(feature = "dim2")]
impl<N: Real> RayCast<N> for ConvexPolygon<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>> {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        ).map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

impl<N: Real> RayCast<N> for Segment<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>> {
        // XXX: optimize if na::dimension::<P>() == 2
        let ls_ray = ray.inverse_transform_by(m);
        println!("Segment: {:?}", *self);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        ).map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}
<commit_msg>Remove print.<commit_after>use na::{self, Real};

use query::algorithms::{gjk, CSOPoint, VoronoiSimplex};
use query::{Ray, RayCast, RayIntersection};
use shape::{Capsule, Segment, SupportMap};
#[cfg(feature = "dim2")]
use shape::ConvexPolygon;
#[cfg(feature = "dim3")]
use shape::{Cone, ConvexHull, Cylinder};
use math::Isometry;

/// Cast a ray on a shape using the GJK algorithm.
pub fn implicit_toi_and_normal_with_ray<N, G: ?Sized>(
    m: &Isometry<N>,
    shape: &G,
    simplex: &mut VoronoiSimplex<N>,
    ray: &Ray<N>,
    solid: bool,
) -> Option<RayIntersection<N>>
where
    N: Real,
    G: SupportMap<N>,
{
    let supp = shape.support_point(m, &-ray.dir);
    simplex.reset(CSOPoint::single_point(supp - ray.origin.coords));

    let inter = gjk::cast_ray(m, shape, simplex, ray);

    if !solid {
        match inter {
            None => None,
            Some((toi, normal)) => {
                if toi.is_zero() {
                    // the ray is inside of the shape.
                    let ndir = na::normalize(&ray.dir);
                    let supp = shape.support_point(m, &ndir);
                    let shift = na::dot(&(supp - ray.origin), &ndir) + na::convert(0.001f64);
                    let new_ray = Ray::new(ray.origin + ndir * shift, -ray.dir);

                    // FIXME: replace by? : simplex.translate_by(&(ray.origin - new_ray.origin));
                    simplex.reset(CSOPoint::single_point(supp - new_ray.origin.coords));

                    gjk::cast_ray(m, shape, simplex, &new_ray)
                        .map(|(toi, normal)| RayIntersection::new(shift - toi, normal))
                } else {
                    Some(RayIntersection::new(toi, normal))
                }
            }
        }
    } else {
        inter.map(|(toi, normal)| RayIntersection::new(toi, normal))
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> RayCast<N> for Cylinder<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>> {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        ).map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> RayCast<N> for Cone<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>> {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        ).map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

impl<N: Real> RayCast<N> for Capsule<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>> {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        ).map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> RayCast<N> for ConvexHull<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>> {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        ).map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

#[cfg(feature = "dim2")]
impl<N: Real> RayCast<N> for ConvexPolygon<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>> {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        ).map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

impl<N: Real> RayCast<N> for Segment<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>> {
        // XXX: optimize if na::dimension::<P>() == 2
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        ).map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-wasm

#![feature(const_fn)]
#![allow(const_err)]

use std::env;
use std::process::{Command, Stdio};

const fn bar() -> usize { 0 - 1 }

fn foo() {
    let _: &'static _ = &bar();
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() > 1 && args[1] == "test" {
        foo();
        return;
    }

    let mut p = Command::new(&args[0])
        .stdout(Stdio::piped())
        .stdin(Stdio::piped())
        .arg("test").output().unwrap();
    assert!(!p.status.success());
}
<commit_msg>Use correct exclusion comment<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-wasm32
// ignore-emscripten

#![feature(const_fn)]
#![allow(const_err)]

use std::env;
use std::process::{Command, Stdio};

const fn bar() -> usize { 0 - 1 }

fn foo() {
    let _: &'static _ = &bar();
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() > 1 && args[1] == "test" {
        foo();
        return;
    }

    let mut p = Command::new(&args[0])
        .stdout(Stdio::piped())
        .stdin(Stdio::piped())
        .arg("test").output().unwrap();
    assert!(!p.status.success());
}
<|endoftext|>


<commit_before>fn f() -> i32 {
    42
}

fn return_fn_ptr() -> fn() -> i32 {
    f
}

fn call_fn_ptr() -> i32 {
    return_fn_ptr()()
}

fn main() {
    assert_eq!(call_fn_ptr(), 42);
    assert!(return_fn_ptr() == f);
    assert!(return_fn_ptr() as unsafe fn() -> i32 == f as fn() -> i32 as unsafe fn() -> i32);
}
<commit_msg>add some sanity tests<commit_after>fn f() -> i32 {
    42
}

fn g(i: i32) -> i32 {
    i*42
}

fn return_fn_ptr() -> fn() -> i32 {
    f
}

fn call_fn_ptr() -> i32 {
    return_fn_ptr()()
}

fn indirect<F: Fn() -> i32>(f: F) -> i32 { f() }
fn indirect_mut<F: FnMut() -> i32>(mut f: F) -> i32 { f() }
fn indirect_once<F: FnOnce() -> i32>(f: F) -> i32 { f() }

fn indirect2<F: Fn(i32) -> i32>(f: F) -> i32 { f(10) }
fn indirect_mut2<F: FnMut(i32) -> i32>(mut f: F) -> i32 { f(10) }
fn indirect_once2<F: FnOnce(i32) -> i32>(f: F) -> i32 { f(10) }

fn main() {
    assert_eq!(call_fn_ptr(), 42);
    assert_eq!(indirect(f), 42);
    assert_eq!(indirect_mut(f), 42);
    assert_eq!(indirect_once(f), 42);
    assert_eq!(indirect2(g), 420);
    assert_eq!(indirect_mut2(g), 420);
    assert_eq!(indirect_once2(g), 420);
    assert!(return_fn_ptr() == f);
    assert!(return_fn_ptr() as unsafe fn() -> i32 == f as fn() -> i32 as unsafe fn() -> i32);
}
<|endoftext|>


<commit_before>//! Tests for build.rs rerun-if-env-changed.

use cargo_test_support::project;
use cargo_test_support::sleep_ms;

#[cargo_test]
fn rerun_if_env_changes() {
    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rerun-if-env-changed=FOO");
                }
            "#,
        )
        .build();

    p.cargo("build")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
    p.cargo("build")
        .env("FOO", "bar")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
    p.cargo("build")
        .env("FOO", "baz")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
    p.cargo("build")
        .env("FOO", "baz")
        .with_stderr("[FINISHED] [..]")
        .run();
    p.cargo("build")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
}

#[cargo_test]
fn rerun_if_env_or_file_changes() {
    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rerun-if-env-changed=FOO");
                    println!("cargo:rerun-if-changed=foo");
                }
            "#,
        )
        .file("foo", "")
        .build();

    p.cargo("build")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
    p.cargo("build")
        .env("FOO", "bar")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
    p.cargo("build")
        .env("FOO", "bar")
        .with_stderr("[FINISHED] [..]")
        .run();
    sleep_ms(1000);
    p.change_file("foo", "");
    p.cargo("build")
        .env("FOO", "bar")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
}

#[cargo_test]
fn rustc_bootstrap() {
    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
            fn main() {
                println!("cargo:rustc-env=RUSTC_BOOTSTRAP=1");
            }
        "#,
        )
        .build();
    p.cargo("build")
        .with_stderr_contains("error: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
        .with_stderr_contains("help: [..] use `RUSTC_BOOTSTRAP=foo cargo build` [..]")
        .with_status(101)
        .run();
    p.cargo("build")
        .masquerade_as_nightly_cargo()
        .with_stderr_contains("warning: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
        .run();
}
<commit_msg>Update comment in build_script_env<commit_after>//! Tests for build.rs rerun-if-env-changed and rustc-env

use cargo_test_support::project;
use cargo_test_support::sleep_ms;

#[cargo_test]
fn rerun_if_env_changes() {
    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rerun-if-env-changed=FOO");
                }
            "#,
        )
        .build();

    p.cargo("build")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
    p.cargo("build")
        .env("FOO", "bar")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
    p.cargo("build")
        .env("FOO", "baz")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
    p.cargo("build")
        .env("FOO", "baz")
        .with_stderr("[FINISHED] [..]")
        .run();
    p.cargo("build")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
}

#[cargo_test]
fn rerun_if_env_or_file_changes() {
    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rerun-if-env-changed=FOO");
                    println!("cargo:rerun-if-changed=foo");
                }
            "#,
        )
        .file("foo", "")
        .build();

    p.cargo("build")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
    p.cargo("build")
        .env("FOO", "bar")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
    p.cargo("build")
        .env("FOO", "bar")
        .with_stderr("[FINISHED] [..]")
        .run();
    sleep_ms(1000);
    p.change_file("foo", "");
    p.cargo("build")
        .env("FOO", "bar")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
",
        )
        .run();
}

#[cargo_test]
fn rustc_bootstrap() {
    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
            fn main() {
                println!("cargo:rustc-env=RUSTC_BOOTSTRAP=1");
            }
        "#,
        )
        .build();
    p.cargo("build")
        .with_stderr_contains("error: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
        .with_stderr_contains("help: [..] use `RUSTC_BOOTSTRAP=foo cargo build` [..]")
        .with_status(101)
        .run();
    p.cargo("build")
        .masquerade_as_nightly_cargo()
        .with_stderr_contains("warning: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
        .run();
}
<|endoftext|>