<commit_before>//! `SpookyHash`: a 128-bit noncryptographic hash function
//!
//! by Bob Jenkins
//!
//! <http://www.burtleburtle.net/bob/hash/spooky.html>
//!
//!  - Oct 31 2010: alpha, framework + `SpookyHash`::Mix appears right
//!  - Oct 31 2011: alpha again, Mix only good to 2^^69 but rest appears right
//!  - Dec 31 2011: beta, improved Mix, tested it for 2-bit deltas
//!  - Feb  2 2012: production, same bits as beta
//!  - Feb  5 2012: adjusted definitions of uint* to be more portable
//!
//! Up to 4 bytes/cycle for long messages.  Reasonably fast for short messages.
//! All 1 or 2 bit deltas achieve avalanche within 1% bias per output bit.
//!
//! This was developed for and tested on 64-bit x86-compatible processors.
//! It assumes the processor is little-endian.  There is a macro
//! controlling whether unaligned reads are allowed (by default they are).
//! This should be an equally good hash on big-endian machines, but it will
//! compute different results on them than on little-endian machines.
//!
//! Google's `CityHash` has similar specs to `SpookyHash`, and `CityHash` is faster
//! on some platforms.  MD4 and MD5 also have similar specs, but they are orders
//! of magnitude slower.  CRCs are two or more times slower, but unlike
//! `SpookyHash`, they have nice math for combining the CRCs of pieces to form
//! the CRCs of wholes.  There are also cryptographic hashes, but those are even
//! slower than MD5.
//!
//! # Examples
//!
//! ```
//! use std::hash::{Hash, Hasher};
//!
//! use fasthash::{spooky, SpookyHasher};
//!
//! fn hash<T: Hash>(t: &T) -> u64 {
//!     let mut s: SpookyHasher = Default::default();
//!     t.hash(&mut s);
//!     s.finish()
//! }
//!
//! let h = spooky::hash64(b"hello world\xff");
//!
//! assert_eq!(h as u64, hash(&"hello world"));
//! ```
//!
use std::hash::Hasher;
use std::os::raw::c_void;
use std::ptr::NonNull;

use crate::ffi;

use crate::hasher::{FastHash, FastHasher, HasherExt, StreamHasher};

/// `SpookyHash` 32-bit hash functions
///
/// # Example
///
/// ```
/// use fasthash::{spooky::Hash32, FastHash};
///
/// assert_eq!(Hash32::hash(b"hello"), 3907268544);
/// assert_eq!(Hash32::hash_with_seed(b"hello", 123), 2211835972);
/// assert_eq!(Hash32::hash(b"helloworld"), 3874077464);
/// ```
#[derive(Clone, Default)]
pub struct Hash32;

impl FastHash for Hash32 {
    type Hash = u32;
    type Seed = u32;

    #[inline(always)]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: T, seed: u32) -> u32 {
        let mut hash1 = u64::from(seed);
        let mut hash2 = u64::from(seed);

        unsafe {
            ffi::SpookyHasherHash(
                bytes.as_ref().as_ptr() as *const _,
                bytes.as_ref().len(),
                &mut hash1,
                &mut hash2,
            );
        }

        hash1 as u32
    }
}

trivial_hasher! {
    /// # Example
    ///
    /// ```
    /// use std::hash::Hasher;
    ///
    /// use fasthash::{spooky::Hasher32, FastHasher};
    ///
    /// let mut h = Hasher32::new();
    ///
    /// h.write(b"hello");
    /// assert_eq!(h.finish(), 3907268544);
    ///
    /// h.write(b"world");
    /// assert_eq!(h.finish(), 3874077464);
    /// ```
    Hasher32(Hash32) -> u32
}

/// `SpookyHash` 64-bit hash functions
///
/// # Example
///
/// ```
/// use fasthash::{spooky::Hash64, FastHash};
///
/// assert_eq!(Hash64::hash(b"hello"), 6105954949053820864);
/// assert_eq!(Hash64::hash_with_seed(b"hello", 123), 8819086853393477700);
/// assert_eq!(Hash64::hash(b"helloworld"), 18412934266828208920);
/// ```
#[derive(Clone, Default)]
pub struct Hash64;

impl FastHash for Hash64 {
    type Hash = u64;
    type Seed = u64;

    #[inline(always)]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: T, seed: u64) -> u64 {
        let mut hash1 = seed;
        let mut hash2 = seed;

        unsafe {
            ffi::SpookyHasherHash(
                bytes.as_ref().as_ptr() as *const _,
                bytes.as_ref().len(),
                &mut hash1,
                &mut hash2,
            );
        }

        hash1
    }
}

trivial_hasher! {
    /// # Example
    ///
    /// ```
    /// use std::hash::Hasher;
    ///
    /// use fasthash::{spooky::Hasher64, FastHasher};
    ///
    /// let mut h = Hasher64::new();
    ///
    /// h.write(b"hello");
    /// assert_eq!(h.finish(), 6105954949053820864);
    ///
    /// h.write(b"world");
    /// assert_eq!(h.finish(), 18412934266828208920);
    /// ```
    Hasher64(Hash64) -> u64
}

/// `SpookyHash` 128-bit hash functions
///
/// # Example
///
/// ```
/// use fasthash::{spooky::Hash128, FastHash};
///
/// assert_eq!(
///     Hash128::hash(b"hello"),
///     112634988270796077198737188616407610157
/// );
/// assert_eq!(
///     Hash128::hash_with_seed(b"hello", 123),
///     133968859623340440246086107642109008647
/// );
/// assert_eq!(
///     Hash128::hash(b"helloworld"),
///     339658686066216790682429200470429822413
/// );
/// ```
#[derive(Clone, Default)]
pub struct Hash128;

impl FastHash for Hash128 {
    type Hash = u128;
    type Seed = u128;

    #[inline(always)]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: T, seed: u128) -> u128 {
        let mut hi = (seed >> 64) as u64;
        let mut lo = seed as u64;

        unsafe {
            ffi::SpookyHasherHash(
                bytes.as_ref().as_ptr() as *const _,
                bytes.as_ref().len(),
                &mut hi,
                &mut lo,
            );
        }

        u128::from(hi).wrapping_shl(64) + u128::from(lo)
    }
}

/// An implementation of `std::hash::Hasher` and `fasthash::HasherExt`.
///
/// # Example
///
/// ```
/// use std::hash::Hasher;
///
/// use fasthash::{spooky::Hasher128, FastHasher, HasherExt};
///
/// let mut h = Hasher128::new();
///
/// h.write(b"hello");
/// assert_eq!(h.finish_ext(), 112634988270796077198737188616407610157);
///
/// h.write(b"world");
/// assert_eq!(h.finish_ext(), 339658686066216790682429200470429822413);
/// ```
#[derive(Clone)]
pub struct Hasher128(NonNull<c_void>);

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

impl Drop for Hasher128 {
    #[inline(always)]
    fn drop(&mut self) {
        unsafe { ffi::SpookyHasherFree(self.0.as_ptr()) }
    }
}

impl Hasher for Hasher128 {
    #[inline(always)]
    fn finish(&self) -> u64 {
        self.finish_ext() as u64
    }

    #[inline(always)]
    fn write(&mut self, bytes: &[u8]) {
        unsafe {
            ffi::SpookyHasherUpdate(
                self.0.as_ptr(),
                bytes.as_ptr() as *const _,
                bytes.len(),
            )
        }
    }
}

impl HasherExt for Hasher128 {
    #[inline(always)]
    fn finish_ext(&self) -> u128 {
        let mut hi = 0_u64;
        let mut lo = 0_u64;

        unsafe {
            ffi::SpookyHasherFinal(self.0.as_ptr(), &mut hi, &mut lo);
        }

        u128::from(hi).wrapping_shl(64) + u128::from(lo)
    }
}

impl FastHasher for Hasher128 {
    type Seed = (u64, u64);
    type Output = u128;

    #[inline(always)]
    fn with_seed(seed: Self::Seed) -> Hasher128 {
        unsafe {
            let h = ffi::SpookyHasherNew();

            ffi::SpookyHasherInit(h, seed.0, seed.1);

            Hasher128(NonNull::new_unchecked(h))
        }
    }
}

impl StreamHasher for Hasher128 {}

impl_build_hasher!(Hasher128, Hash128);

/// `SpookyHash` 32-bit hash functions for a byte array.
#[inline(always)]
pub fn hash32<T: AsRef<[u8]>>(v: T) -> u32 {
    Hash32::hash(v)
}

/// `SpookyHash` 32-bit hash functions for a byte array.
/// For convenience, a 32-bit seed is also hashed into the result.
#[inline(always)]
pub fn hash32_with_seed<T: AsRef<[u8]>>(v: T, seed: u32) -> u32 {
    Hash32::hash_with_seed(v, seed)
}

/// `SpookyHash` 64-bit hash functions for a byte array.
/// For convenience, a 64-bit seed is also hashed into the result.
#[inline(always)]
pub fn hash64<T: AsRef<[u8]>>(v: T) -> u64 {
    Hash64::hash(v)
}

/// `SpookyHash` 64-bit hash functions for a byte array.
#[inline(always)]
pub fn hash64_with_seed<T: AsRef<[u8]>>(v: T, seed: u64) -> u64 {
    Hash64::hash_with_seed(v, seed)
}

/// `SpookyHash` 128-bit hash functions for a byte array.
/// For convenience, a 128-bit seed is also hashed into the result.
#[inline(always)]
pub fn hash128<T: AsRef<[u8]>>(v: T) -> u128 {
    Hash128::hash(v)
}

