<commit_before>// Copyright (c) 2016-2019 Fabian Schuiki

use crate::{crate_prelude::*, hir::HirNode, ty::Type, ParamEnv, ParamEnvBinding};

/// Determine the type of a node.
pub(crate) fn type_of<'gcx>(
    cx: &impl Context<'gcx>,
    node_id: NodeId,
    env: ParamEnv,
) -> Result<Type<'gcx>> {
    let hir = cx.hir_of(node_id)?;
    #[allow(unreachable_patterns)]
    match hir {
        HirNode::Port(p) => cx.map_to_type(p.ty, env),
        HirNode::Expr(e) => match e.kind {
            hir::ExprKind::IntConst(_) => Ok(cx.mkty_int(32)),
            hir::ExprKind::TimeConst(_) => Ok(cx.mkty_time()),
            hir::ExprKind::Ident(_) => cx.type_of(cx.resolve_node(node_id, env)?, env),
            hir::ExprKind::Unary(op, arg) => {
                let arg_ty = cx.type_of(arg, env)?;
                Ok(match op {
                    hir::UnaryOp::BitNot
                    | hir::UnaryOp::PreInc
                    | hir::UnaryOp::PreDec
                    | hir::UnaryOp::PostInc
                    | hir::UnaryOp::PostDec => arg_ty,
                    hir::UnaryOp::LogicNot => cx.mkty_bit(),
                    _ => return cx.unimp_msg("type analysis of", &hir),
                })
            }
            hir::ExprKind::Binary(op, lhs, rhs) => {
                let lhs_ty = cx.type_of(lhs, env)?;
                let _rhs_ty = cx.type_of(rhs, env)?;
                Ok(match op {
                    hir::BinaryOp::Add | hir::BinaryOp::Sub => lhs_ty,
                    hir::BinaryOp::Eq
                    | hir::BinaryOp::Neq
                    | hir::BinaryOp::Lt
                    | hir::BinaryOp::Leq
                    | hir::BinaryOp::Gt
                    | hir::BinaryOp::Geq
                    | hir::BinaryOp::LogicAnd
                    | hir::BinaryOp::LogicOr => cx.mkty_bit(),
                    _ => return cx.unimp_msg("type analysis of", &hir),
                })
            }
            _ => cx.unimp_msg("type analysis of", &hir),
        },
        HirNode::ValueParam(p) => {
            if is_explicit_type(cx, p.ty)? {
                return cx.map_to_type(p.ty, env);
            }
            let env_data = cx.param_env_data(env);
            match env_data.find_value(node_id) {
                Some(ParamEnvBinding::Indirect(assigned_id)) => {
                    return cx.type_of(assigned_id.0, assigned_id.1)
                }
                Some(ParamEnvBinding::Direct(t)) => return Ok(t.ty),
                _ => (),
            }
            if let Some(default) = p.default {
                return cx.type_of(default, env);
            }
            cx.emit(
                DiagBuilder2::error(format!(
                    "{} has implicit type but was not assigned and has no default",
                    p.desc_full()
                ))
                .span(p.human_span())
                .add_note("specify a type for the parameter; or")
                .add_note("add a default value for the parameter; or")
                .add_note("override the parameter from outside"),
            );
            Err(())
        }
        HirNode::VarDecl(d) => cx.map_to_type(d.ty, env),
        HirNode::GenvarDecl(_) => Ok(cx.mkty_int(32)),
        _ => cx.unimp_msg("type analysis of", &hir),
    }
}

/// Convert a node to a type.
pub(crate) fn map_to_type<'gcx>(
    cx: &impl Context<'gcx>,
    node_id: NodeId,
    env: ParamEnv,
) -> Result<Type<'gcx>> {
    let hir = cx.hir_of(node_id)?;
    #[allow(unreachable_patterns)]
    match hir {
        HirNode::Type(hir) => match hir.kind {
            hir::TypeKind::Builtin(hir::BuiltinType::Void) => Ok(cx.mkty_void()),
            hir::TypeKind::Builtin(hir::BuiltinType::Bit) => Ok(cx.mkty_bit()),
            hir::TypeKind::Builtin(hir::BuiltinType::Logic) => Ok(cx.mkty_logic()),
            hir::TypeKind::Builtin(hir::BuiltinType::Byte) => Ok(cx.mkty_int(8)),
            hir::TypeKind::Builtin(hir::BuiltinType::ShortInt) => Ok(cx.mkty_int(16)),
            hir::TypeKind::Builtin(hir::BuiltinType::Int) => Ok(cx.mkty_int(32)),
            hir::TypeKind::Builtin(hir::BuiltinType::LongInt) => Ok(cx.mkty_int(64)),
            hir::TypeKind::Named(name) => {
                let binding =
                    cx.resolve_upwards_or_error(name, cx.parent_node_id(node_id).unwrap())?;
                Ok(cx.mkty_named(name, (binding, env)))
            }
            hir::TypeKind::Struct(..) => Ok(cx.mkty_struct(node_id)),
            // We should never request mapping of an implicit type. Rather, the
            // actual type should be mapped. Arriving here is a bug in the
            // calling function.
            hir::TypeKind::Implicit => unreachable!("implicit type not resolved"),
            _ => cx.unimp_msg("type analysis of", hir),
        },
        HirNode::TypeParam(param) => {
            let env_data = cx.param_env_data(env);
            match env_data.find_type(node_id) {
                Some(ParamEnvBinding::Indirect(assigned_id)) => {
                    return cx.map_to_type(assigned_id.0, assigned_id.1)
                }
                Some(ParamEnvBinding::Direct(t)) => return Ok(t),
                _ => (),
            }
            if let Some(default) = param.default {
                return cx.map_to_type(default, env);
            }
            let mut d = DiagBuilder2::error(format!(
                "{} not assigned and has no default",
                param.desc_full(),
            ));
            let contexts = cx.param_env_contexts(env);
            for &context in &contexts {
                d = d.span(cx.span(context));
            }
            if contexts.is_empty() {
                d = d.span(param.human_span());
            }
            cx.emit(d);
            Err(())
        }
        HirNode::Typedef(def) => cx.map_to_type(def.ty, env),
        _ => cx.unimp_msg("conversion to type of", &hir),
    }
}

/// Check if a type (given by its node id) is explicit.
fn is_explicit_type<'gcx>(cx: &impl Context<'gcx>, node_id: NodeId) -> Result<bool> {
    Ok(match cx.hir_of(node_id)? {
        HirNode::Type(x) => x.is_explicit(),
        _ => false,
    })
}
<commit_msg>typeck: factor out type kind mapping<commit_after>// Copyright (c) 2016-2019 Fabian Schuiki

use crate::{crate_prelude::*, hir::HirNode, ty::Type, ParamEnv, ParamEnvBinding};

/// Determine the type of a node.
pub(crate) fn type_of<'gcx>(
    cx: &impl Context<'gcx>,
    node_id: NodeId,
    env: ParamEnv,
) -> Result<Type<'gcx>> {
    let hir = cx.hir_of(node_id)?;
    #[allow(unreachable_patterns)]
    match hir {
        HirNode::Port(p) => cx.map_to_type(p.ty, env),
        HirNode::Expr(e) => match e.kind {
            hir::ExprKind::IntConst(_) => Ok(cx.mkty_int(32)),
            hir::ExprKind::TimeConst(_) => Ok(cx.mkty_time()),
            hir::ExprKind::Ident(_) => cx.type_of(cx.resolve_node(node_id, env)?, env),
            hir::ExprKind::Unary(op, arg) => {
                let arg_ty = cx.type_of(arg, env)?;
                Ok(match op {
                    hir::UnaryOp::BitNot
                    | hir::UnaryOp::PreInc
                    | hir::UnaryOp::PreDec
                    | hir::UnaryOp::PostInc
                    | hir::UnaryOp::PostDec => arg_ty,
                    hir::UnaryOp::LogicNot => cx.mkty_bit(),
                    _ => return cx.unimp_msg("type analysis of", &hir),
                })
            }
            hir::ExprKind::Binary(op, lhs, rhs) => {
                let lhs_ty = cx.type_of(lhs, env)?;
                let _rhs_ty = cx.type_of(rhs, env)?;
                Ok(match op {
                    hir::BinaryOp::Add | hir::BinaryOp::Sub => lhs_ty,
                    hir::BinaryOp::Eq
                    | hir::BinaryOp::Neq
                    | hir::BinaryOp::Lt
                    | hir::BinaryOp::Leq
                    | hir::BinaryOp::Gt
                    | hir::BinaryOp::Geq
                    | hir::BinaryOp::LogicAnd
                    | hir::BinaryOp::LogicOr => cx.mkty_bit(),
                    _ => return cx.unimp_msg("type analysis of", &hir),
                })
            }
            _ => cx.unimp_msg("type analysis of", &hir),
        },
        HirNode::ValueParam(p) => {
            if is_explicit_type(cx, p.ty)? {
                return cx.map_to_type(p.ty, env);
            }
            let env_data = cx.param_env_data(env);
            match env_data.find_value(node_id) {
                Some(ParamEnvBinding::Indirect(assigned_id)) => {
                    return cx.type_of(assigned_id.0, assigned_id.1)
                }
                Some(ParamEnvBinding::Direct(t)) => return Ok(t.ty),
                _ => (),
            }
            if let Some(default) = p.default {
                return cx.type_of(default, env);
            }
            cx.emit(
                DiagBuilder2::error(format!(
                    "{} has implicit type but was not assigned and has no default",
                    p.desc_full()
                ))
                .span(p.human_span())
                .add_note("specify a type for the parameter; or")
                .add_note("add a default value for the parameter; or")
                .add_note("override the parameter from outside"),
            );
            Err(())
        }
        HirNode::VarDecl(d) => cx.map_to_type(d.ty, env),
        HirNode::GenvarDecl(_) => Ok(cx.mkty_int(32)),
        _ => cx.unimp_msg("type analysis of", &hir),
    }
}

/// Convert a node to a type.
pub(crate) fn map_to_type<'gcx>(
    cx: &impl Context<'gcx>,
    node_id: NodeId,
    env: ParamEnv,
) -> Result<Type<'gcx>> {
    let hir = cx.hir_of(node_id)?;
    #[allow(unreachable_patterns)]
    match hir {
        HirNode::Type(hir) => map_type_kind(cx, node_id, env, hir, &hir.kind),
        HirNode::TypeParam(param) => {
            let env_data = cx.param_env_data(env);
            match env_data.find_type(node_id) {
                Some(ParamEnvBinding::Indirect(assigned_id)) => {
                    return cx.map_to_type(assigned_id.0, assigned_id.1)
                }
                Some(ParamEnvBinding::Direct(t)) => return Ok(t),
                _ => (),
            }
            if let Some(default) = param.default {
                return cx.map_to_type(default, env);
            }
            let mut d = DiagBuilder2::error(format!(
                "{} not assigned and has no default",
                param.desc_full(),
            ));
            let contexts = cx.param_env_contexts(env);
            for &context in &contexts {
                d = d.span(cx.span(context));
            }
            if contexts.is_empty() {
                d = d.span(param.human_span());
            }
            cx.emit(d);
            Err(())
        }
        HirNode::Typedef(def) => cx.map_to_type(def.ty, env),
        _ => cx.unimp_msg("conversion to type of", &hir),
    }
}

