<commit_before>extern crate raw_window_handle;

use self::raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
use crate::{sys::SDL_Window, video::Window};

unsafe impl HasRawWindowHandle for Window {
    fn raw_window_handle(&self) -> RawWindowHandle {
        use self::SDL_SYSWM_TYPE::*;
        let mut wm_info = SDL_SysWMinfo::default();

        // Make certain to retrieve version before querying `SDL_GetWindowWMInfo`
        // as that gives an error on certain systems
        #[cfg(not(target_os = "macos"))]
        unsafe {
            let mut version: sys::SDL_version =  std::mem::zeroed();
            sys::SDL_GetVersion(&mut version);
            wm_info.version = version.into();
        }

        if unsafe { SDL_GetWindowWMInfo(self.raw(), &mut wm_info) } == SDL_bool::SDL_FALSE {
            panic!("Couldn't get SDL window info: {}", crate::get_error());
        }
        match wm_info.subsystem {
            #[cfg(target_os = "windows")]
            SDL_SYSWM_WINDOWS => {
                use self::raw_window_handle::windows::WindowsHandle;
                RawWindowHandle::Windows(WindowsHandle {
                    hwnd: unsafe { wm_info.info.win }.window as *mut libc::c_void,
                    ..WindowsHandle::empty()
                })
            },
            #[cfg(any(
                target_os = "linux",
                target_os = "dragonfly",
                target_os = "freebsd",
                target_os = "netbsd",
                target_os = "openbsd",
            ))]
            SDL_SYSWM_WAYLAND => {
                use self::raw_window_handle::unix::WaylandHandle;
                RawWindowHandle::Wayland(WaylandHandle {
                    surface: unsafe { wm_info.info.wl }.surface as *mut libc::c_void,
                    display: unsafe { wm_info.info.wl }.display as *mut libc::c_void,
                    ..WaylandHandle::empty()
                })
            },
            #[cfg(any(
                target_os = "linux",
                target_os = "dragonfly",
                target_os = "freebsd",
                target_os = "netbsd",
                target_os = "openbsd",
            ))]
            SDL_SYSWM_X11 => {
                use self::raw_window_handle::unix::XlibHandle;
                RawWindowHandle::Xlib(XlibHandle {
                    window: unsafe { wm_info.info.x11 }.window,
                    display: unsafe { wm_info.info.x11 }.display as *mut libc::c_void,
                    ..XlibHandle::empty()
                })
            },
            #[cfg(target_os = "macos")]
            SDL_SYSWM_COCOA => {
                use self::raw_window_handle::macos::MacOSHandle;
                RawWindowHandle::MacOS(MacOSHandle {
                    ns_window: unsafe { wm_info.info.cocoa }.window as *mut libc::c_void,
                    ns_view: 0 as *mut libc::c_void, // consumer of RawWindowHandle should determine this
                    ..MacOSHandle::empty()
                })
            },
            SDL_SYSWM_ANDROID | SDL_SYSWM_UIKIT => {
                let window_system = match wm_info.subsystem {
                    SDL_SYSWM_ANDROID => "Android",
                    SDL_SYSWM_UIKIT => "iOS",
                    _ => unreachable!(),
                };
                panic!("raw-window-handle support for {} not yet implemented", window_system);
            },
            x => {
                let window_system = match x {
                    SDL_SYSWM_DIRECTFB => "DirectFB",
                    SDL_SYSWM_MIR => "Mir",
                    SDL_SYSWM_WINRT => "WinRT",
                    SDL_SYSWM_VIVANTE => "Vivante",
                    _ => unreachable!(),
                };
                panic!("{} window system is not supported, please file issue with raw-window-handle: https://github.com/rust-windowing/raw-window-handle/issues/new", window_system);
            },
        }
    }
}

extern "C" {
    fn SDL_GetWindowWMInfo(window: *mut SDL_Window, info: *mut SDL_SysWMinfo) -> SDL_bool;
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types, dead_code)]
pub enum SDL_bool {
    SDL_FALSE = 0,
    SDL_TRUE = 1,
}

#[repr(C)]
#[derive(Debug, Default, Copy, Clone, PartialEq)]
#[allow(non_camel_case_types, dead_code)]
pub struct SDL_version {
    pub major: u8,
    pub minor: u8,
    pub patch: u8,
}

impl Into<SDL_version> for sys::SDL_version {
    fn into(self) -> SDL_version {
        SDL_version {
            major: self.major,
            minor: self.minor,
            patch: self.patch
        }
    }
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types, dead_code)]
pub enum SDL_SYSWM_TYPE {
    SDL_SYSWM_UNKNOWN = 0,
    SDL_SYSWM_WINDOWS = 1,
    SDL_SYSWM_X11 = 2,
    SDL_SYSWM_DIRECTFB = 3,
    SDL_SYSWM_COCOA = 4,
    SDL_SYSWM_UIKIT = 5,
    SDL_SYSWM_WAYLAND = 6,
    SDL_SYSWM_MIR = 7,
    SDL_SYSWM_WINRT = 8,
    SDL_SYSWM_ANDROID = 9,
    SDL_SYSWM_VIVANTE = 10,
    SDL_SYSWM_OS2 = 11,
}

impl Default for SDL_SYSWM_TYPE {
    fn default() -> Self {
        SDL_SYSWM_TYPE::SDL_SYSWM_UNKNOWN
    }
}

#[repr(C)]
#[derive(Default, Copy, Clone)]
#[allow(non_camel_case_types)]
pub struct SDL_SysWMinfo {
    pub version: SDL_version,
    pub subsystem: SDL_SYSWM_TYPE,

    #[cfg(target_os = "windows")]
    pub info: windows::WindowsSysWMinfo,

    #[cfg(any(
        target_os = "linux",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
    ))]
    pub info: linux::LinuxSysWMinfo,

    #[cfg(target_os = "macos")]
    pub info: macos::MacOSSysWMinfo,
}

