<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::collections::HashSet;
use std::collections::hash_map::RandomState;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;

use devicemapper::consts::SECTOR_SIZE;
use devicemapper::DM;
use devicemapper::{DataBlocks, Sectors, Segment};
use devicemapper::LinearDev;
use devicemapper::{ThinPoolDev, ThinPoolStatus, ThinPoolWorkingStatus};
use time::now;
use uuid::Uuid;
use serde_json;

use super::super::consts::IEC::Mi;
use super::super::engine::{Filesystem, HasName, HasUuid, Pool};
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::structures::Table;
use super::super::types::{FilesystemUuid, PoolUuid, RenameAction, Redundancy};

use super::blockdevmgr::BlockDevMgr;
use super::device::wipe_sectors;
use super::dmdevice::{FlexRole, ThinPoolRole, format_flex_name, format_thinpool_name};
use super::filesystem::{StratFilesystem, FilesystemStatus};
use super::mdv::MetadataVol;
use super::metadata::MIN_MDA_SECTORS;
use super::serde_structs::{FlexDevsSave, PoolSave, Recordable, ThinPoolDevSave};

const DATA_BLOCK_SIZE: Sectors = Sectors(2048);
const META_LOWATER: u64 = 512;
const DATA_LOWATER: DataBlocks = DataBlocks(512);

const INITIAL_META_SIZE: Sectors = Sectors(16 * Mi / SECTOR_SIZE as u64);
const INITIAL_DATA_SIZE: Sectors = Sectors(512 * Mi / SECTOR_SIZE as u64);
const INITIAL_MDV_SIZE: Sectors = Sectors(16 * Mi / SECTOR_SIZE as u64);

#[derive(Debug)]
pub struct StratPool {
    name: String,
    pool_uuid: PoolUuid,
    pub block_devs: BlockDevMgr,
    pub filesystems: Table<StratFilesystem>,
    redundancy: Redundancy,
    thin_pool: ThinPoolDev,
    mdv: MetadataVol,
}

impl StratPool {
    /// Initialize a Stratis Pool.
    /// 1. Initialize the block devices specified by paths.
    /// 2. Set up thinpool device to back filesystems.
    pub fn initialize(name: &str,
                      dm: &DM,
                      paths: &[&Path],
                      redundancy: Redundancy,
                      force: bool)
                      -> EngineResult<StratPool> {
        let pool_uuid = Uuid::new_v4();

        let mut block_mgr =
            try!(BlockDevMgr::initialize(&pool_uuid, paths, MIN_MDA_SECTORS, force));

        if block_mgr.avail_space() < StratPool::min_initial_size() {
            let avail_size = block_mgr.avail_space().bytes();
            try!(block_mgr.destroy_all());
            return Err(EngineError::Engine(ErrorEnum::Invalid,
                                           format!("Space on pool must be at least {} bytes, \
                                                   available space is only {} bytes",
                                                   StratPool::min_initial_size().bytes(),
                                                   avail_size)));

        }

        let meta_regions = block_mgr
            .alloc_space(INITIAL_META_SIZE)
            .expect("blockmgr must not fail, already checked for space");

        let data_regions = block_mgr
            .alloc_space(INITIAL_DATA_SIZE)
            .expect("blockmgr must not fail, already checked for space");

        let thinpool_dev =
            try!(StratPool::setup_thinpooldev(dm, &pool_uuid, meta_regions, data_regions));

        let mdv_regions = block_mgr
            .alloc_space(INITIAL_MDV_SIZE)
            .expect("blockmgr must not fail, already checked for space");
        let device_name = format_flex_name(&pool_uuid, FlexRole::MetadataVolume);
        let mdv_dev = try!(LinearDev::new(&device_name, dm, mdv_regions));
        let mdv = try!(MetadataVol::initialize(&pool_uuid, mdv_dev));

        let mut pool = StratPool {
            name: name.to_owned(),
            pool_uuid: pool_uuid,
            block_devs: block_mgr,
            filesystems: Table::new(),
            redundancy: redundancy,
            thin_pool: thinpool_dev,
            mdv: mdv,
        };

        try!(pool.write_metadata());

        Ok(pool)
    }

    /// Setup a thin pool device for this pool from the designated segments.
    // TODO: complicate this method by optionally checking whether the device
    // already exists.
    pub fn setup_thinpooldev(dm: &DM,
                             pool_uuid: &PoolUuid,
                             meta_segs: Vec<Segment>,
                             data_segs: Vec<Segment>)
                             -> EngineResult<ThinPoolDev> {
        let device_name = format_flex_name(pool_uuid, FlexRole::ThinMeta);
        let meta_dev = try!(LinearDev::new(&device_name, dm, meta_segs));

        // When constructing a thin-pool, Stratis reserves the first N
        // sectors on a block device by creating a linear device with a
        // starting offset. DM writes the super block in the first block.
        // DM requires this first block to be zeros when the meta data for
        // the thin-pool is initially created. If we don't zero the
        // superblock DM issue error messages because it triggers code paths
        // that are trying to re-adopt the device with the attributes that
        // have been passed.
        try!(wipe_sectors(&try!(meta_dev.devnode()), Sectors(0), INITIAL_META_SIZE));

        let device_name = format_flex_name(pool_uuid, FlexRole::ThinData);
        let data_dev = try!(LinearDev::new(&device_name, dm, data_segs));

        let device_name = format_thinpool_name(&pool_uuid, ThinPoolRole::Pool);
        // TODO Fix hard coded data blocksize and low water mark.
        Ok(try!(ThinPoolDev::new(&device_name,
                                 dm,
                                 try!(data_dev.size()),
                                 DATA_BLOCK_SIZE,
                                 DATA_LOWATER,
                                 meta_dev,
                                 data_dev)))
    }

    /// Minimum initial size for a pool.
    pub fn min_initial_size() -> Sectors {
        INITIAL_META_SIZE + INITIAL_DATA_SIZE + INITIAL_MDV_SIZE
    }

    // TODO: Check current time against global last updated, and use
    // alternate time value if earlier, as described in SWDD
    fn write_metadata(&mut self) -> EngineResult<()> {
        let data = try!(serde_json::to_string(&try!(self.record())));
        self.block_devs
            .save_state(&now().to_timespec(), data.as_bytes())
    }

    pub fn check(&mut self) -> () {
        let dm = DM::new().expect("Could not get DM handle");

        if let Err(e) = self.mdv.check() {
            error!("MDV error: {}", e);
            return;
        }

        let result = match self.thin_pool.status(&dm) {
            Ok(r) => r,
            Err(_) => {
                error!("Could not get thinpool status");
                // TODO: Take pool offline?
                return;
            }
        };

        match result {
            ThinPoolStatus::Good(wstatus, usage) => {
                match wstatus {
                    ThinPoolWorkingStatus::Good => {}
                    ThinPoolWorkingStatus::ReadOnly => {
                        // TODO: why is pool r/o and how do we get it
                        // rw again?
                    }
                    ThinPoolWorkingStatus::OutOfSpace => {
                        // TODO: Add more space if possible, or
                        // prevent further usage
                        // Should never happen -- we should be extending first!
                    }
                    ThinPoolWorkingStatus::NeedsCheck => {
                        // TODO: Take pool offline?
                        // TODO: run thin_check
                    }
                }

                if usage.used_meta > usage.total_meta - META_LOWATER {
                    // TODO: Extend meta device
                }

                if usage.used_data > usage.total_data - DATA_LOWATER {
                    // TODO: Extend data device
                }
            }
            ThinPoolStatus::Fail => {
                // TODO: Take pool offline?
                // TODO: Run thin_check
            }
        }

        for fs in &mut self.filesystems {
            match fs.check(&dm) {
                Ok(f_status) => {
                    if let FilesystemStatus::Failed = f_status {
                        // TODO: recover fs? (how?)
                    }
                }
                Err(_e) => error!("fs.check() failed"),
            }
        }
    }

    /// Teardown a pool.
    /// Take down the device mapper devices belonging to the pool.
    /// This method and destroy() must keep their DM teardown operations
    /// in sync.
    pub fn teardown(self) -> EngineResult<()> {
        // TODO: any necessary clean up of filesystems
        if !self.filesystems.is_empty() {
            return Err(EngineError::Engine(ErrorEnum::Busy,
                                           format!("May be unsynced files on device.")));
        }
        let dm = try!(DM::new());
        try!(self.thin_pool.teardown(&dm));
        try!(self.mdv.teardown(&dm));
        Ok(())
    }
}

