<commit_before>use std::io;
use std::str;

use crate::reflect::error::ReflectError;
use crate::wire_format::WireType;

/// `Result` alias for `ProtobufError`
pub type Result<T> = std::result::Result<T, crate::Error>;

/// Enum values added here for diagnostic purposes.
/// Users should not depend on specific values.
#[derive(Debug, thiserror::Error)]
pub(crate) enum WireError {
    #[error("Unexpected EOF")]
    UnexpectedEof,
    #[error("Unexpected wire type")]
    UnexpectedWireType(WireType),
    #[error("Incorrect tag")]
    IncorrectTag(u32),
    #[error("Incorrect varint")]
    IncorrectVarint,
    #[error("Invalid UTF-8 sequence")]
    Utf8Error,
    #[error("Invalid enum `{}` value: {}", .0, .1)]
    InvalidEnumValue(&'static str, i32),
    #[error("Over recursion limit")]
    OverRecursionLimit,
    #[error("Truncated message")]
    TruncatedMessage,
    // not really possible
    #[error("Limit overflow")]
    LimitOverflow,
    #[error("New limit must not be greater than current limit")]
    LimitIncrease,
    #[error("Encoded message size {0} is too large")]
    MessageTooLarge(u64),
    #[error("Value too large for u32: {}", .0)]
    U32Overflow(u64),
    #[error("Value too large for i32: {}", .0)]
    I32Overflow(i64),
}

/// Generic protobuf error
#[derive(Debug, thiserror::Error)]
pub(crate) enum ProtobufError {
    /// I/O error when reading or writing
    #[error(transparent)]
    IoError(#[from] io::Error),
    /// Malformed input
    #[error(transparent)]
    WireError(#[from] WireError),
    #[error(transparent)]
    Reflect(#[from] ReflectError),
    /// Protocol contains a string which is not valid UTF-8 string
    #[error("UTF-8 decode error")]
    Utf8(
        #[source]
        #[from]
        str::Utf8Error,
    ),
    /// Not all required fields of message set.
    #[error("Message `{}` is missing required fields", .0)]
    MessageNotInitialized(String),
    /// Protobuf type and runtime types mismatch.
    #[error("Protobuf type and runtime types are not compatible")]
    IncompatibleProtobufTypeAndRuntimeType,
    /// Group field type not implemented.
    #[error("Group field is not supported")]
    GroupIsNotImplemented,
}

/// Error type for protobuf operations.
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct Error(pub(crate) Box<ProtobufError>);

impl From<ProtobufError> for Error {
    #[cold]
    fn from(e: ProtobufError) -> Self {
        Self(Box::new(e))
    }
}

impl From<WireError> for Error {
    #[cold]
    fn from(e: WireError) -> Self {
        Self(Box::new(ProtobufError::WireError(e)))
    }
}

impl From<ReflectError> for Error {
    #[cold]
    fn from(e: ReflectError) -> Self {
        Self(Box::new(ProtobufError::Reflect(e)))
    }
}

impl From<Error> for io::Error {
    #[cold]
    fn from(err: Error) -> Self {
        match *err.0 {
            ProtobufError::IoError(e) => e,
            ProtobufError::WireError(e) => {
                io::Error::new(io::ErrorKind::InvalidData, ProtobufError::WireError(e))
            }
            ProtobufError::MessageNotInitialized(message) => io::Error::new(
                io::ErrorKind::InvalidInput,
                ProtobufError::MessageNotInitialized(message),
            ),
            e => io::Error::new(io::ErrorKind::Other, Box::new(e)),
        }
    }
}

impl From<io::Error> for Error {
    #[cold]
    fn from(err: io::Error) -> Self {
        Error(Box::new(ProtobufError::IoError(err)))
    }
}
<commit_msg>Assert error size is usize<commit_after>use std::io;
use std::str;

use crate::reflect::error::ReflectError;
use crate::wire_format::WireType;

/// `Result` alias for `ProtobufError`
pub type Result<T> = std::result::Result<T, crate::Error>;

/// Enum values added here for diagnostic purposes.
/// Users should not depend on specific values.
#[derive(Debug, thiserror::Error)]
pub(crate) enum WireError {
    #[error("Unexpected EOF")]
    UnexpectedEof,
    #[error("Unexpected wire type")]
    UnexpectedWireType(WireType),
    #[error("Incorrect tag")]
    IncorrectTag(u32),
    #[error("Incorrect varint")]
    IncorrectVarint,
    #[error("Invalid UTF-8 sequence")]
    Utf8Error,
    #[error("Invalid enum `{}` value: {}", .0, .1)]
    InvalidEnumValue(&'static str, i32),
    #[error("Over recursion limit")]
    OverRecursionLimit,
    #[error("Truncated message")]
    TruncatedMessage,
    // not really possible
    #[error("Limit overflow")]
    LimitOverflow,
    #[error("New limit must not be greater than current limit")]
    LimitIncrease,
    #[error("Encoded message size {0} is too large")]
    MessageTooLarge(u64),
    #[error("Value too large for u32: {}", .0)]
    U32Overflow(u64),
    #[error("Value too large for i32: {}", .0)]
    I32Overflow(i64),
}

/// Generic protobuf error
#[derive(Debug, thiserror::Error)]
pub(crate) enum ProtobufError {
    /// I/O error when reading or writing
    #[error(transparent)]
    IoError(#[from] io::Error),
    /// Malformed input
    #[error(transparent)]
    WireError(#[from] WireError),
    #[error(transparent)]
    Reflect(#[from] ReflectError),
    /// Protocol contains a string which is not valid UTF-8 string
    #[error("UTF-8 decode error")]
    Utf8(
        #[source]
        #[from]
        str::Utf8Error,
    ),
    /// Not all required fields of message set.
    #[error("Message `{}` is missing required fields", .0)]
    MessageNotInitialized(String),
    /// Protobuf type and runtime types mismatch.
    #[error("Protobuf type and runtime types are not compatible")]
    IncompatibleProtobufTypeAndRuntimeType,
    /// Group field type not implemented.
    #[error("Group field is not supported")]
    GroupIsNotImplemented,
}

/// Error type for protobuf operations.
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct Error(pub(crate) Box<ProtobufError>);

impl From<ProtobufError> for Error {
    #[cold]
    fn from(e: ProtobufError) -> Self {
        Self(Box::new(e))
    }
}

impl From<WireError> for Error {
    #[cold]
    fn from(e: WireError) -> Self {
        Self(Box::new(ProtobufError::WireError(e)))
    }
}

impl From<ReflectError> for Error {
    #[cold]
    fn from(e: ReflectError) -> Self {
        Self(Box::new(ProtobufError::Reflect(e)))
    }
}

impl From<Error> for io::Error {
    #[cold]
    fn from(err: Error) -> Self {
        match *err.0 {
            ProtobufError::IoError(e) => e,
            ProtobufError::WireError(e) => {
                io::Error::new(io::ErrorKind::InvalidData, ProtobufError::WireError(e))
            }
            ProtobufError::MessageNotInitialized(message) => io::Error::new(
                io::ErrorKind::InvalidInput,
                ProtobufError::MessageNotInitialized(message),
            ),
            e => io::Error::new(io::ErrorKind::Other, Box::new(e)),
        }
    }
}

impl From<io::Error> for Error {
    #[cold]
    fn from(err: io::Error) -> Self {
        Error(Box::new(ProtobufError::IoError(err)))
    }
}

#[cfg(test)]
mod test {
    use std::mem;

    #[test]
    fn error_size() {
        assert_eq!(mem::size_of::<usize>(), mem::size_of::<crate::Error>());
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(test, allow(dead_code))]

use self::imp::{drop_handler, make_handler};

pub use self::imp::cleanup;
pub use self::imp::init;

pub struct Handler {
    _data: *mut libc::c_void,
}

impl Handler {
    pub unsafe fn new() -> Handler {
        make_handler()
    }

    fn null() -> Handler {
        Handler { _data: crate::ptr::null_mut() }
    }
}

impl Drop for Handler {
    fn drop(&mut self) {
        unsafe {
            drop_handler(self);
        }
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "solaris",
    target_os = "illumos",
    target_os = "netbsd",
    target_os = "openbsd"
))]
mod imp {
    use super::Handler;
    use crate::io;
    use crate::mem;
    use crate::ptr;
    use crate::thread;

    use libc::MAP_FAILED;
    use libc::{mmap, munmap};
    use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL};
    use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
    use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV};

    use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
    use crate::sys::unix::os::page_size;
    use crate::sys_common::thread_info;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
        #[repr(C)]
        struct siginfo_t {
            a: [libc::c_int; 3], // si_signo, si_errno, si_code
            si_addr: *mut libc::c_void,
        }

        (*(info as *const siginfo_t)).si_addr as usize
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
        (*info).si_addr as usize
    }

    // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
    // (unmapped pages) at the end of every thread's stack, so if a thread ends
    // up running into the guard page it'll trigger this handler. We want to
    // detect these cases and print out a helpful error saying that the stack
    // has overflowed. All other signals, however, should go back to what they
    // were originally supposed to do.
    //
    // This handler currently exists purely to print an informative message
    // whenever a thread overflows its stack. We then abort to exit and
    // indicate a crash, but to avoid a misleading SIGSEGV that might lead
    // users to believe that unsafe code has accessed an invalid pointer; the
    // SIGSEGV encountered when overflowing the stack is expected and
    // well-defined.
    //
    // If this is not a stack overflow, the handler un-registers itself and
    // then returns (to allow the original signal to be delivered again).
    // Returning from this kind of signal handler is technically not defined
    // to work when reading the POSIX spec strictly, but in practice it turns
    // out many large systems and all implementations allow returning from a
    // signal handler to work. For a more detailed explanation see the
    // comments on #26458.
    unsafe extern "C" fn signal_handler(
        signum: libc::c_int,
        info: *mut libc::siginfo_t,
        _data: *mut libc::c_void,
    ) {
        let guard = thread_info::stack_guard().unwrap_or(0..0);
        let addr = siginfo_si_addr(info);

        // If the faulting address is within the guard page, then we print a
        // message saying so and abort.
        if guard.start <= addr && addr < guard.end {
            rtprintpanic!(
                "\nthread '{}' has overflowed its stack\n",
                thread::current().name().unwrap_or("<unknown>")
            );
            rtabort!("stack overflow");
        } else {
            // Unregister ourselves by reverting back to the default behavior.
            let mut action: sigaction = mem::zeroed();
            action.sa_sigaction = SIG_DFL;
            sigaction(signum, &action, ptr::null_mut());

            // See comment above for why this function returns.
        }
    }

    static MAIN_ALTSTACK: AtomicPtr<libc::c_void> = AtomicPtr::new(ptr::null_mut());
    static NEED_ALTSTACK: AtomicBool = AtomicBool::new(false);

    pub unsafe fn init() {
        let mut action: sigaction = mem::zeroed();
        for &signal in &[SIGSEGV, SIGBUS] {
            sigaction(signal, ptr::null_mut(), &mut action);
            // Configure our signal handler if one is not already set.
            if action.sa_sigaction == SIG_DFL {
                action.sa_flags = SA_SIGINFO | SA_ONSTACK;
                action.sa_sigaction = signal_handler as sighandler_t;
                sigaction(signal, &action, ptr::null_mut());
                NEED_ALTSTACK.store(true, Ordering::Relaxed);
            }
        }

        let handler = make_handler();
        MAIN_ALTSTACK.store(handler._data, Ordering::Relaxed);
        mem::forget(handler);
    }

    pub unsafe fn cleanup() {
        Handler { _data: MAIN_ALTSTACK.load(Ordering::Relaxed) };
    }

    unsafe fn get_stackp() -> *mut libc::c_void {
        let stackp = mmap(
            ptr::null_mut(),
            SIGSTKSZ + page_size(),
            PROT_READ | PROT_WRITE,
            MAP_PRIVATE | MAP_ANON,
            -1,
            0,
        );
        if stackp == MAP_FAILED {
            panic!("failed to allocate an alternative stack: {}", io::Error::last_os_error());
        }
        let guard_result = libc::mprotect(stackp, page_size(), PROT_NONE);
        if guard_result != 0 {
            panic!("failed to set up alternative stack guard page: {}", io::Error::last_os_error());
        }
        stackp.add(page_size())
    }

    #[cfg(any(
        target_os = "linux",
        target_os = "macos",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
        target_os = "solaris",
        target_os = "illumos"
    ))]
    unsafe fn get_stack() -> libc::stack_t {
        libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ }
    }

