<commit_before>// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/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.

#![allow(dead_code)]

use std::io;
use std::mem;
use std::os::unix::prelude::*;
use super::SpiModeFlags;

const SPI_IOC_MAGIC: u8 = 'k' as u8;

const SPI_IOC_NR_TRANSFER: u8 = 0;
const SPI_IOC_NR_MODE: u8 = 1;
const SPI_IOC_NR_LSB_FIRST: u8 = 2;
const SPI_IOC_NR_BITS_PER_WORD: u8 = 3;
const SPI_IOC_NR_MAX_SPEED_HZ: u8 = 4;
const SPI_IOC_NR_MODE32: u8 = 5;

fn from_nix_error(err: ::nix::Error) -> io::Error {
    io::Error::from_raw_os_error(err.errno() as i32)
}

fn from_nix_result<T>(res: ::nix::Result<T>) -> io::Result<T> {
    match res {
        Ok(r) => Ok(r),
        Err(err) => Err(from_nix_error(err)),
    }
}

/// Structure that is used when performing communication
/// with the kernel.
///
/// From the kernel documentation:
///
/// ```text
/// struct spi_ioc_transfer - describes a single SPI transfer
/// @tx_buf: Holds pointer to userspace buffer with transmit data, or null.
///   If no data is provided, zeroes are shifted out.
/// @rx_buf: Holds pointer to userspace buffer for receive data, or null.
/// @len: Length of tx and rx buffers, in bytes.
/// @speed_hz: Temporary override of the device's bitrate.
/// @bits_per_word: Temporary override of the device's wordsize.
/// @delay_usecs: If nonzero, how long to delay after the last bit transfer
///      before optionally deselecting the device before the next transfer.
/// @cs_change: True to deselect device before starting the next transfer.
///
/// This structure is mapped directly to the kernel spi_transfer structure;
/// the fields have the same meanings, except of course that the pointers
/// are in a different address space (and may be of different sizes in some
/// cases, such as 32-bit i386 userspace over a 64-bit x86_64 kernel).
/// Zero-initialize the structure, including currently unused fields, to
/// accommodate potential future updates.
///
/// SPI_IOC_MESSAGE gives userspace the equivalent of kernel spi_sync().
/// Pass it an array of related transfers, they'll execute together.
/// Each transfer may be half duplex (either direction) or full duplex.
///
///      struct spi_ioc_transfer mesg[4];
///      ...
///      status = ioctl(fd, SPI_IOC_MESSAGE(4), mesg);
///
/// So for example one transfer might send a nine bit command (right aligned
/// in a 16-bit word), the next could read a block of 8-bit data before
/// terminating that command by temporarily deselecting the chip; the next
/// could send a different nine bit command (re-selecting the chip), and the
/// last transfer might write some register values.
/// ```
#[allow(non_camel_case_types)]
#[derive(Debug)]
#[repr(C)]
struct spi_ioc_transfer {
    pub tx_buf: u64,
    pub rx_buf: u64,
    pub len: u32,

    // optional overrides
    pub speed_hz: u32,
    pub delay_usecs: u16,
    pub bits_per_word: u8,
    pub cs_change: u8,
    pub pad: u32,
}

/// Representation of a spidev transfer that is shared
/// with external users
#[derive(Default)]
pub struct SpidevTransfer {
    pub tx_buf: Option<Box<[u8]>>,
    pub rx_buf: Option<Box<[u8]>>,
    len: u32,
    speed_hz: u32,
    delay_usecs: u16,
    bits_per_word: u8,
    cs_change: u8,
    pad: u32,
}

impl SpidevTransfer {
    pub fn read(length: usize) -> SpidevTransfer {
        SpidevTransfer {
            tx_buf: None,
            rx_buf: Some(vec![0u8; length].into_boxed_slice()),
            len: length as u32,
            ..Default::default()
        }
    }

    pub fn write(tx_buf: &[u8]) -> SpidevTransfer {
        let len = tx_buf.len();
        let rx_buf_vec: Vec<u8> = vec![0; len];
        let mut tx_buf_vec = Vec::with_capacity(len);
        for i in 0..len {
            tx_buf_vec.push(tx_buf[i]);
        }

        SpidevTransfer {
            tx_buf: Some(tx_buf_vec.into_boxed_slice()),
            rx_buf: Some(rx_buf_vec.into_boxed_slice()),
            len: tx_buf.len() as u32,
            ..Default::default()
        }
    }

    fn as_spi_ioc_transfer(&self) -> spi_ioc_transfer {
        spi_ioc_transfer {
            tx_buf: match self.tx_buf {
                Some(ref bufbox) => bufbox.as_ptr() as u64,
                None => 0,
            },
            rx_buf: match self.rx_buf {
                Some(ref bufbox) => bufbox.as_ptr() as u64,
                None => 0,
            },
            len: self.len,
            speed_hz: self.speed_hz,
            delay_usecs: self.delay_usecs,
            bits_per_word: self.bits_per_word,
            cs_change: self.cs_change,
            pad: self.pad,
        }
    }
}

ioctl!(read ioctl_get_mode_u8 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u8);
ioctl!(read ioctl_get_mode_u32 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u32);
ioctl!(write ioctl_set_mode_u8 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u8);
ioctl!(write ioctl_set_mode_u32 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE32; u32);

pub fn get_mode(fd: RawFd) -> io::Result<u8> {
    let mut mode: u8 = 0;
    try!(from_nix_result(unsafe { ioctl_get_mode_u8(fd, &mut mode) }));
    Ok(mode)
}

pub fn set_mode(fd: RawFd, mode: SpiModeFlags) -> io::Result<()> {
    // we will always use the 8-bit mode write unless bits not in
    // the 8-bit mask are used.  This is because WR_MODE32 was not
    // added until later kernels.  This provides a reasonable story
    // for forwards and backwards compatibility
    if (mode.bits & 0xFFFFFF00) != 0 {
        try!(from_nix_result(unsafe { ioctl_set_mode_u32(fd, &mode.bits) }));
    } else {
        let bits: u8 = mode.bits as u8;
        try!(from_nix_result(unsafe { ioctl_set_mode_u8(fd, &bits) }));
    }
    Ok(())
}

ioctl!(read  ioctl_get_lsb_first with SPI_IOC_MAGIC, SPI_IOC_NR_LSB_FIRST; u8);
ioctl!(write ioctl_set_lsb_first with SPI_IOC_MAGIC, SPI_IOC_NR_LSB_FIRST; u8);

pub fn get_lsb_first(fd: RawFd) -> io::Result<u8> {
    let mut lsb_first: u8 = 0;
    try!(from_nix_result(unsafe { ioctl_get_lsb_first(fd, &mut lsb_first) }));
    Ok(lsb_first)
}

pub fn set_lsb_first(fd: RawFd, lsb_first: bool) -> io::Result<()> {
    let lsb_first_value: u8 = if lsb_first { 1 } else { 0 };
    try!(from_nix_result(unsafe { ioctl_set_lsb_first(fd, &lsb_first_value) }));
    Ok(())
}

ioctl!(read  ioctl_get_bits_per_word with SPI_IOC_MAGIC, SPI_IOC_NR_BITS_PER_WORD; u8);
ioctl!(write ioctl_set_bits_per_word with SPI_IOC_MAGIC, SPI_IOC_NR_BITS_PER_WORD; u8);

pub fn get_bits_per_word(fd: RawFd) -> io::Result<u8> {
    let mut bits_per_word: u8 = 0;
    try!(from_nix_result(unsafe { ioctl_get_bits_per_word(fd, &mut bits_per_word)} ));
    Ok(bits_per_word)
}

pub fn set_bits_per_word(fd: RawFd, bits_per_word: u8) -> io::Result<()> {
    try!(from_nix_result(unsafe { ioctl_set_bits_per_word(fd, &bits_per_word) }));
    Ok(())
}

ioctl!(read  ioctl_get_max_speed_hz with SPI_IOC_MAGIC, SPI_IOC_NR_MAX_SPEED_HZ; u32);
ioctl!(write ioctl_set_max_speed_hz with SPI_IOC_MAGIC, SPI_IOC_NR_MAX_SPEED_HZ; u32);

pub fn get_max_speed_hz(fd: RawFd) -> io::Result<u32> {
    let mut max_speed_hz: u32 = 0;
    try!(from_nix_result(unsafe { ioctl_get_max_speed_hz(fd, &mut max_speed_hz)} ));
    Ok(max_speed_hz)
}

pub fn set_max_speed_hz(fd: RawFd, max_speed_hz: u32) -> io::Result<()> {
    try!(from_nix_result(unsafe { ioctl_set_max_speed_hz(fd, &max_speed_hz) }));
    Ok(())
}

// NOTE: this macro works for single transfers but cannot properly
// calculate size for multi transfer whose length we will not know
// until runtime.  We fallback to using the underlying ioctl for that
// use case.
ioctl!(write ioctl_spidev_transfer with SPI_IOC_MAGIC, SPI_IOC_NR_TRANSFER; spi_ioc_transfer);
ioctl!(write buf ioctl_spidev_transfer_buf with SPI_IOC_MAGIC, SPI_IOC_NR_TRANSFER; Box<[spi_ioc_transfer]>);

pub fn transfer(fd: RawFd, transfer: &mut SpidevTransfer) -> io::Result<()> {
    let mut raw_transfer = transfer.as_spi_ioc_transfer();

    // The kernel will directly modify the rx_buf of the SpidevTransfer
    // rx_buf if present, so there is no need to do any additional work
    try!(from_nix_result(unsafe { ioctl_spidev_transfer(fd, &mut raw_transfer) }));
    Ok(())
}

pub fn transfer_multiple(fd: RawFd, transfers: &Vec<SpidevTransfer>) -> io::Result<()> {
    // create a boxed slice containing several spi_ioc_transfers
    let mut raw_transfers = transfers
        .iter()
        .map(|transfer| transfer.as_spi_ioc_transfer())
        .collect::<Vec<_>>()
        .into_boxed_slice();

    let tot_size = raw_transfers.len() * mem::size_of::<spi_ioc_transfer>();
    try!(from_nix_result(unsafe { ioctl_spidev_transfer_buf(fd, &mut raw_transfers, tot_size) }));
    Ok(())
}
<commit_msg>ioctl: nix: fix up multiple transfer code by using as_mut_ptr()<commit_after>// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/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.

#![allow(dead_code)]

use std::io;
use std::mem;
use std::os::unix::prelude::*;
use super::SpiModeFlags;

const SPI_IOC_MAGIC: u8 = 'k' as u8;

const SPI_IOC_NR_TRANSFER: u8 = 0;
const SPI_IOC_NR_MODE: u8 = 1;
const SPI_IOC_NR_LSB_FIRST: u8 = 2;
const SPI_IOC_NR_BITS_PER_WORD: u8 = 3;
const SPI_IOC_NR_MAX_SPEED_HZ: u8 = 4;
const SPI_IOC_NR_MODE32: u8 = 5;

fn from_nix_error(err: ::nix::Error) -> io::Error {
    io::Error::from_raw_os_error(err.errno() as i32)
}

fn from_nix_result<T>(res: ::nix::Result<T>) -> io::Result<T> {
    match res {
        Ok(r) => Ok(r),
        Err(err) => Err(from_nix_error(err)),
    }
}

