<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/.

use std::{
    fs::{File, OpenOptions},
    io::{Read, Write},
    path::{Path, PathBuf},
    thread::sleep,
    time::Duration,
};

use chrono::{DateTime, TimeZone, Utc};
use data_encoding::BASE32_NOPAD;
use serde_json::{Map, Value};

use devicemapper::{
    Bytes, DmDevice, DmFlags, DmName, DmOptions, DmUuid, Sectors, ThinDev, ThinDevId, ThinPoolDev,
    ThinStatus,
};

use nix::{
    mount::{mount, umount, MsFlags},
    sys::statvfs::statvfs,
};

use crate::{
    engine::{
        engine::{DumpState, Filesystem, StateDiff},
        strat_engine::{
            cmd::{create_fs, set_uuid, udev_settle, xfs_growfs},
            devlinks,
            dm::get_dm,
            names::{format_thin_ids, ThinRole},
            serde_structs::FilesystemSave,
            thinpool::{thinpool::DATA_LOWATER, DATA_BLOCK_SIZE},
        },
        types::{
            ActionAvailability, FilesystemUuid, Name, PoolUuid, StratFilesystemDiff,
            StratFilesystemState, StratisUuid,
        },
    },
    stratis::{StratisError, StratisResult},
};

const TEMP_MNT_POINT_PREFIX: &str = "stratis_mp_";

/// Set the low water mark on the filesystem at 4 times the data low water.  The filesystem
/// expansion check is triggered by crossing the data low water mark for the thin pool.
pub const FILESYSTEM_LOWATER: Sectors = Sectors(4 * (DATA_LOWATER.0 * DATA_BLOCK_SIZE.0));

#[derive(Debug)]
pub struct StratFilesystem {
    thin_dev: ThinDev,
    created: DateTime<Utc>,
}

impl StratFilesystem {
    /// Create a StratFilesystem on top of the given ThinDev.
    pub fn initialize(
        pool_uuid: PoolUuid,
        thinpool_dev: &ThinPoolDev,
        size: Sectors,
        id: ThinDevId,
    ) -> StratisResult<(FilesystemUuid, StratFilesystem)> {
        let fs_uuid = FilesystemUuid::new_v4();
        let (dm_name, dm_uuid) = format_thin_ids(pool_uuid, ThinRole::Filesystem(fs_uuid));
        let mut thin_dev =
            ThinDev::new(get_dm(), &dm_name, Some(&dm_uuid), size, thinpool_dev, id)?;

        if let Err(err) = create_fs(&thin_dev.devnode(), Some(StratisUuid::Fs(fs_uuid)), false) {
            udev_settle().unwrap_or_else(|err| {
                warn!("{}", err);
                sleep(Duration::from_secs(5));
            });
            if let Err(err2) = thin_dev.destroy(get_dm(), thinpool_dev) {
                error!(
                    "While handling create_fs error, thin_dev.destroy() failed: {}",
                    err2
                );
                // This will result in a dangling DM device that will prevent
                // the thinpool from being destroyed, and wasted space in the
                // thinpool.
                // TODO: Recover. But how?
            }
            return Err(err);
        }

        Ok((
            fs_uuid,
            StratFilesystem {
                thin_dev,
                created: Utc::now(),
            },
        ))
    }

    /// Build a StratFilesystem that includes the ThinDev and related info.
    pub fn setup(
        pool_uuid: PoolUuid,
        thinpool_dev: &ThinPoolDev,
        fssave: &FilesystemSave,
    ) -> StratisResult<StratFilesystem> {
        let (dm_name, dm_uuid) = format_thin_ids(pool_uuid, ThinRole::Filesystem(fssave.uuid));
        let thin_dev = ThinDev::setup(
            get_dm(),
            &dm_name,
            Some(&dm_uuid),
            fssave.size,
            thinpool_dev,
            fssave.thin_id,
        )?;
        Ok(StratFilesystem {
            thin_dev,
            created: Utc.timestamp(fssave.created as i64, 0),
        })
    }

    /// Send a synthetic udev change event to the devicemapper device representing
    /// the filesystem.
    pub fn udev_fs_change(&self, pool_name: &str, fs_uuid: FilesystemUuid, fs_name: &str) {
        fn udev_change_event(
            thin_dev: &ThinDev,
            pool_name: &str,
            fs_uuid: FilesystemUuid,
            fs_name: &str,
        ) -> StratisResult<()> {
            let device = thin_dev.device();
            let uevent_file = [
                "/sys/dev/block",
                &format!("{}:{}", device.major, device.minor),
                "uevent",
            ]
            .iter()
            .collect::<PathBuf>();
            OpenOptions::new()
                .write(true)
                .open(&uevent_file)?
                .write_all(
                    format!(
                        "{} {} STRATISPOOLNAME={} STRATISFSNAME={}",
                        devlinks::UEVENT_CHANGE_EVENT,
                        fs_uuid,
                        BASE32_NOPAD.encode(pool_name.as_bytes()),
                        BASE32_NOPAD.encode(fs_name.as_bytes()),
                    )
                    .as_bytes(),
                )?;
            Ok(())
        }

        if let Err(e) = udev_change_event(&self.thin_dev, pool_name, fs_uuid, fs_name) {
            warn!("Failed to notify udev to perform symlink operation: {}", e);
        }
    }

    /// Create a snapshot of the filesystem. Return the resulting filesystem/ThinDev
    /// to the caller.  Use snapshot_name for the Stratis filesystem name.  Use
    /// snapshot_dmname for the new name of the ThinDev allocated for the snapshot.
    /// Mounting a filesystem with a duplicate UUID would require special handling,
    /// so snapshot_fs_uuid is used to update the new snapshot filesystem so it has
    /// a unique UUID.
    #[allow(clippy::too_many_arguments)]
    pub fn snapshot(
        &self,
        thin_pool: &ThinPoolDev,
        snapshot_name: &str,
        snapshot_dm_name: &DmName,
        snapshot_dm_uuid: Option<&DmUuid>,
        snapshot_fs_name: &Name,
        snapshot_fs_uuid: FilesystemUuid,
        snapshot_thin_id: ThinDevId,
    ) -> StratisResult<StratFilesystem> {
        match self.thin_dev.snapshot(
            get_dm(),
            snapshot_dm_name,
            snapshot_dm_uuid,
            thin_pool,
            snapshot_thin_id,
        ) {
            Ok(thin_dev) => {
                // If the source is mounted, XFS puts a dummy record in the
                // log to enforce replay of the snapshot to deal with any
                // orphaned inodes. The dummy record put the log in a dirty
                // state. xfs_admin won't allow a filesystem UUID
                // to be updated when the log is dirty.  To clear the log
                // we mount/unmount the filesystem before updating the UUID.
                //
                // If the source is unmounted the XFS log will be clean so
                // we can skip the mount/unmount.
                if !self.mount_points()?.is_empty() {
                    let tmp_dir = tempfile::Builder::new()
                        .prefix(TEMP_MNT_POINT_PREFIX)
                        .tempdir()?;
                    // Mount the snapshot with the "nouuid" option. mount
                    // will fail due to duplicate UUID otherwise.
                    mount(
                        Some(&thin_dev.devnode()),
                        tmp_dir.path(),
                        Some("xfs"),
                        MsFlags::empty(),
                        Some("nouuid"),
                    )?;
                    umount(tmp_dir.path())?;
                }

                set_uuid(&thin_dev.devnode(), snapshot_fs_uuid)?;
                Ok(StratFilesystem {
                    thin_dev,
                    created: Utc::now(),
                })
            }
            Err(e) => Err(StratisError::Msg(format!(
                "failed to create {} snapshot for {} - {}",
                snapshot_name, snapshot_fs_name, e
            ))),
        }
    }

    /// Check if filesystem is getting full and needs to be extended.
    ///
    /// Returns:
    /// * Some(_) if metadata should be saved.
    /// * None if metadata should not be saved.
    /// TODO: deal with the thindev in a Fail state.
    pub fn check(&mut self) -> StratisResult<Option<StratFilesystemDiff>> {
        match self.thin_dev.status(get_dm(), DmOptions::default())? {
            ThinStatus::Working(_) => {
                if let Some(mount_point) = self.mount_points()?.first() {
                    let original_state = self.dump();
                    let (fs_total_bytes, fs_total_used_bytes) = fs_usage(mount_point)?;
                    let free_bytes = fs_total_bytes - fs_total_used_bytes;
                    if free_bytes.sectors() < FILESYSTEM_LOWATER {
                        let old_table = self.thin_dev.table().table.clone();
                        let mut new_table = old_table.clone();
                        new_table.length =
                            self.thin_dev.size() + Self::extend_size(self.thin_dev.size());
                        self.thin_dev.set_table(get_dm(), new_table)?;
                        if let Err(causal) = xfs_growfs(mount_point) {
                            if let Err(rollback) = self.thin_dev.set_table(get_dm(), old_table) {
                                Err(StratisError::RollbackError {
                                    causal_error: Box::new(causal),
                                    rollback_error: Box::new(StratisError::from(rollback)),
                                    // NOTE: Read-only may be too aggressive.
                                    level: ActionAvailability::NoPoolChanges,
                                })
                            } else {
                                Err(causal)
                            }
                        } else {
                            Ok(Some(original_state.diff(&self.dump())))
                        }
                    } else {
                        Ok(None)
                    }
                } else {
                    Ok(None)
                }
            }
            ThinStatus::Error => {
                let error_msg = format!(
                    "Unable to get status for filesystem thin device {}",
                    self.thin_dev.device()
                );
                Err(StratisError::Msg(error_msg))
            }
            ThinStatus::Fail => Ok(None),
        }
    }

    /// Return an extend size for the thindev under the filesystem
    /// TODO: returning the current size will double the space provisioned to
    /// the thin device.  We should determine if this is a reasonable value.
    fn extend_size(current_size: Sectors) -> Sectors {
        current_size
    }

    /// Tear down the filesystem.
    pub fn teardown(&mut self) -> StratisResult<()> {
        self.thin_dev.teardown(get_dm())?;
        Ok(())
    }

    /// Destroy the filesystem.
    pub fn destroy(&mut self, thin_pool: &ThinPoolDev) -> StratisResult<()> {
        self.thin_dev.destroy(get_dm(), thin_pool)?;
        Ok(())
    }

    pub fn record(&self, name: &Name, uuid: FilesystemUuid) -> FilesystemSave {
        FilesystemSave {
            name: name.to_owned(),
            uuid,
            thin_id: self.thin_dev.id(),
            size: self.thin_dev.size(),
            created: self.created.timestamp() as u64,
        }
    }

    pub fn suspend(&mut self, flush: bool) -> StratisResult<()> {
        self.thin_dev.suspend(
            get_dm(),
            if flush {
                DmOptions::default()
            } else {
                DmOptions::default().set_flags(DmFlags::DM_NOFLUSH)
            },
        )?;
        Ok(())
    }

    pub fn resume(&mut self) -> StratisResult<()> {
        self.thin_dev.resume(get_dm())?;
        Ok(())
    }

    /// Find places where this filesystem is mounted.
    fn mount_points(&self) -> StratisResult<Vec<PathBuf>> {
        // Use major:minor values to find mounts for this filesystem
        let major = u64::from(self.thin_dev.device().major);
        let minor = u64::from(self.thin_dev.device().minor);

        let mut mount_data = String::new();
        File::open("/proc/self/mountinfo")?.read_to_string(&mut mount_data)?;
        let parser = libmount::mountinfo::Parser::new(mount_data.as_bytes());

        let mut ret_vec = Vec::new();
        for mp in parser {
            match mp {
                Ok(mount) => {
                    if mount.major as u64 == major && mount.minor as u64 == minor {
                        ret_vec.push(PathBuf::from(&mount.mount_point));
                    }
                }
                Err(e) => {
                    let error_msg = format!("Error during parsing {:?}: {:?}", *self, e);
                    return Err(StratisError::Msg(error_msg));
                }
            }
        }

        Ok(ret_vec)
    }

