<commit_before>// Copyright 2014-2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Common utilities.

mod text;
pub use self::text::{Text, TextSlice, TextIterator, IntoTextIterator, trim_newline};

mod nonnanfloat;
pub use self::nonnanfloat::NonNaNFloat;

mod interval;
pub use self::interval::{Interval, IntervalError};

/// Strand information.
#[derive(Debug, Clone, Copy)]
pub enum Strand {
    Forward,
    Reverse,
    Unknown,
}

impl PartialEq for Strand {
    /// Returns true if both are `Forward` or both are `Reverse`, otherwise returns false.
    fn eq(&self, other: &Strand) -> bool {
        match (self, other) {
            (&Strand::Forward, &Strand::Forward) => true,
            (&Strand::Reverse, &Strand::Reverse) => true,
            _ => false
        }
    }
}

/// In place implementation of scan over a slice.
pub fn scan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], op: F) {
    let mut s = a[0];
    for v in a.iter_mut().skip(1) {
        s = op(s, *v);
        *v = s;
    }
}

// Inplace implementation of prescan over a slice.
pub fn prescan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], neutral: T, op: F) {
    let mut s = neutral;
    for v in a.iter_mut() {
        let t = *v;
        *v = s;
        s = op(s, t);
    }
}

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

    #[test]
    fn test_scan() {
        let mut a = vec![1, 0, 0, 1];
        scan(&mut a[..], |a, b| a + b);
        assert_eq!(a, vec![1, 1, 1, 2]);
    }

    #[test]
    fn test_prescan() {
        let mut a = vec![1, 0, 0, 1];
        prescan(&mut a[..], 0, |a, b| a + b);
        assert_eq!(a, vec![0, 1, 1, 1]);
    }
}
<commit_msg>Add 'from_char' and 'is_unknown' static functions for Strand enum<commit_after>// Copyright 2014-2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Common utilities.

mod text;
pub use self::text::{Text, TextSlice, TextIterator, IntoTextIterator, trim_newline};

mod nonnanfloat;
pub use self::nonnanfloat::NonNaNFloat;

mod interval;
pub use self::interval::{Interval, IntervalError};

/// Strand information.
#[derive(Debug, Clone, Copy)]
pub enum Strand {
    Forward,
    Reverse,
    Unknown,
}

impl PartialEq for Strand {
    /// Returns true if both are `Forward` or both are `Reverse`, otherwise returns false.
    fn eq(&self, other: &Strand) -> bool {
        match (self, other) {
            (&Strand::Forward, &Strand::Forward) => true,
            (&Strand::Reverse, &Strand::Reverse) => true,
            _ => false
        }
    }
}

impl Strand {

    /// Returns a `Strand` enum representing the given char.
    ///
    /// The mapping is as follows:
    ///     * '+', 'f', or 'F' becomes `Strand::Forward`
    ///     * '-', 'r', or 'R' becomes `Strand::Forward`
    ///     * '.', '?' becomes `Strand::Forward`
    ///     * Any other inputs will return an `Err(Error::InvalidStrandChar)`
    pub fn from_char(strand_char: &char) -> Result<Strand, Error> {
        match *strand_char {
            '+' | 'f' | 'F' => Ok(Strand::Forward),
            '-' | 'r' | 'R' => Ok(Strand::Reverse),
            '.' | '?'  => Ok(Strand::Unknown),
            invalid => Err(Error::InvalidStrandChar(invalid)),
        }
    }

    pub fn is_unknown(&self) -> bool {
        match self {
            &Strand::Unknown => true,
            _ => false,
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        InvalidStrandChar(invalid_char: char) {
            description("invalid character for strand conversion")
            display("character {:?} can not be converted to a Strand", invalid_char)
        }
    }
}

/// In place implementation of scan over a slice.
pub fn scan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], op: F) {
    let mut s = a[0];
    for v in a.iter_mut().skip(1) {
        s = op(s, *v);
        *v = s;
    }
}

// Inplace implementation of prescan over a slice.
pub fn prescan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], neutral: T, op: F) {
    let mut s = neutral;
    for v in a.iter_mut() {
        let t = *v;
        *v = s;
        s = op(s, t);
    }
}

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

    #[test]
    fn test_scan() {
        let mut a = vec![1, 0, 0, 1];
        scan(&mut a[..], |a, b| a + b);
        assert_eq!(a, vec![1, 1, 1, 2]);
    }

    #[test]
    fn test_prescan() {
        let mut a = vec![1, 0, 0, 1];
        prescan(&mut a[..], 0, |a, b| a + b);
        assert_eq!(a, vec![0, 1, 1, 1]);
    }

    #[test]
    fn test_strand() {
        assert_eq!(Strand::from_char(&'+').unwrap(), Strand::Forward);
        assert_eq!(Strand::from_char(&'-').unwrap(), Strand::Reverse);
        assert!(Strand::from_char(&'.').unwrap().is_unknown());
        assert!(Strand::from_char(&'o').is_err());
    }
}
<|endoftext|>


<commit_before>use core::fmt::{self, Debug, Display, Error, Formatter};
use core::marker::PhantomData;
use core::slice;
use core::str;

use capstone_sys::*;

use crate::arch::ArchDetail;
use crate::constants::Arch;
use crate::ffi::str_from_cstr_ptr;

/// Representation of the array of instructions returned by disasm
#[derive(Debug)]
pub struct Instructions<'a>(&'a mut [cs_insn]);

/// Integer type used in `InsnId`
pub type InsnIdInt = u32;

/// Represents an instruction id, which may be architecture-specific.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct InsnId(pub InsnIdInt);

/// Integer type used in `InsnGroupId`
pub type InsnGroupIdInt = u8;

/// Represents the group an instruction belongs to, which may be architecture-specific.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct InsnGroupId(pub InsnGroupIdInt);

pub use capstone_sys::cs_group_type as InsnGroupType;

/// Integer type used in `RegId`
pub type RegIdInt = u16;

/// Represents an register id, which is architecture-specific.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct RegId(pub RegIdInt);

impl<'a> Instructions<'a> {
    pub(crate) unsafe fn from_raw_parts(ptr: *mut cs_insn, len: usize) -> Instructions<'a> {
        Instructions(slice::from_raw_parts_mut(ptr, len))
    }

    pub(crate) fn new_empty() -> Instructions<'a> {
        Instructions(&mut [])
    }

    /// Get number of instructions
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Iterator over instructions
    pub fn iter(&'a self) -> InstructionIterator<'a> {
        let iter = self.0.iter();
        InstructionIterator(iter)
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl<'a> Drop for Instructions<'a> {
    fn drop(&mut self) {
        if !self.is_empty() {
            unsafe {
                cs_free(self.0.as_mut_ptr(), self.len());
            }
        }
    }
}

/// impl Iterator (and variants) for a type that wraps slice::iterator
///
/// Implements Iterator, ExactSizeIterator, and DoubleEndedIterator
macro_rules! impl_SliceIterator_wrapper {
    (
        impl <$( $lifetime:tt ),*> Iterator for $iterator:ty {
            type Item = $item:ty;
            [ $next:expr ]
        }
    ) => {
        impl <$( $lifetime ),*> Iterator for $iterator {
            type Item = $item;

            #[inline]
            fn next(&mut self) -> Option<Self::Item> {
                self.0.next().map($next)
            }

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                self.0.size_hint()
            }

            #[inline]
            fn count(self) -> usize {
                self.0.count()
            }
        }

        impl<'a> ExactSizeIterator for $iterator {
            #[inline]
            fn len(&self) -> usize {
                self.0.len()
            }
        }

        impl<'a> DoubleEndedIterator for $iterator {
            #[inline]
            fn next_back(&mut self) -> Option<Self::Item> {
                self.0.next_back().map($next)
            }
        }
    }
}

/// An iterator over the instructions returned by disasm
///
/// This is currently the only supported interface for reading them.
pub struct InstructionIterator<'a>(slice::Iter<'a, cs_insn>);

impl_SliceIterator_wrapper!(
    impl<'a> Iterator for InstructionIterator<'a> {
        type Item = Insn<'a>;
        [
            |x| Insn { insn: *x, _marker: PhantomData }
        ]
    }
);

