<commit_before>#![allow(missing_docs, nonstandard_style)]

use crate::ffi::{OsStr, OsString};
use crate::io::ErrorKind;
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
use crate::path::PathBuf;
use crate::time::Duration;

pub use self::rand::hashmap_random_keys;
pub use libc::strlen;

#[macro_use]
pub mod compat;

pub mod alloc;
pub mod args;
pub mod c;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod fs;
pub mod handle;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod thread;
pub mod thread_local_dtor;
pub mod thread_local_key;
pub mod thread_parker;
pub mod time;
cfg_if::cfg_if! {
    if #[cfg(not(target_vendor = "uwp"))] {
        pub mod stdio;
        pub mod stack_overflow;
    } else {
        pub mod stdio_uwp;
        pub mod stack_overflow_uwp;
        pub use self::stdio_uwp as stdio;
        pub use self::stack_overflow_uwp as stack_overflow;
    }
}

// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
    stack_overflow::init();
}

// SAFETY: must be called only once during runtime cleanup.
// NOTE: this is not guaranteed to run, for example when the program aborts.
pub unsafe fn cleanup() {
    net::cleanup();
}

pub fn decode_error_kind(errno: i32) -> ErrorKind {
    use ErrorKind::*;

    match errno as c::DWORD {
        c::ERROR_ACCESS_DENIED => return PermissionDenied,
        c::ERROR_ALREADY_EXISTS => return AlreadyExists,
        c::ERROR_FILE_EXISTS => return AlreadyExists,
        c::ERROR_BROKEN_PIPE => return BrokenPipe,
        c::ERROR_FILE_NOT_FOUND => return NotFound,
        c::ERROR_PATH_NOT_FOUND => return NotFound,
        c::ERROR_NO_DATA => return BrokenPipe,
        c::ERROR_INVALID_PARAMETER => return InvalidInput,
        c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory,
        c::ERROR_SEM_TIMEOUT
        | c::WAIT_TIMEOUT
        | c::ERROR_DRIVER_CANCEL_TIMEOUT
        | c::ERROR_OPERATION_ABORTED
        | c::ERROR_SERVICE_REQUEST_TIMEOUT
        | c::ERROR_COUNTER_TIMEOUT
        | c::ERROR_TIMEOUT
        | c::ERROR_RESOURCE_CALL_TIMED_OUT
        | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT
        | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT
        | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT
        | c::ERROR_DS_TIMELIMIT_EXCEEDED
        | c::DNS_ERROR_RECORD_TIMED_OUT
        | c::ERROR_IPSEC_IKE_TIMED_OUT
        | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT
        | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return TimedOut,
        c::ERROR_CALL_NOT_IMPLEMENTED => return Unsupported,
        c::ERROR_HOST_UNREACHABLE => return HostUnreachable,
        c::ERROR_NETWORK_UNREACHABLE => return NetworkUnreachable,
        c::ERROR_DIRECTORY => return NotADirectory,
        c::ERROR_DIRECTORY_NOT_SUPPORTED => return IsADirectory,
        c::ERROR_DIR_NOT_EMPTY => return DirectoryNotEmpty,
        c::ERROR_WRITE_PROTECT => return ReadOnlyFilesystem,
        c::ERROR_DISK_FULL
        | c::ERROR_HANDLE_DISK_FULL => return StorageFull,
        c::ERROR_SEEK_ON_DEVICE => return NotSeekable,
        c::ERROR_DISK_QUOTA_EXCEEDED => return FilesystemQuotaExceeded,
        c::ERROR_FILE_TOO_LARGE => return FileTooLarge,
        c::ERROR_BUSY => return ResourceBusy,
        c::ERROR_POSSIBLE_DEADLOCK => return Deadlock,
        c::ERROR_NOT_SAME_DEVICE => return CrossesDevices,
        c::ERROR_TOO_MANY_LINKS => return TooManyLinks,
        c::ERROR_FILENAME_EXCED_RANGE => return FilenameTooLong,
        _ => {}
    }

    match errno {
        c::WSAEACCES => PermissionDenied,
        c::WSAEADDRINUSE => AddrInUse,
        c::WSAEADDRNOTAVAIL => AddrNotAvailable,
        c::WSAECONNABORTED => ConnectionAborted,
        c::WSAECONNREFUSED => ConnectionRefused,
        c::WSAECONNRESET => ConnectionReset,
        c::WSAEINVAL => InvalidInput,
        c::WSAENOTCONN => NotConnected,
        c::WSAEWOULDBLOCK => WouldBlock,
        c::WSAETIMEDOUT => TimedOut,
        c::WSAEHOSTUNREACH => HostUnreachable,
        c::WSAENETDOWN => NetworkDown,
        c::WSAENETUNREACH => NetworkUnreachable,

        _ => Uncategorized,
    }
}

pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
    let ptr = haystack.as_ptr();
    let mut start = &haystack[..];

    // For performance reasons unfold the loop eight times.
    while start.len() >= 8 {
        macro_rules! if_return {
            ($($n:literal,)+) => {
                $(
                    if start[$n] == needle {
                        return Some((&start[$n] as *const u16 as usize - ptr as usize) / 2);
                    }
                )+
            }
        }

        if_return!(0, 1, 2, 3, 4, 5, 6, 7,);

        start = &start[8..];
    }

    for c in start {
        if *c == needle {
            return Some((c as *const u16 as usize - ptr as usize) / 2);
        }
    }
    None
}

pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> {
    fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
        let mut maybe_result: Vec<u16> = s.encode_wide().collect();
        if unrolled_find_u16s(0, &maybe_result).is_some() {
            return Err(crate::io::Error::new_const(
                ErrorKind::InvalidInput,
                &"strings passed to WinAPI cannot contain NULs",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }
    inner(s.as_ref())
}

// Many Windows APIs follow a pattern of where we hand a buffer and then they
// will report back to us how large the buffer should be or how many bytes
// currently reside in the buffer. This function is an abstraction over these
// functions by making them easier to call.
//
// The first callback, `f1`, is yielded a (pointer, len) pair which can be
// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case).
// The closure is expected to return what the syscall returns which will be
// interpreted by this function to determine if the syscall needs to be invoked
// again (with more buffer space).
//
// Once the syscall has completed (errors bail out early) the second closure is
// yielded the data which has been read from the syscall. The return value
// from this closure is then the return value of the function.
fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> crate::io::Result<T>
where
    F1: FnMut(*mut u16, c::DWORD) -> c::DWORD,
    F2: FnOnce(&[u16]) -> T,
{
    // Start off with a stack buf but then spill over to the heap if we end up
    // needing more space.
    let mut stack_buf = [0u16; 512];
    let mut heap_buf = Vec::new();
    unsafe {
        let mut n = stack_buf.len();
        loop {
            let buf = if n <= stack_buf.len() {
                &mut stack_buf[..]
            } else {
                let extra = n - heap_buf.len();
                heap_buf.reserve(extra);
                heap_buf.set_len(n);
                &mut heap_buf[..]
            };

            // This function is typically called on windows API functions which
            // will return the correct length of the string, but these functions
            // also return the `0` on error. In some cases, however, the
            // returned "correct length" may actually be 0!
            //
            // To handle this case we call `SetLastError` to reset it to 0 and
            // then check it again if we get the "0 error value". If the "last
            // error" is still 0 then we interpret it as a 0 length buffer and
            // not an actual error.
            c::SetLastError(0);
            let k = match f1(buf.as_mut_ptr(), n as c::DWORD) {
                0 if c::GetLastError() == 0 => 0,
                0 => return Err(crate::io::Error::last_os_error()),
                n => n,
            } as usize;
            if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
                n *= 2;
            } else if k >= n {
                n = k;
            } else {
                return Ok(f2(&buf[..k]));
            }
        }
    }
}

fn os2path(s: &[u16]) -> PathBuf {
    PathBuf::from(OsString::from_wide(s))
}

pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] {
    match unrolled_find_u16s(0, v) {
        // don't include the 0
        Some(i) => &v[..i],
        None => v,
    }
}

pub trait IsZero {
    fn is_zero(&self) -> bool;
}

macro_rules! impl_is_zero {
    ($($t:ident)*) => ($(impl IsZero for $t {
        fn is_zero(&self) -> bool {
            *self == 0
        }
    })*)
}

impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }

pub fn cvt<I: IsZero>(i: I) -> crate::io::Result<I> {
    if i.is_zero() { Err(crate::io::Error::last_os_error()) } else { Ok(i) }
}

pub fn dur2timeout(dur: Duration) -> c::DWORD {
    // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
    // timeouts in windows APIs are typically u32 milliseconds. To translate, we
    // have two pieces to take care of:
    //
    // * Nanosecond precision is rounded up
    // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE
    //   (never time out).
    dur.as_secs()
        .checked_mul(1000)
        .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000))
        .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 }))
        .map(|ms| if ms > <c::DWORD>::MAX as u64 { c::INFINITE } else { ms as c::DWORD })
        .unwrap_or(c::INFINITE)
}

/// Use `__fastfail` to abort the process
///
/// This is the same implementation as in libpanic_abort's `__rust_start_panic`. See
/// that function for more information on `__fastfail`
#[allow(unreachable_code)]
pub fn abort_internal() -> ! {
    const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
    unsafe {
        cfg_if::cfg_if! {
            if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
                asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
                crate::intrinsics::unreachable();
            } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
                asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
                crate::intrinsics::unreachable();
            } else if #[cfg(target_arch = "aarch64")] {
                asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
                crate::intrinsics::unreachable();
            }
        }
    }
    crate::intrinsics::abort();
}
<commit_msg>ErrorKind: Windows: Fix tidy<commit_after>#![allow(missing_docs, nonstandard_style)]

use crate::ffi::{OsStr, OsString};
use crate::io::ErrorKind;
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
use crate::path::PathBuf;
use crate::time::Duration;