/// Check if a type (given by its node id) is explicit.
fn is_explicit_type<'gcx>(cx: &impl Context<'gcx>, node_id: NodeId) -> Result<bool> {
    Ok(match cx.hir_of(node_id)? {
        HirNode::Type(x) => x.is_explicit(),
        _ => false,
    })
}

/// Map an HIR type into the type system.
///
/// This essentially converts `hir::TypeKind` to `Type`.
fn map_type_kind<'gcx>(
    cx: &impl Context<'gcx>,
    node_id: NodeId,
    env: ParamEnv,
    root: &hir::Type,
    kind: &hir::TypeKind,
) -> Result<Type<'gcx>> {
    #[allow(unreachable_patterns)]
    match *kind {
        hir::TypeKind::Builtin(hir::BuiltinType::Void) => Ok(cx.mkty_void()),
        hir::TypeKind::Builtin(hir::BuiltinType::Bit) => Ok(cx.mkty_bit()),
        hir::TypeKind::Builtin(hir::BuiltinType::Logic) => Ok(cx.mkty_logic()),
        hir::TypeKind::Builtin(hir::BuiltinType::Byte) => Ok(cx.mkty_int(8)),
        hir::TypeKind::Builtin(hir::BuiltinType::ShortInt) => Ok(cx.mkty_int(16)),
        hir::TypeKind::Builtin(hir::BuiltinType::Int) => Ok(cx.mkty_int(32)),
        hir::TypeKind::Builtin(hir::BuiltinType::LongInt) => Ok(cx.mkty_int(64)),
        hir::TypeKind::Named(name) => {
            let binding = cx.resolve_upwards_or_error(name, cx.parent_node_id(node_id).unwrap())?;
            Ok(cx.mkty_named(name, (binding, env)))
        }
        hir::TypeKind::Struct(..) => Ok(cx.mkty_struct(node_id)),
        // We should never request mapping of an implicit type. Rather, the
        // actual type should be mapped. Arriving here is a bug in the
        // calling function.
        hir::TypeKind::Implicit => unreachable!("implicit type not resolved"),
        _ => cx.unimp_msg("type analysis of", root),
    }
}
<|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/.

use std::io;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::ErrorKind;
use std::io::{Seek, Write, SeekFrom};
use std::fs::{OpenOptions, read_dir};
use std::os::unix::prelude::AsRawFd;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::thread;
use std::time::Duration;

use devicemapper::consts::SECTOR_SIZE;
use devicemapper::Device;
use devicemapper::Segment;
use devicemapper::{Bytes, Sectors};
use time::Timespec;
use uuid::Uuid;

use consts::IEC;
use engine::{DevUuid, EngineResult, EngineError, ErrorEnum, PoolUuid};
use super::metadata::{StaticHeader, BDA, validate_mda_size};
use super::engine::DevOwnership;
pub use super::BlockDevSave;

const MIN_DEV_SIZE: Bytes = Bytes(IEC::Gi as u64);

ioctl!(read blkgetsize64 with 0x12, 114; u64);

pub fn blkdev_size(file: &File) -> EngineResult<Bytes> {
    let mut val: u64 = 0;

    match unsafe { blkgetsize64(file.as_raw_fd(), &mut val) } {
        Err(x) => Err(EngineError::Nix(x)),
        Ok(_) => Ok(Bytes(val)),
    }
}

/// Resolve a list of Paths of some sort to a set of unique Devices.
/// Return an IOError if there was a problem resolving any particular device.
pub fn resolve_devices(paths: &[&Path]) -> io::Result<HashSet<Device>> {
    let mut devices = HashSet::new();
    for path in paths {
        let dev = try!(Device::from_str(&path.to_string_lossy()));
        devices.insert(dev);
    }
    Ok(devices)
}

/// Find all Stratis Blockdevs.
///
/// Returns a map of pool uuids to maps of blockdev uuids to blockdevs.
pub fn find_all() -> EngineResult<HashMap<PoolUuid, HashMap<DevUuid, BlockDev>>> {

    /// If a Path refers to a valid Stratis blockdev, return a BlockDev
    /// struct. Otherwise, return None. Return an error if there was
    /// a problem inspecting the device.
    fn setup(devnode: &Path) -> EngineResult<Option<BlockDev>> {
        let mut f = try!(OpenOptions::new()
            .read(true)
            .open(devnode));

        if let Some(bda) = BDA::load(&mut f).ok() {
            let dev = try!(Device::from_str(&devnode.to_string_lossy()));
            Ok(Some(BlockDev {
                dev: dev,
                devnode: devnode.to_owned(),
                bda: bda,
            }))
        } else {
            Ok(None)
        }
    }

    let mut pool_map = HashMap::new();
    for dir_e in try!(read_dir("/dev")) {
        let devnode = match dir_e {
            Ok(d) => d.path(),
            Err(_) => continue,
        };

        match setup(&devnode) {
            Ok(Some(blockdev)) => {
                pool_map.entry(blockdev.pool_uuid().clone())
                    .or_insert_with(HashMap::new)
                    .insert(blockdev.uuid().clone(), blockdev);
            }
            _ => continue,
        };
    }

    Ok(pool_map)
}

/// Write buf at offset length times.
pub fn write_sectors(path: &Path,
                     offset: Sectors,
                     length: Sectors,
                     buf: &[u8; SECTOR_SIZE])
                     -> EngineResult<()> {
    let mut f = try!(OpenOptions::new().write(true).open(path));

    try!(f.seek(SeekFrom::Start(*offset)));
    for _ in 0..*length {
        try!(f.write_all(buf));
    }

    try!(f.flush());
    Ok(())
}

/// Zero sectors at the given offset for length sectors.
pub fn wipe_sectors(path: &Path, offset: Sectors, length: Sectors) -> EngineResult<()> {
    write_sectors(path, offset, length, &[0u8; SECTOR_SIZE])
}

/// Initialize multiple blockdevs at once. This allows all of them
/// to be checked for usability before writing to any of them.
pub fn initialize(pool_uuid: &PoolUuid,
                  devices: HashSet<Device>,
                  mda_size: Sectors,
                  force: bool)
                  -> EngineResult<Vec<BlockDev>> {
    /// Gets device information, returns an error if problem with obtaining
    /// that information.
    /// Returns a tuple with the blockdev's path, its size in bytes,
    /// its ownership as determined by calling determine_ownership(),
    /// and an open File handle, all of which are needed later.
    fn dev_info(dev: &Device) -> EngineResult<(PathBuf, Bytes, DevOwnership, File)> {
        let devnode = try!(dev.devnode().ok_or_else(|| {
            io::Error::new(ErrorKind::InvalidInput,
                           format!("could not get device node from dev {}", dev.dstr()))
        }));
        let mut f = try!(OpenOptions::new()
            .read(true)
            .write(true)
            .open(&devnode)
            .map_err(|_| {
                io::Error::new(ErrorKind::PermissionDenied,
                               format!("Could not open {}", devnode.display()))
            }));

        let dev_size = try!(blkdev_size(&f));

        let ownership = match StaticHeader::determine_ownership(&mut f) {
            Ok(ownership) => ownership,
            Err(err) => {
                let error_message = format!("{} for device {}", err, devnode.display());
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            }
        };

        Ok((devnode, dev_size, ownership, f))
    }

    /// Filter devices for admission to pool based on dev_infos.
    /// If there is an error finding out the info, return that error.
    /// Also, return an error if a device is not appropriate for this pool.
    fn filter_devs<I>(dev_infos: I,
                      pool_uuid: &PoolUuid,
                      force: bool)
                      -> EngineResult<Vec<(Device, (PathBuf, Bytes, File))>>
        where I: Iterator<Item = (Device, EngineResult<(PathBuf, Bytes, DevOwnership, File)>)>
    {
        let mut add_devs = Vec::new();
        for (dev, dev_result) in dev_infos {
            let (devnode, dev_size, ownership, f) = try!(dev_result);
            if dev_size < MIN_DEV_SIZE {
                let error_message = format!("{} too small, minimum {} bytes",
                                            devnode.display(),
                                            MIN_DEV_SIZE);
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            };
            match ownership {
                DevOwnership::Unowned => add_devs.push((dev, (devnode, dev_size, f))),
                DevOwnership::Theirs => {
                    if !force {
                        let error_str = format!("First 8K of {} not zeroed", devnode.display());
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    } else {
                        add_devs.push((dev, (devnode, dev_size, f)))
                    }
                }
                DevOwnership::Ours(uuid) => {
                    if *pool_uuid != uuid {
                        let error_str = format!("Device {} already belongs to Stratis pool {}",
                                                devnode.display(),
                                                uuid);
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    }
                }
            }
        }
        Ok(add_devs)
    }

    try!(validate_mda_size(mda_size));

    let dev_infos = devices.into_iter().map(|d: Device| (d, dev_info(&d)));

    let add_devs = try!(filter_devs(dev_infos, pool_uuid, force));

    // TODO: Fix this code.  We should deal with any number of blockdevs
    //
    if add_devs.len() < 2 {
        return Err(EngineError::Engine(ErrorEnum::Error,
                                       "Need at least 2 blockdevs to create a pool".into()));
    }

    let mut bds = Vec::new();
    for (dev, (devnode, dev_size, mut f)) in add_devs {

        let bda = try!(BDA::initialize(&mut f,
                                       pool_uuid,
                                       &Uuid::new_v4(),
                                       mda_size,
                                       dev_size.sectors()));

        let bd = BlockDev {
            dev: dev,
            devnode: devnode.clone(),
            bda: bda,
        };
        bds.push(bd);
    }
    Ok(bds)
}

#[derive(Debug)]
pub struct BlockDev {
    dev: Device,
    pub devnode: PathBuf,
    bda: BDA,
}

impl BlockDev {
    pub fn to_save(&self) -> BlockDevSave {
        BlockDevSave {
            devnode: self.devnode.clone(),
            total_size: self.size(),
        }
    }

    pub fn wipe_metadata(self) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        BDA::wipe(&mut f)
    }

    /// Get the "x:y" device string for this blockdev
    pub fn dstr(&self) -> String {
        self.dev.dstr()
    }

    pub fn save_state(&mut self, time: &Timespec, metadata: &[u8]) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        self.bda.save_state(time, metadata, &mut f)
    }

    pub fn load_state(&self) -> EngineResult<Option<Vec<u8>>> {
        let mut f = try!(OpenOptions::new().read(true).open(&self.devnode));
        self.bda.load_state(&mut f)
    }

    /// List the available-for-upper-layer-use range in this blockdev.
    fn avail_range(&self) -> (Sectors, Sectors) {
        let start = self.bda.size();
        let size = self.size();
        // Blockdev size is at least MIN_DEV_SIZE, so this can fail only if
        // size of metadata area exceeds 1 GiB. Initial metadata area size
        // is 4 MiB.
        assert!(start <= size);
        (start, size - start)
    }

    /// Return the available range as a segment
    pub fn avail_range_segment(&self) -> Segment {
        let (start, length) = self.avail_range();
        Segment::new(self.dev, start, length)
    }

    /// The /dev/mapper/<name> device is not immediately available for use.
    /// TODO: Implement wait for event or poll.
    pub fn wait_for_dm() {
        thread::sleep(Duration::from_millis(500))
    }

    /// The device's UUID.
    pub fn uuid(&self) -> &DevUuid {
        self.bda.dev_uuid()
    }

    /// The device's pool's UUID.
    pub fn pool_uuid(&self) -> &PoolUuid {
        self.bda.pool_uuid()
    }

    /// The device's size.
    pub fn size(&self) -> Sectors {
        self.bda.dev_size()
    }

    /// Last time metadata was written to this device.
    pub fn last_update_time(&self) -> Option<&Timespec> {
        self.bda.last_update_time()
    }
}
<commit_msg>Use RangeAllocator in BlockDev<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::io;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::ErrorKind;
use std::io::{Seek, Write, SeekFrom};
use std::fs::{OpenOptions, read_dir};
use std::os::unix::prelude::AsRawFd;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::thread;
use std::time::Duration;