/// Structure that is used when performing communication
/// with the kernel.
///
/// From the kernel documentation:
///
/// ```text
/// struct spi_ioc_transfer - describes a single SPI transfer
/// @tx_buf: Holds pointer to userspace buffer with transmit data, or null.
///   If no data is provided, zeroes are shifted out.
/// @rx_buf: Holds pointer to userspace buffer for receive data, or null.
/// @len: Length of tx and rx buffers, in bytes.
/// @speed_hz: Temporary override of the device's bitrate.
/// @bits_per_word: Temporary override of the device's wordsize.
/// @delay_usecs: If nonzero, how long to delay after the last bit transfer
///      before optionally deselecting the device before the next transfer.
/// @cs_change: True to deselect device before starting the next transfer.
///
/// This structure is mapped directly to the kernel spi_transfer structure;
/// the fields have the same meanings, except of course that the pointers
/// are in a different address space (and may be of different sizes in some
/// cases, such as 32-bit i386 userspace over a 64-bit x86_64 kernel).
/// Zero-initialize the structure, including currently unused fields, to
/// accommodate potential future updates.
///
/// SPI_IOC_MESSAGE gives userspace the equivalent of kernel spi_sync().
/// Pass it an array of related transfers, they'll execute together.
/// Each transfer may be half duplex (either direction) or full duplex.
///
///      struct spi_ioc_transfer mesg[4];
///      ...
///      status = ioctl(fd, SPI_IOC_MESSAGE(4), mesg);
///
/// So for example one transfer might send a nine bit command (right aligned
/// in a 16-bit word), the next could read a block of 8-bit data before
/// terminating that command by temporarily deselecting the chip; the next
/// could send a different nine bit command (re-selecting the chip), and the
/// last transfer might write some register values.
/// ```
#[allow(non_camel_case_types)]
#[derive(Debug)]
#[repr(C)]
struct spi_ioc_transfer {
    pub tx_buf: u64,
    pub rx_buf: u64,
    pub len: u32,

    // optional overrides
    pub speed_hz: u32,
    pub delay_usecs: u16,
    pub bits_per_word: u8,
    pub cs_change: u8,
    pub pad: u32,
}

/// Representation of a spidev transfer that is shared
/// with external users
#[derive(Default)]
pub struct SpidevTransfer {
    pub tx_buf: Option<Box<[u8]>>,
    pub rx_buf: Option<Box<[u8]>>,
    len: u32,
    speed_hz: u32,
    delay_usecs: u16,
    bits_per_word: u8,
    cs_change: u8,
    pad: u32,
}

impl SpidevTransfer {
    pub fn read(length: usize) -> SpidevTransfer {
        SpidevTransfer {
            tx_buf: None,
            rx_buf: Some(vec![0u8; length].into_boxed_slice()),
            len: length as u32,
            ..Default::default()
        }
    }

    pub fn write(tx_buf: &[u8]) -> SpidevTransfer {
        let len = tx_buf.len();
        let rx_buf_vec: Vec<u8> = vec![0; len];
        let mut tx_buf_vec = Vec::with_capacity(len);
        for i in 0..len {
            tx_buf_vec.push(tx_buf[i]);
        }

        SpidevTransfer {
            tx_buf: Some(tx_buf_vec.into_boxed_slice()),
            rx_buf: Some(rx_buf_vec.into_boxed_slice()),
            len: tx_buf.len() as u32,
            ..Default::default()
        }
    }

    fn as_spi_ioc_transfer(&self) -> spi_ioc_transfer {
        spi_ioc_transfer {
            tx_buf: match self.tx_buf {
                Some(ref bufbox) => bufbox.as_ptr() as u64,
                None => 0,
            },
            rx_buf: match self.rx_buf {
                Some(ref bufbox) => bufbox.as_ptr() as u64,
                None => 0,
            },
            len: self.len,
            speed_hz: self.speed_hz,
            delay_usecs: self.delay_usecs,
            bits_per_word: self.bits_per_word,
            cs_change: self.cs_change,
            pad: self.pad,
        }
    }
}

ioctl!(read ioctl_get_mode_u8 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u8);
ioctl!(read ioctl_get_mode_u32 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u32);
ioctl!(write ioctl_set_mode_u8 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u8);
ioctl!(write ioctl_set_mode_u32 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE32; u32);

pub fn get_mode(fd: RawFd) -> io::Result<u8> {
    let mut mode: u8 = 0;
    try!(from_nix_result(unsafe { ioctl_get_mode_u8(fd, &mut mode) }));
    Ok(mode)
}

pub fn set_mode(fd: RawFd, mode: SpiModeFlags) -> io::Result<()> {
    // we will always use the 8-bit mode write unless bits not in
    // the 8-bit mask are used.  This is because WR_MODE32 was not
    // added until later kernels.  This provides a reasonable story
    // for forwards and backwards compatibility
    if (mode.bits & 0xFFFFFF00) != 0 {
        try!(from_nix_result(unsafe { ioctl_set_mode_u32(fd, &mode.bits) }));
    } else {
        let bits: u8 = mode.bits as u8;
        try!(from_nix_result(unsafe { ioctl_set_mode_u8(fd, &bits) }));
    }
    Ok(())
}

ioctl!(read  ioctl_get_lsb_first with SPI_IOC_MAGIC, SPI_IOC_NR_LSB_FIRST; u8);
ioctl!(write ioctl_set_lsb_first with SPI_IOC_MAGIC, SPI_IOC_NR_LSB_FIRST; u8);

pub fn get_lsb_first(fd: RawFd) -> io::Result<u8> {
    let mut lsb_first: u8 = 0;
    try!(from_nix_result(unsafe { ioctl_get_lsb_first(fd, &mut lsb_first) }));
    Ok(lsb_first)
}

pub fn set_lsb_first(fd: RawFd, lsb_first: bool) -> io::Result<()> {
    let lsb_first_value: u8 = if lsb_first { 1 } else { 0 };
    try!(from_nix_result(unsafe { ioctl_set_lsb_first(fd, &lsb_first_value) }));
    Ok(())
}

ioctl!(read  ioctl_get_bits_per_word with SPI_IOC_MAGIC, SPI_IOC_NR_BITS_PER_WORD; u8);
ioctl!(write ioctl_set_bits_per_word with SPI_IOC_MAGIC, SPI_IOC_NR_BITS_PER_WORD; u8);

pub fn get_bits_per_word(fd: RawFd) -> io::Result<u8> {
    let mut bits_per_word: u8 = 0;
    try!(from_nix_result(unsafe { ioctl_get_bits_per_word(fd, &mut bits_per_word)} ));
    Ok(bits_per_word)
}

pub fn set_bits_per_word(fd: RawFd, bits_per_word: u8) -> io::Result<()> {
    try!(from_nix_result(unsafe { ioctl_set_bits_per_word(fd, &bits_per_word) }));
    Ok(())
}

ioctl!(read  ioctl_get_max_speed_hz with SPI_IOC_MAGIC, SPI_IOC_NR_MAX_SPEED_HZ; u32);
ioctl!(write ioctl_set_max_speed_hz with SPI_IOC_MAGIC, SPI_IOC_NR_MAX_SPEED_HZ; u32);

pub fn get_max_speed_hz(fd: RawFd) -> io::Result<u32> {
    let mut max_speed_hz: u32 = 0;
    try!(from_nix_result(unsafe { ioctl_get_max_speed_hz(fd, &mut max_speed_hz)} ));
    Ok(max_speed_hz)
}

pub fn set_max_speed_hz(fd: RawFd, max_speed_hz: u32) -> io::Result<()> {
    try!(from_nix_result(unsafe { ioctl_set_max_speed_hz(fd, &max_speed_hz) }));
    Ok(())
}

// NOTE: this macro works for single transfers but cannot properly
// calculate size for multi transfer whose length we will not know
// until runtime.  We fallback to using the underlying ioctl for that
// use case.
ioctl!(write ioctl_spidev_transfer with SPI_IOC_MAGIC, SPI_IOC_NR_TRANSFER; spi_ioc_transfer);
ioctl!(write buf ioctl_spidev_transfer_buf with SPI_IOC_MAGIC, SPI_IOC_NR_TRANSFER; spi_ioc_transfer);

pub fn transfer(fd: RawFd, transfer: &mut SpidevTransfer) -> io::Result<()> {
    let mut raw_transfer = transfer.as_spi_ioc_transfer();

    // The kernel will directly modify the rx_buf of the SpidevTransfer
    // rx_buf if present, so there is no need to do any additional work
    try!(from_nix_result(unsafe {
        ioctl_spidev_transfer(fd, &mut raw_transfer)
    }));
    Ok(())
}

pub fn transfer_multiple(fd: RawFd, transfers: &Vec<SpidevTransfer>) -> io::Result<()> {
    // create a boxed slice containing several spi_ioc_transfers
    let mut raw_transfers = transfers
        .iter()
        .map(|transfer| transfer.as_spi_ioc_transfer())
        .collect::<Vec<_>>()
        .into_boxed_slice();
    let tot_size = raw_transfers.len() * mem::size_of::<spi_ioc_transfer>();

    try!(from_nix_result(unsafe {
        ioctl_spidev_transfer_buf(fd, raw_transfers.as_mut_ptr(), tot_size)
    }));
    Ok(())
}
<|endoftext|>


<commit_before>use crate::utils::sugg::Sugg;
use crate::utils::{
    get_parent_expr, is_type_diagnostic_item, match_def_path, match_trait_method, paths, snippet,
    snippet_with_macro_callsite, span_lint_and_help, span_lint_and_sugg,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, TyS};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::sym;

declare_clippy_lint! {
    /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls
    /// that uselessly convert to the same type.
    ///
    /// **Why is this bad?** Redundant code.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // Bad
    /// // format!() returns a `String`
    /// let s: String = format!("hello").into();
    ///
    /// // Good
    /// let s: String = format!("hello");
    /// ```
    pub USELESS_CONVERSION,
    complexity,
    "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` that perform useless conversions to the same type"
}

#[derive(Default)]
pub struct UselessConversion {
    try_desugar_arm: Vec<HirId>,
}

impl_lint_pass!(UselessConversion => [USELESS_CONVERSION]);

#[allow(clippy::too_many_lines)]
impl<'tcx> LateLintPass<'tcx> for UselessConversion {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        if e.span.from_expansion() {
            return;
        }

        if Some(&e.hir_id) == self.try_desugar_arm.last() {
            return;
        }