/// A wrapper for the raw capstone-sys instruction
pub struct Insn<'a> {
    /// Inner `cs_insn`
    pub(crate) insn: cs_insn,

    /// Adds lifetime
    pub(crate) _marker: PhantomData<&'a InsnDetail<'a>>,
}

/// Contains architecture-independent details about an instruction, such as register reads.
///
/// To get additional architecture-specific information, use the `arch_detail()` method to get an
/// `ArchDetail` enum.
pub struct InsnDetail<'a>(pub(crate) &'a cs_detail, pub(crate) Arch);

impl<'a> Insn<'a> {
    /// The mnemonic for the instruction
    pub fn mnemonic(&self) -> Option<&str> {
        unsafe { str_from_cstr_ptr(self.insn.mnemonic.as_ptr()) }
    }

    /// The operand string associated with the instruction
    pub fn op_str(&self) -> Option<&str> {
        unsafe { str_from_cstr_ptr(self.insn.op_str.as_ptr()) }
    }

    /// Access instruction id
    pub fn id(&self) -> InsnId {
        InsnId(self.insn.id)
    }

    /// Size of instruction (in bytes)
    fn len(&self) -> usize {
        self.insn.size as usize
    }

    /// Instruction address
    pub fn address(&self) -> u64 {
        self.insn.address as u64
    }

    /// Byte-level representation of the instruction
    pub fn bytes(&self) -> &[u8] {
        &self.insn.bytes[..self.len()]
    }

    /// Returns the `Detail` object, if there is one. It is up to the caller to determine
    /// the pre-conditions are satisfied.
    ///
    /// Be careful this is still in early stages and largely untested with various `cs_option` and
    /// architecture matrices
    pub(crate) unsafe fn detail(&self, arch: Arch) -> InsnDetail {
        InsnDetail(&*self.insn.detail, arch)
    }
}

impl<'a> Debug for Insn<'a> {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        fmt.debug_struct("Insn")
            .field("address", &self.address())
            .field("len", &self.len())
            .field("bytes", &self.bytes())
            .field("mnemonic", &self.mnemonic())
            .field("op_str", &self.op_str())
            .finish()
    }
}

impl<'a> Display for Insn<'a> {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{:#x}: ", self.address())?;
        if let Some(mnemonic) = self.mnemonic() {
            write!(fmt, "{} ", mnemonic)?;
            if let Some(op_str) = self.op_str() {
                write!(fmt, "{}", op_str)?;
            }
        }
        Ok(())
    }
}

/// Iterator over registers ids
#[derive(Debug, Clone)]
pub struct RegsIter<'a, T: 'a + Into<RegIdInt> + Copy>(slice::Iter<'a, T>);

impl<'a, T: 'a + Into<RegIdInt> + Copy> Iterator for RegsIter<'a, T> {
    type Item = RegId;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|x| RegId((*x).into()))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }

    #[inline]
    fn count(self) -> usize {
        self.0.count()
    }
}

impl<'a, T: 'a + Into<RegIdInt> + Copy> ExactSizeIterator for RegsIter<'a, T> {
    #[inline]
    fn len(&self) -> usize {
        self.0.len()
    }
}

impl<'a, T: 'a + Into<RegIdInt> + Copy> DoubleEndedIterator for RegsIter<'a, T> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.0.next_back().map(|x| RegId((*x).into()))
    }
}

/// Iterator over instruction group ids
#[derive(Debug, Clone)]
pub struct InsnGroupIter<'a>(slice::Iter<'a, InsnGroupIdInt>);

impl_SliceIterator_wrapper!(
    impl<'a> Iterator for InsnGroupIter<'a> {
        type Item = InsnGroupId;

        [
            |x| InsnGroupId(*x as InsnGroupIdInt)
        ]
    }
);

impl<'a> InsnDetail<'a> {
    /// Returns the implicit read registers
    pub fn regs_read(&self) -> RegsIter<RegIdInt> {
        RegsIter((*self.0).regs_read[..self.regs_read_count() as usize].iter())
    }

    /// Returns the number of implicit read registers
    pub fn regs_read_count(&self) -> u8 {
        (*self.0).regs_read_count
    }

    /// Returns the implicit write registers
    pub fn regs_write(&self) -> RegsIter<RegIdInt> {
        RegsIter((*self.0).regs_write[..self.regs_write_count() as usize].iter())
    }

    /// Returns the number of implicit write registers
    pub fn regs_write_count(&self) -> u8 {
        (*self.0).regs_write_count
    }

    /// Returns the groups to which this instruction belongs
    pub fn groups(&self) -> InsnGroupIter {
        InsnGroupIter((*self.0).groups[..self.groups_count() as usize].iter())
    }

    /// Returns the number groups to which this instruction belongs
    pub fn groups_count(&self) -> u8 {
        (*self.0).groups_count
    }

    /// Architecture-specific detail
    pub fn arch_detail(&self) -> ArchDetail {
        macro_rules! def_arch_detail_match {
            (
                $( [ $ARCH:ident, $detail:ident, $insn_detail:ident, $arch:ident ] )*
            ) => {
                use self::ArchDetail::*;
                use crate::Arch::*;
                $( use crate::arch::$arch::$insn_detail; )*

                return match self.1 {
                    $(
                        $ARCH => {
                            $detail($insn_detail(unsafe { &self.0.__bindgen_anon_1.$arch }))
                        }
                    )*
                    _ => panic!("Unsupported detail arch"),
                }
            }
        }
        def_arch_detail_match!(
            [ARM, ArmDetail, ArmInsnDetail, arm]
            [ARM64, Arm64Detail, Arm64InsnDetail, arm64]
            [EVM, EvmDetail, EvmInsnDetail, evm]
            [M680X, M680xDetail, M680xInsnDetail, m680x]
            [M68K, M68kDetail, M68kInsnDetail, m68k]
            [MIPS, MipsDetail, MipsInsnDetail, mips]
            [PPC, PpcDetail, PpcInsnDetail, ppc]
            [SPARC, SparcDetail, SparcInsnDetail, sparc]
            [TMS320C64X, Tms320c64xDetail, Tms320c64xInsnDetail, tms320c64x]
            [X86, X86Detail, X86InsnDetail, x86]
            [XCORE, XcoreDetail, XcoreInsnDetail, xcore]
        );
    }
}

impl<'a> Debug for InsnDetail<'a> {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("Detail")
            .field("regs_read", &self.regs_read())
            .field("regs_read_count", &self.regs_read_count())
            .field("regs_write", &self.regs_write())
            .field("regs_write_count", &self.regs_write_count())
            .field("groups", &self.groups())
            .field("groups_count", &self.groups_count())
            .finish()
    }
}

impl<'a> Display for Instructions<'a> {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        for instruction in self.iter() {
            write!(fmt, "{:x}:\t", instruction.address())?;
            for byte in instruction.bytes() {
                write!(fmt, " {:02x}", byte)?;
            }
            let remainder = 16 * 3 - instruction.bytes().len() * 3;
            for _ in 0..remainder {
                write!(fmt, " ")?;
            }
            if let Some(mnemonic) = instruction.mnemonic() {
                write!(fmt, " {}", mnemonic)?;
                if let Some(op_str) = instruction.op_str() {
                    write!(fmt, " {}", op_str)?;
                }
            }
            writeln!(fmt)?;
        }
        Ok(())
    }
}
<commit_msg>Add RegAccessType (cs_ac_type) struct<commit_after>use core::convert::TryFrom;
use core::fmt::{self, Debug, Display, Error, Formatter};
use core::marker::PhantomData;
use core::slice;
use core::str;

use capstone_sys::*;

use crate::arch::ArchDetail;
use crate::constants::Arch;
use crate::ffi::str_from_cstr_ptr;

/// Representation of the array of instructions returned by disasm
#[derive(Debug)]
pub struct Instructions<'a>(&'a mut [cs_insn]);

/// Integer type used in `InsnId`
pub type InsnIdInt = u32;

/// Represents an instruction id, which may be architecture-specific.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct InsnId(pub InsnIdInt);