use devicemapper::consts::SECTOR_SIZE;
use devicemapper::Device;
use devicemapper::Segment;
use devicemapper::{Bytes, Sectors};
use time::Timespec;
use uuid::Uuid;

use consts::IEC;
use engine::{DevUuid, EngineResult, EngineError, ErrorEnum, PoolUuid};
use super::metadata::{StaticHeader, BDA, validate_mda_size};
use super::engine::DevOwnership;
pub use super::BlockDevSave;
use engine::strat_engine::range_alloc::RangeAllocator;

const MIN_DEV_SIZE: Bytes = Bytes(IEC::Gi as u64);

ioctl!(read blkgetsize64 with 0x12, 114; u64);

pub fn blkdev_size(file: &File) -> EngineResult<Bytes> {
    let mut val: u64 = 0;

    match unsafe { blkgetsize64(file.as_raw_fd(), &mut val) } {
        Err(x) => Err(EngineError::Nix(x)),
        Ok(_) => Ok(Bytes(val)),
    }
}

/// Resolve a list of Paths of some sort to a set of unique Devices.
/// Return an IOError if there was a problem resolving any particular device.
pub fn resolve_devices(paths: &[&Path]) -> io::Result<HashSet<Device>> {
    let mut devices = HashSet::new();
    for path in paths {
        let dev = try!(Device::from_str(&path.to_string_lossy()));
        devices.insert(dev);
    }
    Ok(devices)
}

/// Find all Stratis Blockdevs.
///
/// Returns a map of pool uuids to maps of blockdev uuids to blockdevs.
pub fn find_all() -> EngineResult<HashMap<PoolUuid, HashMap<DevUuid, BlockDev>>> {

    /// If a Path refers to a valid Stratis blockdev, return a BlockDev
    /// struct. Otherwise, return None. Return an error if there was
    /// a problem inspecting the device.
    fn setup(devnode: &Path) -> EngineResult<Option<BlockDev>> {
        let mut f = try!(OpenOptions::new()
            .read(true)
            .open(devnode));

        if let Some(bda) = BDA::load(&mut f).ok() {
            let dev = try!(Device::from_str(&devnode.to_string_lossy()));
            // TODO: Parse MDA and also initialize RangeAllocator with
            // in-use regions
            let allocator = RangeAllocator::new_with_used(bda.dev_size(),
                                                          &[(Sectors(0), bda.size())]);
            Ok(Some(BlockDev {
                dev: dev,
                devnode: devnode.to_owned(),
                bda: bda,
                used: allocator,
            }))
        } else {
            Ok(None)
        }
    }

    let mut pool_map = HashMap::new();
    for dir_e in try!(read_dir("/dev")) {
        let devnode = match dir_e {
            Ok(d) => d.path(),
            Err(_) => continue,
        };

        match setup(&devnode) {
            Ok(Some(blockdev)) => {
                pool_map.entry(blockdev.pool_uuid().clone())
                    .or_insert_with(HashMap::new)
                    .insert(blockdev.uuid().clone(), blockdev);
            }
            _ => continue,
        };
    }

    Ok(pool_map)
}

/// Write buf at offset length times.
pub fn write_sectors(path: &Path,
                     offset: Sectors,
                     length: Sectors,
                     buf: &[u8; SECTOR_SIZE])
                     -> EngineResult<()> {
    let mut f = try!(OpenOptions::new().write(true).open(path));

    try!(f.seek(SeekFrom::Start(*offset)));
    for _ in 0..*length {
        try!(f.write_all(buf));
    }

    try!(f.flush());
    Ok(())
}

/// Zero sectors at the given offset for length sectors.
pub fn wipe_sectors(path: &Path, offset: Sectors, length: Sectors) -> EngineResult<()> {
    write_sectors(path, offset, length, &[0u8; SECTOR_SIZE])
}

/// Initialize multiple blockdevs at once. This allows all of them
/// to be checked for usability before writing to any of them.
pub fn initialize(pool_uuid: &PoolUuid,
                  devices: HashSet<Device>,
                  mda_size: Sectors,
                  force: bool)
                  -> EngineResult<Vec<BlockDev>> {
    /// Gets device information, returns an error if problem with obtaining
    /// that information.
    /// Returns a tuple with the blockdev's path, its size in bytes,
    /// its ownership as determined by calling determine_ownership(),
    /// and an open File handle, all of which are needed later.
    fn dev_info(dev: &Device) -> EngineResult<(PathBuf, Bytes, DevOwnership, File)> {
        let devnode = try!(dev.devnode().ok_or_else(|| {
            io::Error::new(ErrorKind::InvalidInput,
                           format!("could not get device node from dev {}", dev.dstr()))
        }));
        let mut f = try!(OpenOptions::new()
            .read(true)
            .write(true)
            .open(&devnode)
            .map_err(|_| {
                io::Error::new(ErrorKind::PermissionDenied,
                               format!("Could not open {}", devnode.display()))
            }));

        let dev_size = try!(blkdev_size(&f));

        let ownership = match StaticHeader::determine_ownership(&mut f) {
            Ok(ownership) => ownership,
            Err(err) => {
                let error_message = format!("{} for device {}", err, devnode.display());
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            }
        };

        Ok((devnode, dev_size, ownership, f))
    }

    /// Filter devices for admission to pool based on dev_infos.
    /// If there is an error finding out the info, return that error.
    /// Also, return an error if a device is not appropriate for this pool.
    fn filter_devs<I>(dev_infos: I,
                      pool_uuid: &PoolUuid,
                      force: bool)
                      -> EngineResult<Vec<(Device, (PathBuf, Bytes, File))>>
        where I: Iterator<Item = (Device, EngineResult<(PathBuf, Bytes, DevOwnership, File)>)>
    {
        let mut add_devs = Vec::new();
        for (dev, dev_result) in dev_infos {
            let (devnode, dev_size, ownership, f) = try!(dev_result);
            if dev_size < MIN_DEV_SIZE {
                let error_message = format!("{} too small, minimum {} bytes",
                                            devnode.display(),
                                            MIN_DEV_SIZE);
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            };
            match ownership {
                DevOwnership::Unowned => add_devs.push((dev, (devnode, dev_size, f))),
                DevOwnership::Theirs => {
                    if !force {
                        let error_str = format!("First 8K of {} not zeroed", devnode.display());
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    } else {
                        add_devs.push((dev, (devnode, dev_size, f)))
                    }
                }
                DevOwnership::Ours(uuid) => {
                    if *pool_uuid != uuid {
                        let error_str = format!("Device {} already belongs to Stratis pool {}",
                                                devnode.display(),
                                                uuid);
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    }
                }
            }
        }
        Ok(add_devs)
    }

    try!(validate_mda_size(mda_size));

    let dev_infos = devices.into_iter().map(|d: Device| (d, dev_info(&d)));

    let add_devs = try!(filter_devs(dev_infos, pool_uuid, force));

    // TODO: Fix this code.  We should deal with any number of blockdevs
    //
    if add_devs.len() < 2 {
        return Err(EngineError::Engine(ErrorEnum::Error,
                                       "Need at least 2 blockdevs to create a pool".into()));
    }

    let mut bds = Vec::new();
    for (dev, (devnode, dev_size, mut f)) in add_devs {

        let bda = try!(BDA::initialize(&mut f,
                                       pool_uuid,
                                       &Uuid::new_v4(),
                                       mda_size,
                                       dev_size.sectors()));
        let allocator = RangeAllocator::new_with_used(bda.dev_size(), &[(Sectors(0), bda.size())]);

        let bd = BlockDev {
            dev: dev,
            devnode: devnode.clone(),
            bda: bda,
            used: allocator,
        };
        bds.push(bd);
    }
    Ok(bds)
}

#[derive(Debug)]
pub struct BlockDev {
    dev: Device,
    pub devnode: PathBuf,
    bda: BDA,
    used: RangeAllocator,
}

impl BlockDev {
    pub fn to_save(&self) -> BlockDevSave {
        BlockDevSave {
            devnode: self.devnode.clone(),
            total_size: self.size(),
        }
    }

    pub fn wipe_metadata(self) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        BDA::wipe(&mut f)
    }

    /// Get the "x:y" device string for this blockdev
    pub fn dstr(&self) -> String {
        self.dev.dstr()
    }

    pub fn save_state(&mut self, time: &Timespec, metadata: &[u8]) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        self.bda.save_state(time, metadata, &mut f)
    }

    pub fn load_state(&self) -> EngineResult<Option<Vec<u8>>> {
        let mut f = try!(OpenOptions::new().read(true).open(&self.devnode));
        self.bda.load_state(&mut f)
    }

    /// List the available-for-upper-layer-use range in this blockdev.
    fn avail_range(&self) -> (Sectors, Sectors) {
        let start = self.bda.size();
        let size = self.size();
        // Blockdev size is at least MIN_DEV_SIZE, so this can fail only if
        // size of metadata area exceeds 1 GiB. Initial metadata area size
        // is 4 MiB.
        assert!(start <= size);
        (start, size - start)
    }

    /// Return the available range as a segment
    pub fn avail_range_segment(&self) -> Segment {
        let (start, length) = self.avail_range();
        Segment::new(self.dev, start, length)
    }

    /// The /dev/mapper/<name> device is not immediately available for use.
    /// TODO: Implement wait for event or poll.
    pub fn wait_for_dm() {
        thread::sleep(Duration::from_millis(500))
    }

    /// The device's UUID.
    pub fn uuid(&self) -> &DevUuid {
        self.bda.dev_uuid()
    }

    /// The device's pool's UUID.
    pub fn pool_uuid(&self) -> &PoolUuid {
        self.bda.pool_uuid()
    }

    /// The device's size.
    pub fn size(&self) -> Sectors {
        self.bda.dev_size()
    }

    /// Last time metadata was written to this device.
    pub fn last_update_time(&self) -> Option<&Timespec> {
        self.bda.last_update_time()
    }

    pub fn available(&self) -> Sectors {
        self.used.available()
    }

    // Find some sector ranges that could be allocated. If more
    // sectors are needed than our capacity, return partial results.
    pub fn request_space(&mut self, size: Sectors) -> (Sectors, Vec<(Sectors, Sectors)>) {
        self.used.request(size)
    }
}
<|endoftext|>