        match e.kind {
            ExprKind::Match(_, ref arms, MatchSource::TryDesugar) => {
                let e = match arms[0].body.kind {
                    ExprKind::Ret(Some(ref e)) | ExprKind::Break(_, Some(ref e)) => e,
                    _ => return,
                };
                if let ExprKind::Call(_, ref args) = e.kind {
                    self.try_desugar_arm.push(args[0].hir_id);
                }
            },

            ExprKind::MethodCall(ref name, .., ref args, _) => {
                if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" {
                    let a = cx.typeck_results().expr_ty(e);
                    let b = cx.typeck_results().expr_ty(&args[0]);
                    if TyS::same_type(a, b) {
                        let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
                        span_lint_and_sugg(
                            cx,
                            USELESS_CONVERSION,
                            e.span,
                            &format!("useless conversion to the same type: `{}`", b),
                            "consider removing `.into()`",
                            sugg,
                            Applicability::MachineApplicable, // snippet
                        );
                    }
                }
                if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" {
                    if let Some(parent_expr) = get_parent_expr(cx, e) {
                        if let ExprKind::MethodCall(ref parent_name, ..) = parent_expr.kind {
                            if &*parent_name.ident.as_str() != "into_iter" {
                                return;
                            }
                        }
                    }
                    let a = cx.typeck_results().expr_ty(e);
                    let b = cx.typeck_results().expr_ty(&args[0]);
                    if TyS::same_type(a, b) {
                        let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
                        span_lint_and_sugg(
                            cx,
                            USELESS_CONVERSION,
                            e.span,
                            &format!("useless conversion to the same type: `{}`", b),
                            "consider removing `.into_iter()`",
                            sugg,
                            Applicability::MachineApplicable, // snippet
                        );
                    }
                }
                if match_trait_method(cx, e, &paths::TRY_INTO_TRAIT) && &*name.ident.as_str() == "try_into" {
                    if_chain! {
                        let a = cx.typeck_results().expr_ty(e);
                        let b = cx.typeck_results().expr_ty(&args[0]);
                        if is_type_diagnostic_item(cx, a, sym::result_type);
                        if let ty::Adt(_, substs) = a.kind();
                        if let Some(a_type) = substs.types().next();
                        if TyS::same_type(a_type, b);

                        then {
                            span_lint_and_help(
                                cx,
                                USELESS_CONVERSION,
                                e.span,
                                &format!("useless conversion to the same type: `{}`", b),
                                None,
                                "consider removing `.try_into()`",
                            );
                        }
                    }
                }
            },

            ExprKind::Call(ref path, ref args) => {
                if_chain! {
                    if args.len() == 1;
                    if let ExprKind::Path(ref qpath) = path.kind;
                    if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
                    let a = cx.typeck_results().expr_ty(e);
                    let b = cx.typeck_results().expr_ty(&args[0]);

                    then {
                        if_chain! {
                            if match_def_path(cx, def_id, &paths::TRY_FROM);
                            if is_type_diagnostic_item(cx, a, sym::result_type);
                            if let ty::Adt(_, substs) = a.kind();
                            if let Some(a_type) = substs.types().next();
                            if TyS::same_type(a_type, b);

                            then {
                                let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from"));
                                span_lint_and_help(
                                    cx,
                                    USELESS_CONVERSION,
                                    e.span,
                                    &format!("useless conversion to the same type: `{}`", b),
                                    None,
                                    &hint,
                                );
                            }
                        }

                        if_chain! {
                            if match_def_path(cx, def_id, &paths::FROM_FROM);
                            if TyS::same_type(a, b);

                            then {
                                let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "<expr>").maybe_par();
                                let sugg_msg =
                                    format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
                                span_lint_and_sugg(
                                    cx,
                                    USELESS_CONVERSION,
                                    e.span,
                                    &format!("useless conversion to the same type: `{}`", b),
                                    &sugg_msg,
                                    sugg.to_string(),
                                    Applicability::MachineApplicable, // snippet
                                );
                            }
                        }
                    }
                }
            },

            _ => {},
        }
    }

    fn check_expr_post(&mut self, _: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        if Some(&e.hir_id) == self.try_desugar_arm.last() {
            self.try_desugar_arm.pop();
        }
    }
}
<commit_msg>Apply suggestions from code review to change "that" to "which"<commit_after>use crate::utils::sugg::Sugg;
use crate::utils::{
    get_parent_expr, is_type_diagnostic_item, match_def_path, match_trait_method, paths, snippet,
    snippet_with_macro_callsite, span_lint_and_help, span_lint_and_sugg,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, TyS};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::sym;

declare_clippy_lint! {
    /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls
    /// which uselessly convert to the same type.
    ///
    /// **Why is this bad?** Redundant code.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // Bad
    /// // format!() returns a `String`
    /// let s: String = format!("hello").into();
    ///
    /// // Good
    /// let s: String = format!("hello");
    /// ```
    pub USELESS_CONVERSION,
    complexity,
    "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` which perform useless conversions to the same type"
}

#[derive(Default)]
pub struct UselessConversion {
    try_desugar_arm: Vec<HirId>,
}

impl_lint_pass!(UselessConversion => [USELESS_CONVERSION]);

#[allow(clippy::too_many_lines)]
impl<'tcx> LateLintPass<'tcx> for UselessConversion {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        if e.span.from_expansion() {
            return;
        }

        if Some(&e.hir_id) == self.try_desugar_arm.last() {
            return;
        }