#[cfg(target_os = "windows")]
pub mod windows {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union WindowsSysWMinfo {
        pub win: Handles,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u64; 8usize],
    }

    impl Default for WindowsSysWMinfo {
        fn default() -> Self {
            WindowsSysWMinfo {
                win: Handles::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct Handles {
        pub window: *mut HWND,
        pub hdc: *mut HDC,
        pub hinstance: *mut HINSTANCE,
    }

    impl Default for Handles {
        fn default() -> Self {
            Handles {
                window: 0 as *mut HWND,
                hdc: 0 as *mut HDC,
                hinstance: 0 as *mut HINSTANCE,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct HWND {
        pub unused: libc::c_int,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct HDC {
        pub unused: libc::c_int,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct HINSTANCE {
        pub unused: libc::c_int,
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd",
))]
pub mod linux {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union LinuxSysWMinfo {
        pub x11: X11Info,
        pub wl: WaylandInfo,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u32; 16usize],
    }

    impl Default for LinuxSysWMinfo {
        fn default() -> Self {
            LinuxSysWMinfo {
                wl: WaylandInfo::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct X11Info {
        pub display: *mut Display,
        pub window: Window,
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct WaylandInfo {
        pub display: *mut WLDisplay,
        pub surface: *mut WLSurface,
        pub shell_surface: *mut WLShellSurface,
    }

    impl Default for WaylandInfo {
        fn default() -> Self {
            WaylandInfo {
                display: 0 as *mut WLDisplay,
                surface: 0 as *mut WLSurface,
                shell_surface: 0 as *mut WLShellSurface,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct WLDisplay {
        pub _address: u8,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct WLSurface {
        pub _address: u8,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct WLShellSurface {
        pub _address: u8,
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone)]
    pub struct Display {
        _unused: [u8; 0],
    }

    pub type Window = libc::c_ulong;
}

#[cfg(target_os = "macos")]
pub mod macos {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union MacOSSysWMinfo {
        pub cocoa: CocoaInfo,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u64; 8usize],
    }

    impl Default for MacOSSysWMinfo {
        fn default() -> Self {
            MacOSSysWMinfo {
                cocoa: CocoaInfo::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct CocoaInfo {
        pub window: *mut NSWindow,
    }

    impl Default for CocoaInfo {
        fn default() -> Self {
            CocoaInfo {
                window: 0 as *mut NSWindow,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone)]
    pub struct NSWindow {
        _unused: [u8; 0],
    }
}
<commit_msg>Initialize `SDL_SysWMinfo` zeroed instead of `Default`<commit_after>extern crate raw_window_handle;

use self::raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
use crate::{sys::SDL_Window, video::Window};

unsafe impl HasRawWindowHandle for Window {
    fn raw_window_handle(&self) -> RawWindowHandle {
        use self::SDL_SYSWM_TYPE::*;

        let mut wm_info: SDL_SysWMinfo = unsafe { std::mem::zeroed() };

        // Make certain to retrieve version before querying `SDL_GetWindowWMInfo`
        // as that gives an error on certain systems
        unsafe {
            sys::SDL_GetVersion(&mut wm_info.version);
            if SDL_GetWindowWMInfo(self.raw(), &mut wm_info) == SDL_bool::SDL_FALSE {
                panic!("Couldn't get SDL window info: {}", crate::get_error());
            }
        }

        match wm_info.subsystem {
            #[cfg(target_os = "windows")]
            SDL_SYSWM_WINDOWS => {
                use self::raw_window_handle::windows::WindowsHandle;
                RawWindowHandle::Windows(WindowsHandle {
                    hwnd: unsafe { wm_info.info.win }.window as *mut libc::c_void,
                    ..WindowsHandle::empty()
                })
            },
            #[cfg(any(
            target_os = "linux",
            target_os = "dragonfly",
            target_os = "freebsd",
            target_os = "netbsd",
            target_os = "openbsd",
            ))]
            SDL_SYSWM_WAYLAND => {
                use self::raw_window_handle::unix::WaylandHandle;
                RawWindowHandle::Wayland(WaylandHandle {
                    surface: unsafe { wm_info.info.wl }.surface as *mut libc::c_void,
                    display: unsafe { wm_info.info.wl }.display as *mut libc::c_void,
                    ..WaylandHandle::empty()
                })
            },
            #[cfg(any(
            target_os = "linux",
            target_os = "dragonfly",
            target_os = "freebsd",
            target_os = "netbsd",
            target_os = "openbsd",
            ))]
            SDL_SYSWM_X11 => {
                use self::raw_window_handle::unix::XlibHandle;
                RawWindowHandle::Xlib(XlibHandle {
                    window: unsafe { wm_info.info.x11 }.window,
                    display: unsafe { wm_info.info.x11 }.display as *mut libc::c_void,
                    ..XlibHandle::empty()
                })
            },
            #[cfg(target_os = "macos")]
            SDL_SYSWM_COCOA => {
                use self::raw_window_handle::macos::MacOSHandle;
                RawWindowHandle::MacOS(MacOSHandle {
                    ns_window: unsafe { wm_info.info.cocoa }.window as *mut libc::c_void,
                    ns_view: 0 as *mut libc::c_void, // consumer of RawWindowHandle should determine this
                    ..MacOSHandle::empty()
                })
            },
            SDL_SYSWM_ANDROID | SDL_SYSWM_UIKIT => {
                let window_system = match wm_info.subsystem {
                    SDL_SYSWM_ANDROID => "Android",
                    SDL_SYSWM_UIKIT => "iOS",
                    _ => unreachable!(),
                };
                panic!("raw-window-handle support for {} not yet implemented", window_system);
            },
            x => {
                let window_system = match x {
                    SDL_SYSWM_DIRECTFB => "DirectFB",
                    SDL_SYSWM_MIR => "Mir",
                    SDL_SYSWM_WINRT => "WinRT",
                    SDL_SYSWM_VIVANTE => "Vivante",
                    _ => unreachable!(),
                };
                panic!("{} window system is not supported, please file issue with raw-window-handle: https://github.com/rust-windowing/raw-window-handle/issues/new", window_system);
            },
        }
    }
}

extern "C" {
    fn SDL_GetWindowWMInfo(window: *mut SDL_Window, info: *mut SDL_SysWMinfo) -> SDL_bool;
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types, dead_code)]
pub enum SDL_bool {
    SDL_FALSE = 0,
    SDL_TRUE = 1,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types, dead_code)]
pub enum SDL_SYSWM_TYPE {
    SDL_SYSWM_UNKNOWN = 0,
    SDL_SYSWM_WINDOWS = 1,
    SDL_SYSWM_X11 = 2,
    SDL_SYSWM_DIRECTFB = 3,
    SDL_SYSWM_COCOA = 4,
    SDL_SYSWM_UIKIT = 5,
    SDL_SYSWM_WAYLAND = 6,
    SDL_SYSWM_MIR = 7,
    SDL_SYSWM_WINRT = 8,
    SDL_SYSWM_ANDROID = 9,
    SDL_SYSWM_VIVANTE = 10,
    SDL_SYSWM_OS2 = 11,
}

impl Default for SDL_SYSWM_TYPE {
    fn default() -> Self {
        SDL_SYSWM_TYPE::SDL_SYSWM_UNKNOWN
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
#[allow(non_camel_case_types)]
pub struct SDL_SysWMinfo {
    pub version: sys::SDL_version,
    pub subsystem: SDL_SYSWM_TYPE,

    #[cfg(target_os = "windows")]
    pub info: windows::WindowsSysWMinfo,

    #[cfg(any(
    target_os = "linux",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd",
    ))]
    pub info: linux::LinuxSysWMinfo,

    #[cfg(target_os = "macos")]
    pub info: macos::MacOSSysWMinfo,
}

#[cfg(target_os = "windows")]
pub mod windows {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union WindowsSysWMinfo {
        pub win: Handles,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u64; 8usize],
    }

    impl Default for WindowsSysWMinfo {
        fn default() -> Self {
            WindowsSysWMinfo {
                win: Handles::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct Handles {
        pub window: *mut HWND,
        pub hdc: *mut HDC,
        pub hinstance: *mut HINSTANCE,
    }

    impl Default for Handles {
        fn default() -> Self {
            Handles {
                window: 0 as *mut HWND,
                hdc: 0 as *mut HDC,
                hinstance: 0 as *mut HINSTANCE,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct HWND {
        pub unused: libc::c_int,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct HDC {
        pub unused: libc::c_int,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct HINSTANCE {
        pub unused: libc::c_int,
    }
}

#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
))]
pub mod linux {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union LinuxSysWMinfo {
        pub x11: X11Info,
        pub wl: WaylandInfo,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u32; 16usize],
    }

    impl Default for LinuxSysWMinfo {
        fn default() -> Self {
            LinuxSysWMinfo {
                wl: WaylandInfo::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct X11Info {
        pub display: *mut Display,
        pub window: Window,
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct WaylandInfo {
        pub display: *mut WLDisplay,
        pub surface: *mut WLSurface,
        pub shell_surface: *mut WLShellSurface,
    }

    impl Default for WaylandInfo {
        fn default() -> Self {
            WaylandInfo {
                display: 0 as *mut WLDisplay,
                surface: 0 as *mut WLSurface,
                shell_surface: 0 as *mut WLShellSurface,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct WLDisplay {
        pub _address: u8,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct WLSurface {
        pub _address: u8,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct WLShellSurface {
        pub _address: u8,
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone)]
    pub struct Display {
        _unused: [u8; 0],
    }

    pub type Window = libc::c_ulong;
}

#[cfg(target_os = "macos")]
pub mod macos {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union MacOSSysWMinfo {
        pub cocoa: CocoaInfo,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u64; 8usize],
    }

    impl Default for MacOSSysWMinfo {
        fn default() -> Self {
            MacOSSysWMinfo {
                cocoa: CocoaInfo::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct CocoaInfo {
        pub window: *mut NSWindow,
    }

    impl Default for CocoaInfo {
        fn default() -> Self {
            CocoaInfo {
                window: 0 as *mut NSWindow,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone)]
    pub struct NSWindow {
        _unused: [u8; 0],
    }
}
<|endoftext|>


<commit_before>use super::utils::types::{ Sha256Digest };
use super::blake2::{ Blake2s, Digest };
use super::bytes::{ BytesMut, BufMut };
use super::crystallized_state::CrystallizedState;
use super::aggregate_vote::AggregateVote;
use super::config::Config;

const AGG_VOTE_MSG_SIZE: i32 = 2 + 32 + 32 + 8 + 8;

// Interprets a 3-byte slice from a [u8] as an integer.
fn get_shift_from_source(source: &[u8], offset: usize) -> usize {
    (source[offset + 2] as usize) |
        ((source[offset + 1] as usize) << 8) |
        ((source[offset    ] as usize) << 16)
}

// Given entropy in the form of `seed`, return a shuffled list of validators
// indicies of size `validator_count` or `sample`.
pub fn get_shuffling(
    seed: &Sha256Digest,
    validator_count: &usize,
    sample_size: &Option<usize>,
    config: &Config)
    -> Vec<usize>
{
    assert!(*validator_count > 0);
    let mut output: Vec<usize> = (0..*validator_count).collect();

    assert!(*validator_count <= (config.max_validators as usize));

    // Use a reduced "sample_size" output range if specified
    let output_range: &usize = match sample_size {
        Some(x) => {
            assert!(x <= validator_count,
                    "sample_size should be <= validator_count");
            x
        },
        None => validator_count
    };

    // Do the first blake hash round
    let mut source = Blake2s::new();
    source.input(&seed);

    let mut v = 0;
    while v < *output_range {
        let current_source = source.result();
        let mut source_offset = 0;
        while source_offset < 30 {
            let m = get_shift_from_source(&current_source, source_offset);
            let shuffled_position: usize = (m % (validator_count - v)) + v;
            output.swap(v as usize, shuffled_position as usize);
            v += 1;
            if v >= *validator_count { break; }
            source_offset += 3;
        }
        // Re-hash the source (TODO: this does one extra hash, can be optimised)
        source = Blake2s::new();
        source.input(&current_source);
    }
    output[0..*output_range].to_vec()
}

// Given an aggregate_vote and a crystallized_state,
// return a byte array for signing or verification.
pub fn get_crosslink_aggvote_msg(
    agg_vote: &AggregateVote,
    cry_state: &CrystallizedState)
    ->  Vec<u8>
{
    let mut buf = BytesMut::with_capacity(AGG_VOTE_MSG_SIZE as usize);
    buf.put_u16_be(agg_vote.shard_id);
    buf.extend_from_slice(&agg_vote.shard_block_hash.to_vec());
    buf.extend_from_slice(&cry_state.current_checkpoint.to_vec());
    buf.put_u64_be(cry_state.current_epoch);
    buf.put_u64_be(cry_state.last_justified_epoch);
    buf.to_vec()
}

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

    #[test]
    fn test_shuffling_shift_fn() {
        let mut x = get_shift_from_source(
            &vec![0_u8, 0, 1],
            0);
        assert_eq!((x as u32), 1);

        x = get_shift_from_source(
            &vec![0_u8, 1, 1],
            0);
        assert_eq!(x, 257);

        x = get_shift_from_source(
            &vec![1_u8, 1, 1],
            0);
        assert_eq!(x, 65793);

        x = get_shift_from_source(
            &vec![255_u8, 1, 1],
            0);
        assert_eq!(x, 16711937);
    }

    #[test]
    fn test_shuffling() {
        let s = get_shuffling(
            &Sha256Digest::zero(),
            &10,
            &None,
            &Config::standard());
        assert_eq!(s,
                   vec!(0, 9, 7, 6, 4, 1, 8, 5, 2, 3),
                   "10 validator shuffle was not as expected");
    }

    #[test]
    fn test_shuffling_with_gt_half_max_validators() {
        let mut config = Config::standard();
        config.max_validators = 19;
        let s = get_shuffling(
            &Sha256Digest::zero(),
            &10,
            &None,
            &Config::standard());
        assert_eq!(s,
                   vec!(0, 9, 7, 6, 4, 1, 8, 5, 2, 3),
                   "10 validator shuffle was not as expected");
    }

    #[test]
    fn test_crosslink_aggvote_msg() {
        let mut cs_state = CrystallizedState::zero();
        let mut agg_vote = AggregateVote::zero();
        // All zeros
        let m1 = get_crosslink_aggvote_msg(&agg_vote, &cs_state);
        assert_eq!(m1,
                   vec![0_u8; AGG_VOTE_MSG_SIZE as usize],
                   "failed all zeros test");
        // With some values
        agg_vote.shard_id = 42;
        cs_state.current_epoch = 99;
        cs_state.last_justified_epoch = 123;
        let m2 = get_crosslink_aggvote_msg(&agg_vote, &cs_state);
        assert_eq!(m2[0..2], [0, 42]);
        assert_eq!(m2[2..34], [0; 32]);     // TODO: test with non-zero hash
        assert_eq!(m2[34..66], [0; 32]);    // TODO: test with non-zero hash
        assert_eq!(m2[66..74], [0, 0, 0, 0, 0, 0, 0, 99]);
        assert_eq!(m2[74..82], [0, 0, 0, 0, 0, 0, 0, 123]);
    }

}
<commit_msg>Remove sample_size from val shuffling<commit_after>use super::utils::types::{ Sha256Digest };
use super::blake2::{ Blake2s, Digest };
use super::bytes::{ BytesMut, BufMut };
use super::crystallized_state::CrystallizedState;
use super::aggregate_vote::AggregateVote;
use super::config::Config;

const AGG_VOTE_MSG_SIZE: i32 = 2 + 32 + 32 + 8 + 8;

// Interprets a 3-byte slice from a [u8] as an integer.
fn get_shift_from_source(source: &[u8], offset: usize) -> usize {
    (source[offset + 2] as usize) |
        ((source[offset + 1] as usize) << 8) |
        ((source[offset    ] as usize) << 16)
}

// Given entropy in the form of `seed`, return a shuffled list of validators
// indicies of size `validator_count` or `sample`.
pub fn get_shuffling(
    seed: &Sha256Digest,
    validator_count: &usize,
    config: &Config)
    -> Vec<usize>
{
    assert!(*validator_count > 0, "cannot shuffle 0 validators");
    let mut output: Vec<usize> = (0..*validator_count).collect();
    assert!(*validator_count <= (config.max_validators as usize),
        "validator_count exceeds max_validators");

    // Do the first blake hash round
    let mut source = Blake2s::new();
    source.input(&seed);

    let mut v = 0;
    while v < *validator_count {
        let current_source = source.result();
        let mut source_offset = 0;
        while source_offset < 30 {
            let m = get_shift_from_source(&current_source, source_offset);
            let shuffled_position: usize = (m % (validator_count - v)) + v;
            output.swap(v as usize, shuffled_position as usize);
            v += 1;
            if v >= *validator_count { break; }
            source_offset += 3;
        }
        // Re-hash the source (TODO: this does one extra hash, can be optimised)
        source = Blake2s::new();
        source.input(&current_source);
    }
    output
}

// Given an aggregate_vote and a crystallized_state,
// return a byte array for signing or verification.
pub fn get_crosslink_aggvote_msg(
    agg_vote: &AggregateVote,
    cry_state: &CrystallizedState)
    ->  Vec<u8>
{
    let mut buf = BytesMut::with_capacity(AGG_VOTE_MSG_SIZE as usize);
    buf.put_u16_be(agg_vote.shard_id);
    buf.extend_from_slice(&agg_vote.shard_block_hash.to_vec());
    buf.extend_from_slice(&cry_state.current_checkpoint.to_vec());
    buf.put_u64_be(cry_state.current_epoch);
    buf.put_u64_be(cry_state.last_justified_epoch);
    buf.to_vec()
}

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

    #[test]
    fn test_shuffling_shift_fn() {
        let mut x = get_shift_from_source(
            &vec![0_u8, 0, 1],
            0);
        assert_eq!((x as u32), 1);

        x = get_shift_from_source(
            &vec![0_u8, 1, 1],
            0);
        assert_eq!(x, 257);

        x = get_shift_from_source(
            &vec![1_u8, 1, 1],
            0);
        assert_eq!(x, 65793);

        x = get_shift_from_source(
            &vec![255_u8, 1, 1],
            0);
        assert_eq!(x, 16711937);
    }

    #[test]
    fn test_shuffling() {
        let s = get_shuffling(
            &Sha256Digest::zero(),
            &10,
            &Config::standard());
        assert_eq!(s,
                   vec!(0, 9, 7, 6, 4, 1, 8, 5, 2, 3),
                   "10 validator shuffle was not as expected");
    }

    #[test]
    fn test_shuffling_with_gt_half_max_validators() {
        let mut config = Config::standard();
        config.max_validators = 19;
        let s = get_shuffling(
            &Sha256Digest::zero(),
            &10,
            &Config::standard());
        assert_eq!(s,
                   vec!(0, 9, 7, 6, 4, 1, 8, 5, 2, 3),
                   "10 validator shuffle was not as expected");
    }

    #[test]
    fn test_crosslink_aggvote_msg() {
        let mut cs_state = CrystallizedState::zero();
        let mut agg_vote = AggregateVote::zero();
        // All zeros
        let m1 = get_crosslink_aggvote_msg(&agg_vote, &cs_state);
        assert_eq!(m1,
                   vec![0_u8; AGG_VOTE_MSG_SIZE as usize],
                   "failed all zeros test");
        // With some values
        agg_vote.shard_id = 42;
        cs_state.current_epoch = 99;
        cs_state.last_justified_epoch = 123;
        let m2 = get_crosslink_aggvote_msg(&agg_vote, &cs_state);
        assert_eq!(m2[0..2], [0, 42]);
        assert_eq!(m2[2..34], [0; 32]);     // TODO: test with non-zero hash
        assert_eq!(m2[34..66], [0; 32]);    // TODO: test with non-zero hash
        assert_eq!(m2[66..74], [0, 0, 0, 0, 0, 0, 0, 99]);
        assert_eq!(m2[74..82], [0, 0, 0, 0, 0, 0, 0, 123]);
    }

    #[test]
    fn test_attester_and_proposer_selection() {
        let mut cry_state = CrystallizedState::zero();
        for _ in 0..10 {
            cry_state.active_validators.push(ValidatorRecord {
                pubkey: get_dangerous_test_keypair().public,
                withdrawal_shard: 0,
                withdrawal_address: Address::zero(),
                randao_commitment: Sha256Digest::zero(),
                balance: 0,
                switch_dynasty: 0
            });
        }
        let act_state = ActiveState::zero();
        let (attestors, proposer) = get_attesters_and_proposer(
            &cry_state,
            &act_state,
            &0,
            &Config::standard());
        assert_eq!(attestors, [0, 9, 7, 6, 4, 1, 8, 5, 2]);
        assert_eq!(proposer, 3);
    }

    #[test]
    #[should_panic(expected = "must be >=2 active validators")]
    fn test_attester_and_proposer_selection_with_zero_active_validators() {
        let mut cry_state = CrystallizedState::zero();
        cry_state.active_validators = Vec::new();
        let act_state = ActiveState::zero();
        let (_attestors, _proposer) = get_attesters_and_proposer(
            &cry_state,
            &act_state,
            &0,
            &Config::standard());
    }
}
<|endoftext|>


<commit_before>use std::{io, path};
use std::rand;
use std::rand::Rng;

fn end(level: uint, state: ~[~str], word:~str){
	println("");
	println("|H| ||  /|A\\  |N|\\ ||   /|G\\\\");
	println("|H|H|| /A|_\\\\ |N| \\||  |G|  __ ");
	println("|H| || |A| || |N|  ||   \\|G/|  man ");
	let mut myfile: ~str = level.to_str();
	myfile = myfile + ".txt";

	let read: Result<@Reader, ~str>;
	read = io::file_reader(~path::Path(myfile));

	if read.is_ok() {
	let file = read.unwrap();
	let text: ~[~str] = file.read_lines();
        for i in range(0, text.len()) {
		println(text[i]);

        }
	}
	println("");
	println("");

	print("   ");
	for j in range(0, state.len()){
		print(state[j]);
		print(" ");
	}
	println("");
	println("");
	println(fmt!("   The word was: %s",word.to_str()));
	println("   PLAY AGAIN? ");
}

fn draw(level: uint, state: ~[~str], past_guess: ~[~str]){
	println("");
	println("|H| ||  /|A\\  |N|\\ ||   /|G\\\\");
	println("|H|H|| /A|_\\\\ |N| \\||  |G|  __ ");
	println("|H| || |A| || |N|  ||   \\|G/|  man ");
	let mut myfile: ~str = level.to_str();
	myfile = myfile + ".txt";

	let read: Result<@Reader, ~str>;
	read = io::file_reader(~path::Path(myfile));

	if read.is_ok() {
	let file = read.unwrap();
	let text: ~[~str] = file.read_lines();
        for i in range(0, text.len()) {
		println(text[i]);

        }
	}
	println("");
	println("");

	print("   ");
	for j in range(0, state.len()){
		print(state[j]);
		print(" ");
	}
	println("");
	println("");

	print("   Past Guesses: ");
	for j in range(0, past_guess.len()){
		print(past_guess[j]);
                print(" ");
	}
	println("");
	println("");
	print("   Enter Next Guess: ");
}

fn load(filename: ~str) -> ~[~str] {
	let read: Result<@Reader, ~str>;
	read = io::file_reader(~path::Path(filename));

	if read.is_ok() {
	let file = read.unwrap();
	return file.read_lines();
	}

	println(fmt!("Error in reading the file: %?", read.unwrap_err()));
	return ~[];
}

fn isDuplicate(guess: char, guesses: ~[~str]) -> bool{

	for i in range(0,guesses.len()) {
		if (guess.to_str() == guesses[i]){
			return true;
		}
	}
	return false;

}

//fn searchChar(guess: char) -> bool{

//}

fn main() {
        let mut rng = rand::task_rng();
	let dictionary: ~[~str] = load(~"words.txt");
	let max_size: uint = dictionary.len();
        let n: uint = rng.gen_integer_range(0u, max_size);
	let word: ~str = dictionary[n];
	let word_len: uint = word.char_len();

	//Stores the guessed word
	let mut i = 0;
	let mut stateWord: ~[~str] = ~[];
	while (i < word_len) {
        	stateWord = stateWord + ~[~"_"];
		i += 1;
        }

        //println(fmt!("%s Guessed Word: ", stateWord.to_str()));
	//println(word);

	let mut guesses: ~[~str] = ~[];

	let mut j = 0;

        let max_guess : uint = 6;
	let mut has_won: bool = false;
	while (j < max_guess  && !has_won){
		let mut is_valid: bool = false;
		has_won = true;
		for i in range(0,stateWord.len()) {
			if(stateWord[i]== ~"_"){
				has_won = false;
			}
		}
		if(has_won){
			end(11, stateWord.clone(), word.clone());
			break;
		}
		draw(j+1, stateWord.clone(), guesses.clone());
		let mut line : ~str = ~"";
		while(!is_valid){
		  line = io::stdin().read_line();
		  if(line.len() > 0){
			if(line.char_at(0).is_alphabetic()){
				is_valid = true;
			}
             }

		}
		let guess_char: char = line.char_at(0);
		//println(fmt!("%? guessed: ", guess_char));
		let has_char: bool = word.contains_char(guess_char);

		if(isDuplicate(guess_char, guesses.clone())){
			//println(fmt!("%? Pick another letter! You have already guess ", guess_char.to_str()));
		}else if (has_char){
			guesses.push(guess_char.to_str());
       			let mut i = 0;
			while (i < word_len) {
				if(word.char_at(i) != guess_char){
        	 			//print("_ ");
                		}else{
		 			stateWord[i] = guess_char.to_str();
				}
				i += 1;
       			 }
			//println("");
		}
		else{
			guesses.push(guess_char.to_str());
			//println("nope.");
			j += 1;
		}

	}
	if(j >= max_guess) {end(17, stateWord.clone(), word.clone());}
}
<commit_msg>added levels<commit_after>use std::{io, path};
use std::rand;
use std::rand::Rng;

fn end(level: uint, state: ~[~str], word:~str){
	println("");
	println("|H| ||  /|A\\  |N|\\ ||   /|G\\\\");
	println("|H|H|| /A|_\\\\ |N| \\||  |G|  __ ");
	println("|H| || |A| || |N|  ||   \\|G/|  man ");
	let mut myfile: ~str = level.to_str();
	myfile = myfile + ".txt";

	let read: Result<@Reader, ~str>;
	read = io::file_reader(~path::Path(myfile));

	if read.is_ok() {
	let file = read.unwrap();
	let text: ~[~str] = file.read_lines();
        for i in range(0, text.len()) {
		println(text[i]);

        }
	}
	println("");
	println("");

	print("   ");
	for j in range(0, state.len()){
		print(state[j]);
		print(" ");
	}
	println("");
	println("");
	println(fmt!("   The word was: %s",word.to_str()));
	println("   PLAY AGAIN? ");
}

fn draw(level: uint, state: ~[~str], past_guess: ~[~str]){
	println("");
	println("|H| ||  /|A\\  |N|\\ ||   /|G\\\\");
	println("|H|H|| /A|_\\\\ |N| \\||  |G|  __ ");
	println("|H| || |A| || |N|  ||   \\|G/|  man ");
	let mut myfile: ~str = level.to_str();
	myfile = myfile + ".txt";

	let read: Result<@Reader, ~str>;
	read = io::file_reader(~path::Path(myfile));

	if read.is_ok() {
	let file = read.unwrap();
	let text: ~[~str] = file.read_lines();
        for i in range(0, text.len()) {
		println(text[i]);

        }
	}
	println("");
	println("");

	print("   ");
	for j in range(0, state.len()){
		print(state[j]);
		print(" ");
	}
	println("");
	println("");

	print("   Past Guesses: ");
	for j in range(0, past_guess.len()){
		print(past_guess[j]);
                print(" ");
	}
	println("");
	println("");
	print("   Enter Next Guess: ");
}

fn load(filename: ~str) -> ~[~str] {
	let read: Result<@Reader, ~str>;
	read = io::file_reader(~path::Path(filename));

	if read.is_ok() {
	let file = read.unwrap();
	return file.read_lines();
	}

	println(fmt!("Error in reading the file: %?", read.unwrap_err()));
	return ~[];
}

fn isDuplicate(guess: char, guesses: ~[~str]) -> bool{

	for i in range(0,guesses.len()) {
		if (guess.to_str() == guesses[i]){
			return true;
		}
	}
	return false;

}

//fn searchChar(guess: char) -> bool{

//}

fn main() {
	let mut valid_level: bool = false;
	let mut dif: ~str = ~"";
	println("   Welcome to Hangman ");
        println("   Enter number to select game level: ");
	println("   (1) Normal");
	println("   (2) Expert");
	let mut level : ~str = ~"";
	while(!valid_level){
	  level = io::stdin().read_line();
	  if(level.len() > 0){
			if(level.char_at(0) == '1'){
				dif = ~"n_words.txt";
				valid_level = true;
			}else if(level.char_at(0)=='2'){
				dif = ~"x_words.txt";
				valid_level = true;
			}

             }

	}
        let mut rng = rand::task_rng();
	let dictionary: ~[~str] = load(dif);
	let max_size: uint = dictionary.len();
        let n: uint = rng.gen_integer_range(0u, max_size);
	let word: ~str = dictionary[n];
	let word_len: uint = word.char_len();

	//Stores the guessed word
	let mut i = 0;
	let mut stateWord: ~[~str] = ~[];
	while (i < word_len) {
        	stateWord = stateWord + ~[~"_"];
		i += 1;
        }

        //println(fmt!("%s Guessed Word: ", stateWord.to_str()));
	//println(word);

	let mut guesses: ~[~str] = ~[];

	let mut j = 0;

        let max_guess : uint = 6;
	let mut has_won: bool = false;
	while (j < max_guess  && !has_won){
		let mut is_valid: bool = false;
		has_won = true;
		for i in range(0,stateWord.len()) {
			if(stateWord[i]== ~"_"){
				has_won = false;
			}
		}
		if(has_won){
			end(11, stateWord.clone(), word.clone());
			break;
		}
		draw(j+1, stateWord.clone(), guesses.clone());
		let mut line : ~str = ~"";
		while(!is_valid){
		  line = io::stdin().read_line();
		  if(line.len() > 0){
			if(line.char_at(0).is_alphabetic()){
				is_valid = true;
			}
             }

		}
		let guess_char: char = line.char_at(0);
		//println(fmt!("%? guessed: ", guess_char));
		let has_char: bool = word.contains_char(guess_char);

		if(isDuplicate(guess_char, guesses.clone())){
			//println(fmt!("%? Pick another letter! You have already guess ", guess_char.to_str()));
		}else if (has_char){
			guesses.push(guess_char.to_str());
       			let mut i = 0;
			while (i < word_len) {
				if(word.char_at(i) != guess_char){
        	 			//print("_ ");
                		}else{
		 			stateWord[i] = guess_char.to_str();
				}
				i += 1;
       			 }
			//println("");
		}
		else{
			guesses.push(guess_char.to_str());
			//println("nope.");
			j += 1;
		}

	}
	if(j >= max_guess) {end(17, stateWord.clone(), word.clone());}
}
<|endoftext|>


<commit_before>use super::lookup::*;
use super::pawn::*;
use super::slider::consts::squares_between;
use super::slider::*;
use bb::{BB, EMPTY};
use piece::*;
use position::Position;
use side::Side;
use square::Square;

#[allow(dead_code)]
pub fn slider_non_diag_rays_to_squares(source: BB, attacker: BB, position: &Position) -> BB {
    let empty = position.bb_empty();

    pin_ray_non_diag(source, empty, attacker)
}

#[allow(dead_code)]
pub fn slider_diag_rays_to_squares(source: BB, attacker: BB, position: &Position) -> BB {
    let empty = position.bb_empty();

    pin_ray_diag(source, empty, attacker)
}

pub fn checkers_and_pinned(king: BB, attacker: Side, position: &Position) -> (BB, BB, BB) {
    let occupied = position.bb_occupied();
    let king_sq = king.bitscan();

    let mut checkers = EMPTY;
    let mut pinned = EMPTY;
    let mut pinners = EMPTY;

    // Pawns and Knights can only be checkers, not pinners
    let knights = position.bb_pc(KNIGHT.pc(attacker));
    checkers |= king_sq.knight_moves() & knights;

    let pawns = position.bb_pc(PAWN.pc(attacker));
    for &(shift, file_mask) in PAWN_CAPTURE_FILE_MASKS[attacker.flip().to_usize()].iter() {
        checkers |= king.rot_left(shift as u32) & file_mask & pawns;
    }

    // Sliding pieces can be checkers or pinners depending on occupancy of intermediate squares
    let (diag_attackers, non_diag_attackers) = position.bb_sliders(attacker);
    let potential_diag_pinners = occupied & king_sq.bishop_rays() & diag_attackers;
    let potential_non_diag_pinners = occupied & king_sq.rook_rays() & non_diag_attackers;

    let potential_pinners = potential_diag_pinners | potential_non_diag_pinners;

    for (sq, bb) in potential_pinners.iter() {
        let potentially_pinned = squares_between(sq, king_sq) & occupied;

        if potentially_pinned == EMPTY {
            checkers |= bb;
        } else if potentially_pinned.pop_count() == 1 {
            pinned |= potentially_pinned;
            pinners |= bb;
        }
    }

    (checkers, pinned, pinners)
}

/// returns squares king may not move to
/// - removes king from occupied to handle attacking sliders correctly
pub fn king_danger_squares(king: BB, attacker: Side, position: &Position) -> BB {
    let occupied_without_king = position.bb_occupied() & !king;

    let mut attacked_squares = EMPTY;

    let (diag_attackers, non_diag_attackers) = position.bb_sliders(attacker);
    attacked_squares |= bishop_attacks(diag_attackers, occupied_without_king);
    attacked_squares |= rook_attacks(non_diag_attackers, occupied_without_king);

    let knights = position.bb_pc(KNIGHT.pc(attacker));
    attacked_squares |= knight_moves_from_bb(knights);

    let kings = position.bb_pc(KING.pc(attacker));
    debug_assert_eq!(kings.pop_count(), 1);
    attacked_squares |= kings.bitscan().king_moves();

    let pawns = position.bb_pc(PAWN.pc(attacker));
    for &(shift, file_mask) in PAWN_CAPTURE_FILE_MASKS[attacker.to_usize()].iter() {
        let targets = pawns.rot_left(shift as u32) & file_mask;
        attacked_squares |= targets;
    }

    attacked_squares
}

#[allow(dead_code)]
pub fn attacked_squares_ignoring_ep(attacker: Side, position: &Position) -> BB {
    let occupied = position.bb_occupied();
    let mut attacked_squares = EMPTY;

    let (diag_attackers, non_diag_attackers) = position.bb_sliders(attacker);
    attacked_squares |= rook_attacks(non_diag_attackers, occupied);
    attacked_squares |= bishop_attacks(diag_attackers, occupied);

    let knights = position.bb_pc(KNIGHT.pc(attacker));
    attacked_squares |= knight_moves_from_bb(knights);

    let kings = position.bb_pc(KING.pc(attacker));
    debug_assert_eq!(kings.pop_count(), 1);
    attacked_squares |= kings.bitscan().king_moves();

    let pawns = position.bb_pc(PAWN.pc(attacker));
    for &(shift, file_mask) in PAWN_CAPTURE_FILE_MASKS[attacker.to_usize()].iter() {
        let targets = pawns.rot_left(shift as u32) & file_mask;
        attacked_squares |=  targets;
    }

    attacked_squares
}

#[allow(dead_code)]
pub fn checks_to_sq(sq: Square, attacker: Side, position: &Position) -> BB {
    let occupied = position.bb_occupied();

    let mut attackers = EMPTY;

    let knights = position.bb_pc(KNIGHT.pc(attacker));
    attackers |= sq.knight_moves() & knights;

    let pawns = position.bb_pc(PAWN.pc(attacker));
    let sq_bb = BB::new(sq);
    for &(shift, file_mask) in PAWN_CAPTURE_FILE_MASKS[attacker.flip().to_usize()].iter() {
        attackers |= sq_bb.rot_left(shift as u32) & file_mask & pawns;
    }

    let (diag_attackers, non_diag_attackers) = position.bb_sliders(attacker);

    attackers |= rook_attacks_from_sq(sq, occupied) & non_diag_attackers;
    attackers |= bishop_attacks_from_sq(sq, occupied) & diag_attackers;

    attackers
}

#[cfg(test)]
mod test {
    use super::*;
    use bb::*;
    use side::*;
    use square::*;
    use unindent;

    #[test]
    fn test_checks_to_sq() {
        let position =
            &Position::from_fen("rnbqkbnr/pppppp1p/8/8/8/8/PPPPPPPP/RNB1KBNR w").unwrap();
        let attacks = checks_to_sq(C6, BLACK, position);

        let expected = unindent::unindent(
            "
              ABCDEFGH
            8|.#......|8
            7|.#.#....|7
            6|........|6
            5|........|5
            4|........|4
            3|........|3
            2|........|2
            1|........|1
              ABCDEFGH
            ",
        );
        assert_eq!(attacks.to_string(), expected);
    }

    #[test]
    fn test_slider_rays_to_square() {
        let position =
            &Position::from_fen("rnbqk1nr/pppppppp/8/6b2/8/8/PPPPPPPP/RNBQKBNR w").unwrap();
        let attacks = slider_diag_rays_to_squares(BB::new(D2), BB::new(G5), position);

        let expected = unindent::unindent(
            "
              ABCDEFGH
            8|........|8
            7|........|7
            6|........|6
            5|........|5
            4|.....#..|4
            3|....#...|3
            2|........|2
            1|........|1
              ABCDEFGH
            ",
        );

        assert_eq!(attacks.to_string(), expected);
    }
}
<commit_msg>Improve comments<commit_after>use super::lookup::*;
use super::pawn::*;
use super::slider::consts::squares_between;
use super::slider::*;
use bb::{BB, EMPTY};
use piece::*;
use position::Position;
use side::Side;
use square::Square;

#[allow(dead_code)]
pub fn slider_non_diag_rays_to_squares(source: BB, attacker: BB, position: &Position) -> BB {
    let empty = position.bb_empty();

    pin_ray_non_diag(source, empty, attacker)
}

#[allow(dead_code)]
pub fn slider_diag_rays_to_squares(source: BB, attacker: BB, position: &Position) -> BB {
    let empty = position.bb_empty();

    pin_ray_diag(source, empty, attacker)
}

/// Calculates bitboards of
/// * Opponent pieces giving check
/// * Friendly pieces that are pinned
/// * Opponent pieces pinning friendly pieces
pub fn checkers_and_pinned(king: BB, attacker: Side, position: &Position) -> (BB, BB, BB) {
    let occupied = position.bb_occupied();
    let king_sq = king.bitscan();

    let mut checkers = EMPTY;
    let mut pinned = EMPTY;
    let mut pinners = EMPTY;

    // Pawns and Knights can only be checkers, not pinners
    let knights = position.bb_pc(KNIGHT.pc(attacker));
    checkers |= king_sq.knight_moves() & knights;

    let pawns = position.bb_pc(PAWN.pc(attacker));
    for &(shift, file_mask) in PAWN_CAPTURE_FILE_MASKS[attacker.flip().to_usize()].iter() {
        checkers |= king.rot_left(shift as u32) & file_mask & pawns;
    }

    // Sliding pieces can be checkers or pinners depending on occupancy of intermediate squares
    let (diag_attackers, non_diag_attackers) = position.bb_sliders(attacker);

    let potential_king_attackers = occupied
        & ((king_sq.bishop_rays() & diag_attackers) | (king_sq.rook_rays() & non_diag_attackers));

    for (sq, bb) in potential_king_attackers.iter() {
        let potentially_pinned = squares_between(sq, king_sq) & occupied;

        // If there are no friendly pieces between the attacker and the king
        // then the attacker is giving check
        if potentially_pinned == EMPTY {
            checkers |= bb;
        // If there is a friendly piece between the attacker and the king
        // then it is pinned
        } else if potentially_pinned.pop_count() == 1 {
            pinned |= potentially_pinned;
            pinners |= bb;
        }
    }

    (checkers, pinned, pinners)
}

/// returns squares king may not move to
/// - removes king from occupied to handle attacking sliders correctly
pub fn king_danger_squares(king: BB, attacker: Side, position: &Position) -> BB {
    let occupied_without_king = position.bb_occupied() & !king;

    let mut attacked_squares = EMPTY;

    let (diag_attackers, non_diag_attackers) = position.bb_sliders(attacker);
    attacked_squares |= bishop_attacks(diag_attackers, occupied_without_king);
    attacked_squares |= rook_attacks(non_diag_attackers, occupied_without_king);

    let knights = position.bb_pc(KNIGHT.pc(attacker));
    attacked_squares |= knight_moves_from_bb(knights);

    let kings = position.bb_pc(KING.pc(attacker));
    debug_assert_eq!(kings.pop_count(), 1);
    attacked_squares |= kings.bitscan().king_moves();

    let pawns = position.bb_pc(PAWN.pc(attacker));
    for &(shift, file_mask) in PAWN_CAPTURE_FILE_MASKS[attacker.to_usize()].iter() {
        let targets = pawns.rot_left(shift as u32) & file_mask;
        attacked_squares |= targets;
    }

    attacked_squares
}

#[allow(dead_code)]
pub fn attacked_squares_ignoring_ep(attacker: Side, position: &Position) -> BB {
    let occupied = position.bb_occupied();
    let mut attacked_squares = EMPTY;

    let (diag_attackers, non_diag_attackers) = position.bb_sliders(attacker);
    attacked_squares |= rook_attacks(non_diag_attackers, occupied);
    attacked_squares |= bishop_attacks(diag_attackers, occupied);

    let knights = position.bb_pc(KNIGHT.pc(attacker));
    attacked_squares |= knight_moves_from_bb(knights);

    let kings = position.bb_pc(KING.pc(attacker));
    debug_assert_eq!(kings.pop_count(), 1);
    attacked_squares |= kings.bitscan().king_moves();

    let pawns = position.bb_pc(PAWN.pc(attacker));
    for &(shift, file_mask) in PAWN_CAPTURE_FILE_MASKS[attacker.to_usize()].iter() {
        let targets = pawns.rot_left(shift as u32) & file_mask;
        attacked_squares |= targets;
    }

    attacked_squares
}

#[allow(dead_code)]
pub fn checks_to_sq(sq: Square, attacker: Side, position: &Position) -> BB {
    let occupied = position.bb_occupied();

    let mut attackers = EMPTY;

    let knights = position.bb_pc(KNIGHT.pc(attacker));
    attackers |= sq.knight_moves() & knights;

    let pawns = position.bb_pc(PAWN.pc(attacker));
    let sq_bb = BB::new(sq);
    for &(shift, file_mask) in PAWN_CAPTURE_FILE_MASKS[attacker.flip().to_usize()].iter() {
        attackers |= sq_bb.rot_left(shift as u32) & file_mask & pawns;
    }

    let (diag_attackers, non_diag_attackers) = position.bb_sliders(attacker);

    attackers |= rook_attacks_from_sq(sq, occupied) & non_diag_attackers;
    attackers |= bishop_attacks_from_sq(sq, occupied) & diag_attackers;

    attackers
}

#[cfg(test)]
mod test {
    use super::*;
    use bb::*;
    use side::*;
    use square::*;
    use unindent;

    #[test]
    fn test_checks_to_sq() {
        let position =
            &Position::from_fen("rnbqkbnr/pppppp1p/8/8/8/8/PPPPPPPP/RNB1KBNR w").unwrap();
        let attacks = checks_to_sq(C6, BLACK, position);

        let expected = unindent::unindent(
            "
              ABCDEFGH
            8|.#......|8
            7|.#.#....|7
            6|........|6
            5|........|5
            4|........|4
            3|........|3
            2|........|2
            1|........|1
              ABCDEFGH
            ",
        );
        assert_eq!(attacks.to_string(), expected);
    }

    #[test]
    fn test_slider_rays_to_square() {
        let position =
            &Position::from_fen("rnbqk1nr/pppppppp/8/6b2/8/8/PPPPPPPP/RNBQKBNR w").unwrap();
        let attacks = slider_diag_rays_to_squares(BB::new(D2), BB::new(G5), position);

        let expected = unindent::unindent(
            "
              ABCDEFGH
            8|........|8
            7|........|7
            6|........|6
            5|........|5
            4|.....#..|4
            3|....#...|3
            2|........|2
            1|........|1
              ABCDEFGH
            ",
        );

        assert_eq!(attacks.to_string(), expected);
    }
}
<|endoftext|>


<commit_before>use character::controls::CharacterControl;
use game::constants::{RESOLUTION_X, RESOLUTION_Y};
use gfx;
use gfx_app::controls::{Control, TilemapControls};
use gfx_device_gl;
use gfx_window_glutin;
use glutin;
use glutin::{GlContext, KeyboardInput, MouseButton};
use glutin::ElementState::{Pressed, Released};
use glutin::VirtualKeyCode::{A, D, Escape, R, S, W, X, Z};

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct WindowContext {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl WindowContext {
  pub fn new() -> WindowContext {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Hinterland");

    let builder = if cfg!(feature = "windowed") {
      window_title
        .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
        .with_min_dimensions(RESOLUTION_X, RESOLUTION_Y)
        .with_max_dimensions(RESOLUTION_X, RESOLUTION_Y)
    } else {
      let monitor = {
        events_loop.get_available_monitors().nth(0).expect("No monitor found")
      };
      let monitor_resolution = monitor.get_dimensions();

      let resolution = ((monitor_resolution.1 as f32 * 16.0 / 9.0) as u32, monitor_resolution.1);
      window_title.with_fullscreen(Some(monitor))
                  .with_dimensions(resolution.0, resolution.1)
                  .with_min_dimensions(resolution.0, resolution.1)
                  .with_max_dimensions(resolution.0, resolution.1)
    };

    let context = glutin::ContextBuilder::new()
      .with_vsync(true)
      .with_pixel_format(24, 8)
      .with_gl(glutin::GlRequest::GlThenGles {
        opengles_version: (3, 0),
        opengl_version: (3, 3),
      });

    let (window, device, factory, rtv, dsv) =
      gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    WindowContext {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0),
    }
  }
}

#[derive(Debug, PartialEq, Eq)]
pub enum WindowStatus {
  Open,
  Close,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);
  fn get_viewport_size(&mut self) -> (f32, f32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_hidpi_factor(&mut self) -> f32;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
  fn poll_events(&mut self) -> WindowStatus;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for WindowContext {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
        .swap_buffers()
        .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (f32, f32) {
    if cfg!(feature = "windowed") {
      (RESOLUTION_X as f32, RESOLUTION_Y as f32)
    } else {
      let monitor = self.events_loop.get_available_monitors().nth(0).expect("No monitor found");
      let monitor_resolution = monitor.get_dimensions();
      ((monitor_resolution.1 as f32 * 16.0 / 9.0) as f32, monitor_resolution.1 as f32)
    }
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_hidpi_factor(&mut self) -> f32 {
    self.window.hidpi_factor() as f32
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }

  fn poll_events(&mut self) -> WindowStatus {
    use glutin::WindowEvent::{CursorMoved, CloseRequested, MouseInput};

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };

    let m_pos = &mut self.mouse_pos;

    let mut game_status = WindowStatus::Open;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => { process_keyboard_input(input, controls) },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            WindowStatus::Open
          }
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            WindowStatus::Open
          }
          CursorMoved { position, .. } => {
            *m_pos = position;
            WindowStatus::Open
          }
          CloseRequested => WindowStatus::Close,
          _ => WindowStatus::Open,
        }
      } else {
        WindowStatus::Open
      };
    });
    game_status
  }
}

fn process_keyboard_input(input: glutin::KeyboardInput, controls: &mut TilemapControls) -> WindowStatus {
  match input {
    KeyboardInput { virtual_keycode: Some(Escape), .. } => WindowStatus::Close,
    KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => {
      controls.zoom(&Control::Negative);
      WindowStatus::Open
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
      controls.zoom(&Control::Plus);
      WindowStatus::Open
    }
    KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
      controls.zoom(&Control::Released);
      WindowStatus::Open
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
      controls.move_character(CharacterControl::Up);
      WindowStatus::Open
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
      controls.move_character(CharacterControl::Down);
      WindowStatus::Open
    }
    KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
      controls.move_character(CharacterControl::YMoveStop);
      WindowStatus::Open
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
      controls.move_character(CharacterControl::Left);
      WindowStatus::Open
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
      controls.move_character(CharacterControl::Right);
      WindowStatus::Open
    }
    KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
      controls.move_character(CharacterControl::XMoveStop);
      WindowStatus::Open
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(R), .. } => {
      controls.reload_weapon(true);
      WindowStatus::Open
    },
    KeyboardInput { state: Released, virtual_keycode: Some(R), .. } => {
      controls.reload_weapon(false);
      WindowStatus::Open
    },
    KeyboardInput { state: Pressed, modifiers, .. } => {
      if modifiers.ctrl {
        controls.ctrl_pressed(true);
      }
      WindowStatus::Open
    }
    KeyboardInput { state: Released, modifiers, .. } => {
      if !modifiers.ctrl {
        controls.ctrl_pressed(false);
      }
      WindowStatus::Open
    }
  }
}

<commit_msg>Refactor process_keyboard_input function<commit_after>use character::controls::CharacterControl;
use game::constants::{RESOLUTION_X, RESOLUTION_Y};
use gfx;
use gfx_app::controls::{Control, TilemapControls};
use gfx_device_gl;
use gfx_window_glutin;
use glutin;
use glutin::{GlContext, KeyboardInput, MouseButton};
use glutin::ElementState::{Pressed, Released};
use glutin::VirtualKeyCode::{A, D, Escape, R, S, W, X, Z};

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct WindowContext {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl WindowContext {
  pub fn new() -> WindowContext {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Hinterland");

    let builder = if cfg!(feature = "windowed") {
      window_title
        .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
        .with_min_dimensions(RESOLUTION_X, RESOLUTION_Y)
        .with_max_dimensions(RESOLUTION_X, RESOLUTION_Y)
    } else {
      let monitor = {
        events_loop.get_available_monitors().nth(0).expect("No monitor found")
      };
      let monitor_resolution = monitor.get_dimensions();

      let resolution = ((monitor_resolution.1 as f32 * 16.0 / 9.0) as u32, monitor_resolution.1);
      window_title.with_fullscreen(Some(monitor))
                  .with_dimensions(resolution.0, resolution.1)
                  .with_min_dimensions(resolution.0, resolution.1)
                  .with_max_dimensions(resolution.0, resolution.1)
    };

    let context = glutin::ContextBuilder::new()
      .with_vsync(true)
      .with_pixel_format(24, 8)
      .with_gl(glutin::GlRequest::GlThenGles {
        opengles_version: (3, 0),
        opengl_version: (3, 3),
      });

    let (window, device, factory, rtv, dsv) =
      gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    WindowContext {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0),
    }
  }
}

#[derive(Debug, PartialEq, Eq)]
pub enum WindowStatus {
  Open,
  Close,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);
  fn get_viewport_size(&mut self) -> (f32, f32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_hidpi_factor(&mut self) -> f32;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
  fn poll_events(&mut self) -> WindowStatus;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for WindowContext {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
        .swap_buffers()
        .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (f32, f32) {
    if cfg!(feature = "windowed") {
      (RESOLUTION_X as f32, RESOLUTION_Y as f32)
    } else {
      let monitor = self.events_loop.get_available_monitors().nth(0).expect("No monitor found");
      let monitor_resolution = monitor.get_dimensions();
      ((monitor_resolution.1 as f32 * 16.0 / 9.0) as f32, monitor_resolution.1 as f32)
    }
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_hidpi_factor(&mut self) -> f32 {
    self.window.hidpi_factor() as f32
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }

  fn poll_events(&mut self) -> WindowStatus {
    use glutin::WindowEvent::{CursorMoved, CloseRequested, MouseInput};

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };

    let m_pos = &mut self.mouse_pos;

    let mut game_status = WindowStatus::Open;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => { process_keyboard_input(input, controls) },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            WindowStatus::Open
          }
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            WindowStatus::Open
          }
          CursorMoved { position, .. } => {
            *m_pos = position;
            WindowStatus::Open
          }
          CloseRequested => WindowStatus::Close,
          _ => WindowStatus::Open,
        }
      } else {
        WindowStatus::Open
      };
    });
    game_status
  }
}

fn process_keyboard_input(input: glutin::KeyboardInput, controls: &mut TilemapControls) -> WindowStatus {
  match input {
    KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => {
      controls.zoom(&Control::Negative);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
      controls.zoom(&Control::Plus);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
      controls.zoom(&Control::Released);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
      controls.move_character(CharacterControl::Up);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
      controls.move_character(CharacterControl::Down);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
      controls.move_character(CharacterControl::YMoveStop);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
      controls.move_character(CharacterControl::Left);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
      controls.move_character(CharacterControl::Right);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
      controls.move_character(CharacterControl::XMoveStop);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(R), .. } => {
      controls.reload_weapon(true);
    },
    KeyboardInput { state: Released, virtual_keycode: Some(R), .. } => {
      controls.reload_weapon(false);
    },
    KeyboardInput { state: Pressed, modifiers, .. } => {
      if modifiers.ctrl {
        controls.ctrl_pressed(true);
      }
    }
    KeyboardInput { state: Released, modifiers, .. } => {
      if !modifiers.ctrl {
        controls.ctrl_pressed(false);
      }
    }
  }
  if let Some(Escape) = input.virtual_keycode {
    WindowStatus::Close
  } else {
    WindowStatus::Open
  }
}

<|endoftext|>


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

//! Types dealing with dynamic mutability

use cast;
use clone::Clone;
use cmp::Eq;
use fmt;
use kinds::{marker, Pod};
use ops::{Deref, DerefMut, Drop};
use option::{None, Option, Some};
use ty::Unsafe;

/// A mutable memory location that admits only `Pod` data.
pub struct Cell<T> {
    priv value: Unsafe<T>,
    priv marker1: marker::InvariantType<T>,
    priv marker2: marker::NoFreeze,
    priv marker3: marker::NoShare,
}

impl<T:Pod> Cell<T> {
    /// Creates a new `Cell` containing the given value.
    pub fn new(value: T) -> Cell<T> {
        Cell {
            value: Unsafe{value: value, marker1: marker::InvariantType::<T>},
            marker1: marker::InvariantType::<T>,
            marker2: marker::NoFreeze,
            marker3: marker::NoShare,
        }
    }

    /// Returns a copy of the contained value.
    #[inline]
    pub fn get(&self) -> T {
        unsafe{ *self.value.get() }
    }

    /// Sets the contained value.
    #[inline]
    pub fn set(&self, value: T) {
        unsafe {
            *self.value.get() = value;
        }
    }
}

impl<T:Pod> Clone for Cell<T> {
    fn clone(&self) -> Cell<T> {
        Cell::new(self.get())
    }
}

impl<T:Eq + Pod> Eq for Cell<T> {
    fn eq(&self, other: &Cell<T>) -> bool {
        self.get() == other.get()
    }
}

impl<T: fmt::Show> fmt::Show for Cell<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, r"Cell \{ value: {} \}", unsafe{*&self.value.get()})
    }
}

/// A mutable memory location with dynamically checked borrow rules
pub struct RefCell<T> {
    priv value: Unsafe<T>,
    priv borrow: BorrowFlag,
    priv marker1: marker::InvariantType<T>,
    priv marker2: marker::NoFreeze,
    priv marker3: marker::NoPod,
    priv marker4: marker::NoShare,
}

// Values [1, MAX-1] represent the number of `Ref` active
// (will not outgrow its range since `uint` is the size of the address space)
type BorrowFlag = uint;
static UNUSED: BorrowFlag = 0;
static WRITING: BorrowFlag = -1;

impl<T> RefCell<T> {
    /// Create a new `RefCell` containing `value`
    pub fn new(value: T) -> RefCell<T> {
        RefCell {
            marker1: marker::InvariantType::<T>,
            marker2: marker::NoFreeze,
            marker3: marker::NoPod,
            marker4: marker::NoShare,
            value: Unsafe{value: value, marker1: marker::InvariantType::<T>},
            borrow: UNUSED,
        }
    }

    /// Consumes the `RefCell`, returning the wrapped value.
    pub fn unwrap(self) -> T {
        assert!(self.borrow == UNUSED);
        unsafe{self.value.unwrap()}
    }

    unsafe fn as_mut<'a>(&'a self) -> &'a mut RefCell<T> {
        cast::transmute_mut(self)
    }

    /// Attempts to immutably borrow the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// Returns `None` if the value is currently mutably borrowed.
    pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
        match self.borrow {
            WRITING => None,
            _ => {
                unsafe { self.as_mut().borrow += 1; }
                Some(Ref { parent: self })
            }
        }
    }

    /// Immutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently mutably borrowed.
    pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
        match self.try_borrow() {
            Some(ptr) => ptr,
            None => fail!("RefCell<T> already mutably borrowed")
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// Returns `None` if the value is currently borrowed.
    pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
        match self.borrow {
            UNUSED => unsafe {
                let mut_self = self.as_mut();
                mut_self.borrow = WRITING;
                Some(RefMut { parent: mut_self })
            },
            _ => None
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently borrowed.
    pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
        match self.try_borrow_mut() {
            Some(ptr) => ptr,
            None => fail!("RefCell<T> already borrowed")
        }
    }

    /// Sets the value, replacing what was there.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently borrowed.
    #[inline]
    pub fn set(&self, value: T) {
        let mut reference = self.borrow_mut();
        *reference.get() = value;
    }
}

impl<T:Clone> RefCell<T> {
    /// Returns a copy of the contained value.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently mutably borrowed.
    #[inline]
    pub fn get(&self) -> T {
        let reference = self.borrow();
        (*reference.get()).clone()
    }
}

impl<T: Clone> Clone for RefCell<T> {
    fn clone(&self) -> RefCell<T> {
        let x = self.borrow();
        RefCell::new(x.get().clone())
    }
}

impl<T: Eq> Eq for RefCell<T> {
    fn eq(&self, other: &RefCell<T>) -> bool {
        let a = self.borrow();
        let b = other.borrow();
        a.get() == b.get()
    }
}

/// Wraps a borrowed reference to a value in a `RefCell` box.
pub struct Ref<'b, T> {
    priv parent: &'b RefCell<T>
}