    #[cfg(target_os = "dragonfly")]
    unsafe fn get_stack() -> libc::stack_t {
        libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ }
    }

    pub unsafe fn make_handler() -> Handler {
        if !NEED_ALTSTACK.load(Ordering::Relaxed) {
            return Handler::null();
        }
        let mut stack = mem::zeroed();
        sigaltstack(ptr::null(), &mut stack);
        // Configure alternate signal stack, if one is not already set.
        if stack.ss_flags & SS_DISABLE != 0 {
            stack = get_stack();
            sigaltstack(&stack, ptr::null_mut());
            Handler { _data: stack.ss_sp as *mut libc::c_void }
        } else {
            Handler::null()
        }
    }

    pub unsafe fn drop_handler(handler: &mut Handler) {
        if !handler._data.is_null() {
            let stack = libc::stack_t {
                ss_sp: ptr::null_mut(),
                ss_flags: SS_DISABLE,
                // Workaround for bug in macOS implementation of sigaltstack
                // UNIX2003 which returns ENOMEM when disabling a stack while
                // passing ss_size smaller than MINSIGSTKSZ. According to POSIX
                // both ss_sp and ss_size should be ignored in this case.
                ss_size: SIGSTKSZ,
            };
            sigaltstack(&stack, ptr::null_mut());
            // We know from `get_stackp` that the alternate stack we installed is part of a mapping
            // that started one page earlier, so walk back a page and unmap from there.
            munmap(handler._data.sub(page_size()), SIGSTKSZ + page_size());
        }
    }
}

#[cfg(not(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "solaris",
    target_os = "illumos",
    target_os = "netbsd",
    target_os = "openbsd",
)))]
mod imp {
    pub unsafe fn init() {}

    pub unsafe fn cleanup() {}

    pub unsafe fn make_handler() -> super::Handler {
        super::Handler::null()
    }

    pub unsafe fn drop_handler(_handler: &mut super::Handler) {}
}
<commit_msg>stack overflow handler specific openbsd fix.<commit_after>#![cfg_attr(test, allow(dead_code))]

use self::imp::{drop_handler, make_handler};

pub use self::imp::cleanup;
pub use self::imp::init;

pub struct Handler {
    _data: *mut libc::c_void,
}

impl Handler {
    pub unsafe fn new() -> Handler {
        make_handler()
    }

    fn null() -> Handler {
        Handler { _data: crate::ptr::null_mut() }
    }
}

impl Drop for Handler {
    fn drop(&mut self) {
        unsafe {
            drop_handler(self);
        }
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "solaris",
    target_os = "illumos",
    target_os = "netbsd",
    target_os = "openbsd"
))]
mod imp {
    use super::Handler;
    use crate::io;
    use crate::mem;
    use crate::ptr;
    use crate::thread;

    use libc::MAP_FAILED;
    use libc::{mmap, munmap};
    use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL};
    use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
    use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV};

    use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
    use crate::sys::unix::os::page_size;
    use crate::sys_common::thread_info;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
        #[repr(C)]
        struct siginfo_t {
            a: [libc::c_int; 3], // si_signo, si_errno, si_code
            si_addr: *mut libc::c_void,
        }

        (*(info as *const siginfo_t)).si_addr as usize
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
        (*info).si_addr as usize
    }

    // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
    // (unmapped pages) at the end of every thread's stack, so if a thread ends
    // up running into the guard page it'll trigger this handler. We want to
    // detect these cases and print out a helpful error saying that the stack
    // has overflowed. All other signals, however, should go back to what they
    // were originally supposed to do.
    //
    // This handler currently exists purely to print an informative message
    // whenever a thread overflows its stack. We then abort to exit and
    // indicate a crash, but to avoid a misleading SIGSEGV that might lead
    // users to believe that unsafe code has accessed an invalid pointer; the
    // SIGSEGV encountered when overflowing the stack is expected and
    // well-defined.
    //
    // If this is not a stack overflow, the handler un-registers itself and
    // then returns (to allow the original signal to be delivered again).
    // Returning from this kind of signal handler is technically not defined
    // to work when reading the POSIX spec strictly, but in practice it turns
    // out many large systems and all implementations allow returning from a
    // signal handler to work. For a more detailed explanation see the
    // comments on #26458.
    unsafe extern "C" fn signal_handler(
        signum: libc::c_int,
        info: *mut libc::siginfo_t,
        _data: *mut libc::c_void,
    ) {
        let guard = thread_info::stack_guard().unwrap_or(0..0);
        let addr = siginfo_si_addr(info);

        // If the faulting address is within the guard page, then we print a
        // message saying so and abort.
        if guard.start <= addr && addr < guard.end {
            rtprintpanic!(
                "\nthread '{}' has overflowed its stack\n",
                thread::current().name().unwrap_or("<unknown>")
            );
            rtabort!("stack overflow");
        } else {
            // Unregister ourselves by reverting back to the default behavior.
            let mut action: sigaction = mem::zeroed();
            action.sa_sigaction = SIG_DFL;
            sigaction(signum, &action, ptr::null_mut());

            // See comment above for why this function returns.
        }
    }

    static MAIN_ALTSTACK: AtomicPtr<libc::c_void> = AtomicPtr::new(ptr::null_mut());
    static NEED_ALTSTACK: AtomicBool = AtomicBool::new(false);

    pub unsafe fn init() {
        let mut action: sigaction = mem::zeroed();
        for &signal in &[SIGSEGV, SIGBUS] {
            sigaction(signal, ptr::null_mut(), &mut action);
            // Configure our signal handler if one is not already set.
            if action.sa_sigaction == SIG_DFL {
                action.sa_flags = SA_SIGINFO | SA_ONSTACK;
                action.sa_sigaction = signal_handler as sighandler_t;
                sigaction(signal, &action, ptr::null_mut());
                NEED_ALTSTACK.store(true, Ordering::Relaxed);
            }
        }

        let handler = make_handler();
        MAIN_ALTSTACK.store(handler._data, Ordering::Relaxed);
        mem::forget(handler);
    }

    pub unsafe fn cleanup() {
        Handler { _data: MAIN_ALTSTACK.load(Ordering::Relaxed) };
    }

    unsafe fn get_stackp() -> *mut libc::c_void {
        // OpenBSD requires this flag for stack mapping
        // otherwise the said mapping will fail as a no-op on most systems
        // and has a different meaning on FreeBSD
        #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "linux",))]
        let flags = MAP_PRIVATE | MAP_ANON | libc::MAP_STACK;
        #[cfg(not(any(target_os = "openbsd", target_os = "netbsd", target_os = "linux",)))]
        let flags = MAP_PRIVATE | MAP_ANON;
        let stackp =
            mmap(ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, flags, -1, 0);
        if stackp == MAP_FAILED {
            panic!("failed to allocate an alternative stack: {}", io::Error::last_os_error());
        }
        let guard_result = libc::mprotect(stackp, page_size(), PROT_NONE);
        if guard_result != 0 {
            panic!("failed to set up alternative stack guard page: {}", io::Error::last_os_error());
        }
        stackp.add(page_size())
    }

    #[cfg(any(
        target_os = "linux",
        target_os = "macos",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
        target_os = "solaris",
        target_os = "illumos"
    ))]
    unsafe fn get_stack() -> libc::stack_t {
        libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ }
    }

    #[cfg(target_os = "dragonfly")]
    unsafe fn get_stack() -> libc::stack_t {
        libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ }
    }

    pub unsafe fn make_handler() -> Handler {
        if !NEED_ALTSTACK.load(Ordering::Relaxed) {
            return Handler::null();
        }
        let mut stack = mem::zeroed();
        sigaltstack(ptr::null(), &mut stack);
        // Configure alternate signal stack, if one is not already set.
        if stack.ss_flags & SS_DISABLE != 0 {
            stack = get_stack();
            sigaltstack(&stack, ptr::null_mut());
            Handler { _data: stack.ss_sp as *mut libc::c_void }
        } else {
            Handler::null()
        }
    }

    pub unsafe fn drop_handler(handler: &mut Handler) {
        if !handler._data.is_null() {
            let stack = libc::stack_t {
                ss_sp: ptr::null_mut(),
                ss_flags: SS_DISABLE,
                // Workaround for bug in macOS implementation of sigaltstack
                // UNIX2003 which returns ENOMEM when disabling a stack while
                // passing ss_size smaller than MINSIGSTKSZ. According to POSIX
                // both ss_sp and ss_size should be ignored in this case.
                ss_size: SIGSTKSZ,
            };
            sigaltstack(&stack, ptr::null_mut());
            // We know from `get_stackp` that the alternate stack we installed is part of a mapping
            // that started one page earlier, so walk back a page and unmap from there.
            munmap(handler._data.sub(page_size()), SIGSTKSZ + page_size());
        }
    }
}