        match e.kind {
            ExprKind::Match(_, ref arms, MatchSource::TryDesugar) => {
                let e = match arms[0].body.kind {
                    ExprKind::Ret(Some(ref e)) | ExprKind::Break(_, Some(ref e)) => e,
                    _ => return,
                };
                if let ExprKind::Call(_, ref args) = e.kind {
                    self.try_desugar_arm.push(args[0].hir_id);
                }
            },

            ExprKind::MethodCall(ref name, .., ref args, _) => {
                if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" {
                    let a = cx.typeck_results().expr_ty(e);
                    let b = cx.typeck_results().expr_ty(&args[0]);
                    if TyS::same_type(a, b) {
                        let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
                        span_lint_and_sugg(
                            cx,
                            USELESS_CONVERSION,
                            e.span,
                            &format!("useless conversion to the same type: `{}`", b),
                            "consider removing `.into()`",
                            sugg,
                            Applicability::MachineApplicable, // snippet
                        );
                    }
                }
                if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" {
                    if let Some(parent_expr) = get_parent_expr(cx, e) {
                        if let ExprKind::MethodCall(ref parent_name, ..) = parent_expr.kind {
                            if &*parent_name.ident.as_str() != "into_iter" {
                                return;
                            }
                        }
                    }
                    let a = cx.typeck_results().expr_ty(e);
                    let b = cx.typeck_results().expr_ty(&args[0]);
                    if TyS::same_type(a, b) {
                        let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
                        span_lint_and_sugg(
                            cx,
                            USELESS_CONVERSION,
                            e.span,
                            &format!("useless conversion to the same type: `{}`", b),
                            "consider removing `.into_iter()`",
                            sugg,
                            Applicability::MachineApplicable, // snippet
                        );
                    }
                }
                if match_trait_method(cx, e, &paths::TRY_INTO_TRAIT) && &*name.ident.as_str() == "try_into" {
                    if_chain! {
                        let a = cx.typeck_results().expr_ty(e);
                        let b = cx.typeck_results().expr_ty(&args[0]);
                        if is_type_diagnostic_item(cx, a, sym::result_type);
                        if let ty::Adt(_, substs) = a.kind();
                        if let Some(a_type) = substs.types().next();
                        if TyS::same_type(a_type, b);

                        then {
                            span_lint_and_help(
                                cx,
                                USELESS_CONVERSION,
                                e.span,
                                &format!("useless conversion to the same type: `{}`", b),
                                None,
                                "consider removing `.try_into()`",
                            );
                        }
                    }
                }
            },

            ExprKind::Call(ref path, ref args) => {
                if_chain! {
                    if args.len() == 1;
                    if let ExprKind::Path(ref qpath) = path.kind;
                    if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
                    let a = cx.typeck_results().expr_ty(e);
                    let b = cx.typeck_results().expr_ty(&args[0]);

                    then {
                        if_chain! {
                            if match_def_path(cx, def_id, &paths::TRY_FROM);
                            if is_type_diagnostic_item(cx, a, sym::result_type);
                            if let ty::Adt(_, substs) = a.kind();
                            if let Some(a_type) = substs.types().next();
                            if TyS::same_type(a_type, b);

                            then {
                                let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from"));
                                span_lint_and_help(
                                    cx,
                                    USELESS_CONVERSION,
                                    e.span,
                                    &format!("useless conversion to the same type: `{}`", b),
                                    None,
                                    &hint,
                                );
                            }
                        }

                        if_chain! {
                            if match_def_path(cx, def_id, &paths::FROM_FROM);
                            if TyS::same_type(a, b);

                            then {
                                let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "<expr>").maybe_par();
                                let sugg_msg =
                                    format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
                                span_lint_and_sugg(
                                    cx,
                                    USELESS_CONVERSION,
                                    e.span,
                                    &format!("useless conversion to the same type: `{}`", b),
                                    &sugg_msg,
                                    sugg.to_string(),
                                    Applicability::MachineApplicable, // snippet
                                );
                            }
                        }
                    }
                }
            },

            _ => {},
        }
    }

    fn check_expr_post(&mut self, _: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        if Some(&e.hir_id) == self.try_desugar_arm.last() {
            self.try_desugar_arm.pop();
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Added Display, however, now we need to fix the lifetimes...<commit_after><|endoftext|>


<commit_before>#![feature(test)]
extern crate parser_combinators as pc;
extern crate test;

use std::collections::HashMap;
use std::io::Read;
use std::fs::File;
use std::path::Path;

use pc::primitives::{Parser, State, ParseResult};
use pc::combinator::{between, many, many1, optional, parser, sep_by, unexpected, With, ParserExt};
use pc::char::{any_char, digit, satisfy, spaces, Spaces, string};

#[derive(PartialEq, Debug)]
enum Value {
    Number(f64),
    String(String),
    Bool(bool),
    Null,
    Object(HashMap<String, Value>),
    Array(Vec<Value>)
}

fn lex<'a, P>(p: P) -> With<Spaces<&'a str>, P>
    where P: Parser<Input=&'a str> {
    spaces().with(p)
}

fn integer(input: State<&str>) -> ParseResult<i64, &str> {
    let (s, input) = try!(many1::<String, _>(digit())
        .expected("integer")
        .parse_state(input));
    let mut n = 0;
    for c in s.chars() {
        n = n * 10 + (c as i64 - '0' as i64);
    }
    Ok((n, input))
}

fn number(input: State<&str>) -> ParseResult<f64, &str> {
    let i = satisfy(|c| c == '0').map(|_| 0.0)
             .or(parser(integer).map(|x| x as f64));
    let fractional = many(digit())
        .map(|digits: String| {
            let mut magnitude = 1.0;
            digits.chars().fold(0.0, |acc, d| {
                magnitude /= 10.0;
                match d.to_digit(10) {
                    Some(d) => acc + (d as f64) * magnitude,
                    None => panic!("Not a digit")
                }
            })
        });

    let exp = satisfy(|c| c == 'e' || c == 'E')
        .with(optional(string("-")).and(parser(integer)));
    optional(string("-"))
        .and(i)
        .map(|(sign, n)| if sign.is_some() { -n } else { n })
        .and(optional(string(".")).with(fractional))
        .map(|(x, y)| if x > 0.0 { x + y } else { x - y })
        .and(optional(exp))
        .map(|(n, exp_option)| {
            match exp_option {
                Some((sign, e)) => {
                    let e = if sign.is_some() { -e } else { e };
                    n * 10.0f64.powi(e as i32)
                }
                None => n
            }
        })
    .parse_state(input)
}

fn json_char(input: State<&str>) -> ParseResult<char, &str> {
    let (c, input) = try!(parser(any_char).parse_state(input));
    let mut back_slash_char = satisfy(|c| "\"\\/bfnrt".chars().find(|x| *x == c).is_some()).map(|c| {
        match c {
            '"' => '"',
            '\\' => '\\',
            '/' => '/',
            'b' => '\u{0008}',
            'f' => '\u{000c}',
            'n' => '\n',
            'r' => '\r',
            't' => '\t',
            c => c//Should never happen
        }
    });
    match c {
        '\\' => input.combine(|input| back_slash_char.parse_state(input)),
        '"'  => unexpected("\"").parse_state(input.into_inner()).map(|_| unreachable!()),
        _    => Ok((c, input))
    }
}
fn json_string(input: State<&str>) -> ParseResult<String, &str> {
    between(string("\""), string("\""), many(parser(json_char)))
        .parse_state(input)
}
fn object(input: State<&str>) -> ParseResult<Value, &str> {
    let field = lex(parser(json_string))
        .skip(lex(string(":")))
        .and(lex(parser(json_value)));
    let fields = sep_by(field, string(","));
    between(string("{"), lex(string("}")), fields)
        .map(Value::Object)
        .parse_state(input)
}

#[allow(unconditional_recursion)]
fn json_value(input: State<&str>) -> ParseResult<Value, &str> {
    let array = between(string("["), lex(string("]")), sep_by(parser(json_value), string(",")))
        .map(Value::Array);

    //Wrap a few of the value parsers to workaround the slow compiletimes
    fn rest(input: State<&str>) -> ParseResult<Value, &str> {
        string("false").map(|_| Value::Bool(false))
            .or(string("true").map(|_| Value::Bool(true)))
            .or(string("null").map(|_| Value::Null))
            .parse_state(input)
    }
    lex(parser(json_string).map(Value::String)
        .or(parser(object))
        .or(array)
        .or(parser(number).map(Value::Number))
        .or(parser(rest))
    )
        .parse_state(input)
}

#[test]
fn json_test() {
    use self::Value::*;
    let input =
r#"
{
    "array": [1, ""],
    "object": {},
    "number": 3.14,
    "int": -100,
    "exp": -1e2,
    "exp_neg": 23e-2,
    "true": true,
    "false"  : false,
    "null" : null
}"#;
    let result = parser(json_value)
        .parse(input);
    let expected = Object(vec![
        ("array", Array(vec![Number(1.0), String("".to_string())])),
        ("object", Object(HashMap::new())),
        ("number", Number(3.14)),
        ("int", Number(-100.)),
        ("exp", Number(-1e2)),
        ("exp_neg", Number(23E-2)),
        ("true", Bool(true)),
        ("false", Bool(false)),
        ("null", Null)
    ].into_iter().map(|(k, v)| (k.to_string(), v)).collect());
    match result {
        Ok(result) => assert_eq!(result, (expected, "")),
        Err(e) => {
            println!("{}", e);
            assert!(false);
        }
    }
}

#[bench]
fn bench_json(bencher: &mut ::test::Bencher) {
    let mut data = String::new();
    File::open(&Path::new(&"benches/data.json"))
        .and_then(|mut file| file.read_to_string(&mut data))
        .unwrap();
    let mut parser = parser(json_value);
    match parser.parse(&data[..]) {
        Ok((Value::Array(_), "\r\n")) => (),
        Ok(x) => { println!("{:?}", x); assert!(false); }
        Err(err) => { println!("{}", err); assert!(false); }
    }
    bencher.iter(|| {
        let result = parser.parse(&data);
        ::test::black_box(result)
    });
}
<commit_msg>Generalized the json parser to work with an type of input<commit_after>#![feature(test)]
extern crate parser_combinators as pc;
extern crate test;

use std::collections::HashMap;
use std::io::Read;
use std::fs::File;
use std::path::Path;

use pc::primitives::{Parser, State, Stream, ParseResult};
use pc::combinator::{between, many, many1, optional, parser, sep_by, unexpected, With, ParserExt};
use pc::char::{any_char, digit, satisfy, spaces, Spaces, string};

#[derive(PartialEq, Debug)]
enum Value {
    Number(f64),
    String(String),
    Bool(bool),
    Null,
    Object(HashMap<String, Value>),
    Array(Vec<Value>)
}

fn lex<'a, P>(p: P) -> With<Spaces<P::Input>, P>
    where P: Parser
        , P::Input: Stream<Item=char> {
    spaces().with(p)
}
struct Json<I>(::std::marker::PhantomData<fn (I) -> I>);

impl <I> Json<I>
    where I: Stream<Item=char> {

    fn integer(input: State<I>) -> ParseResult<i64, I> {
        let (s, input) = try!(many1::<String, _>(digit())
            .expected("integer")
            .parse_state(input));
        let mut n = 0;
        for c in s.chars() {
            n = n * 10 + (c as i64 - '0' as i64);
        }
        Ok((n, input))
    }

    fn number(input: State<I>) -> ParseResult<f64, I> {
        let i = satisfy(|c| c == '0').map(|_| 0.0)
                 .or(parser(Json::<I>::integer).map(|x| x as f64));
        let fractional = many(digit())
            .map(|digits: String| {
                let mut magnitude = 1.0;
                digits.chars().fold(0.0, |acc, d| {
                    magnitude /= 10.0;
                    match d.to_digit(10) {
                        Some(d) => acc + (d as f64) * magnitude,
                        None => panic!("Not a digit")
                    }
                })
            });

        let exp = satisfy(|c| c == 'e' || c == 'E')
            .with(optional(string("-")).and(parser(Json::<I>::integer)));
        optional(string("-"))
            .and(i)
            .map(|(sign, n)| if sign.is_some() { -n } else { n })
            .and(optional(string(".")).with(fractional))
            .map(|(x, y)| if x > 0.0 { x + y } else { x - y })
            .and(optional(exp))
            .map(|(n, exp_option)| {
                match exp_option {
                    Some((sign, e)) => {
                        let e = if sign.is_some() { -e } else { e };
                        n * 10.0f64.powi(e as i32)
                    }
                    None => n
                }
            })
        .parse_state(input)
    }

    fn char(input: State<I>) -> ParseResult<char, I> {
        let (c, input) = try!(parser(any_char).parse_state(input));
        let mut back_slash_char = satisfy(|c| "\"\\/bfnrt".chars().find(|x| *x == c).is_some()).map(|c| {
            match c {
                '"' => '"',
                '\\' => '\\',
                '/' => '/',
                'b' => '\u{0008}',
                'f' => '\u{000c}',
                'n' => '\n',
                'r' => '\r',
                't' => '\t',
                c => c//Should never happen
            }
        });
        match c {
            '\\' => input.combine(|input| back_slash_char.parse_state(input)),
            '"'  => unexpected("\"").parse_state(input.into_inner()).map(|_| unreachable!()),
            _    => Ok((c, input))
        }
    }
    fn string(input: State<I>) -> ParseResult<String, I> {
        between(string("\""), string("\""), many(parser(Json::<I>::char)))
            .parse_state(input)
    }
    fn object(input: State<I>) -> ParseResult<Value, I> {
        let field = lex(parser(Json::<I>::string))
            .skip(lex(string(":")))
            .and(lex(parser(Json::<I>::value)));
        let fields = sep_by(field, string(","));
        between(string("{"), lex(string("}")), fields)
            .map(Value::Object)
            .parse_state(input)
    }

    #[allow(unconditional_recursion)]
    fn value(input: State<I>) -> ParseResult<Value, I>
        where I: Stream<Item=char> {
        let array = between(string("["), lex(string("]")), sep_by(parser(Json::<I>::value), string(",")))
            .map(Value::Array);

        //Wrap a few of the value parsers to workaround the slow compiletimes
        fn rest<I>(input: State<I>) -> ParseResult<Value, I>
            where I: Stream<Item=char> {
            string("false").map(|_| Value::Bool(false))
                .or(string("true").map(|_| Value::Bool(true)))
                .or(string("null").map(|_| Value::Null))
                .parse_state(input)
        }
        lex(parser(Json::<I>::string).map(Value::String)
            .or(parser(Json::<I>::object))
            .or(array)
            .or(parser(Json::<I>::number).map(Value::Number))
            .or(parser(rest))
        )
            .parse_state(input)
    }

}

#[test]
fn json_test() {
    use self::Value::*;
    let input =
r#"
{
    "array": [1, ""],
    "object": {},
    "number": 3.14,
    "int": -100,
    "exp": -1e2,
    "exp_neg": 23e-2,
    "true": true,
    "false"  : false,
    "null" : null
}"#;
    let result = parser(Json::value)
        .parse(input);
    let expected = Object(vec![
        ("array", Array(vec![Number(1.0), String("".to_string())])),
        ("object", Object(HashMap::new())),
        ("number", Number(3.14)),
        ("int", Number(-100.)),
        ("exp", Number(-1e2)),
        ("exp_neg", Number(23E-2)),
        ("true", Bool(true)),
        ("false", Bool(false)),
        ("null", Null)
    ].into_iter().map(|(k, v)| (k.to_string(), v)).collect());
    match result {
        Ok(result) => assert_eq!(result, (expected, "")),
        Err(e) => {
            println!("{}", e);
            assert!(false);
        }
    }
}

#[bench]
fn bench_json(bencher: &mut ::test::Bencher) {
    let mut data = String::new();
    File::open(&Path::new(&"benches/data.json"))
        .and_then(|mut file| file.read_to_string(&mut data))
        .unwrap();
    let mut parser = parser(Json::value);
    match parser.parse(&data[..]) {
        Ok((Value::Array(_), "\r\n")) => (),
        Ok(x) => { println!("{:?}", x); assert!(false); }
        Err(err) => { println!("{}", err); assert!(false); }
    }
    bencher.iter(|| {
        let result = parser.parse(&data);
        ::test::black_box(result)
    });
}
<|endoftext|>


<commit_before><commit_msg>Examine clippy::unit_arg<commit_after><|endoftext|>


<commit_before>extern crate mdbook;
#[macro_use]
extern crate pretty_assertions;
extern crate select;
extern crate walkdir;

mod dummy_book;

use dummy_book::{assert_contains_strings, DummyBook};

use std::path::Path;
use std::ffi::OsStr;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};
use select::document::Document;
use select::predicate::{Class, Name, Predicate};
use mdbook::errors::*;
use mdbook::utils::fs::file_to_string;
use mdbook::MDBook;

const BOOK_ROOT: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/dummy_book");
const TOC_TOP_LEVEL: &[&'static str] = &["1. First Chapter",
                                         "2. Second Chapter",
                                         "Conclusion",
                                         "Introduction"];