#[unsafe_destructor]
impl<'b, T> Drop for Ref<'b, T> {
    fn drop(&mut self) {
        assert!(self.parent.borrow != WRITING && self.parent.borrow != UNUSED);
        unsafe { self.parent.as_mut().borrow -= 1; }
    }
}

impl<'b, T> Ref<'b, T> {
    /// Retrieve an immutable reference to the stored value.
    #[inline]
    pub fn get<'a>(&'a self) -> &'a T {
        unsafe{ &*self.parent.value.get() }
    }
}

impl<'b, T> Deref<T> for Ref<'b, T> {
    #[inline]
    fn deref<'a>(&'a self) -> &'a T {
        unsafe{ &*self.parent.value.get() }
    }
}

/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
pub struct RefMut<'b, T> {
    priv parent: &'b mut RefCell<T>
}

#[unsafe_destructor]
impl<'b, T> Drop for RefMut<'b, T> {
    fn drop(&mut self) {
        assert!(self.parent.borrow == WRITING);
        self.parent.borrow = UNUSED;
    }
}

impl<'b, T> RefMut<'b, T> {
    /// Retrieve a mutable reference to the stored value.
    #[inline]
    pub fn get<'a>(&'a mut self) -> &'a mut T {
        unsafe{ &mut *self.parent.value.get() }
    }
}