/// `SpookyHash` 128-bit hash functions for a byte array.
#[inline(always)]
pub fn hash128_with_seed<T: AsRef<[u8]>>(v: T, seed: u128) -> u128 {
    Hash128::hash_with_seed(v, seed)
}
<commit_msg>format code<commit_after>//! `SpookyHash`: a 128-bit noncryptographic hash function
//!
//! by Bob Jenkins
//!
//! <http://www.burtleburtle.net/bob/hash/spooky.html>
//!
//!  - Oct 31 2010: alpha, framework + `SpookyHash`::Mix appears right
//!  - Oct 31 2011: alpha again, Mix only good to 2^^69 but rest appears right
//!  - Dec 31 2011: beta, improved Mix, tested it for 2-bit deltas
//!  - Feb  2 2012: production, same bits as beta
//!  - Feb  5 2012: adjusted definitions of uint* to be more portable
//!
//! Up to 4 bytes/cycle for long messages.  Reasonably fast for short messages.
//! All 1 or 2 bit deltas achieve avalanche within 1% bias per output bit.
//!
//! This was developed for and tested on 64-bit x86-compatible processors.
//! It assumes the processor is little-endian.  There is a macro
//! controlling whether unaligned reads are allowed (by default they are).
//! This should be an equally good hash on big-endian machines, but it will
//! compute different results on them than on little-endian machines.
//!
//! Google's `CityHash` has similar specs to `SpookyHash`, and `CityHash` is faster
//! on some platforms.  MD4 and MD5 also have similar specs, but they are orders
//! of magnitude slower.  CRCs are two or more times slower, but unlike
//! `SpookyHash`, they have nice math for combining the CRCs of pieces to form
//! the CRCs of wholes.  There are also cryptographic hashes, but those are even
//! slower than MD5.
//!
//! # Examples
//!
//! ```
//! use std::hash::{Hash, Hasher};
//!
//! use fasthash::{spooky, SpookyHasher};
//!
//! fn hash<T: Hash>(t: &T) -> u64 {
//!     let mut s: SpookyHasher = Default::default();
//!     t.hash(&mut s);
//!     s.finish()
//! }
//!
//! let h = spooky::hash64(b"hello world\xff");
//!
//! assert_eq!(h as u64, hash(&"hello world"));
//! ```
//!
use std::hash::Hasher;
use std::os::raw::c_void;
use std::ptr::NonNull;

use crate::ffi;

use crate::hasher::{FastHash, FastHasher, HasherExt, StreamHasher};

/// `SpookyHash` 32-bit hash functions
///
/// # Example
///
/// ```
/// use fasthash::{spooky::Hash32, FastHash};
///
/// assert_eq!(Hash32::hash(b"hello"), 3907268544);
/// assert_eq!(Hash32::hash_with_seed(b"hello", 123), 2211835972);
/// assert_eq!(Hash32::hash(b"helloworld"), 3874077464);
/// ```
#[derive(Clone, Default)]
pub struct Hash32;

impl FastHash for Hash32 {
    type Hash = u32;
    type Seed = u32;

    #[inline(always)]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: T, seed: u32) -> u32 {
        let mut hash1 = u64::from(seed);
        let mut hash2 = u64::from(seed);

        unsafe {
            ffi::SpookyHasherHash(
                bytes.as_ref().as_ptr() as *const _,
                bytes.as_ref().len(),
                &mut hash1,
                &mut hash2,
            );
        }

        hash1 as u32
    }
}

trivial_hasher! {
    /// # Example
    ///
    /// ```
    /// use std::hash::Hasher;
    ///
    /// use fasthash::{spooky::Hasher32, FastHasher};
    ///
    /// let mut h = Hasher32::new();
    ///
    /// h.write(b"hello");
    /// assert_eq!(h.finish(), 3907268544);
    ///
    /// h.write(b"world");
    /// assert_eq!(h.finish(), 3874077464);
    /// ```
    Hasher32(Hash32) -> u32
}

/// `SpookyHash` 64-bit hash functions
///
/// # Example
///
/// ```
/// use fasthash::{spooky::Hash64, FastHash};
///
/// assert_eq!(Hash64::hash(b"hello"), 6105954949053820864);
/// assert_eq!(Hash64::hash_with_seed(b"hello", 123), 8819086853393477700);
/// assert_eq!(Hash64::hash(b"helloworld"), 18412934266828208920);
/// ```
#[derive(Clone, Default)]
pub struct Hash64;

impl FastHash for Hash64 {
    type Hash = u64;
    type Seed = u64;

    #[inline(always)]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: T, seed: u64) -> u64 {
        let mut hash1 = seed;
        let mut hash2 = seed;

        unsafe {
            ffi::SpookyHasherHash(
                bytes.as_ref().as_ptr() as *const _,
                bytes.as_ref().len(),
                &mut hash1,
                &mut hash2,
            );
        }

        hash1
    }
}

trivial_hasher! {
    /// # Example
    ///
    /// ```
    /// use std::hash::Hasher;
    ///
    /// use fasthash::{spooky::Hasher64, FastHasher};
    ///
    /// let mut h = Hasher64::new();
    ///
    /// h.write(b"hello");
    /// assert_eq!(h.finish(), 6105954949053820864);
    ///
    /// h.write(b"world");
    /// assert_eq!(h.finish(), 18412934266828208920);
    /// ```
    Hasher64(Hash64) -> u64
}

/// `SpookyHash` 128-bit hash functions
///
/// # Example
///
/// ```
/// use fasthash::{spooky::Hash128, FastHash};
///
/// assert_eq!(
///     Hash128::hash(b"hello"),
///     112634988270796077198737188616407610157
/// );
/// assert_eq!(
///     Hash128::hash_with_seed(b"hello", 123),
///     133968859623340440246086107642109008647
/// );
/// assert_eq!(
///     Hash128::hash(b"helloworld"),
///     339658686066216790682429200470429822413
/// );
/// ```
#[derive(Clone, Default)]
pub struct Hash128;

impl FastHash for Hash128 {
    type Hash = u128;
    type Seed = u128;

    #[inline(always)]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: T, seed: u128) -> u128 {
        let mut hi = (seed >> 64) as u64;
        let mut lo = seed as u64;

        unsafe {
            ffi::SpookyHasherHash(
                bytes.as_ref().as_ptr() as *const _,
                bytes.as_ref().len(),
                &mut hi,
                &mut lo,
            );
        }

        u128::from(hi).wrapping_shl(64) + u128::from(lo)
    }
}

/// An implementation of `std::hash::Hasher` and `fasthash::HasherExt`.
///
/// # Example
///
/// ```
/// use std::hash::Hasher;
///
/// use fasthash::{spooky::Hasher128, FastHasher, HasherExt};
///
/// let mut h = Hasher128::new();
///
/// h.write(b"hello");
/// assert_eq!(h.finish_ext(), 112634988270796077198737188616407610157);
///
/// h.write(b"world");
/// assert_eq!(h.finish_ext(), 339658686066216790682429200470429822413);
/// ```
#[derive(Clone)]
pub struct Hasher128(NonNull<c_void>);

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

impl Drop for Hasher128 {
    #[inline(always)]
    fn drop(&mut self) {
        unsafe { ffi::SpookyHasherFree(self.0.as_ptr()) }
    }
}

impl Hasher for Hasher128 {
    #[inline(always)]
    fn finish(&self) -> u64 {
        self.finish_ext() as u64
    }

    #[inline(always)]
    fn write(&mut self, bytes: &[u8]) {
        unsafe { ffi::SpookyHasherUpdate(self.0.as_ptr(), bytes.as_ptr() as *const _, bytes.len()) }
    }
}

impl HasherExt for Hasher128 {
    #[inline(always)]
    fn finish_ext(&self) -> u128 {
        let mut hi = 0_u64;
        let mut lo = 0_u64;

        unsafe {
            ffi::SpookyHasherFinal(self.0.as_ptr(), &mut hi, &mut lo);
        }

        u128::from(hi).wrapping_shl(64) + u128::from(lo)
    }
}

impl FastHasher for Hasher128 {
    type Seed = (u64, u64);
    type Output = u128;

    #[inline(always)]
    fn with_seed(seed: Self::Seed) -> Hasher128 {
        unsafe {
            let h = ffi::SpookyHasherNew();

            ffi::SpookyHasherInit(h, seed.0, seed.1);

            Hasher128(NonNull::new_unchecked(h))
        }
    }
}

impl StreamHasher for Hasher128 {}

impl_build_hasher!(Hasher128, Hash128);

/// `SpookyHash` 32-bit hash functions for a byte array.
#[inline(always)]
pub fn hash32<T: AsRef<[u8]>>(v: T) -> u32 {
    Hash32::hash(v)
}

/// `SpookyHash` 32-bit hash functions for a byte array.
/// For convenience, a 32-bit seed is also hashed into the result.
#[inline(always)]
pub fn hash32_with_seed<T: AsRef<[u8]>>(v: T, seed: u32) -> u32 {
    Hash32::hash_with_seed(v, seed)
}

/// `SpookyHash` 64-bit hash functions for a byte array.
/// For convenience, a 64-bit seed is also hashed into the result.
#[inline(always)]
pub fn hash64<T: AsRef<[u8]>>(v: T) -> u64 {
    Hash64::hash(v)
}

/// `SpookyHash` 64-bit hash functions for a byte array.
#[inline(always)]
pub fn hash64_with_seed<T: AsRef<[u8]>>(v: T, seed: u64) -> u64 {
    Hash64::hash_with_seed(v, seed)
}

/// `SpookyHash` 128-bit hash functions for a byte array.
/// For convenience, a 128-bit seed is also hashed into the result.
#[inline(always)]
pub fn hash128<T: AsRef<[u8]>>(v: T) -> u128 {
    Hash128::hash(v)
}