impl Pool for StratPool {
    fn create_filesystems<'a, 'b>(&'a mut self,
                                  specs: &[&'b str])
                                  -> EngineResult<Vec<(&'b str, FilesystemUuid)>> {
        let names: HashSet<_, RandomState> = HashSet::from_iter(specs);
        for name in names.iter() {
            if self.filesystems.contains_name(name) {
                return Err(EngineError::Engine(ErrorEnum::AlreadyExists, name.to_string()));
            }
        }

        // TODO: Roll back on filesystem initialization failure.
        let dm = try!(DM::new());
        let mut result = Vec::new();
        for name in names.iter() {
            let uuid = Uuid::new_v4();
            let new_filesystem = try!(StratFilesystem::initialize(&self.pool_uuid,
                                                                  uuid,
                                                                  name,
                                                                  &dm,
                                                                  &mut self.thin_pool));
            try!(self.mdv.save_fs(&new_filesystem));
            self.filesystems.insert(new_filesystem);
            result.push((**name, uuid));
        }

        Ok(result)
    }

    fn add_blockdevs(&mut self, paths: &[&Path], force: bool) -> EngineResult<Vec<PathBuf>> {
        let bdev_paths = try!(self.block_devs.add(&self.pool_uuid, paths, force));
        try!(self.write_metadata());
        Ok(bdev_paths)
    }

    fn destroy(self) -> EngineResult<()> {
        // Ensure that DM teardown operations in this method are in sync
        // with operations in teardown().
        let dm = try!(DM::new());
        try!(self.thin_pool.teardown(&dm));
        try!(self.mdv.teardown(&dm));
        try!(self.block_devs.destroy_all());

        Ok(())
    }

    fn destroy_filesystems<'a, 'b>(&'a mut self,
                                   fs_uuids: &[&'b FilesystemUuid])
                                   -> EngineResult<Vec<&'b FilesystemUuid>> {
        for fsid in fs_uuids {
            try!(self.mdv.rm_fs(fsid));
        }
        destroy_filesystems!{self; fs_uuids}
    }

    fn rename_filesystem(&mut self,
                         uuid: &FilesystemUuid,
                         new_name: &str)
                         -> EngineResult<RenameAction> {
        rename_filesystem!{self; uuid; new_name}
    }

    fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    fn get_filesystem(&mut self, uuid: &FilesystemUuid) -> Option<&mut Filesystem> {
        get_filesystem!(self; uuid)
    }
}

impl HasUuid for StratPool {
    fn uuid(&self) -> &PoolUuid {
        &self.pool_uuid
    }
}

impl HasName for StratPool {
    fn name(&self) -> &str {
        &self.name
    }
}

impl Recordable<PoolSave> for StratPool {
    fn record(&self) -> EngineResult<PoolSave> {

        let mapper = |seg: &Segment| -> EngineResult<(Uuid, Sectors, Sectors)> {
            let bd = try!(self.block_devs
                     .get_by_device(seg.device)
                     .ok_or(EngineError::Engine(ErrorEnum::NotFound,
                                                format!("no block device found for device {:?}",
                                                        seg.device))));
            Ok((*bd.uuid(), seg.start, seg.length))
        };

        let meta_dev = try!(self.mdv.segments().iter().map(&mapper).collect());

        let thin_meta_dev = try!(self.thin_pool
                                     .meta_dev()
                                     .segments()
                                     .iter()
                                     .map(&mapper)
                                     .collect());

        let thin_data_dev = try!(self.thin_pool
                                     .data_dev()
                                     .segments()
                                     .iter()
                                     .map(&mapper)
                                     .collect());

        Ok(PoolSave {
               name: self.name.clone(),
               block_devs: try!(self.block_devs.record()),
               flex_devs: FlexDevsSave {
                   meta_dev: meta_dev,
                   thin_meta_dev: thin_meta_dev,
                   thin_data_dev: thin_data_dev,
               },
               thinpool_dev: ThinPoolDevSave { data_block_size: self.thin_pool.data_block_size() },
           })
    }
}
<commit_msg>Add a setup_mdv() method<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::collections::HashSet;
use std::collections::hash_map::RandomState;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;

use devicemapper::consts::SECTOR_SIZE;
use devicemapper::DM;
use devicemapper::{DataBlocks, Sectors, Segment};
use devicemapper::LinearDev;
use devicemapper::{ThinPoolDev, ThinPoolStatus, ThinPoolWorkingStatus};
use time::now;
use uuid::Uuid;
use serde_json;

use super::super::consts::IEC::Mi;
use super::super::engine::{Filesystem, HasName, HasUuid, Pool};
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::structures::Table;
use super::super::types::{FilesystemUuid, PoolUuid, RenameAction, Redundancy};

use super::blockdevmgr::BlockDevMgr;
use super::device::wipe_sectors;
use super::dmdevice::{FlexRole, ThinPoolRole, format_flex_name, format_thinpool_name};
use super::filesystem::{StratFilesystem, FilesystemStatus};
use super::mdv::MetadataVol;
use super::metadata::MIN_MDA_SECTORS;
use super::serde_structs::{FlexDevsSave, PoolSave, Recordable, ThinPoolDevSave};

const DATA_BLOCK_SIZE: Sectors = Sectors(2048);
const META_LOWATER: u64 = 512;
const DATA_LOWATER: DataBlocks = DataBlocks(512);

const INITIAL_META_SIZE: Sectors = Sectors(16 * Mi / SECTOR_SIZE as u64);
const INITIAL_DATA_SIZE: Sectors = Sectors(512 * Mi / SECTOR_SIZE as u64);
const INITIAL_MDV_SIZE: Sectors = Sectors(16 * Mi / SECTOR_SIZE as u64);

#[derive(Debug)]
pub struct StratPool {
    name: String,
    pool_uuid: PoolUuid,
    pub block_devs: BlockDevMgr,
    pub filesystems: Table<StratFilesystem>,
    redundancy: Redundancy,
    thin_pool: ThinPoolDev,
    mdv: MetadataVol,
}

impl StratPool {
    /// Initialize a Stratis Pool.
    /// 1. Initialize the block devices specified by paths.
    /// 2. Set up thinpool device to back filesystems.
    pub fn initialize(name: &str,
                      dm: &DM,
                      paths: &[&Path],
                      redundancy: Redundancy,
                      force: bool)
                      -> EngineResult<StratPool> {
        let pool_uuid = Uuid::new_v4();

        let mut block_mgr =
            try!(BlockDevMgr::initialize(&pool_uuid, paths, MIN_MDA_SECTORS, force));

        if block_mgr.avail_space() < StratPool::min_initial_size() {
            let avail_size = block_mgr.avail_space().bytes();
            try!(block_mgr.destroy_all());
            return Err(EngineError::Engine(ErrorEnum::Invalid,
                                           format!("Space on pool must be at least {} bytes, \
                                                   available space is only {} bytes",
                                                   StratPool::min_initial_size().bytes(),
                                                   avail_size)));

        }

        let meta_regions = block_mgr
            .alloc_space(INITIAL_META_SIZE)
            .expect("blockmgr must not fail, already checked for space");

        let data_regions = block_mgr
            .alloc_space(INITIAL_DATA_SIZE)
            .expect("blockmgr must not fail, already checked for space");

        let thinpool_dev =
            try!(StratPool::setup_thinpooldev(dm, &pool_uuid, meta_regions, data_regions));

        let mdv_regions = block_mgr
            .alloc_space(INITIAL_MDV_SIZE)
            .expect("blockmgr must not fail, already checked for space");

        let mdv = try!(StratPool::setup_mdv(dm, &pool_uuid, mdv_regions));

        let mut pool = StratPool {
            name: name.to_owned(),
            pool_uuid: pool_uuid,
            block_devs: block_mgr,
            filesystems: Table::new(),
            redundancy: redundancy,
            thin_pool: thinpool_dev,
            mdv: mdv,
        };

        try!(pool.write_metadata());

        Ok(pool)
    }

    /// Setup a thin pool device for this pool from the designated segments.
    // TODO: complicate this method by optionally checking whether the device
    // already exists.
    pub fn setup_thinpooldev(dm: &DM,
                             pool_uuid: &PoolUuid,
                             meta_segs: Vec<Segment>,
                             data_segs: Vec<Segment>)
                             -> EngineResult<ThinPoolDev> {
        let device_name = format_flex_name(pool_uuid, FlexRole::ThinMeta);
        let meta_dev = try!(LinearDev::new(&device_name, dm, meta_segs));

        // When constructing a thin-pool, Stratis reserves the first N
        // sectors on a block device by creating a linear device with a
        // starting offset. DM writes the super block in the first block.
        // DM requires this first block to be zeros when the meta data for
        // the thin-pool is initially created. If we don't zero the
        // superblock DM issue error messages because it triggers code paths
        // that are trying to re-adopt the device with the attributes that
        // have been passed.
        try!(wipe_sectors(&try!(meta_dev.devnode()), Sectors(0), INITIAL_META_SIZE));

        let device_name = format_flex_name(pool_uuid, FlexRole::ThinData);
        let data_dev = try!(LinearDev::new(&device_name, dm, data_segs));

        let device_name = format_thinpool_name(&pool_uuid, ThinPoolRole::Pool);
        // TODO Fix hard coded data blocksize and low water mark.
        Ok(try!(ThinPoolDev::new(&device_name,
                                 dm,
                                 try!(data_dev.size()),
                                 DATA_BLOCK_SIZE,
                                 DATA_LOWATER,
                                 meta_dev,
                                 data_dev)))
    }

    pub fn setup_mdv(dm: &DM,
                     pool_uuid: &PoolUuid,
                     segs: Vec<Segment>)
                     -> EngineResult<MetadataVol> {
        let device_name = format_flex_name(pool_uuid, FlexRole::MetadataVolume);
        let mdv_dev = try!(LinearDev::new(&device_name, dm, segs));
        let mdv = try!(MetadataVol::initialize(&pool_uuid, mdv_dev));
        Ok(mdv)
    }

    /// Minimum initial size for a pool.
    pub fn min_initial_size() -> Sectors {
        INITIAL_META_SIZE + INITIAL_DATA_SIZE + INITIAL_MDV_SIZE
    }

    // TODO: Check current time against global last updated, and use
    // alternate time value if earlier, as described in SWDD
    fn write_metadata(&mut self) -> EngineResult<()> {
        let data = try!(serde_json::to_string(&try!(self.record())));
        self.block_devs
            .save_state(&now().to_timespec(), data.as_bytes())
    }

    pub fn check(&mut self) -> () {
        let dm = DM::new().expect("Could not get DM handle");

        if let Err(e) = self.mdv.check() {
            error!("MDV error: {}", e);
            return;
        }

        let result = match self.thin_pool.status(&dm) {
            Ok(r) => r,
            Err(_) => {
                error!("Could not get thinpool status");
                // TODO: Take pool offline?
                return;
            }
        };

        match result {
            ThinPoolStatus::Good(wstatus, usage) => {
                match wstatus {
                    ThinPoolWorkingStatus::Good => {}
                    ThinPoolWorkingStatus::ReadOnly => {
                        // TODO: why is pool r/o and how do we get it
                        // rw again?
                    }
                    ThinPoolWorkingStatus::OutOfSpace => {
                        // TODO: Add more space if possible, or
                        // prevent further usage
                        // Should never happen -- we should be extending first!
                    }
                    ThinPoolWorkingStatus::NeedsCheck => {
                        // TODO: Take pool offline?
                        // TODO: run thin_check
                    }
                }

                if usage.used_meta > usage.total_meta - META_LOWATER {
                    // TODO: Extend meta device
                }

                if usage.used_data > usage.total_data - DATA_LOWATER {
                    // TODO: Extend data device
                }
            }
            ThinPoolStatus::Fail => {
                // TODO: Take pool offline?
                // TODO: Run thin_check
            }
        }

        for fs in &mut self.filesystems {
            match fs.check(&dm) {
                Ok(f_status) => {
                    if let FilesystemStatus::Failed = f_status {
                        // TODO: recover fs? (how?)
                    }
                }
                Err(_e) => error!("fs.check() failed"),
            }
        }
    }

    /// Teardown a pool.
    /// Take down the device mapper devices belonging to the pool.
    /// This method and destroy() must keep their DM teardown operations
    /// in sync.
    pub fn teardown(self) -> EngineResult<()> {
        // TODO: any necessary clean up of filesystems
        if !self.filesystems.is_empty() {
            return Err(EngineError::Engine(ErrorEnum::Busy,
                                           format!("May be unsynced files on device.")));
        }
        let dm = try!(DM::new());
        try!(self.thin_pool.teardown(&dm));
        try!(self.mdv.teardown(&dm));
        Ok(())
    }
}

impl Pool for StratPool {
    fn create_filesystems<'a, 'b>(&'a mut self,
                                  specs: &[&'b str])
                                  -> EngineResult<Vec<(&'b str, FilesystemUuid)>> {
        let names: HashSet<_, RandomState> = HashSet::from_iter(specs);
        for name in names.iter() {
            if self.filesystems.contains_name(name) {
                return Err(EngineError::Engine(ErrorEnum::AlreadyExists, name.to_string()));
            }
        }

        // TODO: Roll back on filesystem initialization failure.
        let dm = try!(DM::new());
        let mut result = Vec::new();
        for name in names.iter() {
            let uuid = Uuid::new_v4();
            let new_filesystem = try!(StratFilesystem::initialize(&self.pool_uuid,
                                                                  uuid,
                                                                  name,
                                                                  &dm,
                                                                  &mut self.thin_pool));
            try!(self.mdv.save_fs(&new_filesystem));
            self.filesystems.insert(new_filesystem);
            result.push((**name, uuid));
        }

        Ok(result)
    }

    fn add_blockdevs(&mut self, paths: &[&Path], force: bool) -> EngineResult<Vec<PathBuf>> {
        let bdev_paths = try!(self.block_devs.add(&self.pool_uuid, paths, force));
        try!(self.write_metadata());
        Ok(bdev_paths)
    }

    fn destroy(self) -> EngineResult<()> {
        // Ensure that DM teardown operations in this method are in sync
        // with operations in teardown().
        let dm = try!(DM::new());
        try!(self.thin_pool.teardown(&dm));
        try!(self.mdv.teardown(&dm));
        try!(self.block_devs.destroy_all());

        Ok(())
    }

    fn destroy_filesystems<'a, 'b>(&'a mut self,
                                   fs_uuids: &[&'b FilesystemUuid])
                                   -> EngineResult<Vec<&'b FilesystemUuid>> {
        for fsid in fs_uuids {
            try!(self.mdv.rm_fs(fsid));
        }
        destroy_filesystems!{self; fs_uuids}
    }

    fn rename_filesystem(&mut self,
                         uuid: &FilesystemUuid,
                         new_name: &str)
                         -> EngineResult<RenameAction> {
        rename_filesystem!{self; uuid; new_name}
    }

    fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    fn get_filesystem(&mut self, uuid: &FilesystemUuid) -> Option<&mut Filesystem> {
        get_filesystem!(self; uuid)
    }
}

impl HasUuid for StratPool {
    fn uuid(&self) -> &PoolUuid {
        &self.pool_uuid
    }
}

impl HasName for StratPool {
    fn name(&self) -> &str {
        &self.name
    }
}

impl Recordable<PoolSave> for StratPool {
    fn record(&self) -> EngineResult<PoolSave> {

        let mapper = |seg: &Segment| -> EngineResult<(Uuid, Sectors, Sectors)> {
            let bd = try!(self.block_devs
                     .get_by_device(seg.device)
                     .ok_or(EngineError::Engine(ErrorEnum::NotFound,
                                                format!("no block device found for device {:?}",
                                                        seg.device))));
            Ok((*bd.uuid(), seg.start, seg.length))
        };

        let meta_dev = try!(self.mdv.segments().iter().map(&mapper).collect());

        let thin_meta_dev = try!(self.thin_pool
                                     .meta_dev()
                                     .segments()
                                     .iter()
                                     .map(&mapper)
                                     .collect());

        let thin_data_dev = try!(self.thin_pool
                                     .data_dev()
                                     .segments()
                                     .iter()
                                     .map(&mapper)
                                     .collect());

        Ok(PoolSave {
               name: self.name.clone(),
               block_devs: try!(self.block_devs.record()),
               flex_devs: FlexDevsSave {
                   meta_dev: meta_dev,
                   thin_meta_dev: thin_meta_dev,
                   thin_data_dev: thin_data_dev,
               },
               thinpool_dev: ThinPoolDevSave { data_block_size: self.thin_pool.data_block_size() },
           })
    }
}
<|endoftext|>


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

/// Utilities to support Stratis.

use std::path::Path;
use std::process::Command;

use uuid::Uuid;

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

/// Create a filesystem on devnode.
pub fn create_fs(devnode: &Path, uuid: Uuid) -> EngineResult<()> {
    if Command::new("mkfs.xfs")
           .arg("-f")
           .arg("-q")
           .arg(&devnode)
           .arg("-m")
           .arg(format!("uuid={}", uuid))
           .status()?
           .success() {
        Ok(())
    } else {
        let err_msg = format!("Failed to create new filesystem at {:?}", devnode);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}

/// Use the xfs_growfs command to expand a filesystem mounted at the given
/// mount point.
pub fn xfs_growfs(mount_point: &Path) -> EngineResult<()> {
    if Command::new("xfs_growfs")
           .arg(mount_point)
           .arg("-d")
           .status()?
           .success() {
        Ok(())
    } else {
        let err_msg = format!("Failed to expand filesystem {:?}", mount_point);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}

/// Set a new UUID for filesystem on the devnode.
pub fn set_uuid(devnode: &Path, uuid: Uuid) -> EngineResult<()> {
    if Command::new("xfs_admin")
           .arg("-U")
           .arg(format!("{}", uuid))
           .arg(&devnode)
           .status()?
           .success() {
        Ok(())
    } else {
        let err_msg = format!("Failed to set UUID for filesystem at {:?}", devnode);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}
<commit_msg>Reduce spurious test output<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

/// Utilities to support Stratis.

use std::path::Path;
use std::process::Command;

use uuid::Uuid;

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

/// Create a filesystem on devnode.
pub fn create_fs(devnode: &Path, uuid: Uuid) -> EngineResult<()> {
    if Command::new("mkfs.xfs")
           .arg("-f")
           .arg("-q")
           .arg(&devnode)
           .arg("-m")
           .arg(format!("uuid={}", uuid))
           .status()?
           .success() {
        Ok(())
    } else {
        let err_msg = format!("Failed to create new filesystem at {:?}", devnode);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}

/// Use the xfs_growfs command to expand a filesystem mounted at the given
/// mount point.
pub fn xfs_growfs(mount_point: &Path) -> EngineResult<()> {

    let result = Command::new("xfs_growfs")
        .arg(mount_point)
        .arg("-d")
        .output()?;

    if result.status.success() {
        Ok(())
    } else {
        let std_out_txt = String::from_utf8_lossy(&result.stdout);
        let std_err_txt = String::from_utf8_lossy(&result.stderr);
        let err_msg = format!("Failed to expand filesystem {:?} stdout: {} stderr: {}",
                              mount_point,
                              std_out_txt,
                              std_err_txt);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}

/// Set a new UUID for filesystem on the devnode.
pub fn set_uuid(devnode: &Path, uuid: Uuid) -> EngineResult<()> {

    let result = Command::new("xfs_admin")
        .arg("-U")
        .arg(format!("{}", uuid))
        .arg(&devnode)
        .output()?;

    if result.status.success() {
        Ok(())
    } else {
        let std_out_txt = String::from_utf8_lossy(&result.stdout);
        let std_err_txt = String::from_utf8_lossy(&result.stderr);
        let err_msg = format!("Failed to set UUID for filesystem {:?} stdout: {} stderr: {}",
                              devnode,
                              std_out_txt,
                              std_err_txt);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}
<|endoftext|>


<commit_before>//! A CLI tool for inspecting the contents of a DICOM file.
//! Despite the name, this tool may have a different interface and output
//! from other `dcmdump` tools, and does not aim to make a drop-in
//! replacement.
//!
//! Usage:
//!
//! ```none
//! dcmdump <file.dcm>
//! ```
use dicom::core::dictionary::{DataDictionary, DictionaryEntry};
use dicom::core::header::Header;
use dicom::core::value::{PrimitiveValue, Value as DicomValue};
use dicom::core::VR;
use dicom::object::mem::{InMemDicomObject, InMemElement};
use dicom::object::{open_file, DefaultDicomObject, FileMetaTable, StandardDataDictionary};

use term_size;

use std::borrow::Cow;
use std::io::{stdout, ErrorKind, Result as IoResult, Write};

type DynResult<T> = Result<T, Box<dyn std::error::Error>>;

fn main() -> DynResult<()> {
    let filename = ::std::env::args()
        .nth(1)
        .expect("Missing path to DICOM file");

    let obj = open_file(filename)?;

    match dump_file(obj) {
        Err(ref e) if e.kind() == ErrorKind::BrokenPipe => {
            Ok(()) // handle broken pipe separately with a no-op
        }
        Err(e) => Err(e.into()), // raise other errors
        _ => Ok(()),             // all good
    }
}

fn dump_file(obj: DefaultDicomObject) -> IoResult<()> {
    let mut to = stdout();
    write!(to, "# Dicom-File-Format\n\n")?;

    let meta = obj.meta();

    let width = if let Some((width, _)) = term_size::dimensions() {
        width as u32
    } else {
        48
    };

    meta_dump(&mut to, &meta, width)?;

    println!("{:-<46}", "");

    dump(&mut to, &obj, width, 0)?;

    Ok(())
}

fn meta_dump<W>(to: &mut W, meta: &FileMetaTable, width: u32) -> IoResult<()>
where
    W: ?Sized + Write,
{
    writeln!(
        to,
        "Media Storage SOP Class UID: {}",
        meta.media_storage_sop_class_uid
    )?;
    writeln!(
        to,
        "Media Storage SOP Instance UID: {}",
        meta.media_storage_sop_instance_uid
    )?;
    writeln!(to, "Transfer Syntax: {}", meta.transfer_syntax)?;
    writeln!(to, "Implementation Class UID: {}", meta.transfer_syntax)?;

    if let Some(v) = meta.implementation_version_name.as_ref() {
        writeln!(to, "Implementation version name: {}", v)?;
    }
    if let Some(v) = meta.source_application_entity_title.as_ref() {
        writeln!(to, "Source Application Entity Title: {}", v)?;
    }

    if let Some(v) = meta.sending_application_entity_title.as_ref() {
        writeln!(to, "Sending Application Entity Title: {}", v)?;
    }

    if let Some(v) = meta.receiving_application_entity_title.as_ref() {
        writeln!(to, "Receiving Application Entity Title: {}", v)?;
    }

    if let Some(v) = meta.private_information_creator_uid.as_ref() {
        writeln!(to, "Private Information Creator UID: {}", v)?;
    }

    if let Some(v) = meta.private_information.as_ref() {
        writeln!(
            to,
            "Private Information: {}",
            format_value_list(v.iter().map(|n| format!("{:#x}", n)), width, false)
        )?;
    }

    writeln!(to)?;
    Ok(())
}

fn dump<W, D>(to: &mut W, obj: &InMemDicomObject<D>, width: u32, depth: u32) -> IoResult<()>
where
    W: ?Sized + Write,
    D: DataDictionary,
{
    for elem in obj {
        dump_element(&mut *to, &elem, width, depth)?;
    }

    Ok(())
}

fn dump_element<W, D>(to: &mut W, elem: &InMemElement<D>, width: u32, depth: u32) -> IoResult<()>
where
    W: ?Sized + Write,
    D: DataDictionary,
{
    let indent = vec![b' '; (depth * 2) as usize];
    let tag_alias = StandardDataDictionary
        .by_tag(elem.tag())
        .map(DictionaryEntry::alias)
        .unwrap_or("«Unknown Attribute»");
    to.write_all(&indent)?;
    let vm = match elem.vr() {
        VR::OB | VR::OW | VR::UN => 1,
        _ => elem.value().multiplicity(),
    };

    match elem.value() {
        DicomValue::Sequence { items, .. } => {
            writeln!(
                to,
                "{} {:35} {} ({} Item{})",
                elem.tag(),
                tag_alias,
                elem.vr(),
                vm,
                if vm == 1 { "" } else { "s" },
            )?;
            for item in items {
                dump_item(&mut *to, item, width, depth + 2)?;
            }
            to.write_all(&indent)?;
            writeln!(to, "(FFFE, E0DD) SequenceDelimitationItem",)?;
        }
        DicomValue::PixelSequence {
            fragments,
            offset_table,
        } => {
            // write pixel sequence start line
            let vr = elem.vr();
            let num_items = 1 + fragments.len();
            writeln!(
                to,
                "{} PixelData {:25} {} (PixelSequence, {} Item{})",
                elem.tag(),
                "",
                vr,
                num_items,
                if num_items == 1 { "" } else { "s" },
            )?;

            // write offset table
            let byte_len = offset_table.len();
            writeln!(
                to,
                "  (FFFE,E000) pi ({:>3} bytes, 1 Item): {:48}",
                byte_len,
                item_value_summary(&offset_table, width.saturating_sub(42 + depth * 2)),
            )?;

            // write compressed fragments
            for fragment in fragments {
                let byte_len = fragment.len();
                writeln!(
                    to,
                    "  (FFFE,E000) pi ({:>3} bytes, 1 Item): {:48}",
                    byte_len,
                    item_value_summary(&fragment, width.saturating_sub(42 + depth * 2)),
                )?;
            }
        }
        DicomValue::Primitive(value) => {
            let vr = elem.vr();
            let byte_len = value.calculate_byte_len();
            writeln!(
                to,
                "{} {:35} {} ({},{:>3} bytes): {}",
                elem.tag(),
                tag_alias,
                vr,
                vm,
                byte_len,
                value_summary(&value, vr, width.saturating_sub(68 + depth * 2)),
            )?;
        }
    }

    Ok(())
}

fn dump_item<W, D>(to: &mut W, item: &InMemDicomObject<D>, width: u32, depth: u32) -> IoResult<()>
where
    W: ?Sized + Write,
    D: DataDictionary,
{
    let indent: String = std::iter::repeat(' ').take((depth * 2) as usize).collect();
    writeln!(to, "{}(FFFE,E000) na Item", indent)?;
    dump(to, item, width, depth + 1)?;
    writeln!(to, "{}(FFFE,E00D) ItemDelimitationItem", indent,)?;
    Ok(())
}

fn value_summary(value: &PrimitiveValue, vr: VR, max_characters: u32) -> Cow<str> {
    use PrimitiveValue::*;
    match (value, vr) {
        (F32(values), _) => format_value_list(values, max_characters, false).into(),
        (F64(values), _) => format_value_list(values, max_characters, false).into(),
        (I32(values), _) => format_value_list(values, max_characters, false).into(),
        (I64(values), _) => format_value_list(values, max_characters, false).into(),
        (U32(values), _) => format_value_list(values, max_characters, false).into(),
        (U64(values), _) => format_value_list(values, max_characters, false).into(),
        (I16(values), _) => format_value_list(values, max_characters, false).into(),
        (U16(values), VR::OW) => format_value_list(
            values.into_iter().map(|n| format!("{:02X}", n)),
            max_characters,
            false,
        )
        .into(),
        (U16(values), _) => format_value_list(values, max_characters, false).into(),
        (U8(values), VR::OB) | (U8(values), VR::UN) => format_value_list(
            values.into_iter().map(|n| format!("{:02X}", n)),
            max_characters,
            false,
        )
        .into(),
        (U8(values), _) => format_value_list(values, max_characters, false).into(),
        (Tags(values), _) => format_value_list(values, max_characters, false).into(),
        (Strs(values), _) => format_value_list(values, max_characters, true).into(),
        (Date(values), _) => format_value_list(values, max_characters, true).into(),
        (Time(values), _) => format_value_list(values, max_characters, true).into(),
        (DateTime(values), _) => format_value_list(values, max_characters, true).into(),
        (Str(value), _) => cut_str(&format!("\"{}\"", value), max_characters)
            .into_owned()
            .into(),
        (Empty, _) => "".into(),
    }
}

fn item_value_summary(data: &[u8], max_characters: u32) -> String {
    format_value_list(
        data.iter().map(|n| format!("{:02X}", n)),
        max_characters,
        false,
    )
}

fn format_value_list<I>(values: I, max_characters: u32, quoted: bool) -> String
where
    I: IntoIterator,
    I::IntoIter: ExactSizeIterator,
    I::Item: std::fmt::Display,
{
    use itertools::Itertools;
    let values = values.into_iter();
    let len = values.len();
    let mut pieces = values.take(64).map(|piece| {
        if quoted {
            format!("\"{}\"", piece)
        } else {
            piece.to_string()
        }
    });
    let mut pieces = pieces.join(", ");
    if len > 1 {
        pieces = format!("[{}]", pieces);
    }
    cut_str(&pieces, max_characters).into_owned()
}

fn cut_str(s: &str, max_characters: u32) -> Cow<str> {
    let max = (max_characters.saturating_sub(3)) as usize;
    if s.len() > max {
        format!("{}...", &s[..max]).into()
    } else {
        s.into()
    }
}
<commit_msg>[dcmdump] fix and improve file meta table output<commit_after>//! A CLI tool for inspecting the contents of a DICOM file.
//! Despite the name, this tool may have a different interface and output
//! from other `dcmdump` tools, and does not aim to make a drop-in
//! replacement.
//!
//! Usage:
//!
//! ```none
//! dcmdump <file.dcm>
//! ```
use dicom::core::dictionary::{DataDictionary, DictionaryEntry};
use dicom::core::header::Header;
use dicom::core::value::{PrimitiveValue, Value as DicomValue};
use dicom::core::VR;
use dicom::object::mem::{InMemDicomObject, InMemElement};
use dicom::object::{open_file, DefaultDicomObject, FileMetaTable, StandardDataDictionary};
use dicom::encoding::transfer_syntax::TransferSyntaxIndex;
use dicom::transfer_syntax::TransferSyntaxRegistry;

use term_size;

use std::borrow::Cow;
use std::io::{stdout, ErrorKind, Result as IoResult, Write};

type DynResult<T> = Result<T, Box<dyn std::error::Error>>;

fn main() {
    run().unwrap_or_else(|e| {
        eprintln!("{:#}", e);
    });
}

fn run() -> DynResult<()> {
    let filename = ::std::env::args()
        .nth(1)
        .expect("Missing path to DICOM file");

    let obj = open_file(filename)?;

    match dump_file(obj) {
        Err(ref e) if e.kind() == ErrorKind::BrokenPipe => {
            Ok(()) // handle broken pipe separately with a no-op
        }
        Err(e) => Err(e.into()), // raise other errors
        _ => Ok(()),             // all good
    }
}

fn dump_file(obj: DefaultDicomObject) -> IoResult<()> {
    let mut to = stdout();
    write!(to, "# Dicom-File-Format\n\n")?;

    let meta = obj.meta();

    let width = if let Some((width, _)) = term_size::dimensions() {
        width as u32
    } else {
        48
    };

    meta_dump(&mut to, &meta, width)?;

    println!("{:-<46}", "");

    dump(&mut to, &obj, width, 0)?;

    Ok(())
}

fn meta_dump<W>(to: &mut W, meta: &FileMetaTable, width: u32) -> IoResult<()>
where
    W: ?Sized + Write,
{
    writeln!(
        to,
        "Media Storage SOP Class UID: {}",
        meta.media_storage_sop_class_uid
    )?;
    writeln!(
        to,
        "Media Storage SOP Instance UID: {}",
        meta.media_storage_sop_instance_uid
    )?;
    if let Some(ts) = TransferSyntaxRegistry.get(&meta.transfer_syntax) {
        writeln!(to, "Transfer Syntax: {} ({})", ts.uid(), ts.name())?;
    } else {
        writeln!(to, "Transfer Syntax: {} («UNKNOWN»)", meta.transfer_syntax)?;
    }
    writeln!(to, "Implementation Class UID: {}", meta.implementation_class_uid)?;

    if let Some(v) = meta.implementation_version_name.as_ref() {
        writeln!(to, "Implementation version name: {}", v)?;
    }
    if let Some(v) = meta.source_application_entity_title.as_ref() {
        writeln!(to, "Source Application Entity Title: {}", v)?;
    }

    if let Some(v) = meta.sending_application_entity_title.as_ref() {
        writeln!(to, "Sending Application Entity Title: {}", v)?;
    }

    if let Some(v) = meta.receiving_application_entity_title.as_ref() {
        writeln!(to, "Receiving Application Entity Title: {}", v)?;
    }

    if let Some(v) = meta.private_information_creator_uid.as_ref() {
        writeln!(to, "Private Information Creator UID: {}", v)?;
    }

    if let Some(v) = meta.private_information.as_ref() {
        writeln!(
            to,
            "Private Information: {}",
            format_value_list(v.iter().map(|n| format!("{:#x}", n)), width, false)
        )?;
    }

    writeln!(to)?;
    Ok(())
}

fn dump<W, D>(to: &mut W, obj: &InMemDicomObject<D>, width: u32, depth: u32) -> IoResult<()>
where
    W: ?Sized + Write,
    D: DataDictionary,
{
    for elem in obj {
        dump_element(&mut *to, &elem, width, depth)?;
    }

    Ok(())
}

fn dump_element<W, D>(to: &mut W, elem: &InMemElement<D>, width: u32, depth: u32) -> IoResult<()>
where
    W: ?Sized + Write,
    D: DataDictionary,
{
    let indent = vec![b' '; (depth * 2) as usize];
    let tag_alias = StandardDataDictionary
        .by_tag(elem.tag())
        .map(DictionaryEntry::alias)
        .unwrap_or("«Unknown Attribute»");
    to.write_all(&indent)?;
    let vm = match elem.vr() {
        VR::OB | VR::OW | VR::UN => 1,
        _ => elem.value().multiplicity(),
    };

    match elem.value() {
        DicomValue::Sequence { items, .. } => {
            writeln!(
                to,
                "{} {:35} {} ({} Item{})",
                elem.tag(),
                tag_alias,
                elem.vr(),
                vm,
                if vm == 1 { "" } else { "s" },
            )?;
            for item in items {
                dump_item(&mut *to, item, width, depth + 2)?;
            }
            to.write_all(&indent)?;
            writeln!(to, "(FFFE, E0DD) SequenceDelimitationItem",)?;
        }
        DicomValue::PixelSequence {
            fragments,
            offset_table,
        } => {
            // write pixel sequence start line
            let vr = elem.vr();
            let num_items = 1 + fragments.len();
            writeln!(
                to,
                "{} PixelData {:25} {} (PixelSequence, {} Item{})",
                elem.tag(),
                "",
                vr,
                num_items,
                if num_items == 1 { "" } else { "s" },
            )?;

            // write offset table
            let byte_len = offset_table.len();
            writeln!(
                to,
                "  (FFFE,E000) pi ({:>3} bytes, 1 Item): {:48}",
                byte_len,
                item_value_summary(&offset_table, width.saturating_sub(42 + depth * 2)),
            )?;

            // write compressed fragments
            for fragment in fragments {
                let byte_len = fragment.len();
                writeln!(
                    to,
                    "  (FFFE,E000) pi ({:>3} bytes, 1 Item): {:48}",
                    byte_len,
                    item_value_summary(&fragment, width.saturating_sub(42 + depth * 2)),
                )?;
            }
        }
        DicomValue::Primitive(value) => {
            let vr = elem.vr();
            let byte_len = value.calculate_byte_len();
            writeln!(
                to,
                "{} {:35} {} ({},{:>3} bytes): {}",
                elem.tag(),
                tag_alias,
                vr,
                vm,
                byte_len,
                value_summary(&value, vr, width.saturating_sub(68 + depth * 2)),
            )?;
        }
    }

    Ok(())
}

fn dump_item<W, D>(to: &mut W, item: &InMemDicomObject<D>, width: u32, depth: u32) -> IoResult<()>
where
    W: ?Sized + Write,
    D: DataDictionary,
{
    let indent: String = std::iter::repeat(' ').take((depth * 2) as usize).collect();
    writeln!(to, "{}(FFFE,E000) na Item", indent)?;
    dump(to, item, width, depth + 1)?;
    writeln!(to, "{}(FFFE,E00D) ItemDelimitationItem", indent,)?;
    Ok(())
}

fn value_summary(value: &PrimitiveValue, vr: VR, max_characters: u32) -> Cow<str> {
    use PrimitiveValue::*;
    match (value, vr) {
        (F32(values), _) => format_value_list(values, max_characters, false).into(),
        (F64(values), _) => format_value_list(values, max_characters, false).into(),
        (I32(values), _) => format_value_list(values, max_characters, false).into(),
        (I64(values), _) => format_value_list(values, max_characters, false).into(),
        (U32(values), _) => format_value_list(values, max_characters, false).into(),
        (U64(values), _) => format_value_list(values, max_characters, false).into(),
        (I16(values), _) => format_value_list(values, max_characters, false).into(),
        (U16(values), VR::OW) => format_value_list(
            values.into_iter().map(|n| format!("{:02X}", n)),
            max_characters,
            false,
        )
        .into(),
        (U16(values), _) => format_value_list(values, max_characters, false).into(),
        (U8(values), VR::OB) | (U8(values), VR::UN) => format_value_list(
            values.into_iter().map(|n| format!("{:02X}", n)),
            max_characters,
            false,
        )
        .into(),
        (U8(values), _) => format_value_list(values, max_characters, false).into(),
        (Tags(values), _) => format_value_list(values, max_characters, false).into(),
        (Strs(values), _) => format_value_list(values, max_characters, true).into(),
        (Date(values), _) => format_value_list(values, max_characters, true).into(),
        (Time(values), _) => format_value_list(values, max_characters, true).into(),
        (DateTime(values), _) => format_value_list(values, max_characters, true).into(),
        (Str(value), _) => cut_str(&format!("\"{}\"", value), max_characters)
            .into_owned()
            .into(),
        (Empty, _) => "".into(),
    }
}

fn item_value_summary(data: &[u8], max_characters: u32) -> String {
    format_value_list(
        data.iter().map(|n| format!("{:02X}", n)),
        max_characters,
        false,
    )
}

fn format_value_list<I>(values: I, max_characters: u32, quoted: bool) -> String
where
    I: IntoIterator,
    I::IntoIter: ExactSizeIterator,
    I::Item: std::fmt::Display,
{
    use itertools::Itertools;
    let values = values.into_iter();
    let len = values.len();
    let mut pieces = values.take(64).map(|piece| {
        if quoted {
            format!("\"{}\"", piece)
        } else {
            piece.to_string()
        }
    });
    let mut pieces = pieces.join(", ");
    if len > 1 {
        pieces = format!("[{}]", pieces);
    }
    cut_str(&pieces, max_characters).into_owned()
}

fn cut_str(s: &str, max_characters: u32) -> Cow<str> {
    let max = (max_characters.saturating_sub(3)) as usize;
    if s.len() > max {
        format!("{}...", &s[..max]).into()
    } else {
        s.into()
    }
}
<|endoftext|>


<commit_before>#![feature(collections, convert, libc)]

extern crate libc;
extern crate neovim;

use std::io::Write;
use std::fs::OpenOptions;
use std::path::Path;
use libc::{c_int, c_uchar, c_void};
use libc::funcs::posix88::unistd::{pipe, read, write};
use libc::types::os::arch::c95::size_t;

fn send_message(fd: c_int, command: &str) {
    let mut arr = neovim::Array::new();
    arr.add_string(command);
    let msg = neovim::serialize_message(1, "vim_command", &arr);
    let msg_ref: &str = msg.as_ref();
    let msg_ptr = msg_ref.as_ptr() as *const c_void;
    unsafe { write(fd, msg_ptr, msg.len() as size_t) };
}

fn recv_message(fd: c_int) -> Option<neovim::Array> {
    let mut buf : [c_uchar; 1024] = [0; 1024];
    let n = unsafe { read(fd, buf.as_mut_ptr() as *mut c_void, 1024) };
    if n < 0 {
        return None;
    }
    unsafe {
        let v = Vec::from_raw_buf(buf.as_ptr(), n as usize);
        let s = String::from_utf8_unchecked(v);
        Some(neovim::deserialize_message(&s))
    }
}

fn main() {
    // two anonymous pipes for msgpack-rpc between the logger and nvim
    let mut nvim_log : [c_int; 2] = [0; 2]; // to nvim from logger
    let mut log_nvim : [c_int; 2] = [0; 2]; // to logger from nvim
    unsafe {
        pipe(nvim_log.as_mut_ptr());
        pipe(log_nvim.as_mut_ptr());
    };

    // open log file
    let mut opts = OpenOptions::new();
    opts.create(true);
    opts.write(true);
    opts.append(true);
    let mut file = opts.open(&Path::new("events.log")).unwrap();

    // listen for events in a separate thread and log them
    ::std::thread::spawn(move || {
        // listen for bufenter events
        send_message(nvim_log[1], "au BufEnter * call rpcnotify(1, 'bufenter', fnamemodify(bufname(''), ':p'))");

        // receive messages
        while let Some(recv_arr) = recv_message(log_nvim[0]) {
            if recv_arr.len() > 0 {
                let recv_str = format!("{:?}\n", recv_arr).into_bytes();
                file.write_all(recv_str.as_ref()).ok();
            }
        }
    });

    // start nvim
    let args : Vec<String> = ::std::env::args().collect();
    neovim::main_setup(&args);
    neovim::channel_from_fds(nvim_log[0], log_nvim[1]);
    neovim::main_loop();
}
<commit_msg>Remove unnecessary feature flag<commit_after>#![feature(collections, libc)]

extern crate libc;
extern crate neovim;

use std::io::Write;
use std::fs::OpenOptions;
use std::path::Path;
use libc::{c_int, c_uchar, c_void};
use libc::funcs::posix88::unistd::{pipe, read, write};
use libc::types::os::arch::c95::size_t;

fn send_message(fd: c_int, command: &str) {
    let mut arr = neovim::Array::new();
    arr.add_string(command);
    let msg = neovim::serialize_message(1, "vim_command", &arr);
    let msg_ref: &str = msg.as_ref();
    let msg_ptr = msg_ref.as_ptr() as *const c_void;
    unsafe { write(fd, msg_ptr, msg.len() as size_t) };
}

fn recv_message(fd: c_int) -> Option<neovim::Array> {
    let mut buf : [c_uchar; 1024] = [0; 1024];
    let n = unsafe { read(fd, buf.as_mut_ptr() as *mut c_void, 1024) };
    if n < 0 {
        return None;
    }
    unsafe {
        let v = Vec::from_raw_buf(buf.as_ptr(), n as usize);
        let s = String::from_utf8_unchecked(v);
        Some(neovim::deserialize_message(&s))
    }
}

fn main() {
    // two anonymous pipes for msgpack-rpc between the logger and nvim
    let mut nvim_log : [c_int; 2] = [0; 2]; // to nvim from logger
    let mut log_nvim : [c_int; 2] = [0; 2]; // to logger from nvim
    unsafe {
        pipe(nvim_log.as_mut_ptr());
        pipe(log_nvim.as_mut_ptr());
    };

    // open log file
    let mut opts = OpenOptions::new();
    opts.create(true);
    opts.write(true);
    opts.append(true);
    let mut file = opts.open(&Path::new("events.log")).unwrap();

    // listen for events in a separate thread and log them
    ::std::thread::spawn(move || {
        // listen for bufenter events
        send_message(nvim_log[1], "au BufEnter * call rpcnotify(1, 'bufenter', fnamemodify(bufname(''), ':p'))");

        // receive messages
        while let Some(recv_arr) = recv_message(log_nvim[0]) {
            if recv_arr.len() > 0 {
                let recv_str = format!("{:?}\n", recv_arr).into_bytes();
                file.write_all(recv_str.as_ref()).ok();
            }
        }
    });

    // start nvim
    let args : Vec<String> = ::std::env::args().collect();
    neovim::main_setup(&args);
    neovim::channel_from_fds(nvim_log[0], log_nvim[1]);
    neovim::main_loop();
}
<|endoftext|>


<commit_before>extern crate mpd;
extern crate serialize;

use mpd::connection::MpdConnection;
use mpd::playlists::MpdPlaylist;
use mpd::idle::{MpdEvent, PLAYER, UPDATE};
use serialize::json;
use std::str::from_str;

fn main() {
    //let c = MpdConnection::new(Some("192.168.1.10"), 6600);
    let c = MpdConnection::new(None, 6600);
    let conn = match c {
        None => panic!("connection is None"),
        Some(Err(e)) => panic!("connection error: {}", e),
        Some(Ok(c)) => c
    };

    //println!("{}", json::encode(&conn.status()));
    //println!("{}", json::encode(&conn.stats()));
    //println!("{}", json::encode(&conn.playlists()));
    //println!("{}", json::encode(&conn.outputs()));
    //println!("{}", json::encode(&conn.queue().songs()));

    //println!("{}", conn.stop());

    //println!("{}", conn.current_song());

    let v = conn.version();
    println!("version: {}", v);

    for e in conn.wait(None) {
        match e {
            Err(ref v) => panic!("{}", v),
            Ok(ref v) => println!("{}", v)
        }
    }
}
<commit_msg>example: experiments<commit_after>#![allow(unused_imports)]

extern crate mpd;
extern crate serialize;

use mpd::connection::MpdConnection;
use mpd::playlists::MpdPlaylist;
use mpd::outputs::MpdOutput;
use mpd::idle::{MpdEvent, PLAYER, UPDATE};
use serialize::json;
use std::str::from_str;

fn main() {
    //let c = MpdConnection::new(Some("192.168.1.10"), 6600);
    let c = MpdConnection::new(None, 6600);
    let conn = match c {
        None => panic!("connection is None"),
        Some(Err(e)) => panic!("connection error: {}", e),
        Some(Ok(c)) => c
    };

    //println!("{}", json::encode(&conn.status()));
    //println!("{}", json::encode(&conn.stats()));
    println!("{}", json::encode(&conn.playlists()));
    println!("{}", json::encode(&conn.outputs()));
    //println!("{}", json::encode(&conn.queue().songs()));

    for mut out in conn.outputs().unwrap().map(|v| v.unwrap()) {
        println!("enabling {}", out.enable(true));
    }

    //println!("{}", conn.stop());

    //println!("{}", conn.current_song());

    let v = conn.version();
    println!("version: {}", v);

    //for e in conn.wait(None) {
        //match e {
            //Err(ref v) => panic!("{}", v),
            //Ok(ref v) => println!("{}", v)
        //}
    //}
}
<|endoftext|>


<commit_before>extern crate octavo;

use std::io::Write;

use octavo::digest::Digest;
use octavo::digest::md5::Md5;
use octavo::digest::md4::Md4;
use octavo::digest::ripemd::Ripemd160;
use octavo::digest::sha1::Sha1;
use octavo::digest::sha2::*;
use octavo::digest::sha3::*;

fn hex<T: AsRef<[u8]>, D: Digest>(data: T, mut digest: D) -> String {
    digest.update(data);

    let mut result = vec![0; D::output_bytes()];

    digest.result(&mut result[..]);

    let mut out = vec![0; D::output_bytes() * 2];

    for byte in result {
        write!(&mut out, "{:02x}", byte).unwrap();
    }

    String::from_utf8(out).unwrap()
}

fn main() {
    let data = "octavo";

    println!("Data: {:?}\n", data);

    println!("MD4:       {}", hex(&data, Md4::default()));
    println!("MD5:       {}", hex(&data, Md5::default()));
    println!("RIPEMD160: {}", hex(&data, Ripemd160::default()));
    println!("SHA1:      {}", hex(&data, Sha1::default()));
    println!("SHA224:    {}", hex(&data, Sha224::default()));
    println!("SHA256:    {}", hex(&data, Sha256::default()));
    println!("SHA384:    {}", hex(&data, Sha384::default()));
    println!("SHA512:    {}", hex(&data, Sha512::default()));
    println!("SHA3-224:  {}", hex(&data, Sha3224::default()));
    println!("SHA3-256:  {}", hex(&data, Sha3256::default()));
    println!("SHA3-384:  {}", hex(&data, Sha3384::default()));
    println!("SHA3-512:  {}", hex(&data, Sha3512::default()));
}
<commit_msg>feat(examples/sums): add Tiger hash<commit_after>extern crate octavo;

use std::io::Write;

use octavo::digest::Digest;

use octavo::digest::md4::Md4;
use octavo::digest::md5::Md5;
use octavo::digest::ripemd::Ripemd160;
use octavo::digest::sha1::Sha1;
use octavo::digest::sha2::*;
use octavo::digest::sha3::*;
use octavo::digest::tiger::Tiger;

fn hex<T: AsRef<[u8]>, D: Digest>(data: T, mut digest: D) -> String {
    digest.update(data);

    let mut result = vec![0; D::output_bytes()];

    digest.result(&mut result[..]);

    let mut out = vec![0; D::output_bytes() * 2];

    for byte in result {
        write!(&mut out, "{:02x}", byte).unwrap();
    }

    String::from_utf8(out).unwrap()
}

fn main() {
    let data = "octavo";

    println!("Data: {:?}\n", data);

    println!("MD4:       {}", hex(&data, Md4::default()));
    println!("MD5:       {}", hex(&data, Md5::default()));
    println!("RIPEMD160: {}", hex(&data, Ripemd160::default()));
    println!("SHA1:      {}", hex(&data, Sha1::default()));
    println!("SHA224:    {}", hex(&data, Sha224::default()));
    println!("SHA256:    {}", hex(&data, Sha256::default()));
    println!("SHA384:    {}", hex(&data, Sha384::default()));
    println!("SHA512:    {}", hex(&data, Sha512::default()));
    println!("SHA3-224:  {}", hex(&data, Sha3224::default()));
    println!("SHA3-256:  {}", hex(&data, Sha3256::default()));
    println!("SHA3-384:  {}", hex(&data, Sha3384::default()));
    println!("SHA3-512:  {}", hex(&data, Sha3512::default()));
    println!("Tiger:     {}", hex(&data, Tiger::default()));
}
<|endoftext|>


<commit_before>extern crate pkg_config;

fn main() {
    pkg_config::probe_library("cfitsio").unwrap();
}
<commit_msg>Add cargo flag to re-run build script if changed<commit_after>extern crate pkg_config;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    pkg_config::probe_library("cfitsio").unwrap();
}
<|endoftext|>


<commit_before>use crate::common::*;
use crate::data::packet::Packet;
use crate::data::value::*;
use std::any::Any;
use std::io::{ErrorKind, Seek, SeekFrom, Write};
use std::sync::Arc;

use crate::error::*;

pub trait WriteSeek: Write + Seek {}

impl<T: Write + Seek> WriteSeek for T {}

/// Runtime wrapper around either a [`Write`] or a [`WriteSeek`] trait object which supports querying
/// for seek support.
pub enum Writer {
    NonSeekable(Box<dyn Write>, u64),
    Seekable(Box<dyn WriteSeek>),
}

impl Writer {
    /// Creates a [`Writer`] from a trait object that implements both [`Write`] and [`Seek`].
    pub fn from_seekable(inner: Box<dyn WriteSeek>) -> Self {
        Self::Seekable(inner)
    }

    /// Creates a [`Writer`] from a trait object that implements the [`Write`] trait.
    pub fn from_nonseekable(inner: Box<dyn Write>) -> Self {
        Self::NonSeekable(inner, 0)
    }

    /// Returns whether the [`Writer`] can seek within the source.
    pub fn can_seek(&self) -> bool {
        matches!(self, Self::Seekable(_))
    }
}

impl Write for Writer {
    fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
        match self {
            Self::NonSeekable(inner, ref mut index) => {
                let result = inner.write(bytes);

                if let Ok(written) = result {
                    *index += written as u64;
                }

                result
            }
            Self::Seekable(inner) => inner.write(bytes),
        }
    }

    fn flush(&mut self) -> std::io::Result<()> {
        match self {
            Self::NonSeekable(inner, ..) => inner.flush(),
            Self::Seekable(inner) => inner.flush(),
        }
    }
}

impl Seek for Writer {
    fn seek(&mut self, seek: SeekFrom) -> std::io::Result<u64> {
        match self {
            Self::NonSeekable(_, index) => {
                if let SeekFrom::Current(0) = seek {
                    Ok(*index)
                } else {
                    Err(std::io::Error::new(
                        ErrorKind::Other,
                        "Seeking not supported",
                    ))
                }
            }
            Self::Seekable(inner) => inner.seek(seek),
        }
    }
}

/// Used to implement muxing operations.
pub trait Muxer: Send {
    /// Configures a muxer.
    fn configure(&mut self) -> Result<()>;
    /// Writes a stream header into a data structure implementing
    /// the `Write` trait.
    fn write_header(&mut self, out: &mut Writer) -> Result<()>;
    /// Writes a stream packet into a data structure implementing
    /// the `Write` trait.
    fn write_packet(&mut self, out: &mut Writer, pkt: Arc<Packet>) -> Result<()>;
    /// Writes a stream trailer into a data structure implementing
    /// the `Write` trait.
    fn write_trailer(&mut self, out: &mut Writer) -> Result<()>;

    /// Sets global media file information for a muxer.
    fn set_global_info(&mut self, info: GlobalInfo) -> Result<()>;
    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()>;
}

/// Auxiliary structure to encapsulate a muxer object and
/// its additional data.
pub struct Context<M: Muxer + Send> {
    muxer: M,
    writer: Writer,
    /// User private data.
    ///
    /// This data cannot be cloned.
    pub user_private: Option<Box<dyn Any + Send + Sync>>,
}

impl<M: Muxer + Send> Context<M> {
    /// Creates a new `Context` instance.
    pub fn new(muxer: M, writer: Writer) -> Self {
        Context {
            muxer,
            writer,
            user_private: None,
        }
    }

    /// Configures a muxer.
    pub fn configure(&mut self) -> Result<()> {
        self.muxer.configure()
    }

    /// Writes a stream header to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_header(&mut self) -> Result<()> {
        self.muxer.write_header(&mut self.writer)
    }

    /// Writes a stream packet to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_packet(&mut self, pkt: Arc<Packet>) -> Result<()> {
        self.muxer.write_packet(&mut self.writer, pkt)
    }

    /// Writes a stream trailer to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_trailer(&mut self) -> Result<()> {
        self.muxer.write_trailer(&mut self.writer)?;
        self.writer.flush()?;

        Ok(())
    }

    /// Sets global media file information for a muxer.
    pub fn set_global_info(&mut self, info: GlobalInfo) -> Result<()> {
        self.muxer.set_global_info(info)
    }

    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
    where
        V: Into<Value<'a>>,
    {
        self.muxer.set_option(key, val.into())
    }
}

/// Format descriptor.
///
/// Contains information on a format and its own muxer.
#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    /// Format name.
    pub name: &'static str,
    /// Muxer name.
    pub demuxer: &'static str,
    /// Format description.
    pub description: &'static str,
    /// Format media file extensions.
    pub extensions: &'static [&'static str],
    /// Format MIME.
    pub mime: &'static [&'static str],
}

/// Used to get a format descriptor and create a new muxer.
pub trait Descriptor {
    type OutputMuxer: Muxer + Send;

    /// Creates a new muxer for the requested format.
    fn create(&self) -> Self::OutputMuxer;
    /// Returns the descriptor of a format.
    fn describe(&self) -> &Descr;
}

/// Used to look for a specific format.
pub trait Lookup<T: Descriptor + ?Sized> {
    /// Retrieves a specific format by name.
    fn by_name(&self, name: &str) -> Option<&'static T>;
}

impl<T: Descriptor + ?Sized> Lookup<T> for [&'static T] {
    fn by_name(&self, name: &str) -> Option<&'static T> {
        self.iter().find(|&&d| d.describe().name == name).copied()
    }
}
<commit_msg>format: Replace Box with a generic for Writer<commit_after>use crate::common::*;
use crate::data::packet::Packet;
use crate::data::value::*;
use std::any::Any;
use std::io::{ErrorKind, Seek, SeekFrom, Write};
use std::sync::Arc;

use crate::error::*;

pub trait WriteSeek: Write + Seek {}

impl<T: Write + Seek> WriteSeek for T {}

/// Runtime wrapper around either a [`Write`] or a [`WriteSeek`] trait object which supports querying
/// for seek support.
pub enum Writer<W: Write, WS: WriteSeek> {
    NonSeekable(W, u64),
    Seekable(WS),
}

impl<W: Write, WS: WriteSeek> Writer<W, WS> {
    /// Creates a [`Writer`] from an object that implements both [`Write`] and [`Seek`] traits.
    pub fn from_seekable(inner: WS) -> Self {
        Self::Seekable(inner)
    }

    /// Creates a [`Writer`] from an object that implements the [`Write`] trait.
    pub fn from_nonseekable(inner: W) -> Self {
        Self::NonSeekable(inner, 0)
    }

    /// Returns whether the [`Writer`] can seek within the source.
    pub fn can_seek(&self) -> bool {
        matches!(self, Self::Seekable(_))
    }
}

impl<W: Write, WS: WriteSeek> Write for Writer<W, WS> {
    fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
        match self {
            Self::NonSeekable(inner, ref mut index) => {
                let result = inner.write(bytes);

                if let Ok(written) = result {
                    *index += written as u64;
                }

                result
            }
            Self::Seekable(inner) => inner.write(bytes),
        }
    }

    fn flush(&mut self) -> std::io::Result<()> {
        match self {
            Self::NonSeekable(inner, ..) => inner.flush(),
            Self::Seekable(inner) => inner.flush(),
        }
    }
}

impl<W: Write, WS: WriteSeek> Seek for Writer<W, WS> {
    fn seek(&mut self, seek: SeekFrom) -> std::io::Result<u64> {
        match self {
            Self::NonSeekable(_, index) => {
                if let SeekFrom::Current(0) = seek {
                    Ok(*index)
                } else {
                    Err(std::io::Error::new(
                        ErrorKind::Other,
                        "Seeking not supported",
                    ))
                }
            }
            Self::Seekable(inner) => inner.seek(seek),
        }
    }
}

/// Used to implement muxing operations.
pub trait Muxer: Send {
    /// Configures a muxer.
    fn configure(&mut self) -> Result<()>;
    /// Writes a stream header into a data structure implementing
    /// the `Write` trait.
    fn write_header<W: Write, WS: WriteSeek>(&mut self, out: &mut Writer<W, WS>) -> Result<()>;
    /// Writes a stream packet into a data structure implementing
    /// the `Write` trait.
    fn write_packet<W: Write, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<W, WS>,
        pkt: Arc<Packet>,
    ) -> Result<()>;
    /// Writes a stream trailer into a data structure implementing
    /// the `Write` trait.
    fn write_trailer<W: Write, WS: WriteSeek>(&mut self, out: &mut Writer<W, WS>) -> Result<()>;

    /// Sets global media file information for a muxer.
    fn set_global_info(&mut self, info: GlobalInfo) -> Result<()>;
    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()>;
}

/// Auxiliary structure to encapsulate a muxer object and
/// its additional data.
pub struct Context<M: Muxer + Send, W: Write, WS: WriteSeek> {
    muxer: M,
    writer: Writer<W, WS>,
    /// User private data.
    ///
    /// This data cannot be cloned.
    pub user_private: Option<Box<dyn Any + Send + Sync>>,
}

impl<M: Muxer + Send, W: Write, WS: WriteSeek> Context<M, W, WS> {
    /// Creates a new `Context` instance.
    pub fn new(muxer: M, writer: Writer<W, WS>) -> Self {
        Context {
            muxer,
            writer,
            user_private: None,
        }
    }

