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

//! A simple native mutex implementation. Warning: this API is likely
//! to change soon.

#![allow(dead_code)]

use core::prelude::*;
use self::Flavor::*;

use alloc::boxed::Box;
use rustrt::mutex;

pub const LOCKED: uint = 1 << 0;
pub const BLOCKED: uint = 1 << 1;

/// A mutual exclusion primitive useful for protecting shared data
///
/// This mutex will properly block tasks waiting for the lock to become
/// available. The mutex can also be statically initialized or created via a
/// `new` constructor.
///
/// # Example
///
/// ```rust
/// use sync::mutex::Mutex;
///
/// let m = Mutex::new();
/// let guard = m.lock();
/// // do some work
/// drop(guard); // unlock the lock
/// ```
pub struct Mutex {
    // Note that this static mutex is in a *box*, not inlined into the struct
    // itself. This is done for memory safety reasons with the usage of a
    // StaticNativeMutex inside the static mutex above. Once a native mutex has
    // been used once, its address can never change (it can't be moved). This
    // mutex type can be safely moved at any time, so to ensure that the native
    // mutex is used correctly we box the inner lock to give it a constant
    // address.
    lock: Box<StaticMutex>,
}

/// The static mutex type is provided to allow for static allocation of mutexes.
///
/// Note that this is a separate type because using a Mutex correctly means that
/// it needs to have a destructor run. In Rust, statics are not allowed to have
/// destructors. As a result, a `StaticMutex` has one extra method when compared
/// to a `Mutex`, a `destroy` method. This method is unsafe to call, and
/// documentation can be found directly on the method.
///
/// # Example
///
/// ```rust
/// use sync::mutex::{StaticMutex, MUTEX_INIT};
///
/// static LOCK: StaticMutex = MUTEX_INIT;
///
/// {
///     let _g = LOCK.lock();
///     // do some productive work
/// }
/// // lock is unlocked here.
/// ```
pub struct StaticMutex {
    lock: mutex::StaticNativeMutex,
}

/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
/// dropped (falls out of scope), the lock will be unlocked.
#[must_use]
pub struct Guard<'a> {
    guard: mutex::LockGuard<'a>,
}

fn lift_guard(guard: mutex::LockGuard) -> Guard {
    Guard { guard: guard }
}

/// Static initialization of a mutex. This constant can be used to initialize
/// other mutex constants.
pub const MUTEX_INIT: StaticMutex = StaticMutex {
    lock: mutex::NATIVE_MUTEX_INIT
};

impl StaticMutex {
    /// Attempts to grab this lock, see `Mutex::try_lock`
    pub fn try_lock<'a>(&'a self) -> Option<Guard<'a>> {
        unsafe { self.lock.trylock().map(lift_guard) }
    }

    /// Acquires this lock, see `Mutex::lock`
    pub fn lock<'a>(&'a self) -> Guard<'a> {
        lift_guard(unsafe { self.lock.lock() })
    }

    /// Deallocates resources associated with this static mutex.
    ///
    /// This method is unsafe because it provides no guarantees that there are
    /// no active users of this mutex, and safety is not guaranteed if there are
    /// active users of this mutex.
    ///
    /// This method is required to ensure that there are no memory leaks on
    /// *all* platforms. It may be the case that some platforms do not leak
    /// memory if this method is not called, but this is not guaranteed to be
    /// true on all platforms.
    pub unsafe fn destroy(&self) {
        self.lock.destroy()
    }
}

impl Mutex {
    /// Creates a new mutex in an unlocked state ready for use.
    pub fn new() -> Mutex {
        Mutex {
            lock: box StaticMutex {
                lock: unsafe { mutex::StaticNativeMutex::new() },
            }
        }
    }

    /// Attempts to acquire this lock.
    ///
    /// If the lock could not be acquired at this time, then `None` is returned.
    /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
    /// guard is dropped.
    ///
    /// This function does not block.
    pub fn try_lock<'a>(&'a self) -> Option<Guard<'a>> {
        self.lock.try_lock()
    }

    /// Acquires a mutex, blocking the current task until it is able to do so.
    ///
    /// This function will block the local task until it is available to acquire
    /// the mutex. Upon returning, the task is the only task with the mutex
    /// held. An RAII guard is returned to allow scoped unlock of the lock. When
    /// the guard goes out of scope, the mutex will be unlocked.
    pub fn lock<'a>(&'a self) -> Guard<'a> { self.lock.lock() }
}

impl Drop for Mutex {
    fn drop(&mut self) {
        // This is actually safe b/c we know that there is no further usage of
        // this mutex (it's up to the user to arrange for a mutex to get
        // dropped, that's not our job)
        unsafe { self.lock.destroy() }
    }
}

#[cfg(test)]
mod test {
    use std::prelude::*;
    use super::{Mutex, StaticMutex, MUTEX_INIT};

    #[test]
    fn smoke() {
        let m = Mutex::new();
        drop(m.lock());
        drop(m.lock());
    }

    #[test]
    fn smoke_static() {
        static M: StaticMutex = MUTEX_INIT;
        unsafe {
            drop(M.lock());
            drop(M.lock());
            M.destroy();
        }
    }

    #[test]
    fn lots_and_lots() {
        static M: StaticMutex = MUTEX_INIT;
        static mut CNT: uint = 0;
        static J: uint = 1000;
        static K: uint = 3;

        fn inc() {
            for _ in range(0, J) {
                unsafe {
                    let _g = M.lock();
                    CNT += 1;
                }
            }
        }

        let (tx, rx) = channel();
        for _ in range(0, K) {
            let tx2 = tx.clone();
            spawn(proc() { inc(); tx2.send(()); });
            let tx2 = tx.clone();
            spawn(proc() { inc(); tx2.send(()); });
        }

        drop(tx);
        for _ in range(0, 2 * K) {
            rx.recv();
        }
        assert_eq!(unsafe {CNT}, J * K * 2);
        unsafe {
            M.destroy();
        }
    }

    #[test]
    fn trylock() {
        let m = Mutex::new();
        assert!(m.try_lock().is_some());
    }
}
<commit_msg>Fallout from namespaced enums<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A simple native mutex implementation. Warning: this API is likely
//! to change soon.

#![allow(dead_code)]

use core::prelude::*;
use alloc::boxed::Box;
use rustrt::mutex;

pub const LOCKED: uint = 1 << 0;
pub const BLOCKED: uint = 1 << 1;

/// A mutual exclusion primitive useful for protecting shared data
///
/// This mutex will properly block tasks waiting for the lock to become
/// available. The mutex can also be statically initialized or created via a
/// `new` constructor.
///
/// # Example
///
/// ```rust
/// use sync::mutex::Mutex;
///
/// let m = Mutex::new();
/// let guard = m.lock();
/// // do some work
/// drop(guard); // unlock the lock
/// ```
pub struct Mutex {
    // Note that this static mutex is in a *box*, not inlined into the struct
    // itself. This is done for memory safety reasons with the usage of a
    // StaticNativeMutex inside the static mutex above. Once a native mutex has
    // been used once, its address can never change (it can't be moved). This
    // mutex type can be safely moved at any time, so to ensure that the native
    // mutex is used correctly we box the inner lock to give it a constant
    // address.
    lock: Box<StaticMutex>,
}

/// The static mutex type is provided to allow for static allocation of mutexes.
///
/// Note that this is a separate type because using a Mutex correctly means that
/// it needs to have a destructor run. In Rust, statics are not allowed to have
/// destructors. As a result, a `StaticMutex` has one extra method when compared
/// to a `Mutex`, a `destroy` method. This method is unsafe to call, and
/// documentation can be found directly on the method.
///
/// # Example
///
/// ```rust
/// use sync::mutex::{StaticMutex, MUTEX_INIT};
///
/// static LOCK: StaticMutex = MUTEX_INIT;
///
/// {
///     let _g = LOCK.lock();
///     // do some productive work
/// }
/// // lock is unlocked here.
/// ```
pub struct StaticMutex {
    lock: mutex::StaticNativeMutex,
}

/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
/// dropped (falls out of scope), the lock will be unlocked.
#[must_use]
pub struct Guard<'a> {
    guard: mutex::LockGuard<'a>,
}

fn lift_guard(guard: mutex::LockGuard) -> Guard {
    Guard { guard: guard }
}

/// Static initialization of a mutex. This constant can be used to initialize
/// other mutex constants.
pub const MUTEX_INIT: StaticMutex = StaticMutex {
    lock: mutex::NATIVE_MUTEX_INIT
};

impl StaticMutex {
    /// Attempts to grab this lock, see `Mutex::try_lock`
    pub fn try_lock<'a>(&'a self) -> Option<Guard<'a>> {
        unsafe { self.lock.trylock().map(lift_guard) }
    }

    /// Acquires this lock, see `Mutex::lock`
    pub fn lock<'a>(&'a self) -> Guard<'a> {
        lift_guard(unsafe { self.lock.lock() })
    }

    /// Deallocates resources associated with this static mutex.
    ///
    /// This method is unsafe because it provides no guarantees that there are
    /// no active users of this mutex, and safety is not guaranteed if there are
    /// active users of this mutex.
    ///
    /// This method is required to ensure that there are no memory leaks on
    /// *all* platforms. It may be the case that some platforms do not leak
    /// memory if this method is not called, but this is not guaranteed to be
    /// true on all platforms.
    pub unsafe fn destroy(&self) {
        self.lock.destroy()
    }
}

impl Mutex {
    /// Creates a new mutex in an unlocked state ready for use.
    pub fn new() -> Mutex {
        Mutex {
            lock: box StaticMutex {
                lock: unsafe { mutex::StaticNativeMutex::new() },
            }
        }
    }

    /// Attempts to acquire this lock.
    ///
    /// If the lock could not be acquired at this time, then `None` is returned.
    /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
    /// guard is dropped.
    ///
    /// This function does not block.
    pub fn try_lock<'a>(&'a self) -> Option<Guard<'a>> {
        self.lock.try_lock()
    }

    /// Acquires a mutex, blocking the current task until it is able to do so.
    ///
    /// This function will block the local task until it is available to acquire
    /// the mutex. Upon returning, the task is the only task with the mutex
    /// held. An RAII guard is returned to allow scoped unlock of the lock. When
    /// the guard goes out of scope, the mutex will be unlocked.
    pub fn lock<'a>(&'a self) -> Guard<'a> { self.lock.lock() }
}

impl Drop for Mutex {
    fn drop(&mut self) {
        // This is actually safe b/c we know that there is no further usage of
        // this mutex (it's up to the user to arrange for a mutex to get
        // dropped, that's not our job)
        unsafe { self.lock.destroy() }
    }
}