/// `SpookyHash` 128-bit hash functions for a byte array.
#[inline(always)]
pub fn hash128_with_seed<T: AsRef<[u8]>>(v: T, seed: u128) -> u128 {
    Hash128::hash_with_seed(v, seed)
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{fd_set, select, timeval, FD_ISSET, FD_SET, FD_ZERO};

fn main() {
    loop {
        // Timeout before next even loop iteration.
        let mut timeval = timeval {
            tv_sec: 1,
            tv_usec: 0,
        };

        // From official documentation:
        // Creates a value whose bytes are all zero.

        // This has the same effect as allocating space with mem::uninitialized
        // and then zeroing it out.
        // It is useful for FFI sometimes, but should generally be avoided.

        // There is no guarantee that an all-zero byte-pattern represents a valid value
        // of some type T.
        // If T has a destructor and the value is destroyed (due to a panic or the end of a scope)
        // before being initialized, then the destructor will run on zeroed data,
        // likely leading to undefined behavior.

        // See also the documentation for mem::uninitialized, which has many of the same caveats.
        let mut read_fds: fd_set = unsafe { std::mem::zeroed() };
        let mut write_fds: fd_set = unsafe { std::mem::zeroed() };

        // Initializes the file descriptor set fdset to have zero bits for all file descriptors.
        // We do this for both read and write sets.
        unsafe { FD_ZERO(&mut read_fds) };
        unsafe { FD_ZERO(&mut write_fds) };

        // Is this amount of file descriptors we need???
        let mut nfds = 0;

        // add read interests to read fd_sets
        // explain what we actually do here

        // add write interests to write fd_sets
        // explain what are you doing one more time

        // select syscall

        // work with potential errors

        // this is all I should do for now I think. At least, I'm not sure
        // I need to do something else here in the first version.
    }
}
<commit_msg>adds udp_socket to socket<commit_after>extern crate libc;

use std::net::UdpSocket;

use libc::{fd_set, select, timeval, FD_ISSET, FD_SET, FD_ZERO};

fn main() {
    let sock = UdpSocket::bind("0.0.0.0:5546").expect("Failed to bind socket");
    sock.set_nonblocking(true).expect("Failed to enter non-blocking mode");

    // Here's your udp_socket, it should be polled with select syscall (bad wording, yeah).

    loop {
        // Timeout before next even loop iteration.
        let mut timeval = timeval {
            tv_sec: 1,
            tv_usec: 0,
        };

        // From official documentation:
        // Creates a value whose bytes are all zero.

        // This has the same effect as allocating space with mem::uninitialized
        // and then zeroing it out.
        // It is useful for FFI sometimes, but should generally be avoided.

        // There is no guarantee that an all-zero byte-pattern represents a valid value
        // of some type T.
        // If T has a destructor and the value is destroyed (due to a panic or the end of a scope)
        // before being initialized, then the destructor will run on zeroed data,
        // likely leading to undefined behavior.

        // See also the documentation for mem::uninitialized, which has many of the same caveats.
        let mut read_fds: fd_set = unsafe { std::mem::zeroed() };
        let mut write_fds: fd_set = unsafe { std::mem::zeroed() };

        // Initializes the file descriptor set fdset to have zero bits for all file descriptors.
        // We do this for both read and write sets.
        unsafe { FD_ZERO(&mut read_fds) };
        unsafe { FD_ZERO(&mut write_fds) };

        // Is this amount of file descriptors we need???
        let mut nfds = 0;

        // add read interests to read fd_sets
        // explain what we actually do here

        // add write interests to write fd_sets
        // explain what are you doing one more time

        // select syscall

        // work with potential errors

        // this is all I should do for now I think. At least, I'm not sure
        // I need to do something else here in the first version.
    }
}
<|endoftext|>


<commit_before>extern crate tcod;
use tcod::RootConsole;
use tcod::{Console};
use tcod::console::{FontLayout, FontType};
use tcod::input::{Key, KeyCode};

mod traits;
use traits::{Renderable, Movable, Position};

mod units;

const SCREEN_WIDTH: u8 = 80;
const SCREEN_HEIGHT: u8 = 50;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right
}

#[derive(Debug)]
enum KeyType {
    Movement(Direction),
    Exit,
    Other,
}

fn key_type(key: &Key) -> KeyType {
    match key.code {
        KeyCode::Right  =>  KeyType::Movement(Direction::Right),
        KeyCode::Left   =>  KeyType::Movement(Direction::Left),
        KeyCode::Up     =>  KeyType::Movement(Direction::Up),
        KeyCode::Down   =>  KeyType::Movement(Direction::Down),
        KeyCode::Escape =>  KeyType::Exit,
        _ => KeyType::Other,
    }
}

fn main() {
    let mut root = RootConsole::initializer()
                    .size(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32)
                    .title("Roguelike Tutorial")
                    .fullscreen(false)
                    .font("arial10x10.png", FontLayout::Tcod)
                    .font_type(FontType::Greyscale)
                    .init();

    root.set_default_foreground(tcod::colors::WHITE);

    let mut player = units::Unit::new(1, 1, '@');

    while !root.window_closed() {
        root.clear();
        player.render(&mut root);
        root.flush();

        let key = root.wait_for_keypress(true);

        match key_type(&key) {
            KeyType::Movement(dir)  => {
                let (x,y) = player.get_position();
                match dir {
                    Direction::Up    if y > 0                 => player.nudge(dir),
                    Direction::Down  if y < SCREEN_HEIGHT-1   => player.nudge(dir),
                    Direction::Left  if x > 0                 => player.nudge(dir),
                    Direction::Right if x < SCREEN_WIDTH-1    => player.nudge(dir),
                    _ => {}
                }
            },
            KeyType::Exit           => break,
            KeyType::Other          => println!("{:?}", key),
        }
    }
}
<commit_msg>Switched to rendering to an off-screen console.<commit_after>extern crate tcod;
use tcod::RootConsole;
use tcod::{Console};
use tcod::console::{FontLayout, FontType, Offscreen};
use tcod::input::{Key, KeyCode};

mod traits;
use traits::{Renderable, Movable, Position};

mod units;

const SCREEN_WIDTH: u8 = 80;
const SCREEN_HEIGHT: u8 = 50;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right
}

#[derive(Debug)]
enum KeyType {
    Movement(Direction),
    Exit,
    Other,
}

fn key_type(key: &Key) -> KeyType {
    match key.code {
        KeyCode::Right  =>  KeyType::Movement(Direction::Right),
        KeyCode::Left   =>  KeyType::Movement(Direction::Left),
        KeyCode::Up     =>  KeyType::Movement(Direction::Up),
        KeyCode::Down   =>  KeyType::Movement(Direction::Down),
        KeyCode::Escape =>  KeyType::Exit,
        _ => KeyType::Other,
    }
}