/// Integer type used in `InsnGroupId`
pub type InsnGroupIdInt = u8;

/// Represents the group an instruction belongs to, which may be architecture-specific.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct InsnGroupId(pub InsnGroupIdInt);

pub use capstone_sys::cs_group_type as InsnGroupType;

/// Integer type used in `RegId`
pub type RegIdInt = u16;

/// Represents an register id, which is architecture-specific.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct RegId(pub RegIdInt);

/// Represents how the register is accessed.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum RegAccessType {
    /// Operand read from memory or register.
    ReadOnly,
    /// Operand write from memory or register.
    WriteOnly,
    /// Operand read and write from memory or register.
    ReadWrite,
}

impl RegAccessType {
    /// Returns whether the instruction reads from the operand.
    ///
    /// Note that an instruction may read and write to the register
    /// simultaneously. In this case, the operand is also considered as
    /// readable.
    pub fn is_readable(self) -> bool {
        self == RegAccessType::ReadOnly || self == RegAccessType::ReadWrite
    }

    /// Returns whether the instruction writes from the operand.
    ///
    /// Note that an instruction may read and write to the register
    /// simultaneously. In this case, the operand is also considered as
    /// writable.
    pub fn is_writable(self) -> bool {
        self == RegAccessType::WriteOnly || self == RegAccessType::ReadWrite
    }
}

impl TryFrom<cs_ac_type> for RegAccessType {
    type Error = ();

    fn try_from(access: cs_ac_type) -> Result<Self, Self::Error> {
        // Check for flags other than CS_AC_READ or CS_AC_WRITE.
        let unknown_flag_mask = !(CS_AC_READ | CS_AC_WRITE).0;
        if (access.0 & unknown_flag_mask) != 0 {
            return Err(());
        }

        let is_readable = (access & CS_AC_READ).0 != 0;
        let is_writable = (access & CS_AC_WRITE).0 != 0;
        match (is_readable, is_writable) {
            (true, false) => Ok(RegAccessType::ReadOnly),
            (false, true) => Ok(RegAccessType::WriteOnly),
            (true, true) => Ok(RegAccessType::ReadWrite),
            _ => Err(()),
        }
    }
}

impl<'a> Instructions<'a> {
    pub(crate) unsafe fn from_raw_parts(ptr: *mut cs_insn, len: usize) -> Instructions<'a> {
        Instructions(slice::from_raw_parts_mut(ptr, len))
    }

    pub(crate) fn new_empty() -> Instructions<'a> {
        Instructions(&mut [])
    }

    /// Get number of instructions
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Iterator over instructions
    pub fn iter(&'a self) -> InstructionIterator<'a> {
        let iter = self.0.iter();
        InstructionIterator(iter)
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl<'a> Drop for Instructions<'a> {
    fn drop(&mut self) {
        if !self.is_empty() {
            unsafe {
                cs_free(self.0.as_mut_ptr(), self.len());
            }
        }
    }
}

/// impl Iterator (and variants) for a type that wraps slice::iterator
///
/// Implements Iterator, ExactSizeIterator, and DoubleEndedIterator
macro_rules! impl_SliceIterator_wrapper {
    (
        impl <$( $lifetime:tt ),*> Iterator for $iterator:ty {
            type Item = $item:ty;
            [ $next:expr ]
        }
    ) => {
        impl <$( $lifetime ),*> Iterator for $iterator {
            type Item = $item;

            #[inline]
            fn next(&mut self) -> Option<Self::Item> {
                self.0.next().map($next)
            }

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                self.0.size_hint()
            }

            #[inline]
            fn count(self) -> usize {
                self.0.count()
            }
        }

        impl<'a> ExactSizeIterator for $iterator {
            #[inline]
            fn len(&self) -> usize {
                self.0.len()
            }
        }

        impl<'a> DoubleEndedIterator for $iterator {
            #[inline]
            fn next_back(&mut self) -> Option<Self::Item> {
                self.0.next_back().map($next)
            }
        }
    }
}

/// An iterator over the instructions returned by disasm
///
/// This is currently the only supported interface for reading them.
pub struct InstructionIterator<'a>(slice::Iter<'a, cs_insn>);

impl_SliceIterator_wrapper!(
    impl<'a> Iterator for InstructionIterator<'a> {
        type Item = Insn<'a>;
        [
            |x| Insn { insn: *x, _marker: PhantomData }
        ]
    }
);

/// A wrapper for the raw capstone-sys instruction
pub struct Insn<'a> {
    /// Inner `cs_insn`
    pub(crate) insn: cs_insn,

    /// Adds lifetime
    pub(crate) _marker: PhantomData<&'a InsnDetail<'a>>,
}

/// Contains architecture-independent details about an instruction, such as register reads.
///
/// To get additional architecture-specific information, use the `arch_detail()` method to get an
/// `ArchDetail` enum.
pub struct InsnDetail<'a>(pub(crate) &'a cs_detail, pub(crate) Arch);

impl<'a> Insn<'a> {
    /// The mnemonic for the instruction
    pub fn mnemonic(&self) -> Option<&str> {
        unsafe { str_from_cstr_ptr(self.insn.mnemonic.as_ptr()) }
    }

    /// The operand string associated with the instruction
    pub fn op_str(&self) -> Option<&str> {
        unsafe { str_from_cstr_ptr(self.insn.op_str.as_ptr()) }
    }

    /// Access instruction id
    pub fn id(&self) -> InsnId {
        InsnId(self.insn.id)
    }

    /// Size of instruction (in bytes)
    fn len(&self) -> usize {
        self.insn.size as usize
    }

    /// Instruction address
    pub fn address(&self) -> u64 {
        self.insn.address as u64
    }

    /// Byte-level representation of the instruction
    pub fn bytes(&self) -> &[u8] {
        &self.insn.bytes[..self.len()]
    }

    /// Returns the `Detail` object, if there is one. It is up to the caller to determine
    /// the pre-conditions are satisfied.
    ///
    /// Be careful this is still in early stages and largely untested with various `cs_option` and
    /// architecture matrices
    pub(crate) unsafe fn detail(&self, arch: Arch) -> InsnDetail {
        InsnDetail(&*self.insn.detail, arch)
    }
}

impl<'a> Debug for Insn<'a> {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        fmt.debug_struct("Insn")
            .field("address", &self.address())
            .field("len", &self.len())
            .field("bytes", &self.bytes())
            .field("mnemonic", &self.mnemonic())
            .field("op_str", &self.op_str())
            .finish()
    }
}

impl<'a> Display for Insn<'a> {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{:#x}: ", self.address())?;
        if let Some(mnemonic) = self.mnemonic() {
            write!(fmt, "{} ", mnemonic)?;
            if let Some(op_str) = self.op_str() {
                write!(fmt, "{}", op_str)?;
            }
        }
        Ok(())
    }
}

/// Iterator over registers ids
#[derive(Debug, Clone)]
pub struct RegsIter<'a, T: 'a + Into<RegIdInt> + Copy>(slice::Iter<'a, T>);

impl<'a, T: 'a + Into<RegIdInt> + Copy> Iterator for RegsIter<'a, T> {
    type Item = RegId;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|x| RegId((*x).into()))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }

    #[inline]
    fn count(self) -> usize {
        self.0.count()
    }
}

impl<'a, T: 'a + Into<RegIdInt> + Copy> ExactSizeIterator for RegsIter<'a, T> {
    #[inline]
    fn len(&self) -> usize {
        self.0.len()
    }
}

impl<'a, T: 'a + Into<RegIdInt> + Copy> DoubleEndedIterator for RegsIter<'a, T> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.0.next_back().map(|x| RegId((*x).into()))
    }
}

/// Iterator over instruction group ids
#[derive(Debug, Clone)]
pub struct InsnGroupIter<'a>(slice::Iter<'a, InsnGroupIdInt>);

impl_SliceIterator_wrapper!(
    impl<'a> Iterator for InsnGroupIter<'a> {
        type Item = InsnGroupId;

        [
            |x| InsnGroupId(*x as InsnGroupIdInt)
        ]
    }
);