    pub fn thindev_size(&self) -> Sectors {
        self.thin_dev.size()
    }
}

impl Filesystem for StratFilesystem {
    fn devnode(&self) -> PathBuf {
        self.thin_dev.devnode()
    }

    fn created(&self) -> DateTime<Utc> {
        self.created
    }

    fn path_to_mount_filesystem(&self, pool_name: &str, fs_name: &str) -> PathBuf {
        devlinks::filesystem_mount_path(pool_name, fs_name)
    }

    fn used(&self) -> StratisResult<Bytes> {
        match self.thin_dev.status(get_dm(), DmOptions::default())? {
            ThinStatus::Working(wk_status) => Ok(wk_status.nr_mapped_sectors.bytes()),
            ThinStatus::Error => {
                let error_msg = format!(
                    "Unable to get status for filesystem thin device {}",
                    self.thin_dev.device()
                );
                Err(StratisError::Msg(error_msg))
            }
            ThinStatus::Fail => {
                let error_msg = format!("ThinDev {} is in a failed state", self.thin_dev.device());
                Err(StratisError::Msg(error_msg))
            }
        }
    }

    fn size(&self) -> Bytes {
        self.thin_dev.size().bytes()
    }
}

impl DumpState for StratFilesystem {
    type State = StratFilesystemState;

    fn dump(&self) -> Self::State {
        StratFilesystemState::new(self.thin_dev.size().bytes())
    }
}

/// Return total bytes allocated to the filesystem, total bytes used by data/metadata
pub fn fs_usage(mount_point: &Path) -> StratisResult<(Bytes, Bytes)> {
    let stat = statvfs(mount_point)?;

    // Upcast all arch-dependent variable width values to u64
    let (block_size, blocks, blocks_free) = (
        stat.block_size() as u64,
        stat.blocks() as u64,
        stat.blocks_free() as u64,
    );
    Ok((
        Bytes::from(block_size * blocks),
        Bytes::from(block_size * (blocks - blocks_free)),
    ))
}

impl<'a> Into<Value> for &'a StratFilesystem {
    fn into(self) -> Value {
        let mut json = Map::new();
        json.insert(
            "size".to_string(),
            Value::from(self.thindev_size().to_string()),
        );
        json.insert(
            "used".to_string(),
            Value::from(
                self.used()
                    .map(|v| v.to_string())
                    .unwrap_or_else(|_| "Unavailable".to_string()),
            ),
        );
        Value::from(json)
    }
}
<commit_msg>Remove dead suspend() and resume() methods<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/.

use std::{
    fs::{File, OpenOptions},
    io::{Read, Write},
    path::{Path, PathBuf},
    thread::sleep,
    time::Duration,
};

use chrono::{DateTime, TimeZone, Utc};
use data_encoding::BASE32_NOPAD;
use serde_json::{Map, Value};

use devicemapper::{
    Bytes, DmDevice, DmName, DmOptions, DmUuid, Sectors, ThinDev, ThinDevId, ThinPoolDev,
    ThinStatus,
};

use nix::{
    mount::{mount, umount, MsFlags},
    sys::statvfs::statvfs,
};

use crate::{
    engine::{
        engine::{DumpState, Filesystem, StateDiff},
        strat_engine::{
            cmd::{create_fs, set_uuid, udev_settle, xfs_growfs},
            devlinks,
            dm::get_dm,
            names::{format_thin_ids, ThinRole},
            serde_structs::FilesystemSave,
            thinpool::{thinpool::DATA_LOWATER, DATA_BLOCK_SIZE},
        },
        types::{
            ActionAvailability, FilesystemUuid, Name, PoolUuid, StratFilesystemDiff,
            StratFilesystemState, StratisUuid,
        },
    },
    stratis::{StratisError, StratisResult},
};

const TEMP_MNT_POINT_PREFIX: &str = "stratis_mp_";

/// Set the low water mark on the filesystem at 4 times the data low water.  The filesystem
/// expansion check is triggered by crossing the data low water mark for the thin pool.
pub const FILESYSTEM_LOWATER: Sectors = Sectors(4 * (DATA_LOWATER.0 * DATA_BLOCK_SIZE.0));

#[derive(Debug)]
pub struct StratFilesystem {
    thin_dev: ThinDev,
    created: DateTime<Utc>,
}

impl StratFilesystem {
    /// Create a StratFilesystem on top of the given ThinDev.
    pub fn initialize(
        pool_uuid: PoolUuid,
        thinpool_dev: &ThinPoolDev,
        size: Sectors,
        id: ThinDevId,
    ) -> StratisResult<(FilesystemUuid, StratFilesystem)> {
        let fs_uuid = FilesystemUuid::new_v4();
        let (dm_name, dm_uuid) = format_thin_ids(pool_uuid, ThinRole::Filesystem(fs_uuid));
        let mut thin_dev =
            ThinDev::new(get_dm(), &dm_name, Some(&dm_uuid), size, thinpool_dev, id)?;

        if let Err(err) = create_fs(&thin_dev.devnode(), Some(StratisUuid::Fs(fs_uuid)), false) {
            udev_settle().unwrap_or_else(|err| {
                warn!("{}", err);
                sleep(Duration::from_secs(5));
            });
            if let Err(err2) = thin_dev.destroy(get_dm(), thinpool_dev) {
                error!(
                    "While handling create_fs error, thin_dev.destroy() failed: {}",
                    err2
                );
                // This will result in a dangling DM device that will prevent
                // the thinpool from being destroyed, and wasted space in the
                // thinpool.
                // TODO: Recover. But how?
            }
            return Err(err);
        }

        Ok((
            fs_uuid,
            StratFilesystem {
                thin_dev,
                created: Utc::now(),
            },
        ))
    }

    /// Build a StratFilesystem that includes the ThinDev and related info.
    pub fn setup(
        pool_uuid: PoolUuid,
        thinpool_dev: &ThinPoolDev,
        fssave: &FilesystemSave,
    ) -> StratisResult<StratFilesystem> {
        let (dm_name, dm_uuid) = format_thin_ids(pool_uuid, ThinRole::Filesystem(fssave.uuid));
        let thin_dev = ThinDev::setup(
            get_dm(),
            &dm_name,
            Some(&dm_uuid),
            fssave.size,
            thinpool_dev,
            fssave.thin_id,
        )?;
        Ok(StratFilesystem {
            thin_dev,
            created: Utc.timestamp(fssave.created as i64, 0),
        })
    }

    /// Send a synthetic udev change event to the devicemapper device representing
    /// the filesystem.
    pub fn udev_fs_change(&self, pool_name: &str, fs_uuid: FilesystemUuid, fs_name: &str) {
        fn udev_change_event(
            thin_dev: &ThinDev,
            pool_name: &str,
            fs_uuid: FilesystemUuid,
            fs_name: &str,
        ) -> StratisResult<()> {
            let device = thin_dev.device();
            let uevent_file = [
                "/sys/dev/block",
                &format!("{}:{}", device.major, device.minor),
                "uevent",
            ]
            .iter()
            .collect::<PathBuf>();
            OpenOptions::new()
                .write(true)
                .open(&uevent_file)?
                .write_all(
                    format!(
                        "{} {} STRATISPOOLNAME={} STRATISFSNAME={}",
                        devlinks::UEVENT_CHANGE_EVENT,
                        fs_uuid,
                        BASE32_NOPAD.encode(pool_name.as_bytes()),
                        BASE32_NOPAD.encode(fs_name.as_bytes()),
                    )
                    .as_bytes(),
                )?;
            Ok(())
        }

        if let Err(e) = udev_change_event(&self.thin_dev, pool_name, fs_uuid, fs_name) {
            warn!("Failed to notify udev to perform symlink operation: {}", e);
        }
    }

    /// Create a snapshot of the filesystem. Return the resulting filesystem/ThinDev
    /// to the caller.  Use snapshot_name for the Stratis filesystem name.  Use
    /// snapshot_dmname for the new name of the ThinDev allocated for the snapshot.
    /// Mounting a filesystem with a duplicate UUID would require special handling,
    /// so snapshot_fs_uuid is used to update the new snapshot filesystem so it has
    /// a unique UUID.
    #[allow(clippy::too_many_arguments)]
    pub fn snapshot(
        &self,
        thin_pool: &ThinPoolDev,
        snapshot_name: &str,
        snapshot_dm_name: &DmName,
        snapshot_dm_uuid: Option<&DmUuid>,
        snapshot_fs_name: &Name,
        snapshot_fs_uuid: FilesystemUuid,
        snapshot_thin_id: ThinDevId,
    ) -> StratisResult<StratFilesystem> {
        match self.thin_dev.snapshot(
            get_dm(),
            snapshot_dm_name,
            snapshot_dm_uuid,
            thin_pool,
            snapshot_thin_id,
        ) {
            Ok(thin_dev) => {
                // If the source is mounted, XFS puts a dummy record in the
                // log to enforce replay of the snapshot to deal with any
                // orphaned inodes. The dummy record put the log in a dirty
                // state. xfs_admin won't allow a filesystem UUID
                // to be updated when the log is dirty.  To clear the log
                // we mount/unmount the filesystem before updating the UUID.
                //
                // If the source is unmounted the XFS log will be clean so
                // we can skip the mount/unmount.
                if !self.mount_points()?.is_empty() {
                    let tmp_dir = tempfile::Builder::new()
                        .prefix(TEMP_MNT_POINT_PREFIX)
                        .tempdir()?;
                    // Mount the snapshot with the "nouuid" option. mount
                    // will fail due to duplicate UUID otherwise.
                    mount(
                        Some(&thin_dev.devnode()),
                        tmp_dir.path(),
                        Some("xfs"),
                        MsFlags::empty(),
                        Some("nouuid"),
                    )?;
                    umount(tmp_dir.path())?;
                }

                set_uuid(&thin_dev.devnode(), snapshot_fs_uuid)?;
                Ok(StratFilesystem {
                    thin_dev,
                    created: Utc::now(),
                })
            }
            Err(e) => Err(StratisError::Msg(format!(
                "failed to create {} snapshot for {} - {}",
                snapshot_name, snapshot_fs_name, e
            ))),
        }
    }

    /// Check if filesystem is getting full and needs to be extended.
    ///
    /// Returns:
    /// * Some(_) if metadata should be saved.
    /// * None if metadata should not be saved.
    /// TODO: deal with the thindev in a Fail state.
    pub fn check(&mut self) -> StratisResult<Option<StratFilesystemDiff>> {
        match self.thin_dev.status(get_dm(), DmOptions::default())? {
            ThinStatus::Working(_) => {
                if let Some(mount_point) = self.mount_points()?.first() {
                    let original_state = self.dump();
                    let (fs_total_bytes, fs_total_used_bytes) = fs_usage(mount_point)?;
                    let free_bytes = fs_total_bytes - fs_total_used_bytes;
                    if free_bytes.sectors() < FILESYSTEM_LOWATER {
                        let old_table = self.thin_dev.table().table.clone();
                        let mut new_table = old_table.clone();
                        new_table.length =
                            self.thin_dev.size() + Self::extend_size(self.thin_dev.size());
                        self.thin_dev.set_table(get_dm(), new_table)?;
                        if let Err(causal) = xfs_growfs(mount_point) {
                            if let Err(rollback) = self.thin_dev.set_table(get_dm(), old_table) {
                                Err(StratisError::RollbackError {
                                    causal_error: Box::new(causal),
                                    rollback_error: Box::new(StratisError::from(rollback)),
                                    // NOTE: Read-only may be too aggressive.
                                    level: ActionAvailability::NoPoolChanges,
                                })
                            } else {
                                Err(causal)
                            }
                        } else {
                            Ok(Some(original_state.diff(&self.dump())))
                        }
                    } else {
                        Ok(None)
                    }
                } else {
                    Ok(None)
                }
            }
            ThinStatus::Error => {
                let error_msg = format!(
                    "Unable to get status for filesystem thin device {}",
                    self.thin_dev.device()
                );
                Err(StratisError::Msg(error_msg))
            }
            ThinStatus::Fail => Ok(None),
        }
    }