impl<'b, T> Deref<T> for RefMut<'b, T> {
    #[inline]
    fn deref<'a>(&'a self) -> &'a T {
        unsafe{ &*self.parent.value.get() }
    }
}

impl<'b, T> DerefMut<T> for RefMut<'b, T> {
    #[inline]
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe{ &mut *self.parent.value.get() }
    }
}

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

    #[test]
    fn smoketest_cell() {
        let x = Cell::new(10);
        assert_eq!(x, Cell::new(10));
        assert_eq!(x.get(), 10);
        x.set(20);
        assert_eq!(x, Cell::new(20));
        assert_eq!(x.get(), 20);

        let y = Cell::new((30, 40));
        assert_eq!(y, Cell::new((30, 40)));
        assert_eq!(y.get(), (30, 40));
    }

    #[test]
    fn double_imm_borrow() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        x.borrow();
    }

    #[test]
    fn no_mut_then_imm_borrow() {
        let x = RefCell::new(0);
        let _b1 = x.borrow_mut();
        assert!(x.try_borrow().is_none());
    }

    #[test]
    fn no_imm_then_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    fn no_double_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow_mut();
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    fn imm_release_borrow_mut() {
        let x = RefCell::new(0);
        {
            let _b1 = x.borrow();
        }
        x.borrow_mut();
    }

    #[test]
    fn mut_release_borrow_mut() {
        let x = RefCell::new(0);
        {
            let _b1 = x.borrow_mut();
        }
        x.borrow();
    }

    #[test]
    fn double_borrow_single_release_no_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        {
            let _b2 = x.borrow();
        }
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    #[should_fail]
    fn discard_doesnt_unborrow() {
        let x = RefCell::new(0);
        let _b = x.borrow();
        let _ = _b;
        let _b = x.borrow_mut();
    }
}
<commit_msg>Clean up marker types and Unsafe initialization<commit_after>// Copyright 2012-2013 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.