impl<'a> InsnDetail<'a> {
    /// Returns the implicit read registers
    pub fn regs_read(&self) -> RegsIter<RegIdInt> {
        RegsIter((*self.0).regs_read[..self.regs_read_count() as usize].iter())
    }

    /// Returns the number of implicit read registers
    pub fn regs_read_count(&self) -> u8 {
        (*self.0).regs_read_count
    }

    /// Returns the implicit write registers
    pub fn regs_write(&self) -> RegsIter<RegIdInt> {
        RegsIter((*self.0).regs_write[..self.regs_write_count() as usize].iter())
    }

    /// Returns the number of implicit write registers
    pub fn regs_write_count(&self) -> u8 {
        (*self.0).regs_write_count
    }

    /// Returns the groups to which this instruction belongs
    pub fn groups(&self) -> InsnGroupIter {
        InsnGroupIter((*self.0).groups[..self.groups_count() as usize].iter())
    }

    /// Returns the number groups to which this instruction belongs
    pub fn groups_count(&self) -> u8 {
        (*self.0).groups_count
    }

    /// Architecture-specific detail
    pub fn arch_detail(&self) -> ArchDetail {
        macro_rules! def_arch_detail_match {
            (
                $( [ $ARCH:ident, $detail:ident, $insn_detail:ident, $arch:ident ] )*
            ) => {
                use self::ArchDetail::*;
                use crate::Arch::*;
                $( use crate::arch::$arch::$insn_detail; )*

                return match self.1 {
                    $(
                        $ARCH => {
                            $detail($insn_detail(unsafe { &self.0.__bindgen_anon_1.$arch }))
                        }
                    )*
                    _ => panic!("Unsupported detail arch"),
                }
            }
        }
        def_arch_detail_match!(
            [ARM, ArmDetail, ArmInsnDetail, arm]
            [ARM64, Arm64Detail, Arm64InsnDetail, arm64]
            [EVM, EvmDetail, EvmInsnDetail, evm]
            [M680X, M680xDetail, M680xInsnDetail, m680x]
            [M68K, M68kDetail, M68kInsnDetail, m68k]
            [MIPS, MipsDetail, MipsInsnDetail, mips]
            [PPC, PpcDetail, PpcInsnDetail, ppc]
            [SPARC, SparcDetail, SparcInsnDetail, sparc]
            [TMS320C64X, Tms320c64xDetail, Tms320c64xInsnDetail, tms320c64x]
            [X86, X86Detail, X86InsnDetail, x86]
            [XCORE, XcoreDetail, XcoreInsnDetail, xcore]
        );
    }
}

impl<'a> Debug for InsnDetail<'a> {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("Detail")
            .field("regs_read", &self.regs_read())
            .field("regs_read_count", &self.regs_read_count())
            .field("regs_write", &self.regs_write())
            .field("regs_write_count", &self.regs_write_count())
            .field("groups", &self.groups())
            .field("groups_count", &self.groups_count())
            .finish()
    }
}

impl<'a> Display for Instructions<'a> {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        for instruction in self.iter() {
            write!(fmt, "{:x}:\t", instruction.address())?;
            for byte in instruction.bytes() {
                write!(fmt, " {:02x}", byte)?;
            }
            let remainder = 16 * 3 - instruction.bytes().len() * 3;
            for _ in 0..remainder {
                write!(fmt, " ")?;
            }
            if let Some(mnemonic) = instruction.mnemonic() {
                write!(fmt, " {}", mnemonic)?;
                if let Some(op_str) = instruction.op_str() {
                    write!(fmt, " {}", op_str)?;
                }
            }
            writeln!(fmt)?;
        }
        Ok(())
    }
}

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

    #[test]
    fn test_invalid_reg_access() {
        assert_eq!(RegAccessType::try_from(cs_ac_type(1337)), Err(()));
    }
}
<|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 cookie_storage::CookieStorage;
use http_loader;
use hyper::header::Host;
use net_traits::MessageData;
use net_traits::hosts::replace_hosts;
use net_traits::unwrap_websocket_protocol;
use net_traits::{WebSocketCommunicate, WebSocketConnectData, WebSocketDomAction, WebSocketNetworkEvent};
use std::ascii::AsciiExt;
use std::sync::{Arc, Mutex, RwLock};
use std::thread;
use util::thread::spawn_named;
use websocket::client::request::Url;
use websocket::header::{Headers, Origin, WebSocketProtocol};
use websocket::message::Type;
use websocket::receiver::Receiver;
use websocket::result::{WebSocketError, WebSocketResult};
use websocket::sender::Sender;
use websocket::stream::WebSocketStream;
use websocket::ws::receiver::Receiver as WSReceiver;
use websocket::ws::sender::Sender as Sender_Object;
use websocket::ws::util::url::parse_url;
use websocket::{Client, Message};

/// *Establish a WebSocket Connection* as defined in RFC 6455.
fn establish_a_websocket_connection(resource_url: &Url, net_url: (Host, String, bool),
                                    origin: String, protocols: Vec<String>,
                                    cookie_jar: Arc<RwLock<CookieStorage>>)
    -> WebSocketResult<(Headers, Sender<WebSocketStream>, Receiver<WebSocketStream>)> {
    let host = Host {
        hostname: resource_url.host_str().unwrap().to_owned(),
        port: resource_url.port_or_known_default(),
    };

    let mut request = try!(Client::connect(net_url));
    request.headers.set(Origin(origin));
    request.headers.set(host);
    if !protocols.is_empty() {
        request.headers.set(WebSocketProtocol(protocols.clone()));
    };

    http_loader::set_request_cookies(resource_url.clone(), &mut request.headers, &cookie_jar);

    let response = try!(request.send());
    try!(response.validate());

    {
       let protocol_in_use = unwrap_websocket_protocol(response.protocol());
        if let Some(protocol_name) = protocol_in_use {
                if !protocols.is_empty() && !protocols.iter().any(|p| (&**p).eq_ignore_ascii_case(protocol_name)) {
                    return Err(WebSocketError::ProtocolError("Protocol in Use not in client-supplied protocol list"));
            };
        };
    }

    let headers = response.headers.clone();
    let (sender, receiver) = response.begin().split();
    Ok((headers, sender, receiver))

}