fn main() {
    let mut root = RootConsole::initializer()
                    .size(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32)
                    .title("Roguelike Tutorial")
                    .fullscreen(false)
                    .font("arial10x10.png", FontLayout::Tcod)
                    .font_type(FontType::Greyscale)
                    .init();

    let mut buffer_console = Offscreen::new(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32);

    root.set_default_foreground(tcod::colors::WHITE);

    let mut player = units::Unit::new(1, 1, '@');

    while !root.window_closed() {
        buffer_console.clear();

        player.render(&mut buffer_console);

        tcod::console::blit(&buffer_console, (0,0), (0,0), &mut root, (0,0), 1.0, 1.0);
        root.flush();

        let key = root.wait_for_keypress(true);

        match key_type(&key) {
            KeyType::Movement(dir)  => {
                let (x,y) = player.get_position();
                match dir {
                    Direction::Up    if y > 0                 => player.nudge(dir),
                    Direction::Down  if y < SCREEN_HEIGHT-1   => player.nudge(dir),
                    Direction::Left  if x > 0                 => player.nudge(dir),
                    Direction::Right if x < SCREEN_WIDTH-1    => player.nudge(dir),
                    _ => {}
                }
            },
            KeyType::Exit           => break,
            KeyType::Other          => println!("{:?}", key),
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use crate::{methods::Method, utils::schemas};
use eyre::Result;
use schemars::{gen::SchemaSettings, schema_for, JsonSchema};
use serde::Serialize;
use thiserror::Error;

/// An enumeration of custom errors returned by this library
///
/// Where possible functions should return one of these errors to provide greater
/// context to the user, in particular regarding actions that can be taken to
/// resolve the error.
#[derive(Error, Debug, JsonSchema, Serialize)]
#[serde(tag = "type")]
#[schemars(deny_unknown_fields)]
pub enum Error {
    /// The user attempted to call a method that is not implemented internally
    /// and so must be delegated to a plugin. However, none of the registered
    /// plugins implement this method. It may be that the use needs to do
    /// `stencila plugins refresh` to fetch the manifests for the plugins.
    /// Or it may be that the method name is just plain wrong.
    #[error("None of the registered plugins implement method '{method}'")]
    UndelegatableMethod { method: Method },

    /// The user attempted to call a method that is not implemented internally
    /// and so must be delegated to a plugin. At least one of the plugins implements
    /// this method but not with the values for the supplied parameters e.g.
    /// `decode(content, format)` which `format = 'some-unknown-format'`.
    #[error("None of the registered plugins implement method '{method}' with given parameters")]
    UndelegatableCall {
        method: Method,
        params: HashMap<String, serde_json::Value>,
    },

    /// The user attempted to call a method that is not implemented internally
    /// and so must be delegated to a plugin. There is a matching implementation
    /// for the call but plugin which implements it is not yet installed.
    #[error("Plugin '{plugin}' is not yet installed")]
    PluginNotInstalled { plugin: String },

    /// Another, unspecified, error type
    #[error("An unknown error occurred")]
    Unknown,
}

/// Get JSON Schema for the `Error` enum.
///
/// This needs to be generated slightly differently to the other schemas
/// in this library because of the way `thiserror` wants enums to be layed out.
pub fn schema() -> Result<serde_json::Value> {
    let settings = SchemaSettings::draft2019_09().with(|settings| {
        settings.option_add_null_type = false;
        settings.inline_subschemas = false;
    });
    let schema = settings.into_generator().into_root_schema_for::<Error>();
    let schema = serde_json::to_value(schema)?;
    Ok(schema)
}
<commit_msg>Update rust/src/errors.rs<commit_after>use std::collections::HashMap;

use crate::{methods::Method, utils::schemas};
use eyre::Result;
use schemars::{gen::SchemaSettings, schema_for, JsonSchema};
use serde::Serialize;
use thiserror::Error;

/// An enumeration of custom errors returned by this library
///
/// Where possible functions should return one of these errors to provide greater
/// context to the user, in particular regarding actions that can be taken to
/// resolve the error.
#[derive(Error, Debug, JsonSchema, Serialize)]
#[serde(tag = "type")]
#[schemars(deny_unknown_fields)]
pub enum Error {
    /// The user attempted to call a method that is not implemented internally
    /// and so must be delegated to a plugin. However, none of the registered
    /// plugins implement this method. It may be that the user needs to do
    /// `stencila plugins refresh` to fetch the manifests for the plugins.
    /// Or it may be that the method name is just plain wrong.
    #[error("None of the registered plugins implement method '{method}'")]
    UndelegatableMethod { method: Method },

    /// The user attempted to call a method that is not implemented internally
    /// and so must be delegated to a plugin. At least one of the plugins implements
    /// this method but not with the values for the supplied parameters e.g.
    /// `decode(content, format)` which `format = 'some-unknown-format'`.
    #[error("None of the registered plugins implement method '{method}' with given parameters")]
    UndelegatableCall {
        method: Method,
        params: HashMap<String, serde_json::Value>,
    },

    /// The user attempted to call a method that is not implemented internally
    /// and so must be delegated to a plugin. There is a matching implementation
    /// for the call but plugin which implements it is not yet installed.
    #[error("Plugin '{plugin}' is not yet installed")]
    PluginNotInstalled { plugin: String },

    /// Another, unspecified, error type
    #[error("An unknown error occurred")]
    Unknown,
}

/// Get JSON Schema for the `Error` enum.
///
/// This needs to be generated slightly differently to the other schemas
/// in this library because of the way `thiserror` wants enums to be layed out.
pub fn schema() -> Result<serde_json::Value> {
    let settings = SchemaSettings::draft2019_09().with(|settings| {
        settings.option_add_null_type = false;
        settings.inline_subschemas = false;
    });
    let schema = settings.into_generator().into_root_schema_for::<Error>();
    let schema = serde_json::to_value(schema)?;
    Ok(schema)
}
<|endoftext|>


<commit_before>use color::PuyoColor;
use field_bit::FieldBit;
use simd;
use simdext::*;
use std::mem;

#[derive(Clone, Copy)]
pub struct BitField {
    m: [FieldBit; 3],
}

impl BitField {
    pub fn new() -> BitField {
        BitField {
            m: [FieldBit::new_empty(),
                FieldBit::from_values(0xFFFF, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0xFFFF),
                FieldBit::new_empty(), ]
        }
    }

    pub fn color(&self, x: usize, y: usize) -> PuyoColor {
        let b0: u8 = if self.m[0].get(x, y) { 1 } else { 0 };
        let b1: u8 = if self.m[1].get(x, y) { 2 } else { 0 };
        let b2: u8 = if self.m[2].get(x, y) { 4 } else { 0 };

        unsafe {
            mem::transmute(b0 | b1 | b2)
        }
    }

    pub fn set_color(&mut self, x: usize, y: usize, c: PuyoColor) {
        let cc = c as u8;
        for i in 0 .. 3 {
            if (cc & (1 << i)) != 0 {
                self.m[i as usize].set(x, y);
            } else {
                self.m[i as usize].unset(x, y);
            }
        }
    }

    pub fn bits(&self, c: PuyoColor) -> FieldBit {
        let v = match c {
            PuyoColor::EMPTY => {  // 0
                (self.r(0) | self.r(1) | self.r(2)) ^ simd::u16x8::splat(0xFFFF)
            },
            PuyoColor::OJAMA => {  // 1
                mm_andnot_epu16(self.r(2), mm_andnot_epu16(self.r(1), self.r(0)))
            },
            PuyoColor::WALL => {   // 2
                mm_andnot_epu16(self.r(2), mm_andnot_epu16(self.r(0), self.r(1)))
            },
            PuyoColor::IRON => {   // 3
                mm_andnot_epu16(self.r(2), mm_and_epu16(self.r(0), self.r(1)))
            },
            PuyoColor::RED => {    // 4
                mm_andnot_epu16(self.r(0), mm_andnot_epu16(self.r(1), self.r(2)))
            },
            PuyoColor::BLUE => {   // 5
                mm_and_epu16(self.r(0), mm_andnot_epu16(self.r(1), self.r(2)))
            },
            PuyoColor::YELLOW => { // 6
                mm_andnot_epu16(self.r(0), mm_and_epu16(self.r(1), self.r(2)))
            },
            PuyoColor::GREEN => {  // 7
                mm_and_epu16(self.r(0), mm_and_epu16(self.r(1), self.r(2)))
            },
        };

        FieldBit::new(v)
    }

    fn r(&self, i: usize) -> simd::u16x8 {
        self.m[i].as_u16x8()
    }
}

#[cfg(test)]
mod tests {
    use super::BitField;
    use color::PuyoColor;

    #[test]
    fn test_initial() {
        let bf = BitField::new();
        for x in 0 .. 8 {
            for y in 0 .. 16 {
                if x == 0 || x == 7 || y == 0 || y == 15 {
                    assert_eq!(bf.color(x, y), PuyoColor::WALL);
                } else {
                    assert_eq!(bf.color(x, y), PuyoColor::EMPTY);
                }
            }
        }
    }

    #[test]
    fn test_set_color() {
        let colors = [
            PuyoColor::EMPTY, PuyoColor::OJAMA, PuyoColor::WALL, PuyoColor::IRON,
            PuyoColor::RED, PuyoColor::BLUE, PuyoColor::YELLOW, PuyoColor::GREEN,
        ];
        let mut bf = BitField::new();

        for c in colors.iter() {
            bf.set_color(1, 1, *c);
            assert_eq!(*c, bf.color(1, 1));
        }
    }
}
<commit_msg>Add PlainField::from_str, and tests for BitField::bits.<commit_after>use color::PuyoColor;
use field;
use field_bit::FieldBit;
use plain_field::PuyoPlainField;
use simd;
use simdext::*;
use std::mem;

#[derive(Clone, Copy)]
pub struct BitField {
    m: [FieldBit; 3],
}

impl BitField {
    pub fn new() -> BitField {
        BitField {
            m: [FieldBit::new_empty(),
                FieldBit::from_values(0xFFFF, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0xFFFF),
                FieldBit::new_empty(), ]
        }
    }

    pub fn from_plain_field(pf: PuyoPlainField) -> BitField {
        let mut bf = BitField::new();

        // TODO(mayah): We have better algorithm here.
        for x in 0 .. field::WIDTH {
            for y in 0 .. field::HEIGHT {
                bf.set_color(x, y, pf.color(x, y))
            }
        }

        bf
    }

    pub fn from_str(s: &str) -> BitField {
        BitField::from_plain_field(PuyoPlainField::from_str(s))
    }

    pub fn color(&self, x: usize, y: usize) -> PuyoColor {
        let b0: u8 = if self.m[0].get(x, y) { 1 } else { 0 };
        let b1: u8 = if self.m[1].get(x, y) { 2 } else { 0 };
        let b2: u8 = if self.m[2].get(x, y) { 4 } else { 0 };

        unsafe {
            mem::transmute(b0 | b1 | b2)
        }
    }

    pub fn set_color(&mut self, x: usize, y: usize, c: PuyoColor) {
        let cc = c as u8;
        for i in 0 .. 3 {
            if (cc & (1 << i)) != 0 {
                self.m[i as usize].set(x, y);
            } else {
                self.m[i as usize].unset(x, y);
            }
        }
    }

    pub fn bits(&self, c: PuyoColor) -> FieldBit {
        let v = match c {
            PuyoColor::EMPTY => {  // 0
                (self.r(0) | self.r(1) | self.r(2)) ^ simd::u16x8::splat(0xFFFF)
            },
            PuyoColor::OJAMA => {  // 1
                mm_andnot_epu16(self.r(2), mm_andnot_epu16(self.r(1), self.r(0)))
            },
            PuyoColor::WALL => {   // 2
                mm_andnot_epu16(self.r(2), mm_andnot_epu16(self.r(0), self.r(1)))
            },
            PuyoColor::IRON => {   // 3
                mm_andnot_epu16(self.r(2), mm_and_epu16(self.r(0), self.r(1)))
            },
            PuyoColor::RED => {    // 4
                mm_andnot_epu16(self.r(0), mm_andnot_epu16(self.r(1), self.r(2)))
            },
            PuyoColor::BLUE => {   // 5
                mm_and_epu16(self.r(0), mm_andnot_epu16(self.r(1), self.r(2)))
            },
            PuyoColor::YELLOW => { // 6
                mm_andnot_epu16(self.r(0), mm_and_epu16(self.r(1), self.r(2)))
            },
            PuyoColor::GREEN => {  // 7
                mm_and_epu16(self.r(0), mm_and_epu16(self.r(1), self.r(2)))
            },
        };

        FieldBit::new(v)
    }

    fn r(&self, i: usize) -> simd::u16x8 {
        self.m[i].as_u16x8()
    }
}

#[cfg(test)]
mod tests {
    use super::BitField;
    use color::PuyoColor;

    #[test]
    fn test_initial() {
        let bf = BitField::new();
        for x in 0 .. 8 {
            for y in 0 .. 16 {
                if x == 0 || x == 7 || y == 0 || y == 15 {
                    assert_eq!(bf.color(x, y), PuyoColor::WALL);
                } else {
                    assert_eq!(bf.color(x, y), PuyoColor::EMPTY);
                }
            }
        }
    }

    #[test]
    fn test_from_str() {
        let bf = BitField::from_str(concat!(
            "RGBRGB",
            "RGBRGB",
            "RGBRGB"));

        assert_eq!(bf.color(1, 1), PuyoColor::RED);
        assert_eq!(bf.color(2, 1), PuyoColor::GREEN);
        assert_eq!(bf.color(3, 1), PuyoColor::BLUE);
        assert_eq!(bf.color(1, 3), PuyoColor::RED);
        assert_eq!(bf.color(2, 3), PuyoColor::GREEN);
        assert_eq!(bf.color(3, 3), PuyoColor::BLUE);
    }

    #[test]
    fn test_set_color() {
        let colors = [
            PuyoColor::EMPTY, PuyoColor::OJAMA, PuyoColor::WALL, PuyoColor::IRON,
            PuyoColor::RED, PuyoColor::BLUE, PuyoColor::YELLOW, PuyoColor::GREEN,
        ];
        let mut bf = BitField::new();

        for c in colors.iter() {
            bf.set_color(1, 1, *c);
            assert_eq!(*c, bf.color(1, 1));
        }
    }

    #[test]
    fn test_bits() {
        let bf = BitField::from_str(concat!(
            "OOOOOO",
            "RGBRGB",
            "RGBRGB",
            "RGBRGB"));

        let red = bf.bits(PuyoColor::RED);
        let blue = bf.bits(PuyoColor::BLUE);
        let green = bf.bits(PuyoColor::GREEN);
        let yellow = bf.bits(PuyoColor::YELLOW);
        let ojama = bf.bits(PuyoColor::OJAMA);

        for x in 1 .. 7 {
            for y in 1 .. 5 {
                match bf.color(x, y) {
                    PuyoColor::RED => {
                        assert!(red.get(x, y));
                        assert!(!blue.get(x, y));
                        assert!(!yellow.get(x, y));
                        assert!(!green.get(x, y));
                        assert!(!ojama.get(x, y));
                    },
                    PuyoColor::BLUE => {
                        assert!(!red.get(x, y));
                        assert!(blue.get(x, y));
                        assert!(!yellow.get(x, y));
                        assert!(!green.get(x, y));
                        assert!(!ojama.get(x, y));
                    },
                    PuyoColor::YELLOW => {
                        assert!(!red.get(x, y));
                        assert!(!blue.get(x, y));
                        assert!(yellow.get(x, y));
                        assert!(!green.get(x, y));
                        assert!(!ojama.get(x, y));
                    },
                    PuyoColor::GREEN => {
                        assert!(!red.get(x, y));
                        assert!(!blue.get(x, y));
                        assert!(!yellow.get(x, y));
                        assert!(green.get(x, y));
                        assert!(!ojama.get(x, y));
                    },
                    PuyoColor::OJAMA => {
                        assert!(!red.get(x, y));
                        assert!(!blue.get(x, y));
                        assert!(!yellow.get(x, y));
                        assert!(!green.get(x, y));
                        assert!(ojama.get(x, y));
                    },
                    _ => {
                        // skip
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::consts::constant_simple;
use crate::utils;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{def, Arm, Expr, ExprKind, PatKind, QPath};
use rustc_lint::LintContext;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:**
    /// Finds patterns that reimplement `Option::unwrap_or`.
    ///
    /// **Why is this bad?**
    /// Concise code helps focusing on behavior instead of boilerplate.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let foo: Option<i32> = None;
    /// match foo {
    ///     Some(v) => v,
    ///     None => 1,
    /// };
    /// ```
    ///
    /// Use instead:
    /// ```rust
    /// let foo: Option<i32> = None;
    /// foo.unwrap_or(1);
    /// ```
    pub MANUAL_UNWRAP_OR,
    complexity,
    "finds patterns that can be encoded more concisely with `Option::unwrap_or(_else)`"
}

declare_lint_pass!(ManualUnwrapOr => [MANUAL_UNWRAP_OR]);

impl LateLintPass<'_> for ManualUnwrapOr {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
        if in_external_macro(cx.sess(), expr.span) {
            return;
        }
        lint_option_unwrap_or_case(cx, expr);
    }
}

fn lint_option_unwrap_or_case<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
    fn applicable_none_arm<'a>(arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> {
        if_chain! {
            if arms.len() == 2;
            if arms.iter().all(|arm| arm.guard.is_none());
            if let Some((idx, none_arm)) = arms.iter().enumerate().find(|(_, arm)|
                if let PatKind::Path(ref qpath) = arm.pat.kind {
                    utils::match_qpath(qpath, &utils::paths::OPTION_NONE)
                } else {
                    false
                }
            );
            let some_arm = &arms[1 - idx];
            if let PatKind::TupleStruct(ref some_qpath, &[some_binding], _) = some_arm.pat.kind;
            if utils::match_qpath(some_qpath, &utils::paths::OPTION_SOME);
            if let PatKind::Binding(_, binding_hir_id, ..) = some_binding.kind;
            if let ExprKind::Path(QPath::Resolved(_, body_path)) = some_arm.body.kind;
            if let def::Res::Local(body_path_hir_id) = body_path.res;
            if body_path_hir_id == binding_hir_id;
            if !utils::usage::contains_return_break_continue_macro(none_arm.body);
            then {
                Some(none_arm)
            }
            else {
                None
            }
        }
    }

    if_chain! {
        if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind;
        let ty = cx.typeck_results().expr_ty(scrutinee);
        if utils::is_type_diagnostic_item(cx, ty, sym!(option_type));
        if let Some(none_arm) = applicable_none_arm(match_arms);
        if let Some(scrutinee_snippet) = utils::snippet_opt(cx, scrutinee.span);
        if let Some(none_body_snippet) = utils::snippet_opt(cx, none_arm.body.span);
        if let Some(indent) = utils::indent_of(cx, expr.span);
        then {
            let reindented_none_body =
                utils::reindent_multiline(none_body_snippet.into(), true, Some(indent));
            let eager_eval = constant_simple(cx, cx.typeck_results(), none_arm.body).is_some();
            let method = if eager_eval {
                "unwrap_or"
            } else {
                "unwrap_or_else"
            };
            utils::span_lint_and_sugg(
                cx,
                MANUAL_UNWRAP_OR, expr.span,
                &format!("this pattern reimplements `Option::{}`", &method),
                "replace with",
                format!(
                    "{}.{}({}{})",
                    scrutinee_snippet,
                    method,
                    if eager_eval { ""} else { "|| " },
                    reindented_none_body
                ),
                Applicability::MachineApplicable,
            );
            true
        } else {
            false
        }
    }
}
<commit_msg>manual-unwrap-or / more pr remarks<commit_after>use crate::consts::constant_simple;
use crate::utils;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{def, Arm, Expr, ExprKind, PatKind, QPath};
use rustc_lint::LintContext;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:**
    /// Finds patterns that reimplement `Option::unwrap_or`.
    ///
    /// **Why is this bad?**
    /// Concise code helps focusing on behavior instead of boilerplate.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let foo: Option<i32> = None;
    /// match foo {
    ///     Some(v) => v,
    ///     None => 1,
    /// };
    /// ```
    ///
    /// Use instead:
    /// ```rust
    /// let foo: Option<i32> = None;
    /// foo.unwrap_or(1);
    /// ```
    pub MANUAL_UNWRAP_OR,
    complexity,
    "finds patterns that can be encoded more concisely with `Option::unwrap_or(_else)`"
}

declare_lint_pass!(ManualUnwrapOr => [MANUAL_UNWRAP_OR]);

impl LateLintPass<'_> for ManualUnwrapOr {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
        if in_external_macro(cx.sess(), expr.span) {
            return;
        }
        lint_option_unwrap_or_case(cx, expr);
    }
}

fn lint_option_unwrap_or_case<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
    fn applicable_none_arm<'a>(arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> {
        if_chain! {
            if arms.len() == 2;
            if arms.iter().all(|arm| arm.guard.is_none());
            if let Some((idx, none_arm)) = arms.iter().enumerate().find(|(_, arm)|
                if let PatKind::Path(ref qpath) = arm.pat.kind {
                    utils::match_qpath(qpath, &utils::paths::OPTION_NONE)
                } else {
                    false
                }
            );
            let some_arm = &arms[1 - idx];
            if let PatKind::TupleStruct(ref some_qpath, &[some_binding], _) = some_arm.pat.kind;
            if utils::match_qpath(some_qpath, &utils::paths::OPTION_SOME);
            if let PatKind::Binding(_, binding_hir_id, ..) = some_binding.kind;
            if let ExprKind::Path(QPath::Resolved(_, body_path)) = some_arm.body.kind;
            if let def::Res::Local(body_path_hir_id) = body_path.res;
            if body_path_hir_id == binding_hir_id;
            if !utils::usage::contains_return_break_continue_macro(none_arm.body);
            then {
                Some(none_arm)
            } else {
                None
            }
        }
    }

    if_chain! {
        if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind;
        let ty = cx.typeck_results().expr_ty(scrutinee);
        if utils::is_type_diagnostic_item(cx, ty, sym!(option_type));
        if let Some(none_arm) = applicable_none_arm(match_arms);
        if let Some(scrutinee_snippet) = utils::snippet_opt(cx, scrutinee.span);
        if let Some(none_body_snippet) = utils::snippet_opt(cx, none_arm.body.span);
        if let Some(indent) = utils::indent_of(cx, expr.span);
        then {
            let reindented_none_body =
                utils::reindent_multiline(none_body_snippet.into(), true, Some(indent));
            let eager_eval = constant_simple(cx, cx.typeck_results(), none_arm.body).is_some();
            let method = if eager_eval {
                "unwrap_or"
            } else {
                "unwrap_or_else"
            };
            utils::span_lint_and_sugg(
                cx,
                MANUAL_UNWRAP_OR, expr.span,
                &format!("this pattern reimplements `Option::{}`", &method),
                "replace with",
                format!(
                    "{}.{}({}{})",
                    scrutinee_snippet,
                    method,
                    if eager_eval { "" } else { "|| " },
                    reindented_none_body
                ),
                Applicability::MachineApplicable,
            );
        }
    }
}
<|endoftext|>