    /// Return an extend size for the thindev under the filesystem
    /// TODO: returning the current size will double the space provisioned to
    /// the thin device.  We should determine if this is a reasonable value.
    fn extend_size(current_size: Sectors) -> Sectors {
        current_size
    }

    /// Tear down the filesystem.
    pub fn teardown(&mut self) -> StratisResult<()> {
        self.thin_dev.teardown(get_dm())?;
        Ok(())
    }

    /// Destroy the filesystem.
    pub fn destroy(&mut self, thin_pool: &ThinPoolDev) -> StratisResult<()> {
        self.thin_dev.destroy(get_dm(), thin_pool)?;
        Ok(())
    }

    pub fn record(&self, name: &Name, uuid: FilesystemUuid) -> FilesystemSave {
        FilesystemSave {
            name: name.to_owned(),
            uuid,
            thin_id: self.thin_dev.id(),
            size: self.thin_dev.size(),
            created: self.created.timestamp() as u64,
        }
    }

    /// Find places where this filesystem is mounted.
    fn mount_points(&self) -> StratisResult<Vec<PathBuf>> {
        // Use major:minor values to find mounts for this filesystem
        let major = u64::from(self.thin_dev.device().major);
        let minor = u64::from(self.thin_dev.device().minor);

        let mut mount_data = String::new();
        File::open("/proc/self/mountinfo")?.read_to_string(&mut mount_data)?;
        let parser = libmount::mountinfo::Parser::new(mount_data.as_bytes());

        let mut ret_vec = Vec::new();
        for mp in parser {
            match mp {
                Ok(mount) => {
                    if mount.major as u64 == major && mount.minor as u64 == minor {
                        ret_vec.push(PathBuf::from(&mount.mount_point));
                    }
                }
                Err(e) => {
                    let error_msg = format!("Error during parsing {:?}: {:?}", *self, e);
                    return Err(StratisError::Msg(error_msg));
                }
            }
        }

        Ok(ret_vec)
    }

    pub fn thindev_size(&self) -> Sectors {
        self.thin_dev.size()
    }
}

impl Filesystem for StratFilesystem {
    fn devnode(&self) -> PathBuf {
        self.thin_dev.devnode()
    }

    fn created(&self) -> DateTime<Utc> {
        self.created
    }

    fn path_to_mount_filesystem(&self, pool_name: &str, fs_name: &str) -> PathBuf {
        devlinks::filesystem_mount_path(pool_name, fs_name)
    }

    fn used(&self) -> StratisResult<Bytes> {
        match self.thin_dev.status(get_dm(), DmOptions::default())? {
            ThinStatus::Working(wk_status) => Ok(wk_status.nr_mapped_sectors.bytes()),
            ThinStatus::Error => {
                let error_msg = format!(
                    "Unable to get status for filesystem thin device {}",
                    self.thin_dev.device()
                );
                Err(StratisError::Msg(error_msg))
            }
            ThinStatus::Fail => {
                let error_msg = format!("ThinDev {} is in a failed state", self.thin_dev.device());
                Err(StratisError::Msg(error_msg))
            }
        }
    }

    fn size(&self) -> Bytes {
        self.thin_dev.size().bytes()
    }
}

impl DumpState for StratFilesystem {
    type State = StratFilesystemState;

    fn dump(&self) -> Self::State {
        StratFilesystemState::new(self.thin_dev.size().bytes())
    }
}

/// Return total bytes allocated to the filesystem, total bytes used by data/metadata
pub fn fs_usage(mount_point: &Path) -> StratisResult<(Bytes, Bytes)> {
    let stat = statvfs(mount_point)?;

    // Upcast all arch-dependent variable width values to u64
    let (block_size, blocks, blocks_free) = (
        stat.block_size() as u64,
        stat.blocks() as u64,
        stat.blocks_free() as u64,
    );
    Ok((
        Bytes::from(block_size * blocks),
        Bytes::from(block_size * (blocks - blocks_free)),
    ))
}

impl<'a> Into<Value> for &'a StratFilesystem {
    fn into(self) -> Value {
        let mut json = Map::new();
        json.insert(
            "size".to_string(),
            Value::from(self.thindev_size().to_string()),
        );
        json.insert(
            "used".to_string(),
            Value::from(
                self.used()
                    .map(|v| v.to_string())
                    .unwrap_or_else(|_| "Unavailable".to_string()),
            ),
        );
        Value::from(json)
    }
}
<|endoftext|>


<commit_before>#![macro_use]
use middle::analysis::ast::*;
use ast::Expression::*;
use std::cmp;
use syntax::codemap::BytePos;
pub use rust::NO_EXPANSION;

enum Predicate {
    And(usize),
    Not(usize),
    Oom(usize),
    Zom(usize),
    Nothing
}

enum VecType {
    And,
    OneOrMore,
    Nothing
}

pub struct UselessChaining<'a: 'c, 'b: 'a, 'c>
{
  grammar: &'c AGrammar<'a, 'b>,
  pred: Predicate,
  vec_pred : Vec<Predicate>,
  vec_type : VecType
}

impl <'a, 'b, 'c> UselessChaining<'a, 'b, 'c>
{
  pub fn analyse(grammar: AGrammar<'a, 'b>) -> Partial<AGrammar<'a, 'b>> {
    UselessChaining::check_chaining(&grammar);
    Partial::Value(grammar)
  }

  fn check_chaining(grammar: &'c AGrammar<'a, 'b>){
    let mut analyser = UselessChaining{
      grammar: grammar,
      pred: Predicate::Nothing,
      vec_pred: vec![],
      vec_type: VecType::Nothing
    };
    for rule in &grammar.rules {
      // println!("\nRegle");
      analyser.visit_expr(rule.expr_idx)
    }
  }

  fn span_end_point(&self, sp: Span) -> Span{
      let lo = cmp::max(sp.hi().0 - 1, sp.lo().0);
      sp.with_lo(BytePos(lo))
  }

  fn get_th(&self, n: usize) -> &'static str {
      match n {
          1 => "st",
          2 => "nd",
          3 => "rd",
          _ => "th"
      }
  }

  fn warn_useless_chaining(&self, pred: (&'static str, &'static str, &'static str, &'static str), span1: Span, span2: Span){
      let (detected,help,first,second) = pred;
      self.grammar.span_warn(
          span1,
          format!(
              "Detected useless chaining: {}
              \nHelp: {}
              \nFirst predicate {}"
          ,detected,help,first)
      );
      self.grammar.span_note(
          span2,
          format!("Second predicate {}", second)
      )
  }

  fn warn_vec_useless_chaining(&self, pred: (&'static str, &'static str, &'static str), i: usize, span: Span){
      let (warn,note,span_note) = pred;
      if i==0 {
          self.grammar.span_warn(
              span,
              format!(
                  "Detected useless chaining: multiple {}
                  \nHelp: {}
                  \nFirst occurence of {}"
              ,warn,note,warn)
          )
      }
      else{
          self.grammar.span_note(
              span,
              format!("{}{} occurence of {}",i+1,self.get_th(i+1),span_note)
          )
      }

  }

  fn warn_verify_multiple(&self) {
      for (i, x) in self.vec_pred.iter().enumerate() {
          match x {
              &Predicate::And(this) => {
                  let lo = self.grammar[this].span().lo();
                  let span = Span::new(lo,lo,NO_EXPANSION);
                  self.warn_vec_useless_chaining(("&","&(&e) -> &e","and"),i,span);
              }
              &Predicate::Oom(this) => {
                  let sp = self.grammar[this].span();
                  let span = self.span_end_point(sp);
                  self.warn_vec_useless_chaining(("+","(e+)+ -> e+","one or more"),i,span);
              }
              _ => unreachable!()
          }
      }
  }

  fn verify_multiple(&mut self){
      if self.vec_pred.len()>=2 {
          self.warn_verify_multiple()
      }
      self.vec_pred.clear();
      self.vec_type=VecType::Nothing;
  }
 }

impl<'a, 'b, 'c> ExprByIndex for UselessChaining<'a, 'b, 'c>
{
  fn expr_by_index(&self, index: usize) -> Expression {
    self.grammar.expr_by_index(index).clone()
  }
}

impl<'a, 'b, 'c> Visitor<()> for UselessChaining<'a, 'b, 'c>
{
    unit_visitor_impl!(str_literal);
    unit_visitor_impl!(atom);

  fn visit_expr(&mut self, this: usize) {
      match self.expr_by_index(this) {
        NonTerminalSymbol(rule) => {
          // println!("NonTerminalSymbol");
          self.visit_non_terminal_symbol(this, rule)
        }
        ZeroOrMore(child) => {
          // println!("ZeroOrMore");
          self.visit_zero_or_more(this, child)
        }
        OneOrMore(child) => {
          // println!("OneOrMore");
          self.visit_one_or_more(this, child)
        }
        NotPredicate(child) => {
          // println!("NotPredicate");
          self.visit_not_predicate(this, child)
        }
        AndPredicate(child) => {
          // println!("AndPredicate");
          self.visit_and_predicate(this, child)
        }
        Choice(choices) => {
          // println!("choice")
          self.visit_choice(this, choices)
        }
        Sequence(seq) => {
          // println!("StrLiteral: {}",strl)
          self.visit_sequence(this, seq)
        }
        _ => {
          self.pred=Predicate::Nothing;
          self.verify_multiple();
        }
      }
  }

  fn visit_non_terminal_symbol(&mut self, _this: usize, rule: Ident){
    // println!("non_terminal");
    self.visit_expr(self.grammar.find_rule_by_ident(rule).expr_idx)
  }

  fn visit_one_or_more(&mut self, this: usize, child: usize){
    // println!("one_or_more");
    match self.pred {
        Predicate::Zom(t) => {
            let first_span = self.grammar[this].span();
            let second_span = self.grammar[t].span();
            self.warn_useless_chaining(
                ("(e+)*","(e+)* -> e+","One or more","Zero or more"),
                self.span_end_point(first_span),
                self.span_end_point(second_span)
            );
        }
        _ => ()
    }
    match self.vec_type {
        VecType::And => {
            self.verify_multiple()
        }
        VecType::Nothing => {
            self.vec_type=VecType::OneOrMore
        }
        _ => ()
    }
    self.vec_pred.push(Predicate::Oom(this));
    self.visit_expr(child)
  }

  fn visit_zero_or_more(&mut self, this: usize, child: usize){
    // println!("zero_or_more");
    self.pred = Predicate::Zom(this);
    self.verify_multiple();
    self.visit_expr(child)
  }