pub fn init(connect: WebSocketCommunicate, connect_data: WebSocketConnectData, cookie_jar: Arc<RwLock<CookieStorage>>) {
    spawn_named(format!("WebSocket connection to {}", connect_data.resource_url), move || {
        // Step 8: Protocols.

        // Step 9.

        // URL that we actually fetch from the network, after applying the replacements
        // specified in the hosts file.
        let net_url_result = parse_url(&replace_hosts(&connect_data.resource_url));
        let net_url = match net_url_result {
            Ok(net_url) => net_url,
            Err(e) => {
                debug!("Failed to establish a WebSocket connection: {:?}", e);
                let _ = connect.event_sender.send(WebSocketNetworkEvent::Fail);
                return;
            }
        };
        let channel = establish_a_websocket_connection(&connect_data.resource_url,
                                                       net_url,
                                                       connect_data.origin,
                                                       connect_data.protocols.clone(),
                                                       cookie_jar);
        let (_, ws_sender, mut receiver) = match channel {
            Ok(channel) => {
                let _ = connect.event_sender.send(WebSocketNetworkEvent::ConnectionEstablished(channel.0.clone(),
                                                                                connect_data.protocols));
                channel
            },
            Err(e) => {
                debug!("Failed to establish a WebSocket connection: {:?}", e);
                let _ = connect.event_sender.send(WebSocketNetworkEvent::Fail);
                return;
            }

        };

        let ws_sender = Arc::new(Mutex::new(ws_sender));

        let ws_sender_incoming = ws_sender.clone();
        let resource_event_sender = connect.event_sender;
        thread::spawn(move || {
            for message in receiver.incoming_messages() {
                let message: Message = match message {
                    Ok(m) => m,
                    Err(e) => {
                        debug!("Error receiving incoming WebSocket message: {:?}", e);
                        let _ = resource_event_sender.send(WebSocketNetworkEvent::Fail);
                        break;
                    }
                };
                let message = match message.opcode {
                    Type::Text => MessageData::Text(String::from_utf8_lossy(&message.payload).into_owned()),
                    Type::Binary => MessageData::Binary(message.payload.into_owned()),
                    Type::Ping => {
                        let pong = Message::pong(message.payload);
                        ws_sender_incoming.lock().unwrap().send_message(&pong).unwrap();
                        continue;
                    },
                    Type::Pong => continue,
                    Type::Close => {
                        ws_sender_incoming.lock().unwrap().send_message(&message).unwrap();
                        let code = message.cd_status_code;
                        let reason = String::from_utf8_lossy(&message.payload).into_owned();
                        let _ = resource_event_sender.send(WebSocketNetworkEvent::Close(code, reason));
                        break;
                    },
                };
                let _ = resource_event_sender.send(WebSocketNetworkEvent::MessageReceived(message));
            }
        });

        let ws_sender_outgoing = ws_sender.clone();
        let resource_action_receiver = connect.action_receiver;
        thread::spawn(move || {
            while let Ok(dom_action) = resource_action_receiver.recv() {
                match dom_action {
                    WebSocketDomAction::SendMessage(MessageData::Text(data)) => {
                        ws_sender_outgoing.lock().unwrap().send_message(&Message::text(data)).unwrap();
                    },
                    WebSocketDomAction::SendMessage(MessageData::Binary(data)) => {
                        ws_sender_outgoing.lock().unwrap().send_message(&Message::binary(data)).unwrap();
                    },
                    WebSocketDomAction::Close(code, reason) => {
                        let message = match code {
                            Some(code) => Message::close_because(code, reason.unwrap_or("".to_owned())),
                            None => Message::close()
                        };
                        ws_sender_outgoing.lock().unwrap().send_message(&message).unwrap();
                    },
                }
            }
        });
    });
}
<commit_msg>check close on both incoming/outgoing websocket<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 cookie_storage::CookieStorage;
use http_loader;
use hyper::header::Host;
use net_traits::MessageData;
use net_traits::hosts::replace_hosts;
use net_traits::unwrap_websocket_protocol;
use net_traits::{WebSocketCommunicate, WebSocketConnectData, WebSocketDomAction, WebSocketNetworkEvent};
use std::ascii::AsciiExt;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, RwLock};
use std::thread;
use util::thread::spawn_named;
use websocket::client::request::Url;
use websocket::header::{Headers, Origin, WebSocketProtocol};
use websocket::message::Type;
use websocket::receiver::Receiver;
use websocket::result::{WebSocketError, WebSocketResult};
use websocket::sender::Sender;
use websocket::stream::WebSocketStream;
use websocket::ws::receiver::Receiver as WSReceiver;
use websocket::ws::sender::Sender as Sender_Object;
use websocket::ws::util::url::parse_url;
use websocket::{Client, Message};

/// *Establish a WebSocket Connection* as defined in RFC 6455.
fn establish_a_websocket_connection(resource_url: &Url, net_url: (Host, String, bool),
                                    origin: String, protocols: Vec<String>,
                                    cookie_jar: Arc<RwLock<CookieStorage>>)
    -> WebSocketResult<(Headers, Sender<WebSocketStream>, Receiver<WebSocketStream>)> {
    let host = Host {
        hostname: resource_url.host_str().unwrap().to_owned(),
        port: resource_url.port_or_known_default(),
    };

    let mut request = try!(Client::connect(net_url));
    request.headers.set(Origin(origin));
    request.headers.set(host);
    if !protocols.is_empty() {
        request.headers.set(WebSocketProtocol(protocols.clone()));
    };

    http_loader::set_request_cookies(resource_url.clone(), &mut request.headers, &cookie_jar);

    let response = try!(request.send());
    try!(response.validate());

    {
       let protocol_in_use = unwrap_websocket_protocol(response.protocol());
        if let Some(protocol_name) = protocol_in_use {
                if !protocols.is_empty() && !protocols.iter().any(|p| (&**p).eq_ignore_ascii_case(protocol_name)) {
                    return Err(WebSocketError::ProtocolError("Protocol in Use not in client-supplied protocol list"));
            };
        };
    }

    let headers = response.headers.clone();
    let (sender, receiver) = response.begin().split();
    Ok((headers, sender, receiver))

}

pub fn init(connect: WebSocketCommunicate, connect_data: WebSocketConnectData, cookie_jar: Arc<RwLock<CookieStorage>>) {
    spawn_named(format!("WebSocket connection to {}", connect_data.resource_url), move || {
        // Step 8: Protocols.

        // Step 9.

        // URL that we actually fetch from the network, after applying the replacements
        // specified in the hosts file.
        let net_url_result = parse_url(&replace_hosts(&connect_data.resource_url));
        let net_url = match net_url_result {
            Ok(net_url) => net_url,
            Err(e) => {
                debug!("Failed to establish a WebSocket connection: {:?}", e);
                let _ = connect.event_sender.send(WebSocketNetworkEvent::Fail);
                return;
            }
        };
        let channel = establish_a_websocket_connection(&connect_data.resource_url,
                                                       net_url,
                                                       connect_data.origin,
                                                       connect_data.protocols.clone(),
                                                       cookie_jar);
        let (_, ws_sender, mut receiver) = match channel {
            Ok(channel) => {
                let _ = connect.event_sender.send(WebSocketNetworkEvent::ConnectionEstablished(channel.0.clone(),
                                                                                connect_data.protocols));
                channel
            },
            Err(e) => {
                debug!("Failed to establish a WebSocket connection: {:?}", e);
                let _ = connect.event_sender.send(WebSocketNetworkEvent::Fail);
                return;
            }

        };

        let initiated_close = Arc::new(AtomicBool::new(false));
        let ws_sender = Arc::new(Mutex::new(ws_sender));

        let initiated_close_incoming = initiated_close.clone();
        let ws_sender_incoming = ws_sender.clone();
        let resource_event_sender = connect.event_sender;
        thread::spawn(move || {
            for message in receiver.incoming_messages() {
                let message: Message = match message {
                    Ok(m) => m,
                    Err(e) => {
                        debug!("Error receiving incoming WebSocket message: {:?}", e);
                        let _ = resource_event_sender.send(WebSocketNetworkEvent::Fail);
                        break;
                    }
                };
                let message = match message.opcode {
                    Type::Text => MessageData::Text(String::from_utf8_lossy(&message.payload).into_owned()),
                    Type::Binary => MessageData::Binary(message.payload.into_owned()),
                    Type::Ping => {
                        let pong = Message::pong(message.payload);
                        ws_sender_incoming.lock().unwrap().send_message(&pong).unwrap();
                        continue;
                    },
                    Type::Pong => continue,
                    Type::Close => {
                        if !initiated_close_incoming.fetch_or(true, Ordering::SeqCst) {
                            ws_sender_incoming.lock().unwrap().send_message(&message).unwrap();
                        }
                        let code = message.cd_status_code;
                        let reason = String::from_utf8_lossy(&message.payload).into_owned();
                        let _ = resource_event_sender.send(WebSocketNetworkEvent::Close(code, reason));
                        break;
                    },
                };
                let _ = resource_event_sender.send(WebSocketNetworkEvent::MessageReceived(message));
            }
        });

        let initiated_close_outgoing = initiated_close.clone();
        let ws_sender_outgoing = ws_sender.clone();
        let resource_action_receiver = connect.action_receiver;
        thread::spawn(move || {
            while let Ok(dom_action) = resource_action_receiver.recv() {
                match dom_action {
                    WebSocketDomAction::SendMessage(MessageData::Text(data)) => {
                        ws_sender_outgoing.lock().unwrap().send_message(&Message::text(data)).unwrap();
                    },
                    WebSocketDomAction::SendMessage(MessageData::Binary(data)) => {
                        ws_sender_outgoing.lock().unwrap().send_message(&Message::binary(data)).unwrap();
                    },
                    WebSocketDomAction::Close(code, reason) => {
                        if !initiated_close_outgoing.fetch_or(true, Ordering::SeqCst) {
                            let message = match code {
                                Some(code) => Message::close_because(code, reason.unwrap_or("".to_owned())),
                                None => Message::close()
                            };
                            ws_sender_outgoing.lock().unwrap().send_message(&message).unwrap();
                        }
                    },
                }
            }
        });
    });
}
<|endoftext|>