    /// Configures a muxer.
    pub fn configure(&mut self) -> Result<()> {
        self.muxer.configure()
    }

    /// Writes a stream header to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_header(&mut self) -> Result<()> {
        self.muxer.write_header(&mut self.writer)
    }

    /// Writes a stream packet to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_packet(&mut self, pkt: Arc<Packet>) -> Result<()> {
        self.muxer.write_packet(&mut self.writer, pkt)
    }

    /// Writes a stream trailer to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_trailer(&mut self) -> Result<()> {
        self.muxer.write_trailer(&mut self.writer)?;
        self.writer.flush()?;

        Ok(())
    }

    /// Sets global media file information for a muxer.
    pub fn set_global_info(&mut self, info: GlobalInfo) -> Result<()> {
        self.muxer.set_global_info(info)
    }

    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
    where
        V: Into<Value<'a>>,
    {
        self.muxer.set_option(key, val.into())
    }
}

/// Format descriptor.
///
/// Contains information on a format and its own muxer.
#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    /// Format name.
    pub name: &'static str,
    /// Muxer name.
    pub demuxer: &'static str,
    /// Format description.
    pub description: &'static str,
    /// Format media file extensions.
    pub extensions: &'static [&'static str],
    /// Format MIME.
    pub mime: &'static [&'static str],
}