//! Types dealing with dynamic mutability

use cast;
use clone::Clone;
use cmp::Eq;
use fmt;
use kinds::{marker, Pod};
use ops::{Deref, DerefMut, Drop};
use option::{None, Option, Some};
use ty::Unsafe;

/// A mutable memory location that admits only `Pod` data.
pub struct Cell<T> {
    priv value: Unsafe<T>,
    priv marker1: marker::NoFreeze,
    priv marker2: marker::NoShare,
}

impl<T:Pod> Cell<T> {
    /// Creates a new `Cell` containing the given value.
    pub fn new(value: T) -> Cell<T> {
        Cell {
            value: Unsafe::new(value),
            marker1: marker::NoFreeze,
            marker2: marker::NoShare,
        }
    }

    /// Returns a copy of the contained value.
    #[inline]
    pub fn get(&self) -> T {
        unsafe{ *self.value.get() }
    }

    /// Sets the contained value.
    #[inline]
    pub fn set(&self, value: T) {
        unsafe {
            *self.value.get() = value;
        }
    }
}

impl<T:Pod> Clone for Cell<T> {
    fn clone(&self) -> Cell<T> {
        Cell::new(self.get())
    }
}

impl<T:Eq + Pod> Eq for Cell<T> {
    fn eq(&self, other: &Cell<T>) -> bool {
        self.get() == other.get()
    }
}