<commit_before>use ::{ NifTerm, NifEnv, NifEncoder, NifDecoder, NifResult, NifError };
use super::binary::{ NifBinary, OwnedNifBinary };

impl<'a> NifDecoder<'a> for String {
    fn decode(term: NifTerm<'a>) -> NifResult<Self> {
        let string: &str = try!(NifDecoder::decode(term));
        Ok(string.to_string())
    }
}
impl<'a> NifDecoder<'a> for &'a str {
    fn decode(term: NifTerm<'a>) -> NifResult<Self> {
        let binary = try!(NifBinary::from_term(term));
        match ::std::str::from_utf8(binary.as_slice()) {
            Ok(string) => Ok(string),
            Err(_) => Err(NifError::BadArg),
        }
    }
}

use std::io::Write;

impl NifEncoder for str {
    fn encode<'b>(&self, env: NifEnv<'b>) -> NifTerm<'b> {
        let str_len = self.len();
        let mut bin = match OwnedNifBinary::new(str_len) {
            Some(bin) => bin,
            None => panic!("binary term allocation fail"),
        };
        bin.as_mut_slice().write(self.as_bytes()).expect("memory copy of string failed");
        bin.release(env).to_term(env)
    }
}
<commit_msg>implement NifEncoder for String<commit_after>use ::{ NifTerm, NifEnv, NifEncoder, NifDecoder, NifResult, NifError };
use super::binary::{ NifBinary, OwnedNifBinary };

impl<'a> NifDecoder<'a> for String {
    fn decode(term: NifTerm<'a>) -> NifResult<Self> {
        let string: &str = try!(NifDecoder::decode(term));
        Ok(string.to_string())
    }
}
impl<'a> NifDecoder<'a> for &'a str {
    fn decode(term: NifTerm<'a>) -> NifResult<Self> {
        let binary = try!(NifBinary::from_term(term));
        match ::std::str::from_utf8(binary.as_slice()) {
            Ok(string) => Ok(string),
            Err(_) => Err(NifError::BadArg),
        }
    }
}

use std::io::Write;

impl NifEncoder for str {
    fn encode<'b>(&self, env: NifEnv<'b>) -> NifTerm<'b> {
        let str_len = self.len();
        let mut bin = match OwnedNifBinary::new(str_len) {
            Some(bin) => bin,
            None => panic!("binary term allocation fail"),
        };
        bin.as_mut_slice().write(self.as_bytes()).expect("memory copy of string failed");
        bin.release(env).to_term(env)
    }
}

impl NifEncoder for String {
    fn encode<'b>(&self, env: NifEnv<'b>) -> NifTerm<'b> {
        self.as_str().encode(env)
    }
}
<|endoftext|>


<commit_before>use crate::convert::Convert;
use crate::operations::*;
use crate::AHasher;
use core::hash::BuildHasher;
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering;

#[cfg(all(feature = "compile-time-rng", not(test)))]
use const_random::const_random;

///This constant come from Kunth's prng
pub(crate) const MULTIPLE: u64 = 6364136223846793005;
pub(crate) const INCREMENT: u64 = 1442695040888963407;

// Const random provides randomized starting key with no runtime cost.
#[cfg(all(feature = "compile-time-rng", not(test)))]
pub(crate) const INIT_SEED: [u64; 2] = [const_random!(u64), const_random!(u64)];

#[cfg(any(not(feature = "compile-time-rng"), test))]
pub(crate) const INIT_SEED: [u64; 2] = [0x2360_ED05_1FC6_5DA4, 0x4385_DF64_9FCC_F645]; //From PCG-64

#[cfg(all(feature = "compile-time-rng", not(test)))]
static SEED: AtomicUsize = AtomicUsize::new(const_random!(u64) as usize);

#[cfg(any(not(feature = "compile-time-rng"), test))]
static SEED: AtomicUsize = AtomicUsize::new(INCREMENT as usize);

/// Provides a [Hasher] factory. This is typically used (e.g. by [HashMap]) to create
/// [AHasher]s in order to hash the keys of the map. See `build_hasher` below.
///
/// [build_hasher]: ahash::
/// [Hasher]: std::hash::Hasher
/// [BuildHasher]: std::hash::BuildHasher
/// [HashMap]: std::collections::HashMap
#[derive(Clone)]
pub struct RandomState {
    pub(crate) k0: u64,
    pub(crate) k1: u64,
    pub(crate) k2: u64,
    pub(crate) k3: u64,
}

impl RandomState {
    #[inline]
    pub fn new() -> RandomState {
        //Using a self pointer. When running with ASLR this is a random value.
        let previous = SEED.load(Ordering::Relaxed) as u64;
        let stack_mem_loc = &previous as *const _ as u64;
        //This is similar to the update function in the fallback.
        //only one multiply is needed because memory locations are not under an attackers control.
        let current_seed = previous
            .wrapping_add(stack_mem_loc)
            .wrapping_mul(MULTIPLE)
            .rotate_right(31);
        SEED.store(current_seed as usize, Ordering::Relaxed);
        let (k0, k1, k2, k3) = scramble_keys(&SEED as *const _ as u64, current_seed);
        RandomState { k0, k1, k2, k3 }
    }

    /// Allows for explicitly setting the seeds to used.
    pub fn with_seeds(k0: u64, k1: u64) -> RandomState {
        let (k0, k1, k2, k3) = scramble_keys(k0, k1);
        RandomState { k0, k1, k2, k3 }
    }
}

/// This is based on the fallback hasher
#[inline]
pub(crate) fn scramble_keys(a: u64, b: u64) -> (u64, u64, u64, u64) {
    let k1 = (INIT_SEED[0] ^ a).folded_multiply(MULTIPLE).wrapping_add(b);
    let k2 = (INIT_SEED[0] ^ b).folded_multiply(MULTIPLE).wrapping_add(a);
    let k3 = (INIT_SEED[1] ^ a).folded_multiply(MULTIPLE).wrapping_add(b);
    let k4 = (INIT_SEED[1] ^ b).folded_multiply(MULTIPLE).wrapping_add(a);
    let combined = (a ^ b).folded_multiply(MULTIPLE).wrapping_add(INCREMENT);
    let rot1 = (combined & 63) as u32;
    let rot2 = ((combined >> 16) & 63) as u32;
    let rot3 = ((combined >> 32) & 63) as u32;
    let rot4 = ((combined >> 48) & 63) as u32;
    (
        k1.rotate_left(rot1),
        k2.rotate_left(rot2),
        k3.rotate_left(rot3),
        k4.rotate_left(rot4),
    )
}

impl Default for RandomState {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl BuildHasher for RandomState {
    type Hasher = AHasher;

    /// Constructs a new [AHasher] with keys based on compile time generated constants** and the location
    /// this object was constructed at in memory. This means that two different [BuildHasher]s will will generate
    /// [AHasher]s that will return different hashcodes, but [Hasher]s created from the same [BuildHasher]
    /// will generate the same hashes for the same input data.
    ///
    /// ** - only if the `compile-time-rng` feature is enabled.
    ///
    /// # Examples
    ///
    /// ```
    /// use ahash::{AHasher, RandomState};
    /// use std::hash::{Hasher, BuildHasher};
    ///
    /// let build_hasher = RandomState::new();
    /// let mut hasher_1 = build_hasher.build_hasher();
    /// let mut hasher_2 = build_hasher.build_hasher();
    ///
    /// hasher_1.write_u32(1234);
    /// hasher_2.write_u32(1234);
    ///
    /// assert_eq!(hasher_1.finish(), hasher_2.finish());
    ///
    /// let other_build_hasher = RandomState::new();
    /// let mut different_hasher = other_build_hasher.build_hasher();
    /// different_hasher.write_u32(1234);
    /// assert_ne!(different_hasher.finish(), hasher_1.finish());
    /// ```
    /// [Hasher]: std::hash::Hasher
    /// [BuildHasher]: std::hash::BuildHasher
    /// [HashMap]: std::collections::HashMap
    #[inline]
    fn build_hasher(&self) -> AHasher {
        AHasher::new_with_keys([self.k0, self.k1].convert(), [self.k2, self.k3].convert())
    }
}

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

    #[test]
    fn test_const_rand_disabled() {
        assert_eq!(INIT_SEED, [0x2360_ED05_1FC6_5DA4, 0x4385_DF64_9FCC_F645]);
    }
}
<commit_msg>Add Debug impl to RandomState<commit_after>use crate::convert::Convert;
use crate::operations::*;
use crate::AHasher;
use core::hash::BuildHasher;
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering;

#[cfg(all(feature = "compile-time-rng", not(test)))]
use const_random::const_random;

///This constant come from Kunth's prng
pub(crate) const MULTIPLE: u64 = 6364136223846793005;
pub(crate) const INCREMENT: u64 = 1442695040888963407;

// Const random provides randomized starting key with no runtime cost.
#[cfg(all(feature = "compile-time-rng", not(test)))]
pub(crate) const INIT_SEED: [u64; 2] = [const_random!(u64), const_random!(u64)];

#[cfg(any(not(feature = "compile-time-rng"), test))]
pub(crate) const INIT_SEED: [u64; 2] = [0x2360_ED05_1FC6_5DA4, 0x4385_DF64_9FCC_F645]; //From PCG-64

#[cfg(all(feature = "compile-time-rng", not(test)))]
static SEED: AtomicUsize = AtomicUsize::new(const_random!(u64) as usize);

#[cfg(any(not(feature = "compile-time-rng"), test))]
static SEED: AtomicUsize = AtomicUsize::new(INCREMENT as usize);

/// Provides a [Hasher] factory. This is typically used (e.g. by [HashMap]) to create
/// [AHasher]s in order to hash the keys of the map. See `build_hasher` below.
///
/// [build_hasher]: ahash::
/// [Hasher]: std::hash::Hasher
/// [BuildHasher]: std::hash::BuildHasher
/// [HashMap]: std::collections::HashMap
#[derive(Debug, Clone)]
pub struct RandomState {
    pub(crate) k0: u64,
    pub(crate) k1: u64,
    pub(crate) k2: u64,
    pub(crate) k3: u64,
}

impl RandomState {
    #[inline]
    pub fn new() -> RandomState {
        //Using a self pointer. When running with ASLR this is a random value.
        let previous = SEED.load(Ordering::Relaxed) as u64;
        let stack_mem_loc = &previous as *const _ as u64;
        //This is similar to the update function in the fallback.
        //only one multiply is needed because memory locations are not under an attackers control.
        let current_seed = previous
            .wrapping_add(stack_mem_loc)
            .wrapping_mul(MULTIPLE)
            .rotate_right(31);
        SEED.store(current_seed as usize, Ordering::Relaxed);
        let (k0, k1, k2, k3) = scramble_keys(&SEED as *const _ as u64, current_seed);
        RandomState { k0, k1, k2, k3 }
    }

    /// Allows for explicitly setting the seeds to used.
    pub fn with_seeds(k0: u64, k1: u64) -> RandomState {
        let (k0, k1, k2, k3) = scramble_keys(k0, k1);
        RandomState { k0, k1, k2, k3 }
    }
}