#[cfg(not(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "solaris",
    target_os = "illumos",
    target_os = "netbsd",
    target_os = "openbsd",
)))]
mod imp {
    pub unsafe fn init() {}

    pub unsafe fn cleanup() {}

    pub unsafe fn make_handler() -> super::Handler {
        super::Handler::null()
    }

    pub unsafe fn drop_handler(_handler: &mut super::Handler) {}
}
<|endoftext|>


<commit_before>extern crate pty;
extern crate libc;

use self::pty::prelude::*;

use std::ffi::CString;

use std::io::prelude::*;
use std::ptr;
use std::string::String;

#[test]
fn it_can_read_write() {
    let fork = Fork::from_ptmx().unwrap();

    if let Some(mut master) = fork.is_parent().ok() {
        let _ = master.write("echo readme!\n".to_string().as_bytes());

        let mut string = String::new();

        master.read_to_string(&mut string).unwrap_or_else(|e| panic!(e));

        assert!(string.contains("readme!"));

        let _ = master.write("exit\n".to_string().as_bytes());
    } else {
        let mut ptrs = [CString::new("bash").unwrap().as_ptr(), ptr::null()];

        print!(" "); // FIXME I'm not sure but this is needed to prevent read-block.

        let _ = unsafe { libc::execvp(*ptrs.as_ptr(), ptrs.as_mut_ptr()) };
    }
}
<commit_msg>switch from execvp to Command::new to solve freeing of mem issue, correct reading back of output with read() rather than read_to_string<commit_after>extern crate pty;
extern crate libc;

use std::io::prelude::*;
use std::string::String;
use std::process::Command;
use pty::fork::{Fork, Master};

fn read_line(master:&mut Master) -> String {
    let mut buf = [0];
    let mut res = String::new();
    while buf[0] as char != '\n' {
        master.read(&mut buf).expect("cannot read 1 byte");
        res.push(buf[0] as char)
    }
    res
}

#[test]
fn it_can_read_write() {
    let fork = Fork::from_ptmx().unwrap();

    if let Some(mut master) = fork.is_parent().ok() {
        let _ = master.write("echo readme!\n".to_string().as_bytes());

        read_line(&mut master); // this is the "echo readme!" we just sent
        read_line(&mut master); // this is the shell and "echo readme!" again
        assert_eq!(read_line(&mut master).trim(), "readme!");
        let _ = master.write("exit\n".to_string().as_bytes());
    } else {
        let _ = Command::new("bash").status();
    }
}
<|endoftext|>


<commit_before>extern crate gcc;
extern crate libbindgen;

use std::env;
use std::path::Path;

fn main() {
    let mut gcc_config = gcc::Config::new();

    gcc_config.file("src/fasthash.cpp")
        .file("src/smhasher/City.cpp")
        .file("src/smhasher/farmhash-c.c")
        .file("src/smhasher/lookup3.cpp")
        .file("src/smhasher/mum.cc")
        .file("src/smhasher/metrohash64.cpp")
        .file("src/smhasher/metrohash128.cpp")
        .file("src/smhasher/MurmurHash1.cpp")
        .file("src/smhasher/MurmurHash2.cpp")
        .file("src/smhasher/MurmurHash3.cpp")
        .file("src/smhasher/Spooky.cpp")
        .file("src/smhasher/t1ha.cc")
        .file("src/smhasher/xxhash.c");

    if cfg!(feature = "sse42") {
        gcc_config.flag("-msse4.2")
            .file("src/smhasher/metrohash64crc.cpp")
            .file("src/smhasher/metrohash128crc.cpp");
    }

    gcc_config.compile("libfasthash.a");

    let out_dir = env::var("OUT_DIR").unwrap();
    let out_file = Path::new(&out_dir).join("src/fasthash.rs");

    if Path::new("src/fasthash.rs").exists() {
        std::fs::copy("src/fasthash.rs", out_file).unwrap();
    } else {
        let _ = libbindgen::builder()
            .clang_arg("-xc++")
            .clang_arg("--std=c++11")
            .clang_arg(if cfg!(feature = "sse42") {
                "-msse4.2"
            } else {
                "-march=native"
            })
            .header("src/fasthash.hpp")
            .no_unstable_rust()
            .whitelisted_function("^CityHash.*")
            .whitelisted_function("^farmhash.*")
            .whitelisted_function("^lookup3.*")
            .whitelisted_function("^metrohash.*")
            .whitelisted_function("^mum_hash.*")
            .whitelisted_function("^MurmurHash.*")
            .whitelisted_function("^SpookyHasher.*")
            .whitelisted_function("^t1ha.*")
            .whitelisted_function("^XXH.*")
            .link_static("fasthash")
            .generate()
            .unwrap()
            .write_to_file(out_file)
            .expect("Couldn't write bindings!");
    }

    if cfg!(target_os = "macos") {
        println!("cargo:rustc-link-lib=dylib=c++");
    } else {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    }
}
<commit_msg>Force to link libfasthash.a when use cached fasthash.rs<commit_after>extern crate gcc;
extern crate libbindgen;

use std::env;
use std::path::Path;

fn main() {
    let mut gcc_config = gcc::Config::new();

    gcc_config.file("src/fasthash.cpp")
        .file("src/smhasher/City.cpp")
        .file("src/smhasher/farmhash-c.c")
        .file("src/smhasher/lookup3.cpp")
        .file("src/smhasher/mum.cc")
        .file("src/smhasher/metrohash64.cpp")
        .file("src/smhasher/metrohash128.cpp")
        .file("src/smhasher/MurmurHash1.cpp")
        .file("src/smhasher/MurmurHash2.cpp")
        .file("src/smhasher/MurmurHash3.cpp")
        .file("src/smhasher/Spooky.cpp")
        .file("src/smhasher/t1ha.cc")
        .file("src/smhasher/xxhash.c");

    if cfg!(feature = "sse42") {
        gcc_config.flag("-msse4.2")
            .file("src/smhasher/metrohash64crc.cpp")
            .file("src/smhasher/metrohash128crc.cpp");
    }

    gcc_config.compile("libfasthash.a");

    let out_dir = env::var("OUT_DIR").unwrap();
    let out_file = Path::new(&out_dir).join("src/fasthash.rs");

    if Path::new("src/fasthash.rs").exists() {
        std::fs::copy("src/fasthash.rs", out_file).unwrap();

        println!("cargo:rustc-link-lib=static=fasthash");
    } else {
        let _ = libbindgen::builder()
            .clang_arg("-xc++")
            .clang_arg("--std=c++11")
            .clang_arg(if cfg!(feature = "sse42") {
                "-msse4.2"
            } else {
                "-march=native"
            })
            .header("src/fasthash.hpp")
            .no_unstable_rust()
            .whitelisted_function("^CityHash.*")
            .whitelisted_function("^farmhash.*")
            .whitelisted_function("^lookup3.*")
            .whitelisted_function("^metrohash.*")
            .whitelisted_function("^mum_hash.*")
            .whitelisted_function("^MurmurHash.*")
            .whitelisted_function("^SpookyHasher.*")
            .whitelisted_function("^t1ha.*")
            .whitelisted_function("^XXH.*")
            .link_static("fasthash")
            .generate()
            .unwrap()
            .write_to_file(out_file)
            .expect("Couldn't write bindings!");
    }

    if cfg!(target_os = "macos") {
        println!("cargo:rustc-link-lib=dylib=c++");
    } else {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    }
}
<|endoftext|>


<commit_before>extern crate amq_protocol_types;

use amq_protocol_types::*;

#[test]
fn test_full_integration() {
    let mut table          = FieldTable::new();
    let value              = AMQPValue::FieldTable(table);
    let mut buf: [u8; 512] = [0; 512];
    assert_eq!(parse_value(gen_value((&mut buf[..], 0), &value).unwrap().0).to_result().unwrap(), value);
}
<commit_msg>add integration test<commit_after>extern crate amq_protocol_types;

use amq_protocol_types::*;

#[test]
fn test_full_integration() {
    let mut table = FieldTable::new();
    let mut table2 = FieldTable::new();

    table2.insert("foo".to_string(), AMQPValue::DecimalValue(DecimalValue { scale: 55, value: 999, }));
    table2.insert("bar".to_string(), AMQPValue::ShortString("blah".to_string()));
    table2.insert("baz".to_string(), AMQPValue::LongString("blah42".to_string()));

    table.insert("foo".to_string(),  AMQPValue::FieldArray(vec![AMQPValue::Void]));
    table.insert("oof".to_string(),  AMQPValue::FieldArray(FieldArray::new()));
    table.insert("bar".to_string(),  AMQPValue::FieldTable(FieldTable::new()));
    table.insert("blah".to_string(), AMQPValue::Boolean(false));
    table.insert("aaaa".to_string(), AMQPValue::ShortShortInt(42));
    table.insert("bbbb".to_string(), AMQPValue::ShortShortUInt(64));
    table.insert("cccc".to_string(), AMQPValue::ShortInt(32));
    table.insert("dddd".to_string(), AMQPValue::ShortUInt(132));
    table.insert("eeee".to_string(), AMQPValue::LongInt(-53));
    table.insert("ffff".to_string(), AMQPValue::LongUInt(66666));
    table.insert("gggg".to_string(), AMQPValue::LongLongInt(-9999));
    table.insert("hhhh".to_string(), AMQPValue::LongLongUInt(0));
    table.insert("iiii".to_string(), AMQPValue::Float(42.3));
    table.insert("jjjj".to_string(), AMQPValue::Double(0.00987654321));
    table.insert("kkkk".to_string(), AMQPValue::Timestamp(1234567890));
    table.insert("llll".to_string(), AMQPValue::Void);

    let value              = AMQPValue::FieldTable(table);
    let mut buf: [u8; 512] = [0; 512];

    assert_eq!(parse_value(gen_value((&mut buf[..], 0), &value).unwrap().0).to_result().unwrap(), value);
}
<|endoftext|>


<commit_before>use std::f32;
use std::io::Read;
use std::io::Chars;
use super::Error;

pub struct BufferConsumer<B> {
    row: usize,
    col: usize,
    buffer: Chars<B>,
    tmp_char: Option<char>,
}