pub use self::rand::hashmap_random_keys;
pub use libc::strlen;

#[macro_use]
pub mod compat;

pub mod alloc;
pub mod args;
pub mod c;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod fs;
pub mod handle;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod thread;
pub mod thread_local_dtor;
pub mod thread_local_key;
pub mod thread_parker;
pub mod time;
cfg_if::cfg_if! {
    if #[cfg(not(target_vendor = "uwp"))] {
        pub mod stdio;
        pub mod stack_overflow;
    } else {
        pub mod stdio_uwp;
        pub mod stack_overflow_uwp;
        pub use self::stdio_uwp as stdio;
        pub use self::stack_overflow_uwp as stack_overflow;
    }
}

// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
    stack_overflow::init();
}

// SAFETY: must be called only once during runtime cleanup.
// NOTE: this is not guaranteed to run, for example when the program aborts.
pub unsafe fn cleanup() {
    net::cleanup();
}

pub fn decode_error_kind(errno: i32) -> ErrorKind {
    use ErrorKind::*;

    match errno as c::DWORD {
        c::ERROR_ACCESS_DENIED => return PermissionDenied,
        c::ERROR_ALREADY_EXISTS => return AlreadyExists,
        c::ERROR_FILE_EXISTS => return AlreadyExists,
        c::ERROR_BROKEN_PIPE => return BrokenPipe,
        c::ERROR_FILE_NOT_FOUND => return NotFound,
        c::ERROR_PATH_NOT_FOUND => return NotFound,
        c::ERROR_NO_DATA => return BrokenPipe,
        c::ERROR_INVALID_PARAMETER => return InvalidInput,
        c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory,
        c::ERROR_SEM_TIMEOUT
        | c::WAIT_TIMEOUT
        | c::ERROR_DRIVER_CANCEL_TIMEOUT
        | c::ERROR_OPERATION_ABORTED
        | c::ERROR_SERVICE_REQUEST_TIMEOUT
        | c::ERROR_COUNTER_TIMEOUT
        | c::ERROR_TIMEOUT
        | c::ERROR_RESOURCE_CALL_TIMED_OUT
        | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT
        | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT
        | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT
        | c::ERROR_DS_TIMELIMIT_EXCEEDED
        | c::DNS_ERROR_RECORD_TIMED_OUT
        | c::ERROR_IPSEC_IKE_TIMED_OUT
        | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT
        | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return TimedOut,
        c::ERROR_CALL_NOT_IMPLEMENTED => return Unsupported,
        c::ERROR_HOST_UNREACHABLE => return HostUnreachable,
        c::ERROR_NETWORK_UNREACHABLE => return NetworkUnreachable,
        c::ERROR_DIRECTORY => return NotADirectory,
        c::ERROR_DIRECTORY_NOT_SUPPORTED => return IsADirectory,
        c::ERROR_DIR_NOT_EMPTY => return DirectoryNotEmpty,
        c::ERROR_WRITE_PROTECT => return ReadOnlyFilesystem,
        c::ERROR_DISK_FULL | c::ERROR_HANDLE_DISK_FULL => return StorageFull,
        c::ERROR_SEEK_ON_DEVICE => return NotSeekable,
        c::ERROR_DISK_QUOTA_EXCEEDED => return FilesystemQuotaExceeded,
        c::ERROR_FILE_TOO_LARGE => return FileTooLarge,
        c::ERROR_BUSY => return ResourceBusy,
        c::ERROR_POSSIBLE_DEADLOCK => return Deadlock,
        c::ERROR_NOT_SAME_DEVICE => return CrossesDevices,
        c::ERROR_TOO_MANY_LINKS => return TooManyLinks,
        c::ERROR_FILENAME_EXCED_RANGE => return FilenameTooLong,
        _ => {}
    }

    match errno {
        c::WSAEACCES => PermissionDenied,
        c::WSAEADDRINUSE => AddrInUse,
        c::WSAEADDRNOTAVAIL => AddrNotAvailable,
        c::WSAECONNABORTED => ConnectionAborted,
        c::WSAECONNREFUSED => ConnectionRefused,
        c::WSAECONNRESET => ConnectionReset,
        c::WSAEINVAL => InvalidInput,
        c::WSAENOTCONN => NotConnected,
        c::WSAEWOULDBLOCK => WouldBlock,
        c::WSAETIMEDOUT => TimedOut,
        c::WSAEHOSTUNREACH => HostUnreachable,
        c::WSAENETDOWN => NetworkDown,
        c::WSAENETUNREACH => NetworkUnreachable,

        _ => Uncategorized,
    }
}

pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
    let ptr = haystack.as_ptr();
    let mut start = &haystack[..];

    // For performance reasons unfold the loop eight times.
    while start.len() >= 8 {
        macro_rules! if_return {
            ($($n:literal,)+) => {
                $(
                    if start[$n] == needle {
                        return Some((&start[$n] as *const u16 as usize - ptr as usize) / 2);
                    }
                )+
            }
        }

        if_return!(0, 1, 2, 3, 4, 5, 6, 7,);

        start = &start[8..];
    }

    for c in start {
        if *c == needle {
            return Some((c as *const u16 as usize - ptr as usize) / 2);
        }
    }
    None
}

pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> {
    fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
        let mut maybe_result: Vec<u16> = s.encode_wide().collect();
        if unrolled_find_u16s(0, &maybe_result).is_some() {
            return Err(crate::io::Error::new_const(
                ErrorKind::InvalidInput,
                &"strings passed to WinAPI cannot contain NULs",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }
    inner(s.as_ref())
}

// Many Windows APIs follow a pattern of where we hand a buffer and then they
// will report back to us how large the buffer should be or how many bytes
// currently reside in the buffer. This function is an abstraction over these
// functions by making them easier to call.
//
// The first callback, `f1`, is yielded a (pointer, len) pair which can be
// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case).
// The closure is expected to return what the syscall returns which will be
// interpreted by this function to determine if the syscall needs to be invoked
// again (with more buffer space).
//
// Once the syscall has completed (errors bail out early) the second closure is
// yielded the data which has been read from the syscall. The return value
// from this closure is then the return value of the function.
fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> crate::io::Result<T>
where
    F1: FnMut(*mut u16, c::DWORD) -> c::DWORD,
    F2: FnOnce(&[u16]) -> T,
{
    // Start off with a stack buf but then spill over to the heap if we end up
    // needing more space.
    let mut stack_buf = [0u16; 512];
    let mut heap_buf = Vec::new();
    unsafe {
        let mut n = stack_buf.len();
        loop {
            let buf = if n <= stack_buf.len() {
                &mut stack_buf[..]
            } else {
                let extra = n - heap_buf.len();
                heap_buf.reserve(extra);
                heap_buf.set_len(n);
                &mut heap_buf[..]
            };

            // This function is typically called on windows API functions which
            // will return the correct length of the string, but these functions
            // also return the `0` on error. In some cases, however, the
            // returned "correct length" may actually be 0!
            //
            // To handle this case we call `SetLastError` to reset it to 0 and
            // then check it again if we get the "0 error value". If the "last
            // error" is still 0 then we interpret it as a 0 length buffer and
            // not an actual error.
            c::SetLastError(0);
            let k = match f1(buf.as_mut_ptr(), n as c::DWORD) {
                0 if c::GetLastError() == 0 => 0,
                0 => return Err(crate::io::Error::last_os_error()),
                n => n,
            } as usize;
            if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
                n *= 2;
            } else if k >= n {
                n = k;
            } else {
                return Ok(f2(&buf[..k]));
            }
        }
    }
}

fn os2path(s: &[u16]) -> PathBuf {
    PathBuf::from(OsString::from_wide(s))
}

pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] {
    match unrolled_find_u16s(0, v) {
        // don't include the 0
        Some(i) => &v[..i],
        None => v,
    }
}

pub trait IsZero {
    fn is_zero(&self) -> bool;
}

macro_rules! impl_is_zero {
    ($($t:ident)*) => ($(impl IsZero for $t {
        fn is_zero(&self) -> bool {
            *self == 0
        }
    })*)
}

impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }

pub fn cvt<I: IsZero>(i: I) -> crate::io::Result<I> {
    if i.is_zero() { Err(crate::io::Error::last_os_error()) } else { Ok(i) }
}

pub fn dur2timeout(dur: Duration) -> c::DWORD {
    // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
    // timeouts in windows APIs are typically u32 milliseconds. To translate, we
    // have two pieces to take care of:
    //
    // * Nanosecond precision is rounded up
    // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE
    //   (never time out).
    dur.as_secs()
        .checked_mul(1000)
        .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000))
        .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 }))
        .map(|ms| if ms > <c::DWORD>::MAX as u64 { c::INFINITE } else { ms as c::DWORD })
        .unwrap_or(c::INFINITE)
}

/// Use `__fastfail` to abort the process
///
/// This is the same implementation as in libpanic_abort's `__rust_start_panic`. See
/// that function for more information on `__fastfail`
#[allow(unreachable_code)]
pub fn abort_internal() -> ! {
    const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
    unsafe {
        cfg_if::cfg_if! {
            if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
                asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
                crate::intrinsics::unreachable();
            } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
                asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
                crate::intrinsics::unreachable();
            } else if #[cfg(target_arch = "aarch64")] {
                asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
                crate::intrinsics::unreachable();
            }
        }
    }
    crate::intrinsics::abort();
}
<|endoftext|>


<commit_before>extern crate unicode_names;

use std::marker::PhantomData;

use irc::client::prelude::*;

use plugin::*;
use FrippyClient;

use error::ErrorKind as FrippyErrorKind;
use error::FrippyError;
use failure::Fail;

#[derive(PluginName, Default, Debug)]
pub struct Unicode<C> {
    phantom: PhantomData<C>,
}

impl<C: FrippyClient> Unicode<C> {
    pub fn new() -> Unicode<C> {
        Unicode {
            phantom: PhantomData,
        }
    }