impl<T: fmt::Show> fmt::Show for Cell<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, r"Cell \{ value: {} \}", unsafe{*&self.value.get()})
    }
}

/// A mutable memory location with dynamically checked borrow rules
pub struct RefCell<T> {
    priv value: Unsafe<T>,
    priv borrow: BorrowFlag,
    priv marker1: marker::NoFreeze,
    priv marker2: marker::NoPod,
    priv marker3: marker::NoShare,
}

// Values [1, MAX-1] represent the number of `Ref` active
// (will not outgrow its range since `uint` is the size of the address space)
type BorrowFlag = uint;
static UNUSED: BorrowFlag = 0;
static WRITING: BorrowFlag = -1;

impl<T> RefCell<T> {
    /// Create a new `RefCell` containing `value`
    pub fn new(value: T) -> RefCell<T> {
        RefCell {
            marker1: marker::NoFreeze,
            marker2: marker::NoPod,
            marker3: marker::NoShare,
            value: Unsafe::new(value),
            borrow: UNUSED,
        }
    }

    /// Consumes the `RefCell`, returning the wrapped value.
    pub fn unwrap(self) -> T {
        assert!(self.borrow == UNUSED);
        unsafe{self.value.unwrap()}
    }

    unsafe fn as_mut<'a>(&'a self) -> &'a mut RefCell<T> {
        cast::transmute_mut(self)
    }

    /// Attempts to immutably borrow the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// Returns `None` if the value is currently mutably borrowed.
    pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
        match self.borrow {
            WRITING => None,
            _ => {
                unsafe { self.as_mut().borrow += 1; }
                Some(Ref { parent: self })
            }
        }
    }

    /// Immutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently mutably borrowed.
    pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
        match self.try_borrow() {
            Some(ptr) => ptr,
            None => fail!("RefCell<T> already mutably borrowed")
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// Returns `None` if the value is currently borrowed.
    pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
        match self.borrow {
            UNUSED => unsafe {
                let mut_self = self.as_mut();
                mut_self.borrow = WRITING;
                Some(RefMut { parent: mut_self })
            },
            _ => None
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently borrowed.
    pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
        match self.try_borrow_mut() {
            Some(ptr) => ptr,
            None => fail!("RefCell<T> already borrowed")
        }
    }

    /// Sets the value, replacing what was there.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently borrowed.
    #[inline]
    pub fn set(&self, value: T) {
        let mut reference = self.borrow_mut();
        *reference.get() = value;
    }
}