#[cfg(test)]
mod test {
    use std::prelude::*;
    use super::{Mutex, StaticMutex, MUTEX_INIT};

    #[test]
    fn smoke() {
        let m = Mutex::new();
        drop(m.lock());
        drop(m.lock());
    }

    #[test]
    fn smoke_static() {
        static M: StaticMutex = MUTEX_INIT;
        unsafe {
            drop(M.lock());
            drop(M.lock());
            M.destroy();
        }
    }

    #[test]
    fn lots_and_lots() {
        static M: StaticMutex = MUTEX_INIT;
        static mut CNT: uint = 0;
        static J: uint = 1000;
        static K: uint = 3;

        fn inc() {
            for _ in range(0, J) {
                unsafe {
                    let _g = M.lock();
                    CNT += 1;
                }
            }
        }

        let (tx, rx) = channel();
        for _ in range(0, K) {
            let tx2 = tx.clone();
            spawn(proc() { inc(); tx2.send(()); });
            let tx2 = tx.clone();
            spawn(proc() { inc(); tx2.send(()); });
        }

        drop(tx);
        for _ in range(0, 2 * K) {
            rx.recv();
        }
        assert_eq!(unsafe {CNT}, J * K * 2);
        unsafe {
            M.destroy();
        }
    }

    #[test]
    fn trylock() {
        let m = Mutex::new();
        assert!(m.try_lock().is_some());
    }
}
<|endoftext|>


<commit_before>use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::io;
use std::any::Any;

use tokio_core::reactor;
use tokio_core::net::TcpListener;
use tokio_core::net::TcpStream;

use futures::stream::Stream;
use futures::Future;

use server_conf::ServerConf;

use net2;

use socket::AnySocketAddr;
use socket::ToSocketListener;
use socket::ToTokioListener;
use socket::ToServerStream;
use socket::ToClientStream;
use socket::StreamItem;

impl ToSocketListener for SocketAddr {
    fn to_listener(&self, conf: &ServerConf) -> Box<ToTokioListener + Send> {
        let listen_addr = self.to_socket_addrs().unwrap().next().unwrap();
        Box::new(listener(&listen_addr, conf).unwrap())
    }

    fn cleanup(&self) {}
}

#[cfg(unix)]
fn configure_tcp(tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    use net2::unix::UnixTcpBuilderExt;
    if let Some(reuse_port) = conf.reuse_port {
        tcp.reuse_port(reuse_port)?;
    }
    Ok(())
}

#[cfg(windows)]
fn configure_tcp(_tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    Ok(())
}

fn listener(
    addr: &SocketAddr,
    conf: &ServerConf)
        -> io::Result<::std::net::TcpListener>
{
    let listener = match *addr {
        SocketAddr::V4(_) => net2::TcpBuilder::new_v4()?,
        SocketAddr::V6(_) => net2::TcpBuilder::new_v6()?,
    };

    if let SocketAddr::V6(_) = *addr {
        // Assume only_v6 = false by default
        // Note: it is not default behavior for Rust
        let only_v6 = conf.only_v6.unwrap_or(false);
        listener.only_v6(only_v6)?;
    }

    configure_tcp(&listener, conf)?;
    listener.reuse_address(true)?;
    listener.bind(addr)?;
    let backlog = conf.backlog.unwrap_or(1024);
    listener.listen(backlog)
}

impl ToTokioListener for ::std::net::TcpListener {
    fn to_tokio_listener(self: Box<Self>, handle: &reactor::Handle) -> Box<ToServerStream> {
        let local_addr = self.local_addr().unwrap();
        Box::new(TcpListener::from_listener(*self, &local_addr, handle).unwrap())
    }

    fn local_addr(&self) -> io::Result<AnySocketAddr> {
        Ok(AnySocketAddr::Inet(self.local_addr().unwrap()))
    }
}

impl ToServerStream for TcpListener {
    fn incoming(self: Box<Self>)
        -> Box<Stream<Item=(Box<StreamItem>, Box<Any>), Error=io::Error>>
    {
        let stream = (*self).incoming().map(|(stream, addr)|
            (Box::new(stream) as Box<StreamItem>, Box::new(addr) as Box<Any>)
        );
        Box::new(stream)
    }
}

impl ToClientStream for SocketAddr {
    fn connect(&self, handle: &reactor::Handle)
        -> Box<Future<Item=Box<StreamItem>, Error=io::Error> + Send>
    {
        let stream = TcpStream::connect(self, &handle).map(|stream|
            Box::new(stream) as Box<StreamItem>
        );
        Box::new(stream)
    }
}

impl StreamItem for TcpStream {
    fn is_tcp(&self) -> bool {
        true
    }

    fn set_nodelay(&self, no_delay: bool) -> io::Result<()> {
        self.set_nodelay(no_delay)
    }
}
<commit_msg>Unnecessary addr -> addr conversion<commit_after>use std::net::SocketAddr;
use std::io;
use std::any::Any;

use tokio_core::reactor;
use tokio_core::net::TcpListener;
use tokio_core::net::TcpStream;

use futures::stream::Stream;
use futures::Future;

use server_conf::ServerConf;

use net2;

use socket::AnySocketAddr;
use socket::ToSocketListener;
use socket::ToTokioListener;
use socket::ToServerStream;
use socket::ToClientStream;
use socket::StreamItem;

impl ToSocketListener for SocketAddr {
    fn to_listener(&self, conf: &ServerConf) -> Box<ToTokioListener + Send> {
        Box::new(listener(self, conf).unwrap())
    }

    fn cleanup(&self) {}
}

#[cfg(unix)]
fn configure_tcp(tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    use net2::unix::UnixTcpBuilderExt;
    if let Some(reuse_port) = conf.reuse_port {
        tcp.reuse_port(reuse_port)?;
    }
    Ok(())
}

#[cfg(windows)]
fn configure_tcp(_tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    Ok(())
}

fn listener(
    addr: &SocketAddr,
    conf: &ServerConf)
        -> io::Result<::std::net::TcpListener>
{
    let listener = match *addr {
        SocketAddr::V4(_) => net2::TcpBuilder::new_v4()?,
        SocketAddr::V6(_) => net2::TcpBuilder::new_v6()?,
    };

    if let SocketAddr::V6(_) = *addr {
        // Assume only_v6 = false by default
        // Note: it is not default behavior for Rust
        let only_v6 = conf.only_v6.unwrap_or(false);
        listener.only_v6(only_v6)?;
    }

    configure_tcp(&listener, conf)?;
    listener.reuse_address(true)?;
    listener.bind(addr)?;
    let backlog = conf.backlog.unwrap_or(1024);
    listener.listen(backlog)
}

impl ToTokioListener for ::std::net::TcpListener {
    fn to_tokio_listener(self: Box<Self>, handle: &reactor::Handle) -> Box<ToServerStream> {
        let local_addr = self.local_addr().unwrap();
        Box::new(TcpListener::from_listener(*self, &local_addr, handle).unwrap())
    }

    fn local_addr(&self) -> io::Result<AnySocketAddr> {
        Ok(AnySocketAddr::Inet(self.local_addr().unwrap()))
    }
}

impl ToServerStream for TcpListener {
    fn incoming(self: Box<Self>)
        -> Box<Stream<Item=(Box<StreamItem>, Box<Any>), Error=io::Error>>
    {
        let stream = (*self).incoming().map(|(stream, addr)|
            (Box::new(stream) as Box<StreamItem>, Box::new(addr) as Box<Any>)
        );
        Box::new(stream)
    }
}

impl ToClientStream for SocketAddr {
    fn connect(&self, handle: &reactor::Handle)
        -> Box<Future<Item=Box<StreamItem>, Error=io::Error> + Send>
    {
        let stream = TcpStream::connect(self, &handle).map(|stream|
            Box::new(stream) as Box<StreamItem>
        );
        Box::new(stream)
    }
}

impl StreamItem for TcpStream {
    fn is_tcp(&self) -> bool {
        true
    }

    fn set_nodelay(&self, no_delay: bool) -> io::Result<()> {
        self.set_nodelay(no_delay)
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "specialize")]
use crate::HasherExt;
use core::hash::Hash;
use core::hash::Hasher;

#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std as alloc;

use alloc::string::String;
use alloc::vec::Vec;

/// Provides a way to get an optimized hasher for a given data type.
/// Rather than using a Hasher generically which can hash any value, this provides a way to get a specialized hash
/// for a specific type. So this may be faster for primitive types. It does however consume the hasher in the process.
/// # Example
/// ```
/// use std::hash::BuildHasher;
/// use ahash::RandomState;
/// use ahash::CallHasher;
///
/// let hash_builder = RandomState::new();
/// //...
/// let value = 17;
/// let hash = u32::get_hash(&value, hash_builder.build_hasher());
/// ```
pub trait CallHasher {
    fn get_hash<H: Hasher>(value: &Self, hasher: H) -> u64;
}