<commit_before>//! lint when there is an enum with no variants

use crate::utils::span_lint_and_help;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Checks for `enum`s with no variants.
    ///
    /// **Why is this bad?** If you want to introduce a type which
    /// can't be instantiated, you should use `!` (the never type),
    /// or a wrapper around it, because `!` has more extensive
    /// compiler support (type inference, etc...) and wrappers
    /// around it are the conventional way to define an uninhabited type.
    /// For further information visit [never type documentation](https://doc.rust-lang.org/std/primitive.never.html)
    ///
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// Bad:
    /// ```rust
    /// enum Test {}
    /// ```
    ///
    /// Good:
    /// ```rust
    /// #![feature(never_type)]
    ///
    /// struct Test(!);
    /// ```
    pub EMPTY_ENUM,
    pedantic,
    "enum with no variants"
}

declare_lint_pass!(EmptyEnum => [EMPTY_ENUM]);

impl<'tcx> LateLintPass<'tcx> for EmptyEnum {
    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
        let did = cx.tcx.hir().local_def_id(item.hir_id);
        if let ItemKind::Enum(..) = item.kind {
            let ty = cx.tcx.type_of(did);
            let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
            if adt.variants.is_empty() {
                span_lint_and_help(
                    cx,
                    EMPTY_ENUM,
                    item.span,
                    "enum with no variants",
                    None,
                    "consider using the uninhabited type `!` (never type) or a wrapper \
                    around it to introduce a type which can't be instantiated",
                );
            }
        }
    }
}
<commit_msg>Check if never type feature is enabled by TyCtxt before suggesting empty enum lint<commit_after>//! lint when there is an enum with no variants

use crate::utils::span_lint_and_help;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Checks for `enum`s with no variants.
    ///
    /// **Why is this bad?** If you want to introduce a type which
    /// can't be instantiated, you should use `!` (the never type),
    /// or a wrapper around it, because `!` has more extensive
    /// compiler support (type inference, etc...) and wrappers
    /// around it are the conventional way to define an uninhabited type.
    /// For further information visit [never type documentation](https://doc.rust-lang.org/std/primitive.never.html)
    ///
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// Bad:
    /// ```rust
    /// enum Test {}
    /// ```
    ///
    /// Good:
    /// ```rust
    /// #![feature(never_type)]
    ///
    /// struct Test(!);
    /// ```
    pub EMPTY_ENUM,
    pedantic,
    "enum with no variants"
}

declare_lint_pass!(EmptyEnum => [EMPTY_ENUM]);

impl<'tcx> LateLintPass<'tcx> for EmptyEnum {
    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
        let did = cx.tcx.hir().local_def_id(item.hir_id);
        if let ItemKind::Enum(..) = item.kind {
            let ty = cx.tcx.type_of(did);
            let adt = ty.ty_adt_def().expect("already checked whether this is an enum");

            // Only suggest the never type if the feature is enabled
            if adt.variants.is_empty() && cx.tcx.features().never_type {
                span_lint_and_help(
                    cx,
                    EMPTY_ENUM,
                    item.span,
                    "enum with no variants",
                    None,
                    "consider using the uninhabited type `!` (never type) or a wrapper \
                    around it to introduce a type which can't be instantiated",
                );
            }
        }
    }
}
<|endoftext|>


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

use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast;
use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint};
use crate::syntax::ptr::P;

/// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
/// operators.
///
/// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or
/// confusing.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
/// ```
declare_clippy_lint! {
    pub SUSPICIOUS_ASSIGNMENT_FORMATTING,
    style,
    "suspicious formatting of `*=`, `-=` or `!=`"
}

/// **What it does:** Checks for formatting of `else if`. It lints if the `else`
/// and `if` are not on the same line or the `else` seems to be missing.
///
/// **Why is this bad?** This is probably some refactoring remnant, even if the
/// code is correct, it might look confusing.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// if foo {
/// } if bar { // looks like an `else` is missing here
/// }
///
/// if foo {
/// } else
///
/// if bar { // this is the `else` block of the previous `if`, but should it be?
/// }
/// ```
declare_clippy_lint! {
    pub SUSPICIOUS_ELSE_FORMATTING,
    style,
    "suspicious formatting of `else if`"
}

/// **What it does:** Checks for possible missing comma in an array. It lints if
/// an array element is a binary operator expression and it lies on two lines.
///
/// **Why is this bad?** This could lead to unexpected results.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// let a = &[
///     -1, -2, -3 // <= no comma here
///     -4, -5, -6
/// ];
/// ```
declare_clippy_lint! {
    pub POSSIBLE_MISSING_COMMA,
    correctness,
    "possible missing comma in array"
}

#[derive(Copy, Clone)]
pub struct Formatting;

impl LintPass for Formatting {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            SUSPICIOUS_ASSIGNMENT_FORMATTING,
            SUSPICIOUS_ELSE_FORMATTING,
            POSSIBLE_MISSING_COMMA
        )
    }
}

impl EarlyLintPass for Formatting {
    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        for w in block.stmts.windows(2) {
            match (&w[0].node, &w[1].node) {
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second)) |
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
                    check_consecutive_ifs(cx, first, second);
                },
                _ => (),
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
        check_assign(cx, expr);
        check_else_if(cx, expr);
        check_array(cx, expr);
    }
}