/// Used to get a format descriptor and create a new muxer.
pub trait Descriptor {
    type OutputMuxer: Muxer + Send;

    /// Creates a new muxer for the requested format.
    fn create(&self) -> Self::OutputMuxer;
    /// Returns the descriptor of a format.
    fn describe(&self) -> &Descr;
}

/// Used to look for a specific format.
pub trait Lookup<T: Descriptor + ?Sized> {
    /// Retrieves a specific format by name.
    fn by_name(&self, name: &str) -> Option<&'static T>;
}

impl<T: Descriptor + ?Sized> Lookup<T> for [&'static T] {
    fn by_name(&self, name: &str) -> Option<&'static T> {
        self.iter().find(|&&d| d.describe().name == name).copied()
    }
}
<|endoftext|>


<commit_before>#![cfg(target_os = "windows")]

use std::ptr;

use winit;

use ContextError;
use CreationError;
use GlAttributes;
use GlRequest;
use Api;
use PixelFormat;
use PixelFormatRequirements;

use winapi;

use api::wgl::Context as WglContext;
use api::egl::Context as EglContext;
use api::egl::ffi::egl::Egl;
use api::egl;

unsafe impl Send for Context {}
unsafe impl Sync for Context {}

pub enum Context {
    Egl(EglContext),
    Wgl(WglContext),
}