  fn visit_not_predicate(&mut self, this: usize, child: usize){
    // println!("not_predicate");
    match self.pred {
        Predicate::Not(t) => {
            let f_lo = self.grammar[this].span().lo();
            let s_lo = self.grammar[t].span().lo();
            let first_span = Span::new(f_lo, f_lo, NO_EXPANSION);
            let second_span = Span::new(s_lo, s_lo, NO_EXPANSION);
            self.warn_useless_chaining(
                ("!(!e)","!(!e) -> &e","not","not"),
                first_span,
                second_span
            );
        }
        Predicate::And(t) => {
            let f_lo = self.grammar[this].span().lo();
            let s_lo = self.grammar[t].span().lo();
            let first_span = Span::new(f_lo, f_lo, NO_EXPANSION);
            let second_span = Span::new(s_lo, s_lo, NO_EXPANSION);
            self.warn_useless_chaining(
                ("&(!e)","&(!e) -> !e","not","and"),
                first_span,
                second_span
            );
        }
        _ => {}
    }
    self.pred=Predicate::Not(this);
    self.verify_multiple();
    self.visit_expr(child)
  }

  fn visit_and_predicate(&mut self, this: usize, child: usize){
    // println!("and_predicate");
    match self.pred {
        Predicate::Not(t) => {
            let f_lo = self.grammar[this].span().lo();
            let s_lo = self.grammar[t].span().lo();
            let first_span = Span::new(f_lo, f_lo, NO_EXPANSION);
            let second_span = Span::new(s_lo, s_lo, NO_EXPANSION);
            self.warn_useless_chaining(
                ("!(&e)","!(&e) -> !e","and","not"),
                first_span,
                second_span
            );
        }
        _ => {}
    }
    self.pred=Predicate::And(this);

    match self.vec_type {
        VecType::OneOrMore => {
            self.verify_multiple()
        }
        VecType::Nothing => {
            self.vec_type=VecType::And;
        }
        _ => ()
    }
    self.vec_pred.push(Predicate::And(this));
    self.visit_expr(child)
  }

  fn visit_sequence(&mut self, _: usize, children: Vec<usize>){
    for child in children {
        self.verify_multiple();
        self.visit_expr(child);
    }
  }

  fn visit_choice(&mut self, _: usize, _: Vec<usize>){
      // for child in children {
      //     self.verify_multiple();
      //     self.visit_expr(child);
      // }
      self.verify_multiple();
  }
}
<commit_msg>[analysis] Add Copyright to useless chaining<commit_after>// Copyright 2018 Chao Lin & William Sergeant (Sorbonne University)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![macro_use]
use middle::analysis::ast::*;
use ast::Expression::*;
use std::cmp;
use syntax::codemap::BytePos;
pub use rust::NO_EXPANSION;

enum Predicate {
    And(usize),
    Not(usize),
    Oom(usize),
    Zom(usize),
    Nothing
}

enum VecType {
    And,
    OneOrMore,
    Nothing
}

pub struct UselessChaining<'a: 'c, 'b: 'a, 'c>
{
  grammar: &'c AGrammar<'a, 'b>,
  pred: Predicate,
  vec_pred : Vec<Predicate>,
  vec_type : VecType
}

impl <'a, 'b, 'c> UselessChaining<'a, 'b, 'c>
{
  pub fn analyse(grammar: AGrammar<'a, 'b>) -> Partial<AGrammar<'a, 'b>> {
    UselessChaining::check_chaining(&grammar);
    Partial::Value(grammar)
  }

  fn check_chaining(grammar: &'c AGrammar<'a, 'b>){
    let mut analyser = UselessChaining{
      grammar: grammar,
      pred: Predicate::Nothing,
      vec_pred: vec![],
      vec_type: VecType::Nothing
    };
    for rule in &grammar.rules {
      // println!("\nRegle");
      analyser.visit_expr(rule.expr_idx)
    }
  }

  fn span_end_point(&self, sp: Span) -> Span{
      let lo = cmp::max(sp.hi().0 - 1, sp.lo().0);
      sp.with_lo(BytePos(lo))
  }

  fn get_th(&self, n: usize) -> &'static str {
      match n {
          1 => "st",
          2 => "nd",
          3 => "rd",
          _ => "th"
      }
  }

  fn warn_useless_chaining(&self, pred: (&'static str, &'static str, &'static str, &'static str), span1: Span, span2: Span){
      let (detected,help,first,second) = pred;
      self.grammar.span_warn(
          span1,
          format!(
              "Detected useless chaining: {}
              \nHelp: {}
              \nFirst predicate {}"
          ,detected,help,first)
      );
      self.grammar.span_note(
          span2,
          format!("Second predicate {}", second)
      )
  }

  fn warn_vec_useless_chaining(&self, pred: (&'static str, &'static str, &'static str), i: usize, span: Span){
      let (warn,note,span_note) = pred;
      if i==0 {
          self.grammar.span_warn(
              span,
              format!(
                  "Detected useless chaining: multiple {}
                  \nHelp: {}
                  \nFirst occurence of {}"
              ,warn,note,warn)
          )
      }
      else{
          self.grammar.span_note(
              span,
              format!("{}{} occurence of {}",i+1,self.get_th(i+1),span_note)
          )
      }

  }

  fn warn_verify_multiple(&self) {
      for (i, x) in self.vec_pred.iter().enumerate() {
          match x {
              &Predicate::And(this) => {
                  let lo = self.grammar[this].span().lo();
                  let span = Span::new(lo,lo,NO_EXPANSION);
                  self.warn_vec_useless_chaining(("&","&(&e) -> &e","and"),i,span);
              }
              &Predicate::Oom(this) => {
                  let sp = self.grammar[this].span();
                  let span = self.span_end_point(sp);
                  self.warn_vec_useless_chaining(("+","(e+)+ -> e+","one or more"),i,span);
              }
              _ => unreachable!()
          }
      }
  }

  fn verify_multiple(&mut self){
      if self.vec_pred.len()>=2 {
          self.warn_verify_multiple()
      }
      self.vec_pred.clear();
      self.vec_type=VecType::Nothing;
  }
 }

impl<'a, 'b, 'c> ExprByIndex for UselessChaining<'a, 'b, 'c>
{
  fn expr_by_index(&self, index: usize) -> Expression {
    self.grammar.expr_by_index(index).clone()
  }
}

impl<'a, 'b, 'c> Visitor<()> for UselessChaining<'a, 'b, 'c>
{
    unit_visitor_impl!(str_literal);
    unit_visitor_impl!(atom);

  fn visit_expr(&mut self, this: usize) {
      match self.expr_by_index(this) {
        NonTerminalSymbol(rule) => {
          // println!("NonTerminalSymbol");
          self.visit_non_terminal_symbol(this, rule)
        }
        ZeroOrMore(child) => {
          // println!("ZeroOrMore");
          self.visit_zero_or_more(this, child)
        }
        OneOrMore(child) => {
          // println!("OneOrMore");
          self.visit_one_or_more(this, child)
        }
        NotPredicate(child) => {
          // println!("NotPredicate");
          self.visit_not_predicate(this, child)
        }
        AndPredicate(child) => {
          // println!("AndPredicate");
          self.visit_and_predicate(this, child)
        }
        Choice(choices) => {
          // println!("choice")
          self.visit_choice(this, choices)
        }
        Sequence(seq) => {
          // println!("StrLiteral: {}",strl)
          self.visit_sequence(this, seq)
        }
        _ => {
          self.pred=Predicate::Nothing;
          self.verify_multiple();
        }
      }
  }

  fn visit_non_terminal_symbol(&mut self, _this: usize, rule: Ident){
    // println!("non_terminal");
    self.visit_expr(self.grammar.find_rule_by_ident(rule).expr_idx)
  }

  fn visit_one_or_more(&mut self, this: usize, child: usize){
    // println!("one_or_more");
    match self.pred {
        Predicate::Zom(t) => {
            let first_span = self.grammar[this].span();
            let second_span = self.grammar[t].span();
            self.warn_useless_chaining(
                ("(e+)*","(e+)* -> e+","One or more","Zero or more"),
                self.span_end_point(first_span),
                self.span_end_point(second_span)
            );
        }
        _ => ()
    }
    match self.vec_type {
        VecType::And => {
            self.verify_multiple()
        }
        VecType::Nothing => {
            self.vec_type=VecType::OneOrMore
        }
        _ => ()
    }
    self.vec_pred.push(Predicate::Oom(this));
    self.visit_expr(child)
  }

  fn visit_zero_or_more(&mut self, this: usize, child: usize){
    // println!("zero_or_more");
    self.pred = Predicate::Zom(this);
    self.verify_multiple();
    self.visit_expr(child)
  }

  fn visit_not_predicate(&mut self, this: usize, child: usize){
    // println!("not_predicate");
    match self.pred {
        Predicate::Not(t) => {
            let f_lo = self.grammar[this].span().lo();
            let s_lo = self.grammar[t].span().lo();
            let first_span = Span::new(f_lo, f_lo, NO_EXPANSION);
            let second_span = Span::new(s_lo, s_lo, NO_EXPANSION);
            self.warn_useless_chaining(
                ("!(!e)","!(!e) -> &e","not","not"),
                first_span,
                second_span
            );
        }
        Predicate::And(t) => {
            let f_lo = self.grammar[this].span().lo();
            let s_lo = self.grammar[t].span().lo();
            let first_span = Span::new(f_lo, f_lo, NO_EXPANSION);
            let second_span = Span::new(s_lo, s_lo, NO_EXPANSION);
            self.warn_useless_chaining(
                ("&(!e)","&(!e) -> !e","not","and"),
                first_span,
                second_span
            );
        }
        _ => {}
    }
    self.pred=Predicate::Not(this);
    self.verify_multiple();
    self.visit_expr(child)
  }

  fn visit_and_predicate(&mut self, this: usize, child: usize){
    // println!("and_predicate");
    match self.pred {
        Predicate::Not(t) => {
            let f_lo = self.grammar[this].span().lo();
            let s_lo = self.grammar[t].span().lo();
            let first_span = Span::new(f_lo, f_lo, NO_EXPANSION);
            let second_span = Span::new(s_lo, s_lo, NO_EXPANSION);
            self.warn_useless_chaining(
                ("!(&e)","!(&e) -> !e","and","not"),
                first_span,
                second_span
            );
        }
        _ => {}
    }
    self.pred=Predicate::And(this);

    match self.vec_type {
        VecType::OneOrMore => {
            self.verify_multiple()
        }
        VecType::Nothing => {
            self.vec_type=VecType::And;
        }
        _ => ()
    }
    self.vec_pred.push(Predicate::And(this));
    self.visit_expr(child)
  }

  fn visit_sequence(&mut self, _: usize, children: Vec<usize>){
    for child in children {
        self.verify_multiple();
        self.visit_expr(child);
    }
  }

  fn visit_choice(&mut self, _: usize, _: Vec<usize>){
      // for child in children {
      //     self.verify_multiple();
      //     self.visit_expr(child);
      // }
      self.verify_multiple();
  }
}
<|endoftext|>


<commit_before>// run-pass
// ignore-cloudabi no processes
// ignore-emscripten no processes

// Tests ensuring that `dbg!(expr)` has the expected run-time behavior.
// as well as some compile time properties we expect.

#[derive(Copy, Clone, Debug)]
struct Unit;

#[derive(Copy, Clone, Debug, PartialEq)]
struct Point<T> {
    x: T,
    y: T,
}

#[derive(Debug, PartialEq)]
struct NoCopy(usize);