/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node {
        if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(lhs.span) {
            let eq_span = lhs.span.between(rhs.span);
            if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node {
                if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
                    let op = ast::UnOp::to_string(op);
                    let eqop_span = lhs.span.between(sub_rhs.span);
                    if eq_snippet.ends_with('=') {
                        span_note_and_lint(
                            cx,
                            SUSPICIOUS_ASSIGNMENT_FORMATTING,
                            eqop_span,
                            &format!(
                                "this looks like you are trying to use `.. {op}= ..`, but you \
                                 really are doing `.. = ({op} ..)`",
                                op = op
                            ),
                            eqop_span,
                            &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op),
                        );
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else if`.
fn check_else_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let Some((then, &Some(ref else_))) = unsugar_if(expr) {
        if unsugar_if(else_).is_some() && !differing_macro_contexts(then.span, else_.span) && !in_macro(then.span) {
            // this will be a span from the closing ‘}’ of the “then” block (excluding) to
            // the
            // “if” of the “else if” block (excluding)
            let else_span = then.span.between(else_.span);

            // the snippet should look like " else \n    " with maybe comments anywhere
            // it’s bad when there is a ‘\n’ after the “else”
            if let Some(else_snippet) = snippet_opt(cx, else_span) {
                let else_pos = else_snippet
                    .find("else")
                    .expect("there must be a `else` here");

                if else_snippet[else_pos..].contains('\n') {
                    span_note_and_lint(
                        cx,
                        SUSPICIOUS_ELSE_FORMATTING,
                        else_span,
                        "this is an `else if` but the formatting might hide it",
                        else_span,
                        "to remove this lint, remove the `else` or remove the new line between `else` \
                         and `if`",
                    );
                }
            }
        }
    }
}

fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool {
    //+, &, *, -
    bin_op == ast::BinOpKind::Add
    || bin_op == ast::BinOpKind::And
    || bin_op == ast::BinOpKind::Mul
    || bin_op == ast::BinOpKind::Sub
}

/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Array(ref array) = expr.node {
        for element in array {
            if let ast::ExprKind::Binary(ref op, ref lhs, _) = element.node {
                if has_unary_equivalent(op.node) {
                    if !differing_macro_contexts(lhs.span, op.span) {
                        let space_span = lhs.span.between(op.span);
                        if let Some(space_snippet) = snippet_opt(cx, space_span) {
                            let lint_span = lhs.span.with_lo(lhs.span.hi());
                            if space_snippet.contains('\n') {
                                span_note_and_lint(
                                    cx,
                                    POSSIBLE_MISSING_COMMA,
                                    lint_span,
                                    "possibly missing a comma here",
                                    lint_span,
                                    "to remove this lint, add a comma or write the expr in a single line",
                                );
                            }
                        }
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs.
fn check_consecutive_ifs(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
    if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some()
        && unsugar_if(second).is_some()
    {
        // where the else would be
        let else_span = first.span.between(second.span);

        if let Some(else_snippet) = snippet_opt(cx, else_span) {
            if !else_snippet.contains('\n') {
                span_note_and_lint(
                    cx,
                    SUSPICIOUS_ELSE_FORMATTING,
                    else_span,
                    "this looks like an `else if` but the `else` is missing",
                    else_span,
                    "to remove this lint, add the missing `else` or add a new line before the second \
                     `if`",
                );
            }
        }
    }
}

/// Match `if` or `if let` expressions and return the `then` and `else` block.
fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
    match expr.node {
        ast::ExprKind::If(_, ref then, ref else_) | ast::ExprKind::IfLet(_, _, ref then, ref else_) => {
            Some((then, else_))
        },
        _ => None,
    }
}
<commit_msg>Fix `collapsible_if` error<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast;
use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint};
use crate::syntax::ptr::P;

/// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
/// operators.
///
/// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or
/// confusing.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
/// ```
declare_clippy_lint! {
    pub SUSPICIOUS_ASSIGNMENT_FORMATTING,
    style,
    "suspicious formatting of `*=`, `-=` or `!=`"
}

/// **What it does:** Checks for formatting of `else if`. It lints if the `else`
/// and `if` are not on the same line or the `else` seems to be missing.
///
/// **Why is this bad?** This is probably some refactoring remnant, even if the
/// code is correct, it might look confusing.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// if foo {
/// } if bar { // looks like an `else` is missing here
/// }
///
/// if foo {
/// } else
///
/// if bar { // this is the `else` block of the previous `if`, but should it be?
/// }
/// ```
declare_clippy_lint! {
    pub SUSPICIOUS_ELSE_FORMATTING,
    style,
    "suspicious formatting of `else if`"
}

/// **What it does:** Checks for possible missing comma in an array. It lints if
/// an array element is a binary operator expression and it lies on two lines.
///
/// **Why is this bad?** This could lead to unexpected results.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// let a = &[
///     -1, -2, -3 // <= no comma here
///     -4, -5, -6
/// ];
/// ```
declare_clippy_lint! {
    pub POSSIBLE_MISSING_COMMA,
    correctness,
    "possible missing comma in array"
}

#[derive(Copy, Clone)]
pub struct Formatting;

impl LintPass for Formatting {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            SUSPICIOUS_ASSIGNMENT_FORMATTING,
            SUSPICIOUS_ELSE_FORMATTING,
            POSSIBLE_MISSING_COMMA
        )
    }
}

impl EarlyLintPass for Formatting {
    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        for w in block.stmts.windows(2) {
            match (&w[0].node, &w[1].node) {
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second)) |
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
                    check_consecutive_ifs(cx, first, second);
                },
                _ => (),
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
        check_assign(cx, expr);
        check_else_if(cx, expr);
        check_array(cx, expr);
    }
}