impl Context {

    /// See the docs in the crate root file.
    pub fn new(
        window_builder: winit::WindowBuilder,
        events_loop: &winit::EventsLoop,
        pf_reqs: &PixelFormatRequirements,
        gl_attr: &GlAttributes<&Self>,
        egl: Option<&Egl>,
    ) -> Result<(winit::Window, Self), CreationError>
    {
        let window = try!(window_builder.build(events_loop));
        let gl_attr = gl_attr.clone().map_sharing(|ctxt| {
            match *ctxt {
                Context::Wgl(ref c) => c.get_hglrc(),
                Context::Egl(_) => unimplemented!(),        // FIXME:
            }
        });
        let context_result = unsafe {
            let w = window.platform_window() as winapi::HWND;
            match gl_attr.version {
                GlRequest::Specific(Api::OpenGlEs, (_major, _minor)) => {
                    if let Some(egl) = egl {
                        if let Ok(c) =
                               EglContext::new(egl.clone(),
                                               &pf_reqs,
                                               &gl_attr.clone().map_sharing(|_| unimplemented!()),
                                               egl::NativeDisplay::Other(Some(ptr::null())))
                            .and_then(|p| p.finish(w)) {
                            Ok(Context::Egl(c))
                        } else {
                            WglContext::new(&pf_reqs, &gl_attr, w).map(Context::Wgl)
                        }

                    } else {
                        // falling back to WGL, which is always available
                        WglContext::new(&pf_reqs, &gl_attr, w).map(Context::Wgl)
                    }
                }
                _ => WglContext::new(&pf_reqs, &gl_attr, w).map(Context::Wgl),
            }
        };
        context_result.map(|context| (window, context))
    }