<commit_before>use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{
    def::{DefKind, Res},
    Item, ItemKind, UseKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::BytePos;

declare_clippy_lint! {
    /// **What it does:** Checks for `use Enum::*`.
    ///
    /// **Why is this bad?** It is usually better style to use the prefixed name of
    /// an enumeration variant, rather than importing variants.
    ///
    /// **Known problems:** Old-style enumerations that prefix the variants are
    /// still around.
    ///
    /// **Example:**
    /// ```rust
    /// use std::cmp::Ordering::*;
    /// ```
    pub ENUM_GLOB_USE,
    pedantic,
    "use items that import all variants of an enum"
}

declare_clippy_lint! {
    /// **What it does:** Checks for wildcard imports `use _::*`.
    ///
    /// **Why is this bad?** wildcard imports can polute the namespace. This is especially bad if
    /// you try to import something through a wildcard, that already has been imported by name from
    /// a different source:
    ///
    /// ```rust,ignore
    /// use crate1::foo; // Imports a function named foo
    /// use crate2::*; // Has a function named foo
    ///
    /// foo(); // Calls crate1::foo
    /// ```
    ///
    /// This can lead to confusing error messages at best and to unexpected behavior at worst.
    ///
    /// **Known problems:** If macros are imported through the wildcard, this macro is not included
    /// by the suggestion and has to be added by hand.
    ///
    /// **Example:**
    ///
    /// Bad:
    /// ```rust,ignore
    /// use crate1::*;
    ///
    /// foo();
    /// ```
    ///
    /// Good:
    /// ```rust,ignore
    /// use crate1::foo;
    ///
    /// foo();
    /// ```
    pub WILDCARD_IMPORTS,
    pedantic,
    "lint `use _::*` statements"
}

declare_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]);