#[cfg(not(feature = "specialize"))]
impl<T> CallHasher for T
where
    T: Hash + ?Sized,
{
    #[inline]
    fn get_hash<H: Hasher>(value: &T, mut hasher: H) -> u64 {
        value.hash(&mut hasher);
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl<T> CallHasher for T
where
    T: Hash + ?Sized,
{
    #[inline]
    default fn get_hash<H: Hasher>(value: &T, mut hasher: H) -> u64 {
        value.hash(&mut hasher);
        hasher.finish()
    }
}

macro_rules! call_hasher_impl {
    ($typ:ty) => {
        #[cfg(feature = "specialize")]
        impl CallHasher for $typ {
            #[inline]
            fn get_hash<H: Hasher>(value: &$typ, hasher: H) -> u64 {
                hasher.hash_u64(*value as u64)
            }
        }
        #[cfg(feature = "specialize")]
        impl CallHasher for &$typ {
            #[inline]
            fn get_hash<H: Hasher>(value: &&$typ, hasher: H) -> u64 {
                hasher.hash_u64(**value as u64)
            }
        }
        #[cfg(feature = "specialize")]
        impl CallHasher for &&$typ {
            #[inline]
            fn get_hash<H: Hasher>(value: &&&$typ, hasher: H) -> u64 {
                hasher.hash_u64(***value as u64)
            }
        }
    };
}
call_hasher_impl!(u8);
call_hasher_impl!(u16);
call_hasher_impl!(u32);
call_hasher_impl!(u64);
call_hasher_impl!(i8);
call_hasher_impl!(i16);
call_hasher_impl!(i32);
call_hasher_impl!(i64);

#[cfg(feature = "specialize")]
impl CallHasher for u128 {
    #[inline]
    fn get_hash<H: Hasher>(value: &u128, mut hasher: H) -> u64 {
        hasher.write_u128(*value);
        hasher.short_finish()
    }
}

impl CallHasher for &u128 {
    #[inline]
    fn get_hash<H: Hasher>(value: &&u128, mut hasher: H) -> u64 {
        hasher.write_u128(**value);
        hasher.short_finish()
    }
}

impl CallHasher for &&u128 {
    #[inline]
    fn get_hash<H: Hasher>(value: &&&u128, mut hasher: H) -> u64 {
        hasher.write_u128(***value);
        hasher.short_finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for i128 {
    #[inline]
    fn get_hash<H: Hasher>(value: &i128,  mut hasher: H) -> u64 {
        hasher.write_u128(*value as u128);
        hasher.short_finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &i128 {
    #[inline]
    fn get_hash<H: Hasher>(value: &&i128,  mut hasher: H) -> u64 {
        hasher.write_u128(**value as u128);
        hasher.short_finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &&i128 {
    #[inline]
    fn get_hash<H: Hasher>(value: &&&i128,  mut hasher: H) -> u64 {
        hasher.write_u128(***value as u128);
        hasher.short_finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for [u8] {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value);
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &[u8] {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(*value);
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &&[u8] {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(**value);
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for Vec<u8> {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value);
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &Vec<u8> {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(*value);
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &&Vec<u8> {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(**value);
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for str {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &str {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &&str {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &&&str {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

#[cfg(all(feature = "specialize"))]
impl CallHasher for String {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

#[cfg(all(feature = "specialize"))]
impl CallHasher for &String {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

#[cfg(all(feature = "specialize"))]
impl CallHasher for &&String {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

#[cfg(all(feature = "specialize"))]
impl CallHasher for &&&String {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

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

    #[test]
    #[cfg(feature = "specialize")]
    pub fn test_specialized_invoked() {
        let shortened = u64::get_hash(&0, AHasher::new_with_keys(1, 2));
        let mut hasher = AHasher::new_with_keys(1, 2);
        0_u64.hash(&mut hasher);
        assert_ne!(hasher.finish(), shortened);
    }

    /// Tests that some non-trivial transformation takes place.
    #[test]
    pub fn test_input_processed() {
        let hasher = || AHasher::new_with_keys(3, 2);
        assert_ne!(0, u64::get_hash(&0, hasher()));
        assert_ne!(1, u64::get_hash(&0, hasher()));
        assert_ne!(2, u64::get_hash(&0, hasher()));
        assert_ne!(3, u64::get_hash(&0, hasher()));
        assert_ne!(4, u64::get_hash(&0, hasher()));
        assert_ne!(5, u64::get_hash(&0, hasher()));

        assert_ne!(0, u64::get_hash(&1, hasher()));
        assert_ne!(1, u64::get_hash(&1, hasher()));
        assert_ne!(2, u64::get_hash(&1, hasher()));
        assert_ne!(3, u64::get_hash(&1, hasher()));
        assert_ne!(4, u64::get_hash(&1, hasher()));
        assert_ne!(5, u64::get_hash(&1, hasher()));

        let xored = u64::get_hash(&0, hasher()) ^ u64::get_hash(&1, hasher());
        assert_ne!(0, xored);
        assert_ne!(1, xored);
        assert_ne!(2, xored);
        assert_ne!(3, xored);
        assert_ne!(4, xored);
        assert_ne!(5, xored);
    }

    #[test]
    pub fn test_ref_independent() {
        let hasher = || AHasher::new_with_keys(3, 2);
        assert_eq!(<&u8>::get_hash(&&1, hasher()), u8::get_hash(&1, hasher()));
        assert_eq!(<&u16>::get_hash(&&2, hasher()), u16::get_hash(&2, hasher()));
        assert_eq!(<&u32>::get_hash(&&3, hasher()), u32::get_hash(&3, hasher()));
        assert_eq!(<&u64>::get_hash(&&4, hasher()), u64::get_hash(&4, hasher()));
        assert_eq!(<&u128>::get_hash(&&5, hasher()), u128::get_hash(&5, hasher()));
        assert_eq!(<&str>::get_hash(&"test", hasher()), str::get_hash("test", hasher()));
        assert_eq!(<&str>::get_hash(&"test", hasher()), String::get_hash(&"test".to_string(), hasher()));
        assert_eq!(<&str>::get_hash(&"test", hasher()), <[u8]>::get_hash("test".as_bytes(), hasher()));

        let hasher = || AHasher::new_with_keys(3, 2);
        assert_eq!(<&&u8>::get_hash(&&&1, hasher()), u8::get_hash(&1, hasher()));
        assert_eq!(<&&u16>::get_hash(&&&2, hasher()), u16::get_hash(&2, hasher()));
        assert_eq!(<&&u32>::get_hash(&&&3, hasher()), u32::get_hash(&3, hasher()));
        assert_eq!(<&&u64>::get_hash(&&&4, hasher()), u64::get_hash(&4, hasher()));
        assert_eq!(<&&u128>::get_hash(&&&5, hasher()), u128::get_hash(&5, hasher()));
        assert_eq!(<&&str>::get_hash(&&"test", hasher()), str::get_hash("test",hasher()));
        assert_eq!(<&&str>::get_hash(&&"test", hasher()), String::get_hash(&"test".to_string(), hasher()));
        assert_eq!(<&&str>::get_hash(&&"test", hasher()), <[u8]>::get_hash(&"test".to_string().into_bytes(), hasher()));
    }
}
<commit_msg>Add missing cfg flags<commit_after>#[cfg(feature = "specialize")]
use crate::HasherExt;
use core::hash::Hash;
use core::hash::Hasher;

#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std as alloc;

#[cfg(feature = "specialize")]
use alloc::string::String;
#[cfg(feature = "specialize")]
use alloc::vec::Vec;

/// Provides a way to get an optimized hasher for a given data type.
/// Rather than using a Hasher generically which can hash any value, this provides a way to get a specialized hash
/// for a specific type. So this may be faster for primitive types. It does however consume the hasher in the process.
/// # Example
/// ```
/// use std::hash::BuildHasher;
/// use ahash::RandomState;
/// use ahash::CallHasher;
///
/// let hash_builder = RandomState::new();
/// //...
/// let value = 17;
/// let hash = u32::get_hash(&value, hash_builder.build_hasher());
/// ```
pub trait CallHasher {
    fn get_hash<H: Hasher>(value: &Self, hasher: H) -> u64;
}

#[cfg(not(feature = "specialize"))]
impl<T> CallHasher for T
where
    T: Hash + ?Sized,
{
    #[inline]
    fn get_hash<H: Hasher>(value: &T, mut hasher: H) -> u64 {
        value.hash(&mut hasher);
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl<T> CallHasher for T
where
    T: Hash + ?Sized,
{
    #[inline]
    default fn get_hash<H: Hasher>(value: &T, mut hasher: H) -> u64 {
        value.hash(&mut hasher);
        hasher.finish()
    }
}

macro_rules! call_hasher_impl {
    ($typ:ty) => {
        #[cfg(feature = "specialize")]
        impl CallHasher for $typ {
            #[inline]
            fn get_hash<H: Hasher>(value: &$typ, hasher: H) -> u64 {
                hasher.hash_u64(*value as u64)
            }
        }
        #[cfg(feature = "specialize")]
        impl CallHasher for &$typ {
            #[inline]
            fn get_hash<H: Hasher>(value: &&$typ, hasher: H) -> u64 {
                hasher.hash_u64(**value as u64)
            }
        }
        #[cfg(feature = "specialize")]
        impl CallHasher for &&$typ {
            #[inline]
            fn get_hash<H: Hasher>(value: &&&$typ, hasher: H) -> u64 {
                hasher.hash_u64(***value as u64)
            }
        }
    };
}
call_hasher_impl!(u8);
call_hasher_impl!(u16);
call_hasher_impl!(u32);
call_hasher_impl!(u64);
call_hasher_impl!(i8);
call_hasher_impl!(i16);
call_hasher_impl!(i32);
call_hasher_impl!(i64);

#[cfg(feature = "specialize")]
impl CallHasher for u128 {
    #[inline]
    fn get_hash<H: Hasher>(value: &u128, mut hasher: H) -> u64 {
        hasher.write_u128(*value);
        hasher.short_finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &u128 {
    #[inline]
    fn get_hash<H: Hasher>(value: &&u128, mut hasher: H) -> u64 {
        hasher.write_u128(**value);
        hasher.short_finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &&u128 {
    #[inline]
    fn get_hash<H: Hasher>(value: &&&u128, mut hasher: H) -> u64 {
        hasher.write_u128(***value);
        hasher.short_finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for i128 {
    #[inline]
    fn get_hash<H: Hasher>(value: &i128,  mut hasher: H) -> u64 {
        hasher.write_u128(*value as u128);
        hasher.short_finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &i128 {
    #[inline]
    fn get_hash<H: Hasher>(value: &&i128,  mut hasher: H) -> u64 {
        hasher.write_u128(**value as u128);
        hasher.short_finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &&i128 {
    #[inline]
    fn get_hash<H: Hasher>(value: &&&i128,  mut hasher: H) -> u64 {
        hasher.write_u128(***value as u128);
        hasher.short_finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for [u8] {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value);
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &[u8] {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(*value);
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &&[u8] {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(**value);
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for Vec<u8> {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value);
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &Vec<u8> {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(*value);
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &&Vec<u8> {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(**value);
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for str {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &str {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &&str {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

#[cfg(feature = "specialize")]
impl CallHasher for &&&str {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

#[cfg(all(feature = "specialize"))]
impl CallHasher for String {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

#[cfg(all(feature = "specialize"))]
impl CallHasher for &String {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

#[cfg(all(feature = "specialize"))]
impl CallHasher for &&String {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

#[cfg(all(feature = "specialize"))]
impl CallHasher for &&&String {
    #[inline]
    fn get_hash<H: Hasher>(value: &Self, mut hasher: H) -> u64 {
        hasher.write(value.as_bytes());
        hasher.finish()
    }
}

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

    #[test]
    #[cfg(feature = "specialize")]
    pub fn test_specialized_invoked() {
        let shortened = u64::get_hash(&0, AHasher::new_with_keys(1, 2));
        let mut hasher = AHasher::new_with_keys(1, 2);
        0_u64.hash(&mut hasher);
        assert_ne!(hasher.finish(), shortened);
    }

    /// Tests that some non-trivial transformation takes place.
    #[test]
    pub fn test_input_processed() {
        let hasher = || AHasher::new_with_keys(3, 2);
        assert_ne!(0, u64::get_hash(&0, hasher()));
        assert_ne!(1, u64::get_hash(&0, hasher()));
        assert_ne!(2, u64::get_hash(&0, hasher()));
        assert_ne!(3, u64::get_hash(&0, hasher()));
        assert_ne!(4, u64::get_hash(&0, hasher()));
        assert_ne!(5, u64::get_hash(&0, hasher()));

        assert_ne!(0, u64::get_hash(&1, hasher()));
        assert_ne!(1, u64::get_hash(&1, hasher()));
        assert_ne!(2, u64::get_hash(&1, hasher()));
        assert_ne!(3, u64::get_hash(&1, hasher()));
        assert_ne!(4, u64::get_hash(&1, hasher()));
        assert_ne!(5, u64::get_hash(&1, hasher()));

        let xored = u64::get_hash(&0, hasher()) ^ u64::get_hash(&1, hasher());
        assert_ne!(0, xored);
        assert_ne!(1, xored);
        assert_ne!(2, xored);
        assert_ne!(3, xored);
        assert_ne!(4, xored);
        assert_ne!(5, xored);
    }

    #[test]
    pub fn test_ref_independent() {
        let hasher = || AHasher::new_with_keys(3, 2);
        assert_eq!(<&u8>::get_hash(&&1, hasher()), u8::get_hash(&1, hasher()));
        assert_eq!(<&u16>::get_hash(&&2, hasher()), u16::get_hash(&2, hasher()));
        assert_eq!(<&u32>::get_hash(&&3, hasher()), u32::get_hash(&3, hasher()));
        assert_eq!(<&u64>::get_hash(&&4, hasher()), u64::get_hash(&4, hasher()));
        assert_eq!(<&u128>::get_hash(&&5, hasher()), u128::get_hash(&5, hasher()));
        assert_eq!(<&str>::get_hash(&"test", hasher()), str::get_hash("test", hasher()));
        assert_eq!(<&str>::get_hash(&"test", hasher()), String::get_hash(&"test".to_string(), hasher()));
        #[cfg(feature = "specialize")]
        assert_eq!(<&str>::get_hash(&"test", hasher()), <[u8]>::get_hash("test".as_bytes(), hasher()));

        let hasher = || AHasher::new_with_keys(3, 2);
        assert_eq!(<&&u8>::get_hash(&&&1, hasher()), u8::get_hash(&1, hasher()));
        assert_eq!(<&&u16>::get_hash(&&&2, hasher()), u16::get_hash(&2, hasher()));
        assert_eq!(<&&u32>::get_hash(&&&3, hasher()), u32::get_hash(&3, hasher()));
        assert_eq!(<&&u64>::get_hash(&&&4, hasher()), u64::get_hash(&4, hasher()));
        assert_eq!(<&&u128>::get_hash(&&&5, hasher()), u128::get_hash(&5, hasher()));
        assert_eq!(<&&str>::get_hash(&&"test", hasher()), str::get_hash("test",hasher()));
        assert_eq!(<&&str>::get_hash(&&"test", hasher()), String::get_hash(&"test".to_string(), hasher()));
        #[cfg(feature = "specialize")]
        assert_eq!(<&&str>::get_hash(&&"test", hasher()), <[u8]>::get_hash(&"test".to_string().into_bytes(), hasher()));
    }
}
<|endoftext|>


<commit_before>use crate::action_client::{OnFeedback, OnTransition};
use crate::msg::actionlib_msgs::GoalStatusArray;
use crate::static_messages::MUTEX_LOCK_FAIL;
use crate::{Action, FeedbackType, GoalType, ResultType, SyncClientGoalHandle};
use crate::{GoalID, GoalState, GoalStatus};
use std::sync::{Arc, Mutex};

pub type OnSendGoal<T> = Arc<dyn Fn(<T as Action>::Goal) + Send + Sync + 'static>;
pub type OnSendCancel = Arc<dyn Fn(GoalID) + Send + Sync + 'static>;

pub struct CommStateMachine<T: Action> {
    action_goal: GoalType<T>,
    on_feedback: Option<OnFeedback<T>>,
    on_transition: Option<OnTransition<T>>,
    send_cancel_handler: OnSendCancel,
    state: Arc<Mutex<State>>,
    latest_goal_status: GoalStatus,
    latest_result: Option<ResultType<T>>,
}

impl<T: Action> CommStateMachine<T> {
    pub(crate) fn new(action_goal: GoalType<T>, send_cancel_handler: OnSendCancel) -> Self {
        Self {
            action_goal,
            send_cancel_handler,
            state: Arc::new(Mutex::new(State::WaitingForGoalAck)),
            latest_goal_status: GoalStatus::default(),
            on_feedback: None,
            on_transition: None,
            latest_result: None,
        }
    }

    pub(crate) fn register_on_feedback(&mut self, f: OnFeedback<T>) {
        self.on_feedback = Some(f);
    }

    pub(crate) fn register_on_transition(&mut self, f: OnTransition<T>) {
        self.on_transition = Some(f);
    }

    #[inline]
    pub fn send_cancel(&self, msg: GoalID) {
        (*self.send_cancel_handler)(msg);
    }

    #[inline]
    pub fn action_goal(&self) -> &GoalType<T> {
        &self.action_goal
    }

    #[inline]
    pub fn state(&self) -> State {
        *self.state.lock().expect(MUTEX_LOCK_FAIL)
    }

    #[inline]
    pub fn latest_goal_status(&self) -> &GoalStatus {
        &self.latest_goal_status
    }

    #[inline]
    pub fn latest_result(&self) -> &Option<ResultType<T>> {
        &self.latest_result
    }

    pub fn transition_to(&self, state: State) {
        {
            let mut state_lock = self.state.lock().expect(MUTEX_LOCK_FAIL);
            rosrust::ros_debug!(
                "Transitioning to {:?} (from {:?}, goal: {})",
                state,
                *state_lock,
                self.action_goal.id.id,
            );
            *state_lock = state;
        }

        if let Some(on_transition) = &self.on_transition {
            on_transition(SyncClientGoalHandle::new(self))
        }
    }

    pub fn update_feedback(&mut self, action_feedback: &FeedbackType<T>) {
        if self.action_goal.id.id != action_feedback.status.goal_id.id {
            return;
        }

        if self.state() == State::Done {
            return;
        }

        if let Some(on_feedback) = &self.on_feedback {
            on_feedback(
                SyncClientGoalHandle::new(self),
                action_feedback.body.clone(),
            )
        }
    }

    pub fn update_result(&mut self, action_result: &ResultType<T>) {
        if self.action_goal.id.id != action_result.status.goal_id.id {
            return;
        }

        let status = action_result.status.clone();

        self.latest_goal_status = status.clone();
        self.latest_result = Some(action_result.clone());

        match self.state() {
            State::WaitingForGoalAck
            | State::Pending
            | State::Active
            | State::WaitingForResult
            | State::WaitingForCancelAck
            | State::Recalling
            | State::Preempting => {
                let mut status_array = GoalStatusArray::default();
                status_array.status_list.push(status.into());
                self.update_status(&status_array);
                self.transition_to(State::Done);
            }
            State::Done => {
                rosrust::ros_err!("Got a result when we were already in the DONE state");
            }
            State::Lost => {
                rosrust::ros_err!("In a funny state: Lost");
            }
        };
    }

    fn update_status_inner(
        &mut self,
        status_array: &GoalStatusArray,
    ) -> Result<(), Option<String>> {
        use std::convert::TryInto;

        if self.state() == State::Done {
            return Err(None);
        }
        let status = status_array
            .status_list
            .iter()
            .find(|status| status.goal_id.id == self.action_goal.id.id)
            .cloned()
            .ok_or_else(|| {
                match self.state() {
                    State::Pending
                    | State::Active
                    | State::WaitingForCancelAck
                    | State::Recalling
                    | State::Preempting
                    | State::Lost => self.mark_as_lost(),
                    State::WaitingForGoalAck | State::WaitingForResult | State::Done => {}
                }
                None
            })?;

        let goal_state = status
            .status
            .try_into()
            .map_err(|err| format!("Got an unknown status from the ActionServer: {}", err))?;

        self.latest_goal_status = status.into();

        let steps = self
            .state
            .lock()
            .expect(MUTEX_LOCK_FAIL)
            .transition_to(goal_state)
            .into_update_status_steps()?;

        for step in steps {
            self.transition_to(*step);
        }

        Ok(())
    }

    pub fn update_status(&mut self, status_array: &GoalStatusArray) {
        if let Err(Some(err)) = self.update_status_inner(status_array) {
            rosrust::ros_err!("{}", err);
        }
    }

    fn mark_as_lost(&mut self) {
        self.latest_goal_status.state = GoalState::Lost;
        self.transition_to(State::Done);
    }
}

// TODO: consider removing "Lost"
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum State {
    WaitingForGoalAck,
    Pending,
    Active,
    WaitingForResult,
    WaitingForCancelAck,
    Recalling,
    Preempting,
    Done,
    Lost,
}

#[derive(Clone, Debug)]
pub enum Transition {
    NoTransition,
    Invalid(State, GoalState),
    FunnyState(State),
    UnknownStatus(GoalState),
    Steps(&'static [State]),
}

impl Transition {
    fn into_update_status_steps(self) -> Result<&'static [State], String> {
        match self {
            Transition::NoTransition => Ok(&[]),
            Transition::Invalid(state, goal_state) => Err(format!(
                "Invalid goal status transition from {:?} to {:?}",
                state, goal_state,
            )),
            Transition::FunnyState(state) => {
                Err(format!("CommStateMachine is in a funny state: {:?}", state))
            }
            Transition::UnknownStatus(goal_state) => Err(format!(
                "Got an unknown status from the ActionServer: {:?}",
                goal_state,
            )),
            Transition::Steps(steps) => Ok(steps),
        }
    }
}

impl State {
    pub fn transition_to(self, goal: GoalState) -> Transition {
        match self {
            State::WaitingForGoalAck => match goal {
                GoalState::Pending => Transition::Steps(&[State::Pending]),
                GoalState::Active => Transition::Steps(&[State::Active]),
                GoalState::Rejected => {
                    Transition::Steps(&[State::Pending, State::WaitingForResult])
                }
                GoalState::Recalling => Transition::Steps(&[State::Pending, State::Recalling]),
                GoalState::Recalled => {
                    Transition::Steps(&[State::Pending, State::WaitingForResult])
                }
                GoalState::Preempted => {
                    Transition::Steps(&[State::Active, State::Preempting, State::WaitingForResult])
                }
                GoalState::Succeeded => {
                    Transition::Steps(&[State::Active, State::WaitingForResult])
                }
                GoalState::Aborted => Transition::Steps(&[State::Active, State::WaitingForResult]),
                GoalState::Preempting => Transition::Steps(&[State::Active, State::Preempting]),
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::Pending => match goal {
                GoalState::Pending => Transition::NoTransition,
                GoalState::Active => Transition::Steps(&[State::Active]),
                GoalState::Rejected => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Recalling => Transition::Steps(&[State::Recalling]),
                GoalState::Recalled => {
                    Transition::Steps(&[State::Recalling, State::WaitingForResult])
                }
                GoalState::Preempted => {
                    Transition::Steps(&[State::Active, State::Preempting, State::WaitingForResult])
                }
                GoalState::Succeeded => {
                    Transition::Steps(&[State::Active, State::WaitingForResult])
                }
                GoalState::Aborted => Transition::Steps(&[State::Active, State::WaitingForResult]),
                GoalState::Preempting => Transition::Steps(&[State::Active, State::Preempting]),
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::Active => match goal {
                GoalState::Pending => Transition::Invalid(self, goal),
                GoalState::Active => Transition::NoTransition,
                GoalState::Rejected => Transition::Invalid(self, goal),
                GoalState::Recalling => Transition::Invalid(self, goal),
                GoalState::Recalled => Transition::Invalid(self, goal),
                GoalState::Preempted => {
                    Transition::Steps(&[State::Preempting, State::WaitingForResult])
                }
                GoalState::Succeeded => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Aborted => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Preempting => Transition::Steps(&[State::Preempting]),
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::WaitingForResult => match goal {
                GoalState::Pending => Transition::Invalid(self, goal),
                GoalState::Active => Transition::NoTransition,
                GoalState::Rejected => Transition::NoTransition,
                GoalState::Recalling => Transition::Invalid(self, goal),
                GoalState::Recalled => Transition::NoTransition,
                GoalState::Preempted => Transition::NoTransition,
                GoalState::Succeeded => Transition::NoTransition,
                GoalState::Aborted => Transition::NoTransition,
                GoalState::Preempting => Transition::Invalid(self, goal),
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::WaitingForCancelAck => match goal {
                GoalState::Pending => Transition::NoTransition,
                GoalState::Active => Transition::NoTransition,
                GoalState::Rejected => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Recalling => Transition::Steps(&[State::Recalling]),
                GoalState::Recalled => {
                    Transition::Steps(&[State::Recalling, State::WaitingForResult])
                }
                GoalState::Preempted => {
                    Transition::Steps(&[State::Preempting, State::WaitingForResult])
                }
                GoalState::Succeeded => {
                    Transition::Steps(&[State::Preempting, State::WaitingForResult])
                }
                GoalState::Aborted => {
                    Transition::Steps(&[State::Preempting, State::WaitingForResult])
                }
                GoalState::Preempting => Transition::Steps(&[State::Preempting]),
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::Recalling => match goal {
                GoalState::Pending => Transition::Invalid(self, goal),
                GoalState::Active => Transition::Invalid(self, goal),
                GoalState::Rejected => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Recalling => Transition::NoTransition,
                GoalState::Recalled => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Preempted => {
                    Transition::Steps(&[State::Preempting, State::WaitingForResult])
                }
                GoalState::Succeeded => {
                    Transition::Steps(&[State::Preempting, State::WaitingForResult])
                }
                GoalState::Aborted => {
                    Transition::Steps(&[State::Preempting, State::WaitingForResult])
                }
                GoalState::Preempting => Transition::Steps(&[State::Preempting]),
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::Preempting => match goal {
                GoalState::Pending => Transition::Invalid(self, goal),
                GoalState::Active => Transition::Invalid(self, goal),
                GoalState::Rejected => Transition::Invalid(self, goal),
                GoalState::Recalling => Transition::Invalid(self, goal),
                GoalState::Recalled => Transition::Invalid(self, goal),
                GoalState::Preempted => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Succeeded => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Aborted => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Preempting => Transition::NoTransition,
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::Done => match goal {
                GoalState::Pending => Transition::Invalid(self, goal),
                GoalState::Active => Transition::Invalid(self, goal),
                GoalState::Rejected => Transition::NoTransition,
                GoalState::Recalling => Transition::Invalid(self, goal),
                GoalState::Recalled => Transition::NoTransition,
                GoalState::Preempted => Transition::NoTransition,
                GoalState::Succeeded => Transition::NoTransition,
                GoalState::Aborted => Transition::NoTransition,
                GoalState::Preempting => Transition::Invalid(self, goal),
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::Lost => Transition::FunnyState(State::Lost),
        }
    }
}
<commit_msg>Make action client comm state lock-free<commit_after>use crate::action_client::{OnFeedback, OnTransition};
use crate::msg::actionlib_msgs::GoalStatusArray;
use crate::{Action, FeedbackType, GoalType, ResultType, SyncClientGoalHandle};
use crate::{GoalID, GoalState, GoalStatus};
use std::cell::Cell;
use std::sync::Arc;

pub type OnSendGoal<T> = Arc<dyn Fn(<T as Action>::Goal) + Send + Sync + 'static>;
pub type OnSendCancel = Arc<dyn Fn(GoalID) + Send + Sync + 'static>;

pub struct CommStateMachine<T: Action> {
    action_goal: GoalType<T>,
    on_feedback: Option<OnFeedback<T>>,
    on_transition: Option<OnTransition<T>>,
    send_cancel_handler: OnSendCancel,
    state: Cell<State>,
    latest_goal_status: GoalStatus,
    latest_result: Option<ResultType<T>>,
}

impl<T: Action> CommStateMachine<T> {
    pub(crate) fn new(action_goal: GoalType<T>, send_cancel_handler: OnSendCancel) -> Self {
        Self {
            action_goal,
            send_cancel_handler,
            state: Cell::new(State::WaitingForGoalAck),
            latest_goal_status: GoalStatus::default(),
            on_feedback: None,
            on_transition: None,
            latest_result: None,
        }
    }

    pub(crate) fn register_on_feedback(&mut self, f: OnFeedback<T>) {
        self.on_feedback = Some(f);
    }

    pub(crate) fn register_on_transition(&mut self, f: OnTransition<T>) {
        self.on_transition = Some(f);
    }

    #[inline]
    pub fn send_cancel(&self, msg: GoalID) {
        (*self.send_cancel_handler)(msg);
    }

    #[inline]
    pub fn action_goal(&self) -> &GoalType<T> {
        &self.action_goal
    }

    #[inline]
    pub fn state(&self) -> State {
        self.state.get()
    }

    #[inline]
    pub fn latest_goal_status(&self) -> &GoalStatus {
        &self.latest_goal_status
    }

    #[inline]
    pub fn latest_result(&self) -> &Option<ResultType<T>> {
        &self.latest_result
    }

    pub fn transition_to(&self, state: State) {
        let old_state = self.state.replace(state);
        rosrust::ros_debug!(
            "Transitioning to {:?} (from {:?}, goal: {})",
            state,
            old_state,
            self.action_goal.id.id,
        );

        if let Some(on_transition) = &self.on_transition {
            on_transition(SyncClientGoalHandle::new(self))
        }
    }

    pub fn update_feedback(&mut self, action_feedback: &FeedbackType<T>) {
        if self.action_goal.id.id != action_feedback.status.goal_id.id {
            return;
        }

        if self.state() == State::Done {
            return;
        }

        if let Some(on_feedback) = &self.on_feedback {
            on_feedback(
                SyncClientGoalHandle::new(self),
                action_feedback.body.clone(),
            )
        }
    }

    pub fn update_result(&mut self, action_result: &ResultType<T>) {
        if self.action_goal.id.id != action_result.status.goal_id.id {
            return;
        }

        let status = action_result.status.clone();

        self.latest_goal_status = status.clone();
        self.latest_result = Some(action_result.clone());

        match self.state() {
            State::WaitingForGoalAck
            | State::Pending
            | State::Active
            | State::WaitingForResult
            | State::WaitingForCancelAck
            | State::Recalling
            | State::Preempting => {
                let mut status_array = GoalStatusArray::default();
                status_array.status_list.push(status.into());
                self.update_status(&status_array);
                self.transition_to(State::Done);
            }
            State::Done => {
                rosrust::ros_err!("Got a result when we were already in the DONE state");
            }
            State::Lost => {
                rosrust::ros_err!("In a funny state: Lost");
            }
        };
    }

    fn update_status_inner(
        &mut self,
        status_array: &GoalStatusArray,
    ) -> Result<(), Option<String>> {
        use std::convert::TryInto;

        if self.state() == State::Done {
            return Err(None);
        }
        let status = status_array
            .status_list
            .iter()
            .find(|status| status.goal_id.id == self.action_goal.id.id)
            .cloned()
            .ok_or_else(|| {
                match self.state() {
                    State::Pending
                    | State::Active
                    | State::WaitingForCancelAck
                    | State::Recalling
                    | State::Preempting
                    | State::Lost => self.mark_as_lost(),
                    State::WaitingForGoalAck | State::WaitingForResult | State::Done => {}
                }
                None
            })?;

        let goal_state = status
            .status
            .try_into()
            .map_err(|err| format!("Got an unknown status from the ActionServer: {}", err))?;

        self.latest_goal_status = status.into();

        let steps = self
            .state
            .get()
            .transition_to(goal_state)
            .into_update_status_steps()?;

        for step in steps {
            self.transition_to(*step);
        }

        Ok(())
    }

    pub fn update_status(&mut self, status_array: &GoalStatusArray) {
        if let Err(Some(err)) = self.update_status_inner(status_array) {
            rosrust::ros_err!("{}", err);
        }
    }

    fn mark_as_lost(&mut self) {
        self.latest_goal_status.state = GoalState::Lost;
        self.transition_to(State::Done);
    }
}

// TODO: consider removing "Lost"
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum State {
    WaitingForGoalAck,
    Pending,
    Active,
    WaitingForResult,
    WaitingForCancelAck,
    Recalling,
    Preempting,
    Done,
    Lost,
}

#[derive(Clone, Debug)]
pub enum Transition {
    NoTransition,
    Invalid(State, GoalState),
    FunnyState(State),
    UnknownStatus(GoalState),
    Steps(&'static [State]),
}

impl Transition {
    fn into_update_status_steps(self) -> Result<&'static [State], String> {
        match self {
            Transition::NoTransition => Ok(&[]),
            Transition::Invalid(state, goal_state) => Err(format!(
                "Invalid goal status transition from {:?} to {:?}",
                state, goal_state,
            )),
            Transition::FunnyState(state) => {
                Err(format!("CommStateMachine is in a funny state: {:?}", state))
            }
            Transition::UnknownStatus(goal_state) => Err(format!(
                "Got an unknown status from the ActionServer: {:?}",
                goal_state,
            )),
            Transition::Steps(steps) => Ok(steps),
        }
    }
}

impl State {
    pub fn transition_to(self, goal: GoalState) -> Transition {
        match self {
            State::WaitingForGoalAck => match goal {
                GoalState::Pending => Transition::Steps(&[State::Pending]),
                GoalState::Active => Transition::Steps(&[State::Active]),
                GoalState::Rejected => {
                    Transition::Steps(&[State::Pending, State::WaitingForResult])
                }
                GoalState::Recalling => Transition::Steps(&[State::Pending, State::Recalling]),
                GoalState::Recalled => {
                    Transition::Steps(&[State::Pending, State::WaitingForResult])
                }
                GoalState::Preempted => {
                    Transition::Steps(&[State::Active, State::Preempting, State::WaitingForResult])
                }
                GoalState::Succeeded => {
                    Transition::Steps(&[State::Active, State::WaitingForResult])
                }
                GoalState::Aborted => Transition::Steps(&[State::Active, State::WaitingForResult]),
                GoalState::Preempting => Transition::Steps(&[State::Active, State::Preempting]),
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::Pending => match goal {
                GoalState::Pending => Transition::NoTransition,
                GoalState::Active => Transition::Steps(&[State::Active]),
                GoalState::Rejected => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Recalling => Transition::Steps(&[State::Recalling]),
                GoalState::Recalled => {
                    Transition::Steps(&[State::Recalling, State::WaitingForResult])
                }
                GoalState::Preempted => {
                    Transition::Steps(&[State::Active, State::Preempting, State::WaitingForResult])
                }
                GoalState::Succeeded => {
                    Transition::Steps(&[State::Active, State::WaitingForResult])
                }
                GoalState::Aborted => Transition::Steps(&[State::Active, State::WaitingForResult]),
                GoalState::Preempting => Transition::Steps(&[State::Active, State::Preempting]),
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::Active => match goal {
                GoalState::Pending => Transition::Invalid(self, goal),
                GoalState::Active => Transition::NoTransition,
                GoalState::Rejected => Transition::Invalid(self, goal),
                GoalState::Recalling => Transition::Invalid(self, goal),
                GoalState::Recalled => Transition::Invalid(self, goal),
                GoalState::Preempted => {
                    Transition::Steps(&[State::Preempting, State::WaitingForResult])
                }
                GoalState::Succeeded => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Aborted => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Preempting => Transition::Steps(&[State::Preempting]),
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::WaitingForResult => match goal {
                GoalState::Pending => Transition::Invalid(self, goal),
                GoalState::Active => Transition::NoTransition,
                GoalState::Rejected => Transition::NoTransition,
                GoalState::Recalling => Transition::Invalid(self, goal),
                GoalState::Recalled => Transition::NoTransition,
                GoalState::Preempted => Transition::NoTransition,
                GoalState::Succeeded => Transition::NoTransition,
                GoalState::Aborted => Transition::NoTransition,
                GoalState::Preempting => Transition::Invalid(self, goal),
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::WaitingForCancelAck => match goal {
                GoalState::Pending => Transition::NoTransition,
                GoalState::Active => Transition::NoTransition,
                GoalState::Rejected => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Recalling => Transition::Steps(&[State::Recalling]),
                GoalState::Recalled => {
                    Transition::Steps(&[State::Recalling, State::WaitingForResult])
                }
                GoalState::Preempted => {
                    Transition::Steps(&[State::Preempting, State::WaitingForResult])
                }
                GoalState::Succeeded => {
                    Transition::Steps(&[State::Preempting, State::WaitingForResult])
                }
                GoalState::Aborted => {
                    Transition::Steps(&[State::Preempting, State::WaitingForResult])
                }
                GoalState::Preempting => Transition::Steps(&[State::Preempting]),
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::Recalling => match goal {
                GoalState::Pending => Transition::Invalid(self, goal),
                GoalState::Active => Transition::Invalid(self, goal),
                GoalState::Rejected => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Recalling => Transition::NoTransition,
                GoalState::Recalled => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Preempted => {
                    Transition::Steps(&[State::Preempting, State::WaitingForResult])
                }
                GoalState::Succeeded => {
                    Transition::Steps(&[State::Preempting, State::WaitingForResult])
                }
                GoalState::Aborted => {
                    Transition::Steps(&[State::Preempting, State::WaitingForResult])
                }
                GoalState::Preempting => Transition::Steps(&[State::Preempting]),
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::Preempting => match goal {
                GoalState::Pending => Transition::Invalid(self, goal),
                GoalState::Active => Transition::Invalid(self, goal),
                GoalState::Rejected => Transition::Invalid(self, goal),
                GoalState::Recalling => Transition::Invalid(self, goal),
                GoalState::Recalled => Transition::Invalid(self, goal),
                GoalState::Preempted => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Succeeded => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Aborted => Transition::Steps(&[State::WaitingForResult]),
                GoalState::Preempting => Transition::NoTransition,
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::Done => match goal {
                GoalState::Pending => Transition::Invalid(self, goal),
                GoalState::Active => Transition::Invalid(self, goal),
                GoalState::Rejected => Transition::NoTransition,
                GoalState::Recalling => Transition::Invalid(self, goal),
                GoalState::Recalled => Transition::NoTransition,
                GoalState::Preempted => Transition::NoTransition,
                GoalState::Succeeded => Transition::NoTransition,
                GoalState::Aborted => Transition::NoTransition,
                GoalState::Preempting => Transition::Invalid(self, goal),
                GoalState::Lost => Transition::UnknownStatus(GoalState::Lost),
            },
            State::Lost => Transition::FunnyState(State::Lost),
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
    "hello".to_string(); // implicit dispatch

    // Group of `qualified` methods:
    str::to_string("hello"); // explicit dispatch by struct
    ToString::to_string("hello"); // explicit dispatch by trait

    // `Fully qualified` method call ()
    <str as ToString>::to_string("hello"); // wow!
}
<commit_msg>[rust] just tweaked a couple of comments<commit_after>fn main() {
    // Implicit dispatch
    "hello".to_string();

    // Group of `qualified` methods:

    // Explicit dispatch by struct
    str::to_string("hello");

    // Explicit dispatch by Trait
    ToString::to_string("hello");

    // `Fully qualified` method call
    <str as ToString>::to_string("hello");
}
<|endoftext|>


<commit_before>use kernel32;
use shell32;
use std;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use std::thread;
use std::time;
use user32;
use uuid;
use winapi;

const IDI_POLARIS: isize = 0x101;

pub trait ToWin {
    type Out;
    fn to_win(&self) -> Self::Out;
}

impl<'a> ToWin for &'a str {
    type Out = Vec<u16>;

    fn to_win(&self) -> Self::Out {
        OsStr::new(self)
            .encode_wide()
            .chain(std::iter::once(0))
            .collect()
    }
}

impl ToWin for uuid::Uuid {
    type Out = winapi::GUID;

    fn to_win(&self) -> Self::Out {
        let bytes = self.as_bytes();
        let end = [bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14],
                   bytes[15]];

        winapi::GUID {
            Data1: ((bytes[0] as u32) << 24 | (bytes[1] as u32) << 16 | (bytes[2] as u32) << 8 |
                    (bytes[3] as u32)),
            Data2: ((bytes[4] as u16) << 8 | (bytes[5] as u16)),
            Data3: ((bytes[6] as u16) << 8 | (bytes[7] as u16)),
            Data4: end,
        }
    }
}

fn create_window() -> Option<winapi::HWND> {

    let class_name = "Polaris-class".to_win();
	let window_name = "Polaris-window".to_win();

	unsafe {
		let module_handle = kernel32::GetModuleHandleW(std::ptr::null());
		let wnd = winapi::WNDCLASSW {
			style: 0,
			lpfnWndProc: Some(window_proc),
			hInstance: module_handle,
			hIcon: std::ptr::null_mut(),
			hCursor: std::ptr::null_mut(),
			lpszClassName: class_name.as_ptr(),
			hbrBackground: winapi::COLOR_WINDOW as winapi::HBRUSH,
			lpszMenuName: std::ptr::null_mut(),
			cbClsExtra: 0,
			cbWndExtra: 0,
		};

		let atom = user32::RegisterClassW(&wnd);
		if atom == 0 {
			return None;
		}

		let window_handle = user32::CreateWindowExW(0,
													atom as winapi::LPCWSTR,
													window_name.as_ptr(),
													winapi::WS_DISABLED,
													0,
													0,
													0,
													0,
													user32::GetDesktopWindow(),
													std::ptr::null_mut(),
													std::ptr::null_mut(),
													std::ptr::null_mut());

		if window_handle.is_null() {
			return None;
		}

	    return Some(window_handle);
	}
}

fn add_notification_icon(window_handle: winapi::HWND, id: winapi::GUID) {
	unsafe {
		let module = kernel32::GetModuleHandleW(std::ptr::null());
		let icon = user32::LoadIconW(module, std::mem::transmute(IDI_POLARIS));
		assert!(!icon.is_null());

		let mut icon_data = winapi::NOTIFYICONDATAW {
			cbSize: std::mem::size_of::<winapi::NOTIFYICONDATAW>() as u32,
			hWnd: window_handle,
			uFlags: winapi::NIF_ICON | winapi::NIF_GUID,
			guidItem: id,
			hIcon: icon,
			uID: 0,
			uCallbackMessage: 0,
			szTip: [0; 128],
			dwState: 0,
			dwStateMask: 0,
			szInfo: [0; 256],
			uTimeout: 0,
			szInfoTitle: [0; 64],
			dwInfoFlags: 0,
			hBalloonIcon: std::ptr::null_mut(),
		};

		shell32::Shell_NotifyIconW(winapi::NIM_ADD, &mut icon_data);
	}
}

pub fn run() {
	println!("Starting up UI (Windows)");

    let path = std::env::current_exe().expect("Could not get current path");
    let guid = uuid::Uuid::new_v5(&uuid::NAMESPACE_OID, path.to_str().unwrap()).to_win();
    let window_handle = create_window().expect("Could not initialize window");
    add_notification_icon(window_handle, guid);

    loop {
        thread::sleep(time::Duration::from_secs(10));
    }
}

pub unsafe extern "system" fn window_proc(h_wnd: winapi::HWND,
                                          msg: winapi::UINT,
                                          w_param: winapi::WPARAM,
                                          l_param: winapi::LPARAM)
                                          -> winapi::LRESULT {
    if msg == winapi::winuser::WM_DESTROY {
        user32::PostQuitMessage(0);
    }
    return user32::DefWindowProcW(h_wnd, msg, w_param, l_param);
}
<commit_msg>Added context menu with Quit option<commit_after>use kernel32;
use shell32;
use std;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use user32;
use uuid;
use winapi;

const IDI_POLARIS: isize = 0x101;
const UID_NOTIFICATION_ICON: u32 = 0;
const MESSAGE_NOTIFICATION_ICON: u32 = winapi::WM_USER + 1;
const MESSAGE_NOTIFICATION_ICON_QUIT: u32 = winapi::WM_USER + 2;

pub trait ToWin {
    type Out;
    fn to_win(&self) -> Self::Out;
}

impl<'a> ToWin for &'a str {
    type Out = Vec<u16>;

    fn to_win(&self) -> Self::Out {
        OsStr::new(self)
            .encode_wide()
            .chain(std::iter::once(0))
            .collect()
    }
}

impl ToWin for uuid::Uuid {
    type Out = winapi::GUID;

    fn to_win(&self) -> Self::Out {
        let bytes = self.as_bytes();
        let end = [bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14],
                   bytes[15]];

        winapi::GUID {
            Data1: ((bytes[0] as u32) << 24 | (bytes[1] as u32) << 16 | (bytes[2] as u32) << 8 |
                    (bytes[3] as u32)),
            Data2: ((bytes[4] as u16) << 8 | (bytes[5] as u16)),
            Data3: ((bytes[6] as u16) << 8 | (bytes[7] as u16)),
            Data4: end,
        }
    }
}

pub trait Constructible {
    type Out;
    fn new() -> Self::Out;
}

impl Constructible for winapi::NOTIFYICONDATAW {
    type Out = winapi::NOTIFYICONDATAW;

    fn new() -> Self::Out {
        winapi::NOTIFYICONDATAW {
            cbSize: std::mem::size_of::<winapi::NOTIFYICONDATAW>() as u32,
            hWnd: std::ptr::null_mut(),
            uFlags: 0,
            guidItem: uuid::Uuid::nil().to_win(),
            hIcon: std::ptr::null_mut(),
            uID: 0,
            uCallbackMessage: 0,
            szTip: [0; 128],
            dwState: 0,
            dwStateMask: 0,
            szInfo: [0; 256],
            uTimeout: winapi::NOTIFYICON_VERSION_4,
            szInfoTitle: [0; 64],
            dwInfoFlags: 0,
            hBalloonIcon: std::ptr::null_mut(),
        }
    }
}

fn create_window() -> Option<winapi::HWND> {

    let class_name = "Polaris-class".to_win();
    let window_name = "Polaris-window".to_win();

    unsafe {
        let module_handle = kernel32::GetModuleHandleW(std::ptr::null());
        let wnd = winapi::WNDCLASSW {
            style: 0,
            lpfnWndProc: Some(window_proc),
            hInstance: module_handle,
            hIcon: std::ptr::null_mut(),
            hCursor: std::ptr::null_mut(),
            lpszClassName: class_name.as_ptr(),
            hbrBackground: winapi::COLOR_WINDOW as winapi::HBRUSH,
            lpszMenuName: std::ptr::null_mut(),
            cbClsExtra: 0,
            cbWndExtra: 0,
        };

        let atom = user32::RegisterClassW(&wnd);
        if atom == 0 {
            return None;
        }

        let window_handle = user32::CreateWindowExW(0,
                                                    atom as winapi::LPCWSTR,
                                                    window_name.as_ptr(),
                                                    winapi::WS_DISABLED,
                                                    0,
                                                    0,
                                                    0,
                                                    0,
                                                    user32::GetDesktopWindow(),
                                                    std::ptr::null_mut(),
                                                    std::ptr::null_mut(),
                                                    std::ptr::null_mut());

        if window_handle.is_null() {
            return None;
        }

        return Some(window_handle);
    }
}

fn add_notification_icon(window: winapi::HWND) {

    let mut tooltip = [0 as winapi::WCHAR; 128];
    for (&x, p) in "Polaris".to_win().iter().zip(tooltip.iter_mut()) {
        *p = x;
    }

    unsafe {
        let module = kernel32::GetModuleHandleW(std::ptr::null());
        let icon = user32::LoadIconW(module, std::mem::transmute(IDI_POLARIS));
        let mut flags = winapi::NIF_MESSAGE | winapi::NIF_TIP;
        if !icon.is_null() {
            flags |= winapi::NIF_ICON;
        }

        let mut icon_data = winapi::NOTIFYICONDATAW::new();
        icon_data.hWnd = window;
        icon_data.uID = UID_NOTIFICATION_ICON;
        icon_data.uFlags = flags;
        icon_data.hIcon = icon;
        icon_data.uCallbackMessage = MESSAGE_NOTIFICATION_ICON;
        icon_data.szTip = tooltip;

        shell32::Shell_NotifyIconW(winapi::NIM_ADD, &mut icon_data);
    }
}

fn remove_notification_icon(window: winapi::HWND) {
    let mut icon_data = winapi::NOTIFYICONDATAW::new();
    icon_data.hWnd = window;
    icon_data.uID = UID_NOTIFICATION_ICON;
    unsafe {
        shell32::Shell_NotifyIconW(winapi::NIM_DELETE, &mut icon_data);
    }
}

fn open_notification_context_menu(window: winapi::HWND) {
    println!("Opening notification icon context menu");
    let quit_string = "Quit Polaris".to_win();

    unsafe {
        let context_menu = user32::CreatePopupMenu();
        if context_menu.is_null() {
            return;
        }
        user32::InsertMenuW(context_menu,
                            0,
                            winapi::winuser::MF_STRING,
                            MESSAGE_NOTIFICATION_ICON_QUIT as u64,
                            quit_string.as_ptr());

        let mut cursor_position = winapi::POINT { x: 0, y: 0 };
        user32::GetCursorPos(&mut cursor_position);

        user32::SetForegroundWindow(window);
        let flags = winapi::winuser::TPM_RIGHTALIGN | winapi::winuser::TPM_BOTTOMALIGN |
                    winapi::winuser::TPM_RIGHTBUTTON;
        user32::TrackPopupMenu(context_menu,
                               flags,
                               cursor_position.x,
                               cursor_position.y,
                               0,
                               window,
                               std::ptr::null_mut());
        user32::PostMessageW(window, 0, 0, 0);

        println!("Closing notification context menu");
        user32::DestroyMenu(context_menu);
    }
}

fn quit(window: winapi::HWND) {
    println!("Shutting down UI");
    unsafe {
        user32::PostMessageW(window, winapi::winuser::WM_CLOSE, 0, 0);
    }
}

pub fn run() {
    println!("Starting up UI (Windows)");

    create_window().expect("Could not initialize window");

    let mut message = winapi::MSG {
        hwnd: std::ptr::null_mut(),
        message: 0,
        wParam: 0,
        lParam: 0,
        time: 0,
        pt: winapi::POINT { x: 0, y: 0 },
    };

    loop {
        let status: i32;
        unsafe {
            status = user32::GetMessageW(&mut message, std::ptr::null_mut(), 0, 0);
            if status == -1 {
                panic!("GetMessageW error: {}", kernel32::GetLastError());
            }
            if status == 0 {
                break;
            }
            user32::TranslateMessage(&message);
            user32::DispatchMessageW(&message);
        }
    }
}

pub unsafe extern "system" fn window_proc(window: winapi::HWND,
                                          msg: winapi::UINT,
                                          w_param: winapi::WPARAM,
                                          l_param: winapi::LPARAM)
                                          -> winapi::LRESULT {
    match msg {

        winapi::winuser::WM_CREATE => {
            add_notification_icon(window);
        }

        MESSAGE_NOTIFICATION_ICON => {
            match winapi::LOWORD(l_param as winapi::DWORD) as u32 {
                winapi::winuser::WM_RBUTTONUP => {
                    open_notification_context_menu(window);
                }
                _ => (),
            }
        }

        winapi::winuser::WM_COMMAND => {
            match winapi::LOWORD(w_param as winapi::DWORD) as u32 {
                MESSAGE_NOTIFICATION_ICON_QUIT => {
                    quit(window);
                }
                _ => (),
            }
        }

        winapi::winuser::WM_DESTROY => {
            remove_notification_icon(window);
            user32::PostQuitMessage(0);
        }

        _ => (),
    };

    return user32::DefWindowProcW(window, msg, w_param, l_param);
}
<|endoftext|>


<commit_before>/*! Thread-safe FitsFile struct */

#![warn(missing_docs)]

use errors::Result;
use fitsfile::FitsFile;
use hdu::{DescribesHdu, FitsHdu};
use std::path::Path;
use std::sync::{Arc, Mutex};

#[derive(Clone)]
pub struct ThreadsafeFitsfile(Arc<Mutex<FitsFile>>);

unsafe impl Send for ThreadsafeFitsfile {}

impl FitsFile {
    pub fn threadsafe(self) -> ThreadsafeFitsfile {
        ThreadsafeFitsfile(Arc::new(Mutex::new(self)))
    }
}

impl ThreadsafeFitsfile {
    pub fn hdu<T: DescribesHdu>(&mut self, hdu_description: T) -> Result<FitsHdu> {
        FitsHdu::new(&mut *self.0.lock()?, hdu_description)
    }
}

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

    #[test]
    fn test_using_other_threads() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let f = f.threadsafe();

        /* Spawn loads of threads... */
        for _ in 0..10_000 {
            let mut f1 = f.clone();
            thread::spawn(move || {
                let hdu = f1.hdu(0).unwrap();
                let mut ff = f1.0.lock().unwrap();
                let image: Vec<i32> = hdu.read_image(&mut ff).unwrap();
                assert_eq!(image.len(), 10_000);
            });
        }
    }
}
<commit_msg>Add documentation<commit_after>/*! Thread-safe FitsFile struct */

use errors::Result;
use fitsfile::FitsFile;
use std::sync::{Arc, Mutex, MutexGuard};

/** Thread-safe [`FitsFile`][fits-file] representation.

This struct wraps an `Arc<Mutex<FitsFile>>` and implements `Send`.

To get a [`ThreadsafeFitsfile`][threadsafe-fitsfile] from a [`FitsFile`][fits-file], call the
[`threadsafe`][fits-file-threadsafe] method.

[fits-file]: ../fitsfile/struct.FitsFile.html
[threadsafe-fitsfile]: struct.ThreadsafeFitsFile.html
[fits-file-threadsafe]: ../fitsfile/struct.FitsFile.html#method.threadsafe
*/
#[derive(Clone)]
pub struct ThreadsafeFitsFile(Arc<Mutex<FitsFile>>);

/* Ensure that the new struct is safe to send to other threads */
unsafe impl Send for ThreadsafeFitsFile {}

impl FitsFile {
    /**
    Create a threadsafe [`ThreadsafeFitsFile`][threadsafe-fitsfile] copy of the current
    [`FitsFile`][fits-file].

    [threadsafe-fitsfile]: struct.ThreadsafeFitsFile.html
    [fits-file]: ../fitsfile/struct.FitsFile.html
     */
    pub fn threadsafe(self) -> ThreadsafeFitsFile {
        ThreadsafeFitsFile(Arc::new(Mutex::new(self)))
    }
}

impl ThreadsafeFitsFile {
    /**
    Lock the underlying mutex to return exclusive access to the FitsFile.
    */
    pub fn lock<'a>(&'a self) -> Result<MutexGuard<'a, FitsFile>> {
        self.0.lock().map_err(From::from)
    }
}

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

    #[test]
    fn test_using_other_threads() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let f = f.threadsafe();

        /* Spawn loads of threads... */
        let mut handles = Vec::new();
        for i in 0..10_000 {
            let mut f1 = f.clone();
            let handle = thread::spawn(move || {
                /* Get the underlyng fits file back */
                let mut t = f1.lock().unwrap();

                /* Fetch a different HDU per thread */
                let hdu_num = i % 2;
                let _hdu = t.hdu(hdu_num).unwrap();
            });
            handles.push(handle);
        }

        /* Wait for all of the threads to finish */
        for handle in handles {
            handle.join().unwrap();
        }
    }
}
<|endoftext|>


<commit_before>use crate::consts::{constant, Constant};
use crate::utils::{is_direct_expn_of, is_expn_of, match_panic_call, snippet_opt, span_lint_and_help};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_hir::{Expr, ExprKind, PatKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Checks for `assert!(true)` and `assert!(false)` calls.
    ///
    /// **Why is this bad?** Will be optimized out by the compiler or should probably be replaced by a
    /// `panic!()` or `unreachable!()`
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```rust,ignore
    /// assert!(false)
    /// assert!(true)
    /// const B: bool = false;
    /// assert!(B)
    /// ```
    pub ASSERTIONS_ON_CONSTANTS,
    style,
    "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`"
}

declare_lint_pass!(AssertionsOnConstants => [ASSERTIONS_ON_CONSTANTS]);

impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        let lint_true = |is_debug: bool| {
            span_lint_and_help(
                cx,
                ASSERTIONS_ON_CONSTANTS,
                e.span,
                if is_debug {
                    "`debug_assert!(true)` will be optimized out by the compiler"
                } else {
                    "`assert!(true)` will be optimized out by the compiler"
                },
                None,
                "remove it",
            );
        };
        let lint_false_without_message = || {
            span_lint_and_help(
                cx,
                ASSERTIONS_ON_CONSTANTS,
                e.span,
                "`assert!(false)` should probably be replaced",
                None,
                "use `panic!()` or `unreachable!()`",
            );
        };
        let lint_false_with_message = |panic_message: String| {
            span_lint_and_help(
                cx,
                ASSERTIONS_ON_CONSTANTS,
                e.span,
                &format!("`assert!(false, {})` should probably be replaced", panic_message),
                None,
                &format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message),
            )
        };

        if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") {
            if debug_assert_span.from_expansion() {
                return;
            }
            if_chain! {
                if let ExprKind::Unary(_, ref lit) = e.kind;
                if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), lit);
                if is_true;
                then {
                    lint_true(true);
                }
            };
        } else if let Some(assert_span) = is_direct_expn_of(e.span, "assert") {
            if assert_span.from_expansion() {
                return;
            }
            if let Some(assert_match) = match_assert_with_message(&cx, e) {
                match assert_match {
                    // matched assert but not message
                    AssertKind::WithoutMessage(false) => lint_false_without_message(),
                    AssertKind::WithoutMessage(true) | AssertKind::WithMessage(_, true) => lint_true(false),
                    AssertKind::WithMessage(panic_message, false) => lint_false_with_message(panic_message),
                };
            }
        }
    }
}

/// Result of calling `match_assert_with_message`.
enum AssertKind {
    WithMessage(String, bool),
    WithoutMessage(bool),
}

/// Check if the expression matches
///
/// ```rust,ignore
/// match { let _t = !c; _t } {
///     true => {
///         {
///             ::std::rt::begin_panic(message, _)
///         }
///     }
///     _ => { }
/// };
/// ```
///
/// where `message` is any expression and `c` is a constant bool.
fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<AssertKind> {
    if_chain! {
        if let ExprKind::Match(ref expr, ref arms, _) = expr.kind;
        // matches { let _t = expr; _t }
        if let ExprKind::DropTemps(ref expr) = expr.kind;
        if let ExprKind::Unary(UnOp::UnNot, ref expr) = expr.kind;
        // bind the first argument of the `assert!` macro
        if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr);
        // arm 1 pattern
        if let PatKind::Lit(ref lit_expr) = arms[0].pat.kind;
        if let ExprKind::Lit(ref lit) = lit_expr.kind;
        if let LitKind::Bool(true) = lit.node;
        // arm 1 block
        if let ExprKind::Block(ref block, _) = arms[0].body.kind;
        if block.stmts.is_empty();
        if let Some(block_expr) = &block.expr;
        // inner block is optional. unwarp it if it exists, or use the expression as is otherwise.
        if let Some(begin_panic_call) = match block_expr.kind {
            ExprKind::Block(ref inner_block, _) => &inner_block.expr,
            _ => &block.expr,
        };
        // function call
        if let Some(args) = match_panic_call(cx, begin_panic_call);
        if args.len() == 1;
        // bind the second argument of the `assert!` macro if it exists
        if let panic_message = snippet_opt(cx, args[0].span);
        // second argument of begin_panic is irrelevant
        // as is the second match arm
        then {
            // an empty message occurs when it was generated by the macro
            // (and not passed by the user)
            return panic_message
                .filter(|msg| !msg.is_empty())
                .map(|msg| AssertKind::WithMessage(msg, is_true))
                .or(Some(AssertKind::WithoutMessage(is_true)));
        }
    }
    None
}
<commit_msg>Auto merge of #6363 - o752d:patch-2, r=flip1995<commit_after>use crate::consts::{constant, Constant};
use crate::utils::{is_direct_expn_of, is_expn_of, match_panic_call, snippet_opt, span_lint_and_help};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_hir::{Expr, ExprKind, PatKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Checks for `assert!(true)` and `assert!(false)` calls.
    ///
    /// **Why is this bad?** Will be optimized out by the compiler or should probably be replaced by a
    /// `panic!()` or `unreachable!()`
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```rust,ignore
    /// assert!(false)
    /// assert!(true)
    /// const B: bool = false;
    /// assert!(B)
    /// ```
    pub ASSERTIONS_ON_CONSTANTS,
    style,
    "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`"
}

declare_lint_pass!(AssertionsOnConstants => [ASSERTIONS_ON_CONSTANTS]);

impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        let lint_true = |is_debug: bool| {
            span_lint_and_help(
                cx,
                ASSERTIONS_ON_CONSTANTS,
                e.span,
                if is_debug {
                    "`debug_assert!(true)` will be optimized out by the compiler"
                } else {
                    "`assert!(true)` will be optimized out by the compiler"
                },
                None,
                "remove it",
            );
        };
        let lint_false_without_message = || {
            span_lint_and_help(
                cx,
                ASSERTIONS_ON_CONSTANTS,
                e.span,
                "`assert!(false)` should probably be replaced",
                None,
                "use `panic!()` or `unreachable!()`",
            );
        };
        let lint_false_with_message = |panic_message: String| {
            span_lint_and_help(
                cx,
                ASSERTIONS_ON_CONSTANTS,
                e.span,
                &format!("`assert!(false, {})` should probably be replaced", panic_message),
                None,
                &format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message),
            )
        };

        if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") {
            if debug_assert_span.from_expansion() {
                return;
            }
            if_chain! {
                if let ExprKind::Unary(_, ref lit) = e.kind;
                if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), lit);
                if is_true;
                then {
                    lint_true(true);
                }
            };
        } else if let Some(assert_span) = is_direct_expn_of(e.span, "assert") {
            if assert_span.from_expansion() {
                return;
            }
            if let Some(assert_match) = match_assert_with_message(&cx, e) {
                match assert_match {
                    // matched assert but not message
                    AssertKind::WithoutMessage(false) => lint_false_without_message(),
                    AssertKind::WithoutMessage(true) | AssertKind::WithMessage(_, true) => lint_true(false),
                    AssertKind::WithMessage(panic_message, false) => lint_false_with_message(panic_message),
                };
            }
        }
    }
}

/// Result of calling `match_assert_with_message`.
enum AssertKind {
    WithMessage(String, bool),
    WithoutMessage(bool),
}

/// Check if the expression matches
///
/// ```rust,ignore
/// match { let _t = !c; _t } {
///     true => {
///         {
///             ::std::rt::begin_panic(message, _)
///         }
///     }
///     _ => { }
/// };
/// ```
///
/// where `message` is any expression and `c` is a constant bool.
fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<AssertKind> {
    if_chain! {
        if let ExprKind::Match(ref expr, ref arms, _) = expr.kind;
        // matches { let _t = expr; _t }
        if let ExprKind::DropTemps(ref expr) = expr.kind;
        if let ExprKind::Unary(UnOp::UnNot, ref expr) = expr.kind;
        // bind the first argument of the `assert!` macro
        if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr);
        // arm 1 pattern
        if let PatKind::Lit(ref lit_expr) = arms[0].pat.kind;
        if let ExprKind::Lit(ref lit) = lit_expr.kind;
        if let LitKind::Bool(true) = lit.node;
        // arm 1 block
        if let ExprKind::Block(ref block, _) = arms[0].body.kind;
        if block.stmts.is_empty();
        if let Some(block_expr) = &block.expr;
        // inner block is optional. unwrap it if it exists, or use the expression as is otherwise.
        if let Some(begin_panic_call) = match block_expr.kind {
            ExprKind::Block(ref inner_block, _) => &inner_block.expr,
            _ => &block.expr,
        };
        // function call
        if let Some(args) = match_panic_call(cx, begin_panic_call);
        if args.len() == 1;
        // bind the second argument of the `assert!` macro if it exists
        if let panic_message = snippet_opt(cx, args[0].span);
        // second argument of begin_panic is irrelevant
        // as is the second match arm
        then {
            // an empty message occurs when it was generated by the macro
            // (and not passed by the user)
            return panic_message
                .filter(|msg| !msg.is_empty())
                .map(|msg| AssertKind::WithMessage(msg, is_true))
                .or(Some(AssertKind::WithoutMessage(is_true)));
        }
    }
    None
}
<|endoftext|>