impl<B> BufferConsumer<B>
    where B: Read
{
    pub fn new(reader: B) -> BufferConsumer<B> {
        BufferConsumer {
            row: 0,
            col: 0,
            buffer: reader.chars(),
            tmp_char: None,
        }
    }

    pub fn consume_word(&mut self) -> Result<String, Error> {
        self.consume_while(valid_alphabet_char)
    }

    pub fn consume_identifier(&mut self) -> Result<String, Error> {
        self.consume_while(valid_identifier_char)
    }

    pub fn consume_path(&mut self) -> Result<String, Error> {
        self.consume_while(valid_path_char)
    }

    pub fn consume_number(&mut self) -> Result<f32, Error> {
        let num: String = try!(self.consume_while(is_numeric));
        f32::from_str_radix(&num, 10)
            .map_err(|err| {
                Error::new(self.row, self.col, format!("Incorrect float value: {}", err))
            })
    }

    pub fn consume_whitespace(&mut self) -> Result<(), Error> {
        try!(self.consume_while(char::is_whitespace));
        Ok(())
    }

    pub fn expect_char(&mut self, expect: char) -> Result<(), Error> {
        match self.look_next_char() {
            Some(c) if c == expect => {
                self.consume_any_char();
                Ok(())
            }
            Some(c) => {
                Err(self.error_str(format!(
                    "Expected character `{}` found: `{}`",
                    expect,
                    c
                )))
            }
            _ => {
                Err(self.error_str(format!(
                    "Unexpected end of stream, expected `{}`",
                    expect
                )))
            }
        }
    }

    /// Consume characters until `test` returns false.
    /// This function return Err() only if the end of the stream
    /// is encountered.
    pub fn consume_while<F>(&mut self, test: F) -> Result<String, Error>
        where F: Fn(char) -> bool
    {
        let mut result = String::new();
        loop {
            match self.look_next_char() {
                Some(c) => {
                    if !test(c) {
                        return Ok(result)
                    }
                    self.consume_any_char();
                    result.push(c);
                }
                None => return Ok(result),
            }
        }
    }

    pub fn consume_any_char(&mut self) -> Option<char> {
        if self.tmp_char.is_none() {
            match self.buffer.next().and_then(|a| a.ok()) {
                Some(c) => {
                    if c == '\n' {
                        self.row += 1;
                        self.col = 0;
                    } else {
                        self.col += 1;
                    }
                    self.tmp_char = Some(c);
                    Some(c)
                }
                None => None
            }
        } else {
            let c = self.tmp_char.unwrap();
            self.tmp_char = None;
            Some(c)
        }
    }

    pub fn look_next_char(&mut self) -> Option<char> {
        if self.tmp_char.is_none() {
            self.consume_any_char()
        } else {
            self.tmp_char
        }
    }

    pub fn error(&self, msg: &str) -> Error {
        Error::new(self.row, self.col, msg.to_string())
    }

    pub fn error_str(&self, msg: String) -> Error {
        Error::new(self.row, self.col, msg)
    }

    pub fn error_eof(&self) -> Error {
        Error::new(self.row, self.col, "Unexpected end of stream".to_string())
    }
}

// ======================================== //
//                  HELPERS                 //
// ======================================== //

fn is_numeric(c: char) -> bool {
    char::is_numeric(c) || c == '.'
}

fn valid_alphabet_char(c: char) -> bool {
    match c {
        'a'...'z' | 'A'...'Z' => true,
        _ => false,
    }
}

fn valid_identifier_char(c: char) -> bool {
    match c {
        '0'...'9' | '-' | '_' => true,
        _ => valid_alphabet_char(c),
    }
}

fn valid_path_char(c: char) -> bool {
    match c {
        '.' => true,
        _ => valid_identifier_char(c)
    }
}
<commit_msg>consume_any_char now consume everytime.<commit_after>use std::f32;
use std::io::Read;
use std::io::Chars;
use super::Error;

pub struct BufferConsumer<B> {
    row: usize,
    col: usize,
    buffer: Chars<B>,
    tmp_char: Option<char>,
}

impl<B> BufferConsumer<B>
    where B: Read
{
    pub fn new(reader: B) -> BufferConsumer<B> {
        BufferConsumer {
            row: 0,
            col: 0,
            buffer: reader.chars(),
            tmp_char: None,
        }
    }

    pub fn consume_word(&mut self) -> Result<String, Error> {
        self.consume_while(valid_alphabet_char)
    }

    pub fn consume_identifier(&mut self) -> Result<String, Error> {
        self.consume_while(valid_identifier_char)
    }

    pub fn consume_path(&mut self) -> Result<String, Error> {
        self.consume_while(valid_path_char)
    }

    pub fn consume_number(&mut self) -> Result<f32, Error> {
        let num: String = try!(self.consume_while(is_numeric));
        f32::from_str_radix(&num, 10)
            .map_err(|err| {
                Error::new(self.row, self.col, format!("Incorrect float value: {}", err))
            })
    }

    pub fn consume_whitespace(&mut self) -> Result<(), Error> {
        try!(self.consume_while(char::is_whitespace));
        Ok(())
    }

    pub fn expect_char(&mut self, expect: char) -> Result<(), Error> {
        match self.look_next_char() {
            Some(c) if c == expect => {
                self.consume_any_char();
                Ok(())
            }
            Some(c) => {
                Err(self.error_str(format!(
                    "Expected character `{}` found: `{}`",
                    expect,
                    c
                )))
            }
            _ => {
                Err(self.error_str(format!(
                    "Unexpected end of stream, expected `{}`",
                    expect
                )))
            }
        }
    }

    /// Consume characters until `test` returns false.
    /// This function return Err() only if the end of the stream
    /// is encountered.
    pub fn consume_while<F>(&mut self, test: F) -> Result<String, Error>
        where F: Fn(char) -> bool
    {
        let mut result = String::new();
        loop {
            match self.look_next_char() {
                Some(c) => {
                    if !test(c) {
                        return Ok(result)
                    }
                    self.consume_any_char();
                    result.push(c);
                }
                None => return Ok(result),
            }
        }
    }

    pub fn consume_any_char(&mut self) -> Option<char> {
        if self.tmp_char.is_none() {
            match self.buffer.next().and_then(|a| a.ok()) {
                Some(c) => {
                    if c == '\n' {
                        self.row += 1;
                        self.col = 0;
                    } else {
                        self.col += 1;
                    }
                    Some(c)
                }
                None => None
            }
        } else {
            let c = self.tmp_char.unwrap();
            self.tmp_char = None;
            Some(c)
        }
    }

    pub fn look_next_char(&mut self) -> Option<char> {

        if self.tmp_char.is_none() {
            self.tmp_char = self.consume_any_char();
        }

        self.tmp_char
    }

    pub fn error(&self, msg: &str) -> Error {
        Error::new(self.row, self.col, msg.to_string())
    }

    pub fn error_str(&self, msg: String) -> Error {
        Error::new(self.row, self.col, msg)
    }

    pub fn error_eof(&self) -> Error {
        Error::new(self.row, self.col, "Unexpected end of stream".to_string())
    }
}

// ======================================== //
//                  HELPERS                 //
// ======================================== //

fn is_numeric(c: char) -> bool {
    char::is_numeric(c) || c == '.'
}

fn valid_alphabet_char(c: char) -> bool {
    match c {
        'a'...'z' | 'A'...'Z' => true,
        _ => false,
    }
}

fn valid_identifier_char(c: char) -> bool {
    match c {
        '0'...'9' | '-' | '_' => true,
        _ => valid_alphabet_char(c),
    }
}

fn valid_path_char(c: char) -> bool {
    match c {
        '.' => true,
        _ => valid_identifier_char(c)
    }
}

// ======================================== //
//                   TESTS                  //
// ======================================== //

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

    #[test]
    fn consume_any_char_should_consume() {
        let text = "abcd";
        let mut consumer = BufferConsumer::new(text.as_bytes());
        assert_eq!(consumer.consume_any_char(), Some('a'));
        assert_eq!(consumer.consume_any_char(), Some('b'));
        assert_eq!(consumer.consume_any_char(), Some('c'));
        assert_eq!(consumer.consume_any_char(), Some('d'));
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::fmt::Debug;

use Transform;
use interaction::SurfaceInteraction;
use paramset::TextureParams;
use spectrum::Spectrum;
use texture::{ConstantTexture, Texture, TextureMapping2D, UVMapping2D};

#[derive(Debug)]
pub struct CheckerboardTexture<T> {
    tex1: Arc<Texture<T> + Send + Sync>,
    tex2: Arc<Texture<T> + Send + Sync>,
    mapping: Box<TextureMapping2D + Send + Sync>,
}

impl<T> CheckerboardTexture<T> {
    pub fn new(tex1: Arc<Texture<T> + Send + Sync>,
               tex2: Arc<Texture<T> + Send + Sync>,
               mapping: Box<TextureMapping2D + Send + Sync>)
               -> CheckerboardTexture<T> {
        CheckerboardTexture {
            tex1: tex1,
            tex2: tex2,
            mapping: mapping,
        }
    }
}

impl CheckerboardTexture<Spectrum> {
    pub fn bw() -> CheckerboardTexture<Spectrum> {
        CheckerboardTexture::new(Arc::new(ConstantTexture::new(Spectrum::black())),
                                 Arc::new(ConstantTexture::new(Spectrum::white())),
                                 Box::new(UVMapping2D::new(10.0, 10.0, 0.0, 0.0)))
    }

    pub fn create_spectrum(_tex2world: &Transform,
                           tp: &mut TextureParams)
                           -> CheckerboardTexture<Spectrum> {
        let dim = tp.find_int("dimension", 2);
        if dim != 2 && dim != 3 {
            panic!("{} dimensional checkerboard texture not supported", dim);
        }
        let tex1 = tp.get_spectrum_texture("tex1", &Spectrum::white());
        let tex2 = tp.get_spectrum_texture("tex2", &Spectrum::black());
        if dim == 2 {
            // Initialize 2D texture mapping `map` from `tp`
            let typ = tp.find_string("mapping", "uv");
            let map = if typ == "uv" {
                let su = tp.find_float("uscale", 1.0);
                let sv = tp.find_float("vscale", 1.0);
                let du = tp.find_float("udelta", 0.0);
                let dv = tp.find_float("vdelta", 0.0);
                UVMapping2D::new(su, sv, du, dv)
            } else if typ == "spherical" {
                unimplemented!()
            } else if typ == "cylindrical" {
                unimplemented!()
            } else if typ == "planar" {
                unimplemented!()
            } else {
                error!("2D texture mapping {} unknown", typ);
                UVMapping2D::new(1.0, 1.0, 0.0, 0.0)
            };

            // Compute `aaMethod` for `CheckerboardTexture`
            let _aa = tp.find_string("aamode", "closedform");
            // TODO finish aamode
            CheckerboardTexture::new(tex1, tex2, Box::new(map))
        } else {
            unimplemented!()
        }
    }
}

impl<T: Debug> Texture<T> for CheckerboardTexture<T> {
    fn evaluate(&self, si: &SurfaceInteraction) -> T {
        let (st, _dstdx, _dstdy) = self.mapping.map(si);
        if (st.x.floor() as u32 + st.y.floor() as u32) % 2 == 0 {
            self.tex1.evaluate(si)
        } else {
            self.tex2.evaluate(si)
        }
        // TODO implement closeform antialiasing
    }
}
<commit_msg>Implement closedform aa method for checkerboard<commit_after>use std::sync::Arc;
use std::fmt::Debug;
use std::ops::{Add, Mul};

use Transform;
use interaction::SurfaceInteraction;
use paramset::TextureParams;
use spectrum::Spectrum;
use texture::{Texture, TextureMapping2D, UVMapping2D};

#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum AAMethod {
    None,
    ClosedForm,
}