    pub fn resize(&self, _width: u32, _height: u32) {
        // Method is for API consistency.
    }

    #[inline]
    pub unsafe fn make_current(&self) -> Result<(), ContextError> {
        match *self {
            Context::Wgl(ref c) => c.make_current(),
            Context::Egl(ref c) => c.make_current(),
        }
    }

    #[inline]
    pub fn is_current(&self) -> bool {
        match *self {
            Context::Wgl(ref c) => c.is_current(),
            Context::Egl(ref c) => c.is_current(),
        }
    }

    #[inline]
    pub fn get_proc_address(&self, addr: &str) -> *const () {
        match *self {
            Context::Wgl(ref c) => c.get_proc_address(addr),
            Context::Egl(ref c) => c.get_proc_address(addr),
        }
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        match *self {
            Context::Wgl(ref c) => c.swap_buffers(),
            Context::Egl(ref c) => c.swap_buffers(),
        }
    }

    #[inline]
    pub fn get_api(&self) -> Api {
        match *self {
            Context::Wgl(ref c) => c.get_api(),
            Context::Egl(ref c) => c.get_api(),
        }
    }

    #[inline]
    pub fn get_pixel_format(&self) -> PixelFormat {
        match *self {
            Context::Wgl(ref c) => c.get_pixel_format(),
            Context::Egl(ref c) => c.get_pixel_format(),
        }
    }
}
<commit_msg>Add inline decorator to resize method in windows backend<commit_after>#![cfg(target_os = "windows")]