const TOC_SECOND_LEVEL: &[&'static str] = &["1.1. Nested Chapter"];

/// Make sure you can load the dummy book and build it without panicking.
#[test]
fn build_the_dummy_book() {
    let temp = DummyBook::new().build().unwrap();
    let mut md = MDBook::new(temp.path());

    md.build().unwrap();
}

#[test]
fn by_default_mdbook_generates_rendered_content_in_the_book_directory() {
    let temp = DummyBook::new().build().unwrap();
    let mut md = MDBook::new(temp.path());

    assert!(!temp.path().join("book").exists());
    md.build().unwrap();

    assert!(temp.path().join("book").exists());
    assert!(temp.path().join("book").join("index.html").exists());
}

#[test]
fn make_sure_bottom_level_files_contain_links_to_chapters() {
    let temp = DummyBook::new().build().unwrap();
    let mut md = MDBook::new(temp.path());
    md.build().unwrap();

    let dest = temp.path().join("book");
    let links = vec![r#"href="intro.html""#,
                     r#"href="./first/index.html""#,
                     r#"href="./first/nested.html""#,
                     r#"href="./second.html""#,
                     r#"href="./conclusion.html""#];

    let files_in_bottom_dir = vec!["index.html", "intro.html", "second.html", "conclusion.html"];

    for filename in files_in_bottom_dir {
        assert_contains_strings(dest.join(filename), &links);
    }
}

#[test]
fn check_correct_cross_links_in_nested_dir() {
    let temp = DummyBook::new().build().unwrap();
    let mut md = MDBook::new(temp.path());
    md.build().unwrap();

    let first = temp.path().join("book").join("first");
    let links = vec![r#"<base href="../">"#,
                     r#"href="intro.html""#,
                     r#"href="./first/index.html""#,
                     r#"href="./first/nested.html""#,
                     r#"href="./second.html""#,
                     r#"href="./conclusion.html""#];

    let files_in_nested_dir = vec!["index.html", "nested.html"];

    for filename in files_in_nested_dir {
        assert_contains_strings(first.join(filename), &links);
    }

    assert_contains_strings(first.join("index.html"),
                            &[r##"href="./first/index.html#some-section" id="some-section""##]);

    assert_contains_strings(first.join("nested.html"),
                            &[r##"href="./first/nested.html#some-section" id="some-section""##]);
}

#[test]
fn rendered_code_has_playpen_stuff() {
    let temp = DummyBook::new().build().unwrap();
    let mut md = MDBook::new(temp.path());
    md.build().unwrap();

    let nested = temp.path().join("book/first/nested.html");
    let playpen_class = vec![r#"class="playpen""#];

    assert_contains_strings(nested, &playpen_class);

    let book_js = temp.path().join("book/book.js");
    assert_contains_strings(book_js, &[".playpen"]);
}

#[test]
fn chapter_content_appears_in_rendered_document() {
    let content = vec![("index.html", "Here's some interesting text"),
                       ("second.html", "Second Chapter"),
                       ("first/nested.html", "testable code"),
                       ("first/index.html", "more text"),
                       ("conclusion.html", "Conclusion")];

    let temp = DummyBook::new().build().unwrap();
    let mut md = MDBook::new(temp.path());
    md.build().unwrap();

    let destination = temp.path().join("book");

    for (filename, text) in content {
        let path = destination.join(filename);
        assert_contains_strings(path, &[text]);
    }
}

/// Apply a series of predicates to some root predicate, where each
/// successive predicate is the descendant of the last one. Similar to how you
/// might do `ul.foo li a` in CSS to access all anchor tags in the `foo` list.
macro_rules! descendants {
    ($root:expr, $($child:expr),*) => {
        $root
        $(
            .descendant($child)
        )*
    };
}

/// Make sure that all `*.md` files (excluding `SUMMARY.md`) were rendered
/// and placed in the `book` directory with their extensions set to `*.html`.
#[test]
fn chapter_files_were_rendered_to_html() {
    let temp = DummyBook::new().build().unwrap();
    let src = Path::new(BOOK_ROOT).join("src");

    let chapter_files = WalkDir::new(&src).into_iter()
                                          .filter_entry(|entry| entry_ends_with(entry, ".md"))
                                          .filter_map(|entry| entry.ok())
                                          .map(|entry| entry.path().to_path_buf())
                                          .filter(|path| {
                                                      path.file_name().and_then(OsStr::to_str)
                                                          != Some("SUMMARY.md")
                                                  });

    for chapter in chapter_files {
        let rendered_location = temp.path().join(chapter.strip_prefix(&src).unwrap())
                                    .with_extension("html");
        assert!(rendered_location.exists(),
                "{} doesn't exits",
                rendered_location.display());
    }
}

fn entry_ends_with(entry: &DirEntry, ending: &str) -> bool {
    entry.file_name().to_string_lossy().ends_with(ending)
}

/// Read the main page (`book/index.html`) and expose it as a DOM which we
/// can search with the `select` crate
fn root_index_html() -> Result<Document> {
    let temp = DummyBook::new().build()
                               .chain_err(|| "Couldn't create the dummy book")?;
    MDBook::new(temp.path()).build()
                            .chain_err(|| "Book building failed")?;

    let index_page = temp.path().join("book").join("index.html");
    let html = file_to_string(&index_page).chain_err(|| "Unable to read index.html")?;

    Ok(Document::from(html.as_str()))
}

#[test]
fn check_second_toc_level() {
    let doc = root_index_html().unwrap();
    let mut should_be = Vec::from(TOC_SECOND_LEVEL);
    should_be.sort();

    let pred = descendants!(Class("chapter"), Name("li"), Name("li"), Name("a"));

    let mut children_of_children: Vec<_> =
        doc.find(pred).map(|elem| elem.text().trim().to_string())
           .collect();
    children_of_children.sort();

    assert_eq!(children_of_children, should_be);
}

#[test]
fn check_first_toc_level() {
    let doc = root_index_html().unwrap();
    let mut should_be = Vec::from(TOC_TOP_LEVEL);

    should_be.extend(TOC_SECOND_LEVEL);
    should_be.sort();

    let pred = descendants!(Class("chapter"), Name("li"), Name("a"));

    let mut children: Vec<_> = doc.find(pred).map(|elem| elem.text().trim().to_string())
                                       .collect();
    children.sort();

    assert_eq!(children, should_be);
}

#[test]
fn check_spacers() {
    let doc = root_index_html().unwrap();
    let should_be = 1;

    let num_spacers =
        doc.find(Class("chapter").descendant(Name("li").and(Class("spacer")))).count();
    assert_eq!(num_spacers, should_be);
}
<commit_msg>Add tests to check create-missing.<commit_after>extern crate mdbook;
#[macro_use]
extern crate pretty_assertions;
extern crate select;
extern crate tempdir;
extern crate walkdir;

mod dummy_book;

use dummy_book::{assert_contains_strings, DummyBook};

use std::fs::{File, remove_file};
use std::io::Write;
use std::path::Path;
use std::ffi::OsStr;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};
use select::document::Document;
use select::predicate::{Class, Name, Predicate};
use tempdir::TempDir;
use mdbook::errors::*;
use mdbook::utils::fs::file_to_string;
use mdbook::MDBook;

const BOOK_ROOT: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/dummy_book");
const TOC_TOP_LEVEL: &[&'static str] = &["1. First Chapter",
                                         "2. Second Chapter",
                                         "Conclusion",
                                         "Introduction"];
const TOC_SECOND_LEVEL: &[&'static str] = &["1.1. Nested Chapter"];

/// Make sure you can load the dummy book and build it without panicking.
#[test]
fn build_the_dummy_book() {
    let temp = DummyBook::new().build().unwrap();
    let mut md = MDBook::new(temp.path());

    md.build().unwrap();
}

#[test]
fn by_default_mdbook_generates_rendered_content_in_the_book_directory() {
    let temp = DummyBook::new().build().unwrap();
    let mut md = MDBook::new(temp.path());

    assert!(!temp.path().join("book").exists());
    md.build().unwrap();

    assert!(temp.path().join("book").exists());
    assert!(temp.path().join("book").join("index.html").exists());
}

#[test]
fn make_sure_bottom_level_files_contain_links_to_chapters() {
    let temp = DummyBook::new().build().unwrap();
    let mut md = MDBook::new(temp.path());
    md.build().unwrap();

    let dest = temp.path().join("book");
    let links = vec![r#"href="intro.html""#,
                     r#"href="./first/index.html""#,
                     r#"href="./first/nested.html""#,
                     r#"href="./second.html""#,
                     r#"href="./conclusion.html""#];

    let files_in_bottom_dir = vec!["index.html", "intro.html", "second.html", "conclusion.html"];

    for filename in files_in_bottom_dir {
        assert_contains_strings(dest.join(filename), &links);
    }
}

#[test]
fn check_correct_cross_links_in_nested_dir() {
    let temp = DummyBook::new().build().unwrap();
    let mut md = MDBook::new(temp.path());
    md.build().unwrap();

    let first = temp.path().join("book").join("first");
    let links = vec![r#"<base href="../">"#,
                     r#"href="intro.html""#,
                     r#"href="./first/index.html""#,
                     r#"href="./first/nested.html""#,
                     r#"href="./second.html""#,
                     r#"href="./conclusion.html""#];

    let files_in_nested_dir = vec!["index.html", "nested.html"];

    for filename in files_in_nested_dir {
        assert_contains_strings(first.join(filename), &links);
    }

    assert_contains_strings(first.join("index.html"),
                            &[r##"href="./first/index.html#some-section" id="some-section""##]);

    assert_contains_strings(first.join("nested.html"),
                            &[r##"href="./first/nested.html#some-section" id="some-section""##]);
}

#[test]
fn rendered_code_has_playpen_stuff() {
    let temp = DummyBook::new().build().unwrap();
    let mut md = MDBook::new(temp.path());
    md.build().unwrap();

    let nested = temp.path().join("book/first/nested.html");
    let playpen_class = vec![r#"class="playpen""#];

    assert_contains_strings(nested, &playpen_class);

    let book_js = temp.path().join("book/book.js");
    assert_contains_strings(book_js, &[".playpen"]);
}

#[test]
fn chapter_content_appears_in_rendered_document() {
    let content = vec![("index.html", "Here's some interesting text"),
                       ("second.html", "Second Chapter"),
                       ("first/nested.html", "testable code"),
                       ("first/index.html", "more text"),
                       ("conclusion.html", "Conclusion")];

    let temp = DummyBook::new().build().unwrap();
    let mut md = MDBook::new(temp.path());
    md.build().unwrap();

    let destination = temp.path().join("book");

    for (filename, text) in content {
        let path = destination.join(filename);
        assert_contains_strings(path, &[text]);
    }
}

/// Apply a series of predicates to some root predicate, where each
/// successive predicate is the descendant of the last one. Similar to how you
/// might do `ul.foo li a` in CSS to access all anchor tags in the `foo` list.
macro_rules! descendants {
    ($root:expr, $($child:expr),*) => {
        $root
        $(
            .descendant($child)
        )*
    };
}

/// Make sure that all `*.md` files (excluding `SUMMARY.md`) were rendered
/// and placed in the `book` directory with their extensions set to `*.html`.
#[test]
fn chapter_files_were_rendered_to_html() {
    let temp = DummyBook::new().build().unwrap();
    let src = Path::new(BOOK_ROOT).join("src");

    let chapter_files = WalkDir::new(&src).into_iter()
                                          .filter_entry(|entry| entry_ends_with(entry, ".md"))
                                          .filter_map(|entry| entry.ok())
                                          .map(|entry| entry.path().to_path_buf())
                                          .filter(|path| {
                                                      path.file_name().and_then(OsStr::to_str)
                                                          != Some("SUMMARY.md")
                                                  });

    for chapter in chapter_files {
        let rendered_location = temp.path().join(chapter.strip_prefix(&src).unwrap())
                                    .with_extension("html");
        assert!(rendered_location.exists(),
                "{} doesn't exits",
                rendered_location.display());
    }
}

fn entry_ends_with(entry: &DirEntry, ending: &str) -> bool {
    entry.file_name().to_string_lossy().ends_with(ending)
}

/// Read the main page (`book/index.html`) and expose it as a DOM which we
/// can search with the `select` crate
fn root_index_html() -> Result<Document> {
    let temp = DummyBook::new().build()
                               .chain_err(|| "Couldn't create the dummy book")?;
    MDBook::new(temp.path()).build()
                            .chain_err(|| "Book building failed")?;

    let index_page = temp.path().join("book").join("index.html");
    let html = file_to_string(&index_page).chain_err(|| "Unable to read index.html")?;

    Ok(Document::from(html.as_str()))
}

#[test]
fn check_second_toc_level() {
    let doc = root_index_html().unwrap();
    let mut should_be = Vec::from(TOC_SECOND_LEVEL);
    should_be.sort();

    let pred = descendants!(Class("chapter"), Name("li"), Name("li"), Name("a"));

    let mut children_of_children: Vec<_> =
        doc.find(pred).map(|elem| elem.text().trim().to_string())
           .collect();
    children_of_children.sort();

    assert_eq!(children_of_children, should_be);
}

#[test]
fn check_first_toc_level() {
    let doc = root_index_html().unwrap();
    let mut should_be = Vec::from(TOC_TOP_LEVEL);

    should_be.extend(TOC_SECOND_LEVEL);
    should_be.sort();

    let pred = descendants!(Class("chapter"), Name("li"), Name("a"));

    let mut children: Vec<_> = doc.find(pred).map(|elem| elem.text().trim().to_string())
                                       .collect();
    children.sort();

    assert_eq!(children, should_be);
}

#[test]
fn check_spacers() {
    let doc = root_index_html().unwrap();
    let should_be = 1;

    let num_spacers =
        doc.find(Class("chapter").descendant(Name("li").and(Class("spacer")))).count();
    assert_eq!(num_spacers, should_be);
}

/// Ensure building fails if `create-missing` is false and one of the files does
/// not exist.
#[test]
fn failure_on_missing_file() {
    let (md, _temp) = create_missing_setup(Some(false));

    // On failure, `build()` does not return a specific error, so assume
    // any error is a failure due to a missing file.
    assert!(md.read_config().unwrap().build().is_err());
}

/// Ensure a missing file is created if `create-missing` is true.
#[test]
fn create_missing_file_with_config() {
    let (md, temp) = create_missing_setup(Some(true));

    md.read_config().unwrap().build().unwrap();
    assert!(temp.path().join("src").join("intro.md").exists());
}

/// Ensure a missing file is created if `create-missing` is not set (the default
/// is true).
#[test]
fn create_missing_file_without_config() {
    let (md, temp) = create_missing_setup(None);

    md.read_config().unwrap().build().unwrap();
    assert!(temp.path().join("src").join("intro.md").exists());
}

fn create_missing_setup(create_missing: Option<bool>) -> (MDBook, TempDir) {
    let temp = DummyBook::new().build().unwrap();
    let md = MDBook::new(temp.path());

    let mut file = File::create(temp.path().join("book.toml")).unwrap();
    match create_missing {
        Some(true) => file.write_all(b"[build]\ncreate-missing = true\n").unwrap(),
        Some(false) => file.write_all(b"[build]\ncreate-missing = false\n").unwrap(),
        None => (),
    }
    file.flush().unwrap();

    remove_file(temp.path().join("src").join("intro.md")).unwrap();

    (md, temp)
}
<|endoftext|>


<commit_before>//! This module implements the relocation model for the x86 architecture, as well as aliases for x68 Assemblers.

use crate::Register;
use crate::relocations::{Relocation, RelocationSize, RelocationKind, ImpossibleRelocation};

/// Relocation implementation for the x86 architecture.
#[derive(Debug, Clone)]
pub struct X86Relocation {
    size: RelocationSize,
    kind: RelocationKind,
    offset: u8,
    start_offset: u8,
}

impl Relocation for X86Relocation {
    type Encoding = (u8, u8, u8);
    fn from_encoding(encoding: Self::Encoding) -> Self {
        Self {
            offset: encoding.0,
            size: RelocationSize::from_encoding(encoding.1),
            kind: RelocationKind::from_encoding(encoding.2),
            start_offset: 0,
        }
    }
    fn from_size(size: RelocationSize) -> Self {
        Self {
            size,
            kind: RelocationKind::Relative,
            offset: 0,
            start_offset: size as u8,
        }
    }
    fn start_offset(&self) -> usize {
        self.start_offset as usize
    }
    fn field_offset(&self) -> usize{
        self.size.size() + self.offset as usize
    }
    fn size(&self) -> usize {
        self.size.size()
    }
    fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation> {
        self.size.write_value(buf, value)
    }
    fn read_value(&self, buf: &[u8]) -> isize {
        self.size.read_value(buf)
    }
    fn kind(&self) -> RelocationKind {
        self.kind
    }
    fn page_size() -> usize {
        4096
    }
}

/// An x86 Assembler. This is aliased here for backwards compatability.
pub type Assembler = crate::Assembler<X86Relocation>;
/// An x86 AssemblyModifier. This is aliased here for backwards compatability.
pub type AssemblyModifier<'a> = crate::Modifier<'a, X86Relocation>;
/// An x86 UncommittedModifier. This is aliased here for backwards compatability.
pub type UncommittedModifier<'a> = crate::UncommittedModifier<'a>;

/// 4-byte general purpose "double-word" registers.
///
/// EIP does not appear here as it is addressed differently in dynasm.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rd {
    EAX = 0x00, ECX = 0x01, EDX = 0x02, EBX = 0x03,
    ESP = 0x04, EBP = 0x05, ESI = 0x06, EDI = 0x07,
}
reg_impls!(Rd);

/// High-byte general purpose registers.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rh {
    AH = 0x4, CH = 0x5, DH = 0x6, BH = 0x7,
}
reg_impls!(Rh);

/// 10-byte floating point registers.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rf {
    ST0 = 0x0, ST1 = 0x1, ST2 = 0x2, ST3 = 0x3,
    ST4 = 0x4, ST5 = 0x5, ST6 = 0x6, ST7 = 0x7,
}
reg_impls!(Rf);

/// 8-byte MMX registers. Alternative encoding exists.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rm {
    MMX0 = 0x0, MMX1 = 0x1, MMX2 = 0x2, MMX3 = 0x3,
    MMX4 = 0x4, MMX5 = 0x5, MMX6 = 0x6, MMX7 = 0x7,
}
reg_impls!(Rm);

/// 16-byte SSE registers.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rx {
    XMM0  = 0x0, XMM1  = 0x1, XMM2  = 0x2, XMM3  = 0x3,
    XMM4  = 0x4, XMM5  = 0x5, XMM6  = 0x6, XMM7  = 0x7,
}
reg_impls!(Rx);

/// 2-byte segment registers.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rs {
    ES = 0x0, CS = 0x1, SS = 0x2, DS = 0x3,
    FS = 0x4, GS = 0x5,
}
reg_impls!(Rs);

/// 4-byte control registers.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RC {
    CR0  = 0x0, CR1  = 0x1, CR2  = 0x2, CR3  = 0x3,
    CR4  = 0x4, CR5  = 0x5, CR6  = 0x6, CR7  = 0x7,
}
reg_impls!(RC);

/// 4-byte debug registers.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RD {
    DR0  = 0x0, DR1  = 0x1, DR2  = 0x2, DR3  = 0x3,
    DR4  = 0x4, DR5  = 0x5, DR6  = 0x6, DR7  = 0x7,
    DR8  = 0x8, DR9  = 0x9, DR10 = 0xA, DR11 = 0xB,
    DR12 = 0xC, DR13 = 0xD, DR14 = 0xE, DR15 = 0xF,
}
reg_impls!(RD);

/// 16-byte bound registers.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RB {
    BND0 = 0x0, BND1 = 0x1, BND2 = 0x2, BND3 = 0x3
}
reg_impls!(RB);

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

    #[test]
    fn reg_code() {
        assert_eq!(EAX.code(), 0);
    }

    #[test]
    fn reg_code_from() {
        assert_eq!(u8::from(ECX), 1);
    }
}
<commit_msg>Fix typo in module doc.<commit_after>//! This module implements the relocation model for the x86 architecture, as well as aliases for x86 Assemblers.

use crate::Register;
use crate::relocations::{Relocation, RelocationSize, RelocationKind, ImpossibleRelocation};

/// Relocation implementation for the x86 architecture.
#[derive(Debug, Clone)]
pub struct X86Relocation {
    size: RelocationSize,
    kind: RelocationKind,
    offset: u8,
    start_offset: u8,
}

impl Relocation for X86Relocation {
    type Encoding = (u8, u8, u8);
    fn from_encoding(encoding: Self::Encoding) -> Self {
        Self {
            offset: encoding.0,
            size: RelocationSize::from_encoding(encoding.1),
            kind: RelocationKind::from_encoding(encoding.2),
            start_offset: 0,
        }
    }
    fn from_size(size: RelocationSize) -> Self {
        Self {
            size,
            kind: RelocationKind::Relative,
            offset: 0,
            start_offset: size as u8,
        }
    }
    fn start_offset(&self) -> usize {
        self.start_offset as usize
    }
    fn field_offset(&self) -> usize{
        self.size.size() + self.offset as usize
    }
    fn size(&self) -> usize {
        self.size.size()
    }
    fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation> {
        self.size.write_value(buf, value)
    }
    fn read_value(&self, buf: &[u8]) -> isize {
        self.size.read_value(buf)
    }
    fn kind(&self) -> RelocationKind {
        self.kind
    }
    fn page_size() -> usize {
        4096
    }
}

/// An x86 Assembler. This is aliased here for backwards compatability.
pub type Assembler = crate::Assembler<X86Relocation>;
/// An x86 AssemblyModifier. This is aliased here for backwards compatability.
pub type AssemblyModifier<'a> = crate::Modifier<'a, X86Relocation>;
/// An x86 UncommittedModifier. This is aliased here for backwards compatability.
pub type UncommittedModifier<'a> = crate::UncommittedModifier<'a>;

/// 4-byte general purpose "double-word" registers.
///
/// EIP does not appear here as it is addressed differently in dynasm.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rd {
    EAX = 0x00, ECX = 0x01, EDX = 0x02, EBX = 0x03,
    ESP = 0x04, EBP = 0x05, ESI = 0x06, EDI = 0x07,
}
reg_impls!(Rd);

/// High-byte general purpose registers.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rh {
    AH = 0x4, CH = 0x5, DH = 0x6, BH = 0x7,
}
reg_impls!(Rh);

/// 10-byte floating point registers.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rf {
    ST0 = 0x0, ST1 = 0x1, ST2 = 0x2, ST3 = 0x3,
    ST4 = 0x4, ST5 = 0x5, ST6 = 0x6, ST7 = 0x7,
}
reg_impls!(Rf);

/// 8-byte MMX registers. Alternative encoding exists.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rm {
    MMX0 = 0x0, MMX1 = 0x1, MMX2 = 0x2, MMX3 = 0x3,
    MMX4 = 0x4, MMX5 = 0x5, MMX6 = 0x6, MMX7 = 0x7,
}
reg_impls!(Rm);

/// 16-byte SSE registers.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rx {
    XMM0  = 0x0, XMM1  = 0x1, XMM2  = 0x2, XMM3  = 0x3,
    XMM4  = 0x4, XMM5  = 0x5, XMM6  = 0x6, XMM7  = 0x7,
}
reg_impls!(Rx);