#[derive(Debug)]
pub struct CheckerboardTexture<T> {
    tex1: Arc<Texture<T> + Send + Sync>,
    tex2: Arc<Texture<T> + Send + Sync>,
    mapping: Box<TextureMapping2D + Send + Sync>,
    aa_method: AAMethod,
}

impl<T> CheckerboardTexture<T> {
    pub fn new(tex1: Arc<Texture<T> + Send + Sync>,
               tex2: Arc<Texture<T> + Send + Sync>,
               mapping: Box<TextureMapping2D + Send + Sync>,
               aa_method: AAMethod)
               -> CheckerboardTexture<T> {
        CheckerboardTexture {
            tex1,
            tex2,
            mapping,
            aa_method,
        }
    }
}

impl CheckerboardTexture<Spectrum> {
    pub fn create_spectrum(_tex2world: &Transform,
                           tp: &mut TextureParams)
                           -> CheckerboardTexture<Spectrum> {
        let dim = tp.find_int("dimension", 2);
        if dim != 2 && dim != 3 {
            panic!("{} dimensional checkerboard texture not supported", dim);
        }
        let tex1 = tp.get_spectrum_texture("tex1", &Spectrum::white());
        let tex2 = tp.get_spectrum_texture("tex2", &Spectrum::black());
        if dim == 2 {
            // Initialize 2D texture mapping `map` from `tp`
            let typ = tp.find_string("mapping", "uv");
            let map = if typ == "uv" {
                let su = tp.find_float("uscale", 1.0);
                let sv = tp.find_float("vscale", 1.0);
                let du = tp.find_float("udelta", 0.0);
                let dv = tp.find_float("vdelta", 0.0);
                UVMapping2D::new(su, sv, du, dv)
            } else if typ == "spherical" {
                unimplemented!()
            } else if typ == "cylindrical" {
                unimplemented!()
            } else if typ == "planar" {
                unimplemented!()
            } else {
                error!("2D texture mapping {} unknown", typ);
                UVMapping2D::new(1.0, 1.0, 0.0, 0.0)
            };

            // Compute `aaMethod` for `CheckerboardTexture`
            let aa = tp.find_string("aamode", "closedform");
            let aa_method = if aa == "none" {
                AAMethod::None
            } else if aa == "closedform" {
                AAMethod::ClosedForm
            } else {
                warn!("Unknown aamethod \"{}\" found for CheckerboardTexture. Using closedform instead",
                      aa);
                AAMethod::ClosedForm
            };
            CheckerboardTexture::new(tex1, tex2, Box::new(map), aa_method)
        } else {
            unimplemented!()
        }
    }
}

impl<T> Texture<T> for CheckerboardTexture<T>
    where T: Debug,
          T: Mul<f32, Output = T>,
          T: Add<Output = T>
{
    fn evaluate(&self, si: &SurfaceInteraction) -> T {
        let (st, dstdx, dstdy) = self.mapping.map(si);
        match self.aa_method {
            AAMethod::None => {
                if (st.x.floor() as u32 + st.y.floor() as u32) % 2 == 0 {
                    self.tex1.evaluate(si)
                } else {
                    self.tex2.evaluate(si)
                }
            }
            AAMethod::ClosedForm => {
                // Compute closed-form box-filtered _Checkerboard2DTexture_ value

                // Evaluate single check if filter is entirely inside one of them
                let ds = f32::max(f32::abs(dstdx[0]), f32::abs(dstdy[0]));
                let dt = f32::max(f32::abs(dstdx[1]), f32::abs(dstdy[1]));
                let s0 = st[0] - ds;
                let s1 = st[0] + ds;
                let t0 = st[1] - dt;
                let t1 = st[1] + dt;
                if f32::floor(s0) == f32::floor(s1) && f32::floor(t0) == f32::floor(t1) {
                    // Point sample _Checkerboard2DTexture_
                    if (f32::floor(st[0]) as i32 + f32::floor(st[1]) as i32) % 2 == 0 {
                        return self.tex1.evaluate(si);
                    } else {
                        return self.tex2.evaluate(si);
                    }
                }

                // Apply box filter to checkerboard region
                fn bump_int(x: f32) -> i32 {
                    return (f32::floor(x / 2.0) +
                            2.0 * f32::max(x / 2.0 - f32::floor(x / 2.0) - 0.5, 0.0)) as
                           i32;
                }
                let sint = (bump_int(s1) - bump_int(s0)) as f32 / (2.0 * ds);
                let tint = (bump_int(t1) - bump_int(t0)) as f32 / (2.0 * dt);
                let mut area2 = sint + tint - 2.0 * sint * tint;
                if ds > 1.0 || dt > 1.0 {
                    area2 = 0.5
                };
                return self.tex1.evaluate(si) * (1.0 - area2) + self.tex2.evaluate(si) * area2;
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Macros to define CSS properties.

pub trait Property<T> {
    fn inherits_automatically() -> bool;
    fn compute(&self, _: &T) -> Self;
}

/// Generates a property definition that simply parses strings to enum variants
/// or to a tuple struct of the given type.
///
/// For example, the SVG spec defines the `stroke-linejoin` property
/// to have possible values `miter | round | bevel | inherit`, with a default
/// of `miter`.  We can define the property like this:
///
/// ```ignore
/// make_property!(
/// StrokeLinejoin,
/// default: Miter,
///
/// "miter" => Miter,
/// "round" => Round,
/// "bevel" => Bevel,
/// );
/// ```
///
/// The macro will generate a `StrokeLinejoin` enum with the provided
/// variants.  It will generate an `impl Default for StrokeLinejoin`
/// with the provided `default:` value.  Finally, it will generate an
/// `impl Parse for StrokeLinejoin`, from `parsers::Parse`, with
/// `type Err = ValueErrorKind`.
#[macro_export]
macro_rules! make_property {
    ($computed_values_type: ty,
     $name: ident,
     default: $default: ident,
     inherits_automatically: $inherits_automatically: expr,
     identifiers:
     $($str_prop: expr => $variant: ident,)+
    ) => {
        #[derive(Debug, Copy, Clone, PartialEq)]
        #[repr(C)]
        pub enum $name {
            $($variant),+
        }

        impl_default!($name, $name::$default);
        impl_property!($computed_values_type, $name, $inherits_automatically);

        impl crate::parsers::Parse for $name {
            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, crate::error::ParseError<'i>> {
                Ok(parse_identifiers!(
                    parser,
                    $($str_prop => $name::$variant,)+
                )?)
            }
        }
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     inherits_automatically: $inherits_automatically: expr,
     newtype_parse: $type: ty,
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));
        impl_property!($computed_values_type, $name, $inherits_automatically);

        impl crate::parsers::Parse for $name {
            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, crate::error::ParseError<'i>> {
                Ok($name(<$type as crate::parsers::Parse>::parse(parser)?))
            }
        }
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     newtype_parse: $type: ty,
     property_impl: { $prop: item }
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));

        $prop

        impl crate::parsers::Parse for $name {
            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, crate::error::ParseError<'i>> {
                Ok($name(<$type as crate::parsers::Parse>::parse(parser)?))
            }
        }
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     property_impl: { $prop: item }
    ) => {
        impl_default!($name, $default);

        $prop
    };

    // pending - only BaselineShift
    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     newtype: $type: ty,
     property_impl: { $prop: item },
     parse_impl: { $parse: item }
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));

        $prop

        $parse
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     inherits_automatically: $inherits_automatically: expr,
     newtype: $type: ty,
     parse_impl: { $parse: item },
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));
        impl_property!($computed_values_type, $name, $inherits_automatically);

        $parse
    };

    ($computed_values_type: ty,
     $name: ident,
     inherits_automatically: $inherits_automatically: expr,
     fields: {
       $($field_name: ident : $field_type: ty, default: $field_default : expr,)+
     }
     parse_impl: { $parse: item }
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name {
            $(pub $field_name: $field_type),+
        }

        impl_default!($name, $name { $($field_name: $field_default),+ });
        impl_property!($computed_values_type, $name, $inherits_automatically);

        $parse
    };
}

macro_rules! impl_default {
    ($name:ident, $default:expr) => {
        impl Default for $name {
            fn default() -> $name {
                $default
            }
        }
    };
}

macro_rules! impl_property {
    ($computed_values_type:ty, $name:ident, $inherits_automatically:expr) => {
        impl crate::property_macros::Property<$computed_values_type> for $name {
            fn inherits_automatically() -> bool {
                $inherits_automatically
            }

            fn compute(&self, _v: &$computed_values_type) -> Self {
                self.clone()
            }
        }
    };
}

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

    use crate::parsers::Parse;
    use cssparser::RGBA;

    #[test]
    fn check_identifiers_property() {
        make_property! {
            (),
            Foo,
            default: Def,
            inherits_automatically: true,

            identifiers:
            "def" => Def,
            "bar" => Bar,
            "baz" => Baz,
        }

        assert_eq!(<Foo as Default>::default(), Foo::Def);
        assert_eq!(<Foo as Property<()>>::inherits_automatically(), true);
        assert!(<Foo as Parse>::parse_str("blargh").is_err());
        assert_eq!(<Foo as Parse>::parse_str("bar"), Ok(Foo::Bar));
    }

    #[test]
    fn check_compute() {
        make_property! {
            RGBA,
            AddColor,
            default: RGBA::new(1, 1, 1, 1),
            newtype_parse: RGBA,
            property_impl: {
                impl Property<RGBA> for AddColor {
                    fn inherits_automatically() -> bool {
                        true
                    }

                    fn compute(&self, v: &RGBA) -> Self {
                        AddColor(RGBA::new(
                            self.0.red + v.red,
                            self.0.green + v.green,
                            self.0.blue + v.blue,
                            self.0.alpha + v.alpha
                        ))
                    }
                }
            }
        }

        let color = RGBA::new(1, 1, 1, 1);
        let a = <AddColor as Parse>::parse_str("#02030405").unwrap();
        let b = a.compute(&color);

        assert_eq!(b, AddColor(RGBA::new(3, 4, 5, 6)));
    }
}
<commit_msg>Remove the unused pattern in make_property!<commit_after>//! Macros to define CSS properties.

pub trait Property<T> {
    fn inherits_automatically() -> bool;
    fn compute(&self, _: &T) -> Self;
}