/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node {
        if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(lhs.span) {
            let eq_span = lhs.span.between(rhs.span);
            if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node {
                if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
                    let op = ast::UnOp::to_string(op);
                    let eqop_span = lhs.span.between(sub_rhs.span);
                    if eq_snippet.ends_with('=') {
                        span_note_and_lint(
                            cx,
                            SUSPICIOUS_ASSIGNMENT_FORMATTING,
                            eqop_span,
                            &format!(
                                "this looks like you are trying to use `.. {op}= ..`, but you \
                                 really are doing `.. = ({op} ..)`",
                                op = op
                            ),
                            eqop_span,
                            &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op),
                        );
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else if`.
fn check_else_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let Some((then, &Some(ref else_))) = unsugar_if(expr) {
        if unsugar_if(else_).is_some() && !differing_macro_contexts(then.span, else_.span) && !in_macro(then.span) {
            // this will be a span from the closing ‘}’ of the “then” block (excluding) to
            // the
            // “if” of the “else if” block (excluding)
            let else_span = then.span.between(else_.span);

            // the snippet should look like " else \n    " with maybe comments anywhere
            // it’s bad when there is a ‘\n’ after the “else”
            if let Some(else_snippet) = snippet_opt(cx, else_span) {
                let else_pos = else_snippet
                    .find("else")
                    .expect("there must be a `else` here");

                if else_snippet[else_pos..].contains('\n') {
                    span_note_and_lint(
                        cx,
                        SUSPICIOUS_ELSE_FORMATTING,
                        else_span,
                        "this is an `else if` but the formatting might hide it",
                        else_span,
                        "to remove this lint, remove the `else` or remove the new line between `else` \
                         and `if`",
                    );
                }
            }
        }
    }
}

fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool {
    //+, &, *, -
    bin_op == ast::BinOpKind::Add
    || bin_op == ast::BinOpKind::And
    || bin_op == ast::BinOpKind::Mul
    || bin_op == ast::BinOpKind::Sub
}

/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Array(ref array) = expr.node {
        for element in array {
            if let ast::ExprKind::Binary(ref op, ref lhs, _) = element.node {
                if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span) {
                    let space_span = lhs.span.between(op.span);
                    if let Some(space_snippet) = snippet_opt(cx, space_span) {
                        let lint_span = lhs.span.with_lo(lhs.span.hi());
                        if space_snippet.contains('\n') {
                            span_note_and_lint(
                                cx,
                                POSSIBLE_MISSING_COMMA,
                                lint_span,
                                "possibly missing a comma here",
                                lint_span,
                                "to remove this lint, add a comma or write the expr in a single line",
                            );
                        }
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs.
fn check_consecutive_ifs(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
    if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some()
        && unsugar_if(second).is_some()
    {
        // where the else would be
        let else_span = first.span.between(second.span);

        if let Some(else_snippet) = snippet_opt(cx, else_span) {
            if !else_snippet.contains('\n') {
                span_note_and_lint(
                    cx,
                    SUSPICIOUS_ELSE_FORMATTING,
                    else_span,
                    "this looks like an `else if` but the `else` is missing",
                    else_span,
                    "to remove this lint, add the missing `else` or add a new line before the second \
                     `if`",
                );
            }
        }
    }
}

/// Match `if` or `if let` expressions and return the `then` and `else` block.
fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
    match expr.node {
        ast::ExprKind::If(_, ref then, ref else_) | ast::ExprKind::IfLet(_, _, ref then, ref else_) => {
            Some((then, else_))
        },
        _ => None,
    }
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]

use azure::core::range;
use azure::core::HTTPMethod;
use azure::core::lease::{LeaseId, LeaseStatus, LeaseState, LeaseDuration, LeaseAction};
use chrono;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha2::Sha256;
use hyper;
use hyper::Client;
use hyper::header::{Header, HeaderFormat, Headers, ContentEncoding, ContentLanguage,
                    ContentLength, ContentType, Date, IfModifiedSince, IfUnmodifiedSince};
use base64;
use std::fmt::Display;
use std::io::Read;
use url;

use url::percent_encoding::{utf8_percent_encode, USERINFO_ENCODE_SET};
use hyper::header::parsing::HTTP_VALUE;

const AZURE_VERSION: &'static str = "2017-02-22";
const VERSION: &'static str = "1.0";

pub enum TokenType {
    Master,
    Resource,
}

#[derive(Clone,Copy)]
pub enum ResourceType {
    Databases,
    Collections,
    Documents,
}

pub fn generate_authorization(hmac_key: &str,
                              verb: &str,
                              token_type: TokenType,
                              resource_type: ResourceType,
                              resource_link: &str,
                              dt: &chrono::DateTime<chrono::UTC>)
                              -> String {
    let str_unencoded =
        format!("type={}&ver={}&sig={}",
                match token_type {
                    TokenType::Master => "master",
                    TokenType::Resource => "resource",
                },
                VERSION,
                encode_str_to_sign(&string_to_sign(verb, resource_type, resource_link, dt),
                                   hmac_key));

    utf8_percent_encode(&str_unencoded, url::percent_encoding::USERINFO_ENCODE_SET)
        .collect::<String>()
}

fn encode_str_to_sign(str_to_sign: &str, hmac_key: &str) -> String {
    let mut v_hmac_key: Vec<u8> = Vec::new();

    v_hmac_key.extend(base64::decode(hmac_key).unwrap());

    let mut hmac = Hmac::new(Sha256::new(), &v_hmac_key);
    hmac.input(str_to_sign.as_bytes());

    base64::encode(hmac.result().code())
}

pub fn string_to_sign(verb: &str,
                      rt: ResourceType,
                      resource_link: &str,
                      dt: &chrono::DateTime<chrono::UTC>)
                      -> String {
    let time = format!("{}", dt.format("%a, %d %h %Y %T GMT"));

    // From official docs:
    // StringToSign = Verb.toLowerCase() + "\n" + ResourceType.toLowerCase() + "\n" + ResourceLink + "\n" + Date.toLowerCase() + "\n" + "" + "\n";
    // Notice the empty string at the end so we need to add two carriage returns

    format!("{}\n{}\n{}\n{}\n\n",
            verb.to_lowercase(),
            match rt {
                ResourceType::Databases => "dbs",
                ResourceType::Collections => "colls",
                ResourceType::Documents => "docs",
            },
            resource_link,
            time.to_lowercase())

}

#[cfg(test)]
mod tests {
    use azure::cosmos::*;

    #[test]
    fn string_to_sign_00() {
        let time = chrono::DateTime::parse_from_rfc3339("1900-01-01T01:00:00.000000000+00:00")
            .unwrap();
        let time = time.with_timezone(&chrono::UTC);
        let ret = string_to_sign("GET",
                                 ResourceType::Databases,
                                 "dbs/MyDatabase/colls/MyCollection",
                                 &time);
        assert_eq!(ret,
                   "get
dbs
dbs/MyDatabase/colls/MyCollection
mon, 01 jan 1900 01:00:00 gmt

");
     #[test]
    fn generate_authorization_00() {
        let time = chrono::DateTime::parse_from_rfc3339("1900-01-01T01:00:00.000000000+00:00")
            .unwrap();
        let time = time.with_timezone(&chrono::UTC);
        let ret = generate_authorization(
            "8F8xXXOptJxkblM1DBXW7a6NMI5oE8NnwPGYBmwxLCKfejOK7B7yhcCHMGvN3PBrlMLIOeol1Hv9RCdzAZR5sg==",
            "GET",
            TokenType::Master,
                                 ResourceType::Databases,

                                 "dbs/MyDatabase/colls/MyCollection",
                                 &time);
        assert_eq!(ret,
        "type%3dmaster%26ver%3d1.0%26sig%3dQkz%2fr%2b1N2%2bPEnNijxGbGB%2fADvLsLBQmZ7uBBMuIwf4I%3d");
    }
}
<commit_msg>Signature not working<commit_after>#![allow(unused_imports)]

use azure::core::range;
use azure::core::HTTPMethod;
use azure::core::lease::{LeaseId, LeaseStatus, LeaseState, LeaseDuration, LeaseAction};
use chrono;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha2::Sha256;
use hyper;
use hyper::Client;
use hyper::header::{Header, HeaderFormat, Headers, ContentEncoding, ContentLanguage,
                    ContentLength, ContentType, Date, IfModifiedSince, IfUnmodifiedSince};
use base64;
use std::fmt::Display;
use std::io::Read;
use url;

use url::percent_encoding::{utf8_percent_encode, USERINFO_ENCODE_SET};
use hyper::header::parsing::HTTP_VALUE;

const AZURE_VERSION: &'static str = "2017-02-22";
const VERSION: &'static str = "1.0";

pub enum TokenType {
    Master,
    Resource,
}

#[derive(Clone,Copy)]
pub enum ResourceType {
    Databases,
    Collections,
    Documents,
}

pub fn generate_authorization(hmac_key: &str,
                              verb: &str,
                              token_type: TokenType,
                              resource_type: ResourceType,
                              resource_link: &str,
                              dt: &chrono::DateTime<chrono::UTC>)
                              -> String {
    let str_unencoded =
        format!("type={}&ver={}&sig={}",
                match token_type {
                    TokenType::Master => "master",
                    TokenType::Resource => "resource",
                },
                VERSION,
                encode_str_to_sign(&string_to_sign(verb, resource_type, resource_link, dt),
                                   hmac_key));

    utf8_percent_encode(&str_unencoded, url::percent_encoding::DEFAULT_ENCODE_SET)
        .collect::<String>()
}

fn encode_str_to_sign(str_to_sign: &str, hmac_key: &str) -> String {
    let mut v_hmac_key: Vec<u8> = Vec::new();

    v_hmac_key.extend(base64::decode(hmac_key).unwrap());

    let mut hmac = Hmac::new(Sha256::new(), &v_hmac_key);
    hmac.input(str_to_sign.as_bytes());

    base64::encode(hmac.result().code())
}

pub fn string_to_sign(verb: &str,
                      rt: ResourceType,
                      resource_link: &str,
                      dt: &chrono::DateTime<chrono::UTC>)
                      -> String {
    let time = format!("{}", dt.format("%a, %d %h %Y %T GMT"));

    // From official docs:
    // StringToSign = Verb.toLowerCase() + "\n" + ResourceType.toLowerCase() + "\n" + ResourceLink + "\n" + Date.toLowerCase() + "\n" + "" + "\n";
    // Notice the empty string at the end so we need to add two carriage returns

    format!("{}\n{}\n{}\n{}\n\n",
            verb.to_lowercase(),
            match rt {
                ResourceType::Databases => "dbs",
                ResourceType::Collections => "colls",
                ResourceType::Documents => "docs",
            },
            resource_link,
            time.to_lowercase())

}

#[cfg(test)]
mod tests {
    use azure::cosmos::*;

    #[test]
    fn string_to_sign_00() {
        let time = chrono::DateTime::parse_from_rfc3339("1900-01-01T01:00:00.000000000+00:00")
            .unwrap();
        let time = time.with_timezone(&chrono::UTC);
        let ret = string_to_sign("GET",
                                 ResourceType::Databases,
                                 "dbs/MyDatabase/colls/MyCollection",
                                 &time);
        assert_eq!(ret,
                   "get
dbs
dbs/MyDatabase/colls/MyCollection
mon, 01 jan 1900 01:00:00 gmt

");
    }

    #[test]
    fn generate_authorization_00() {
        let time = chrono::DateTime::parse_from_rfc3339("1900-01-01T01:00:00.000000000+00:00")
            .unwrap();
        let time = time.with_timezone(&chrono::UTC);
        let ret = generate_authorization("8F8xXXOptJxkblM1DBXW7a6NMI5oE8NnwPGYBmwxLCKfejOK7B7yhcCHMGvN3PBrlMLIOeol1Hv9RCdzAZR5sg==",
                                         "GET",
                                         TokenType::Master,
                                         ResourceType::Databases,
                                         "dbs/MyDatabase/colls/MyCollection",
                                         &time);
        assert_eq!(ret,
                   "type%3dmaster%26ver%3d1.0%26sig%3dQkz%2fr%2b1N2%2bPEnNijxGbGB%2fADvLsLBQmZ7uBBMuIwf4I%3d");
    }

    #[test]
    fn generate_authorization_01() {
        let time = chrono::DateTime::parse_from_rfc3339("2017-04-27T00:51:12.000000000+00:00")
            .unwrap();
        let time = time.with_timezone(&chrono::UTC);
        let ret = generate_authorization("dsZQi3KtZmCv1ljt3VNWNm7sQUF1y5rJfC6kv5JiwvW0EndXdDku/dkKBp8/ufDToSxL",
                                         "GET",
                                         TokenType::Master,
                                         ResourceType::Databases,
                                         "dbs/ToDoList",
                                         &time);
        assert_eq!(ret,
                   "type%3dmaster%26ver%3d1.0%26sig%3dc09PEVJrgp2uQRkr934kFbTqhByc7TVr3O");
    }
}
<|endoftext|>