    fn get_name(&self, symbol: char) -> String {
        match unicode_names::name(symbol) {
            Some(sym) => sym.to_string().to_lowercase(),
            None => String::from("UNKNOWN"),
        }
    }

    fn format_response(&self, content: &str) -> String {
        let character = content
            .chars()
            .next()
            .expect("content contains at least one character");

        let mut buf = [0; 4];

        let byte_string = character
            .encode_utf8(&mut buf)
            .as_bytes()
            .iter()
            .map(|b| format!("{:#b}", b))
            .collect::<Vec<String>>()
            .join(",");

        let name = self.get_name(character);

        format!(
            "{} is '{}' | UTF-8: {2:#x} ({2}), Bytes: [{3}]",
            character, name, character as u32, byte_string
        )
    }
}

impl<C: FrippyClient> Plugin for Unicode<C> {
    type Client = C;

    fn execute(&self, _: &Self::Client, _: &Message) -> ExecutionStatus {
        ExecutionStatus::Done
    }

    fn execute_threaded(&self, _: &Self::Client, _: &Message) -> Result<(), FrippyError> {
        panic!("Unicode should not use threading")
    }

    fn command(&self, client: &Self::Client, command: PluginCommand) -> Result<(), FrippyError> {
        let token = match command.tokens.iter().find(|t| !t.is_empty()) {
            Some(t) => t,
            None => {
                let msg = "No non-space character was found.";

                if let Err(e) = client.send_notice(command.source, msg) {
                    Err(e.context(FrippyErrorKind::Connection))?;
                }

                return Ok(());
            }
        };

        if let Err(e) = client.send_privmsg(command.target, &self.format_response(&token)) {
            Err(e.context(FrippyErrorKind::Connection))?;
        }

        Ok(())
    }

    fn evaluate(&self, _: &Self::Client, command: PluginCommand) -> Result<String, String> {
        let tokens = command.tokens;

        if tokens.is_empty() {
            return Err(String::from("No non-space character was found."));
        }

        Ok(self.format_response(&tokens[0]))
    }
}
<commit_msg>Unicode: Use hex formatting for the byte list<commit_after>extern crate unicode_names;

use std::marker::PhantomData;

use irc::client::prelude::*;

use plugin::*;
use FrippyClient;

use error::ErrorKind as FrippyErrorKind;
use error::FrippyError;
use failure::Fail;

#[derive(PluginName, Default, Debug)]
pub struct Unicode<C> {
    phantom: PhantomData<C>,
}

impl<C: FrippyClient> Unicode<C> {
    pub fn new() -> Unicode<C> {
        Unicode {
            phantom: PhantomData,
        }
    }

    fn get_name(&self, symbol: char) -> String {
        match unicode_names::name(symbol) {
            Some(sym) => sym.to_string().to_lowercase(),
            None => String::from("UNKNOWN"),
        }
    }

    fn format_response(&self, content: &str) -> String {
        let character = content
            .chars()
            .next()
            .expect("content contains at least one character");

        let mut buf = [0; 4];

        let byte_string = character
            .encode_utf8(&mut buf)
            .as_bytes()
            .iter()
            .map(|b| format!("{:#x}", b))
            .collect::<Vec<String>>()
            .join(",");

        let name = self.get_name(character);

        format!(
            "{} is '{}' | UTF-8: {2:#x} ({2}), Bytes: [{3}]",
            character, name, character as u32, byte_string
        )
    }
}

impl<C: FrippyClient> Plugin for Unicode<C> {
    type Client = C;

    fn execute(&self, _: &Self::Client, _: &Message) -> ExecutionStatus {
        ExecutionStatus::Done
    }

    fn execute_threaded(&self, _: &Self::Client, _: &Message) -> Result<(), FrippyError> {
        panic!("Unicode should not use threading")
    }

    fn command(&self, client: &Self::Client, command: PluginCommand) -> Result<(), FrippyError> {
        let token = match command.tokens.iter().find(|t| !t.is_empty()) {
            Some(t) => t,
            None => {
                let msg = "No non-space character was found.";

                if let Err(e) = client.send_notice(command.source, msg) {
                    Err(e.context(FrippyErrorKind::Connection))?;
                }

                return Ok(());
            }
        };

        if let Err(e) = client.send_privmsg(command.target, &self.format_response(&token)) {
            Err(e.context(FrippyErrorKind::Connection))?;
        }

        Ok(())
    }

    fn evaluate(&self, _: &Self::Client, command: PluginCommand) -> Result<String, String> {
        let tokens = command.tokens;

        if tokens.is_empty() {
            return Err(String::from("No non-space character was found."));
        }

        Ok(self.format_response(&tokens[0]))
    }
}
<|endoftext|>


<commit_before>use super::super::{completer::*, flags, Binary, DirectoryStack, Shell, Variables};
use crate::{sys, types};
use liner::{BasicCompleter, CursorPosition, Event, EventKind};
use std::{env, io::ErrorKind, mem, path::PathBuf};

pub(crate) fn readln(shell: &mut Shell) -> Option<String> {
    let vars_ptr = &shell.variables as *const Variables;
    let dirs_ptr = &shell.directory_stack as *const DirectoryStack;

    // Collects the current list of values from history for completion.
    let history = shell
        .context
        .as_ref()
        .unwrap()
        .history
        .buffers
        .iter()
        // Map each underlying `liner::Buffer` into a `String`.
        .map(|x| x.chars().cloned().collect())
        // Collect each result into a vector to avoid borrowing issues.
        .collect::<Vec<types::Str>>();

    let prompt = shell.prompt();
    let vars = &shell.variables;
    let builtins = &shell.builtins;

    let line = shell.context.as_mut().unwrap().read_line(
        prompt,
        None,
        &mut move |Event { editor, kind }| {
            if let EventKind::BeforeComplete = kind {
                let (words, pos) = editor.get_words_and_cursor_position();

                let filename = match pos {
                    CursorPosition::InWord(index) => index > 0,
                    CursorPosition::InSpace(Some(_), _) => true,
                    CursorPosition::InSpace(None, _) => false,
                    CursorPosition::OnWordLeftEdge(index) => index >= 1,
                    CursorPosition::OnWordRightEdge(index) => {
                        match (words.into_iter().nth(index), env::current_dir()) {
                            (Some((start, end)), Ok(file)) => {
                                let filename = editor.current_buffer().range(start, end);
                                complete_as_file(&file, &filename, index)
                            }
                            _ => false,
                        }
                    }
                };

                let dir_completer = env::current_dir()
                    .ok()
                    .as_ref()
                    .and_then(|dir| dir.to_str())
                    .map(|dir| IonFileCompleter::new(Some(dir), dirs_ptr, vars_ptr));

                if filename {
                    if let Some(completer) = dir_completer {
                        mem::replace(&mut editor.context().completer, Some(Box::new(completer)));
                    }
                } else {
                    // Creates a list of definitions from the shell environment that
                    // will be used
                    // in the creation of a custom completer.
                    let words = builtins
                        .keys()
                        .iter()
                        // Add built-in commands to the completer's definitions.
                        .map(|&s| s.to_string())
                        // Add the history list to the completer's definitions.
                        .chain(history.iter().map(|s| s.to_string()))
                        // Add the aliases to the completer's definitions.
                        .chain(vars.aliases().map(|(key, _)| key.to_string()))
                        // Add the list of available functions to the completer's
                        // definitions.
                        .chain(vars.functions().map(|(key, _)| key.to_string()))
                        // Add the list of available variables to the completer's
                        // definitions. TODO: We should make
                        // it free to do String->SmallString
                        //       and mostly free to go back (free if allocated)
                        .chain(vars.string_vars().map(|(s, _)| ["$", &s].concat()))
                        .collect();

                    // Initialize a new completer from the definitions collected.
                    let custom_completer = BasicCompleter::new(words);

                    // Creates completers containing definitions from all directories
                    // listed
                    // in the environment's **$PATH** variable.
                    let mut file_completers: Vec<_> = env::var("PATH")
                        .unwrap_or_else(|_| "/bin/".to_string())
                        .split(sys::PATH_SEPARATOR)
                        .map(|s| IonFileCompleter::new(Some(s), dirs_ptr, vars_ptr))
                        .collect();

                    // Also add files/directories in the current directory to the
                    // completion list.
                    if let Some(completer) = dir_completer {
                        file_completers.push(completer);
                    }

                    // Merge the collected definitions with the file path definitions.
                    let completer = MultiCompleter::new(file_completers, custom_completer);

                    // Replace the shell's current completer with the newly-created
                    // completer.
                    mem::replace(&mut editor.context().completer, Some(Box::new(completer)));
                }
            }
        },
    );

    match line {
        Ok(line) => {
            if line.bytes().any(|c| !c.is_ascii_whitespace()) {
                shell.flags |= flags::UNTERMINATED;
            }
            Some(line)
        }
        // Handles Ctrl + C
        Err(ref err) if err.kind() == ErrorKind::Interrupted => None,
        // Handles Ctrl + D
        Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => {
            if shell.flow_control.unclosed_block() {
                shell.flow_control.pop();
                Some("".to_string())
            } else {
                shell.exit(shell.previous_status);
            }
        }
        Err(err) => {
            eprintln!("ion: liner: {}", err);
            None
        }
    }
}