/// This is based on the fallback hasher
#[inline]
pub(crate) fn scramble_keys(a: u64, b: u64) -> (u64, u64, u64, u64) {
    let k1 = (INIT_SEED[0] ^ a).folded_multiply(MULTIPLE).wrapping_add(b);
    let k2 = (INIT_SEED[0] ^ b).folded_multiply(MULTIPLE).wrapping_add(a);
    let k3 = (INIT_SEED[1] ^ a).folded_multiply(MULTIPLE).wrapping_add(b);
    let k4 = (INIT_SEED[1] ^ b).folded_multiply(MULTIPLE).wrapping_add(a);
    let combined = (a ^ b).folded_multiply(MULTIPLE).wrapping_add(INCREMENT);
    let rot1 = (combined & 63) as u32;
    let rot2 = ((combined >> 16) & 63) as u32;
    let rot3 = ((combined >> 32) & 63) as u32;
    let rot4 = ((combined >> 48) & 63) as u32;
    (
        k1.rotate_left(rot1),
        k2.rotate_left(rot2),
        k3.rotate_left(rot3),
        k4.rotate_left(rot4),
    )
}

impl Default for RandomState {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl BuildHasher for RandomState {
    type Hasher = AHasher;

    /// Constructs a new [AHasher] with keys based on compile time generated constants** and the location
    /// this object was constructed at in memory. This means that two different [BuildHasher]s will will generate
    /// [AHasher]s that will return different hashcodes, but [Hasher]s created from the same [BuildHasher]
    /// will generate the same hashes for the same input data.
    ///
    /// ** - only if the `compile-time-rng` feature is enabled.
    ///
    /// # Examples
    ///
    /// ```
    /// use ahash::{AHasher, RandomState};
    /// use std::hash::{Hasher, BuildHasher};
    ///
    /// let build_hasher = RandomState::new();
    /// let mut hasher_1 = build_hasher.build_hasher();
    /// let mut hasher_2 = build_hasher.build_hasher();
    ///
    /// hasher_1.write_u32(1234);
    /// hasher_2.write_u32(1234);
    ///
    /// assert_eq!(hasher_1.finish(), hasher_2.finish());
    ///
    /// let other_build_hasher = RandomState::new();
    /// let mut different_hasher = other_build_hasher.build_hasher();
    /// different_hasher.write_u32(1234);
    /// assert_ne!(different_hasher.finish(), hasher_1.finish());
    /// ```
    /// [Hasher]: std::hash::Hasher
    /// [BuildHasher]: std::hash::BuildHasher
    /// [HashMap]: std::collections::HashMap
    #[inline]
    fn build_hasher(&self) -> AHasher {
        AHasher::new_with_keys([self.k0, self.k1].convert(), [self.k2, self.k3].convert())
    }
}

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

    #[test]
    fn test_const_rand_disabled() {
        assert_eq!(INIT_SEED, [0x2360_ED05_1FC6_5DA4, 0x4385_DF64_9FCC_F645]);
    }
}
<|endoftext|>


<commit_before>//! Contains result and error type for FBX reader.

extern crate byteorder;

use std::io;
use std::string;
use std::fmt;

/// A specialized `std::result::Result` type for FBX parsing.
pub type Result<T> = ::std::result::Result<T, Error>;

/// An FBX parsing error.
#[derive(Debug)]
pub struct Error {
    /// Last position of successfully read data when an error detected.
    pos: u64,
    /// Error type.
    kind: ErrorKind,
}

impl Error {
    /// Constructs `Error` with position and objects which can be converted to `ErrorKind`.
    pub fn new<K: Into<ErrorKind>>(pos: u64, kind: K) -> Self {
        Error {
            pos: pos,
            kind: kind.into(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            ErrorKind::FromUtf8Error(ref err) => write!(f, "UTF-8 conversion error at pos={}: {}", self.pos, err),
            ErrorKind::InvalidMagic => write!(f, "Invalid magic header at pos={}: Non-FBX or corrupted data?", self.pos),
            ErrorKind::Io(ref err) => write!(f, "I/O error at pos={}: {}", self.pos, err),
            ErrorKind::DataError(ref err) => write!(f, "Invalid data at pos={}: {}", self.pos, err),
            ErrorKind::UnexpectedValue(ref err) => write!(f, "Got an unexpected value at pos={}: {}", self.pos, err),
            ErrorKind::UnexpectedEof => write!(f, "Unexpected EOF at pos={}", self.pos),
            ErrorKind::Unimplemented(ref err) => write!(f, "Unimplemented feature: {}", err),
        }
    }
}

/// Error type.
#[derive(Debug)]
pub enum ErrorKind {
    /// Conversion from array of u8 to String failed.
    FromUtf8Error(string::FromUtf8Error),
    /// Invalid magic binary detected.
    InvalidMagic,
    /// I/O operation error.
    Io(io::Error),
    /// Corrupted or inconsistent FBX data detected.
    DataError(String),
    /// Got an unexpected value, and cannot continue parsing.
    ///
    /// This is specialization of `DataError`.
    UnexpectedValue(String),
    /// Reached unexpected EOF.
    UnexpectedEof,
    /// Attempted to use unimplemented feature.
    Unimplemented(String),
}

impl From<string::FromUtf8Error> for ErrorKind {
    fn from(err: string::FromUtf8Error) -> ErrorKind {
        ErrorKind::FromUtf8Error(err)
    }
}

impl From<io::Error> for ErrorKind {
    fn from(err: io::Error) -> ErrorKind {
        // TODO: `io::Error::UnexpectedEof` should be converted to `ErrorKind::UnexpectedEof`.
        ErrorKind::Io(err)
    }
}

impl From<byteorder::Error> for ErrorKind {
    fn from(err: byteorder::Error) -> ErrorKind {
        match err {
            byteorder::Error::UnexpectedEOF => ErrorKind::UnexpectedEof,
            byteorder::Error::Io(err) => ErrorKind::Io(err),
        }
    }
}
<commit_msg>Implement `std::error::Error` trait for `reader::error::Error`<commit_after>//! Contains result and error type for FBX reader.

extern crate byteorder;

use std::io;
use std::string;
use std::fmt;

/// A specialized `std::result::Result` type for FBX parsing.
pub type Result<T> = ::std::result::Result<T, Error>;

/// An FBX parsing error.
#[derive(Debug)]
pub struct Error {
    /// Last position of successfully read data when an error detected.
    pos: u64,
    /// Error type.
    kind: ErrorKind,
}

impl Error {
    /// Constructs `Error` with position and objects which can be converted to `ErrorKind`.
    pub fn new<K: Into<ErrorKind>>(pos: u64, kind: K) -> Self {
        Error {
            pos: pos,
            kind: kind.into(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            ErrorKind::FromUtf8Error(ref err) => write!(f, "UTF-8 conversion error at pos={}: {}", self.pos, err),
            ErrorKind::InvalidMagic => write!(f, "Invalid magic header at pos={}: Non-FBX or corrupted data?", self.pos),
            ErrorKind::Io(ref err) => write!(f, "I/O error at pos={}: {}", self.pos, err),
            ErrorKind::DataError(ref err) => write!(f, "Invalid data at pos={}: {}", self.pos, err),
            ErrorKind::UnexpectedValue(ref err) => write!(f, "Got an unexpected value at pos={}: {}", self.pos, err),
            ErrorKind::UnexpectedEof => write!(f, "Unexpected EOF at pos={}", self.pos),
            ErrorKind::Unimplemented(ref err) => write!(f, "Unimplemented feature: {}", err),
        }
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        match self.kind {
            ErrorKind::FromUtf8Error(ref err) => err.description(),
            ErrorKind::InvalidMagic => "Got an invalid magic header",
            ErrorKind::Io(ref err) => err.description(),
            ErrorKind::DataError(_) => "Got an invalid data",
            ErrorKind::UnexpectedValue(_) => "Invalid value in FBX data",
            ErrorKind::UnexpectedEof => "Unexpected EOF",
            ErrorKind::Unimplemented(_) => "Attempt to use unimplemented feature",
        }
    }
}

/// Error type.
#[derive(Debug)]
pub enum ErrorKind {
    /// Conversion from array of u8 to String failed.
    FromUtf8Error(string::FromUtf8Error),
    /// Invalid magic binary detected.
    InvalidMagic,
    /// I/O operation error.
    Io(io::Error),
    /// Corrupted or inconsistent FBX data detected.
    DataError(String),
    /// Got an unexpected value, and cannot continue parsing.
    ///
    /// This is specialization of `DataError`.
    UnexpectedValue(String),
    /// Reached unexpected EOF.
    UnexpectedEof,
    /// Attempted to use unimplemented feature.
    Unimplemented(String),
}

impl From<string::FromUtf8Error> for ErrorKind {
    fn from(err: string::FromUtf8Error) -> ErrorKind {
        ErrorKind::FromUtf8Error(err)
    }
}

impl From<io::Error> for ErrorKind {
    fn from(err: io::Error) -> ErrorKind {
        // TODO: `io::Error::UnexpectedEof` should be converted to `ErrorKind::UnexpectedEof`.
        ErrorKind::Io(err)
    }
}

impl From<byteorder::Error> for ErrorKind {
    fn from(err: byteorder::Error) -> ErrorKind {
        match err {
            byteorder::Error::UnexpectedEOF => ErrorKind::UnexpectedEof,
            byteorder::Error::Io(err) => ErrorKind::Io(err),
        }
    }
}
<|endoftext|>


<commit_before>use super::item::ItemInfo;
use super::Parser;

use crate::{new_sub_parser_from_file, DirectoryOwnership};

use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod};
use rustc_ast::attr;
use rustc_ast::token::{self, TokenKind};
use rustc_errors::{struct_span_err, PResult};
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{FileName, Span, DUMMY_SP};
use rustc_span::symbol::sym;

use std::path::{self, Path, PathBuf};

/// Information about the path to a module.
// Public for rustfmt usage.
pub struct ModulePath<'a> {
    name: String,
    path_exists: bool,
    pub result: PResult<'a, ModulePathSuccess>,
}

// Public for rustfmt usage.
pub struct ModulePathSuccess {
    pub path: PathBuf,
    pub directory_ownership: DirectoryOwnership,
}