/// 2-byte segment registers.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rs {
    ES = 0x0, CS = 0x1, SS = 0x2, DS = 0x3,
    FS = 0x4, GS = 0x5,
}
reg_impls!(Rs);

/// 4-byte control registers.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RC {
    CR0  = 0x0, CR1  = 0x1, CR2  = 0x2, CR3  = 0x3,
    CR4  = 0x4, CR5  = 0x5, CR6  = 0x6, CR7  = 0x7,
}
reg_impls!(RC);

/// 4-byte debug registers.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RD {
    DR0  = 0x0, DR1  = 0x1, DR2  = 0x2, DR3  = 0x3,
    DR4  = 0x4, DR5  = 0x5, DR6  = 0x6, DR7  = 0x7,
    DR8  = 0x8, DR9  = 0x9, DR10 = 0xA, DR11 = 0xB,
    DR12 = 0xC, DR13 = 0xD, DR14 = 0xE, DR15 = 0xF,
}
reg_impls!(RD);

/// 16-byte bound registers.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RB {
    BND0 = 0x0, BND1 = 0x1, BND2 = 0x2, BND3 = 0x3
}
reg_impls!(RB);

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

    #[test]
    fn reg_code() {
        assert_eq!(EAX.code(), 0);
    }

    #[test]
    fn reg_code_from() {
        assert_eq!(u8::from(ECX), 1);
    }
}
<|endoftext|>


<commit_before>#![warn(unused_results)]

extern crate data_encoding;
extern crate getopts;

use data_encoding::{DecodeKind, Encoding};
use getopts::Options;
use std::fs::File;
use std::io::{Read, Write};

macro_rules! check {
    ($e: expr, $c: expr) => {
        if !$c {
            return Err($e);
        }
    };
}