/// Generates a property definition that simply parses strings to enum variants
/// or to a tuple struct of the given type.
///
/// For example, the SVG spec defines the `stroke-linejoin` property
/// to have possible values `miter | round | bevel | inherit`, with a default
/// of `miter`.  We can define the property like this:
///
/// ```ignore
/// make_property!(
/// StrokeLinejoin,
/// default: Miter,
///
/// "miter" => Miter,
/// "round" => Round,
/// "bevel" => Bevel,
/// );
/// ```
///
/// The macro will generate a `StrokeLinejoin` enum with the provided
/// variants.  It will generate an `impl Default for StrokeLinejoin`
/// with the provided `default:` value.  Finally, it will generate an
/// `impl Parse for StrokeLinejoin`, from `parsers::Parse`, with
/// `type Err = ValueErrorKind`.
#[macro_export]
macro_rules! make_property {
    ($computed_values_type: ty,
     $name: ident,
     default: $default: ident,
     inherits_automatically: $inherits_automatically: expr,
     identifiers:
     $($str_prop: expr => $variant: ident,)+
    ) => {
        #[derive(Debug, Copy, Clone, PartialEq)]
        #[repr(C)]
        pub enum $name {
            $($variant),+
        }

        impl_default!($name, $name::$default);
        impl_property!($computed_values_type, $name, $inherits_automatically);

        impl crate::parsers::Parse for $name {
            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, crate::error::ParseError<'i>> {
                Ok(parse_identifiers!(
                    parser,
                    $($str_prop => $name::$variant,)+
                )?)
            }
        }
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     inherits_automatically: $inherits_automatically: expr,
     newtype_parse: $type: ty,
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));
        impl_property!($computed_values_type, $name, $inherits_automatically);

        impl crate::parsers::Parse for $name {
            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, crate::error::ParseError<'i>> {
                Ok($name(<$type as crate::parsers::Parse>::parse(parser)?))
            }
        }
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     property_impl: { $prop: item }
    ) => {
        impl_default!($name, $default);

        $prop
    };

    // pending - only BaselineShift
    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     newtype: $type: ty,
     property_impl: { $prop: item },
     parse_impl: { $parse: item }
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));

        $prop

        $parse
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     inherits_automatically: $inherits_automatically: expr,
     newtype: $type: ty,
     parse_impl: { $parse: item },
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));
        impl_property!($computed_values_type, $name, $inherits_automatically);

        $parse
    };

    ($computed_values_type: ty,
     $name: ident,
     inherits_automatically: $inherits_automatically: expr,
     fields: {
       $($field_name: ident : $field_type: ty, default: $field_default : expr,)+
     }
     parse_impl: { $parse: item }
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name {
            $(pub $field_name: $field_type),+
        }

        impl_default!($name, $name { $($field_name: $field_default),+ });
        impl_property!($computed_values_type, $name, $inherits_automatically);

        $parse
    };
}

macro_rules! impl_default {
    ($name:ident, $default:expr) => {
        impl Default for $name {
            fn default() -> $name {
                $default
            }
        }
    };
}

macro_rules! impl_property {
    ($computed_values_type:ty, $name:ident, $inherits_automatically:expr) => {
        impl crate::property_macros::Property<$computed_values_type> for $name {
            fn inherits_automatically() -> bool {
                $inherits_automatically
            }

            fn compute(&self, _v: &$computed_values_type) -> Self {
                self.clone()
            }
        }
    };
}

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

    use crate::parsers::Parse;

    #[test]
    fn check_identifiers_property() {
        make_property! {
            (),
            Foo,
            default: Def,
            inherits_automatically: true,

            identifiers:
            "def" => Def,
            "bar" => Bar,
            "baz" => Baz,
        }

        assert_eq!(<Foo as Default>::default(), Foo::Def);
        assert_eq!(<Foo as Property<()>>::inherits_automatically(), true);
        assert!(<Foo as Parse>::parse_str("blargh").is_err());
        assert_eq!(<Foo as Parse>::parse_str("bar"), Ok(Foo::Bar));
    }
}
<|endoftext|>


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

// ----------------

// This program exercises the Rust Deflate decoder at
// https://github.com/alexcrichton/flate2-rs
// which is the top result for https://crates.io/search?q=flate&sort=downloads
//
// Wuffs' C code doesn't depend on Rust per se, but this program gives some
// performance data for specific Rust Deflate implementations. The equivalent
// Wuffs benchmarks (on the same test images) are run via:
//
// wuffs bench std/deflate
//
// To run this program, do "cargo run --release" from the parent directory (the
// directory containing the Cargo.toml file).

extern crate flate2;
extern crate rustc_version_runtime;

use std::io::Read;
use std::time::Instant;

const ITERSCALE: u64 = 20;
const REPS: u64 = 5;

fn main() {
    let version = rustc_version_runtime::version();
    print!(
        "# Rust {}.{}.{}\n",
        version.major,
        version.minor,
        version.patch
    );
    print!("#\n");
    print!("# The output format, including the \"Benchmark\" prefixes, is compatible with the\n");
    print!("# https://godoc.org/golang.org/x/perf/cmd/benchstat tool. To install it, first\n");
    print!("# install Go, then run \"go get golang.org/x/perf/cmd/benchstat\".\n");

    let mut dst = vec![0u8; 64 * 1024 * 1024];

    // The various magic constants below are copied from test/c/std/deflate.c
    for i in 0..(1 + REPS) {
        bench(
            "1k",
            &mut dst[..],
            &include_bytes!("../../../test/data/romeo.txt.gz")[20..550],
            i == 0, // warm_up
            942, // want_num_bytes
            2000, // iters_unscaled
        );

        bench(
            "10k",
            &mut dst[..],
            &include_bytes!("../../../test/data/midsummer.txt.gz")[24..5166],
            i == 0, // warm_up
            11065, // want_num_bytes
            300, // iters_unscaled
        );

        bench(
            "100k",
            &mut dst[..],
            &include_bytes!("../../../test/data/pi.txt.gz")[17..48335],
            i == 0, // warm_up
            100003, // want_num_bytes
            30, // iters_unscaled
        );
    }
}

fn bench(
    name: &str, // Benchmark name.
    dst: &mut [u8], // Destination buffer.
    src: &[u8], // Source data.
    warm_up: bool, // Whether this is a warm up rep.
    want_num_bytes: u64, // Expected num_bytes per iteration.
    iters_unscaled: u64, // Base number of iterations.
) {
    let iters = iters_unscaled * ITERSCALE;
    let mut total_num_bytes = 0u64;

    let start = Instant::now();
    for _ in 0..iters {
        let n = decode(&mut dst[..], src);
        if n != want_num_bytes {
            panic!("num_bytes: got {}, want {}", n, want_num_bytes);
        }
        total_num_bytes += n;
    }
    let elapsed = start.elapsed();

    let elapsed_nanos = (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64);
    let kb_per_s: u64 = total_num_bytes * 1_000_000 / elapsed_nanos;

    if warm_up {
        return;
    }

    print!(
        "Benchmarkrust_deflate_decode_{:16}   {:8}   {:12} ns/op   {:3}.{:03} MB/s\n",
        name,
        iters,
        elapsed_nanos / iters,
        kb_per_s / 1_000,
        kb_per_s % 1_000
    );
}

// decode returns the number of bytes processed.
fn decode(dst: &mut [u8], src: &[u8]) -> u64 {
    let mut num_bytes = 0u64;
    let mut decoder = flate2::read::DeflateDecoder::new(src);
    loop {
        let n = decoder.read(dst).unwrap();
        if n == 0 {
            break;
        }
        num_bytes += n as u64;
    }
    num_bytes
}
<commit_msg>Fix script/bench-rust-deflate typo<commit_after>// Copyright 2019 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// ----------------

// This program exercises the Rust Deflate decoder at
// https://github.com/alexcrichton/flate2-rs
// which is the top result for https://crates.io/search?q=flate&sort=downloads
//
// Wuffs' C code doesn't depend on Rust per se, but this program gives some
// performance data for specific Rust Deflate implementations. The equivalent
// Wuffs benchmarks (on the same test files) are run via:
//
// wuffs bench std/deflate
//
// To run this program, do "cargo run --release" from the parent directory (the
// directory containing the Cargo.toml file).

extern crate flate2;
extern crate rustc_version_runtime;

use std::io::Read;
use std::time::Instant;

const ITERSCALE: u64 = 20;
const REPS: u64 = 5;

fn main() {
    let version = rustc_version_runtime::version();
    print!(
        "# Rust {}.{}.{}\n",
        version.major,
        version.minor,
        version.patch
    );
    print!("#\n");
    print!("# The output format, including the \"Benchmark\" prefixes, is compatible with the\n");
    print!("# https://godoc.org/golang.org/x/perf/cmd/benchstat tool. To install it, first\n");
    print!("# install Go, then run \"go get golang.org/x/perf/cmd/benchstat\".\n");

    let mut dst = vec![0u8; 64 * 1024 * 1024];

    // The various magic constants below are copied from test/c/std/deflate.c
    for i in 0..(1 + REPS) {
        bench(
            "1k",
            &mut dst[..],
            &include_bytes!("../../../test/data/romeo.txt.gz")[20..550],
            i == 0, // warm_up
            942, // want_num_bytes
            2000, // iters_unscaled
        );

        bench(
            "10k",
            &mut dst[..],
            &include_bytes!("../../../test/data/midsummer.txt.gz")[24..5166],
            i == 0, // warm_up
            11065, // want_num_bytes
            300, // iters_unscaled
        );

        bench(
            "100k",
            &mut dst[..],
            &include_bytes!("../../../test/data/pi.txt.gz")[17..48335],
            i == 0, // warm_up
            100003, // want_num_bytes
            30, // iters_unscaled
        );
    }
}

fn bench(
    name: &str, // Benchmark name.
    dst: &mut [u8], // Destination buffer.
    src: &[u8], // Source data.
    warm_up: bool, // Whether this is a warm up rep.
    want_num_bytes: u64, // Expected num_bytes per iteration.
    iters_unscaled: u64, // Base number of iterations.
) {
    let iters = iters_unscaled * ITERSCALE;
    let mut total_num_bytes = 0u64;

    let start = Instant::now();
    for _ in 0..iters {
        let n = decode(&mut dst[..], src);
        if n != want_num_bytes {
            panic!("num_bytes: got {}, want {}", n, want_num_bytes);
        }
        total_num_bytes += n;
    }
    let elapsed = start.elapsed();

    let elapsed_nanos = (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64);
    let kb_per_s: u64 = total_num_bytes * 1_000_000 / elapsed_nanos;

    if warm_up {
        return;
    }

    print!(
        "Benchmarkrust_deflate_decode_{:16}   {:8}   {:12} ns/op   {:3}.{:03} MB/s\n",
        name,
        iters,
        elapsed_nanos / iters,
        kb_per_s / 1_000,
        kb_per_s % 1_000
    );
}