fn test() {
    let a: Unit = dbg!(Unit);
    let _: Unit = dbg!(a);
    // We can move `a` because it's Copy.
    drop(a);

    // `Point<T>` will be faithfully formatted according to `{:#?}`.
    let a = Point { x: 42, y: 24 };
    let b: Point<u8> = dbg!(Point { x: 42, y: 24 }); // test stringify!(..)
    let c: Point<u8> = dbg!(b);
    // Identity conversion:
    assert_eq!(a, b);
    assert_eq!(a, c);
    // We can move `b` because it's Copy.
    drop(b);

    // Test that we can borrow and that successive applications is still identity.
    let a = NoCopy(1337);
    let b: &NoCopy = dbg!(dbg!(&a));
    assert_eq!(&a, b);

    // Test involving lifetimes of temporaries:
    fn f<'a>(x: &'a u8) -> &'a u8 { x }
    let a: &u8 = dbg!(f(&42));
    assert_eq!(a, &42);

    // Test side effects:
    let mut foo = 41;
    assert_eq!(7331, dbg!({
        foo += 1;
        eprintln!("before");
        7331
    }));
    assert_eq!(foo, 42);
}

fn validate_stderr(stderr: Vec<String>) {
    assert_eq!(stderr, &[
        ":21] Unit = Unit",

        ":22] a = Unit",

        ":28] Point{x: 42, y: 24,} = Point {",
        "    x: 42,",
        "    y: 24",
        "}",

        ":29] b = Point {",
        "    x: 42,",
        "    y: 24",
        "}",

        ":38] &a = NoCopy(",
        "    1337",
        ")",

        ":38] dbg!(& a) = NoCopy(",
        "    1337",
        ")",
        ":43] f(&42) = 42",

        "before",
        ":48] { foo += 1; eprintln!(\"before\"); 7331 } = 7331",
    ]);
}

fn main() {
    // The following is a hack to deal with compiletest's inability
    // to check the output (to stdout) of run-pass tests.
    use std::env;
    use std::process::Command;

    let mut args = env::args();
    let prog = args.next().unwrap();
    let child = args.next();
    if let Some("child") = child.as_ref().map(|s| &**s) {
        // Only run the test if we've been spawned as 'child'
        test()
    } else {
        // This essentially spawns as 'child' to run the tests
        // and then it collects output of stderr and checks the output
        // against what we expect.
        let out = Command::new(&prog).arg("child").output().unwrap();
        assert!(out.status.success());
        assert!(out.stdout.is_empty());

        let stderr = String::from_utf8(out.stderr).unwrap();
        let stderr = stderr.lines().map(|mut s| {
            if s.starts_with("[") {
                // Strip `[` and file path:
                s = s.trim_start_matches("[");
                assert!(s.starts_with(file!()));
                s = s.trim_start_matches(file!());
            }
            s.to_owned()
        }).collect();

        validate_stderr(stderr);
    }
}
<commit_msg>Test behaviour<commit_after>// run-pass
// ignore-cloudabi no processes
// ignore-emscripten no processes

// Tests ensuring that `dbg!(expr)` has the expected run-time behavior.
// as well as some compile time properties we expect.

#[derive(Copy, Clone, Debug)]
struct Unit;

#[derive(Copy, Clone, Debug, PartialEq)]
struct Point<T> {
    x: T,
    y: T,
}

#[derive(Debug, PartialEq)]
struct NoCopy(usize);

fn test() {
    let a: Unit = dbg!(Unit);
    let _: Unit = dbg!(a);
    // We can move `a` because it's Copy.
    drop(a);

    // `Point<T>` will be faithfully formatted according to `{:#?}`.
    let a = Point { x: 42, y: 24 };
    let b: Point<u8> = dbg!(Point { x: 42, y: 24 }); // test stringify!(..)
    let c: Point<u8> = dbg!(b);
    // Identity conversion:
    assert_eq!(a, b);
    assert_eq!(a, c);
    // We can move `b` because it's Copy.
    drop(b);

    // Without parameters works as expected.
    let _: () = dbg!();

    // Test that we can borrow and that successive applications is still identity.
    let a = NoCopy(1337);
    let b: &NoCopy = dbg!(dbg!(&a));
    assert_eq!(&a, b);

    // Test involving lifetimes of temporaries:
    fn f<'a>(x: &'a u8) -> &'a u8 { x }
    let a: &u8 = dbg!(f(&42));
    assert_eq!(a, &42);

    // Test side effects:
    let mut foo = 41;
    assert_eq!(7331, dbg!({
        foo += 1;
        eprintln!("before");
        7331
    }));
    assert_eq!(foo, 42);
}

fn validate_stderr(stderr: Vec<String>) {
    assert_eq!(stderr, &[
        ":21] Unit = Unit",

        ":22] a = Unit",

        ":28] Point{x: 42, y: 24,} = Point {",
        "    x: 42,",
        "    y: 24",
        "}",

        ":29] b = Point {",
        "    x: 42,",
        "    y: 24",
        "}",

        ":37]",

        ":41] &a = NoCopy(",
        "    1337",
        ")",

        ":41] dbg!(& a) = NoCopy(",
        "    1337",
        ")",
        ":46] f(&42) = 42",

        "before",
        ":51] { foo += 1; eprintln!(\"before\"); 7331 } = 7331",
    ]);
}

fn main() {
    // The following is a hack to deal with compiletest's inability
    // to check the output (to stdout) of run-pass tests.
    use std::env;
    use std::process::Command;

    let mut args = env::args();
    let prog = args.next().unwrap();
    let child = args.next();
    if let Some("child") = child.as_ref().map(|s| &**s) {
        // Only run the test if we've been spawned as 'child'
        test()
    } else {
        // This essentially spawns as 'child' to run the tests
        // and then it collects output of stderr and checks the output
        // against what we expect.
        let out = Command::new(&prog).arg("child").output().unwrap();
        assert!(out.status.success());
        assert!(out.stdout.is_empty());

        let stderr = String::from_utf8(out.stderr).unwrap();
        let stderr = stderr.lines().map(|mut s| {
            if s.starts_with("[") {
                // Strip `[` and file path:
                s = s.trim_start_matches("[");
                assert!(s.starts_with(file!()));
                s = s.trim_start_matches(file!());
            }
            s.to_owned()
        }).collect();

        validate_stderr(stderr);
    }
}
<|endoftext|>


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

use std::cell::Cell;
use std::collections::hashmap::HashMap;
use std::gc::Gc;
use syntax::codemap::Span;
use syntax::ext::base::ExtCtxt;

#[deriving(Show)]
pub enum AttributeValue {
  IntValue(uint),
  StrValue(String),
  RefValue(String),
}

pub enum AttributeType {
  StringAttribute,
  IntAttribute,
  RefAttribute,
}

#[deriving(Show)]
pub struct Attribute {
  pub value: AttributeValue,
  pub key_span: Span,
  pub value_span: Span,
}

impl Attribute {
  pub fn new(value: AttributeValue, key_span: Span, value_span: Span)
      -> Attribute {
    Attribute {
      value: value,
      key_span: key_span,
      value_span: value_span,
    }
  }
}

#[deriving(Show)]
pub struct Node {
  pub name: Option<String>,
  pub name_span: Span,

  pub path: String,
  pub path_span: Span,

  pub attributes: HashMap<String, Attribute>,
  pub subnodes: HashMap<String, Gc<Node>>,

  pub type_name: Cell<Option<&'static str>>,
}

impl Node {
  pub fn new(name: Option<String>, name_span: Span, path: String,
      path_span: Span) -> Node {
    Node {
      name: name,
      name_span: name_span,
      path: path,
      path_span: path_span,
      attributes: HashMap::new(),
      subnodes: HashMap::new(),
      type_name: Cell::new(None),
    }
  }

  pub fn get_attr<'a>(&'a self, key: &str) -> &'a Attribute {
    self.attributes.get(&key.to_str())
  }

  pub fn get_string_attr<'a>(&'a self, key: &str) -> Option<&'a String> {
    self.attributes.find(&key.to_str()).and_then(|av| match av.value {
      StrValue(ref s) => Some(s),
      _ => None,
    })
  }

  pub fn get_int_attr(&self, key: &str) -> Option<uint> {
    self.attributes.find(&key.to_str()).and_then(|av| match av.value {
      IntValue(ref u) => Some(*u),
      _ => None,
    })
  }

  pub fn get_ref_attr<'a>(&'a self, key: &str) -> Option<&'a String> {
    self.attributes.find(&key.to_str()).and_then(|av| match av.value {
      RefValue(ref s) => Some(s),
      _ => None,
    })
  }

  pub fn get_required_string_attr<'a>(&'a self, cx: &ExtCtxt, key: &str)
      -> Option<&'a String> {
    match self.get_string_attr(key) {
      Some(val) => Some(val),
      None => {
        cx.parse_sess().span_diagnostic.span_err(self.name_span,
            format!("required string attribute `{}` is missing", key)
            .as_slice());
        None
      }
    }
  }

  pub fn get_required_int_attr<'a>(&'a self, cx: &ExtCtxt, key: &str)
      -> Option<uint> {
    match self.get_int_attr(key) {
      Some(val) => Some(val),
      None => {
        cx.parse_sess().span_diagnostic.span_err(self.name_span,
            format!("required integer attribute `{}` is missing", key)
            .as_slice());
        None
      }
    }
  }

  pub fn get_required_ref_attr<'a>(&'a self, cx: &ExtCtxt, key: &str)
      -> Option<&'a String> {
    match self.get_ref_attr(key) {
      Some(val) => Some(val),
      None => {
        cx.parse_sess().span_diagnostic.span_err(self.name_span,
            format!("required ref attribute `{}` is missing", key)
            .as_slice());
        None
      }
    }
  }

  pub fn expect_no_attributes(&self, cx: &ExtCtxt) -> bool {
    let mut ok = true;
    for (_, v) in self.attributes.iter() {
      ok = false;
      cx.parse_sess().span_diagnostic.span_err(v.key_span,
          "no attributes expected");
    }
    ok
  }

  pub fn expect_no_subnodes(&self, cx: &ExtCtxt) -> bool {
    let mut ok = true;
    for (_, sub) in self.subnodes.iter() {
      ok = false;
      cx.parse_sess().span_diagnostic.span_err(sub.name_span,
          "no subnodes expected");
    }
    ok
  }

  pub fn expect_attributes(&self, cx: &ExtCtxt,
      expectations: &[(&str, AttributeType)]) -> bool {
    let mut ok = true;
    for &(n, ref t) in expectations.iter() {
      match t {
        &StringAttribute => {
          if self.get_required_string_attr(cx, n).is_none() {ok = false}
        },
        &IntAttribute => {
          if self.get_required_int_attr(cx, n).is_none() {ok = false}
        },
        &RefAttribute => {
          if self.get_required_ref_attr(cx, n).is_none() {ok = false}
        },
      }
    }
    ok
  }

  pub fn expect_subnodes(&self, cx: &ExtCtxt, expectations: &[&str]) -> bool {
    let mut ok = true;
    for (path, sub) in self.subnodes.iter() {
      if !expectations.contains(&path.as_slice()) {
        ok = false;
        cx.parse_sess().span_diagnostic.span_err(sub.path_span,
            format!("unknown subnode `{}` in node `{}`",
                path, self.path).as_slice());
      }
    }
    ok
  }

  pub fn get_by_path<'a>(&'a self, path: &str) -> Option<&'a Gc<Node>> {
    self.subnodes.find(&path.to_str())
  }
}

#[deriving(Show)]
pub struct PlatformTree {
  nodes: HashMap<String, Gc<Node>>,
  named: HashMap<String, Gc<Node>>,
}

impl PlatformTree {
  pub fn new(nodes: HashMap<String, Gc<Node>>, named: HashMap<String, Gc<Node>>)
      -> PlatformTree {
    PlatformTree {
      nodes: nodes,
      named: named,
    }
  }