impl<T:Clone> RefCell<T> {
    /// Returns a copy of the contained value.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently mutably borrowed.
    #[inline]
    pub fn get(&self) -> T {
        let reference = self.borrow();
        (*reference.get()).clone()
    }
}

impl<T: Clone> Clone for RefCell<T> {
    fn clone(&self) -> RefCell<T> {
        let x = self.borrow();
        RefCell::new(x.get().clone())
    }
}

impl<T: Eq> Eq for RefCell<T> {
    fn eq(&self, other: &RefCell<T>) -> bool {
        let a = self.borrow();
        let b = other.borrow();
        a.get() == b.get()
    }
}

/// Wraps a borrowed reference to a value in a `RefCell` box.
pub struct Ref<'b, T> {
    priv parent: &'b RefCell<T>
}

#[unsafe_destructor]
impl<'b, T> Drop for Ref<'b, T> {
    fn drop(&mut self) {
        assert!(self.parent.borrow != WRITING && self.parent.borrow != UNUSED);
        unsafe { self.parent.as_mut().borrow -= 1; }
    }
}

impl<'b, T> Ref<'b, T> {
    /// Retrieve an immutable reference to the stored value.
    #[inline]
    pub fn get<'a>(&'a self) -> &'a T {
        unsafe{ &*self.parent.value.get() }
    }
}