impl LateLintPass<'_, '_> for WildcardImports {
    fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &Item<'_>) {
        if item.vis.node.is_pub() || item.vis.node.is_pub_restricted() {
            return;
        }
        if_chain! {
            if !in_macro(item.span);
            if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind;
            let used_imports = cx.tcx.names_imported_by_glob_use(item.hir_id.owner_def_id());
            if !used_imports.is_empty(); // Already handled by `unused_imports`
            then {
                let mut applicability = Applicability::MachineApplicable;
                let import_source = snippet_with_applicability(cx, use_path.span, "..", &mut applicability);
                let (span, braced_glob) = if import_source.is_empty() {
                    // This is a `_::{_, *}` import
                    (
                        use_path.span.with_hi(use_path.span.hi() + BytePos(1)),
                        true,
                    )
                } else {
                    (
                        use_path.span.with_hi(use_path.span.hi() + BytePos(3)),
                        false,
                    )
                };

                let imports_string = if used_imports.len() == 1 {
                    used_imports.iter().next().unwrap().to_string()
                } else {
                    let mut imports = used_imports
                        .iter()
                        .map(ToString::to_string)
                        .collect::<Vec<_>>();
                    imports.sort();
                    if braced_glob {
                        imports.join(", ")
                    } else {
                        format!("{{{}}}", imports.join(", "))
                    }
                };

                let sugg = if import_source.is_empty() {
                    imports_string
                } else {
                    format!("{}::{}", import_source, imports_string)
                };

                let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res {
                    (ENUM_GLOB_USE, "usage of wildcard import for enum variants")
                } else {
                    (WILDCARD_IMPORTS, "usage of wildcard import")
                };

                span_lint_and_sugg(
                    cx,
                    lint,
                    span,
                    message,
                    "try",
                    sugg,
                    applicability,
                );
            }
        }
    }
}
<commit_msg>Filter prelude glob imports<commit_after>use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{
    def::{DefKind, Res},
    Item, ItemKind, UseKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::BytePos;

declare_clippy_lint! {
    /// **What it does:** Checks for `use Enum::*`.
    ///
    /// **Why is this bad?** It is usually better style to use the prefixed name of
    /// an enumeration variant, rather than importing variants.
    ///
    /// **Known problems:** Old-style enumerations that prefix the variants are
    /// still around.
    ///
    /// **Example:**
    /// ```rust
    /// use std::cmp::Ordering::*;
    /// ```
    pub ENUM_GLOB_USE,
    pedantic,
    "use items that import all variants of an enum"
}

declare_clippy_lint! {
    /// **What it does:** Checks for wildcard imports `use _::*`.
    ///
    /// **Why is this bad?** wildcard imports can polute the namespace. This is especially bad if
    /// you try to import something through a wildcard, that already has been imported by name from
    /// a different source:
    ///
    /// ```rust,ignore
    /// use crate1::foo; // Imports a function named foo
    /// use crate2::*; // Has a function named foo
    ///
    /// foo(); // Calls crate1::foo
    /// ```
    ///
    /// This can lead to confusing error messages at best and to unexpected behavior at worst.
    ///
    /// **Known problems:** If macros are imported through the wildcard, this macro is not included
    /// by the suggestion and has to be added by hand.
    ///
    /// **Example:**
    ///
    /// Bad:
    /// ```rust,ignore
    /// use crate1::*;
    ///
    /// foo();
    /// ```
    ///
    /// Good:
    /// ```rust,ignore
    /// use crate1::foo;
    ///
    /// foo();
    /// ```
    pub WILDCARD_IMPORTS,
    pedantic,
    "lint `use _::*` statements"
}

declare_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]);