impl<'a> Parser<'a> {
    /// Parses a source module as a crate. This is the main entry point for the parser.
    pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> {
        let lo = self.token.span;
        let (module, attrs) = self.parse_mod(&token::Eof)?;
        let span = lo.to(self.token.span);
        let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`.
        Ok(ast::Crate { attrs, module, span, proc_macros })
    }

    /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
    pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
        let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs);

        let id = self.parse_ident()?;
        let (module, mut inner_attrs) = if self.eat(&token::Semi) {
            if in_cfg && self.recurse_into_file_modules {
                // This mod is in an external file. Let's go get it!
                let ModulePathSuccess { path, directory_ownership } = submod_path(
                    self.sess,
                    id,
                    &attrs,
                    self.directory.ownership,
                    &self.directory.path,
                )?;
                self.eval_src_mod(path, directory_ownership, id.to_string(), id.span)?
            } else {
                (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new())
            }
        } else {
            let old_directory = self.directory.clone();
            self.push_directory(id, &attrs);

            self.expect(&token::OpenDelim(token::Brace))?;
            let module = self.parse_mod(&token::CloseDelim(token::Brace))?;

            self.directory = old_directory;
            module
        };
        attrs.append(&mut inner_attrs);
        Ok((id, ItemKind::Mod(module)))
    }

    /// Parses the contents of a module (inner attributes followed by module items).
    fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec<Attribute>)> {
        let lo = self.token.span;
        let attrs = self.parse_inner_attributes()?;
        let module = self.parse_mod_items(term, lo)?;
        Ok((module, attrs))
    }

    /// Given a termination token, parses all of the items in a module.
    fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> {
        let mut items = vec![];
        while let Some(item) = self.parse_item()? {
            items.push(item);
            self.maybe_consume_incorrect_semicolon(&items);
        }

        if !self.eat(term) {
            let token_str = super::token_descr(&self.token);
            if !self.maybe_consume_incorrect_semicolon(&items) {
                let msg = &format!("expected item, found {}", token_str);
                let mut err = self.struct_span_err(self.token.span, msg);
                err.span_label(self.token.span, "expected item");
                return Err(err);
            }
        }

        let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };

        Ok(Mod { inner: inner_lo.to(hi), items, inline: true })
    }

    /// Reads a module from a source file.
    fn eval_src_mod(
        &mut self,
        path: PathBuf,
        directory_ownership: DirectoryOwnership,
        name: String,
        id_sp: Span,
    ) -> PResult<'a, (Mod, Vec<Attribute>)> {
        let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut();
        self.error_on_circular_module(id_sp, &path, &included_mod_stack)?;
        included_mod_stack.push(path.clone());
        drop(included_mod_stack);

        let mut p0 =
            new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp);
        p0.cfg_mods = self.cfg_mods;
        let mut module = p0.parse_mod(&token::Eof)?;
        module.0.inline = false;

        self.sess.included_mod_stack.borrow_mut().pop();
        Ok(module)
    }

    fn error_on_circular_module(
        &self,
        span: Span,
        path: &Path,
        included_mod_stack: &[PathBuf],
    ) -> PResult<'a, ()> {
        if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
            let mut err = String::from("circular modules: ");
            let len = included_mod_stack.len();
            for p in &included_mod_stack[i..len] {
                err.push_str(&p.to_string_lossy());
                err.push_str(" -> ");
            }
            err.push_str(&path.to_string_lossy());
            return Err(self.struct_span_err(span, &err[..]));
        }
        Ok(())
    }

    fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
        if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) {
            self.directory.path.push(&*path.as_str());
            self.directory.ownership = DirectoryOwnership::Owned { relative: None };
        } else {
            // We have to push on the current module name in the case of relative
            // paths in order to ensure that any additional module paths from inline
            // `mod x { ... }` come after the relative extension.
            //
            // For example, a `mod z { ... }` inside `x/y.rs` should set the current
            // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
            if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership {
                if let Some(ident) = relative.take() {
                    // remove the relative offset
                    self.directory.path.push(&*ident.as_str());
                }
            }
            self.directory.path.push(&*id.as_str());
        }
    }
}

fn submod_path<'a>(
    sess: &'a ParseSess,
    id: ast::Ident,
    outer_attrs: &[Attribute],
    directory_ownership: DirectoryOwnership,
    dir_path: &Path,
) -> PResult<'a, ModulePathSuccess> {
    if let Some(path) = submod_path_from_attr(outer_attrs, dir_path) {
        let directory_ownership = match path.file_name().and_then(|s| s.to_str()) {
            // All `#[path]` files are treated as though they are a `mod.rs` file.
            // This means that `mod foo;` declarations inside `#[path]`-included
            // files are siblings,
            //
            // Note that this will produce weirdness when a file named `foo.rs` is
            // `#[path]` included and contains a `mod foo;` declaration.
            // If you encounter this, it's your own darn fault :P
            Some(_) => DirectoryOwnership::Owned { relative: None },
            _ => DirectoryOwnership::UnownedViaMod,
        };
        return Ok(ModulePathSuccess { directory_ownership, path });
    }

    let relative = match directory_ownership {
        DirectoryOwnership::Owned { relative } => relative,
        DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
    };
    let ModulePath { path_exists, name, result } =
        default_submod_path(sess, id, relative, dir_path);
    match directory_ownership {
        DirectoryOwnership::Owned { .. } => Ok(result?),
        DirectoryOwnership::UnownedViaBlock => {
            let _ = result.map_err(|mut err| err.cancel());
            error_decl_mod_in_block(sess, id.span, path_exists, &name)
        }
        DirectoryOwnership::UnownedViaMod => {
            let _ = result.map_err(|mut err| err.cancel());
            error_cannot_declare_mod_here(sess, id.span, path_exists, &name)
        }
    }
}

fn error_decl_mod_in_block<'a, T>(
    sess: &'a ParseSess,
    id_sp: Span,
    path_exists: bool,
    name: &str,
) -> PResult<'a, T> {
    let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute";
    let mut err = sess.span_diagnostic.struct_span_err(id_sp, msg);
    if path_exists {
        let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name);
        err.span_note(id_sp, &msg);
    }
    Err(err)
}

fn error_cannot_declare_mod_here<'a, T>(
    sess: &'a ParseSess,
    id_sp: Span,
    path_exists: bool,
    name: &str,
) -> PResult<'a, T> {
    let mut err =
        sess.span_diagnostic.struct_span_err(id_sp, "cannot declare a new module at this location");
    if !id_sp.is_dummy() {
        if let FileName::Real(src_path) = sess.source_map().span_to_filename(id_sp) {
            if let Some(stem) = src_path.file_stem() {
                let mut dest_path = src_path.clone();
                dest_path.set_file_name(stem);
                dest_path.push("mod.rs");
                err.span_note(
                    id_sp,
                    &format!(
                        "maybe move this module `{}` to its own \
                                directory via `{}`",
                        src_path.display(),
                        dest_path.display()
                    ),
                );
            }
        }
    }
    if path_exists {
        err.span_note(
            id_sp,
            &format!("... or maybe `use` the module `{}` instead of possibly redeclaring it", name),
        );
    }
    Err(err)
}

/// Derive a submodule path from the first found `#[path = "path_string"]`.
/// The provided `dir_path` is joined with the `path_string`.
// Public for rustfmt usage.
pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
    // Extract path string from first `#[path = "path_string"]` attribute.
    let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?;
    let path_string = path_string.as_str();

    // On windows, the base path might have the form
    // `\\?\foo\bar` in which case it does not tolerate
    // mixed `/` and `\` separators, so canonicalize
    // `/` to `\`.
    #[cfg(windows)]
    let path_string = path_string.replace("/", "\\");

    Some(dir_path.join(&*path_string))
}

/// Returns a path to a module.
// Public for rustfmt usage.
pub fn default_submod_path<'a>(
    sess: &'a ParseSess,
    id: ast::Ident,
    relative: Option<ast::Ident>,
    dir_path: &Path,
) -> ModulePath<'a> {
    // If we're in a foo.rs file instead of a mod.rs file,
    // we need to look for submodules in
    // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
    // `./<id>.rs` and `./<id>/mod.rs`.
    let relative_prefix_string;
    let relative_prefix = if let Some(ident) = relative {
        relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
        &relative_prefix_string
    } else {
        ""
    };

    let mod_name = id.name.to_string();
    let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
    let secondary_path_str =
        format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
    let default_path = dir_path.join(&default_path_str);
    let secondary_path = dir_path.join(&secondary_path_str);
    let default_exists = sess.source_map().file_exists(&default_path);
    let secondary_exists = sess.source_map().file_exists(&secondary_path);

    let result = match (default_exists, secondary_exists) {
        (true, false) => Ok(ModulePathSuccess {
            path: default_path,
            directory_ownership: DirectoryOwnership::Owned { relative: Some(id) },
        }),
        (false, true) => Ok(ModulePathSuccess {
            path: secondary_path,
            directory_ownership: DirectoryOwnership::Owned { relative: None },
        }),
        (false, false) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                id.span,
                E0583,
                "file not found for module `{}`",
                mod_name,
            );
            err.help(&format!(
                "to create the module `{}`, create file \"{}\"",
                mod_name,
                default_path.display(),
            ));
            Err(err)
        }
        (true, true) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                id.span,
                E0584,
                "file for module `{}` found at both {} and {}",
                mod_name,
                default_path_str,
                secondary_path_str,
            );
            err.help("delete or rename one of them to remove the ambiguity");
            Err(err)
        }
    };

    ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
}
<commit_msg>decouple push_directory from Parser<commit_after>use super::item::ItemInfo;
use super::Parser;

use crate::{new_sub_parser_from_file, DirectoryOwnership};

use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod};
use rustc_ast::attr;
use rustc_ast::token::{self, TokenKind};
use rustc_errors::{struct_span_err, PResult};
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{FileName, Span, DUMMY_SP};
use rustc_span::symbol::sym;

use std::path::{self, Path, PathBuf};

/// Information about the path to a module.
// Public for rustfmt usage.
pub struct ModulePath<'a> {
    name: String,
    path_exists: bool,
    pub result: PResult<'a, ModulePathSuccess>,
}

// Public for rustfmt usage.
pub struct ModulePathSuccess {
    pub path: PathBuf,
    pub directory_ownership: DirectoryOwnership,
}