  pub fn get_by_name<'a>(&'a self, name: &str) -> Option<&'a Gc<Node>> {
    self.named.find(&name.to_str())
  }

  pub fn get_by_path<'a>(&'a self, name: &str) -> Option<&'a Gc<Node>> {
    self.nodes.find(&name.to_str())
  }

  pub fn expect_subnodes(&self, cx: &ExtCtxt, expectations: &[&str]) -> bool {
    let mut ok = true;
    for (path, sub) in self.nodes.iter() {
      if !expectations.contains(&path.as_slice()) {
        ok = false;
        cx.parse_sess().span_diagnostic.span_err(sub.path_span,
            format!("unknown root node `{}`", path).as_slice());
      }
    }
    ok
  }
}
<commit_msg>Added platformtree::node api docs.<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::cell::Cell;
use std::collections::hashmap::HashMap;
use std::gc::Gc;
use syntax::codemap::Span;
use syntax::ext::base::ExtCtxt;

/// Holds a value for an attribute.
///
/// The value can be an unsigned integer, string or reference.
#[deriving(Show)]
pub enum AttributeValue {
  IntValue(uint),
  StrValue(String),
  RefValue(String),
}

/// Expected attribute type.
///
/// Used in Node::expect_attributes to provide the expected type of the
/// attribute.
pub enum AttributeType {
  IntAttribute,
  StringAttribute,
  RefAttribute,
}

/// Attribute value and metadata.
///
/// Stored inside of a HashMap, the key to HashMap is the attribute name.
/// Provides spans for both key and value.
#[deriving(Show)]
pub struct Attribute {
  pub value: AttributeValue,
  pub key_span: Span,
  pub value_span: Span,
}

impl Attribute {
  pub fn new(value: AttributeValue, key_span: Span, value_span: Span)
      -> Attribute {
    Attribute {
      value: value,
      key_span: key_span,
      value_span: value_span,
    }
  }
}

/// PlatformTree node.
///
/// Might have an optional name, is the name is missing, name_span is equal to
/// path_span. Attributes are stored by name, subnodes are stored by path.
/// Type_name, if present, must specify the type path for the node's
/// materialized object.
#[deriving(Show)]
pub struct Node {
  pub name: Option<String>,
  pub name_span: Span,

  pub path: String,
  pub path_span: Span,

  pub attributes: HashMap<String, Attribute>,
  pub subnodes: HashMap<String, Gc<Node>>,

  pub type_name: Cell<Option<&'static str>>,
}

impl Node {
  pub fn new(name: Option<String>, name_span: Span, path: String,
      path_span: Span) -> Node {
    Node {
      name: name,
      name_span: name_span,
      path: path,
      path_span: path_span,
      attributes: HashMap::new(),
      subnodes: HashMap::new(),
      type_name: Cell::new(None),
    }
  }

  /// Returns attribute by name or fail!()s.
  pub fn get_attr<'a>(&'a self, key: &str) -> &'a Attribute {
    self.attributes.get(&key.to_str())
  }

  /// Returns a string attribute by name or None, if it's not present or not of
  /// a StringAttribute type.
  pub fn get_string_attr<'a>(&'a self, key: &str) -> Option<&'a String> {
    self.attributes.find(&key.to_str()).and_then(|av| match av.value {
      StrValue(ref s) => Some(s),
      _ => None,
    })
  }

  /// Returns an integer attribute by name or None, if it's not present or not
  /// of an IntAttribute type.
  pub fn get_int_attr(&self, key: &str) -> Option<uint> {
    self.attributes.find(&key.to_str()).and_then(|av| match av.value {
      IntValue(ref u) => Some(*u),
      _ => None,
    })
  }

  /// Returns a reference attribute by name or None, if it's not present or not
  /// of a RefAttribute type.
  pub fn get_ref_attr<'a>(&'a self, key: &str) -> Option<&'a String> {
    self.attributes.find(&key.to_str()).and_then(|av| match av.value {
      RefValue(ref s) => Some(s),
      _ => None,
    })
  }

  /// Returns a string attribute by name or None, if it's not present or not of
  /// a StringAttribute type. Reports a parser error if an attribute is
  /// missing.
  pub fn get_required_string_attr<'a>(&'a self, cx: &ExtCtxt, key: &str)
      -> Option<&'a String> {
    match self.get_string_attr(key) {
      Some(val) => Some(val),
      None => {
        cx.parse_sess().span_diagnostic.span_err(self.name_span,
            format!("required string attribute `{}` is missing", key)
            .as_slice());
        None
      }
    }
  }

  /// Returns an integer attribute by name or None, if it's not present or not
  /// of an IntAttribute type. Reports a parser error if an attribute is
  /// missing.
  pub fn get_required_int_attr<'a>(&'a self, cx: &ExtCtxt, key: &str)
      -> Option<uint> {
    match self.get_int_attr(key) {
      Some(val) => Some(val),
      None => {
        cx.parse_sess().span_diagnostic.span_err(self.name_span,
            format!("required integer attribute `{}` is missing", key)
            .as_slice());
        None
      }
    }
  }

  /// Returns a reference attribute by name or None, if it's not present or not
  /// of a RefAttribute type. Reports a parser error if an attribute is
  /// missing.
  pub fn get_required_ref_attr<'a>(&'a self, cx: &ExtCtxt, key: &str)
      -> Option<&'a String> {
    match self.get_ref_attr(key) {
      Some(val) => Some(val),
      None => {
        cx.parse_sess().span_diagnostic.span_err(self.name_span,
            format!("required ref attribute `{}` is missing", key)
            .as_slice());
        None
      }
    }
  }

  /// Returns true if node has no attributes. Returs false and reports a parser
  /// error for each found attribute otherwise.
  pub fn expect_no_attributes(&self, cx: &ExtCtxt) -> bool {
    let mut ok = true;
    for (_, v) in self.attributes.iter() {
      ok = false;
      cx.parse_sess().span_diagnostic.span_err(v.key_span,
          "no attributes expected");
    }
    ok
  }

  /// Returns true if node has no subnodes. Returs false and reports a parser
  /// error for each found subnode otherwise.
  pub fn expect_no_subnodes(&self, cx: &ExtCtxt) -> bool {
    let mut ok = true;
    for (_, sub) in self.subnodes.iter() {
      ok = false;
      cx.parse_sess().span_diagnostic.span_err(sub.name_span,
          "no subnodes expected");
    }
    ok
  }

  /// Returns true if node has all of the requested attributes and their types
  /// match. Reports parser errors and returns false otherwise.
  pub fn expect_attributes(&self, cx: &ExtCtxt,
      expectations: &[(&str, AttributeType)]) -> bool {
    let mut ok = true;
    for &(n, ref t) in expectations.iter() {
      match t {
        &StringAttribute => {
          if self.get_required_string_attr(cx, n).is_none() {ok = false}
        },
        &IntAttribute => {
          if self.get_required_int_attr(cx, n).is_none() {ok = false}
        },
        &RefAttribute => {
          if self.get_required_ref_attr(cx, n).is_none() {ok = false}
        },
      }
    }
    ok
  }

  /// Returns true if node has all of the requested subnodes matched by path.
  /// Reports parser errors and returns false otherwise.
  pub fn expect_subnodes(&self, cx: &ExtCtxt, expectations: &[&str]) -> bool {
    let mut ok = true;
    for (path, sub) in self.subnodes.iter() {
      if !expectations.contains(&path.as_slice()) {
        ok = false;
        cx.parse_sess().span_diagnostic.span_err(sub.path_span,
            format!("unknown subnode `{}` in node `{}`",
                path, self.path).as_slice());
      }
    }
    ok
  }

  /// Returns a subnode by path or None, if not found.
  pub fn get_by_path<'a>(&'a self, path: &str) -> Option<&'a Gc<Node>> {
    self.subnodes.find(&path.to_str())
  }
}

/// PlatformTree root object.
///
/// Root nodes are stored by path in `nodes`, All the nmaed nodes are also
/// stored by name in `named`.
#[deriving(Show)]
pub struct PlatformTree {
  nodes: HashMap<String, Gc<Node>>,
  named: HashMap<String, Gc<Node>>,
}

impl PlatformTree {
  pub fn new(nodes: HashMap<String, Gc<Node>>, named: HashMap<String, Gc<Node>>)
      -> PlatformTree {
    PlatformTree {
      nodes: nodes,
      named: named,
    }
  }

  /// Returns a node by name or None, if not found.
  pub fn get_by_name<'a>(&'a self, name: &str) -> Option<&'a Gc<Node>> {
    self.named.find(&name.to_str())
  }

  /// Returns a root node by path or None, if not found.
  pub fn get_by_path<'a>(&'a self, name: &str) -> Option<&'a Gc<Node>> {
    self.nodes.find(&name.to_str())
  }

  /// Returns true if PT has all of the requested root odes matched by path.
  /// Reports parser errors and returns false otherwise.
  pub fn expect_subnodes(&self, cx: &ExtCtxt, expectations: &[&str]) -> bool {
    let mut ok = true;
    for (path, sub) in self.nodes.iter() {
      if !expectations.contains(&path.as_slice()) {
        ok = false;
        cx.parse_sess().span_diagnostic.span_err(sub.path_span,
            format!("unknown root node `{}`", path).as_slice());
      }
    }
    ok
  }
}
<|endoftext|>


<commit_before>/// Ye Olde Await Macro
///
/// Basically a translation of polling to yielding. This crate's macro is
/// reexported in the `futures_await` crate, you should not use this crate
/// specifically. If I knew how to define this macro in the `futures_await`
/// crate I would. Ideally this crate would not exist.

// TODO: how to define this in the `futures_await` crate but have it still
// importable via `futurses_await::prelude::await`?

#[macro_export]
macro_rules! await {
    ($e:expr) => ({
        let mut future = $e;
        loop {
            let poll = unsafe {
                let pin = ::futures::__rt::anchor_experiment::PinMut::new_unchecked(&mut future);
                ::futures::__rt::in_ctx(|ctx| ::futures::__rt::StableFuture::poll(pin, ctx))
            };
            match poll {
                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Ready(e)) => {
                    break ::futures::__rt::std::result::Result::Ok(e)
                }
                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Pending) => {}
                ::futures::__rt::std::result::Result::Err(e) => {
                    break ::futures::__rt::std::result::Result::Err(e)
                }
            }
            yield ::futures::__rt::Async::Pending
        }
    })
}

///
/// Await an item from the stream
/// Basically it does same as `await` macro, but for streams
///

#[macro_export]
macro_rules! await_item {
    ($e:expr) => ({
        loop {
            let poll = ::futures::__rt::in_ctx(|ctx| ::futures::Stream::poll_next(&mut $e, ctx));
            match poll {
                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Ready(e)) => {
                    break ::futures::__rt::std::result::Result::Ok(e)
                }
                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Pending) => {}
                ::futures::__rt::std::result::Result::Err(e) => {
                    break ::futures::__rt::std::result::Result::Err(e)
                }
            }

            yield ::futures::__rt::Async::Pending
        }
    })
}

// TODO: This macro needs to use an extra temporary variable because of
// rust-lang/rust#44197, once that's fixed this should just use $e directly
// inside the yield expression
#[macro_export]
macro_rules! stream_yield {
    ($e:expr) => ({
        let e = $e;
        yield ::futures::__rt::Async::Ready(e)
    })
}
<commit_msg>Scope unsafe in await macro better.<commit_after>/// Ye Olde Await Macro
///
/// Basically a translation of polling to yielding. This crate's macro is
/// reexported in the `futures_await` crate, you should not use this crate
/// specifically. If I knew how to define this macro in the `futures_await`
/// crate I would. Ideally this crate would not exist.

// TODO: how to define this in the `futures_await` crate but have it still
// importable via `futurses_await::prelude::await`?