// decode returns the number of bytes processed.
fn decode(dst: &mut [u8], src: &[u8]) -> u64 {
    let mut num_bytes = 0u64;
    let mut decoder = flate2::read::DeflateDecoder::new(src);
    loop {
        let n = decoder.read(dst).unwrap();
        if n == 0 {
            break;
        }
        num_bytes += n as u64;
    }
    num_bytes
}
<|endoftext|>


<commit_before>extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};

fn get_named_field_idents<'a>(struct_data: &'a syn::DataStruct) -> Vec<&'a syn::Ident> {
    struct_data
        .fields
        .iter()
        .map(|f| match &f.ident {
            Some(ref ident) => ident,
            _ => panic!("ssz_derive only supports named struct fields."),
        })
        .collect()
}

#[proc_macro_derive(Encode)]
pub fn ssz_encode_derive(input: TokenStream) -> TokenStream {
    let item = parse_macro_input!(input as DeriveInput);

    let name = &item.ident;

    let struct_data = match &item.data {
        syn::Data::Struct(s) => s,
        _ => panic!("ssz_derive only supports structs."),
    };

    let field_idents = get_named_field_idents(&struct_data);

    let output = quote! {
        impl Encodable for #name {
            fn ssz_append(&self, s: &mut SszStream) {
                #(
                    s.append(&self.#field_idents);
                )*
            }
        }
    };
    output.into()
}

#[proc_macro_derive(Decode)]
pub fn ssz_decode_derive(input: TokenStream) -> TokenStream {
    let item = parse_macro_input!(input as DeriveInput);

    let name = &item.ident;

    let struct_data = match &item.data {
        syn::Data::Struct(s) => s,
        _ => panic!("ssz_derive only supports structs."),
    };

    let field_idents = get_named_field_idents(&struct_data);

    // Using a var in an iteration always consumes the var, therefore we must make a `fields_a` and
    // a `fields_b` in order to perform two loops.
    //
    // https://github.com/dtolnay/quote/issues/8
    let field_idents_a = &field_idents;
    let field_idents_b = &field_idents;

    let output = quote! {
        impl Decodable for #name {
            fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
                #(
                    let (#field_idents_a, i) = <_>::ssz_decode(bytes, i)?;
                )*

                Ok((
                    Self {
                        #(
                            #field_idents_b,
                        )*
                    },
                    i
                ))
            }
        }
    };
    output.into()
}
<commit_msg>Add docs to ssz_derive<commit_after>//! Provides the following procedural derive macros:
//!
//! - `#[derive(Encode)]`
//! - `#[derive(Decode)]`
//!
//! These macros provide SSZ encoding/decoding for a `struct`. Fields are encoded/decoded in the
//! order they are defined.
//!
//! Presently, only `structs` with named fields are supported. `enum`s and tuple-structs are
//! unsupported.
//!
//! Example:
//! ```
//! use ssz::{ssz_encode, Decodable, Encodable};
//!
//! #[derive(Encodable, Decodable)]
//! struct Foo {
//!     bar: bool,
//!     baz: u64,
//! }
//!
//! fn main() {
//!     let foo = Foo {
//!         bar: true,
//!         baz: 42,
//!     };
//!
//!     let bytes = ssz_encode(&foo);
//!
//!     let decoded_foo = Foo::ssz_decode(bytes, 0).unwrap();
//!
//!     assert_eq!(foo.baz, decoded_foo.baz);
//! }
//! ```

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};

fn get_named_field_idents<'a>(struct_data: &'a syn::DataStruct) -> Vec<&'a syn::Ident> {
    struct_data
        .fields
        .iter()
        .map(|f| match &f.ident {
            Some(ref ident) => ident,
            _ => panic!("ssz_derive only supports named struct fields."),
        })
        .collect()
}

/// Implements `ssz::Encodable` on some `struct`.
///
/// Fields are encoded in the order they are defined.
#[proc_macro_derive(Encode)]
pub fn ssz_encode_derive(input: TokenStream) -> TokenStream {
    let item = parse_macro_input!(input as DeriveInput);

    let name = &item.ident;

    let struct_data = match &item.data {
        syn::Data::Struct(s) => s,
        _ => panic!("ssz_derive only supports structs."),
    };

    let field_idents = get_named_field_idents(&struct_data);

    let output = quote! {
        impl Encodable for #name {
            fn ssz_append(&self, s: &mut SszStream) {
                #(
                    s.append(&self.#field_idents);
                )*
            }
        }
    };
    output.into()
}

/// Implements `ssz::Decodable` on some `struct`.
///
/// Fields are decoded in the order they are defined.
#[proc_macro_derive(Decode)]
pub fn ssz_decode_derive(input: TokenStream) -> TokenStream {
    let item = parse_macro_input!(input as DeriveInput);

    let name = &item.ident;

    let struct_data = match &item.data {
        syn::Data::Struct(s) => s,
        _ => panic!("ssz_derive only supports structs."),
    };

    let field_idents = get_named_field_idents(&struct_data);

    // Using a var in an iteration always consumes the var, therefore we must make a `fields_a` and
    // a `fields_b` in order to perform two loops.
    //
    // https://github.com/dtolnay/quote/issues/8
    let field_idents_a = &field_idents;
    let field_idents_b = &field_idents;

    let output = quote! {
        impl Decodable for #name {
            fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
                #(
                    let (#field_idents_a, i) = <_>::ssz_decode(bytes, i)?;
                )*

                Ok((
                    Self {
                        #(
                            #field_idents_b,
                        )*
                    },
                    i
                ))
            }
        }
    };
    output.into()
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "deny-warnings", deny(warnings))]

use clap::{App, Arg, SubCommand};
use clippy_dev::*;
use std::path::Path;

mod fmt;
mod new_lint;
mod stderr_length_check;

#[derive(PartialEq)]
enum UpdateMode {
    Check,
    Change,
}

fn main() {
    let matches = App::new("Clippy developer tooling")
        .subcommand(
            SubCommand::with_name("fmt")
                .about("Run rustfmt on all projects and tests")
                .arg(
                    Arg::with_name("check")
                        .long("check")
                        .help("Use the rustfmt --check option"),
                )
                .arg(
                    Arg::with_name("verbose")
                        .short("v")
                        .long("verbose")
                        .help("Echo commands run"),
                ),
        )
        .subcommand(
            SubCommand::with_name("update_lints")
                .about("Updates lint registration and information from the source code")
                .long_about(
                    "Makes sure that:\n \
                     * the lint count in README.md is correct\n \
                     * the changelog contains markdown link references at the bottom\n \
                     * all lint groups include the correct lints\n \
                     * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
                     * all lints are registered in the lint store",
                )
                .arg(Arg::with_name("print-only").long("print-only").help(
                    "Print a table of lints to STDOUT. \
                     This does not include deprecated and internal lints. \
                     (Does not modify any files)",
                ))
                .arg(
                    Arg::with_name("check")
                        .long("check")
                        .help("Checks that `cargo dev update_lints` has been run. Used on CI."),
                ),
        )
        .subcommand(
            SubCommand::with_name("new_lint")
                .about("Create new lint and run `cargo dev update_lints`")
                .arg(
                    Arg::with_name("pass")
                        .short("p")
                        .long("pass")
                        .help("Specify whether the lint runs during the early or late pass")
                        .takes_value(true)
                        .possible_values(&["early", "late"])
                        .required(true),
                )
                .arg(
                    Arg::with_name("name")
                        .short("n")
                        .long("name")
                        .help("Name of the new lint in snake case, ex: fn_too_long")
                        .takes_value(true)
                        .required(true),
                )
                .arg(
                    Arg::with_name("category")
                        .short("c")
                        .long("category")
                        .help("What category the lint belongs to")
                        .default_value("nursery")
                        .possible_values(&[
                            "style",
                            "correctness",
                            "complexity",
                            "perf",
                            "pedantic",
                            "restriction",
                            "cargo",
                            "nursery",
                            "internal",
                            "internal_warn",
                        ])
                        .takes_value(true),
                ),
        )
        .arg(
            Arg::with_name("limit-stderr-length")
                .long("limit-stderr-length")
                .help("Ensures that stderr files do not grow longer than a certain amount of lines."),
        )
        .get_matches();

    if matches.is_present("limit-stderr-length") {
        stderr_length_check::check();
    }

    match matches.subcommand() {
        ("fmt", Some(matches)) => {
            fmt::run(matches.is_present("check"), matches.is_present("verbose"));
        },
        ("update_lints", Some(matches)) => {
            if matches.is_present("print-only") {
                print_lints();
            } else if matches.is_present("check") {
                update_lints(&UpdateMode::Check);
            } else {
                update_lints(&UpdateMode::Change);
            }
        },
        ("new_lint", Some(matches)) => {
            match new_lint::create(
                matches.value_of("pass"),
                matches.value_of("name"),
                matches.value_of("category"),
            ) {
                Ok(_) => update_lints(&UpdateMode::Change),
                Err(e) => eprintln!("Unable to create lint: {}", e),
            }
        },
        _ => {},
    }
}

fn print_lints() {
    let lint_list = gather_all();
    let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list).collect();
    let lint_count = usable_lints.len();
    let grouped_by_lint_group = Lint::by_lint_group(&usable_lints);

    for (lint_group, mut lints) in grouped_by_lint_group {
        if lint_group == "Deprecated" {
            continue;
        }
        println!("\n## {}", lint_group);

        lints.sort_by_key(|l| l.name.clone());

        for lint in lints {
            println!(
                "* [{}]({}#{}) ({})",
                lint.name,
                clippy_dev::DOCS_LINK.clone(),
                lint.name,
                lint.desc
            );
        }
    }

    println!("there are {} lints", lint_count);
}