use std::ptr;

use winit;

use ContextError;
use CreationError;
use GlAttributes;
use GlRequest;
use Api;
use PixelFormat;
use PixelFormatRequirements;

use winapi;

use api::wgl::Context as WglContext;
use api::egl::Context as EglContext;
use api::egl::ffi::egl::Egl;
use api::egl;

unsafe impl Send for Context {}
unsafe impl Sync for Context {}

pub enum Context {
    Egl(EglContext),
    Wgl(WglContext),
}

impl Context {

    /// See the docs in the crate root file.
    pub fn new(
        window_builder: winit::WindowBuilder,
        events_loop: &winit::EventsLoop,
        pf_reqs: &PixelFormatRequirements,
        gl_attr: &GlAttributes<&Self>,
        egl: Option<&Egl>,
    ) -> Result<(winit::Window, Self), CreationError>
    {
        let window = try!(window_builder.build(events_loop));
        let gl_attr = gl_attr.clone().map_sharing(|ctxt| {
            match *ctxt {
                Context::Wgl(ref c) => c.get_hglrc(),
                Context::Egl(_) => unimplemented!(),        // FIXME:
            }
        });
        let context_result = unsafe {
            let w = window.platform_window() as winapi::HWND;
            match gl_attr.version {
                GlRequest::Specific(Api::OpenGlEs, (_major, _minor)) => {
                    if let Some(egl) = egl {
                        if let Ok(c) =
                               EglContext::new(egl.clone(),
                                               &pf_reqs,
                                               &gl_attr.clone().map_sharing(|_| unimplemented!()),
                                               egl::NativeDisplay::Other(Some(ptr::null())))
                            .and_then(|p| p.finish(w)) {
                            Ok(Context::Egl(c))
                        } else {
                            WglContext::new(&pf_reqs, &gl_attr, w).map(Context::Wgl)
                        }

                    } else {
                        // falling back to WGL, which is always available
                        WglContext::new(&pf_reqs, &gl_attr, w).map(Context::Wgl)
                    }
                }
                _ => WglContext::new(&pf_reqs, &gl_attr, w).map(Context::Wgl),
            }
        };
        context_result.map(|context| (window, context))
    }

    #[inline]
    pub fn resize(&self, _width: u32, _height: u32) {
        // Method is for API consistency.
    }

    #[inline]
    pub unsafe fn make_current(&self) -> Result<(), ContextError> {
        match *self {
            Context::Wgl(ref c) => c.make_current(),
            Context::Egl(ref c) => c.make_current(),
        }
    }

    #[inline]
    pub fn is_current(&self) -> bool {
        match *self {
            Context::Wgl(ref c) => c.is_current(),
            Context::Egl(ref c) => c.is_current(),
        }
    }

    #[inline]
    pub fn get_proc_address(&self, addr: &str) -> *const () {
        match *self {
            Context::Wgl(ref c) => c.get_proc_address(addr),
            Context::Egl(ref c) => c.get_proc_address(addr),
        }
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        match *self {
            Context::Wgl(ref c) => c.swap_buffers(),
            Context::Egl(ref c) => c.swap_buffers(),
        }
    }

    #[inline]
    pub fn get_api(&self) -> Api {
        match *self {
            Context::Wgl(ref c) => c.get_api(),
            Context::Egl(ref c) => c.get_api(),
        }
    }

    #[inline]
    pub fn get_pixel_format(&self) -> PixelFormat {
        match *self {
            Context::Wgl(ref c) => c.get_pixel_format(),
            Context::Egl(ref c) => c.get_pixel_format(),
        }
    }
}
<|endoftext|>


<commit_before>extern crate cc;
extern crate pkg_config;

use std::{env, fs, io::Write, path::Path, process::Command};

use wayland_scanner::{generate_code, Side};

const PROTOCOL_DIR: &str = "../protocols";

fn main() {
    dump_git_version();
    build_wayland_glib_interface();
    generate_custom_protocols();
}

/// Writes the current git hash to a file that is read by Way Cooler
///
/// If this is a release build, the file will be empty.
fn dump_git_version() {
    let out_dir = env::var("OUT_DIR").expect("Could not find out directory!");
    let dest_path = Path::new(&out_dir).join("git-version.txt");
    let mut f = fs::File::create(&dest_path)
        .expect("Could not write git version to out directory");
    if let Some(git_version) = git_version() {
        f.write_all(git_version.as_ref())
            .expect("Could not write to git version file");
    }
}

/// Gets the current hash of HEAD. Returns None if for some reason
/// that could not be retrieved (e.g not in a git repository)
fn git_version() -> Option<String> {
    if !in_release_commit() {
        Command::new("git")
            .arg("rev-parse")
            .arg("HEAD")
            .output()
            .ok()
            .map(|output| output.stdout)
            .map(|hash| String::from_utf8_lossy(&hash).trim().into())
    } else {
        None
    }
}

/// Determines if the current HEAD is tagged with a release
fn in_release_commit() -> bool {
    let result = Command::new("git")
        .arg("describe")
        .arg("--exact-match")
        .arg("--tags")
        .arg("HEAD")
        .output()
        .unwrap();
    result.status.success()
}

/// Build the wayland-glib interface as a static library
fn build_wayland_glib_interface() {
    let glib = pkg_config::probe_library("glib-2.0").unwrap();
    let dbus = pkg_config::probe_library("dbus-1").unwrap();
    let wayland = pkg_config::probe_library("wayland-client").unwrap();

    let mut builder = cc::Build::new();

    let include_paths = glib
        .include_paths
        .iter()
        .chain(dbus.include_paths.iter())
        .chain(wayland.include_paths.iter());

    for path in include_paths {
        builder.include(path);
    }

    builder
        .file("src/wayland_glib_interface.c")
        .compile("wayland_glib_interface");
    println!("cargo:rustc-flags=-l wayland-client");
}

fn generate_custom_protocols() {
    let out_dir_str = env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(&out_dir_str);
    let path = Path::new(PROTOCOL_DIR).join("way-cooler-mousegrabber-unstable-v1.xml");
    generate_code(path, out_dir.join("mouse_grabber_api.rs"), Side::Client);
    println!("cargo:rerun-if-changed={}", PROTOCOL_DIR);
}
<commit_msg>Apply cargo format<commit_after>extern crate cc;
extern crate pkg_config;

use std::{env, fs, io::Write, path::Path, process::Command};

use wayland_scanner::{generate_code, Side};

const PROTOCOL_DIR: &str = "../protocols";

fn main() {
    dump_git_version();
    build_wayland_glib_interface();
    generate_custom_protocols();
}

/// Writes the current git hash to a file that is read by Way Cooler
///
/// If this is a release build, the file will be empty.
fn dump_git_version() {
    let out_dir = env::var("OUT_DIR").expect("Could not find out directory!");
    let dest_path = Path::new(&out_dir).join("git-version.txt");
    let mut f = fs::File::create(&dest_path)
        .expect("Could not write git version to out directory");
    if let Some(git_version) = git_version() {
        f.write_all(git_version.as_ref())
            .expect("Could not write to git version file");
    }
}

/// Gets the current hash of HEAD. Returns None if for some reason
/// that could not be retrieved (e.g not in a git repository)
fn git_version() -> Option<String> {
    if !in_release_commit() {
        Command::new("git")
            .arg("rev-parse")
            .arg("HEAD")
            .output()
            .ok()
            .map(|output| output.stdout)
            .map(|hash| String::from_utf8_lossy(&hash).trim().into())
    } else {
        None
    }
}

/// Determines if the current HEAD is tagged with a release
fn in_release_commit() -> bool {
    let result = Command::new("git")
        .arg("describe")
        .arg("--exact-match")
        .arg("--tags")
        .arg("HEAD")
        .output()
        .unwrap();
    result.status.success()
}

/// Build the wayland-glib interface as a static library
fn build_wayland_glib_interface() {
    let glib = pkg_config::probe_library("glib-2.0").unwrap();
    let dbus = pkg_config::probe_library("dbus-1").unwrap();
    let wayland = pkg_config::probe_library("wayland-client").unwrap();

    let mut builder = cc::Build::new();

    let include_paths = glib
        .include_paths
        .iter()
        .chain(dbus.include_paths.iter())
        .chain(wayland.include_paths.iter());

    for path in include_paths {
        builder.include(path);
    }

    builder
        .file("src/wayland_glib_interface.c")
        .compile("wayland_glib_interface");
    println!("cargo:rustc-flags=-l wayland-client");
}

fn generate_custom_protocols() {
    let out_dir_str = env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(&out_dir_str);
    let path =
        Path::new(PROTOCOL_DIR).join("way-cooler-mousegrabber-unstable-v1.xml");
    generate_code(path, out_dir.join("mouse_grabber_api.rs"), Side::Client);
    println!("cargo:rerun-if-changed={}", PROTOCOL_DIR);
}
<|endoftext|>


<commit_before>use libc::{c_char, c_int, c_uint, c_void, size_t};
use std::ffi::CStr;
use std::str::from_utf8;

pub type c_bool = c_int;

pub type csh = *const c_void;
pub type cs_err = c_int;
pub type cs_opt_type = c_int;