impl<'a> Parser<'a> {
    /// Parses a source module as a crate. This is the main entry point for the parser.
    pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> {
        let lo = self.token.span;
        let (module, attrs) = self.parse_mod(&token::Eof)?;
        let span = lo.to(self.token.span);
        let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`.
        Ok(ast::Crate { attrs, module, span, proc_macros })
    }

    /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
    pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
        let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs);

        let id = self.parse_ident()?;
        let (module, mut inner_attrs) = if self.eat(&token::Semi) {
            if in_cfg && self.recurse_into_file_modules {
                // This mod is in an external file. Let's go get it!
                let ModulePathSuccess { path, directory_ownership } = submod_path(
                    self.sess,
                    id,
                    &attrs,
                    self.directory.ownership,
                    &self.directory.path,
                )?;
                self.eval_src_mod(path, directory_ownership, id.to_string(), id.span)?
            } else {
                (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new())
            }
        } else {
            let old_directory = self.directory.clone();
            push_directory(id, &attrs, &mut self.directory.ownership, &mut self.directory.path);

            self.expect(&token::OpenDelim(token::Brace))?;
            let module = self.parse_mod(&token::CloseDelim(token::Brace))?;

            self.directory = old_directory;
            module
        };
        attrs.append(&mut inner_attrs);
        Ok((id, ItemKind::Mod(module)))
    }

    /// Parses the contents of a module (inner attributes followed by module items).
    fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec<Attribute>)> {
        let lo = self.token.span;
        let attrs = self.parse_inner_attributes()?;
        let module = self.parse_mod_items(term, lo)?;
        Ok((module, attrs))
    }

    /// Given a termination token, parses all of the items in a module.
    fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> {
        let mut items = vec![];
        while let Some(item) = self.parse_item()? {
            items.push(item);
            self.maybe_consume_incorrect_semicolon(&items);
        }

        if !self.eat(term) {
            let token_str = super::token_descr(&self.token);
            if !self.maybe_consume_incorrect_semicolon(&items) {
                let msg = &format!("expected item, found {}", token_str);
                let mut err = self.struct_span_err(self.token.span, msg);
                err.span_label(self.token.span, "expected item");
                return Err(err);
            }
        }

        let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };

        Ok(Mod { inner: inner_lo.to(hi), items, inline: true })
    }

    /// Reads a module from a source file.
    fn eval_src_mod(
        &mut self,
        path: PathBuf,
        directory_ownership: DirectoryOwnership,
        name: String,
        id_sp: Span,
    ) -> PResult<'a, (Mod, Vec<Attribute>)> {
        let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut();
        self.error_on_circular_module(id_sp, &path, &included_mod_stack)?;
        included_mod_stack.push(path.clone());
        drop(included_mod_stack);

        let mut p0 =
            new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp);
        p0.cfg_mods = self.cfg_mods;
        let mut module = p0.parse_mod(&token::Eof)?;
        module.0.inline = false;

        self.sess.included_mod_stack.borrow_mut().pop();
        Ok(module)
    }

    fn error_on_circular_module(
        &self,
        span: Span,
        path: &Path,
        included_mod_stack: &[PathBuf],
    ) -> PResult<'a, ()> {
        if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
            let mut err = String::from("circular modules: ");
            let len = included_mod_stack.len();
            for p in &included_mod_stack[i..len] {
                err.push_str(&p.to_string_lossy());
                err.push_str(" -> ");
            }
            err.push_str(&path.to_string_lossy());
            return Err(self.struct_span_err(span, &err[..]));
        }
        Ok(())
    }
}

fn push_directory(
    id: Ident,
    attrs: &[Attribute],
    dir_ownership: &mut DirectoryOwnership,
    dir_path: &mut PathBuf,
) {
    if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) {
        dir_path.push(&*path.as_str());
        *dir_ownership = DirectoryOwnership::Owned { relative: None };
    } else {
        // We have to push on the current module name in the case of relative
        // paths in order to ensure that any additional module paths from inline
        // `mod x { ... }` come after the relative extension.
        //
        // For example, a `mod z { ... }` inside `x/y.rs` should set the current
        // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
        if let DirectoryOwnership::Owned { relative } = dir_ownership {
            if let Some(ident) = relative.take() {
                // Remove the relative offset.
                dir_path.push(&*ident.as_str());
            }
        }
        dir_path.push(&*id.as_str());
    }
}

fn submod_path<'a>(
    sess: &'a ParseSess,
    id: ast::Ident,
    outer_attrs: &[Attribute],
    directory_ownership: DirectoryOwnership,
    dir_path: &Path,
) -> PResult<'a, ModulePathSuccess> {
    if let Some(path) = submod_path_from_attr(outer_attrs, dir_path) {
        let directory_ownership = match path.file_name().and_then(|s| s.to_str()) {
            // All `#[path]` files are treated as though they are a `mod.rs` file.
            // This means that `mod foo;` declarations inside `#[path]`-included
            // files are siblings,
            //
            // Note that this will produce weirdness when a file named `foo.rs` is
            // `#[path]` included and contains a `mod foo;` declaration.
            // If you encounter this, it's your own darn fault :P
            Some(_) => DirectoryOwnership::Owned { relative: None },
            _ => DirectoryOwnership::UnownedViaMod,
        };
        return Ok(ModulePathSuccess { directory_ownership, path });
    }

    let relative = match directory_ownership {
        DirectoryOwnership::Owned { relative } => relative,
        DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
    };
    let ModulePath { path_exists, name, result } =
        default_submod_path(sess, id, relative, dir_path);
    match directory_ownership {
        DirectoryOwnership::Owned { .. } => Ok(result?),
        DirectoryOwnership::UnownedViaBlock => {
            let _ = result.map_err(|mut err| err.cancel());
            error_decl_mod_in_block(sess, id.span, path_exists, &name)
        }
        DirectoryOwnership::UnownedViaMod => {
            let _ = result.map_err(|mut err| err.cancel());
            error_cannot_declare_mod_here(sess, id.span, path_exists, &name)
        }
    }
}

fn error_decl_mod_in_block<'a, T>(
    sess: &'a ParseSess,
    id_sp: Span,
    path_exists: bool,
    name: &str,
) -> PResult<'a, T> {
    let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute";
    let mut err = sess.span_diagnostic.struct_span_err(id_sp, msg);
    if path_exists {
        let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name);
        err.span_note(id_sp, &msg);
    }
    Err(err)
}

fn error_cannot_declare_mod_here<'a, T>(
    sess: &'a ParseSess,
    id_sp: Span,
    path_exists: bool,
    name: &str,
) -> PResult<'a, T> {
    let mut err =
        sess.span_diagnostic.struct_span_err(id_sp, "cannot declare a new module at this location");
    if !id_sp.is_dummy() {
        if let FileName::Real(src_path) = sess.source_map().span_to_filename(id_sp) {
            if let Some(stem) = src_path.file_stem() {
                let mut dest_path = src_path.clone();
                dest_path.set_file_name(stem);
                dest_path.push("mod.rs");
                err.span_note(
                    id_sp,
                    &format!(
                        "maybe move this module `{}` to its own \
                                directory via `{}`",
                        src_path.display(),
                        dest_path.display()
                    ),
                );
            }
        }
    }
    if path_exists {
        err.span_note(
            id_sp,
            &format!("... or maybe `use` the module `{}` instead of possibly redeclaring it", name),
        );
    }
    Err(err)
}

/// Derive a submodule path from the first found `#[path = "path_string"]`.
/// The provided `dir_path` is joined with the `path_string`.
// Public for rustfmt usage.
pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
    // Extract path string from first `#[path = "path_string"]` attribute.
    let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?;
    let path_string = path_string.as_str();

    // On windows, the base path might have the form
    // `\\?\foo\bar` in which case it does not tolerate
    // mixed `/` and `\` separators, so canonicalize
    // `/` to `\`.
    #[cfg(windows)]
    let path_string = path_string.replace("/", "\\");

    Some(dir_path.join(&*path_string))
}

/// Returns a path to a module.
// Public for rustfmt usage.
pub fn default_submod_path<'a>(
    sess: &'a ParseSess,
    id: ast::Ident,
    relative: Option<ast::Ident>,
    dir_path: &Path,
) -> ModulePath<'a> {
    // If we're in a foo.rs file instead of a mod.rs file,
    // we need to look for submodules in
    // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
    // `./<id>.rs` and `./<id>/mod.rs`.
    let relative_prefix_string;
    let relative_prefix = if let Some(ident) = relative {
        relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
        &relative_prefix_string
    } else {
        ""
    };

    let mod_name = id.name.to_string();
    let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
    let secondary_path_str =
        format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
    let default_path = dir_path.join(&default_path_str);
    let secondary_path = dir_path.join(&secondary_path_str);
    let default_exists = sess.source_map().file_exists(&default_path);
    let secondary_exists = sess.source_map().file_exists(&secondary_path);

    let result = match (default_exists, secondary_exists) {
        (true, false) => Ok(ModulePathSuccess {
            path: default_path,
            directory_ownership: DirectoryOwnership::Owned { relative: Some(id) },
        }),
        (false, true) => Ok(ModulePathSuccess {
            path: secondary_path,
            directory_ownership: DirectoryOwnership::Owned { relative: None },
        }),
        (false, false) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                id.span,
                E0583,
                "file not found for module `{}`",
                mod_name,
            );
            err.help(&format!(
                "to create the module `{}`, create file \"{}\"",
                mod_name,
                default_path.display(),
            ));
            Err(err)
        }
        (true, true) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                id.span,
                E0584,
                "file for module `{}` found at both {} and {}",
                mod_name,
                default_path_str,
                secondary_path_str,
            );
            err.help("delete or rename one of them to remove the ambiguity");
            Err(err)
        }
    };

    ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
}
<|endoftext|>


<commit_before>//! Functions for changing world and entity state.

use std::path::Path;
use std::fs::{self, File};
use rand::Rng;
use calx_alg::RngExt;
use calx_grid::{Dijkstra, Dir6, HexFov, HexGeom};
use calx_ecs::Entity;
use world::World;
use area;
use location::Location;
use item::Slot;
use components::{CompositeStats, BrainState};
use query::{self, ControlState};
use msg;

/// Player input action.
#[derive(Copy, Eq, PartialEq, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum Input {
    /// Take a step in the given direction.
    Step(Dir6),
    /// Melee attack in the given direction.
    Melee(Dir6),
    /// Shoot in the given direction.
    Shoot(Dir6),
    /// Do nothing for a turn.
    Pass,
}

/// Top-level game state update function. Only valid to call if
/// control_state() returned ReadyToUpdate.
pub fn update(w: &mut World) {
    assert!(query::control_state(w) == ControlState::ReadyToUpdate);

    clean_dead(w);
    ai_main(w);

    w.flags.tick += 1;
    w.flags.player_acted = false;
}

/// Run AI for all autonomous mobs.
fn ai_main(w: &mut World) {
    let actives: Vec<Entity> = w.ecs.brain.iter().map(|(&e, _)| e).collect();
    for e in actives.into_iter() {
        update_entity(w, e);
    }
}

fn clean_dead(w: &mut World) {
    let dead: Vec<Entity> = w.ecs
                             .iter()
                             .filter(|&&e| !query::is_alive(w, e))
                             .map(|&e| e)
                             .collect();
    for e in dead.into_iter() {
        w.ecs.remove(e);
    }
}

pub fn update_entity(w: &mut World, e: Entity) {
    if query::is_mob(w, e) && !query::is_player(w, e) &&
       query::ticks_this_frame(w, e) {
        mob_ai(w, e);
    }
}

pub fn mob_ai(w: &mut World, e: Entity) {
    assert!(query::is_mob(w, e));
    assert!(!query::is_player(w, e));
    assert!(query::ticks_this_frame(w, e));

    if query::brain_state(w, e) == Some(BrainState::Asleep) {
        let self_loc = query::location(w, e).unwrap();
        // Mob is inactive, but may wake up if it spots the player.
        if let Some(player_loc) = query::player(w)
                                      .and_then(|e| query::location(w, e)) {
            // TODO: Line-of-sight, stealth concerns, other enemies than
            // player etc.
            if let Some(d) = player_loc.distance_from(self_loc) {
                if d < 6 {
                    wake_up(w, e);
                }
            }
        }

        return;
    }

    if let Some(p) = query::player(w) {
        let loc = query::location(w, e).expect("no location");

        let vec_to_enemy = loc.v2_at(query::location(w, p)
                                         .expect("no location"));
        if let Some(v) = vec_to_enemy {
            if v.hex_dist() == 1 {
                // Melee range, hit.
                melee(w, e, Dir6::from_v2(v));
            } else {
                // Walk towards.
                let pathing_depth = 16;
                let pathing = Dijkstra::new(vec![query::location(w, p)
                                                     .expect("no location")],
                                            |&loc| !query::blocks_walk(w, loc),
                                            pathing_depth);

                let steps = pathing.sorted_neighbors(&loc);
                if steps.len() > 0 {
                    step(w,
                         e,
                         loc.dir6_towards(steps[0])
                            .expect("No loc pair orientation"));
                } else {
                    let dir = w.flags.rng.gen();
                    step(w, e, dir);
                    // TODO: Fall asleep if things get boring.
                }
            }
        }
    }
}