/// Infer if the given filename is actually a partial filename
fn complete_as_file(current_dir: &PathBuf, filename: &str, index: usize) -> bool {
    let filename = filename.trim();
    let mut file = current_dir.clone();
    file.push(&filename);
    // If the user explicitly requests a file through this syntax then complete as
    // a file
    filename.starts_with('.') ||
    // If the file starts with a dollar sign, it's a variable, not a file
    (!filename.starts_with('$') &&
    // Once we are beyond the first string, assume its a file
    (index > 0 ||
    // If we are referencing a file that exists then just complete to that file
    file.exists() ||
    // If we have a partial file inside an existing directory, e.g. /foo/b when
    // /foo/bar exists, then treat it as file as long as `foo` isn't the
    // current directory, otherwise this would apply to any string `foo`
    file.parent().filter(|parent| parent.exists() && parent != current_dir).is_some()))
    // By default assume its not a file
}
<commit_msg>Remove needless clones for history<commit_after>use super::super::{completer::*, flags, Binary, Shell};
use crate::sys;
use liner::{BasicCompleter, CursorPosition, Event, EventKind};
use std::{env, io::ErrorKind, mem, path::PathBuf};

pub(crate) fn readln(shell: &mut Shell) -> Option<String> {
    let prompt = shell.prompt();
    let vars = &shell.variables;
    let builtins = &shell.builtins;
    let dirs = &shell.directory_stack;

    let line =
        shell.context.as_mut().unwrap().read_line(prompt, None, &mut |Event { editor, kind }| {
            if let EventKind::BeforeComplete = kind {
                let (words, pos) = editor.get_words_and_cursor_position();

                let filename = match pos {
                    CursorPosition::InWord(index) => index > 0,
                    CursorPosition::InSpace(Some(_), _) => true,
                    CursorPosition::InSpace(None, _) => false,
                    CursorPosition::OnWordLeftEdge(index) => index >= 1,
                    CursorPosition::OnWordRightEdge(index) => words
                        .into_iter()
                        .nth(index)
                        .map(|(start, end)| editor.current_buffer().range(start, end))
                        .and_then(|filename| {
                            Some(complete_as_file(&env::current_dir().ok()?, &filename, index))
                        })
                        .filter(|&x| x)
                        .is_some(),
                };

                let dir_completer = env::current_dir()
                    .ok()
                    .as_ref()
                    .and_then(|dir| dir.to_str())
                    .map(|dir| IonFileCompleter::new(Some(dir), dirs, vars));

                if filename {
                    if let Some(completer) = dir_completer {
                        mem::replace(&mut editor.context().completer, Some(Box::new(completer)));
                    }
                } else {
                    // Creates a list of definitions from the shell environment that
                    // will be used
                    // in the creation of a custom completer.
                    let words = builtins
                        .keys()
                        .iter()
                        // Add built-in commands to the completer's definitions.
                        .map(|&s| s.to_string())
                        // Add the history list to the completer's definitions.
                        // Map each underlying `liner::Buffer` into a `String`.
                        .chain(editor.context().history.buffers.iter().map(|x| x.into()))
                        // Add the aliases to the completer's definitions.
                        .chain(vars.aliases().map(|(key, _)| key.to_string()))
                        // Add the list of available functions to the completer's
                        // definitions.
                        .chain(vars.functions().map(|(key, _)| key.to_string()))
                        // Add the list of available variables to the completer's
                        // definitions. TODO: We should make
                        // it free to do String->SmallString
                        //       and mostly free to go back (free if allocated)
                        .chain(vars.string_vars().map(|(s, _)| ["$", &s].concat()))
                        .collect();

                    // Initialize a new completer from the definitions collected.
                    let custom_completer = BasicCompleter::new(words);

                    // Creates completers containing definitions from all directories
                    // listed
                    // in the environment's **$PATH** variable.
                    let mut file_completers: Vec<_> = env::var("PATH")
                        .unwrap_or_else(|_| "/bin/".to_string())
                        .split(sys::PATH_SEPARATOR)
                        .map(|s| IonFileCompleter::new(Some(s), dirs, vars))
                        .collect();

                    // Also add files/directories in the current directory to the
                    // completion list.
                    if let Some(completer) = dir_completer {
                        file_completers.push(completer);
                    }

                    // Merge the collected definitions with the file path definitions.
                    let completer = MultiCompleter::new(file_completers, custom_completer);

                    // Replace the shell's current completer with the newly-created
                    // completer.
                    mem::replace(&mut editor.context().completer, Some(Box::new(completer)));
                }
            }
        });

    match line {
        Ok(line) => {
            if line.bytes().any(|c| !c.is_ascii_whitespace()) {
                shell.flags |= flags::UNTERMINATED;
            }
            Some(line)
        }
        // Handles Ctrl + C
        Err(ref err) if err.kind() == ErrorKind::Interrupted => None,
        // Handles Ctrl + D
        Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => {
            if shell.flow_control.unclosed_block() {
                shell.flow_control.pop();
                Some("".to_string())
            } else {
                shell.exit(shell.previous_status);
            }
        }
        Err(err) => {
            eprintln!("ion: liner: {}", err);
            None
        }
    }
}

/// Infer if the given filename is actually a partial filename
fn complete_as_file(current_dir: &PathBuf, filename: &str, index: usize) -> bool {
    let filename = filename.trim();
    let mut file = current_dir.clone();
    file.push(&filename);
    // If the user explicitly requests a file through this syntax then complete as
    // a file
    filename.starts_with('.') ||
    // If the file starts with a dollar sign, it's a variable, not a file
    (!filename.starts_with('$') &&
    // Once we are beyond the first string, assume its a file
    (index > 0 ||
    // If we are referencing a file that exists then just complete to that file
    file.exists() ||
    // If we have a partial file inside an existing directory, e.g. /foo/b when
    // /foo/bar exists, then treat it as file as long as `foo` isn't the
    // current directory, otherwise this would apply to any string `foo`
    file.parent().filter(|parent| parent.exists() && parent != current_dir).is_some()))
    // By default assume its not a file
}
<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashMap};
use std::fs;
use std::io::{self, Write};
use std::thread::ThreadId;
use std::time::Instant;

use crate::session::config::{Options, OptLevel};