#[derive(Debug)]
pub enum Error {
    ParseOpts(::getopts::Fail),
    ExtraArgs(Vec<String>),
    Cmdline(String),
    Decode(::data_encoding::DecodeError),
    Builder(::data_encoding::SpecificationError),
    IO(String, ::std::io::Error),
    Read(::std::io::Error),
    Write(::std::io::Error),
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        use self::Error::*;
        match self {
            ParseOpts(ref e) => e.fmt(f),
            ExtraArgs(ref a) => write!(f, "Unexpected arguments {:?}", a),
            Cmdline(ref m) => write!(f, "{}", m),
            Decode(ref e) => e.fmt(f),
            Builder(ref e) => e.fmt(f),
            IO(ref p, ref e) => write!(f, "{}: {}", p, e),
            Read(ref e) => write!(f, "Read error: {}", e),
            Write(ref e) => write!(f, "Write error: {}", e),
        }
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match self {
            ParseOpts(ref e) => e.description(),
            ExtraArgs(_) => "unexpected argument",
            Cmdline(_) => "invalid command-line",
            Decode(ref e) => e.description(),
            Builder(ref e) => e.description(),
            IO(_, ref e) => e.description(),
            Read(ref e) => e.description(),
            Write(ref e) => e.description(),
        }
    }
}

type Result<T> = std::result::Result<T, Error>;

fn floor(x: usize, d: usize) -> usize {
    x / d * d
}
fn ceil(x: usize, d: usize) -> usize {
    floor(x + d - 1, d)
}

#[test]
fn floor_ceil() {
    assert_eq!(floor(10, 5), 10);
    assert_eq!(floor(13, 5), 10);
    assert_eq!(floor(15, 5), 15);
    assert_eq!(ceil(10, 5), 10);
    assert_eq!(ceil(13, 5), 15);
    assert_eq!(ceil(15, 5), 15);
}

fn encode_block(base: &Encoding) -> usize {
    match base.bit_width() {
        1 | 2 | 4 => 1,
        3 | 6 => 3,
        5 => 5,
        _ => unreachable!(),
    }
}
fn decode_block(base: &Encoding) -> usize {
    encode_block(base) * 8 / base.bit_width()
}

pub fn encode<R: Read, W: Write>(
    base: &Encoding, wrap: usize, mut reader: R, mut writer: W, size: usize,
) -> Result<()> {
    let block = if wrap == 0 {
        encode_block(&base)
    } else {
        assert_eq!(wrap * base.bit_width() % 8, 0);
        wrap * base.bit_width() / 8
    };
    assert_eq!(block % encode_block(&base), 0);
    assert!(size >= block);
    let mut input = vec![0u8; size];
    let mut output = vec![0u8; base.encode_len(size)];
    let mut rest = 0;
    loop {
        let ilen = reader.read(&mut input[rest ..]).map_err(Error::Read)?;
        let next = if ilen == 0 { rest } else { floor(rest + ilen, block) };
        let olen = base.encode_len(next);
        base.encode_mut(&input[0 .. next], &mut output[0 .. olen]);
        writer.write_all(&output[0 .. olen]).map_err(Error::Write)?;
        if ilen == 0 {
            return Ok(());
        }
        rest = rest + ilen - next;
        for i in 0 .. rest {
            input[i] = input[next + i];
        }
    }
}

pub fn decode<R, W>(base: &Encoding, mut reader: R, mut writer: W, size: usize) -> Result<()>
where
    R: Read,
    W: Write,
{
    let block = decode_block(base);
    assert!(size >= block);
    let mut input = vec![0u8; size];
    let mut output = vec![0u8; base.decode_len(ceil(size, block)).unwrap()];
    let mut pos = 0;
    let mut rest = 0;
    loop {
        let ilen = reader.read(&mut input[rest ..]).map_err(Error::Read)?;
        let next = if ilen == 0 { rest } else { floor(rest + ilen, block) };
        let mlen = base.decode_len(next).map_err(|mut error| {
            error.position += pos;
            Error::Decode(error)
        })?;
        let (next, olen) = match base.decode_mut(&input[0 .. next], &mut output[0 .. mlen]) {
            Ok(olen) => (next, olen),
            Err(mut partial) => {
                if partial.error.kind != DecodeKind::Length {
                    partial.error.position += pos;
                    return Err(Error::Decode(partial.error));
                }
                assert_ne!(ilen, 0);
                (partial.read, partial.written)
            }
        };
        writer.write_all(&output[0 .. olen]).map_err(Error::Write)?;
        rest = rest + ilen - next;
        if ilen == 0 {
            return Ok(());
        }
        for i in 0 .. rest {
            input[i] = input[next + i];
        }
        pos += next;
    }
}

fn main() {
    let (program, args): (_, Vec<_>) = {
        let mut i = std::env::args();
        match i.next() {
            None => ("data-encoding".into(), vec![]),
            Some(p) => (p, i.collect()),
        }
    };
    let program = program.rsplit('/').next().unwrap_or(&program);

    if let Err(e) = wrapped_main(program, args) {
        let _ = writeln!(&mut std::io::stderr(), "{}: {}", program, e);
        std::process::exit(1)
    }
}

fn wrapped_main(program: &str, args: Vec<String>) -> Result<()> {
    let mut opts = Options::new();
    let _ = opts
        .reqopt("m", "mode", "{encode|decode|describe}", "<mode>")
        .optopt("b", "base", "{16|hex|32|32hex|64|64url}", "<base>")
        .optopt("i", "input", "read from <file> instead of standard input", "<file>")
        .optopt("o", "output", "write to <file> instead of standard output", "<file>")
        .optopt("", "block", "read blocks of about <size> bytes", "<size>")
        .optopt("p", "padding", "pad with <padding>", "<padding>")
        .optopt("g", "ignore", "when decoding, ignore characters in <ignore>", "<ignore>")
        .optopt("w", "width", "when encoding, wrap every <cols> characters", "<cols>")
        .optopt("s", "separator", "when encoding, wrap with <separator>", "<separator>")
        .optopt("", "symbols", "define a custom base using <symbols>", "<symbols>")
        .optopt("", "translate", "when decoding, translate <new> as <old>", "<new><old>")
        .optflag("", "ignore_trailing_bits", "when decoding, ignore non-zero trailing bits")
        .optflag("", "least_significant_bit_first", "use least significant bit first bit-order");

    if args.len() == 1 && (args[0] == "--help" || args[0] == "-h") {
        let brief = format!(
            r"Usage: {program} --mode=<mode> --base=<base> [<options>]
Usage: {program} --mode=<mode> --symbols=<symbols> [<options>]",
            program = program
        );
        print!(
            "{0}
Examples:
    # Encode using the RFC4648 base64 encoding
    {1} -mencode -b64     # without padding
    {1} -mencode -b64 -p= # with padding

    # Encode using the MIME base64 encoding
    {1} -mencode -b64 -p= -w76 -s$'\\r\\n'

    # Show base information for the permissive hexadecimal encoding
    {1} --mode=describe --base=hex

    # Decode using the DNSCurve base32 encoding
    {1} -mdecode \\
        --symbols=0123456789bcdfghjklmnpqrstuvwxyz \\
        --translate=BCDFGHJKLMNPQRSTUVWXYZbcdfghjklmnpqrstuvwxyz \\
        --least_significant_bit_first
",
            opts.usage(&brief),
            program
        );
        return Ok(());
    }

    let matches = opts.parse(&args).map_err(Error::ParseOpts)?;
    check!(Error::ExtraArgs(matches.free), matches.free.is_empty());

    let mut spec = match matches.opt_str("base") {
        None => {
            let mut spec = ::data_encoding::Specification::new();
            spec.symbols = matches
                .opt_str("symbols")
                .ok_or_else(|| Error::Cmdline("Base or symbols must be provided".into()))?;
            spec
        }
        Some(base) => {
            check!(
                Error::Cmdline("Base and symbols are incompatible".into()),
                !matches.opt_present("symbols")
            );
            match base.as_str() {
                "16" => ::data_encoding::HEXUPPER.specification(),
                "hex" => ::data_encoding::HEXLOWER_PERMISSIVE.specification(),
                "32" => ::data_encoding::BASE32.specification(),
                "32hex" => ::data_encoding::BASE32HEX.specification(),
                "64" => ::data_encoding::BASE64.specification(),
                "64url" => ::data_encoding::BASE64URL.specification(),
                _ => return Err(Error::Cmdline("Invalid base".into())),
            }
        }
    };
    if let Some(padding) = matches.opt_str("padding") {
        let mut chars = padding.chars();
        spec.padding = chars.next();
        check!(Error::Cmdline("Empty padding".into()), spec.padding.is_some());
        check!(Error::Cmdline("Padding must be a character".into()), chars.next().is_none());
    } else {
        spec.padding = None;
    }
    if let Some(mut newold) = matches.opt_str("translate") {
        let invalid_translate = Error::Cmdline("Invalid translate".into());
        check!(invalid_translate, newold.len() % 2 == 0);
        let len = newold.len() / 2;
        check!(invalid_translate, newold.is_char_boundary(len));
        spec.translate.to = newold.split_off(len);
        spec.translate.from = newold;
    }
    if matches.opt_present("ignore_trailing_bits") {
        spec.check_trailing_bits = false;
    }
    if matches.opt_present("least_significant_bit_first") {
        spec.bit_order = ::data_encoding::BitOrder::LeastSignificantFirst;
    }
    if let Some(ignore) = matches.opt_str("ignore") {
        spec.ignore.push_str(ignore.as_str());
    }
    if let Some(width) = matches.opt_str("width") {
        spec.wrap.width =
            width.parse().map_err(|_| Error::Cmdline("Invalid width value".into()))?;
    }
    if let Some(separator) = matches.opt_str("separator") {
        spec.wrap.separator.push_str(separator.as_str());
    }
    let base = spec.encoding().map_err(Error::Builder)?;

    let mode = match matches.opt_str("mode").unwrap().as_str() {
        "encode" => true,
        "decode" => false,
        "describe" => {
            println!("{:#?}", base.specification());
            return Ok(());
        }
        _ => return Err(Error::Cmdline("Invalid mode".into())),
    };

    let input: Box<Read>;
    if let Some(file) = matches.opt_str("input") {
        input = Box::new(File::open(&file).map_err(|e| Error::IO(file, e))?);
    } else {
        input = Box::new(std::io::stdin());
    };

    let mut output: Box<Write>;
    if let Some(file) = matches.opt_str("output") {
        output = Box::new(File::create(&file).map_err(|e| Error::IO(file, e))?);
    } else {
        output = stdout();
    }
    output = Box::new(std::io::BufWriter::new(output));

    let size = matches
        .opt_str("block")
        .unwrap_or_else(|| "15360".to_owned())
        .parse()
        .map_err(|_| Error::Cmdline("Invalid block value".into()))?;
    check!(Error::Cmdline("Block value must be greater or equal than 8".into()), size >= 8);

    if mode {
        encode(&base, spec.wrap.width, input, output, size)
    } else {
        decode(&base, input, output, size)
    }
}

// TODO: Change (and inline) the following lines when Stdout does not
// go through a LineWriter anymore.
#[cfg(target_os = "linux")]
fn stdout() -> Box<Write> {
    Box::new(unsafe { <File as std::os::unix::io::FromRawFd>::from_raw_fd(1) })
}
#[cfg(not(target_os = "linux"))]
fn stdout() -> Box<Write> {
    Box::new(std::io::stdout())
}
<commit_msg>bin: Use dyn syntax for trait objects<commit_after>#![warn(unused_results)]

extern crate data_encoding;
extern crate getopts;

use data_encoding::{DecodeKind, Encoding};
use getopts::Options;
use std::fs::File;
use std::io::{Read, Write};