#[macro_export]
macro_rules! await {
    ($e:expr) => ({
        let mut future = $e;
        loop {
            let poll = {
                let pin = unsafe {
                    ::futures::__rt::anchor_experiment::PinMut::new_unchecked(&mut future)
                };
                ::futures::__rt::in_ctx(|ctx| ::futures::__rt::StableFuture::poll(pin, ctx))
            };
            match poll {
                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Ready(e)) => {
                    break ::futures::__rt::std::result::Result::Ok(e)
                }
                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Pending) => {}
                ::futures::__rt::std::result::Result::Err(e) => {
                    break ::futures::__rt::std::result::Result::Err(e)
                }
            }
            yield ::futures::__rt::Async::Pending
        }
    })
}

///
/// Await an item from the stream
/// Basically it does same as `await` macro, but for streams
///

#[macro_export]
macro_rules! await_item {
    ($e:expr) => ({
        loop {
            let poll = ::futures::__rt::in_ctx(|ctx| ::futures::Stream::poll_next(&mut $e, ctx));
            match poll {
                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Ready(e)) => {
                    break ::futures::__rt::std::result::Result::Ok(e)
                }
                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Pending) => {}
                ::futures::__rt::std::result::Result::Err(e) => {
                    break ::futures::__rt::std::result::Result::Err(e)
                }
            }

            yield ::futures::__rt::Async::Pending
        }
    })
}

// TODO: This macro needs to use an extra temporary variable because of
// rust-lang/rust#44197, once that's fixed this should just use $e directly
// inside the yield expression
#[macro_export]
macro_rules! stream_yield {
    ($e:expr) => ({
        let e = $e;
        yield ::futures::__rt::Async::Ready(e)
    })
}
<|endoftext|>


<commit_before>use crate::iter;
use crate::num::Wrapping;

/// Trait to represent types that can be created by summing up an iterator.
///
/// This trait is used to implement the [`sum()`] method on iterators. Types which
/// implement the trait can be generated by the [`sum()`] method. Like
/// [`FromIterator`] this trait should rarely be called directly and instead
/// interacted with through [`Iterator::sum()`].
///
/// [`sum()`]: Sum::sum
/// [`FromIterator`]: iter::FromIterator
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
pub trait Sum<A = Self>: Sized {
    /// Method which takes an iterator and generates `Self` from the elements by
    /// "summing up" the items.
    #[stable(feature = "iter_arith_traits", since = "1.12.0")]
    fn sum<I: Iterator<Item = A>>(iter: I) -> Self;
}

/// Trait to represent types that can be created by multiplying elements of an
/// iterator.
///
/// This trait is used to implement the [`product()`] method on iterators. Types
/// which implement the trait can be generated by the [`product()`] method. Like
/// [`FromIterator`] this trait should rarely be called directly and instead
/// interacted with through [`Iterator::product()`].
///
/// [`product()`]: Product::product
/// [`FromIterator`]: iter::FromIterator
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
pub trait Product<A = Self>: Sized {
    /// Method which takes an iterator and generates `Self` from the elements by
    /// multiplying the items.
    #[stable(feature = "iter_arith_traits", since = "1.12.0")]
    fn product<I: Iterator<Item = A>>(iter: I) -> Self;
}

macro_rules! integer_sum_product {
    (@impls $zero:expr, $one:expr, #[$attr:meta], $($a:ty)*) => ($(
        #[$attr]
        impl Sum for $a {
            fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
                iter.fold(
                    $zero,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a + b,
                )
            }
        }

        #[$attr]
        impl Product for $a {
            fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
                iter.fold(
                    $one,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a * b,
                )
            }
        }

        #[$attr]
        impl<'a> Sum<&'a $a> for $a {
            fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
                iter.fold(
                    $zero,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a + b,
                )
            }
        }

        #[$attr]
        impl<'a> Product<&'a $a> for $a {
            fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
                iter.fold(
                    $one,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a * b,
                )
            }
        }
    )*);
    ($($a:ty)*) => (
        integer_sum_product!(@impls 0, 1,
                #[stable(feature = "iter_arith_traits", since = "1.12.0")],
                $($a)*);
        integer_sum_product!(@impls Wrapping(0), Wrapping(1),
                #[stable(feature = "wrapping_iter_arith", since = "1.14.0")],
                $(Wrapping<$a>)*);
    );
}

macro_rules! float_sum_product {
    ($($a:ident)*) => ($(
        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
        impl Sum for $a {
            fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
                iter.fold(
                    0.0,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a + b,
                )
            }
        }

        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
        impl Product for $a {
            fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
                iter.fold(
                    1.0,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a * b,
                )
            }
        }

        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
        impl<'a> Sum<&'a $a> for $a {
            fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
                iter.fold(
                    0.0,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a + b,
                )
            }
        }

        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
        impl<'a> Product<&'a $a> for $a {
            fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
                iter.fold(
                    1.0,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a * b,
                )
            }
        }
    )*)
}

integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
float_sum_product! { f32 f64 }

#[stable(feature = "iter_arith_traits_result", since = "1.16.0")]
impl<T, U, E> Sum<Result<U, E>> for Result<T, E>
where
    T: Sum<U>,
{
    /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further
    /// elements are taken, and the [`Err`] is returned. Should no [`Err`]
    /// occur, the sum of all elements is returned.
    ///
    /// # Examples
    ///
    /// This sums up every integer in a vector, rejecting the sum if a negative
    /// element is encountered:
    ///
    /// ```
    /// let v = vec![1, 2];
    /// let res: Result<i32, &'static str> = v.iter().map(|&x: &i32|
    ///     if x < 0 { Err("Negative element found") }
    ///     else { Ok(x) }
    /// ).sum();
    /// assert_eq!(res, Ok(3));
    /// ```
    fn sum<I>(iter: I) -> Result<T, E>
    where
        I: Iterator<Item = Result<U, E>>,
    {
        iter::process_results(iter, |i| i.sum())
    }
}

#[stable(feature = "iter_arith_traits_result", since = "1.16.0")]
impl<T, U, E> Product<Result<U, E>> for Result<T, E>
where
    T: Product<U>,
{
    /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further
    /// elements are taken, and the [`Err`] is returned. Should no [`Err`]
    /// occur, the product of all elements is returned.
    fn product<I>(iter: I) -> Result<T, E>
    where
        I: Iterator<Item = Result<U, E>>,
    {
        iter::process_results(iter, |i| i.product())
    }
}

#[stable(feature = "iter_arith_traits_option", since = "1.37.0")]
impl<T, U> Sum<Option<U>> for Option<T>
where
    T: Sum<U>,
{
    /// Takes each element in the [`Iterator`]: if it is a [`None`], no further
    /// elements are taken, and the [`None`] is returned. Should no [`None`]
    /// occur, the sum of all elements is returned.
    ///
    /// # Examples
    ///
    /// This sums up the position of the character 'a' in a vector of strings,
    /// if a word did not have the character 'a' the operation returns `None`:
    ///
    /// ```
    /// let words = vec!["have", "a", "great", "day"];
    /// let total: Option<usize> = words.iter().map(|w| w.find('a')).sum();
    /// assert_eq!(total, Some(5));
    /// ```
    fn sum<I>(iter: I) -> Option<T>
    where
        I: Iterator<Item = Option<U>>,
    {
        iter.map(|x| x.ok_or(())).sum::<Result<_, _>>().ok()
    }
}

#[stable(feature = "iter_arith_traits_option", since = "1.37.0")]
impl<T, U> Product<Option<U>> for Option<T>
where
    T: Product<U>,
{
    /// Takes each element in the [`Iterator`]: if it is a [`None`], no further
    /// elements are taken, and the [`None`] is returned. Should no [`None`]
    /// occur, the product of all elements is returned.
    fn product<I>(iter: I) -> Option<T>
    where
        I: Iterator<Item = Option<U>>,
    {
        iter.map(|x| x.ok_or(())).product::<Result<_, _>>().ok()
    }
}
<commit_msg>Rollup merge of #86389 - kpreid:sum, r=scottmcm<commit_after>use crate::iter;
use crate::num::Wrapping;

/// Trait to represent types that can be created by summing up an iterator.
///
/// This trait is used to implement [`Iterator::sum()`]. Types which implement
/// this trait can be generated by using the [`sum()`] method on an iterator.
/// Like [`FromIterator`], this trait should rarely be called directly.
///
/// [`sum()`]: Iterator::sum
/// [`FromIterator`]: iter::FromIterator
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
pub trait Sum<A = Self>: Sized {
    /// Method which takes an iterator and generates `Self` from the elements by
    /// "summing up" the items.
    #[stable(feature = "iter_arith_traits", since = "1.12.0")]
    fn sum<I: Iterator<Item = A>>(iter: I) -> Self;
}

/// Trait to represent types that can be created by multiplying elements of an
/// iterator.
///
/// This trait is used to implement [`Iterator::product()`]. Types which implement
/// this trait can be generated by using the [`product()`] method on an iterator.
/// Like [`FromIterator`], this trait should rarely be called directly.
///
/// [`product()`]: Iterator::product
/// [`FromIterator`]: iter::FromIterator
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
pub trait Product<A = Self>: Sized {
    /// Method which takes an iterator and generates `Self` from the elements by
    /// multiplying the items.
    #[stable(feature = "iter_arith_traits", since = "1.12.0")]
    fn product<I: Iterator<Item = A>>(iter: I) -> Self;
}

macro_rules! integer_sum_product {
    (@impls $zero:expr, $one:expr, #[$attr:meta], $($a:ty)*) => ($(
        #[$attr]
        impl Sum for $a {
            fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
                iter.fold(
                    $zero,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a + b,
                )
            }
        }

        #[$attr]
        impl Product for $a {
            fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
                iter.fold(
                    $one,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a * b,
                )
            }
        }

        #[$attr]
        impl<'a> Sum<&'a $a> for $a {
            fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
                iter.fold(
                    $zero,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a + b,
                )
            }
        }

        #[$attr]
        impl<'a> Product<&'a $a> for $a {
            fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
                iter.fold(
                    $one,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a * b,
                )
            }
        }
    )*);
    ($($a:ty)*) => (
        integer_sum_product!(@impls 0, 1,
                #[stable(feature = "iter_arith_traits", since = "1.12.0")],
                $($a)*);
        integer_sum_product!(@impls Wrapping(0), Wrapping(1),
                #[stable(feature = "wrapping_iter_arith", since = "1.14.0")],
                $(Wrapping<$a>)*);
    );
}

macro_rules! float_sum_product {
    ($($a:ident)*) => ($(
        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
        impl Sum for $a {
            fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
                iter.fold(
                    0.0,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a + b,
                )
            }
        }

        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
        impl Product for $a {
            fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
                iter.fold(
                    1.0,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a * b,
                )
            }
        }

        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
        impl<'a> Sum<&'a $a> for $a {
            fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
                iter.fold(
                    0.0,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a + b,
                )
            }
        }

        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
        impl<'a> Product<&'a $a> for $a {
            fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
                iter.fold(
                    1.0,
                    #[rustc_inherit_overflow_checks]
                    |a, b| a * b,
                )
            }
        }
    )*)
}

integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
float_sum_product! { f32 f64 }

#[stable(feature = "iter_arith_traits_result", since = "1.16.0")]
impl<T, U, E> Sum<Result<U, E>> for Result<T, E>
where
    T: Sum<U>,
{
    /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further
    /// elements are taken, and the [`Err`] is returned. Should no [`Err`]
    /// occur, the sum of all elements is returned.
    ///
    /// # Examples
    ///
    /// This sums up every integer in a vector, rejecting the sum if a negative
    /// element is encountered:
    ///
    /// ```
    /// let v = vec![1, 2];
    /// let res: Result<i32, &'static str> = v.iter().map(|&x: &i32|
    ///     if x < 0 { Err("Negative element found") }
    ///     else { Ok(x) }
    /// ).sum();
    /// assert_eq!(res, Ok(3));
    /// ```
    fn sum<I>(iter: I) -> Result<T, E>
    where
        I: Iterator<Item = Result<U, E>>,
    {
        iter::process_results(iter, |i| i.sum())
    }
}