#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
pub enum ProfileCategory {
    Parsing,
    Expansion,
    TypeChecking,
    BorrowChecking,
    Codegen,
    Linking,
    Other,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ProfilerEvent {
    QueryStart { query_name: &'static str, category: ProfileCategory, time: Instant },
    QueryEnd { query_name: &'static str, category: ProfileCategory, time: Instant },
    GenericActivityStart { category: ProfileCategory, time: Instant },
    GenericActivityEnd { category: ProfileCategory, time: Instant },
    QueryCacheHit { query_name: &'static str, category: ProfileCategory },
    QueryCount { query_name: &'static str, category: ProfileCategory, count: usize },
}

impl ProfilerEvent {
    fn is_start_event(&self) -> bool {
        use self::ProfilerEvent::*;

        match self {
            QueryStart { .. } | GenericActivityStart { .. } => true,
            QueryEnd { .. } | GenericActivityEnd { .. } |
            QueryCacheHit { .. } | QueryCount { .. } => false,
        }
    }
}

pub struct SelfProfiler {
    events: HashMap<ThreadId, Vec<ProfilerEvent>>,
}

struct CategoryResultData {
    query_times: BTreeMap<&'static str, u64>,
    query_cache_stats: BTreeMap<&'static str, (u64, u64)>, //(hits, total)
}

impl CategoryResultData {
    fn new() -> CategoryResultData {
        CategoryResultData {
            query_times: BTreeMap::new(),
            query_cache_stats: BTreeMap::new(),
        }
    }

    fn total_time(&self) -> u64 {
        let mut total = 0;
        for (_, time) in &self.query_times {
            total += time;
        }

        total
    }

    fn total_cache_data(&self) -> (u64, u64) {
        let (mut hits, mut total) = (0, 0);

        for (_, (h, t)) in &self.query_cache_stats {
            hits += h;
            total += t;
        }

        (hits, total)
    }
}

impl Default for CategoryResultData {
    fn default() -> CategoryResultData {
        CategoryResultData::new()
    }
}

struct CalculatedResults {
    categories: BTreeMap<ProfileCategory, CategoryResultData>,
    crate_name: Option<String>,
    optimization_level: OptLevel,
    incremental: bool,
    verbose: bool,
}

impl CalculatedResults {
    fn new() -> CalculatedResults {
        CalculatedResults {
            categories: BTreeMap::new(),
            crate_name: None,
            optimization_level: OptLevel::No,
            incremental: false,
            verbose: false,
        }
    }

    fn consolidate(mut cr1: CalculatedResults, cr2: CalculatedResults) -> CalculatedResults {
        for (category, data) in cr2.categories {
            let cr1_data = cr1.categories.entry(category).or_default();

            for (query, time) in data.query_times {
                *cr1_data.query_times.entry(query).or_default() += time;
            }

            for (query, (hits, total)) in data.query_cache_stats {
                let (h, t) = cr1_data.query_cache_stats.entry(query).or_insert((0, 0));
                *h += hits;
                *t += total;
            }
        }

        cr1
    }

    fn total_time(&self) -> u64 {
        let mut total = 0;

        for (_, data) in &self.categories {
            total += data.total_time();
        }

        total
    }

    fn with_options(mut self, opts: &Options) -> CalculatedResults {
        self.crate_name = opts.crate_name.clone();
        self.optimization_level = opts.optimize;
        self.incremental = opts.incremental.is_some();
        self.verbose = opts.debugging_opts.verbose;

        self
    }
}

fn time_between_ns(start: Instant, end: Instant) -> u64 {
    if start < end {
        let time = end - start;
        (time.as_secs() * 1_000_000_000) + (time.subsec_nanos() as u64)
    } else {
        debug!("time_between_ns: ignorning instance of end < start");
        0
    }
}

fn calculate_percent(numerator: u64, denominator: u64) -> f32 {
    if denominator > 0 {
        ((numerator as f32) / (denominator as f32)) * 100.0
    } else {
        0.0
    }
}

impl SelfProfiler {
    pub fn new() -> SelfProfiler {
        let mut profiler = SelfProfiler {
            events: HashMap::new(),
        };

        profiler.start_activity(ProfileCategory::Other);

        profiler
    }

    pub fn start_activity(&mut self, category: ProfileCategory) {
        self.record(ProfilerEvent::GenericActivityStart {
            category,
            time: Instant::now(),
        })
    }

    pub fn end_activity(&mut self, category: ProfileCategory) {
        self.record(ProfilerEvent::GenericActivityEnd {
            category,
            time: Instant::now(),
        })
    }

    pub fn record_computed_queries(
        &mut self,
        query_name: &'static str,
        category: ProfileCategory,
        count: usize)
        {
        self.record(ProfilerEvent::QueryCount {
            query_name,
            category,
            count,
        })
    }

    pub fn record_query_hit(&mut self, query_name: &'static str, category: ProfileCategory) {
        self.record(ProfilerEvent::QueryCacheHit {
            query_name,
            category,
        })
    }

    pub fn start_query(&mut self, query_name: &'static str, category: ProfileCategory) {
        self.record(ProfilerEvent::QueryStart {
            query_name,
            category,
            time: Instant::now(),
        });
    }

    pub fn end_query(&mut self, query_name: &'static str, category: ProfileCategory) {
        self.record(ProfilerEvent::QueryEnd {
            query_name,
            category,
            time: Instant::now(),
        })
    }

    fn record(&mut self, event: ProfilerEvent) {
        let thread_id = std::thread::current().id();
        let events = self.events.entry(thread_id).or_default();

        events.push(event);
    }

    fn calculate_thread_results(events: &Vec<ProfilerEvent>) -> CalculatedResults {
        use self::ProfilerEvent::*;

        assert!(
            events.last().map(|e| !e.is_start_event()).unwrap_or(true),
            "there was an event running when calculate_reslts() was called"
        );

        let mut results = CalculatedResults::new();

        let mut query_stack = Vec::new();

        for event in events {
            match event {
                QueryStart { .. } | GenericActivityStart { .. } => {
                    query_stack.push(event);
                },
                QueryEnd { query_name, category, time: end_time } => {
                    let previous_query = query_stack.pop();
                    if let Some(QueryStart {
                                    query_name: p_query_name,
                                    time: start_time,
                                    category: _ }) = previous_query {
                        assert_eq!(
                            p_query_name,
                            query_name,
                            "Saw a query end but the previous query wasn't the corresponding start"
                        );

                        let time_ns = time_between_ns(*start_time, *end_time);
                        let result_data = results.categories.entry(*category).or_default();

                        *result_data.query_times.entry(query_name).or_default() += time_ns;
                    } else {
                        bug!("Saw a query end but the previous event wasn't a query start");
                    }
                }
                GenericActivityEnd { category, time: end_time } => {
                    let previous_event = query_stack.pop();
                    if let Some(GenericActivityStart {
                                    category: previous_category,
                                    time: start_time }) = previous_event {
                        assert_eq!(
                            previous_category,
                            category,
                            "Saw an end but the previous event wasn't the corresponding start"
                        );

                        let time_ns = time_between_ns(*start_time, *end_time);
                        let result_data = results.categories.entry(*category).or_default();

                        *result_data.query_times
                            .entry("{time spent not running queries}")
                            .or_default() += time_ns;
                    } else {
                        bug!("Saw an activity end but the previous event wasn't an activity start");
                    }
                },
                QueryCacheHit { category, query_name } => {
                    let result_data = results.categories.entry(*category).or_default();

                    let (hits, total) =
                        result_data.query_cache_stats.entry(query_name).or_insert((0, 0));
                    *hits += 1;
                    *total += 1;
                },
                QueryCount { category, query_name, count } => {
                    let result_data = results.categories.entry(*category).or_default();

                    let (_, totals) =
                        result_data.query_cache_stats.entry(query_name).or_insert((0, 0));
                    *totals += *count as u64;
                },
            }
        }

        //normalize the times to ms
        for (_, data) in &mut results.categories {
            for (_, time) in &mut data.query_times {
                *time = *time / 1_000_000;
            }
        }

        results
    }

    fn get_results(&self, opts: &Options) -> CalculatedResults {
        self.events
            .iter()
            .map(|(_, r)| SelfProfiler::calculate_thread_results(r))
            .fold(CalculatedResults::new(), CalculatedResults::consolidate)
            .with_options(opts)
    }

    pub fn print_results(&mut self, opts: &Options) {
        self.end_activity(ProfileCategory::Other);

        let results = self.get_results(opts);

        let total_time = results.total_time() as f32;

        let out = io::stderr();
        let mut lock = out.lock();

        let crate_name = results.crate_name.map(|n| format!(" for {}", n)).unwrap_or_default();

        writeln!(lock, "Self profiling results{}:", crate_name).unwrap();
        writeln!(lock).unwrap();

        writeln!(lock, "| Phase                                     | Time (ms)      \
                        | Time (%) | Queries        | Hits (%)")
            .unwrap();
        writeln!(lock, "| ----------------------------------------- | -------------- \
                        | -------- | -------------- | --------")
            .unwrap();

        let mut categories: Vec<_> = results.categories.iter().collect();
        categories.sort_by(|(_, data1), (_, data2)| data2.total_time().cmp(&data1.total_time()));

        for (category, data) in categories {
            let (category_hits, category_total) = data.total_cache_data();
            let category_hit_percent = calculate_percent(category_hits, category_total);

            writeln!(
                lock,
                "| {0: <41} | {1: >14} | {2: >8.2} | {3: >14} | {4: >8}",
                format!("{:?}", category),
                data.total_time(),
                ((data.total_time() as f32) / total_time) * 100.0,
                category_total,
                format!("{:.2}", category_hit_percent),
            ).unwrap();

            //in verbose mode, show individual query data
            if results.verbose {
                //don't show queries that took less than 1ms
                let mut times: Vec<_> = data.query_times.iter().filter(|(_, t)| **t > 0).collect();
                times.sort_by(|(_, time1), (_, time2)| time2.cmp(time1));

                for (query, time) in times {
                    let (hits, total) = data.query_cache_stats.get(query).unwrap_or(&(0, 0));
                    let hit_percent = calculate_percent(*hits, *total);

                    writeln!(
                        lock,
                        "| - {0: <39} | {1: >14} | {2: >8.2} | {3: >14} | {4: >8}",
                        query,
                        time,
                        ((*time as f32) / total_time) * 100.0,
                        total,
                        format!("{:.2}", hit_percent),
                    ).unwrap();
                }
            }
        }

        writeln!(lock).unwrap();
        writeln!(lock, "Optimization level: {:?}", opts.optimize).unwrap();
        writeln!(lock, "Incremental: {}", if results.incremental { "on" } else { "off" }).unwrap();
    }

    pub fn save_results(&self, opts: &Options) {
        let results = self.get_results(opts);

        let compilation_options =
            format!("{{ \"optimization_level\": \"{:?}\", \"incremental\": {} }}",
                    results.optimization_level,
                    if results.incremental { "true" } else { "false" });

        let mut category_data = String::new();

        for (category, data) in &results.categories {
            let (hits, total) = data.total_cache_data();
            let hit_percent = calculate_percent(hits, total);

            category_data.push_str(&format!("{{ \"category\": \"{:?}\", \"time_ms\": {}, \
                                                \"query_count\": {}, \"query_hits\": {} }}",
                                            category,
                                            data.total_time(),
                                            total,
                                            format!("{:.2}", hit_percent)));
        }

        let json = format!("{{ \"category_data\": {}, \"compilation_options\": {} }}",
                        category_data,
                        compilation_options);

        fs::write("self_profiler_results.json", json).unwrap();
    }
}
<commit_msg>Add #[inline] annotations<commit_after>use std::collections::{BTreeMap, HashMap};
use std::fs;
use std::io::{self, Write};
use std::thread::ThreadId;
use std::time::Instant;

use crate::session::config::{Options, OptLevel};

#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
pub enum ProfileCategory {
    Parsing,
    Expansion,
    TypeChecking,
    BorrowChecking,
    Codegen,
    Linking,
    Other,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ProfilerEvent {
    QueryStart { query_name: &'static str, category: ProfileCategory, time: Instant },
    QueryEnd { query_name: &'static str, category: ProfileCategory, time: Instant },
    GenericActivityStart { category: ProfileCategory, time: Instant },
    GenericActivityEnd { category: ProfileCategory, time: Instant },
    QueryCacheHit { query_name: &'static str, category: ProfileCategory },
    QueryCount { query_name: &'static str, category: ProfileCategory, count: usize },
}

impl ProfilerEvent {
    fn is_start_event(&self) -> bool {
        use self::ProfilerEvent::*;

        match self {
            QueryStart { .. } | GenericActivityStart { .. } => true,
            QueryEnd { .. } | GenericActivityEnd { .. } |
            QueryCacheHit { .. } | QueryCount { .. } => false,
        }
    }
}

pub struct SelfProfiler {
    events: HashMap<ThreadId, Vec<ProfilerEvent>>,
}

struct CategoryResultData {
    query_times: BTreeMap<&'static str, u64>,
    query_cache_stats: BTreeMap<&'static str, (u64, u64)>, //(hits, total)
}

impl CategoryResultData {
    fn new() -> CategoryResultData {
        CategoryResultData {
            query_times: BTreeMap::new(),
            query_cache_stats: BTreeMap::new(),
        }
    }

    fn total_time(&self) -> u64 {
        let mut total = 0;
        for (_, time) in &self.query_times {
            total += time;
        }

        total
    }

    fn total_cache_data(&self) -> (u64, u64) {
        let (mut hits, mut total) = (0, 0);

        for (_, (h, t)) in &self.query_cache_stats {
            hits += h;
            total += t;
        }

        (hits, total)
    }
}

impl Default for CategoryResultData {
    fn default() -> CategoryResultData {
        CategoryResultData::new()
    }
}

struct CalculatedResults {
    categories: BTreeMap<ProfileCategory, CategoryResultData>,
    crate_name: Option<String>,
    optimization_level: OptLevel,
    incremental: bool,
    verbose: bool,
}

impl CalculatedResults {
    fn new() -> CalculatedResults {
        CalculatedResults {
            categories: BTreeMap::new(),
            crate_name: None,
            optimization_level: OptLevel::No,
            incremental: false,
            verbose: false,
        }
    }

    fn consolidate(mut cr1: CalculatedResults, cr2: CalculatedResults) -> CalculatedResults {
        for (category, data) in cr2.categories {
            let cr1_data = cr1.categories.entry(category).or_default();

            for (query, time) in data.query_times {
                *cr1_data.query_times.entry(query).or_default() += time;
            }

            for (query, (hits, total)) in data.query_cache_stats {
                let (h, t) = cr1_data.query_cache_stats.entry(query).or_insert((0, 0));
                *h += hits;
                *t += total;
            }
        }

        cr1
    }

    fn total_time(&self) -> u64 {
        let mut total = 0;

        for (_, data) in &self.categories {
            total += data.total_time();
        }

        total
    }

    fn with_options(mut self, opts: &Options) -> CalculatedResults {
        self.crate_name = opts.crate_name.clone();
        self.optimization_level = opts.optimize;
        self.incremental = opts.incremental.is_some();
        self.verbose = opts.debugging_opts.verbose;

        self
    }
}

fn time_between_ns(start: Instant, end: Instant) -> u64 {
    if start < end {
        let time = end - start;
        (time.as_secs() * 1_000_000_000) + (time.subsec_nanos() as u64)
    } else {
        debug!("time_between_ns: ignorning instance of end < start");
        0
    }
}

fn calculate_percent(numerator: u64, denominator: u64) -> f32 {
    if denominator > 0 {
        ((numerator as f32) / (denominator as f32)) * 100.0
    } else {
        0.0
    }
}

impl SelfProfiler {
    pub fn new() -> SelfProfiler {
        let mut profiler = SelfProfiler {
            events: HashMap::new(),
        };

        profiler.start_activity(ProfileCategory::Other);

        profiler
    }

    #[inline]
    pub fn start_activity(&mut self, category: ProfileCategory) {
        self.record(ProfilerEvent::GenericActivityStart {
            category,
            time: Instant::now(),
        })
    }

    #[inline]
    pub fn end_activity(&mut self, category: ProfileCategory) {
        self.record(ProfilerEvent::GenericActivityEnd {
            category,
            time: Instant::now(),
        })
    }

    #[inline]
    pub fn record_computed_queries(
        &mut self,
        query_name: &'static str,
        category: ProfileCategory,
        count: usize)
        {
        self.record(ProfilerEvent::QueryCount {
            query_name,
            category,
            count,
        })
    }

    #[inline]
    pub fn record_query_hit(&mut self, query_name: &'static str, category: ProfileCategory) {
        self.record(ProfilerEvent::QueryCacheHit {
            query_name,
            category,
        })
    }

    #[inline]
    pub fn start_query(&mut self, query_name: &'static str, category: ProfileCategory) {
        self.record(ProfilerEvent::QueryStart {
            query_name,
            category,
            time: Instant::now(),
        });
    }

    #[inline]
    pub fn end_query(&mut self, query_name: &'static str, category: ProfileCategory) {
        self.record(ProfilerEvent::QueryEnd {
            query_name,
            category,
            time: Instant::now(),
        })
    }

    #[inline]
    fn record(&mut self, event: ProfilerEvent) {
        let thread_id = std::thread::current().id();
        let events = self.events.entry(thread_id).or_default();

        events.push(event);
    }

    fn calculate_thread_results(events: &Vec<ProfilerEvent>) -> CalculatedResults {
        use self::ProfilerEvent::*;

        assert!(
            events.last().map(|e| !e.is_start_event()).unwrap_or(true),
            "there was an event running when calculate_reslts() was called"
        );

        let mut results = CalculatedResults::new();

        let mut query_stack = Vec::new();

        for event in events {
            match event {
                QueryStart { .. } | GenericActivityStart { .. } => {
                    query_stack.push(event);
                },
                QueryEnd { query_name, category, time: end_time } => {
                    let previous_query = query_stack.pop();
                    if let Some(QueryStart {
                                    query_name: p_query_name,
                                    time: start_time,
                                    category: _ }) = previous_query {
                        assert_eq!(
                            p_query_name,
                            query_name,
                            "Saw a query end but the previous query wasn't the corresponding start"
                        );

                        let time_ns = time_between_ns(*start_time, *end_time);
                        let result_data = results.categories.entry(*category).or_default();

                        *result_data.query_times.entry(query_name).or_default() += time_ns;
                    } else {
                        bug!("Saw a query end but the previous event wasn't a query start");
                    }
                }
                GenericActivityEnd { category, time: end_time } => {
                    let previous_event = query_stack.pop();
                    if let Some(GenericActivityStart {
                                    category: previous_category,
                                    time: start_time }) = previous_event {
                        assert_eq!(
                            previous_category,
                            category,
                            "Saw an end but the previous event wasn't the corresponding start"
                        );

                        let time_ns = time_between_ns(*start_time, *end_time);
                        let result_data = results.categories.entry(*category).or_default();

                        *result_data.query_times
                            .entry("{time spent not running queries}")
                            .or_default() += time_ns;
                    } else {
                        bug!("Saw an activity end but the previous event wasn't an activity start");
                    }
                },
                QueryCacheHit { category, query_name } => {
                    let result_data = results.categories.entry(*category).or_default();

                    let (hits, total) =
                        result_data.query_cache_stats.entry(query_name).or_insert((0, 0));
                    *hits += 1;
                    *total += 1;
                },
                QueryCount { category, query_name, count } => {
                    let result_data = results.categories.entry(*category).or_default();

                    let (_, totals) =
                        result_data.query_cache_stats.entry(query_name).or_insert((0, 0));
                    *totals += *count as u64;
                },
            }
        }

        //normalize the times to ms
        for (_, data) in &mut results.categories {
            for (_, time) in &mut data.query_times {
                *time = *time / 1_000_000;
            }
        }

        results
    }

    fn get_results(&self, opts: &Options) -> CalculatedResults {
        self.events
            .iter()
            .map(|(_, r)| SelfProfiler::calculate_thread_results(r))
            .fold(CalculatedResults::new(), CalculatedResults::consolidate)
            .with_options(opts)
    }

    pub fn print_results(&mut self, opts: &Options) {
        self.end_activity(ProfileCategory::Other);

        let results = self.get_results(opts);

        let total_time = results.total_time() as f32;

        let out = io::stderr();
        let mut lock = out.lock();

        let crate_name = results.crate_name.map(|n| format!(" for {}", n)).unwrap_or_default();

        writeln!(lock, "Self profiling results{}:", crate_name).unwrap();
        writeln!(lock).unwrap();

        writeln!(lock, "| Phase                                     | Time (ms)      \
                        | Time (%) | Queries        | Hits (%)")
            .unwrap();
        writeln!(lock, "| ----------------------------------------- | -------------- \
                        | -------- | -------------- | --------")
            .unwrap();

        let mut categories: Vec<_> = results.categories.iter().collect();
        categories.sort_by(|(_, data1), (_, data2)| data2.total_time().cmp(&data1.total_time()));

        for (category, data) in categories {
            let (category_hits, category_total) = data.total_cache_data();
            let category_hit_percent = calculate_percent(category_hits, category_total);

            writeln!(
                lock,
                "| {0: <41} | {1: >14} | {2: >8.2} | {3: >14} | {4: >8}",
                format!("{:?}", category),
                data.total_time(),
                ((data.total_time() as f32) / total_time) * 100.0,
                category_total,
                format!("{:.2}", category_hit_percent),
            ).unwrap();

            //in verbose mode, show individual query data
            if results.verbose {
                //don't show queries that took less than 1ms
                let mut times: Vec<_> = data.query_times.iter().filter(|(_, t)| **t > 0).collect();
                times.sort_by(|(_, time1), (_, time2)| time2.cmp(time1));

                for (query, time) in times {
                    let (hits, total) = data.query_cache_stats.get(query).unwrap_or(&(0, 0));
                    let hit_percent = calculate_percent(*hits, *total);

                    writeln!(
                        lock,
                        "| - {0: <39} | {1: >14} | {2: >8.2} | {3: >14} | {4: >8}",
                        query,
                        time,
                        ((*time as f32) / total_time) * 100.0,
                        total,
                        format!("{:.2}", hit_percent),
                    ).unwrap();
                }
            }
        }

        writeln!(lock).unwrap();
        writeln!(lock, "Optimization level: {:?}", opts.optimize).unwrap();
        writeln!(lock, "Incremental: {}", if results.incremental { "on" } else { "off" }).unwrap();
    }

    pub fn save_results(&self, opts: &Options) {
        let results = self.get_results(opts);

        let compilation_options =
            format!("{{ \"optimization_level\": \"{:?}\", \"incremental\": {} }}",
                    results.optimization_level,
                    if results.incremental { "true" } else { "false" });

        let mut category_data = String::new();

        for (category, data) in &results.categories {
            let (hits, total) = data.total_cache_data();
            let hit_percent = calculate_percent(hits, total);

            category_data.push_str(&format!("{{ \"category\": \"{:?}\", \"time_ms\": {}, \
                                                \"query_count\": {}, \"query_hits\": {} }}",
                                            category,
                                            data.total_time(),
                                            total,
                                            format!("{:.2}", hit_percent)));
        }

        let json = format!("{{ \"category_data\": {}, \"compilation_options\": {} }}",
                        category_data,
                        compilation_options);

        fs::write("self_profiler_results.json", json).unwrap();
    }
}
<|endoftext|>


<commit_before>#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
    use redis::Commands as _;
    use rusoto_sqs::Sqs as _;

    let config = encoder_reinforce::load_config()?;
    let redis_client = redis::Client::open(config.redis.url)?;
    let mut conn = redis_client.get_connection()?;
    let sqs_client = rusoto_sqs::SqsClient::new(Default::default());

    loop {
        let job: Vec<String> = conn.blpop(&["jobs", "0"], 5)?;
        if job.is_empty() {
            break;
        }
        let fname = job.into_iter().nth(1).unwrap();
        println!("Enqueue {}", fname);

        sqs_client
            .send_message(rusoto_sqs::SendMessageRequest {
                queue_url: config.sqs.queue_url.clone(),
                message_body: fname,
                ..Default::default()
            })
            .await?;
    }
    Ok(())
}
<commit_msg>Fix module name<commit_after>#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
    use redis::Commands as _;
    use rusoto_sqs::Sqs as _;

    let config = encoder::load_config()?;
    let redis_client = redis::Client::open(config.redis.url)?;
    let mut conn = redis_client.get_connection()?;
    let sqs_client = rusoto_sqs::SqsClient::new(Default::default());

    loop {
        let job: Vec<String> = conn.blpop(&["jobs", "0"], 5)?;
        if job.is_empty() {
            break;
        }
        let fname = job.into_iter().nth(1).unwrap();
        println!("Enqueue {}", fname);

        sqs_client
            .send_message(rusoto_sqs::SendMessageRequest {
                queue_url: config.sqs.queue_url.clone(),
                message_body: fname,
                ..Default::default()
            })
            .await?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>extern crate tls;
use std::io::{Read, Write};
use tls::{new_client,init};
use std::net::TcpStream;

#[test]
fn test_client() {
    assert!(init());

    let mut c = new_client()
        .ca_file("tests/cert.pem")
        .connect("google.com", "443", None).unwrap();
    c.handshake().unwrap();

    let notbefore = c.peer_cert_notbefore().unwrap();
    let notafter = c.peer_cert_notafter().unwrap();
    assert!(notbefore < notafter);
    assert!(c.peer_cert_provided());
    assert!(c.peer_cert_contains_name("google.com"));

    // Start an HTTP request just to check read/write
    c.write("GET / HTTP/1.1\n\n".as_bytes()).unwrap();
    let mut buf = [0u8; 256];
    c.read(&mut buf).unwrap();
    println!("{}", String::from_utf8_lossy(&buf));
    assert!(buf.starts_with(b"HTTP/1.1 "));
}

#[test]
fn stream_write_read() {
    assert!(init());

    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect("www.google.com", "443", None)
                .unwrap();

    cli.write("GET / HTTP/1.1\n\n".as_bytes()).unwrap();
    let mut buf = [0u8; 256];
    cli.read(&mut buf).unwrap();
    assert!(buf.starts_with(b"HTTP/1.1 "));
}

#[test]
fn shutdown_twice_fails() {
    assert!(init());

    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect("www.google.com", "443", None)
                .unwrap();

    cli.handshake().unwrap();
    cli.shutdown().unwrap();
    assert!(cli.shutdown().is_err());
}

#[test]
fn shutdown_without_handshake_fails() {
    assert!(init());

    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect("www.google.com", "443", None)
                .unwrap();

    assert!(cli.shutdown().is_err());
}

#[test]
fn ca_invalid() {
    assert!(init());
    // This will fail because there is no CA file
    let cli = new_client()
                .ca_path(".")
                .ca_file("")
                .connect("www.google.com", "443", None);
    assert!(cli.is_err());
}

#[test]
fn ca_string() {
    assert!(init());

    let pem = include_str!("cert.pem");
    let mut cli = new_client()
                .ca(&pem)
                .connect("www.google.com", "443", None)
                .unwrap();
    cli.handshake().unwrap();
}

#[test]
fn ca_string_invalid() {
    assert!(init());

    let cli = new_client()
                .ca("--INVALID PEM")
                .connect("www.google.com", "443", None);
    assert!(cli.is_err());
}

#[test]
fn connect_hostport() {
    assert!(init());
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect("www.google.com:443", "", None)
                .unwrap();
    cli.handshake().unwrap();
}

#[test]
fn connect_servername() {
    assert!(init());
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect("www.google.com", "443", Some("www.google.com"))
                .unwrap();
    cli.handshake().unwrap();
}

#[test]
fn connect_socket() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect_socket(tcp, "www.google.com")
                .unwrap();
    cli.handshake().unwrap();
}

#[test]
fn double_handshake_is_error() {
    assert!(init());

    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect("www.google.com", "443", None)
                .unwrap();

    cli.handshake().unwrap();
    assert!(cli.handshake().is_err());
}

#[test]
fn verify_depth() {
    assert!(init());

    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .verify_depth(0)
                .connect("www.google.com", "443", None)
                .unwrap();
    assert!(cli.handshake().is_err());
}
<commit_msg>Add unit tests for error cases<commit_after>extern crate tls;
use std::io::{Read, Write};
use tls::{new_client,init};
use std::net::TcpStream;

#[test]
fn test_client() {
    assert!(init());

    let mut c = new_client()
        .ca_file("tests/cert.pem")
        .connect("google.com", "443", None).unwrap();
    c.handshake().unwrap();

    let notbefore = c.peer_cert_notbefore().unwrap();
    let notafter = c.peer_cert_notafter().unwrap();
    assert!(notbefore < notafter);
    assert!(c.peer_cert_provided());
    assert!(c.peer_cert_contains_name("google.com"));

    // Start an HTTP request just to check read/write
    c.write("GET / HTTP/1.1\n\n".as_bytes()).unwrap();
    let mut buf = [0u8; 256];
    c.read(&mut buf).unwrap();
    println!("{}", String::from_utf8_lossy(&buf));
    assert!(buf.starts_with(b"HTTP/1.1 "));
}

#[test]
fn stream_write_read() {
    assert!(init());

    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect("www.google.com", "443", None)
                .unwrap();

    cli.write("GET / HTTP/1.1\n\n".as_bytes()).unwrap();
    let mut buf = [0u8; 256];
    cli.read(&mut buf).unwrap();
    assert!(buf.starts_with(b"HTTP/1.1 "));
}

#[test]
fn shutdown_twice_fails() {
    assert!(init());

    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect("www.google.com", "443", None)
                .unwrap();

    cli.handshake().unwrap();
    cli.shutdown().unwrap();
    assert!(cli.shutdown().is_err());
}

#[test]
fn shutdown_without_handshake_fails() {
    assert!(init());

    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect("www.google.com", "443", None)
                .unwrap();

    assert!(cli.shutdown().is_err());
}

#[test]
fn ca_invalid() {
    assert!(init());
    // This will fail because there is no CA file
    let cli = new_client()
                .ca_path(".")
                .ca_file("")
                .connect("www.google.com", "443", None);
    assert!(cli.is_err());
}

#[test]
fn ca_string() {
    assert!(init());

    let pem = include_str!("cert.pem");
    let mut cli = new_client()
                .ca(&pem)
                .connect("www.google.com", "443", None)
                .unwrap();
    cli.handshake().unwrap();
}

#[test]
fn ca_string_invalid() {
    assert!(init());

    let cli = new_client()
                .ca("--INVALID PEM")
                .connect("www.google.com", "443", None);
    assert!(cli.is_err());
}

#[test]
fn connect_hostport() {
    assert!(init());
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect("www.google.com:443", "", None)
                .unwrap();
    cli.handshake().unwrap();
}

#[test]
fn connect_servername() {
    assert!(init());
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect("www.google.com", "443", Some("www.google.com"))
                .unwrap();
    cli.handshake().unwrap();
}

#[test]
fn connect_socket() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect_socket(tcp, "www.google.com")
                .unwrap();
    cli.handshake().unwrap();
}

#[test]
fn double_handshake_is_error() {
    assert!(init());

    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect("www.google.com", "443", None)
                .unwrap();

    cli.handshake().unwrap();
    assert!(cli.handshake().is_err());
}

#[test]
fn verify_depth() {
    assert!(init());

    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .verify_depth(0)
                .connect("www.google.com", "443", None)
                .unwrap();
    assert!(cli.handshake().is_err());
}

#[test]
fn error_connect_no_host() {
    assert!(init());
    let cli = new_client()
                .ca_file("tests/cert.pem")
                .connect("", "443", None);
    assert!(cli.is_err());
}

#[test]
fn error_connect_no_port() {
    assert!(init());
    let cli = new_client()
                .ca_file("tests/cert.pem")
                .connect("www.google.com", "", None);
    assert!(cli.is_err());
}

#[test]
fn error_ciphers() {
    assert!(init());
    let cli = new_client()
                .ca_file("tests/cert.pem")
                .ciphers("unknown_cipher")
                .connect("www.google.com", "443", None);
    assert!(cli.is_err());
}
<|endoftext|>


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

<%namespace name="helpers" file="/helpers.mako.rs" />

// Per CSS-TEXT 6.2, "for legacy reasons, UAs must treat `word-wrap` as an alternate name for
// the `overflow-wrap` property, as if it were a shorthand of `overflow-wrap`."
<%helpers:shorthand name="word-wrap" sub_properties="overflow-wrap"
                    spec="https://drafts.csswg.org/css-text/#propdef-word-wrap">
    use properties::longhands::overflow_wrap;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        Ok(Longhands {
            overflow_wrap: Some(try!(overflow_wrap::parse(context, input))),
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            self.overflow_wrap.to_css(dest)
        }
    }
</%helpers:shorthand>

// https://drafts.csswg.org/css-text-decor-3/#text-emphasis-property
<%helpers:shorthand name="text-emphasis" products="gecko" sub_properties="text-emphasis-color
    text-emphasis-style">
    use properties::longhands::{text_emphasis_color, text_emphasis_style};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let mut color = None;
        let mut style = None;

        loop {
            if color.is_none() {
                if let Ok(value) = input.try(|input| text_emphasis_color::parse(context, input)) {
                    color = Some(value);
                    continue
                }
            }
            if style.is_none() {
                if let Ok(value) = input.try(|input| text_emphasis_style::parse(context, input)) {
                    style = Some(value);
                    continue
                }
            }
            break
        }
        if color.is_some() || style.is_some() {
            if style.is_none() {
                style = Some(text_emphasis_style::get_initial_specified_value());
            }

            Ok(Longhands {
                text_emphasis_color: color,
                text_emphasis_style: style,
            })
        } else {
            Err(())
        }
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let mut style_present = false;
            if let DeclaredValue::Value(ref value) = *self.text_emphasis_style {
                style_present = true;
                try!(value.to_css(dest));
            }

            if let DeclaredValue::Value(ref color) = *self.text_emphasis_color {
                if style_present {
                    try!(write!(dest, " "));
                }
                try!(color.to_css(dest));
            }
            Ok(())
        }
    }
</%helpers:shorthand>

// CSS Compatibility
// https://compat.spec.whatwg.org/
<%helpers:shorthand name="-webkit-text-stroke"
                    sub_properties="-webkit-text-stroke-color
                                    -webkit-text-stroke-width"
                    products="gecko"
                    spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke">
    use cssparser::Color as CSSParserColor;
    use properties::longhands::{_webkit_text_stroke_color, _webkit_text_stroke_width};
    use values::specified::CSSColor;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        use values::specified::{BorderWidth, Length};
        use app_units::Au;

        let (mut color, mut width, mut any) = (None, None, false);
        % for value in "color width".split():
            if ${value}.is_none() {
                if let Ok(value) = input.try(|input| _webkit_text_stroke_${value}::parse(context, input)) {
                    ${value} = Some(value);
                    any = true;
                }
            }
        % endfor

        if !any {
            return Err(());
        }

        Ok(Longhands {
            _webkit_text_stroke_color: color.or(Some(CSSColor { parsed: CSSParserColor::CurrentColor,
                                                                authored: None })),
            _webkit_text_stroke_width: width.or(Some(BorderWidth::from_length(Length::Absolute(Au::from_px(0))))),
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let mut style_present = false;
            if let DeclaredValue::Value(ref width) = *self._webkit_text_stroke_width {
                style_present = true;
                try!(width.to_css(dest));
            }

            if let DeclaredValue::Value(ref color) = *self._webkit_text_stroke_color {
                if style_present {
                    try!(write!(dest, " "));
                }
                try!(color.to_css(dest));
            }

            Ok(())
        }
    }
</%helpers:shorthand>
<commit_msg>Add spec link for text-emphasis<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

// Per CSS-TEXT 6.2, "for legacy reasons, UAs must treat `word-wrap` as an alternate name for
// the `overflow-wrap` property, as if it were a shorthand of `overflow-wrap`."
<%helpers:shorthand name="word-wrap" sub_properties="overflow-wrap"
                    spec="https://drafts.csswg.org/css-text/#propdef-word-wrap">
    use properties::longhands::overflow_wrap;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        Ok(Longhands {
            overflow_wrap: Some(try!(overflow_wrap::parse(context, input))),
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            self.overflow_wrap.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="text-emphasis" products="gecko" sub_properties="text-emphasis-color
    text-emphasis-style"
    spec="https://drafts.csswg.org/css-text-decor-3/#text-emphasis-property">
    use properties::longhands::{text_emphasis_color, text_emphasis_style};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let mut color = None;
        let mut style = None;

        loop {
            if color.is_none() {
                if let Ok(value) = input.try(|input| text_emphasis_color::parse(context, input)) {
                    color = Some(value);
                    continue
                }
            }
            if style.is_none() {
                if let Ok(value) = input.try(|input| text_emphasis_style::parse(context, input)) {
                    style = Some(value);
                    continue
                }
            }
            break
        }
        if color.is_some() || style.is_some() {
            if style.is_none() {
                style = Some(text_emphasis_style::get_initial_specified_value());
            }

            Ok(Longhands {
                text_emphasis_color: color,
                text_emphasis_style: style,
            })
        } else {
            Err(())
        }
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let mut style_present = false;
            if let DeclaredValue::Value(ref value) = *self.text_emphasis_style {
                style_present = true;
                try!(value.to_css(dest));
            }

            if let DeclaredValue::Value(ref color) = *self.text_emphasis_color {
                if style_present {
                    try!(write!(dest, " "));
                }
                try!(color.to_css(dest));
            }
            Ok(())
        }
    }
</%helpers:shorthand>

// CSS Compatibility
// https://compat.spec.whatwg.org/
<%helpers:shorthand name="-webkit-text-stroke"
                    sub_properties="-webkit-text-stroke-color
                                    -webkit-text-stroke-width"
                    products="gecko"
                    spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke">
    use cssparser::Color as CSSParserColor;
    use properties::longhands::{_webkit_text_stroke_color, _webkit_text_stroke_width};
    use values::specified::CSSColor;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        use values::specified::{BorderWidth, Length};
        use app_units::Au;

        let (mut color, mut width, mut any) = (None, None, false);
        % for value in "color width".split():
            if ${value}.is_none() {
                if let Ok(value) = input.try(|input| _webkit_text_stroke_${value}::parse(context, input)) {
                    ${value} = Some(value);
                    any = true;
                }
            }
        % endfor

        if !any {
            return Err(());
        }

        Ok(Longhands {
            _webkit_text_stroke_color: color.or(Some(CSSColor { parsed: CSSParserColor::CurrentColor,
                                                                authored: None })),
            _webkit_text_stroke_width: width.or(Some(BorderWidth::from_length(Length::Absolute(Au::from_px(0))))),
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let mut style_present = false;
            if let DeclaredValue::Value(ref width) = *self._webkit_text_stroke_width {
                style_present = true;
                try!(width.to_css(dest));
            }

            if let DeclaredValue::Value(ref color) = *self._webkit_text_stroke_color {
                if style_present {
                    try!(write!(dest, " "));
                }
                try!(color.to_css(dest));
            }

            Ok(())
        }
    }
</%helpers:shorthand>
<|endoftext|>


<commit_before>#![feature(old_path)]

extern crate piston;
extern crate graphics;
extern crate sdl2_window;
extern crate gfx_device_gl;
extern crate gfx_graphics;

use piston::quack::Get;
use std::cell::RefCell;
use gfx_graphics::gfx::traits::*;
use gfx_graphics::{
    Gfx2d,
    Texture,
    gfx
};
use sdl2_window::{ Sdl2Window, OpenGL };

fn main() {
    let window = Sdl2Window::new(
        OpenGL::_3_2,
        piston::window::WindowSettings {
            title: "gfx_graphics: imagetest".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let mut device = gfx_device_gl::GlDevice::new(Sdl2Window::get_proc_address);
    let piston::window::Size([w, h]) = window.get();
    let frame = gfx::Frame::new(w as u16, h as u16);
    let mut renderer = device.create_renderer();

    let image = Texture::from_path(&mut device,
        &Path::new("./assets/rust.png")).unwrap();
    let mut g2d = Gfx2d::new(&mut device);
    let window = RefCell::new(window);
    for e in piston::events(&window) {
        use piston::event::RenderEvent;
        if let Some(_) = e.render_args() {
            use graphics::Transformed;

            g2d.draw(&mut renderer, &frame, |c, g| {
                let transform = c.transform.trans(100.0, 100.0);

                graphics::clear([1.0; 4], g);
                graphics::Rectangle::new([1.0, 0.0, 0.0, 1.0])
                    .draw([0.0, 0.0, 100.0, 100.0],
                          &c.draw_state,
                          c.transform,
                          g);
                graphics::Rectangle::new([0.0, 1.0, 0.0, 0.3])
                    .draw([50.0, 50.0, 100.0, 100.0],
                          &c.draw_state,
                          c.transform,
                          g);
                graphics::image(&image, transform, g);
            });

            device.submit(renderer.as_buffer());
            renderer.reset();
       }
    }
}
<commit_msg>Used global import for graphics operations<commit_after>#![feature(old_path)]

extern crate piston;
extern crate graphics;
extern crate sdl2_window;
extern crate gfx_device_gl;
extern crate gfx_graphics;

use piston::quack::Get;
use std::cell::RefCell;
use gfx_graphics::gfx::traits::*;
use gfx_graphics::{
    Gfx2d,
    Texture,
    gfx
};
use sdl2_window::{ Sdl2Window, OpenGL };

fn main() {
    let window = Sdl2Window::new(
        OpenGL::_3_2,
        piston::window::WindowSettings {
            title: "gfx_graphics: imagetest".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let mut device = gfx_device_gl::GlDevice::new(Sdl2Window::get_proc_address);
    let piston::window::Size([w, h]) = window.get();
    let frame = gfx::Frame::new(w as u16, h as u16);
    let mut renderer = device.create_renderer();

    let rust_logo = Texture::from_path(&mut device,
        &Path::new("./assets/rust.png")).unwrap();
    let mut g2d = Gfx2d::new(&mut device);
    let window = RefCell::new(window);
    for e in piston::events(&window) {
        use piston::event::RenderEvent;
        if let Some(_) = e.render_args() {
            use graphics::*;

            g2d.draw(&mut renderer, &frame, |c, g| {
                let transform = c.transform.trans(100.0, 100.0);

                clear([1.0; 4], g);
                Rectangle::new([1.0, 0.0, 0.0, 1.0])
                    .draw([0.0, 0.0, 100.0, 100.0],
                          &c.draw_state,
                          c.transform,
                          g);
                Rectangle::new([0.0, 1.0, 0.0, 0.3])
                    .draw([50.0, 50.0, 100.0, 100.0],
                          &c.draw_state,
                          c.transform,
                          g);
                image(&rust_logo, transform, g);
            });

            device.submit(renderer.as_buffer());
            renderer.reset();
       }
    }
}
<|endoftext|>