#[allow(clippy::too_many_lines)]
fn update_lints(update_mode: &UpdateMode) {
    let lint_list: Vec<Lint> = gather_all().collect();

    let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect();
    let lint_count = usable_lints.len();

    let mut sorted_usable_lints = usable_lints.clone();
    sorted_usable_lints.sort_by_key(|lint| lint.name.clone());

    let mut file_change = replace_region_in_file(
        Path::new("src/lintlist/mod.rs"),
        "begin lint list",
        "end lint list",
        false,
        update_mode == &UpdateMode::Change,
        || {
            format!(
                "pub const ALL_LINTS: [Lint; {}] = {:#?};",
                sorted_usable_lints.len(),
                sorted_usable_lints
            )
            .lines()
            .map(ToString::to_string)
            .collect::<Vec<_>>()
        },
    )
    .changed;

    file_change |= replace_region_in_file(
        Path::new("README.md"),
        r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang.github.io/rust-clippy/master/index.html\)"#,
        "",
        true,
        update_mode == &UpdateMode::Change,
        || {
            vec![
                format!("[There are {} lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)", lint_count)
            ]
        }
    ).changed;

    file_change |= replace_region_in_file(
        Path::new("CHANGELOG.md"),
        "<!-- begin autogenerated links to lint list -->",
        "<!-- end autogenerated links to lint list -->",
        false,
        update_mode == &UpdateMode::Change,
        || gen_changelog_lint_list(lint_list.clone()),
    )
    .changed;

    file_change |= replace_region_in_file(
        Path::new("clippy_lints/src/lib.rs"),
        "begin deprecated lints",
        "end deprecated lints",
        false,
        update_mode == &UpdateMode::Change,
        || gen_deprecated(&lint_list),
    )
    .changed;

    file_change |= replace_region_in_file(
        Path::new("clippy_lints/src/lib.rs"),
        "begin register lints",
        "end register lints",
        false,
        update_mode == &UpdateMode::Change,
        || gen_register_lint_list(&lint_list),
    )
    .changed;

    file_change |= replace_region_in_file(
        Path::new("clippy_lints/src/lib.rs"),
        "begin lints modules",
        "end lints modules",
        false,
        update_mode == &UpdateMode::Change,
        || gen_modules_list(lint_list.clone()),
    )
    .changed;

    // Generate lists of lints in the clippy::all lint group
    file_change |= replace_region_in_file(
        Path::new("clippy_lints/src/lib.rs"),
        r#"store.register_group\(true, "clippy::all""#,
        r#"\]\);"#,
        false,
        update_mode == &UpdateMode::Change,
        || {
            // clippy::all should only include the following lint groups:
            let all_group_lints = usable_lints
                .clone()
                .into_iter()
                .filter(|l| {
                    l.group == "correctness" || l.group == "style" || l.group == "complexity" || l.group == "perf"
                })
                .collect();

            gen_lint_group_list(all_group_lints)
        },
    )
    .changed;

    // Generate the list of lints for all other lint groups
    for (lint_group, lints) in Lint::by_lint_group(&usable_lints) {
        file_change |= replace_region_in_file(
            Path::new("clippy_lints/src/lib.rs"),
            &format!("store.register_group\\(true, \"clippy::{}\"", lint_group),
            r#"\]\);"#,
            false,
            update_mode == &UpdateMode::Change,
            || gen_lint_group_list(lints.clone()),
        )
        .changed;
    }

    if update_mode == &UpdateMode::Check && file_change {
        println!(
            "Not all lints defined properly. \
             Please run `cargo dev update_lints` to make sure all lints are defined properly."
        );
        std::process::exit(1);
    }
}
<commit_msg>dev: Make UpdateMode a copy type<commit_after>#![cfg_attr(feature = "deny-warnings", deny(warnings))]

use clap::{App, Arg, SubCommand};
use clippy_dev::*;
use std::path::Path;

mod fmt;
mod new_lint;
mod stderr_length_check;

#[derive(Clone, Copy, PartialEq)]
enum UpdateMode {
    Check,
    Change,
}

fn main() {
    let matches = App::new("Clippy developer tooling")
        .subcommand(
            SubCommand::with_name("fmt")
                .about("Run rustfmt on all projects and tests")
                .arg(
                    Arg::with_name("check")
                        .long("check")
                        .help("Use the rustfmt --check option"),
                )
                .arg(
                    Arg::with_name("verbose")
                        .short("v")
                        .long("verbose")
                        .help("Echo commands run"),
                ),
        )
        .subcommand(
            SubCommand::with_name("update_lints")
                .about("Updates lint registration and information from the source code")
                .long_about(
                    "Makes sure that:\n \
                     * the lint count in README.md is correct\n \
                     * the changelog contains markdown link references at the bottom\n \
                     * all lint groups include the correct lints\n \
                     * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
                     * all lints are registered in the lint store",
                )
                .arg(Arg::with_name("print-only").long("print-only").help(
                    "Print a table of lints to STDOUT. \
                     This does not include deprecated and internal lints. \
                     (Does not modify any files)",
                ))
                .arg(
                    Arg::with_name("check")
                        .long("check")
                        .help("Checks that `cargo dev update_lints` has been run. Used on CI."),
                ),
        )
        .subcommand(
            SubCommand::with_name("new_lint")
                .about("Create new lint and run `cargo dev update_lints`")
                .arg(
                    Arg::with_name("pass")
                        .short("p")
                        .long("pass")
                        .help("Specify whether the lint runs during the early or late pass")
                        .takes_value(true)
                        .possible_values(&["early", "late"])
                        .required(true),
                )
                .arg(
                    Arg::with_name("name")
                        .short("n")
                        .long("name")
                        .help("Name of the new lint in snake case, ex: fn_too_long")
                        .takes_value(true)
                        .required(true),
                )
                .arg(
                    Arg::with_name("category")
                        .short("c")
                        .long("category")
                        .help("What category the lint belongs to")
                        .default_value("nursery")
                        .possible_values(&[
                            "style",
                            "correctness",
                            "complexity",
                            "perf",
                            "pedantic",
                            "restriction",
                            "cargo",
                            "nursery",
                            "internal",
                            "internal_warn",
                        ])
                        .takes_value(true),
                ),
        )
        .arg(
            Arg::with_name("limit-stderr-length")
                .long("limit-stderr-length")
                .help("Ensures that stderr files do not grow longer than a certain amount of lines."),
        )
        .get_matches();

    if matches.is_present("limit-stderr-length") {
        stderr_length_check::check();
    }

    match matches.subcommand() {
        ("fmt", Some(matches)) => {
            fmt::run(matches.is_present("check"), matches.is_present("verbose"));
        },
        ("update_lints", Some(matches)) => {
            if matches.is_present("print-only") {
                print_lints();
            } else if matches.is_present("check") {
                update_lints(UpdateMode::Check);
            } else {
                update_lints(UpdateMode::Change);
            }
        },
        ("new_lint", Some(matches)) => {
            match new_lint::create(
                matches.value_of("pass"),
                matches.value_of("name"),
                matches.value_of("category"),
            ) {
                Ok(_) => update_lints(UpdateMode::Change),
                Err(e) => eprintln!("Unable to create lint: {}", e),
            }
        },
        _ => {},
    }
}

fn print_lints() {
    let lint_list = gather_all();
    let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list).collect();
    let lint_count = usable_lints.len();
    let grouped_by_lint_group = Lint::by_lint_group(&usable_lints);

    for (lint_group, mut lints) in grouped_by_lint_group {
        if lint_group == "Deprecated" {
            continue;
        }
        println!("\n## {}", lint_group);

        lints.sort_by_key(|l| l.name.clone());

        for lint in lints {
            println!(
                "* [{}]({}#{}) ({})",
                lint.name,
                clippy_dev::DOCS_LINK.clone(),
                lint.name,
                lint.desc
            );
        }
    }

    println!("there are {} lints", lint_count);
}

#[allow(clippy::too_many_lines)]
fn update_lints(update_mode: UpdateMode) {
    let lint_list: Vec<Lint> = gather_all().collect();

    let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect();
    let lint_count = usable_lints.len();

    let mut sorted_usable_lints = usable_lints.clone();
    sorted_usable_lints.sort_by_key(|lint| lint.name.clone());

    let mut file_change = replace_region_in_file(
        Path::new("src/lintlist/mod.rs"),
        "begin lint list",
        "end lint list",
        false,
        update_mode == UpdateMode::Change,
        || {
            format!(
                "pub const ALL_LINTS: [Lint; {}] = {:#?};",
                sorted_usable_lints.len(),
                sorted_usable_lints
            )
            .lines()
            .map(ToString::to_string)
            .collect::<Vec<_>>()
        },
    )
    .changed;

    file_change |= replace_region_in_file(
        Path::new("README.md"),
        r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang.github.io/rust-clippy/master/index.html\)"#,
        "",
        true,
        update_mode == UpdateMode::Change,
        || {
            vec![
                format!("[There are {} lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)", lint_count)
            ]
        }
    ).changed;

    file_change |= replace_region_in_file(
        Path::new("CHANGELOG.md"),
        "<!-- begin autogenerated links to lint list -->",
        "<!-- end autogenerated links to lint list -->",
        false,
        update_mode == UpdateMode::Change,
        || gen_changelog_lint_list(lint_list.clone()),
    )
    .changed;

    file_change |= replace_region_in_file(
        Path::new("clippy_lints/src/lib.rs"),
        "begin deprecated lints",
        "end deprecated lints",
        false,
        update_mode == UpdateMode::Change,
        || gen_deprecated(&lint_list),
    )
    .changed;

    file_change |= replace_region_in_file(
        Path::new("clippy_lints/src/lib.rs"),
        "begin register lints",
        "end register lints",
        false,
        update_mode == UpdateMode::Change,
        || gen_register_lint_list(&lint_list),
    )
    .changed;

    file_change |= replace_region_in_file(
        Path::new("clippy_lints/src/lib.rs"),
        "begin lints modules",
        "end lints modules",
        false,
        update_mode == UpdateMode::Change,
        || gen_modules_list(lint_list.clone()),
    )
    .changed;

    // Generate lists of lints in the clippy::all lint group
    file_change |= replace_region_in_file(
        Path::new("clippy_lints/src/lib.rs"),
        r#"store.register_group\(true, "clippy::all""#,
        r#"\]\);"#,
        false,
        update_mode == UpdateMode::Change,
        || {
            // clippy::all should only include the following lint groups:
            let all_group_lints = usable_lints
                .clone()
                .into_iter()
                .filter(|l| {
                    l.group == "correctness" || l.group == "style" || l.group == "complexity" || l.group == "perf"
                })
                .collect();

            gen_lint_group_list(all_group_lints)
        },
    )
    .changed;

    // Generate the list of lints for all other lint groups
    for (lint_group, lints) in Lint::by_lint_group(&usable_lints) {
        file_change |= replace_region_in_file(
            Path::new("clippy_lints/src/lib.rs"),
            &format!("store.register_group\\(true, \"clippy::{}\"", lint_group),
            r#"\]\);"#,
            false,
            update_mode == UpdateMode::Change,
            || gen_lint_group_list(lints.clone()),
        )
        .changed;
    }

    if update_mode == UpdateMode::Check && file_change {
        println!(
            "Not all lints defined properly. \
             Please run `cargo dev update_lints` to make sure all lints are defined properly."
        );
        std::process::exit(1);
    }
}
<|endoftext|>