/// Give player input. Only valid to call if control_state() returned
/// AwaitingInput.
pub fn input(w: &mut World, input: Input) {
    assert!(query::control_state(w) == ControlState::AwaitingInput);
    let p = query::player(w).expect("No player to receive input");
    match input {
        Input::Step(d) => {
            step(w, p, d);
        }
        Input::Melee(d) => {
            melee(w, p, d);
        }
        Input::Shoot(d) => {
            shoot(w, p, d);
        }
        Input::Pass => {}
    }
    w.flags.player_acted = true;

    // Run one world update cycle right away, so that we don't get awkward
    // single frames rendered where the player has acted and the rest of the
    // world hasn't.
    if query::control_state(w) == ControlState::ReadyToUpdate {
        update(w);
    }
}

/// Try to move the entity in direction.
pub fn step(w: &mut World, e: Entity, dir: Dir6) {
    let mut target_loc = query::location(w, e).unwrap() + dir.to_v2();

    if query::can_enter_portals(w, e) {
        target_loc = query::portal(w, target_loc).unwrap_or(target_loc);
    }

    if query::can_enter(w, e, target_loc) {
        place_entity(w, e, target_loc);
    }
}

/// Fight in a direction.
pub fn melee(w: &mut World, e: Entity, dir: Dir6) {
    let loc = query::location(w, e).expect("no location") + dir.to_v2();
    if let Some(e) = query::mob_at(w, loc) {
        let us = query::stats(w, e);
        damage(w, e, us.power + us.attack);
    }
}

pub fn shoot(w: &mut World, e: Entity, dir: Dir6) {
    unimplemented!();
    /*
    let stats = self.stats();

    if stats.ranged_range > 0 {
        action::shoot(self.location().unwrap(), dir, stats.ranged_range, stats.ranged_power);
    }
    */
}

pub fn pick_up(w: &mut World, picker: Entity, item: Entity) -> bool {
    if !query::can_be_picked_up(w, item) {
        return false;
    }

    match query::free_bag_slot(w, picker) {
        Some(slot) => {
            equip(w, item, picker, slot);
            return true;
        }
        // Inventory full.
        None => {
            return false;
        }
    }
}

/// Equip an item to a slot. Slot must be empty.
pub fn equip(w: &mut World, item: Entity, e: Entity, slot: Slot) {
    w.spatial.equip(item, e, slot);
    recompose_stats(w, e)
}

/// Generate composed stats from base stats and the stats of equipped items.
/// This function must be called after any operation that changes the composed
/// stats affecting state of an entity.
pub fn recompose_stats(w: &mut World, e: Entity) {
    let mut stats = query::base_stats(w, e);
    for &slot in [Slot::Body,
                  Slot::Feet,
                  Slot::Head,
                  Slot::Melee,
                  Slot::Ranged,
                  Slot::TrinketF,
                  Slot::TrinketG,
                  Slot::TrinketH,
                  Slot::TrinketI]
                     .iter() {
        if let Some(item) = w.spatial.entity_equipped(e, slot) {
            stats = stats + query::stats(w, item);
        }
    }

    w.ecs.composite_stats.insert(e, CompositeStats(stats));
}

pub fn place_entity(w: &mut World, e: Entity, loc: Location) {
    w.spatial.insert_at(e, loc);
    after_entity_move(w, e);
}

/// Clear map memory of an entity.
pub fn forget_map(w: &mut World, e: Entity) {
    w.ecs.map_memory.get_mut(e).map(|mm| {
        mm.seen.clear();
        mm.remembered.clear();
    });
}

/// Callback when entity moves to a new location.
fn after_entity_move(w: &mut World, e: Entity) {
    let loc = query::location(w, e)
                  .expect("Entity must have location for callback");

    do_fov(w, e);

    for item in w.spatial.entities_at(loc).into_iter() {
        if item != e {
            on_step_on(w, e, item);
        }
    }

    if query::is_player(w, e) {
        w.flags.camera = loc;

        if query::terrain(w, loc).is_exit() {
            area::next_level(w);
        }
    }
}

pub fn do_fov(w: &mut World, e: Entity) {
    if !w.ecs.map_memory.contains(e) {
        return;
    }

    if let Some(loc) = query::location(w, e) {
        let sight_range = 12;
        let seen_locs: Vec<Location> =
            HexFov::new(|pt| query::blocks_sight(w, (loc + pt)), sight_range)
                .fake_isometric()
                .map(|pt| loc + pt)
                .collect();
        let mut mm = &mut w.ecs.map_memory[e];
        mm.seen.clear();
        mm.seen.extend(seen_locs.clone().into_iter());
        mm.remembered.extend(seen_locs.into_iter());
    }
}

pub fn on_step_on(w: &mut World, stepper: Entity, item: Entity) {
    if query::is_instant_item(w, item) && query::is_player(w, stepper) {
        unimplemented!();
    }
}

pub fn set_brain_state(w: &mut World, e: Entity, state: BrainState) {
    w.ecs.brain.get_mut(e).map(|b| b.state = state);
}

pub fn wake_up(w: &mut World, e: Entity) {
    if query::brain_state(w, e) == Some(BrainState::Asleep) {
        set_brain_state(w, e, BrainState::Hunting);
    }
}

/// Apply damage to entity, subject to damage reduction.
pub fn damage(w: &mut World, e: Entity, mut power: i32) {
    let stats = query::stats(w, e);
    power -= stats.protection;

    if power < 1 {
        // Give damage a bit under the reduction an off-chance to hit.
        // Power that's too low can't do anything though.
        if power >= -5 {
            power = 1;
        } else {
            return;
        }
    }

    // Every five points of power is one certain hit.
    let full = power / 5;
    // The fractional points are one probabilistic hit.
    let partial = (power % 5) as f32 / 5.0;

    let damage = full +
                 if w.flags.rng.with_chance(partial) {
        1
    } else {
        0
    };
    apply_damage(w, e, damage);
}

/// Actually subtract points from the entity's hit points. Called from
/// damage method.
fn apply_damage(w: &mut World, e: Entity, amount: i32) {
    if amount <= 0 {
        return;
    }
    let max_hp = query::max_hp(w, e);

    let is_killed = w.ecs.health.get_mut(e).map_or(false, |h| {
        h.wounds += amount;
        h.wounds >= max_hp
    });

    msg::push(::Msg::Damage(e));

    if is_killed {
        query::location(w, e).map(|loc| msg::push(::Msg::Gib(loc)));
        kill(w, e);
    }
}

pub fn kill(w: &mut World, e: Entity) {
    // We use not being present in the spatial index as a shorthand for being
    // dead.
    w.spatial.remove(e);
}

////////////////////////////////////////////////////////////////////////

static SAVE_FILENAME: &'static str = "magog_save.dat";

pub fn save_game(w: &World) {
    // Only save if there's still a living player around.
    if query::game_over(w) {
        return;
    }

    let mut file = File::create(SAVE_FILENAME)
                       .expect("Opening save file failed");
    w.save(&mut file).expect("Saving game failed");
}

pub fn load_game() -> Result<World, ()> {
    if !save_exists() {
        return Err(());
    }
    let path = Path::new(SAVE_FILENAME);
    let mut file = File::open(&path).expect("Opening save file failed");
    // TODO: Use separate error code instead of panic.
    Ok(World::load(&mut file).expect("Invalid save file"))
}

pub fn _delete_save() {
    let _ = fs::remove_file(SAVE_FILENAME);
}

pub fn save_exists() -> bool {
    fs::metadata(SAVE_FILENAME).is_ok()
}
<commit_msg>Dead code cleanup<commit_after><|endoftext|>


<commit_before>//! [GET /_matrix/client/r0/user/{userId}/filter/{filterId}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-user-userid-filter-filterid)

use ruma_api::ruma_api;
use ruma_identifiers::UserId;

use super::IncomingFilterDefinition;

ruma_api! {
    metadata: {
        description: "Retrieve a previously created filter.",
        method: GET,
        name: "get_filter",
        path: "/_matrix/client/r0/user/:user_id/filter/:filter_id",
        rate_limited: false,
        authentication: AccessToken,
    }

    request: {
        /// The user ID to download a filter for.
        #[ruma_api(path)]
        pub user_id: &'a UserId,

        /// The ID of the filter to download.
        #[ruma_api(path)]
        pub filter_id: &'a str,
    }

    response: {
        /// The filter definition.
        #[ruma_api(body)]
        pub filter: IncomingFilterDefinition,
    }

    error: crate::Error
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given user ID and filter ID.
    pub fn new(user_id: &'a UserId, filter_id: &'a str) -> Self {
        Self { user_id, filter_id }
    }
}

impl Response {
    /// Creates a new `Response` with the given filter definition.
    pub fn new(filter: IncomingFilterDefinition) -> Self {
        Self { filter }
    }
}
<commit_msg>client-api: Add a test for get_filter response (de)serialization<commit_after>//! [GET /_matrix/client/r0/user/{userId}/filter/{filterId}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-user-userid-filter-filterid)

use ruma_api::ruma_api;
use ruma_identifiers::UserId;

use super::IncomingFilterDefinition;

ruma_api! {
    metadata: {
        description: "Retrieve a previously created filter.",
        method: GET,
        name: "get_filter",
        path: "/_matrix/client/r0/user/:user_id/filter/:filter_id",
        rate_limited: false,
        authentication: AccessToken,
    }

    request: {
        /// The user ID to download a filter for.
        #[ruma_api(path)]
        pub user_id: &'a UserId,

        /// The ID of the filter to download.
        #[ruma_api(path)]
        pub filter_id: &'a str,
    }

    response: {
        /// The filter definition.
        #[ruma_api(body)]
        pub filter: IncomingFilterDefinition,
    }

    error: crate::Error
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given user ID and filter ID.
    pub fn new(user_id: &'a UserId, filter_id: &'a str) -> Self {
        Self { user_id, filter_id }
    }
}

impl Response {
    /// Creates a new `Response` with the given filter definition.
    pub fn new(filter: IncomingFilterDefinition) -> Self {
        Self { filter }
    }
}

#[cfg(all(test, any(feature = "client", feature = "server")))]
mod tests {
    use matches::assert_matches;

    use crate::r0::filter::IncomingFilterDefinition;

    #[cfg(feature = "client")]
    #[test]
    fn deserialize_response() {
        use ruma_api::IncomingResponse;

        assert_matches!(
            super::Response::try_from_http_response(
                http::Response::builder().body(b"{}" as &[u8]).unwrap(),
            ),
            Ok(Incoming)
        );
    }

    #[cfg(feature = "server")]
    #[test]
    fn serialize_response() {
        use ruma_api::OutgoingResponse;

        assert_matches!(
            super::Response::new(IncomingFilterDefinition::default())
                .try_into_http_response::<Vec<u8>>(),
            Ok(res) if res.body() == b"{}"
        );
    }
}
<|endoftext|>