macro_rules! check {
    ($e: expr, $c: expr) => {
        if !$c {
            return Err($e);
        }
    };
}

#[derive(Debug)]
pub enum Error {
    ParseOpts(::getopts::Fail),
    ExtraArgs(Vec<String>),
    Cmdline(String),
    Decode(::data_encoding::DecodeError),
    Builder(::data_encoding::SpecificationError),
    IO(String, ::std::io::Error),
    Read(::std::io::Error),
    Write(::std::io::Error),
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        use self::Error::*;
        match self {
            ParseOpts(ref e) => e.fmt(f),
            ExtraArgs(ref a) => write!(f, "Unexpected arguments {:?}", a),
            Cmdline(ref m) => write!(f, "{}", m),
            Decode(ref e) => e.fmt(f),
            Builder(ref e) => e.fmt(f),
            IO(ref p, ref e) => write!(f, "{}: {}", p, e),
            Read(ref e) => write!(f, "Read error: {}", e),
            Write(ref e) => write!(f, "Write error: {}", e),
        }
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match self {
            ParseOpts(ref e) => e.description(),
            ExtraArgs(_) => "unexpected argument",
            Cmdline(_) => "invalid command-line",
            Decode(ref e) => e.description(),
            Builder(ref e) => e.description(),
            IO(_, ref e) => e.description(),
            Read(ref e) => e.description(),
            Write(ref e) => e.description(),
        }
    }
}

type Result<T> = std::result::Result<T, Error>;

fn floor(x: usize, d: usize) -> usize {
    x / d * d
}
fn ceil(x: usize, d: usize) -> usize {
    floor(x + d - 1, d)
}

#[test]
fn floor_ceil() {
    assert_eq!(floor(10, 5), 10);
    assert_eq!(floor(13, 5), 10);
    assert_eq!(floor(15, 5), 15);
    assert_eq!(ceil(10, 5), 10);
    assert_eq!(ceil(13, 5), 15);
    assert_eq!(ceil(15, 5), 15);
}

fn encode_block(base: &Encoding) -> usize {
    match base.bit_width() {
        1 | 2 | 4 => 1,
        3 | 6 => 3,
        5 => 5,
        _ => unreachable!(),
    }
}
fn decode_block(base: &Encoding) -> usize {
    encode_block(base) * 8 / base.bit_width()
}

pub fn encode<R: Read, W: Write>(
    base: &Encoding, wrap: usize, mut reader: R, mut writer: W, size: usize,
) -> Result<()> {
    let block = if wrap == 0 {
        encode_block(&base)
    } else {
        assert_eq!(wrap * base.bit_width() % 8, 0);
        wrap * base.bit_width() / 8
    };
    assert_eq!(block % encode_block(&base), 0);
    assert!(size >= block);
    let mut input = vec![0u8; size];
    let mut output = vec![0u8; base.encode_len(size)];
    let mut rest = 0;
    loop {
        let ilen = reader.read(&mut input[rest ..]).map_err(Error::Read)?;
        let next = if ilen == 0 { rest } else { floor(rest + ilen, block) };
        let olen = base.encode_len(next);
        base.encode_mut(&input[0 .. next], &mut output[0 .. olen]);
        writer.write_all(&output[0 .. olen]).map_err(Error::Write)?;
        if ilen == 0 {
            return Ok(());
        }
        rest = rest + ilen - next;
        for i in 0 .. rest {
            input[i] = input[next + i];
        }
    }
}

pub fn decode<R, W>(base: &Encoding, mut reader: R, mut writer: W, size: usize) -> Result<()>
where
    R: Read,
    W: Write,
{
    let block = decode_block(base);
    assert!(size >= block);
    let mut input = vec![0u8; size];
    let mut output = vec![0u8; base.decode_len(ceil(size, block)).unwrap()];
    let mut pos = 0;
    let mut rest = 0;
    loop {
        let ilen = reader.read(&mut input[rest ..]).map_err(Error::Read)?;
        let next = if ilen == 0 { rest } else { floor(rest + ilen, block) };
        let mlen = base.decode_len(next).map_err(|mut error| {
            error.position += pos;
            Error::Decode(error)
        })?;
        let (next, olen) = match base.decode_mut(&input[0 .. next], &mut output[0 .. mlen]) {
            Ok(olen) => (next, olen),
            Err(mut partial) => {
                if partial.error.kind != DecodeKind::Length {
                    partial.error.position += pos;
                    return Err(Error::Decode(partial.error));
                }
                assert_ne!(ilen, 0);
                (partial.read, partial.written)
            }
        };
        writer.write_all(&output[0 .. olen]).map_err(Error::Write)?;
        rest = rest + ilen - next;
        if ilen == 0 {
            return Ok(());
        }
        for i in 0 .. rest {
            input[i] = input[next + i];
        }
        pos += next;
    }
}

fn main() {
    let (program, args): (_, Vec<_>) = {
        let mut i = std::env::args();
        match i.next() {
            None => ("data-encoding".into(), vec![]),
            Some(p) => (p, i.collect()),
        }
    };
    let program = program.rsplit('/').next().unwrap_or(&program);

    if let Err(e) = wrapped_main(program, args) {
        let _ = writeln!(&mut std::io::stderr(), "{}: {}", program, e);
        std::process::exit(1)
    }
}

fn wrapped_main(program: &str, args: Vec<String>) -> Result<()> {
    let mut opts = Options::new();
    let _ = opts
        .reqopt("m", "mode", "{encode|decode|describe}", "<mode>")
        .optopt("b", "base", "{16|hex|32|32hex|64|64url}", "<base>")
        .optopt("i", "input", "read from <file> instead of standard input", "<file>")
        .optopt("o", "output", "write to <file> instead of standard output", "<file>")
        .optopt("", "block", "read blocks of about <size> bytes", "<size>")
        .optopt("p", "padding", "pad with <padding>", "<padding>")
        .optopt("g", "ignore", "when decoding, ignore characters in <ignore>", "<ignore>")
        .optopt("w", "width", "when encoding, wrap every <cols> characters", "<cols>")
        .optopt("s", "separator", "when encoding, wrap with <separator>", "<separator>")
        .optopt("", "symbols", "define a custom base using <symbols>", "<symbols>")
        .optopt("", "translate", "when decoding, translate <new> as <old>", "<new><old>")
        .optflag("", "ignore_trailing_bits", "when decoding, ignore non-zero trailing bits")
        .optflag("", "least_significant_bit_first", "use least significant bit first bit-order");

    if args.len() == 1 && (args[0] == "--help" || args[0] == "-h") {
        let brief = format!(
            r"Usage: {program} --mode=<mode> --base=<base> [<options>]
Usage: {program} --mode=<mode> --symbols=<symbols> [<options>]",
            program = program
        );
        print!(
            "{0}
Examples:
    # Encode using the RFC4648 base64 encoding
    {1} -mencode -b64     # without padding
    {1} -mencode -b64 -p= # with padding

    # Encode using the MIME base64 encoding
    {1} -mencode -b64 -p= -w76 -s$'\\r\\n'

    # Show base information for the permissive hexadecimal encoding
    {1} --mode=describe --base=hex

    # Decode using the DNSCurve base32 encoding
    {1} -mdecode \\
        --symbols=0123456789bcdfghjklmnpqrstuvwxyz \\
        --translate=BCDFGHJKLMNPQRSTUVWXYZbcdfghjklmnpqrstuvwxyz \\
        --least_significant_bit_first
",
            opts.usage(&brief),
            program
        );
        return Ok(());
    }

    let matches = opts.parse(&args).map_err(Error::ParseOpts)?;
    check!(Error::ExtraArgs(matches.free), matches.free.is_empty());

    let mut spec = match matches.opt_str("base") {
        None => {
            let mut spec = ::data_encoding::Specification::new();
            spec.symbols = matches
                .opt_str("symbols")
                .ok_or_else(|| Error::Cmdline("Base or symbols must be provided".into()))?;
            spec
        }
        Some(base) => {
            check!(
                Error::Cmdline("Base and symbols are incompatible".into()),
                !matches.opt_present("symbols")
            );
            match base.as_str() {
                "16" => ::data_encoding::HEXUPPER.specification(),
                "hex" => ::data_encoding::HEXLOWER_PERMISSIVE.specification(),
                "32" => ::data_encoding::BASE32.specification(),
                "32hex" => ::data_encoding::BASE32HEX.specification(),
                "64" => ::data_encoding::BASE64.specification(),
                "64url" => ::data_encoding::BASE64URL.specification(),
                _ => return Err(Error::Cmdline("Invalid base".into())),
            }
        }
    };
    if let Some(padding) = matches.opt_str("padding") {
        let mut chars = padding.chars();
        spec.padding = chars.next();
        check!(Error::Cmdline("Empty padding".into()), spec.padding.is_some());
        check!(Error::Cmdline("Padding must be a character".into()), chars.next().is_none());
    } else {
        spec.padding = None;
    }
    if let Some(mut newold) = matches.opt_str("translate") {
        let invalid_translate = Error::Cmdline("Invalid translate".into());
        check!(invalid_translate, newold.len() % 2 == 0);
        let len = newold.len() / 2;
        check!(invalid_translate, newold.is_char_boundary(len));
        spec.translate.to = newold.split_off(len);
        spec.translate.from = newold;
    }
    if matches.opt_present("ignore_trailing_bits") {
        spec.check_trailing_bits = false;
    }
    if matches.opt_present("least_significant_bit_first") {
        spec.bit_order = ::data_encoding::BitOrder::LeastSignificantFirst;
    }
    if let Some(ignore) = matches.opt_str("ignore") {
        spec.ignore.push_str(ignore.as_str());
    }
    if let Some(width) = matches.opt_str("width") {
        spec.wrap.width =
            width.parse().map_err(|_| Error::Cmdline("Invalid width value".into()))?;
    }
    if let Some(separator) = matches.opt_str("separator") {
        spec.wrap.separator.push_str(separator.as_str());
    }
    let base = spec.encoding().map_err(Error::Builder)?;

    let mode = match matches.opt_str("mode").unwrap().as_str() {
        "encode" => true,
        "decode" => false,
        "describe" => {
            println!("{:#?}", base.specification());
            return Ok(());
        }
        _ => return Err(Error::Cmdline("Invalid mode".into())),
    };

    let input: Box<dyn Read>;
    if let Some(file) = matches.opt_str("input") {
        input = Box::new(File::open(&file).map_err(|e| Error::IO(file, e))?);
    } else {
        input = Box::new(std::io::stdin());
    };

    let mut output: Box<dyn Write>;
    if let Some(file) = matches.opt_str("output") {
        output = Box::new(File::create(&file).map_err(|e| Error::IO(file, e))?);
    } else {
        output = stdout();
    }
    output = Box::new(std::io::BufWriter::new(output));

    let size = matches
        .opt_str("block")
        .unwrap_or_else(|| "15360".to_owned())
        .parse()
        .map_err(|_| Error::Cmdline("Invalid block value".into()))?;
    check!(Error::Cmdline("Block value must be greater or equal than 8".into()), size >= 8);

    if mode {
        encode(&base, spec.wrap.width, input, output, size)
    } else {
        decode(&base, input, output, size)
    }
}

// TODO: Change (and inline) the following lines when Stdout does not
// go through a LineWriter anymore.
#[cfg(target_os = "linux")]
fn stdout() -> Box<dyn Write> {
    Box::new(unsafe { <File as std::os::unix::io::FromRawFd>::from_raw_fd(1) })
}
#[cfg(not(target_os = "linux"))]
fn stdout() -> Box<dyn Write> {
    Box::new(std::io::stdout())
}
<|endoftext|>