#[stable(feature = "iter_arith_traits_result", since = "1.16.0")]
impl<T, U, E> Product<Result<U, E>> for Result<T, E>
where
    T: Product<U>,
{
    /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further
    /// elements are taken, and the [`Err`] is returned. Should no [`Err`]
    /// occur, the product of all elements is returned.
    fn product<I>(iter: I) -> Result<T, E>
    where
        I: Iterator<Item = Result<U, E>>,
    {
        iter::process_results(iter, |i| i.product())
    }
}

#[stable(feature = "iter_arith_traits_option", since = "1.37.0")]
impl<T, U> Sum<Option<U>> for Option<T>
where
    T: Sum<U>,
{
    /// Takes each element in the [`Iterator`]: if it is a [`None`], no further
    /// elements are taken, and the [`None`] is returned. Should no [`None`]
    /// occur, the sum of all elements is returned.
    ///
    /// # Examples
    ///
    /// This sums up the position of the character 'a' in a vector of strings,
    /// if a word did not have the character 'a' the operation returns `None`:
    ///
    /// ```
    /// let words = vec!["have", "a", "great", "day"];
    /// let total: Option<usize> = words.iter().map(|w| w.find('a')).sum();
    /// assert_eq!(total, Some(5));
    /// ```
    fn sum<I>(iter: I) -> Option<T>
    where
        I: Iterator<Item = Option<U>>,
    {
        iter.map(|x| x.ok_or(())).sum::<Result<_, _>>().ok()
    }
}

#[stable(feature = "iter_arith_traits_option", since = "1.37.0")]
impl<T, U> Product<Option<U>> for Option<T>
where
    T: Product<U>,
{
    /// Takes each element in the [`Iterator`]: if it is a [`None`], no further
    /// elements are taken, and the [`None`] is returned. Should no [`None`]
    /// occur, the product of all elements is returned.
    fn product<I>(iter: I) -> Option<T>
    where
        I: Iterator<Item = Option<U>>,
    {
        iter.map(|x| x.ok_or(())).product::<Result<_, _>>().ok()
    }
}
<|endoftext|>


<commit_before>use argon::board::position::Position;
use argon::board::color::StoneColor;
use argon::board::moves::Move;

#[test]
fn position_ok() {
    let m = Move::Play(Position::new(3, 3), StoneColor::Black);
    assert!(m.position().unwrap() == Position::new(3, 3));
}

#[test]
fn position_fail() {
    let m = Move::Pass(StoneColor::White);
    assert!(m.position().is_none());
}
<commit_msg>updated test to push travis build<commit_after>use argon::board::position::Position;
use argon::board::color::StoneColor;
use argon::board::moves::Move;

#[test]
fn position_ok() {
    let m = Move::Play(Position::new(3, 3), StoneColor::Black);
    assert!(m.position().unwrap() == Position::new(3, 3));
}

#[test]
fn position_fail() {
    let m = Move::Pass(StoneColor::White);
    assert!(m.position().is_none());
}

#[test]
fn color() {
    let m = Move::Pass(StoneColor::White);
    assert!(m.color() == StoneColor::White);
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std;
use gl;
use gl::types::{GLint, GLuint, GLsizei};
use stb_image::image;
use cgmath::vector::{Vector2};
use visualizer::shader::Shader;
use core::types::{Size2, MInt};

pub struct Texture {
    id: GLuint,
}

impl Texture {
    pub fn new(path: &Path) -> Texture {
        load_texture(path)
    }

    pub fn new_empty(size: Size2<MInt>) -> Texture {
        get_empty_texture(size)
    }

    pub fn enable(&self, shader: &Shader) {
        let basic_texture_loc = shader.get_uniform("basic_texture") as GLint;
        verify!(gl::Uniform1i(basic_texture_loc, 0));
        self.bind();
    }

    pub fn bind(&self) {
        verify!(gl::ActiveTexture(gl::TEXTURE0));
        verify!(gl::BindTexture(gl::TEXTURE_2D, self.id));
    }

    pub fn set_sub_image(
        &self,
        pos: Vector2<MInt>,
        size: Size2<MInt>,
        data: &Vec<u8>
    ) {
        let bytes_per_pixel = 4;
        let expected_data_length = size.w * size.h * bytes_per_pixel;
        assert_eq!(data.len(), expected_data_length as uint);
        let format = gl::RGBA;
        let level = 0;
        unsafe {
            verify!(gl::TexSubImage2D(
                gl::TEXTURE_2D,
                level,
                pos.x,
                pos.y,
                size.w,
                size.h,
                format,
                gl::UNSIGNED_BYTE,
                std::cast::transmute(data.get(0)),
            ));
        }
    }
}

fn load_image(path: &Path) -> image::Image<u8> {
    let str_path = match path.as_str() {
        Some(s) => s,
        None => fail!("Bad image path: {}", path.display()),
    };
    let load_result = image::load(str_path.to_owned());
    match load_result {
        image::ImageU8(image) => image,
        image::Error(message) => fail!("{}", message),
        _ => fail!("Unknown image format"),
    }
}

fn get_empty_texture(size: Size2<MInt>) -> Texture {
    let s = size.w;
    assert_eq!(size.w, size.h)
    let data = Vec::from_elem((s * s) as uint * 4, 0 as u8);
    let mut id = 0;
    unsafe {
        verify!(gl::GenTextures(1, &mut id))
    };
    verify!(gl::ActiveTexture(gl::TEXTURE0));
    verify!(gl::BindTexture(gl::TEXTURE_2D, id));
    let format = gl::RGBA;
    unsafe {
        let level = 0;
        let border = 0;
        verify!(gl::TexImage2D(
            gl::TEXTURE_2D,
            level,
            format as GLint,
            s,
            s,
            border,
            format,
            gl::UNSIGNED_BYTE,
            std::cast::transmute(data.get(0)),
        ));
    }
    verify!(gl::TexParameteri(gl::TEXTURE_2D,
        gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint));
    verify!(gl::TexParameteri(gl::TEXTURE_2D,
        gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint));
    Texture{id: id}
}

fn load_texture(path: &Path) -> Texture {
    let image = load_image(path);
    let mut id = 0;
    unsafe {
        verify!(gl::GenTextures(1, &mut id))
    };
    verify!(gl::ActiveTexture(gl::TEXTURE0));
    verify!(gl::BindTexture(gl::TEXTURE_2D, id));
    let format = match image.depth {
        4 => gl::RGBA,
        3 => gl::RGB,
        _ => fail!("wrong depth"),
    };
    unsafe {
        let level = 0;
        let border = 0;
        verify!(gl::TexImage2D(
            gl::TEXTURE_2D,
            level,
            format as GLint,
            image.width as GLsizei,
            image.height as GLsizei,
            border,
            format,
            gl::UNSIGNED_BYTE,
            std::cast::transmute(&image.data[0]),
        ));
    }
    verify!(gl::TexParameteri(gl::TEXTURE_2D,
        gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint));
    verify!(gl::TexParameteri(gl::TEXTURE_2D,
        gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint));
    verify!(gl::TexParameteri(gl::TEXTURE_2D,
        gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint));
    verify!(gl::TexParameteri(gl::TEXTURE_2D,
        gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint));
    Texture{id: id}
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>visualizer/texture.rs: Updated for latest rust-stb-image (~str -> &Path)<commit_after>// See LICENSE file for copyright and license details.

use std;
use gl;
use gl::types::{GLint, GLuint, GLsizei};
use stb_image::image;
use cgmath::vector::{Vector2};
use visualizer::shader::Shader;
use core::types::{Size2, MInt};

pub struct Texture {
    id: GLuint,
}

impl Texture {
    pub fn new(path: &Path) -> Texture {
        load_texture(path)
    }

    pub fn new_empty(size: Size2<MInt>) -> Texture {
        get_empty_texture(size)
    }

    pub fn enable(&self, shader: &Shader) {
        let basic_texture_loc = shader.get_uniform("basic_texture") as GLint;
        verify!(gl::Uniform1i(basic_texture_loc, 0));
        self.bind();
    }

    pub fn bind(&self) {
        verify!(gl::ActiveTexture(gl::TEXTURE0));
        verify!(gl::BindTexture(gl::TEXTURE_2D, self.id));
    }

    pub fn set_sub_image(
        &self,
        pos: Vector2<MInt>,
        size: Size2<MInt>,
        data: &Vec<u8>
    ) {
        let bytes_per_pixel = 4;
        let expected_data_length = size.w * size.h * bytes_per_pixel;
        assert_eq!(data.len(), expected_data_length as uint);
        let format = gl::RGBA;
        let level = 0;
        unsafe {
            verify!(gl::TexSubImage2D(
                gl::TEXTURE_2D,
                level,
                pos.x,
                pos.y,
                size.w,
                size.h,
                format,
                gl::UNSIGNED_BYTE,
                std::cast::transmute(data.get(0)),
            ));
        }
    }
}

fn load_image(path: &Path) -> image::Image<u8> {
    match image::load(path) {
        image::ImageU8(image) => image,
        image::Error(message) => fail!("{}", message),
        _ => fail!("Unknown image format"),
    }
}

fn get_empty_texture(size: Size2<MInt>) -> Texture {
    let s = size.w;
    assert_eq!(size.w, size.h)
    let data = Vec::from_elem((s * s) as uint * 4, 0 as u8);
    let mut id = 0;
    unsafe {
        verify!(gl::GenTextures(1, &mut id))
    };
    verify!(gl::ActiveTexture(gl::TEXTURE0));
    verify!(gl::BindTexture(gl::TEXTURE_2D, id));
    let format = gl::RGBA;
    unsafe {
        let level = 0;
        let border = 0;
        verify!(gl::TexImage2D(
            gl::TEXTURE_2D,
            level,
            format as GLint,
            s,
            s,
            border,
            format,
            gl::UNSIGNED_BYTE,
            std::cast::transmute(data.get(0)),
        ));
    }
    verify!(gl::TexParameteri(gl::TEXTURE_2D,
        gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint));
    verify!(gl::TexParameteri(gl::TEXTURE_2D,
        gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint));
    Texture{id: id}
}

fn load_texture(path: &Path) -> Texture {
    let image = load_image(path);
    let mut id = 0;
    unsafe {
        verify!(gl::GenTextures(1, &mut id))
    };
    verify!(gl::ActiveTexture(gl::TEXTURE0));
    verify!(gl::BindTexture(gl::TEXTURE_2D, id));
    let format = match image.depth {
        4 => gl::RGBA,
        3 => gl::RGB,
        _ => fail!("wrong depth"),
    };
    unsafe {
        let level = 0;
        let border = 0;
        verify!(gl::TexImage2D(
            gl::TEXTURE_2D,
            level,
            format as GLint,
            image.width as GLsizei,
            image.height as GLsizei,
            border,
            format,
            gl::UNSIGNED_BYTE,
            std::cast::transmute(&image.data[0]),
        ));
    }
    verify!(gl::TexParameteri(gl::TEXTURE_2D,
        gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint));
    verify!(gl::TexParameteri(gl::TEXTURE_2D,
        gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint));
    verify!(gl::TexParameteri(gl::TEXTURE_2D,
        gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint));
    verify!(gl::TexParameteri(gl::TEXTURE_2D,
        gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint));
    Texture{id: id}
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>