impl<'b, T> Deref<T> for Ref<'b, T> {
    #[inline]
    fn deref<'a>(&'a self) -> &'a T {
        unsafe{ &*self.parent.value.get() }
    }
}

/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
pub struct RefMut<'b, T> {
    priv parent: &'b mut RefCell<T>
}

#[unsafe_destructor]
impl<'b, T> Drop for RefMut<'b, T> {
    fn drop(&mut self) {
        assert!(self.parent.borrow == WRITING);
        self.parent.borrow = UNUSED;
    }
}

impl<'b, T> RefMut<'b, T> {
    /// Retrieve a mutable reference to the stored value.
    #[inline]
    pub fn get<'a>(&'a mut self) -> &'a mut T {
        unsafe{ &mut *self.parent.value.get() }
    }
}

impl<'b, T> Deref<T> for RefMut<'b, T> {
    #[inline]
    fn deref<'a>(&'a self) -> &'a T {
        unsafe{ &*self.parent.value.get() }
    }
}

impl<'b, T> DerefMut<T> for RefMut<'b, T> {
    #[inline]
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe{ &mut *self.parent.value.get() }
    }
}

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

    #[test]
    fn smoketest_cell() {
        let x = Cell::new(10);
        assert_eq!(x, Cell::new(10));
        assert_eq!(x.get(), 10);
        x.set(20);
        assert_eq!(x, Cell::new(20));
        assert_eq!(x.get(), 20);

        let y = Cell::new((30, 40));
        assert_eq!(y, Cell::new((30, 40)));
        assert_eq!(y.get(), (30, 40));
    }

    #[test]
    fn double_imm_borrow() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        x.borrow();
    }

    #[test]
    fn no_mut_then_imm_borrow() {
        let x = RefCell::new(0);
        let _b1 = x.borrow_mut();
        assert!(x.try_borrow().is_none());
    }

    #[test]
    fn no_imm_then_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    fn no_double_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow_mut();
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    fn imm_release_borrow_mut() {
        let x = RefCell::new(0);
        {
            let _b1 = x.borrow();
        }
        x.borrow_mut();
    }

    #[test]
    fn mut_release_borrow_mut() {
        let x = RefCell::new(0);
        {
            let _b1 = x.borrow_mut();
        }
        x.borrow();
    }

    #[test]
    fn double_borrow_single_release_no_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        {
            let _b2 = x.borrow();
        }
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    #[should_fail]
    fn discard_doesnt_unborrow() {
        let x = RefCell::new(0);
        let _b = x.borrow();
        let _ = _b;
        let _b = x.borrow_mut();
    }
}
<|endoftext|>