#[repr(C)]
pub struct CsInsn {
    pub id: c_uint,
    pub address: u64,
    pub size: u16,
    pub bytes: [u8; 16],
    pub mnemonic: [u8; 32],
    pub op_str: [u8; 160],
    pub detail: *const c_void,
}

#[repr(C)]
struct CCapstone1 {
    version: extern "C" fn (major: *mut c_int, minor: *mut c_int) -> c_uint,
    support: extern "C" fn(query: c_int) -> c_bool,
    open: extern "C" fn(arch: c_int, mode: c_int, handle: *mut csh) -> cs_err,
    close: extern "C" fn(handle: *mut csh) -> cs_err,
    option: extern "C" fn(handle: csh, _type: cs_opt_type, value: size_t) -> cs_err,
    err: extern "C" fn(handle: csh) -> cs_err,
    disasm: extern "C" fn(handle: csh, code: *const u8, code_size: size_t, address: u64, count: size_t, insn: *mut *mut cs_insn) -> size_t,
    /*
     To be implemented
    dissam_iter: extern "C" fn(handle: csh, reg_id: c_uint) -> *const c_char;
    reg_name: extern "C" fn(handle: csh, reg_id: c_uint) -> *const c_char;
    insn_name: extern "C" fn(handle: csh, insn_id: c_uint) -> *const c_char;
    insn_group: extern "C" fn(handle: csh, insn: *mut cs_insn, group_id: c_uint) -> c_bool;
    reg_read: extern "C" fn(handle: csh, insn: *mut cs_insn, reg_id: c_uint) -> c_bool;
    reg_write: extern "C" fn(handle: csh, insn: *mut cs_insn, reg_id: c_uint) -> c_bool;
    op_count: extern "C" fn(handle: csh, insn: *mut cs_insn, op_type: c_uint) -> c_int;
    op_index: extern "C" fn(handle: csh, insn: *mut cs_insn, op_type: c_uint, position: c_uint) -> c_int;
    */
}

#[derive(Clone, Copy, Debug)]
pub enum Arch {
    Arm = 0,
    Arm64,
    MIPS,
    X86,
    PowerPC,
    Sparc,
    SystemZ,
    XCore,
    M68K,
}

bitflags!(
    flags Mode: u32 {
        const MODE_LITTLE_ENDIAN = 0,
        const MODE_ARM = 0,
        const MODE_16 = 1 << 1,
        const MODE_32 = 1 << 2,
        const MODE_64 = 1 << 3,
        const MODE_THUMB = 1 << 4,
        const MODE_MCLASS = 1 << 5,
        const MODE_V8 = 1 << 6,
        const MODE_MICRO = 1 << 4,
        const MODE_MIPS3 = 1 << 5,
        const MODE_MIPS32R6 = 1 << 6,
        const MODE_MIPSGP64 = 1 << 7,
        const MODE_V9 = 1 << 4,
        const CS_MODE_QPX = 1 << 4,
        const CS_MODE_M68K_000 = 1 << 1,
        const CS_MODE_M68K_010 = 1 << 2,
        const CS_MODE_M68K_020 = 1 << 3,
        const CS_MODE_M68K_030 = 1 << 4,
        const CS_MODE_M68K_040 = 1 << 5,
        const CS_MODE_M68K_060 = 1 << 6,
        const MODE_BIG_ENDIAN= 1 << 31,
        const MODE_MIPS32 = 1 << 2,
        const MODE_MIPS64 = 1 << 3,
    }
);

#[derive(Clone, Copy, Debug)]
pub enum Opt {
    Syntax = 1,
    Detail,
    Mode,
    // OptMem
}

enum Error {
	Ok, // No error: everything was fine
	Mem, // Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
	Arch, // Unsupported architecture: cs_open()
	Handle, // Invalid handle: cs_op_count(), cs_op_index()
	Csh, // Invalid csh argument: cs_close(), cs_errno(), cs_option()
	Mode, // Invalid/unsupported mode: cs_open()
	InvOption, // Invalid/unsupported option: cs_option()
	Detail, // Information is unavailable because detail option is OFF
	MemSetup, // Dynamic memory management uninitialized (see CS_OPT_MEM)
	Version, // Unsupported version (bindings)
	Diet, // Access irrelevant data in "diet" engine
	Skipdata, // Access irrelevant data for "data" instruction in SKIPDATA mode
	Att, // X86 AT&T syntax is unsupported (opt-out at compile time)
	Intel, // X86 Intel syntax is unsupported (opt-out at compile time)
	Mask, // X86 Intel syntax is unsupported (opt-out at compile time)
}

pub struct Capstone {
    pub api: *mut CCapstone1,
    handle: *const c_void
}

impl Capstone {
    pub fn open(&mut self, arch: Arch, mode: Mode) -> CsErr {
        let mut handle : *const c_void = 0 as *const c_void;
        unsafe {
            let err: Error = ((*self.api).open)(arch as c_int, mode.bits as c_int, &mut handle) as Error;
            self.handle = handle;
            err
        }
    }

}

<commit_msg>Basic implementation of Capstone<commit_after>use libc::{c_char, c_int, c_uint, c_void, size_t};
use std::ffi::CStr;
use std::str::from_utf8;

pub type c_bool = c_int;

pub type csh = *const c_void;
pub type cs_err = c_int;
pub type cs_opt_type = c_int;

#[repr(C)]
pub struct CsInsn {
    pub id: c_uint,
    pub address: u64,
    pub size: u16,
    pub bytes: [u8; 16],
    pub mnemonic: [u8; 32],
    pub op_str: [u8; 160],
    pub detail: *const c_void,
}

#[repr(C)]
struct CCapstone1 {
    version: extern "C" fn (major: *mut c_int, minor: *mut c_int) -> c_uint,
    support: extern "C" fn(query: c_int) -> c_bool,
    open: extern "C" fn(arch: c_int, mode: c_int, handle: *mut csh) -> cs_err,
    close: extern "C" fn(handle: *mut csh) -> cs_err,
    option: extern "C" fn(handle: csh, _type: cs_opt_type, value: size_t) -> cs_err,
    err: extern "C" fn(handle: csh) -> cs_err,
    errno: extern "C" fn(handle: csh) -> cs_err,
    disasm: extern "C" fn(handle: csh, code: *const u8, code_size: size_t, address: u64, count: size_t, insn: *mut *mut cs_insn) -> size_t,
    /*
     To be implemented
    dissam_iter: extern "C" fn(handle: csh, reg_id: c_uint) -> *const c_char;
    reg_name: extern "C" fn(handle: csh, reg_id: c_uint) -> *const c_char;
    insn_name: extern "C" fn(handle: csh, insn_id: c_uint) -> *const c_char;
    insn_group: extern "C" fn(handle: csh, insn: *mut cs_insn, group_id: c_uint) -> c_bool;
    reg_read: extern "C" fn(handle: csh, insn: *mut cs_insn, reg_id: c_uint) -> c_bool;
    reg_write: extern "C" fn(handle: csh, insn: *mut cs_insn, reg_id: c_uint) -> c_bool;
    op_count: extern "C" fn(handle: csh, insn: *mut cs_insn, op_type: c_uint) -> c_int;
    op_index: extern "C" fn(handle: csh, insn: *mut cs_insn, op_type: c_uint, position: c_uint) -> c_int;
    */
}

#[derive(Clone, Copy, Debug)]
pub enum Arch {
    Arm = 0,
    Arm64,
    MIPS,
    X86,
    PowerPC,
    Sparc,
    SystemZ,
    XCore,
    M68K,
}

bitflags!(
    flags Mode: u32 {
        const MODE_LITTLE_ENDIAN = 0,
        const MODE_ARM = 0,
        const MODE_16 = 1 << 1,
        const MODE_32 = 1 << 2,
        const MODE_64 = 1 << 3,
        const MODE_THUMB = 1 << 4,
        const MODE_MCLASS = 1 << 5,
        const MODE_V8 = 1 << 6,
        const MODE_MICRO = 1 << 4,
        const MODE_MIPS3 = 1 << 5,
        const MODE_MIPS32R6 = 1 << 6,
        const MODE_MIPSGP64 = 1 << 7,
        const MODE_V9 = 1 << 4,
        const CS_MODE_QPX = 1 << 4,
        const CS_MODE_M68K_000 = 1 << 1,
        const CS_MODE_M68K_010 = 1 << 2,
        const CS_MODE_M68K_020 = 1 << 3,
        const CS_MODE_M68K_030 = 1 << 4,
        const CS_MODE_M68K_040 = 1 << 5,
        const CS_MODE_M68K_060 = 1 << 6,
        const MODE_BIG_ENDIAN= 1 << 31,
        const MODE_MIPS32 = 1 << 2,
        const MODE_MIPS64 = 1 << 3,
    }
);

#[derive(Clone, Copy, Debug)]
pub enum Opt {
    Syntax = 1,
    Detail,
    Mode,
    // OptMem
}

enum Error {
	Ok, // No error: everything was fine
	Mem, // Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
	Arch, // Unsupported architecture: cs_open()
	Handle, // Invalid handle: cs_op_count(), cs_op_index()
	Csh, // Invalid csh argument: cs_close(), cs_errno(), cs_option()
	Mode, // Invalid/unsupported mode: cs_open()
	InvOption, // Invalid/unsupported option: cs_option()
	Detail, // Information is unavailable because detail option is OFF
	MemSetup, // Dynamic memory management uninitialized (see CS_OPT_MEM)
	Version, // Unsupported version (bindings)
	Diet, // Access irrelevant data in "diet" engine
	Skipdata, // Access irrelevant data for "data" instruction in SKIPDATA mode
	Att, // X86 AT&T syntax is unsupported (opt-out at compile time)
	Intel, // X86 Intel syntax is unsupported (opt-out at compile time)
	Mask, // X86 Intel syntax is unsupported (opt-out at compile time)
}

pub struct Capstone {
    pub api: *mut CCapstone1,
    handle: *const c_void
}

impl Capstone {
    pub fn open(&mut self, arch: Arch, mode: Mode) -> Result<(), Error> {
        let mut handle : *const c_void = 0 as *const c_void;
        unsafe {
            match ((*self.api).open)(arch as c_int, mode.bits as c_int, &mut handle) {
                0 => Ok(),
                e => Err(e as Error),
            }
        }
    }

    pub fn set_option(&self, option: Opt, value: usize) -> Result<(), Error> {
        unsafe {
            match ((*self.api).option)(self.handle, option as c_int, value as size_t) {
                0 => Ok(()),
                e => Err(e as Error),
            }
        }
    }

    // This code has largly been taken from https://github.com/ebfe/rust-capstone/blob/master/src/lib.rs#L104
    // It does lots of allocations which I don't like
    // It would be better to just wrap the pointer within a struct and have a iterator
    // implemented to get the next one which can just point to the data instead

    pub fn disasm(&self, code: &[u8], addr: u64, count: usize) -> Result<Vec<Insn>, Error> {
        unsafe {
            let mut cinsnptr : *mut ll::cs_insn = 0 as *mut ll::cs_insn;
            match ((*self.api).disasm)(self.handle, code.as_ptr(), code.len() as size_t, addr, count as size_t, &mut cinsnptr) {
                0 => Err((*self.api).errno(self.handle) as Error),
                n => {
                    let mut v = Vec::new();
                    let cinsn : &[ll::cs_insn] = std::slice::from_raw_parts(cinsnptr, n as usize);
                    v.extend(cinsn.iter().map(|ci| {
                        Insn {
                            addr: ci.address,
                            bytes: (0..ci.size as usize).map(|i| ci.bytes[i]).collect(),
                            mnemonic: from_utf8(CStr::from_ptr(ci.mnemonic.as_ptr() as *const i8).to_bytes()).unwrap_or("<invalid utf8>").to_string(),
                            op_str: from_utf8(CStr::from_ptr(ci.op_str.as_ptr() as *const i8).to_bytes()).unwrap_or("<invalid utf8>").to_string(),
                        }
                    }));
                    ll::cs_free(cinsnptr, n);
                    Ok(v)
                },
            }
        }
    }
}

<|endoftext|>