impl LateLintPass<'_, '_> for WildcardImports {
    fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &Item<'_>) {
        if item.vis.node.is_pub() || item.vis.node.is_pub_restricted() {
            return;
        }
        if_chain! {
            if !in_macro(item.span);
            if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind;
            // don't lint prelude glob imports
            if !use_path.segments.iter().last().map_or(false, |ps| ps.ident.as_str() == "prelude");
            let used_imports = cx.tcx.names_imported_by_glob_use(item.hir_id.owner_def_id());
            if !used_imports.is_empty(); // Already handled by `unused_imports`
            then {
                let mut applicability = Applicability::MachineApplicable;
                let import_source = snippet_with_applicability(cx, use_path.span, "..", &mut applicability);
                let (span, braced_glob) = if import_source.is_empty() {
                    // This is a `_::{_, *}` import
                    (
                        use_path.span.with_hi(use_path.span.hi() + BytePos(1)),
                        true,
                    )
                } else {
                    (
                        use_path.span.with_hi(use_path.span.hi() + BytePos(3)),
                        false,
                    )
                };

                let imports_string = if used_imports.len() == 1 {
                    used_imports.iter().next().unwrap().to_string()
                } else {
                    let mut imports = used_imports
                        .iter()
                        .map(ToString::to_string)
                        .collect::<Vec<_>>();
                    imports.sort();
                    if braced_glob {
                        imports.join(", ")
                    } else {
                        format!("{{{}}}", imports.join(", "))
                    }
                };

                let sugg = if import_source.is_empty() {
                    imports_string
                } else {
                    format!("{}::{}", import_source, imports_string)
                };

                let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res {
                    (ENUM_GLOB_USE, "usage of wildcard import for enum variants")
                } else {
                    (WILDCARD_IMPORTS, "usage of wildcard import")
                };

                span_lint_and_sugg(
                    cx,
                    lint,
                    span,
                    message,
                    "try",
                    sugg,
                    applicability,
                );
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

//! This pass adds validation calls (AcquireValid, ReleaseValid) where appropriate.
//! It has to be run really early, before transformations like inlining, because
//! introducing these calls *adds* UB -- so, conceptually, this pass is actually part
//! of MIR building, and only after this pass we think of the program has having the
//! normal MIR semantics.

use rustc::ty::{TyCtxt, RegionKind};
use rustc::mir::*;
use rustc::mir::transform::{MirPass, MirSource};

pub struct AddValidation;

impl MirPass for AddValidation {
    fn run_pass<'a, 'tcx>(&self,
                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          _: MirSource,
                          mir: &mut Mir<'tcx>) {
        // PART 1
        // Add an AcquireValid at the beginning of the start block.
        if mir.arg_count > 0 {
            let acquire_stmt = Statement {
                source_info: SourceInfo {
                    scope: ARGUMENT_VISIBILITY_SCOPE,
                    span: mir.span, // TODO: Consider using just the span covering the function argument declaration
                },
                kind: StatementKind::Validate(ValidationOp::Acquire,
                    // Skip return value, go over all the arguments
                    mir.local_decls.iter_enumerated().skip(1).take(mir.arg_count)
                    .map(|(local, local_decl)| (local_decl.ty, Lvalue::Local(local))).collect()
                )
            };
            mir.basic_blocks_mut()[START_BLOCK].statements.insert(0, acquire_stmt);
        }

        // PART 2
        // Add ReleaseValid/AcquireValid around function call terminators.  We don't use a visitor because
        // we need to access the block that a Call jumps to.
        let mut returns : Vec<(SourceInfo, Lvalue<'tcx>, BasicBlock)> = Vec::new(); // Here we collect the destinations.
        let local_decls = mir.local_decls.clone(); // TODO: Find a way to get rid of this clone.
        for block_data in mir.basic_blocks_mut() {
            match block_data.terminator {
                Some(Terminator { kind: TerminatorKind::Call { ref args, ref destination, .. }, source_info }) => {
                    // Before the call: Release all arguments
                    let release_stmt = Statement {
                        source_info,
                        kind: StatementKind::Validate(ValidationOp::Release,
                            args.iter().filter_map(|op| {
                                match op {
                                    &Operand::Consume(ref lval) => {
                                        let ty = lval.ty(&local_decls, tcx).to_ty(tcx);
                                        Some((ty, lval.clone()))
                                    },
                                    &Operand::Constant(..) => { None },
                                }
                            }).collect())
                    };
                    block_data.statements.push(release_stmt);
                    // Remember the return destination for later
                    if let &Some(ref destination) = destination {
                        returns.push((source_info, destination.0.clone(), destination.1));
                    }
                }
                _ => {
                    // Not a block ending in a Call -> ignore.
                    // TODO: Handle drop.
                }
            }
        }
        // Now we go over the returns we collected to acquire the return values.
        for (source_info, dest_lval, dest_block) in returns {
            let ty = dest_lval.ty(&local_decls, tcx).to_ty(tcx);
            let acquire_stmt = Statement {
                source_info,
                kind: StatementKind::Validate(ValidationOp::Acquire, vec![(ty, dest_lval)])
            };
            mir.basic_blocks_mut()[dest_block].statements.insert(0, acquire_stmt);
        }

        // PART 3
        // Add ReleaseValid/AcquireValid around Ref.  Again an iterator does not seem very suited as
        // we need to add new statements before and after each Ref.
        for block_data in mir.basic_blocks_mut() {
            // We want to insert statements around Ref commands as we iterate.  To this end, we iterate backwards
            // using indices.
            for i in (0..block_data.statements.len()).rev() {
                let (dest_lval, re, src_lval) = match block_data.statements[i].kind {
                    StatementKind::Assign(ref dest_lval, Rvalue::Ref(re, _, ref src_lval)) => {
                        (dest_lval.clone(), re, src_lval.clone())
                    },
                    _ => continue,
                };
                // So this is a ref, and we got all the data we wanted.
                let dest_ty = dest_lval.ty(&local_decls, tcx).to_ty(tcx);
                let acquire_stmt = Statement {
                    source_info: block_data.statements[i].source_info,
                    kind: StatementKind::Validate(ValidationOp::Acquire, vec![(dest_ty, dest_lval)]),
                };
                block_data.statements.insert(i+1, acquire_stmt);

                // The source is released until the region of the borrow ends.
                // FIXME: We have to check whether the source path was writable.
                let src_ty = src_lval.ty(&local_decls, tcx).to_ty(tcx);
                let op = match re {
                    &RegionKind::ReScope(ce) => ValidationOp::Suspend(ce),
                    &RegionKind::ReErased => bug!("AddValidation pass must be run before erasing lifetimes"),
                    _ => ValidationOp::Release,
                };
                let release_stmt = Statement {
                    source_info: block_data.statements[i].source_info,
                    kind: StatementKind::Validate(op, vec![(src_ty, src_lval)]),
                };
                block_data.statements.insert(i, release_stmt);
            }
        }
    }
}
<commit_msg>add_validation: handle drop<commit_after>// Copyright 2015 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.

//! This pass adds validation calls (AcquireValid, ReleaseValid) where appropriate.
//! It has to be run really early, before transformations like inlining, because
//! introducing these calls *adds* UB -- so, conceptually, this pass is actually part
//! of MIR building, and only after this pass we think of the program has having the
//! normal MIR semantics.

use rustc::ty::{TyCtxt, RegionKind};
use rustc::mir::*;
use rustc::mir::transform::{MirPass, MirSource};

pub struct AddValidation;

impl MirPass for AddValidation {
    fn run_pass<'a, 'tcx>(&self,
                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          _: MirSource,
                          mir: &mut Mir<'tcx>) {
        // PART 1
        // Add an AcquireValid at the beginning of the start block.
        if mir.arg_count > 0 {
            let acquire_stmt = Statement {
                source_info: SourceInfo {
                    scope: ARGUMENT_VISIBILITY_SCOPE,
                    span: mir.span, // TODO: Consider using just the span covering the function argument declaration
                },
                kind: StatementKind::Validate(ValidationOp::Acquire,
                    // Skip return value, go over all the arguments
                    mir.local_decls.iter_enumerated().skip(1).take(mir.arg_count)
                    .map(|(local, local_decl)| (local_decl.ty, Lvalue::Local(local))).collect()
                )
            };
            mir.basic_blocks_mut()[START_BLOCK].statements.insert(0, acquire_stmt);
        }

        // PART 2
        // Add ReleaseValid/AcquireValid around function call terminators.  We don't use a visitor because
        // we need to access the block that a Call jumps to.
        let mut returns : Vec<(SourceInfo, Lvalue<'tcx>, BasicBlock)> = Vec::new(); // Here we collect the destinations.
        let local_decls = mir.local_decls.clone(); // TODO: Find a way to get rid of this clone.
        for block_data in mir.basic_blocks_mut() {
            match block_data.terminator {
                Some(Terminator { kind: TerminatorKind::Call { ref args, ref destination, .. }, source_info }) => {
                    // Before the call: Release all arguments
                    let release_stmt = Statement {
                        source_info,
                        kind: StatementKind::Validate(ValidationOp::Release,
                            args.iter().filter_map(|op| {
                                match op {
                                    &Operand::Consume(ref lval) => {
                                        let ty = lval.ty(&local_decls, tcx).to_ty(tcx);
                                        Some((ty, lval.clone()))
                                    },
                                    &Operand::Constant(..) => { None },
                                }
                            }).collect())
                    };
                    block_data.statements.push(release_stmt);
                    // Remember the return destination for later
                    if let &Some(ref destination) = destination {
                        returns.push((source_info, destination.0.clone(), destination.1));
                    }
                }
                Some(Terminator { kind: TerminatorKind::Drop { location: ref lval, .. }, source_info }) |
                Some(Terminator { kind: TerminatorKind::DropAndReplace { location: ref lval, .. }, source_info }) => {
                    // Before the call: Release all arguments
                    let ty = lval.ty(&local_decls, tcx).to_ty(tcx);
                    let release_stmt = Statement {
                        source_info,
                        kind: StatementKind::Validate(ValidationOp::Release, vec![(ty, lval.clone())])
                    };
                    block_data.statements.push(release_stmt);
                    // drop doesn't return anything, so we need no acquire.
                }
                _ => {
                    // Not a block ending in a Call -> ignore.
                }
            }
        }
        // Now we go over the returns we collected to acquire the return values.
        for (source_info, dest_lval, dest_block) in returns {
            let ty = dest_lval.ty(&local_decls, tcx).to_ty(tcx);
            let acquire_stmt = Statement {
                source_info,
                kind: StatementKind::Validate(ValidationOp::Acquire, vec![(ty, dest_lval)])
            };
            mir.basic_blocks_mut()[dest_block].statements.insert(0, acquire_stmt);
        }

        // PART 3
        // Add ReleaseValid/AcquireValid around Ref.  Again an iterator does not seem very suited as
        // we need to add new statements before and after each Ref.
        for block_data in mir.basic_blocks_mut() {
            // We want to insert statements around Ref commands as we iterate.  To this end, we iterate backwards
            // using indices.
            for i in (0..block_data.statements.len()).rev() {
                let (dest_lval, re, src_lval) = match block_data.statements[i].kind {
                    StatementKind::Assign(ref dest_lval, Rvalue::Ref(re, _, ref src_lval)) => {
                        (dest_lval.clone(), re, src_lval.clone())
                    },
                    _ => continue,
                };
                // So this is a ref, and we got all the data we wanted.
                let dest_ty = dest_lval.ty(&local_decls, tcx).to_ty(tcx);
                let acquire_stmt = Statement {
                    source_info: block_data.statements[i].source_info,
                    kind: StatementKind::Validate(ValidationOp::Acquire, vec![(dest_ty, dest_lval)]),
                };
                block_data.statements.insert(i+1, acquire_stmt);

                // The source is released until the region of the borrow ends.
                let src_ty = src_lval.ty(&local_decls, tcx).to_ty(tcx);
                let op = match re {
                    &RegionKind::ReScope(ce) => ValidationOp::Suspend(ce),
                    &RegionKind::ReErased => bug!("AddValidation pass must be run before erasing lifetimes"),
                    _ => ValidationOp::Release,
                };
                let release_stmt = Statement {
                    source_info: block_data.statements[i].source_info,
                    kind: StatementKind::Validate(op, vec![(src_ty, src_lval)]),
                };
                block_data.statements.insert(i, release_stmt);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeSet;

use value::{Value, Id};
use relation::{Relation, IndexSelect};
use primitive::{Primitive};
use std::cmp::Ordering;
use std::mem::replace;

#[derive(Clone, Debug)]
pub struct Table {
    pub insert: Option<IndexSelect>,
    pub remove: Option<IndexSelect>,
}

#[derive(Clone, Debug)]
pub struct Union {
    pub selects: Vec<IndexSelect>,
}

#[derive(Clone, Debug, Copy)]
pub enum Direction {
    Ascending,
    Descending,
}

#[derive(Clone, Debug)]
pub enum Input {
    Primitive{
        primitive: Primitive,
        input_bindings: Vec<(usize, usize)>,
    },
    View{
        input_ix: usize,
    },
}

#[derive(Clone, Debug)]
pub struct Source {
    pub id: Id, // used for reporting errors
    pub input: Input,
    pub grouped_fields: Vec<usize>,
    pub sorted_fields: Vec<(usize, Direction)>,
    pub chunked: bool,
    pub negated: bool,
    pub constraint_bindings: Vec<(usize, usize)>,
    pub output_bindings: Vec<(usize, usize)>,
}

impl Source {
    fn prepare(&self, mut rows: Vec<Vec<Value>>) -> Vec<Vec<Value>> {
        // TODO compensate for inputs if primitive

        // sort rows by self.grouped_fields and self.sorted_fields
        rows.sort_by(|a, b| {
            for &ix in self.grouped_fields.iter() {
                match a[ix].cmp(&b[ix]) {
                    Ordering::Greater => return Ordering::Greater,
                    Ordering::Less => return Ordering::Less,
                    Ordering::Equal => ()
                }
            }
            for &(ix, direction) in self.sorted_fields.iter() {
                match (a[ix].cmp(&b[ix]), direction) {
                    (Ordering::Greater, Direction::Ascending) => return Ordering::Greater,
                    (Ordering::Greater, Direction::Descending) => return Ordering::Less,
                    (Ordering::Less, Direction::Ascending) => return Ordering::Less,
                    (Ordering::Less, Direction::Descending) => return Ordering::Greater,
                    (Ordering::Equal, _) => ()
                }
            }
            return Ordering::Equal;
        });

        // group rows by self.grouped_fields
        let mut rows_iter = rows.into_iter();
        let mut groups = Vec::new();
        match rows_iter.next() {
            Some(row) => {
                let mut group = vec![row];
                for row in rows_iter {
                    if self.grouped_fields.iter().any(|&ix| row[ix] != group[0][ix]) {
                        groups.push(group);
                        group = vec![];
                    }
                    group.push(row);
                }
                groups.push(group);
            }
            None => ()
        }

        // collapse groups if self.chunked
        if self.chunked {
            let mut chunk_group = vec![];
            for group in groups.drain(..) {
                let mut chunk = vec![Value::Column(vec![]); group[0].len()];
                for mut row in group.into_iter() {
                    for &ix in self.grouped_fields.iter() {
                        chunk[ix] = replace(&mut row[ix], Value::Null);
                    }
                    for &(ix, _) in self.sorted_fields.iter() {
                        chunk[ix].as_column_mut().push(replace(&mut row[ix], Value::Null));
                    }
                }
                chunk_group.push(chunk);
            }
            groups.push(chunk_group);
        }

        // append ordinals
        for group in groups.iter_mut() {
            for (ordinal, row) in group.iter_mut().enumerate() {
                row.push(Value::Float((ordinal + 1) as f64));
            }
        }

        // flatten groups
        groups.into_iter().flat_map(|group| group).collect()
    }
}

#[derive(Clone, Debug)]
pub struct Join {
    pub constants: Vec<Value>,
    pub sources: Vec<Source>,
    pub select: Vec<usize>,
}

#[derive(Clone, Debug)]
pub enum View {
    Table(Table),
    Union(Union),
    Join(Join),
}

// TODO this algorithm is incredibly naive and also clones excessively
fn join_step(join: &Join, ix: usize, inputs: &[Vec<Vec<Value>>], state: &mut Vec<Value>, index: &mut BTreeSet<Vec<Value>>, errors: &mut Vec<Vec<Value>>) {
    if ix == join.sources.len() {
        index.insert(join.select.iter().map(|ix| state[*ix].clone()).collect());
    } else {
        let source = &join.sources[ix];
        match source.input {
            Input::View{..} => {
                for values in inputs[ix].iter() {
                    for &(field_ix, variable_ix) in source.output_bindings.iter() {
                        state[variable_ix] = values[field_ix].clone();
                    }
                    let satisfies_constraints = source.constraint_bindings.iter().all(|&(field_ix, variable_ix)|
                        state[variable_ix] == values[field_ix]
                        );
                    match (source.negated, satisfies_constraints) {
                            (false, false) => (), // skip row
                            (false, true) => join_step(join, ix+1, inputs, state, index, errors), // choose row and continue
                            (true, false) => (), // skip row
                            (true, true) => return, // bail out
                    }
                }
                if source.negated {
                    // if we haven't bailed out yet, continue
                    join_step(join, ix+1, inputs, state, index, errors);
                }
            }
            Input::Primitive{primitive, ref input_bindings} => {
                // values returned from primitives don't include inputs, so we will have to offset accesses by input_len
                let input_len = input_bindings.len();
                for mut values in primitive.eval(&input_bindings[..], &state[..], &source.id, errors).into_iter() {
                    for &(field_ix, variable_ix) in source.output_bindings.iter() {
                        state[variable_ix] = replace(&mut values[field_ix - input_len], Value::Null);
                    }
                    if source.constraint_bindings.iter().all(|&(field_ix, variable_ix)|
                        state[variable_ix] == values[field_ix - input_len]
                    ) {
                        join_step(join, ix+1, inputs, state, index, errors);
                    }
                }
            }
        }
    }
}

impl View {
    pub fn run(&self, old_output: &Relation, upstream: &[&Relation], errors: &mut Vec<Vec<Value>>) -> Option<Relation> {
        let mut output = Relation::new(
            old_output.view.clone(),
            old_output.fields.clone(),
            old_output.names.clone()
            );
        match *self {
            View::Table(_) => None,
            View::Union(ref union) => {
                assert_eq!(union.selects.len(), upstream.len());
                for select in union.selects.iter() {
                    for values in select.select(&upstream[..]) {
                        output.index.insert(values);
                    }
                }
                Some(output)
            }
            View::Join(ref join) => {
                let mut state = join.constants.clone();
                let inputs = join.sources.iter().map(|source|
                    match source.input {
                        Input::Primitive{..} => {
                            vec![]
                        }
                        Input::View{input_ix, ..} => {
                            source.prepare(upstream[input_ix].index.iter().map(|row| row.clone()).collect())
                        }
                    }).collect::<Vec<_>>();
                join_step(join, 0, &inputs[..], &mut state, &mut output.index, errors);
                Some(output)
            }
        }
    }
}<commit_msg>Handle constants in unions<commit_after>use std::collections::BTreeSet;

use value::{Value, Id};
use relation::{Relation, IndexSelect};
use primitive::{Primitive};
use std::cmp::Ordering;
use std::mem::replace;

#[derive(Clone, Debug)]
pub struct Table {
    pub insert: Option<IndexSelect>,
    pub remove: Option<IndexSelect>,
}

#[derive(Clone, Debug)]
pub struct Union {
    pub constants: Vec<Value>,
    pub mappings: Vec<Vec<(usize, usize)>>,
}

#[derive(Clone, Debug, Copy)]
pub enum Direction {
    Ascending,
    Descending,
}

#[derive(Clone, Debug)]
pub enum Input {
    Primitive{
        primitive: Primitive,
        input_bindings: Vec<(usize, usize)>,
    },
    View{
        input_ix: usize,
    },
}

#[derive(Clone, Debug)]
pub struct Source {
    pub id: Id, // used for reporting errors
    pub input: Input,
    pub grouped_fields: Vec<usize>,
    pub sorted_fields: Vec<(usize, Direction)>,
    pub chunked: bool,
    pub negated: bool,
    pub constraint_bindings: Vec<(usize, usize)>,
    pub output_bindings: Vec<(usize, usize)>,
}

impl Source {
    fn prepare(&self, mut rows: Vec<Vec<Value>>) -> Vec<Vec<Value>> {
        // TODO compensate for inputs if primitive

        // sort rows by self.grouped_fields and self.sorted_fields
        rows.sort_by(|a, b| {
            for &ix in self.grouped_fields.iter() {
                match a[ix].cmp(&b[ix]) {
                    Ordering::Greater => return Ordering::Greater,
                    Ordering::Less => return Ordering::Less,
                    Ordering::Equal => ()
                }
            }
            for &(ix, direction) in self.sorted_fields.iter() {
                match (a[ix].cmp(&b[ix]), direction) {
                    (Ordering::Greater, Direction::Ascending) => return Ordering::Greater,
                    (Ordering::Greater, Direction::Descending) => return Ordering::Less,
                    (Ordering::Less, Direction::Ascending) => return Ordering::Less,
                    (Ordering::Less, Direction::Descending) => return Ordering::Greater,
                    (Ordering::Equal, _) => ()
                }
            }
            return Ordering::Equal;
        });

        // group rows by self.grouped_fields
        let mut rows_iter = rows.into_iter();
        let mut groups = Vec::new();
        match rows_iter.next() {
            Some(row) => {
                let mut group = vec![row];
                for row in rows_iter {
                    if self.grouped_fields.iter().any(|&ix| row[ix] != group[0][ix]) {
                        groups.push(group);
                        group = vec![];
                    }
                    group.push(row);
                }
                groups.push(group);
            }
            None => ()
        }

        // collapse groups if self.chunked
        if self.chunked {
            let mut chunk_group = vec![];
            for group in groups.drain(..) {
                let mut chunk = vec![Value::Column(vec![]); group[0].len()];
                for mut row in group.into_iter() {
                    for &ix in self.grouped_fields.iter() {
                        chunk[ix] = replace(&mut row[ix], Value::Null);
                    }
                    for &(ix, _) in self.sorted_fields.iter() {
                        chunk[ix].as_column_mut().push(replace(&mut row[ix], Value::Null));
                    }
                }
                chunk_group.push(chunk);
            }
            groups.push(chunk_group);
        }

        // append ordinals
        for group in groups.iter_mut() {
            for (ordinal, row) in group.iter_mut().enumerate() {
                row.push(Value::Float((ordinal + 1) as f64));
            }
        }

        // flatten groups
        groups.into_iter().flat_map(|group| group).collect()
    }
}

#[derive(Clone, Debug)]
pub struct Join {
    pub constants: Vec<Value>,
    pub sources: Vec<Source>,
    pub select: Vec<usize>,
}

#[derive(Clone, Debug)]
pub enum View {
    Table(Table),
    Union(Union),
    Join(Join),
}

// TODO this algorithm is incredibly naive and also clones excessively
fn join_step(join: &Join, ix: usize, inputs: &[Vec<Vec<Value>>], state: &mut Vec<Value>, index: &mut BTreeSet<Vec<Value>>, errors: &mut Vec<Vec<Value>>) {
    if ix == join.sources.len() {
        index.insert(join.select.iter().map(|ix| state[*ix].clone()).collect());
    } else {
        let source = &join.sources[ix];
        match source.input {
            Input::View{..} => {
                for values in inputs[ix].iter() {
                    for &(field_ix, variable_ix) in source.output_bindings.iter() {
                        state[variable_ix] = values[field_ix].clone();
                    }
                    let satisfies_constraints = source.constraint_bindings.iter().all(|&(field_ix, variable_ix)|
                        state[variable_ix] == values[field_ix]
                        );
                    match (source.negated, satisfies_constraints) {
                            (false, false) => (), // skip row
                            (false, true) => join_step(join, ix+1, inputs, state, index, errors), // choose row and continue
                            (true, false) => (), // skip row
                            (true, true) => return, // bail out
                    }
                }
                if source.negated {
                    // if we haven't bailed out yet, continue
                    join_step(join, ix+1, inputs, state, index, errors);
                }
            }
            Input::Primitive{primitive, ref input_bindings} => {
                // values returned from primitives don't include inputs, so we will have to offset accesses by input_len
                let input_len = input_bindings.len();
                for mut values in primitive.eval(&input_bindings[..], &state[..], &source.id, errors).into_iter() {
                    for &(field_ix, variable_ix) in source.output_bindings.iter() {
                        state[variable_ix] = replace(&mut values[field_ix - input_len], Value::Null);
                    }
                    if source.constraint_bindings.iter().all(|&(field_ix, variable_ix)|
                        state[variable_ix] == values[field_ix - input_len]
                    ) {
                        join_step(join, ix+1, inputs, state, index, errors);
                    }
                }
            }
        }
    }
}

impl View {
    pub fn run(&self, old_output: &Relation, upstream: &[&Relation], errors: &mut Vec<Vec<Value>>) -> Option<Relation> {
        let mut output = Relation::new(
            old_output.view.clone(),
            old_output.fields.clone(),
            old_output.names.clone()
            );
        match *self {
            View::Table(_) => None,
            View::Union(ref union) => {
                assert_eq!(union.mappings.len(), upstream.len());
                for (mapping, input) in union.mappings.iter().zip(upstream.iter()) {
                    for old_row in input.index.iter() {
                        let mut new_row = union.constants.clone();
                        for &(new_ix, old_ix) in mapping.iter() {
                            new_row[new_ix] = old_row[old_ix].clone();
                        }
                        output.index.insert(new_row);
                    }
                }
                Some(output)
            }
            View::Join(ref join) => {
                let mut state = join.constants.clone();
                let inputs = join.sources.iter().map(|source|
                    match source.input {
                        Input::Primitive{..} => {
                            vec![]
                        }
                        Input::View{input_ix, ..} => {
                            source.prepare(upstream[input_ix].index.iter().map(|row| row.clone()).collect())
                        }
                    }).collect::<Vec<_>>();
                join_step(join, 0, &inputs[..], &mut state, &mut output.index, errors);
                Some(output)
            }
        }
    }
}<|endoftext|>